Repository: NCAR/VAPOR Branch: main Commit: 43b85ed4e78c Files: 1316 Total size: 7.1 MB Directory structure: gitextract__3medrpc/ ├── .circleci/ │ ├── config.yml │ └── downloadWin3rdParty.py ├── .clang-format ├── .editorconfig ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── documentation-request.md │ │ └── enhancement-request.md │ └── workflows/ │ └── release.yml ├── .gitignore ├── .readthedocs.yml ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── Contributing.md ├── LICENSE.txt ├── README.md ├── apps/ │ ├── CMakeLists.txt │ ├── asciitf2vtf/ │ │ └── asciitf2vtf.cpp │ ├── cf2vdc/ │ │ ├── CMakeLists.txt │ │ └── cf2vdc.cpp │ ├── cfvdccreate/ │ │ ├── CMakeLists.txt │ │ └── cfvdccreate.cpp │ ├── linuxlauncher/ │ │ ├── CMakeLists.txt │ │ └── launcher.c │ ├── ncdf2wasp/ │ │ ├── CMakeLists.txt │ │ └── ncdf2wasp.cpp │ ├── pythonapi/ │ │ ├── CMakeLists.txt │ │ ├── cmake.py │ │ ├── example_scripts/ │ │ │ ├── CMakeLists.txt │ │ │ ├── animation_example.py │ │ │ ├── annotation_example.py │ │ │ ├── camera_example.py │ │ │ ├── dataset_example.py │ │ │ ├── example_utils.py │ │ │ ├── flow_example.py │ │ │ ├── numpy_example.py │ │ │ ├── rotate_video.py │ │ │ ├── transfer_function_example.py │ │ │ ├── visualizer_widget_example.py │ │ │ ├── workflow_example.py │ │ │ └── xarray_example.py │ │ ├── setup.py │ │ ├── tests/ │ │ │ ├── CanvasStreamTest.ipynb │ │ │ ├── bld.bat │ │ │ ├── build.sh │ │ │ ├── cppyy-syntax-test.py │ │ │ ├── cppyy-test.py │ │ │ ├── meta.yaml │ │ │ ├── module-data-test.py │ │ │ ├── module-test.py │ │ │ ├── syntax-test.py │ │ │ └── test.py │ │ └── vapor/ │ │ ├── __init__.py │ │ ├── animation.py │ │ ├── annotations.py │ │ ├── camera.py │ │ ├── cmake.py │ │ ├── common.py │ │ ├── config.py │ │ ├── cppyyDoxygenWrapper.py │ │ ├── dataset.py │ │ ├── link.py │ │ ├── params.py │ │ ├── renderer.py │ │ ├── session.py │ │ ├── smartwrapper.py │ │ ├── transferfunction.py │ │ ├── transform.py │ │ ├── utils/ │ │ │ ├── __init__.py │ │ │ ├── histogram.py │ │ │ └── keyframing.py │ │ ├── widget-jquery.js │ │ ├── widget.css │ │ ├── widget.js │ │ └── widget.py │ ├── raw2vdc/ │ │ ├── CMakeLists.txt │ │ └── raw2vdc.cpp │ ├── raw2wasp/ │ │ ├── CMakeLists.txt │ │ └── raw2wasp.cpp │ ├── tiff2geotiff/ │ │ ├── CMakeLists.txt │ │ ├── geotiff_proj4.cpp │ │ ├── getopt.cpp │ │ └── tiff2geotiff.cpp │ ├── vapor_check_udunits/ │ │ ├── CMakeLists.txt │ │ └── vapor_check_udunits.cpp │ ├── vaporgui/ │ │ ├── .gitignore │ │ ├── AbstractWidgetGroup.cpp │ │ ├── AbstractWidgetGroup.h │ │ ├── AnimationController.cpp │ │ ├── AnimationController.h │ │ ├── AnnotationEventRouter.cpp │ │ ├── AnnotationEventRouter.h │ │ ├── AppSettingsMenu.cpp │ │ ├── AppSettingsMenu.h │ │ ├── AppSettingsParams.cpp │ │ ├── AppSettingsParams.h │ │ ├── BannerGUI.cpp │ │ ├── BannerGUI.h │ │ ├── BarbEventRouter.cpp │ │ ├── BarbEventRouter.h │ │ ├── BookmarkManager.cpp │ │ ├── BookmarkManager.h │ │ ├── CLIToolInstaller.cpp │ │ ├── CLIToolInstaller.h │ │ ├── CMakeLists.txt │ │ ├── CaptureController.cpp │ │ ├── CaptureController.h │ │ ├── CheckForNotices.cpp │ │ ├── CheckForNotices.h │ │ ├── CheckForUpdate.cpp │ │ ├── CheckForUpdate.h │ │ ├── CheckForUpdateUI.cpp │ │ ├── CheckForUpdateUI.h │ │ ├── CitationReminder.h │ │ ├── Combo.cpp │ │ ├── Combo.h │ │ ├── ContourEventRouter.cpp │ │ ├── ContourEventRouter.h │ │ ├── CopyRegionAnnotationWidget.cpp │ │ ├── CopyRegionAnnotationWidget.h │ │ ├── CopyRegionWidget.cpp │ │ ├── CopyRegionWidget.h │ │ ├── Core3_2_context.h │ │ ├── DatasetImportController.cpp │ │ ├── DatasetImportController.h │ │ ├── DatasetInspector.cpp │ │ ├── DatasetInspector.h │ │ ├── DatasetTypeLookup.cpp │ │ ├── DatasetTypeLookup.h │ │ ├── ErrorReporter.cpp │ │ ├── ErrorReporter.h │ │ ├── ExportTab.cpp │ │ ├── ExportTab.h │ │ ├── FidelityWidget.cpp │ │ ├── FidelityWidget.h │ │ ├── FidelityWidgetGUI.ui │ │ ├── FileOperationChecker.cpp │ │ ├── FileOperationChecker.h │ │ ├── Flags.h │ │ ├── FlowEventRouter.cpp │ │ ├── FlowEventRouter.h │ │ ├── GLWidget.cpp │ │ ├── GLWidget.h │ │ ├── ImageEventRouter.cpp │ │ ├── ImageEventRouter.h │ │ ├── ImportTab.cpp │ │ ├── ImportTab.h │ │ ├── LeftPanel.cpp │ │ ├── LeftPanel.h │ │ ├── MainForm.cpp │ │ ├── MainForm.h │ │ ├── MainForm_isOpenGLContextActive.cpp │ │ ├── Manip.cpp │ │ ├── Manip.h │ │ ├── ModelEventRouter.cpp │ │ ├── ModelEventRouter.h │ │ ├── NcarCasperUtils.cpp │ │ ├── NcarCasperUtils.h │ │ ├── NewRendererDialog.ui │ │ ├── NewRendererDialogManager.cpp │ │ ├── NewRendererDialogManager.h │ │ ├── NoticeBoard.cpp │ │ ├── NoticeBoard.h │ │ ├── PAnnotationColorbarWidget.cpp │ │ ├── PAnnotationColorbarWidget.h │ │ ├── PAxisAnnotationWidget.cpp │ │ ├── PAxisAnnotationWidget.h │ │ ├── PButton.cpp │ │ ├── PButton.h │ │ ├── PCameraControlsSection.cpp │ │ ├── PCameraControlsSection.h │ │ ├── PCaptureWidget.cpp │ │ ├── PCaptureWidget.h │ │ ├── PCheckbox.cpp │ │ ├── PCheckbox.h │ │ ├── PCheckboxHLI.h │ │ ├── PColorSelector.cpp │ │ ├── PColorSelector.h │ │ ├── PConstantColorWidget.cpp │ │ ├── PConstantColorWidget.h │ │ ├── PCopyRegionAnnotationWidget.cpp │ │ ├── PCopyRegionAnnotationWidget.h │ │ ├── PCopyRegionWidget.cpp │ │ ├── PCopyRegionWidget.h │ │ ├── PCornerSelector.cpp │ │ ├── PCornerSelector.h │ │ ├── PDatasetTransformWidget.cpp │ │ ├── PDatasetTransformWidget.h │ │ ├── PDimensionSelector.cpp │ │ ├── PDimensionSelector.h │ │ ├── PDisplay.cpp │ │ ├── PDisplay.h │ │ ├── PDisplayHLI.h │ │ ├── PDoubleInput.cpp │ │ ├── PDoubleInput.h │ │ ├── PDoubleInputHLI.h │ │ ├── PDynamicMixin.cpp │ │ ├── PDynamicMixin.h │ │ ├── PEnumDropdown.cpp │ │ ├── PEnumDropdown.h │ │ ├── PEnumDropdownHLI.h │ │ ├── PFidelitySection.cpp │ │ ├── PFidelitySection.h │ │ ├── PFileButton.cpp │ │ ├── PFileButton.h │ │ ├── PFileSelector.cpp │ │ ├── PFileSelector.h │ │ ├── PFileSelectorHLI.h │ │ ├── PFlowIntegrationRegionSelector.cpp │ │ ├── PFlowIntegrationRegionSelector.h │ │ ├── PFlowRakeRegionSelector.cpp │ │ ├── PFlowRakeRegionSelector.h │ │ ├── PGeometrySubtab.cpp │ │ ├── PGeometrySubtab.h │ │ ├── PGroup.cpp │ │ ├── PGroup.h │ │ ├── PImportDataButton.cpp │ │ ├── PImportDataButton.h │ │ ├── PImportDataWidget.cpp │ │ ├── PImportDataWidget.h │ │ ├── PIntegerInput.cpp │ │ ├── PIntegerInput.h │ │ ├── PIntegerInputHLI.h │ │ ├── PLabel.cpp │ │ ├── PLabel.h │ │ ├── PLineItem.cpp │ │ ├── PLineItem.h │ │ ├── PMetadataClasses.cpp │ │ ├── PMetadataClasses.h │ │ ├── PMovingDomainSettings.cpp │ │ ├── PMovingDomainSettings.h │ │ ├── PMultiVarSelector.cpp │ │ ├── PMultiVarSelector.h │ │ ├── POrientationSelector.cpp │ │ ├── POrientationSelector.h │ │ ├── POutputResolutionSection.cpp │ │ ├── POutputResolutionSection.h │ │ ├── PProjectionStringWidget.cpp │ │ ├── PProjectionStringWidget.h │ │ ├── PRadioButtons.cpp │ │ ├── PRadioButtons.h │ │ ├── PRegionSelector.cpp │ │ ├── PRegionSelector.h │ │ ├── PSection.cpp │ │ ├── PSection.h │ │ ├── PShowIf.cpp │ │ ├── PShowIf.h │ │ ├── PSliceController.cpp │ │ ├── PSliceController.h │ │ ├── PSliderEdit.cpp │ │ ├── PSliderEdit.h │ │ ├── PSliderEditHLI.h │ │ ├── PStringDropdown.cpp │ │ ├── PStringDropdown.h │ │ ├── PStringDropdownHLI.h │ │ ├── PStringInput.cpp │ │ ├── PStringInput.h │ │ ├── PTFEditor.cpp │ │ ├── PTFEditor.h │ │ ├── PTMSLODInput.h │ │ ├── PTimeRangeSelector.cpp │ │ ├── PTimeRangeSelector.h │ │ ├── PTimestepInput.cpp │ │ ├── PTimestepInput.h │ │ ├── PTimestepSliderEdit.cpp │ │ ├── PTimestepSliderEdit.h │ │ ├── PTotalTimestepsDisplay.cpp │ │ ├── PTotalTimestepsDisplay.h │ │ ├── PTransformWidget.cpp │ │ ├── PTransformWidget.h │ │ ├── PVariableSelector.cpp │ │ ├── PVariableSelector.h │ │ ├── PVisualizerSelector.cpp │ │ ├── PVisualizerSelector.h │ │ ├── PWidget.cpp │ │ ├── PWidget.h │ │ ├── PWidgetHLI.h │ │ ├── PWidgetWrapper.cpp │ │ ├── PWidgetWrapper.h │ │ ├── PWidgets.h │ │ ├── PWidgetsFwd.h │ │ ├── ParamsMenuItems.cpp │ │ ├── ParamsMenuItems.h │ │ ├── ParamsUpdatable.cpp │ │ ├── ParamsUpdatable.h │ │ ├── ParamsWidgetDemo.cpp │ │ ├── ParamsWidgetDemo.h │ │ ├── ParticleEventRouter.cpp │ │ ├── ParticleEventRouter.h │ │ ├── Plot.cpp │ │ ├── Plot.h │ │ ├── PlotParams.cpp │ │ ├── PlotParams.h │ │ ├── ProgressStatusBar.h │ │ ├── PythonVariables.cpp │ │ ├── PythonVariables.h │ │ ├── PythonVariablesGUI.ui │ │ ├── PythonVariablesParams.cpp │ │ ├── PythonVariablesParams.h │ │ ├── QColorWidget.cpp │ │ ├── QColorWidget.h │ │ ├── QCustomIconSizeProxyStyle.h │ │ ├── QEnableable.h │ │ ├── QIntValidatorWithFixup.cpp │ │ ├── QIntValidatorWithFixup.h │ │ ├── QMontereySlider.h │ │ ├── QPaintUtils.cpp │ │ ├── QPaintUtils.h │ │ ├── QPushButtonWithDoubleClick.h │ │ ├── QRange.cpp │ │ ├── QRange.h │ │ ├── QRange.ui │ │ ├── QRangeSlider.cpp │ │ ├── QRangeSlider.h │ │ ├── QRangeSliderTextCombo.cpp │ │ ├── QRangeSliderTextCombo.h │ │ ├── QSinglePoint.cpp │ │ ├── QSinglePoint.h │ │ ├── QSinglePoint.ui │ │ ├── QSliderEdit.cpp │ │ ├── QSliderEdit.h │ │ ├── QSliderEdit.ui │ │ ├── QtVizWinGLContextManager.cpp │ │ ├── QtVizWinGLContextManager.h │ │ ├── RangeCombos.cpp │ │ ├── RangeCombos.h │ │ ├── RenderEventRouter.cpp │ │ ├── RenderEventRouter.h │ │ ├── RenderEventRouterGUI.cpp │ │ ├── RenderEventRouterGUI.h │ │ ├── RenderHolder.cpp │ │ ├── RenderHolder.h │ │ ├── RendererInspector.cpp │ │ ├── RendererInspector.h │ │ ├── RendererList.cpp │ │ ├── RendererList.h │ │ ├── RenderersPanel.cpp │ │ ├── RenderersPanel.h │ │ ├── SliceEventRouter.cpp │ │ ├── SliceEventRouter.h │ │ ├── Statistics.cpp │ │ ├── Statistics.h │ │ ├── StatisticsParams.cpp │ │ ├── StatisticsParams.h │ │ ├── TFColorInfoWidget.cpp │ │ ├── TFColorInfoWidget.h │ │ ├── TFColorWidget.cpp │ │ ├── TFColorWidget.h │ │ ├── TFHistogramInfoWidget.cpp │ │ ├── TFHistogramInfoWidget.h │ │ ├── TFHistogramWidget.cpp │ │ ├── TFHistogramWidget.h │ │ ├── TFInfoWidget.cpp │ │ ├── TFInfoWidget.h │ │ ├── TFIsoValueInfoWidget.cpp │ │ ├── TFIsoValueInfoWidget.h │ │ ├── TFIsoValueWidget.cpp │ │ ├── TFIsoValueWidget.h │ │ ├── TFMapGroupWidget.cpp │ │ ├── TFMapGroupWidget.h │ │ ├── TFMapWidget.cpp │ │ ├── TFMapWidget.h │ │ ├── TFMappingRangeSelector.cpp │ │ ├── TFMappingRangeSelector.h │ │ ├── TFOpacityInfoWidget.cpp │ │ ├── TFOpacityInfoWidget.h │ │ ├── TFOpacityWidget.cpp │ │ ├── TFOpacityWidget.h │ │ ├── TFUtils.cpp │ │ ├── TFUtils.h │ │ ├── TwoDDataEventRouter.cpp │ │ ├── TwoDDataEventRouter.h │ │ ├── UCloseVDCMenu.cpp │ │ ├── UCloseVDCMenu.h │ │ ├── UWidget.cpp │ │ ├── UWidget.h │ │ ├── Updatable.h │ │ ├── V3DInput.cpp │ │ ├── V3DInput.h │ │ ├── V3DIntInput.cpp │ │ ├── V3DIntInput.h │ │ ├── VActions.cpp │ │ ├── VActions.h │ │ ├── VCheckBox.cpp │ │ ├── VCheckBox.h │ │ ├── VComboBox.cpp │ │ ├── VComboBox.h │ │ ├── VContainer.cpp │ │ ├── VContainer.h │ │ ├── VDoubleLineEdit.cpp │ │ ├── VDoubleLineEdit.h │ │ ├── VDoubleRangeMenu.cpp │ │ ├── VDoubleRangeMenu.h │ │ ├── VDoubleSliderEdit.cpp │ │ ├── VDoubleSliderEdit.h │ │ ├── VDoubleSliderEditMenu.cpp │ │ ├── VDoubleSliderEditMenu.h │ │ ├── VDoubleValidator.cpp │ │ ├── VDoubleValidator.h │ │ ├── VFileSelector.cpp │ │ ├── VFileSelector.h │ │ ├── VFrame.cpp │ │ ├── VFrame.h │ │ ├── VGroup.cpp │ │ ├── VGroup.h │ │ ├── VHBoxWidget.cpp │ │ ├── VHBoxWidget.h │ │ ├── VHyperlink.cpp │ │ ├── VHyperlink.h │ │ ├── VIntLineEdit.cpp │ │ ├── VIntLineEdit.h │ │ ├── VIntRangeMenu.cpp │ │ ├── VIntRangeMenu.h │ │ ├── VIntSliderEdit.cpp │ │ ├── VIntSliderEdit.h │ │ ├── VIntSliderEditMenu.cpp │ │ ├── VIntSliderEditMenu.h │ │ ├── VIntSpinBox.cpp │ │ ├── VIntSpinBox.h │ │ ├── VLabel.cpp │ │ ├── VLabel.h │ │ ├── VLabelPair.cpp │ │ ├── VLabelPair.h │ │ ├── VLineEdit_Deprecated.cpp │ │ ├── VLineEdit_Deprecated.h │ │ ├── VLineItem.cpp │ │ ├── VLineItem.h │ │ ├── VNumericFormatMenu.cpp │ │ ├── VNumericFormatMenu.h │ │ ├── VNumericLineEdit.cpp │ │ ├── VNumericLineEdit.h │ │ ├── VProjectionStringFrame.cpp │ │ ├── VProjectionStringFrame.h │ │ ├── VPushButton.cpp │ │ ├── VPushButton.h │ │ ├── VRadioButton.cpp │ │ ├── VRadioButton.h │ │ ├── VRouter.cpp │ │ ├── VRouter.h │ │ ├── VScrollArea.cpp │ │ ├── VScrollArea.h │ │ ├── VScrollGroup.h │ │ ├── VSection.cpp │ │ ├── VSection.h │ │ ├── VSlider.cpp │ │ ├── VSlider.h │ │ ├── VSliderEdit.cpp │ │ ├── VSliderEdit.h │ │ ├── VSliderEditInterface.cpp │ │ ├── VSliderEditInterface.h │ │ ├── VStringLineEdit.cpp │ │ ├── VStringLineEdit.h │ │ ├── VVisibilityCheckbox.cpp │ │ ├── VVisibilityCheckbox.h │ │ ├── VaporFwd.h │ │ ├── VaporTable.cpp │ │ ├── VaporTable.h │ │ ├── VaporTableGUI.ui │ │ ├── VaporWidgetsFwd.h │ │ ├── ViewpointToolbar.cpp │ │ ├── ViewpointToolbar.h │ │ ├── VizWin.cpp │ │ ├── VizWin.h │ │ ├── VizWinMgr.cpp │ │ ├── VizWinMgr.h │ │ ├── VolumeEventRouter.cpp │ │ ├── VolumeEventRouter.h │ │ ├── VolumeIsoEventRouter.cpp │ │ ├── VolumeIsoEventRouter.h │ │ ├── WireFrameEventRouter.cpp │ │ ├── WireFrameEventRouter.h │ │ ├── common.cpp │ │ ├── common.h │ │ ├── core_profile_attributes.mm │ │ ├── hide_std_error_util.cpp │ │ ├── hide_std_error_util.h │ │ ├── images/ │ │ │ ├── arrowrake.xpm │ │ │ ├── back.xpm │ │ │ ├── capture-off.xpm │ │ │ ├── capture-on.xpm │ │ │ ├── cascade.xpm │ │ │ ├── cube.xpm │ │ │ ├── eye.xpm │ │ │ ├── fileopen.xpm │ │ │ ├── forward.xpm │ │ │ ├── home.xpm │ │ │ ├── home2.xpm │ │ │ ├── isoline.xpm │ │ │ ├── lightbulb.xpm │ │ │ ├── magnify.xpm │ │ │ ├── pauseA.xpm │ │ │ ├── pauseimage.xpm │ │ │ ├── planes.xpm │ │ │ ├── playforward.xpm │ │ │ ├── playforwardA.xpm │ │ │ ├── playreverse.xpm │ │ │ ├── playreverseA.xpm │ │ │ ├── probe.xpm │ │ │ ├── rake.xpm │ │ │ ├── replayA.xpm │ │ │ ├── sethome.xpm │ │ │ ├── sphere.xpm │ │ │ ├── spherecolored.xpm │ │ │ ├── step-back-off.xpm │ │ │ ├── step-fwd-off.xpm │ │ │ ├── stepback.xpm │ │ │ ├── stepbackA.xpm │ │ │ ├── stepfwd.xpm │ │ │ ├── stepfwdA.xpm │ │ │ ├── tiles.xpm │ │ │ ├── tobeginA.xpm │ │ │ ├── toendA.xpm │ │ │ ├── twoDData.xpm │ │ │ ├── twoDImage.xpm │ │ │ ├── vapor-icon-32.xpm │ │ │ └── wheel.xpm │ │ ├── mac_helpers.h │ │ ├── mac_helpers.mm │ │ ├── main.cpp │ │ ├── plotWindow.ui │ │ ├── statsWindow.ui │ │ ├── vapor.rc.in │ │ ├── windowsUtils.cpp │ │ └── windowsUtils.h │ ├── vaporpychecker/ │ │ ├── CMakeLists.txt │ │ └── vaporpychecker.cpp │ ├── vaporversion/ │ │ ├── CMakeLists.txt │ │ └── vaporversion.cpp │ ├── vdc2raw/ │ │ ├── CMakeLists.txt │ │ └── vdc2raw.cpp │ ├── vdccompare/ │ │ ├── CMakeLists.txt │ │ └── vdccompare.cpp │ ├── vdccreate/ │ │ ├── CMakeLists.txt │ │ └── vdccreate.cpp │ ├── vdcdump/ │ │ ├── CMakeLists.txt │ │ └── vdcdump.cpp │ ├── vdcerr/ │ │ └── vdcerr.cpp │ ├── wasp2ncdf/ │ │ ├── CMakeLists.txt │ │ └── wasp2ncdf.cpp │ ├── wasp2raw/ │ │ ├── CMakeLists.txt │ │ └── wasp2raw.cpp │ ├── waspcreate/ │ │ ├── CMakeLists.txt │ │ └── waspcreate.cpp │ ├── wrf2vdc/ │ │ ├── CMakeLists.txt │ │ └── wrf2vdc.cpp │ └── wrfvdccreate/ │ ├── CMakeLists.txt │ └── wrfvdccreate.cpp ├── buildutils/ │ ├── AppRun │ ├── GetGitRevisionDescription.cmake │ ├── GetGitRevisionDescription.cmake.in │ ├── NSIS.preInstall.ini.in │ ├── NSIS.preUnInstall.ini.in │ ├── NSIS.template.in │ ├── OpenMPInstaller.cmake │ ├── UtilityFunctions.cmake │ ├── codesignMacOS.sh │ ├── copylibdeps.pl │ ├── exports.awk │ ├── fastdep.pl │ ├── genAppImage.sh │ ├── gen_linux_shared_libs.pl │ ├── install-sh │ ├── install_name.pl │ ├── mklinks.pl │ ├── patchelf/ │ │ ├── COPYING │ │ ├── elf.h │ │ └── patchelf.cpp │ ├── postflight │ ├── postinstall │ ├── postupgrade │ ├── renameomp.sh │ ├── sgiinstall.sh │ └── vapor.desktop ├── conda/ │ ├── vapor/ │ │ ├── build.sh │ │ ├── jupyter_installer_fix.py │ │ ├── make_installer.sh │ │ └── meta.yaml │ ├── vapor-maps/ │ │ └── meta.yaml │ └── vapor-maps-extra/ │ └── meta.yaml ├── include/ │ ├── CMakeLists.txt │ └── vapor/ │ ├── Advection.h │ ├── AdvectionIO.h │ ├── AnimationParams.h │ ├── AnnotationParams.h │ ├── AnnotationRenderer.h │ ├── AnnotationsParams.h │ ├── ArbitrarilyOrientedRegularGrid.h │ ├── AxisAnnotation.h │ ├── BOVCollection.h │ ├── BarbParams.h │ ├── BarbRenderer.h │ ├── Base16StringStream.h │ ├── BlkMemMgr.h │ ├── BookmarkParams.h │ ├── Box.h │ ├── CFuncs.h │ ├── CMakeConfig.h │ ├── CalcEngineMgr.h │ ├── ColorMap.h │ ├── ColorbarPbase.h │ ├── ColorbarRenderer.h │ ├── Compressor.h │ ├── ConstantGrid.h │ ├── ContourParams.h │ ├── ContourRenderer.h │ ├── ControlExecutive.h │ ├── CurvilinearGrid.h │ ├── DC.h │ ├── DCBOV.h │ ├── DCCF.h │ ├── DCMPAS.h │ ├── DCMelanie.h │ ├── DCP.h │ ├── DCRAM.h │ ├── DCUGRID.h │ ├── DCUtils.h │ ├── DCWRF.h │ ├── DataMgr.h │ ├── DataMgrFactory.h │ ├── DataMgrUtils.h │ ├── DataStatus.h │ ├── DatasetsParams.h │ ├── DerivedParticleDensity.h │ ├── DerivedVar.h │ ├── DerivedVarMgr.h │ ├── EasyThreads.h │ ├── Field.h │ ├── FileUtils.h │ ├── FlowParams.h │ ├── FlowRenderer.h │ ├── Font.h │ ├── FontManager.h │ ├── Framebuffer.h │ ├── GLManager.h │ ├── GUIStateParams.h │ ├── GeoImage.h │ ├── GeoImageGeoTiff.h │ ├── GeoImageTMS.h │ ├── GeoTIFWriter.h │ ├── GeoTile.h │ ├── GeoTileEquirectangular.h │ ├── GeoTileMercator.h │ ├── GeoUtil.h │ ├── GetAppPath.h │ ├── Grid.h │ ├── GridHelper.h │ ├── HelloParams.h │ ├── HelloRenderer.h │ ├── Histo.h │ ├── IResourceManager.h │ ├── ImageParams.h │ ├── ImageRenderer.h │ ├── ImageWriter.h │ ├── ImpExp.h │ ├── JPGWriter.h │ ├── KDTreeRG.h │ ├── LayeredGrid.h │ ├── LegacyGL.h │ ├── LegacyVectorMath.h │ ├── MapperFunction.h │ ├── MatWaveBase.h │ ├── MatWaveDwt.h │ ├── MatWaveWavedec.h │ ├── MatrixManager.h │ ├── ModelParams.h │ ├── ModelRenderer.h │ ├── MouseModeParams.h │ ├── MyBase.h │ ├── MyPython.h │ ├── NavigationUtils.h │ ├── NetCDFCFCollection.h │ ├── NetCDFCollection.h │ ├── NetCDFCpp.h │ ├── NetCDFSimple.h │ ├── NonCopyableMixin.h │ ├── OSPRay.h │ ├── OpacityMap.h │ ├── OpenMPSupport.h │ ├── OptionParser.h │ ├── PNGWriter.h │ ├── PVTime.h │ ├── ParamsBase.h │ ├── ParamsMgr.h │ ├── Particle.h │ ├── ParticleParams.h │ ├── ParticleRenderer.h │ ├── Progress.h │ ├── Proj4API.h │ ├── Proj4StringParser.h │ ├── PyEngine.h │ ├── PythonDataMgr.h │ ├── QuadTreeRectangle.hpp │ ├── QuadTreeRectangleP.h │ ├── RayCaster.h │ ├── RayCasterParams.h │ ├── RegularGrid.h │ ├── RenderParams.h │ ├── Renderer.h │ ├── ResourcePath.h │ ├── STLUtils.h │ ├── SetHDF5PluginPath.h │ ├── SettingsParams.h │ ├── Shader.h │ ├── ShaderManager.h │ ├── ShaderProgram.h │ ├── SignificanceMap.h │ ├── SliceParams.h │ ├── SliceRenderer.h │ ├── SphericalGrid.h │ ├── StretchedGrid.h │ ├── StructuredGrid.h │ ├── TFInterpolator.h │ ├── TIFWriter.h │ ├── TMSUtils.h │ ├── TextLabel.h │ ├── Texture.h │ ├── TrackBall.h │ ├── Transform.h │ ├── TwoDDataParams.h │ ├── TwoDDataRenderer.h │ ├── TwoDRenderer.h │ ├── UDUnitsClass.h │ ├── UnstructuredGrid.h │ ├── UnstructuredGrid2D.h │ ├── UnstructuredGrid3D.h │ ├── UnstructuredGridCoordless.h │ ├── UnstructuredGridLayered.h │ ├── VAssert.h │ ├── VDC.h │ ├── VDCNetCDF.h │ ├── VDC_c.h │ ├── VaporField.h │ ├── Version.h │ ├── Viewpoint.h │ ├── ViewpointParams.h │ ├── Visualizer.h │ ├── VisualizerGLContextManager.h │ ├── VolumeAlgorithm.h │ ├── VolumeCellTraversal.h │ ├── VolumeGLSL.h │ ├── VolumeIsoParams.h │ ├── VolumeIsoRenderer.h │ ├── VolumeOSPRay.h │ ├── VolumeParams.h │ ├── VolumeRectilinear.h │ ├── VolumeRegular.h │ ├── VolumeRenderer.h │ ├── VolumeResampled.h │ ├── VolumeTest.h │ ├── VolumeTest2.h │ ├── WASP.h │ ├── WaveCodecIO.h │ ├── WaveFiltBase.h │ ├── WaveFiltBior.h │ ├── WaveFiltCoif.h │ ├── WaveFiltDaub.h │ ├── WaveFiltHaar.h │ ├── WaveFiltInt.h │ ├── WireFrameParams.h │ ├── WireFrameRenderer.h │ ├── XmlNode.h │ ├── common.h │ ├── converter.h │ ├── debug.h │ ├── direntWin32.h │ ├── errorcodes.h │ ├── glutil.h │ ├── jpegapi.h │ ├── nanoflann.hpp │ ├── ptr_cache.hpp │ ├── regionparams.h │ ├── udunits2.h │ ├── utils.h │ └── vizutil.h ├── lib/ │ ├── CMakeLists.txt │ ├── common/ │ │ ├── Base16StringStream.cpp │ │ ├── CFuncs.cpp │ │ ├── CMakeConfig.cpp.in │ │ ├── CMakeLists.txt │ │ ├── EasyThreads.cpp │ │ ├── FileUtils.cpp │ │ ├── GetAppPath.cpp │ │ ├── LegacyVectorMath.cpp │ │ ├── MyBase.cpp │ │ ├── OptionParser.cpp │ │ ├── PVTime.cpp │ │ ├── Progress.cpp │ │ ├── ResourcePath.cpp │ │ ├── STLUtils.cpp │ │ ├── TMSUtils.cpp │ │ ├── VAssert.cpp │ │ ├── Version.cpp │ │ ├── common.cpp │ │ └── utils.cpp │ ├── flow/ │ │ ├── Advection.cpp │ │ ├── AdvectionIO.cpp │ │ ├── CMakeLists.txt │ │ ├── Field.cpp │ │ ├── Particle.cpp │ │ └── VaporField.cpp │ ├── osgl/ │ │ ├── CMakeCopy.cmake │ │ ├── CMakeLists.txt │ │ ├── GLContext.cpp │ │ ├── GLContextProvider.cpp │ │ ├── GLContextProviderEGL.cpp │ │ ├── GLContextProviderMacOS.mm │ │ ├── GLContextProviderMesa.cpp │ │ ├── GLContextProviderNvidia.cpp │ │ ├── GLContextProviderUtil.cpp │ │ ├── Log.cpp │ │ ├── build.sh │ │ ├── glad/ │ │ │ ├── include/ │ │ │ │ ├── EGL/ │ │ │ │ │ └── eglplatform.h │ │ │ │ ├── KHR/ │ │ │ │ │ └── khrplatform.h │ │ │ │ └── glad/ │ │ │ │ ├── egl.h │ │ │ │ └── gl.h │ │ │ └── src/ │ │ │ ├── egl.c │ │ │ └── gl.c │ │ ├── include/ │ │ │ └── vapor/ │ │ │ ├── GLAD.h │ │ │ ├── GLContext.h │ │ │ ├── GLContextProvider.h │ │ │ ├── GLContextProviderCommon.h │ │ │ ├── GLContextProviderEGL.h │ │ │ ├── GLContextProviderMacOS.h │ │ │ ├── GLContextProviderMesa.h │ │ │ ├── GLContextProviderNvidia.h │ │ │ ├── GLContextProviderUtil.h │ │ │ ├── GLInclude.h │ │ │ └── Log.h │ │ ├── meta.yaml │ │ ├── stb_image_write.h │ │ ├── test_framebuffer_glad.cpp │ │ └── test_version.cpp │ ├── params/ │ │ ├── AnimationParams.cpp │ │ ├── AnnotationParams.cpp │ │ ├── AxisAnnotation.cpp │ │ ├── BarbParams.cpp │ │ ├── BookmarkParams.cpp │ │ ├── Box.cpp │ │ ├── CMakeLists.txt │ │ ├── ColorMap.cpp │ │ ├── ColorbarPbase.cpp │ │ ├── ContourParams.cpp │ │ ├── DataStatus.cpp │ │ ├── DatasetsParams.cpp │ │ ├── FlowParams.cpp │ │ ├── GUIStateParams.cpp │ │ ├── HelloParams.cpp │ │ ├── ImageParams.cpp │ │ ├── MapperFunction.cpp │ │ ├── ModelParams.cpp │ │ ├── MouseModeParams.cpp │ │ ├── OpacityMap.cpp │ │ ├── ParamsBase.cpp │ │ ├── ParamsMgr.cpp │ │ ├── ParticleParams.cpp │ │ ├── RayCasterParams.cpp │ │ ├── RenderParams.cpp │ │ ├── SettingsParams.cpp │ │ ├── SliceParams.cpp │ │ ├── TFInterpolator.cpp │ │ ├── TODO.txt │ │ ├── Transform.cpp │ │ ├── TwoDDataParams.cpp │ │ ├── Viewpoint.cpp │ │ ├── ViewpointParams.cpp │ │ ├── VolumeIsoParams.cpp │ │ ├── VolumeParams.cpp │ │ ├── WireFrameParams.cpp │ │ ├── XmlNode.cpp │ │ └── regionparams.cpp │ ├── render/ │ │ ├── AnnotationRenderer.cpp │ │ ├── BarbRenderer.cpp │ │ ├── CMakeLists.txt │ │ ├── CalcEngineMgr.cpp │ │ ├── ColorbarRenderer.cpp │ │ ├── ContourRenderer.cpp │ │ ├── ControlExecutive.cpp │ │ ├── FlowRenderer.cpp │ │ ├── Font.cpp │ │ ├── FontManager.cpp │ │ ├── Framebuffer.cpp │ │ ├── GLManager.cpp │ │ ├── GeoImage.cpp │ │ ├── GeoImageGeoTiff.cpp │ │ ├── GeoImageTMS.cpp │ │ ├── GeoTIFWriter.cpp │ │ ├── GeoTile.cpp │ │ ├── GeoTileEquirectangular.cpp │ │ ├── GeoTileMercator.cpp │ │ ├── HelloRenderer.cpp │ │ ├── Histo.cpp │ │ ├── ImageRenderer.cpp │ │ ├── ImageWriter.cpp │ │ ├── JPGWriter.cpp │ │ ├── LegacyGL.cpp │ │ ├── MatrixManager.cpp │ │ ├── ModelRenderer.cpp │ │ ├── MyPython.cpp │ │ ├── NavigationUtils.cpp │ │ ├── OSPRay.cpp │ │ ├── PNGWriter.cpp │ │ ├── ParticleRenderer.cpp │ │ ├── Proj4StringParser.cpp │ │ ├── PyEngine.cpp │ │ ├── RayCaster.cpp │ │ ├── Renderer.cpp │ │ ├── Shader.cpp │ │ ├── ShaderManager.cpp │ │ ├── ShaderProgram.cpp │ │ ├── SliceRenderer.cpp │ │ ├── TIFWriter.cpp │ │ ├── TODO.txt │ │ ├── TextLabel.cpp │ │ ├── Texture.cpp │ │ ├── TrackBall.cpp │ │ ├── TwoDDataRenderer.cpp │ │ ├── TwoDRenderer.cpp │ │ ├── Visualizer.cpp │ │ ├── VolumeAlgorithm.cpp │ │ ├── VolumeCellTraversal.cpp │ │ ├── VolumeGLSL.cpp │ │ ├── VolumeIsoRenderer.cpp │ │ ├── VolumeOSPRay.cpp │ │ ├── VolumeRectilinear.cpp │ │ ├── VolumeRegular.cpp │ │ ├── VolumeRenderer.cpp │ │ ├── VolumeResampled.cpp │ │ ├── VolumeTest.cpp │ │ ├── VolumeTest2.cpp │ │ ├── WireFrameRenderer.cpp │ │ ├── glutil.cpp │ │ └── jfilewrite.cpp │ ├── vapi/ │ │ ├── CMakeLists.txt │ │ ├── RenderManager.cpp │ │ ├── RenderManager.h │ │ ├── Session.cpp │ │ ├── Session.h │ │ ├── VPCommon.h │ │ └── main.cpp │ ├── vdc/ │ │ ├── ArbitrarilyOrientedRegularGrid.cpp │ │ ├── BOVCollection.cpp │ │ ├── BlkMemMgr.cpp │ │ ├── CMakeLists.txt │ │ ├── ConstantGrid.cpp │ │ ├── CurvilinearGrid.cpp │ │ ├── DC.cpp │ │ ├── DCBOV.cpp │ │ ├── DCCF.cpp │ │ ├── DCMPAS.cpp │ │ ├── DCMelanie.cpp │ │ ├── DCP.cpp │ │ ├── DCRAM.cpp │ │ ├── DCUGRID.cpp │ │ ├── DCUtils.cpp │ │ ├── DCWRF.cpp │ │ ├── DataMgr.cpp │ │ ├── DataMgrUtils.cpp │ │ ├── DerivedParticleDensity.cpp │ │ ├── DerivedVar.cpp │ │ ├── DerivedVarMgr.cpp │ │ ├── GeoUtil.cpp │ │ ├── Grid.cpp │ │ ├── GridHelper.cpp │ │ ├── KDTreeRG.cpp │ │ ├── LayeredGrid.cpp │ │ ├── NetCDFCFCollection.cpp │ │ ├── NetCDFCollection.cpp │ │ ├── NetCDFSimple.cpp │ │ ├── Proj4API.cpp │ │ ├── PythonDataMgr.cpp │ │ ├── QuadTreeRectangleP.cpp │ │ ├── RegularGrid.cpp │ │ ├── StretchedGrid.cpp │ │ ├── StructuredGrid.cpp │ │ ├── TODO.txt │ │ ├── UDUnitsClass.cpp │ │ ├── UnstructuredGrid.cpp │ │ ├── UnstructuredGrid2D.cpp │ │ ├── UnstructuredGrid3D.cpp │ │ ├── UnstructuredGridLayered.cpp │ │ ├── VDC.cpp │ │ ├── VDCNetCDF.cpp │ │ ├── VDC_c.cpp │ │ ├── kdtree.c │ │ ├── kdtree.h │ │ └── vizutil.cpp │ └── wasp/ │ ├── CMakeLists.txt │ ├── Compressor.cpp │ ├── MatWaveBase.cpp │ ├── MatWaveDwt.cpp │ ├── MatWaveWavedec.cpp │ ├── NOTES │ ├── NetCDFCpp.cpp │ ├── SignificanceMap.cpp │ ├── TODO │ ├── WASP.cpp │ ├── WaveFiltBase.cpp │ ├── WaveFiltBior.cpp │ ├── WaveFiltCoif.cpp │ ├── WaveFiltDaub.cpp │ ├── WaveFiltHaar.cpp │ └── WaveFiltInt.cpp ├── plugins/ │ ├── paraview/ │ │ ├── CMakeLists.txt │ │ ├── README │ │ ├── VDFReader.xml │ │ ├── VDFReaderGUI.xml │ │ ├── vtkVDFReader.cxx │ │ └── vtkVDFReader.h │ └── visit/ │ ├── VDC/ │ │ ├── README │ │ ├── avtvdfFileFormat.C │ │ ├── avtvdfFileFormat.h │ │ ├── avtvdfOptions.C │ │ ├── avtvdfOptions.h │ │ ├── vdf.xml │ │ ├── vdf2.xml │ │ ├── vdfCommonPluginInfo.C │ │ ├── vdfEnginePluginInfo.C │ │ ├── vdfMDServerPluginInfo.C │ │ ├── vdfPluginInfo.C │ │ └── vdfPluginInfo.h │ └── WASP/ │ ├── README │ ├── WASP.xml │ ├── WASPCommonPluginInfo.C │ ├── WASPEnginePluginInfo.C │ ├── WASPMDServerPluginInfo.C │ ├── WASPPluginInfo.C │ ├── WASPPluginInfo.h │ ├── avtWASPFileFormat.C │ └── avtWASPFileFormat.h ├── scripts/ │ ├── CMakeLists.txt │ ├── build3rdParty.sh │ ├── getWMSImage.sh │ ├── ptcl2vms.py │ ├── vapor-setup-win32.csh │ ├── vapor-setup-win32.sh │ ├── vapor-setup.bat │ ├── vapor-setup.csh.sed │ ├── vapor-setup.sh.sed │ ├── vaporBatchFuncs.py │ ├── vaporLSF.py │ ├── vaporSGE.py │ ├── vdccp │ ├── vdfbkup.pl │ └── wrf2vdfbatch ├── share/ │ ├── CMakeLists.txt │ ├── Doxygen/ │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ ├── Doxyfile.in │ │ ├── TODO │ │ └── mainpage.dox │ ├── doc/ │ │ ├── DCP_Format.md │ │ ├── VaporPythonGuide.doc │ │ ├── help/ │ │ │ ├── FieldLineAdvectionHelp.html │ │ │ └── UnsteadyHelp.html │ │ └── man/ │ │ ├── asciitf2vtf.pod │ │ ├── getWMSImage.pod │ │ ├── ptcl2vms.pod │ │ ├── raw2wasp.pod │ │ ├── tiff2geotiff.pod │ │ ├── vdccp.py.pod │ │ ├── vdcdump.pod │ │ ├── wasp2raw.pod │ │ └── waspcreate.pod │ ├── docker/ │ │ ├── centos7/ │ │ │ └── Dockerfile │ │ └── ubuntu18/ │ │ └── Dockerfile │ ├── examples/ │ │ ├── .vapor3_prefs │ │ ├── .vapor_prefs │ │ ├── NCL/ │ │ │ ├── USFilled.ncl │ │ │ ├── USOutline.ncl │ │ │ ├── WrfTestScripts.Notes │ │ │ ├── worldFilled.ncl │ │ │ ├── worldOutline.ncl │ │ │ ├── wrf2geotiff.ncl │ │ │ ├── wrf_CrossSection2.ncl │ │ │ ├── wrf_CrossSection2_Final.ncl │ │ │ ├── wrf_CrossSection2_FirstMod.ncl │ │ │ ├── wrf_EtaLevels.ncl │ │ │ ├── wrf_Height.ncl │ │ │ ├── wrf_Height_Final.ncl │ │ │ ├── wrf_Height_FirstMod.ncl │ │ │ ├── wrf_Precip.ncl │ │ │ ├── wrf_Precip_Final.ncl │ │ │ ├── wrf_Precip_FirstMod.ncl │ │ │ ├── wrf_Surface1.ncl │ │ │ ├── wrf_cloud.ncl │ │ │ ├── wrf_crossSection4.ncl │ │ │ └── wrf_pv.ncl │ │ ├── VDC/ │ │ │ └── amr_ex.cpp │ │ ├── generateExampleDCP.py │ │ ├── idl/ │ │ │ ├── AddCurlVDF.pro │ │ │ ├── AddDivVDF.pro │ │ │ ├── AddMagVDF.pro │ │ │ ├── AddWRFCurl.pro │ │ │ ├── AddWRFDiv.pro │ │ │ ├── AddWRFETH.pro │ │ │ ├── MakeCmbo.pro │ │ │ ├── MakeLinCmb.pro │ │ │ ├── PrintMetaVDF.pro │ │ │ ├── QuickStartEx1.pro │ │ │ ├── README.txt │ │ │ ├── ReadRegionVDF.pro │ │ │ ├── ReadVDF.pro │ │ │ ├── WRFVortMagEx.pro │ │ │ ├── WriteTimeVaryVDF.pro │ │ │ ├── WriteVDF.pro │ │ │ ├── curl_findiff.pro │ │ │ ├── deriv_findiff.pro │ │ │ ├── div_findiff.pro │ │ │ ├── elev_deriv.pro │ │ │ ├── expregion.pro │ │ │ ├── impexp.pro │ │ │ ├── impregion.pro │ │ │ ├── marschner_lobb.pro │ │ │ ├── myderiv.pro │ │ │ ├── pencil2vapor.pro │ │ │ ├── wrf_curl_findiff.pro │ │ │ └── wrf_div_findiff.pro │ │ └── listOfSeeds.txt │ ├── gitHooks/ │ │ ├── pre-push │ │ └── setupHooks.sh │ ├── images/ │ │ └── VAPOR.icns │ ├── notices/ │ │ └── __example-notice.json │ ├── palettes/ │ │ ├── Diverging/ │ │ │ ├── BlueWhiteGold.tf3 │ │ │ ├── CoolWarm.tf3 │ │ │ ├── CoolWarmBent.tf3 │ │ │ ├── CoolWarmSmooth.tf3 │ │ │ ├── GreenWhitePurple.tf3 │ │ │ ├── GreenWhiteRed.tf3 │ │ │ ├── PurpleWhiteOrange.tf3 │ │ │ ├── balance.tf3 │ │ │ ├── curl.tf3 │ │ │ ├── delta.tf3 │ │ │ ├── diff.tf3 │ │ │ └── tarn.tf3 │ │ ├── Highlighting/ │ │ │ ├── oxy.tf3 │ │ │ └── topo.tf3 │ │ └── Sequential/ │ │ ├── BlackBody.tf3 │ │ ├── BlackBodyExtended.tf3 │ │ ├── BlackWhite.tf3 │ │ ├── Kindlmann.tf3 │ │ ├── KindlmannExtended.tf3 │ │ ├── Rainbow.tf3 │ │ ├── algae.tf3 │ │ ├── amp.tf3 │ │ ├── deep.tf3 │ │ ├── dense.tf3 │ │ ├── haline.tf3 │ │ ├── ice.tf3 │ │ ├── matter.tf3 │ │ ├── phase.tf3 │ │ ├── rain.tf3 │ │ ├── solar.tf3 │ │ ├── speed.tf3 │ │ ├── tempo.tf3 │ │ ├── thermal.tf3 │ │ └── turbid.tf3 │ ├── python/ │ │ ├── imagewriter.py │ │ ├── plot.py │ │ ├── plot1D.py │ │ ├── pythonSystemStartup.py │ │ ├── vapor_utils.py │ │ └── vapor_wrf.py │ ├── shaders/ │ │ ├── .gitattributes │ │ ├── 2DData.frag │ │ ├── 2DData.vert │ │ ├── BBTraversalAlgorithms.frag │ │ ├── BBTraversalAlgorithmsNV.frag │ │ ├── Contour.frag │ │ ├── Contour.vert │ │ ├── DepthBuffer.frag │ │ ├── DepthBuffer.vert │ │ ├── FlowGlyphsArrow.frag │ │ ├── FlowGlyphsArrow.geom │ │ ├── FlowGlyphsArrow.vert │ │ ├── FlowGlyphsArrow2D.frag │ │ ├── FlowGlyphsArrow2D.geom │ │ ├── FlowGlyphsArrow2D.vert │ │ ├── FlowGlyphsLineDirArrow2D.frag │ │ ├── FlowGlyphsLineDirArrow2D.geom │ │ ├── FlowGlyphsLineDirArrow2D.vert │ │ ├── FlowGlyphsSphere2D.frag │ │ ├── FlowGlyphsSphere2D.geom │ │ ├── FlowGlyphsSphere2D.vert │ │ ├── FlowGlyphsSphereSplat.frag │ │ ├── FlowGlyphsSphereSplat.geom │ │ ├── FlowGlyphsSphereSplat.vert │ │ ├── FlowGlyphsTubeDirArrow.frag │ │ ├── FlowGlyphsTubeDirArrow.geom │ │ ├── FlowGlyphsTubeDirArrow.vert │ │ ├── FlowInclude.geom │ │ ├── FlowLine.frag │ │ ├── FlowLine.vert │ │ ├── FlowLines.frag │ │ ├── FlowLines.geom │ │ ├── FlowLines.vert │ │ ├── FlowTubes.frag │ │ ├── FlowTubes.geom │ │ ├── FlowTubes.vert │ │ ├── Framebuffer.frag │ │ ├── Framebuffer.vert │ │ ├── FramebufferND.frag │ │ ├── FramebufferND.vert │ │ ├── GenerateBBTraversals.pl │ │ ├── GenerateBBTraversalsNvidia.pl │ │ ├── GenerateUniversalBBTraversal.pl │ │ ├── Image.frag │ │ ├── Image.vert │ │ ├── Legacy.frag │ │ ├── Legacy.vert │ │ ├── ParticleDirection.frag │ │ ├── ParticleDirection.geom │ │ ├── ParticleDirection.vert │ │ ├── ParticlePoint.frag │ │ ├── ParticlePoint.geom │ │ ├── ParticlePoint.vert │ │ ├── ProgTexture.efc │ │ ├── Slice.frag │ │ ├── Slice.vert │ │ ├── VolumeBase.frag │ │ ├── VolumeCellBase.frag │ │ ├── VolumeCellDVR.frag │ │ ├── VolumeCellDVR.vert │ │ ├── VolumeCellIso.frag │ │ ├── VolumeCellIso.vert │ │ ├── VolumeDVR.frag │ │ ├── VolumeDVR.vert │ │ ├── VolumeIso.frag │ │ ├── VolumeIso.vert │ │ ├── VolumeIsoInclude.frag │ │ ├── VolumeRayMath.frag │ │ ├── VolumeRectilinearDVR.frag │ │ ├── VolumeRectilinearDVR.vert │ │ ├── VolumeRectilinearIso.frag │ │ ├── VolumeRectilinearIso.vert │ │ ├── White.frag │ │ ├── White.vert │ │ ├── Wireframe.frag │ │ ├── Wireframe.vert │ │ ├── depthpeeling.efc │ │ ├── font.frag │ │ ├── font.vert │ │ ├── includes/ │ │ │ ├── alphagradient.hgl │ │ │ ├── cart2sph.hgl │ │ │ ├── datagradient.hgl │ │ │ ├── depthpeeling.hgl │ │ │ ├── gradient.hgl │ │ │ ├── gradient2.hgl │ │ │ ├── invpermute.hgl │ │ │ ├── permute.hgl │ │ │ └── tex2lay.hgl │ │ ├── main/ │ │ │ ├── 2DData.fgl │ │ │ ├── 2DData.vgl │ │ │ ├── Iso.fgl │ │ │ ├── Iso.vgl │ │ │ ├── ProgTexture.fgl │ │ │ ├── ProgTexture.vgl │ │ │ ├── SphericalDVR.fgl │ │ │ ├── SphericalDVR.vgl │ │ │ ├── depthpeeling.fgl │ │ │ ├── depthpeeling.vgl │ │ │ ├── texSampler.fgl │ │ │ └── texSampler.vgl │ │ └── texSampler.efc │ └── udunits/ │ ├── udunits2-accepted.xml │ ├── udunits2-base.xml │ ├── udunits2-common.xml │ ├── udunits2-derived.xml │ ├── udunits2-prefixes.xml │ └── udunits2.xml ├── site_files/ │ └── site.NCAR └── test_apps/ ├── CMakeLists.txt ├── OpenMP/ │ ├── CMakeLists.txt │ └── GetRange.cpp ├── ParamsMgr/ │ ├── CMakeLists.txt │ ├── file.xml │ └── test_ParamsMgr.cpp ├── TransferFunction/ │ └── test_TransferFunction.cpp ├── base64/ │ ├── CMakeLists.txt │ └── test_base64.cpp ├── controlExec/ │ ├── CMakeLists.txt │ ├── file.xml │ ├── moc_test_vizwin.cpp │ ├── test_CE.cpp │ ├── test_vizwin.cpp │ └── test_vizwin.h ├── datamgr/ │ ├── CMakeLists.txt │ └── test_datamgr.cpp ├── grid_iter/ │ ├── CMakeLists.txt │ └── test_grid_iter.cpp ├── params/ │ ├── file.xml │ └── test_params.cpp ├── params2/ │ ├── CMakeLists.txt │ └── test_params2.cpp ├── pyengine/ │ ├── CMakeLists.txt │ └── test_pyengine.cpp ├── quadtreerectangle/ │ ├── CMakeLists.txt │ └── test_quadtreerectangle.cpp ├── render_regression_tests/ │ ├── README.md │ ├── config.yaml │ ├── run_config.py │ └── run_test.py ├── smokeTests/ │ ├── CMakeLists.txt │ ├── dataMgrTools.cpp │ ├── dataMgrTools.h │ ├── gridTools.cpp │ ├── gridTools.h │ ├── smokeTests.py │ ├── testDataMgr.cpp │ ├── testGrid.cpp │ └── testResults/ │ ├── cf_baseline.txt │ ├── vdc_baseline.txt │ └── wrf_baseline.txt ├── udunits/ │ ├── CMakeLists.txt │ └── test_udunits.cpp ├── vdc3test/ │ ├── test.csh │ └── vdc3test.csh └── xmlnode/ └── test_xmlnode.cpp ================================================ FILE CONTENTS ================================================ ================================================ FILE: .circleci/config.yml ================================================ anchors: - &srcLibs "2024-Sept-src" - &macOSx86Libs "2024-Sept-macOSx86" - &appleSiliconLibs "2024-Sept-appleSilicon" - &u20Libs "2025-July-Ubuntu20" version: 2.1 orbs: win: circleci/windows@2.2.0 references: workspace_root: &workspace_root /tmp/workspace attach_workspace: &attach_workspace attach_workspace: at: *workspace_root commands: get_libraries: parameters: useAWS: type: boolean default: true fileName: type: string sudo: type: string default: "" dir: type: string default: "/usr/local/VAPOR-Deps" steps: - run: name: get third party libraries command: | # if /usr/local/VAPOR-Deps is empty, acquire libraries if [ ! -d <> ]; then <> mkdir -p <> <> chmod -R 777 <> <> chown -R `whoami` <> wget https://vaporawsbucket.s3.us-west-2.amazonaws.com/<>.tar.xz tar -xf <>.tar.xz -C <> fi build_vapor: parameters: branch: type: string default: $CIRCLE_BRANCH beforeCompile: type: string default: "" compileArgs: type: string default: "" moveToCommand: type: string libDir: type: string default: "/usr/local/VAPOR-Deps" libName: type: string default: 2023-Sept steps: - run: name: build vapor command: | libraryDir=`ls <>` ln -s $libraryDir <>/current cp site_files/site.NCAR site.local mkdir -p build cd build git checkout <> <> cmake \ -DCMAKE_BUILD_TYPE:String=Release \ -DDIST_INSTALLER:string=ON \ -DUSE_OMP=ON \ <> \ -DTHIRD_PARTY_DIR=<>/current .. make -j4 make installer for f in VAPOR3-* ; do mv "$f" "<>" ; done mkdir -p /tmp/workspace/installers find VAPOR* -maxdepth 1 -type f \( -name "*.AppImage" -o -name "*.exe" -o -name "*.dmg" \) -exec mv {} /tmp/workspace/installers \; ls /tmp/workspace/installers no_output_timeout: 30m - store_artifacts: path: /tmp/workspace/installers - persist_to_workspace: root: *workspace_root paths: - installers smoke_tests: steps: - restore_cache: name: restore smoke test data keys: - smoke-test-data - run: name: Acquire smoke test data command: | if [ -z "$(ls -A /smokeTestData)" ]; then mkdir -p /smokeTestData wget https://vaporawsbucket.s3.us-west-2.amazonaws.com/smokeTestData.tar.gz tar --no-same-owner -xf /root/project/smokeTestData.tar.gz -C /smokeTestData chown -R root:root /smokeTestData chmod -R 777 /smokeTestData else echo "Data already acquired" fi - save_cache: key: smoke-test-data paths: - /smokeTestData - run: name: Smoke tests command: | python3 ~/project/test_apps/smokeTests/smokeTests.py \ -testDataRoot=/smokeTestData/smokeTestData \ -binaryRoot=~/project/build/test_binaries \ -resultsDir=~/project/test_apps/smokeTests/testResults - store_artifacts: path: ~/project/test_apps/smokeTests/testResults get_macos_dependencies: steps: - run: name: Get dependencies command: | #Caching clang would miss every couple of weeks and require ~2 hours of build time. #Instead of caching it, we're just going to host it on aws and download it. wget https://vaporawsbucket.s3.us-west-2.amazonaws.com/portClang.tar.xz sudo tar -xf portClang.tar.xz -C / brew install cmake no_output_timeout: 45m jobs: build_win10_installer: executor: win/default steps: - checkout - run: name: Install dependencies command: | choco install visualstudio2019-workload-vctools -y choco install python -y choco install git -y choco install cmake --version=3.31.6 -y choco install nsis -y python -m pip install gdown setx /M PATH "%PATH%;C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin" msbuild -version pwd ls python .circleci/downloadWin3rdParty.py no_output_timeout: 20m - run: name: dos2unix command: | dos2unix /c/Users/circleci/project/share/shaders/* dos2unix /c/Users/circleci/project/share/shaders/main dos2unix /c/Users/circleci/project/share/shaders/includes shell: bash.exe - run: name: Build Vapor command: | Copy-Item site_files\* -Destination . mkdir build cd build git checkout $CIRCLE_BRANCH & 'C:\\Program Files\\CMake\\bin\\cmake.exe' -S C:\Users\circleci\project -B C:\Users\circleci\project\build -DDIST_INSTALLER:string=ON -DCMAKE_BUILD_TYPE:STRING=Release -DBUILD_OSP=OFF -G 'Visual Studio 16 2019' -A x64 msbuild C:\Users\circleci\project\build\PACKAGE.vcxproj /p:Configuration=Release /p:Platform=x64 mkdir -p C:\Users\circleci\project\tmp\workspace\installers Copy-Item C:\Users\circleci\project\build\*.exe -Destination C:\Users\circleci\project\tmp\workspace\installers if (!(Test-Path -Path C:\Users\circleci\project\tmp\workspace\installers\*.exe)) { Write-Error "Build failed: No installers found" exit 1 } no_output_timeout: 45m - store_artifacts: path: C:\Users\circleci\project\tmp\workspace\installers - persist_to_workspace: root: C:\Users\circleci\project\tmp\workspace paths: - installers build_macOSx86_installer: macos: xcode: "14.3.1" resource_class: m4pro.large steps: - checkout - get_libraries: fileName: *macOSx86Libs sudo: sudo - get_macos_dependencies - build_vapor: beforeCompile: export PATH=/opt/local/bin:$PATH; softwareupdate --install-rosetta --agree-to-license compileArgs: | -DCMAKE_BUILD_TYPE:String=Release \ -DDIST_INSTALLER:string=ON \ -DUSE_OMP=ON \ -DCPACK_BINARY_DRAGNDROP=ON \ -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang \ -DCMAKE_OSX_ARCHITECTURES=x86_64 \ -DTHIRD_PARTY_DIR=/usr/local/VAPOR-Deps/current \ moveToCommand: ${f/Darwin/macOSx86} build_appleSilicon_installer: macos: xcode: "14.3.1" resource_class: m4pro.large steps: - checkout - get_libraries: fileName: *appleSiliconLibs sudo: sudo - get_macos_dependencies - build_vapor: beforeCompile: export PATH=/opt/local/bin:$PATH compileArgs: | -DCMAKE_BUILD_TYPE:String=Release \ -DDIST_INSTALLER:string=ON \ -DUSE_OMP=ON \ -DCPACK_BINARY_DRAGNDROP=ON \ -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang \ -DTHIRD_PARTY_DIR=/usr/local/VAPOR-Deps/current \ moveToCommand: ${f/Darwin/AppleSilicon} build_python_api_ubuntuDebug: docker: - image: conda/miniconda3 # Debian based docker image resource_class: xlarge steps: - checkout - run: name: conda build . command: | cd /root/project/conda conda update -y -n base -c defaults conda conda install -y conda-build conda config --add channels conda-forge conda config --add channels ncar-vapor conda build . mkdir /usr/local/conda-bld/linux-64/tarBallDir mv /usr/local/conda-bld/linux-64/*.tar.bz2 /usr/local/conda-bld/linux-64/tarBallDir no_output_timeout: 180m - store_artifacts: path: /usr/local/conda-bld/linux-64/tarBallDir build_python_api_ubuntu: docker: - image: conda/miniconda3 # Debian based docker image resource_class: large steps: - checkout - run: name: acquire map image archive command: | cd /root # The following resolves the error "E: The repository 'http://security.debian.org/debian-security stretch/updates Release' does not have a Release file." echo "deb http://archive.debian.org/debian stretch main contrib non-free" > /etc/apt/sources.list apt update apt install -y git git clone https://github.com/NCAR/VAPOR-Data.git - run: name: build conda installer command: | conda update -y -n base -c defaults conda conda config --add channels ncar-vapor conda config --add channels conda-forge conda install -y conda-build cd /root/project/conda #conda build . DEBUG_BUILD=false MAP_IMAGES_PATH="/root/VAPOR-Data/images" conda build . mkdir /usr/local/conda-bld/linux-64/tarBallDir mv /usr/local/conda-bld/linux-64/*.tar.bz2 /usr/local/conda-bld/linux-64/tarBallDir no_output_timeout: 180m - store_artifacts: path: /usr/local/conda-bld/linux-64/tarBallDir build_python_api_osx: macos: xcode: "13.4.1" steps: - checkout - run: name: install miniconda command: | brew install wget wget https://repo.continuum.io/miniconda/Miniconda3-py39_4.9.2-MacOSX-x86_64.sh -O ~/miniconda.sh bash ~/miniconda.sh -b -p ~/miniconda - run: name: acquire map image archive command: | cd /Users/distiller git clone https://github.com/NCAR/VAPOR-Data.git - run: name: conda build . command: | cd /Users/distiller/project/conda /Users/distiller/miniconda/bin/conda install -y conda-build anaconda conda-verify /Users/distiller/miniconda/bin/conda config --add channels conda-forge DEBUG_BUILD=false MAP_IMAGES_PATH="/Users/distiller/VAPOR-Data/images" /Users/distiller/miniconda/bin/conda build . mkdir -p /tmp/workspace/installers mv /Users/distiller/miniconda/conda-bld/osx-64/*.tar.bz2 /tmp/workspace/installers cd /tmp/workspace/installers fileName=${ls} newFileName=${fileName//vapor/vaporUbuntu} no_output_timeout: 30m - store_artifacts: path: /tmp/workspace/installers suse_smoke_tests: docker: - image: opensuse/leap resource_class: medium steps: - suse_prerequisites - attach_workspace: at: / - smoke_tests build_linux_installer: docker: - image: ubuntu:20.04 resource_class: xlarge steps: - checkout - run: name: acquire prerequisites command: | export DEBIAN_FRONTEND=noninteractive apt update apt install -y libffi-dev apt install -y curl apt install -y xz-utils apt install -y git apt install -y g++ apt install -y libomp-dev apt install -y freeglut3-dev apt install -y libexpat1-dev apt install -y libglib2.0-0 apt install -y libdbus-1-3 apt install -y valgrind apt install -y clang-tidy apt install -y lsb-release apt install -y python3-pip pip3 install gdown git config --global --add safe.directory /tmp/_circleci_local_build_repo # all for cmake apt-get update apt-get install -y gpg wget wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null DEBIAN_FRONTEND=noninteractive apt install -y software-properties-common apt-add-repository -y 'deb https://apt.kitware.com/ubuntu/ focal main' apt install -y cmake --allow-unauthenticated # for AppImage apt install -y \ libxcb-icccm4-dev \ libxcb-image0 \ libxcb-keysyms1 \ libxcb-render-util0 \ libxkbcommon-x11-0 \ desktop-file-utils - restore_cache: name: restore intel's oneapi keys: - intelOneapi - run: name: acquire intel hpckit for bundling ospray command: | # if not restored from cache, acquire oneapi if [ ! -d /opt/intel/oneapi ]; then # For bundling Ospray, which wants Intel's MPI implementation to be bundled apt install -y linux-headers-5.15.0-1053-aws wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | tee /etc/apt/sources.list.d/oneAPI.list apt update apt install -y intel-hpckit fi - save_cache: key: intelOneapi paths: - /opt/intel/oneapi - get_libraries: fileName: *u20Libs - build_vapor: moveToCommand: ${f/Linux/Ubuntu20} compileArgs: | -DDIST_APPIMAGE=ON \ -DBUILD_TEST_APPS=ON \ - smoke_tests release_weekly_installers: macos: xcode: "14.3.1" steps: - checkout - *attach_workspace - run: name: publish release command: | cd /Users/distiller/project hash=`git rev-parse HEAD` tag="Weekly" cd /tmp/workspace/installers brew install ghr brew install gh current_date=$(date -u +"%Y-%m-%dT%H:%M:%SZ") release_date=$(gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/NCAR/VAPOR/releases/latest --jq ".published_at") current_date_sec=$(date -jf "%Y-%m-%dT%H:%M:%SZ" "$current_date" +"%s") release_date_sec=$(date -jf "%Y-%m-%dT%H:%M:%SZ" "$release_date" +"%s") weeks_since_release=$(( ($current_date_sec - $release_date_sec) / 604800 )) for installer in VAPOR*3*; do extension="${installer##*.}" new_name="${installer%.*}-w$weeks_since_release.$extension" mv "$installer" "$new_name" done endl=$'\n' title="sha 256"$endl a="AppImage: " sha=`shasum -a 256 VAPOR*.AppImage` linuxSha=$a$sha$endl os="OSX: " sha=`shasum -a 256 VAPOR*x86*.dmg` osxSha=$os$sha$endl os="AppleSilicon: " sha=`shasum -a 256 VAPOR*AppleSilicon*.dmg` siliconSha=$os$sha$endl os="Windows: " sha=`shasum -a 256 VAPOR*.exe` winSha=$os$sha$endl shaMessage="$title$linuxSha$osxSha$siliconSha$winSha" date=`date +"%d_%m_%y"` echo "$shaMessage" echo "$shaMessage" > "/tmp/workspace/installers/sha256.txt" echo ghr -b "Weekly installers are untested an may not be stable. Built with commit ${hash} on ${date} \(DD-MM-YY\)" -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -prerelease -c ${CIRCLE_SHA1} -recreate -c ${hash} -n ${tag} ${tag} /tmp/workspace/installers ghr -b "Weekly installers are untested an may not be stable. Built with commit ${hash} on ${date} \(DD-MM-YY\)" -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -prerelease -c ${CIRCLE_SHA1} -recreate -c ${hash} -n ${tag} ${tag} /tmp/workspace/installers build_ubuntu20_libs: docker: - image: ubuntu:20.04 resource_class: xlarge steps: - run: name: acquire prerequisites command: | DEBIAN_FRONTEND=noninteractive apt update apt install -y xz-utils git curl libomp-dev git config --global --add safe.directory /tmp/_circleci_local_build_repo - checkout - get_libraries: fileName: 2023-Sept-src.tar.xz #driveID: *srcLibID - run: name: build libraries command: | chmod 777 /root/project/scripts/build3rdParty.sh /root/project/scripts/build3rdParty.sh -o Ubuntu no_output_timeout: 60m - build_vapor: moveToCommand: ${f/Linux/Ubuntu20} - store_artifacts: path: /tmp/workspace/installers - store_artifacts: path: /usr/local/VAPOR-Deps/2023-Sept-Ubuntu.tar.xz build_macOSx86_libs: macos: xcode: "13.4.1" resource_class: macos.x86.medium.gen2 steps: - checkout - run: name: Get MacPorts command: | curl -k -O https://distfiles.macports.org/MacPorts/MacPorts-2.7.1.tar.bz2 tar xf MacPorts-2.7.1.tar.bz2 cd MacPorts-2.7.1/ ./configure make -j6 sudo make install - run: name: Get clang13 command: | sudo /opt/local/bin/port selfupdate (sudo yes || true) | sudo /opt/local/bin/port install clang-13 sudo /opt/local/bin/port select --set clang mp-clang-13 /opt/local/bin/clang++ -v > clangVersion.txt no_output_timeout: 30m - get_libraries: fileName: *srcLibs sudo: sudo - run: name: build libraries command: | chmod 777 /Users/distiller/project/scripts/build3rdParty.sh /Users/distiller/project/scripts/build3rdParty.sh -o macOSx86 - build_vapor: beforeCompile: export PATH=/opt/local/bin:$PATH; softwareupdate --install-rosetta --agree-to-license; sudo port select --set clang mp-clang-13 compileArgs: | -DCPACK_BINARY_DRAGNDROP=ON \ -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_C_COMPILER=clang \ -DMACOS_BUILD_ARM64=OFF \ -DCMAKE_OSX_ARCHITECTURES=x86_64 \ moveToCommand: ${f/Darwin/macOSx86} - store_artifacts: path: /tmp/workspace/installers - store_artifacts: path: /usr/local/VAPOR-Deps build_AppleSilicon_libs: macos: xcode: "13.4.1" resource_class: macos.m1.large.gen1 steps: - checkout - get_libraries: driveID: *srcLibs sudo: sudo - run: name: Get MacPorts command: | curl -k -O https://distfiles.macports.org/MacPorts/MacPorts-2.7.1.tar.bz2 tar xf MacPorts-2.7.1.tar.bz2 cd MacPorts-2.7.1/ ./configure make -j8 sudo make install - run: name: Get clang13 command: | sudo /opt/local/bin/port selfupdate (sudo yes || true) | sudo /opt/local/bin/port install clang-13 sudo /opt/local/bin/port select --set clang mp-clang-13 /opt/local/bin/clang++ -v > clangVersion.txt no_output_timeout: 30m - run: name: build libraries command: | chmod 777 /Users/distiller/project/scripts/build3rdParty.sh /Users/distiller/project/scripts/build3rdParty.sh -o appleSilicon - build_vapor: beforeCompile: export PATH=/opt/local/bin:$PATH compileArgs: | -DCPACK_BINARY_DRAGNDROP=ON \ -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_C_COMPILER=clang \ moveToCommand: ${f/Darwin/AppleSilicon} - store_artifacts: path: /tmp/workspace/installers - store_artifacts: path: /usr/local/VAPOR-Deps build_win10_libs: executor: win/default steps: - checkout - run: name: get source files command: | gdown https://drive.google.com/uc?id=1FG8ngmz9Tk3HKZgGejqwtbkBAVonm91z tar xvf ${filename} -C /usr/local/VAPOR-Deps msbuild -version - run: name: build libraries command: | chmod 777 /root/project/scripts/build3rdParty.sh /root/project/scripts/build3rdParty.sh -o Windows - store_artifacts: path: C:\Users\circleci\project\tmp\workspace\installers workflows: version: 2 build: jobs: #- build_python_api_ubuntuDebug #- build_python_api_ubuntu #- build_python_api_osx - build_win10_installer # - build_macOS_installers # - build_appleSilicon_installer # - build_macOSx86_installer - build_linux_installer #- build_suse_installer #- build_ubuntu20_libs # - build_macOSx86_libs #- build_AppleSilicon_libs #- build_suse_libs # - build_windows_libs # - release_weekly_installers # - release_weekly_installers: # requires: # - build_win10_installer # - build_appleSilicon_installer # - build_macOSx86_installer # - build_linux_installer weekly: triggers: - schedule: cron: "30 17 * * 1" #Time is GMT filters: branches: only: main jobs: - build_linux_installer - build_appleSilicon_installer - build_macOSx86_installer - build_win10_installer #- build_macOS_installers #- build_python_api_ubuntu #- build_python_api_osx - release_weekly_installers: requires: - build_linux_installer - build_appleSilicon_installer - build_macOSx86_installer - build_win10_installer #- build_macOS_installers #- build_python_api_ubuntu #- build_python_api_osx ================================================ FILE: .circleci/downloadWin3rdParty.py ================================================ import gdown url = "https://drive.google.com/a/ucar.edu/uc?id=1fzZ-mbY4Cek1TRsaKm79a08Od5gNCogk" output = "2019-Aug-Win32.zip" gdown.download(url, output, quiet=False) import zipfile with zipfile.ZipFile("2019-Aug-Win32.zip", 'r') as zip_ref: zip_ref.extractall('C:\\') ================================================ FILE: .clang-format ================================================ --- Language: Cpp # BasedOnStyle: LLVM AccessModifierOffset: -4 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveBitFields: true AlignConsecutiveDeclarations: true AlignConsecutiveMacros: true AlignEscapedNewlines: Left AlignOperands: AlignAfterOperator AlignTrailingComments: true AllowAllArgumentsOnNextLine: true AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: Always AllowShortCaseLabelsOnASingleLine: true AllowShortEnumsOnASingleLine: true AllowShortFunctionsOnASingleLine: All AllowShortIfStatementsOnASingleLine: WithoutElse AllowShortLambdasOnASingleLine: All AllowShortLoopsOnASingleLine: true AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: MultiLine BinPackArguments: true BinPackParameters: true BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: WebKit BreakBeforeTernaryOperators: true BreakConstructorInitializers: BeforeColon BreakInheritanceList: BeforeColon BreakStringLiterals: false ColumnLimit: 200 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 0 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DeriveLineEnding: true DerivePointerAlignment: false DisableFormat: false FixNamespaceComments: true ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH IncludeBlocks: Preserve IndentCaseBlocks: false IndentCaseLabels: false IndentExternBlock: NoIndent IndentGotoLabels: true IndentPPDirectives: BeforeHash IndentWidth: 4 IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: false MaxEmptyLinesToKeep: 3 NamespaceIndentation: None PointerAlignment: Right ReflowComments: true SortIncludes: false SortUsingDeclarations: true SpaceAfterCStyleCast: false SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: false SpaceBeforeAssignmentOperators: true SpaceBeforeCpp11BracedList: false SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeRangeBasedForLoopColon: true SpaceBeforeSquareBrackets: false SpaceInEmptyBlock: false SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 4 SpacesInAngles: false SpacesInCStyleCastParentheses: false SpacesInConditionalStatement: false SpacesInContainerLiterals: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Latest StatementMacros: - Q_UNUSED - QT_REQUIRE_VERSION TabWidth: 4 UseCRLF: false UseTab: Never ... ================================================ FILE: .editorconfig ================================================ [*.{c,cpp,h,pl,frag,vert}] indent_style = tab indent_size = 4 ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a bug report title: '' labels: Bug assignees: '' --- ### Describe the bug A clear and concise description of what the bug is. **Helpful additional information** (*Please click check boxes AFTER submitting ticket*) - [ ] Did VAPOR crash? - [ ] Did you get wrong results? **Impact** - [ ] High - User productivity significantly degraded - [ ] Medium - User productivity partially degraded - [ ] Low - User productivity trivially degraded ### To Reproduce Steps to reproduce the behavior. For example: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error *Additionally, please attach a session file to this ticket to easily reproduce (use File->Save Session).* ### Expected behavior A clear and concise description of what you expected to happen. ### Attachments * Can you reproduce the bug on our test data? * If so, which file? * If not, access to your data would be very helpful. If the data set is small, please zip and upload it as an attachment. If it is large, please provide instructions for how we can contact you to obtain this data. * Please attach a session file to easily reproduce (use File->Save Session). * Please attach any screenshots relevant to understanding the issue. ### Desktop - OS and version: [e.g. Ubuntu 18.04] - Version: [e.g. Vapor 3.1] ### Additional context Add any other context about the problem here. Attach any (zipped) relevant files, such as data, configurations, session files, etc. ================================================ FILE: .github/ISSUE_TEMPLATE/documentation-request.md ================================================ --- name: Documentation Request about: Submit a request fo Documentation on VAPOR title: '' labels: Documentation assignees: '' --- ### Describe what needs to be documented. A clear and concise description of what you would like to see. ### Is the documentation missing? If so, please describe where have you looked for the documentation and where you expect to see it. ### Is the documentation there but needs improvement? *Please provide the url of the documentation.* ### Additional context Add any other context or screenshots about the desired documentation. ================================================ FILE: .github/ISSUE_TEMPLATE/enhancement-request.md ================================================ --- name: Enhancement request about: Suggest an idea for this project title: '' labels: Enhancement assignees: '' --- ### Is your feature request related to a problem? A clear and concise description of the problem. E.g. I'm always frustrated when [...] ### Describe the solution you'd like. A clear and concise description of what you want to happen. **Impact** (*Please click check boxes AFTER submitting ticket*) - [ ] High - User productivity significantly improved - [ ] Medium - User productivity partially improved - [ ] Low - User productivity trivially improved ### Is your feature request specific to a data set? Can you use one of our example data sets to demonstrate the desired feature? * Please provide a data set. If the data set is small, please zip and upload it as an attachment. If it is large, please provide instructions on how we can contact you to obtain this data. ### Additional context Add any other context or screenshots about the feature request here. ================================================ FILE: .github/workflows/release.yml ================================================ name: Trigger Documentation Update on: release: types: [published] workflow_dispatch: jobs: trigger-doc-update: runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout VAPOR repo uses: actions/checkout@v4 - name: Trigger documentation update run: | curl -X POST -H "Authorization: token ${{ secrets.GH_TOKEN }}" \ -H "Accept: application/vnd.github.v3+json" \ https://api.github.com/repos/NCAR/VaporDocumentationWebsite/dispatches \ -d '{"event_type":"update-docs"}' ================================================ FILE: .gitignore ================================================ .DS_Store apps/vaporgui/guis/ui/*.h apps/vaporgui/moc/ lib/idl/IDLMetadataAuto.cpp lib/render/moc/ share/doc/Doxygen/Doxyfile site.mk targets/ .ycm_extra_conf.py make/Darwin/VaporXcode/vaporXcode.xcodeproj/project.xcworkspace/ make/Darwin/VaporXcode/vaporXcode.xcodeproj/xcuserdata/ plugins/visit/CMakeCache.txt plugins/visit/CMakeFiles/ plugins/visit/CMakeLists.txt plugins/visit/Makefile plugins/visit/WASP/CMakeCache.txt plugins/visit/WASP/CMakeFiles/ plugins/visit/WASP/CMakeLists.txt plugins/visit/WASP/Makefile plugins/visit/WASP/WASP.xml.bak plugins/visit/WASP/cmake_install.cmake plugins/visit/vdf.xml.bak plugins/visit/VDC/CMake* share/fonts/Pacifico.ttf __pycache__ .idea tags # CMake Makefile cmake_install.cmake CmakeFiles CMakeCache.txt /site.local bin /build /build-release /cmake-build-* /xcode /apps/vaporgui/ui/ /buildutils/LinuxInstallLibs.txt # vim swap files *.swp *.swo # object files *.o *.out* ================================================ FILE: .readthedocs.yml ================================================ # .readthedocs.yml # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Build documentation in the docs/ directory with Sphinx sphinx: configuration: docs/conf.py # Build documentation with MkDocs #mkdocs: # configuration: mkdocs.yml # Optionally build your docs in additional formats such as PDF formats: - pdf # Optionally set the version of Python and requirements required to build your docs python: version: 3.7 # install: # - requirements: docs/requirements.txt ================================================ FILE: CMakeLists.txt ================================================ # Note on building VDC only: # These packages from Ubuntu repo are required to build VAPOR with only VDC enabled: # (tested on Ubuntu 18.04) # # libnetcdf-dev, libudunits2-dev, libproj-dev cmake_minimum_required (VERSION 3.17) project (VAPOR3) include (buildutils/UtilityFunctions.cmake) include (buildutils/GetGitRevisionDescription.cmake) include (buildutils/OpenMPInstaller.cmake) set (CMAKE_CXX_STANDARD 17) set (CMAKE_EXPORT_COMPILE_COMMANDS ON) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "DEBUG" "RELEASE" "RELWITHDEBINFO") endif() if(APPLE) if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "") # Check if the target architecture is arm64 include(CheckCXXSourceRuns) set(CMAKE_REQUIRED_FLAGS "-arch arm64") set(CHECK_ARM64_SOURCE_CODE "int main() { return 0; }") check_cxx_source_runs("${CHECK_ARM64_SOURCE_CODE}" IS_ARM64) if(IS_ARM64) set(CMAKE_OSX_ARCHITECTURES arm64) else() set(CMAKE_OSX_ARCHITECTURES x86_64) endif() endif() set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0" CACHE STRING "Minimum OS X deployment version" FORCE) if (CMAKE_OSX_ARCHITECTURES MATCHES "arm64") message("Building on macOS M1 architecture (arm64)") else() message("Building on macOS x86 architecture") set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "macOS build architecture" FORCE) endif() endif() set (VERSION_MAJOR 3) set (VERSION_MINOR 11) set (VERSION_MICRO 0) set (VERSION_RC ) message("CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}") if (CMAKE_BUILD_TYPE STREQUAL "Release") get_git_head_revision (GIT_REFSPEC VERSION_COMMIT) message("VERSION_COMMIT ${VERSION_COMMIT}") execute_process ( COMMAND git rev-parse --short ${VERSION_COMMIT} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE VERSION_COMMIT OUTPUT_STRIP_TRAILING_WHITESPACE ) message("VERSION_COMMIT2 ${VERSION_COMMIT}") endif () string (TIMESTAMP VERSION_DATE UTC) if (VERSION_RC) set (VERSION_STRING ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}.${VERSION_RC}) else () set (VERSION_STRING ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}) endif () set (VERSION_STRING_FULL ${VERSION_STRING}.${VERSION_COMMIT}) if (APPLE) add_definitions (-DDarwin) elseif (WIN32) add_definitions (-DWIN32 -DNOMINMAX) add_definitions (-DGLAD_API_CALL_EXPORT) add_compile_definitions(_HAS_STD_BYTE=0) endif() # compiler warning flags if (NOT WIN32) SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-sign-compare -Wno-overloaded-virtual -Wno-parentheses") SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-sign-compare") else () # Enable multithread compiling on Visual Studio # This feature is glitchy so you may need to re-run SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP") endif() if (CMAKE_GENERATOR STREQUAL "Xcode") set (DEFAULT_BUILD_UTILITIES OFF) else () set (DEFAULT_BUILD_UTILITIES ON) endif () option (BUILD_VDC "Build VDC library and utilities" ON) option (BUILD_GUI "Build Vapor GUI" ON) option (BUILD_PYTHON "Build Vapor Python Library" OFF) option (BUILD_OSP "Build OSPRay" ON) option (BUILD_UTL "Build conversion and utility applications" ${DEFAULT_BUILD_UTILITIES}) option (BUILD_DOC "Build Vapor Doxygen documentation" ON) option (BUILD_TEST_APPS "Build test applications" OFF) option (DIST_INSTALLER "Generate installer for distributing vapor binaries. Will generate standard make install if off" OFF) option (USE_OMP "Use OpenMP on some calculations" OFF) option (CONDA_BUILD "Use Conda to build" OFF) if (UNIX AND NOT APPLE) include (CMakeDependentOption) cmake_dependent_option (DIST_APPIMAGE "Generate an AppImage for VAPOR's installation across multiple Linux platforms" OFF "DIST_INSTALLER" ON) endif (UNIX AND NOT APPLE) if( USE_OMP ) find_package(OpenMP REQUIRED) if( OpenMP_CXX_FOUND AND OpenMP_CXX_FLAGS ) message(STATUS "OpenMP found! (${OpenMP_CXX_LIB_NAMES})") else() message(STATUS "OpenMP NOT found! Are you using Apple Clang?") endif() endif() set (GENERATE_FULL_INSTALLER ON) if (BUILD_GUI) set (BUILD_VDC ON) endif () set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set (test_output_dir ${CMAKE_BINARY_DIR}/test_binaries) set (debug_output_dir ${CMAKE_BINARY_DIR}/debug_binaries) set (QTDIR ) set (OSPRAYDIR ) set (PYTHONDIR ) set (PYTHONVERSION ) set (PYTHONPATH ) set (NUMPY_INCLUDE_DIR ) set (THIRD_PARTY_DIR ) set (THIRD_PARTY_LIB_DIR ) set (THIRD_PARTY_INC_DIR ) set (MAP_IMAGES_PATH ) include (site_files/site.NCAR OPTIONAL) include (site.local OPTIONAL) if (CONDA_BUILD) unset (QTDIR) unset (OSPRAYDIR) unset (PYTHONDIR) unset (PYTHONVERSION) unset (PYTHONPATH) unset (NUMPY_INCLUDE_DIR) unset (THIRD_PARTY_DIR) unset (THIRD_PARTY_LIB_DIR) unset (THIRD_PARTY_INC_DIR) if (DEFINED ENV{MAP_IMAGES_PATH}) set (MAP_IMAGES_PATH $ENV{MAP_IMAGES_PATH}) endif() else() message("THIRD_PARTY_DIR = ${THIRD_PARTY_DIR}") include_directories (SYSTEM ${THIRD_PARTY_INC_DIR}) include_directories (SYSTEM ${THIRD_PARTY_INC_DIR}/freetype2) link_directories (${THIRD_PARTY_LIB_DIR}) link_directories (${PYTHONPATH}) list (APPEND CMAKE_PREFIX_PATH ${THIRD_PARTY_LIB_DIR}) list (APPEND CMAKE_PREFIX_PATH ${THIRD_PARTY_DIR}) list (APPEND CMAKE_PREFIX_PATH ${THIRD_PARTY_DIR}/HDF_Group/HDF5/1.12.2/lib) if (APPLE) set(CMAKE_MODULE_PATH /opt/local/lib/libomp) endif() endif() include_directories ("${PROJECT_SOURCE_DIR}/lib/osgl/include") include_directories ("${PROJECT_SOURCE_DIR}/lib/osgl/glad/include") if (WIN32) get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES) endif () if (BUILD_VDC AND EXISTS ${PYTHONPATH}/lib-dynload) link_directories (${PYTHONPATH}/lib-dynload) endif () find_library(NETCDF netcdf) find_library(UDUNITS2 udunits2) find_library(FREETYPE freetype) find_library(GEOTIFF geotiff) find_library(JPEG jpeg) find_library(HDF5_LIB hdf5) find_library(EXPAT expat) message("Library NETCDF = ${NETCDF}") message("Library UDUNITS2 = ${UDUNITS2}") message("Library FREETYPE = ${FREETYPE}") message("Library GEOTIFF = ${GEOTIFF}") message("Library JPEG = ${JPEG}") message("Library HDF5_LIB = ${HDF5_LIB}") message("Library EXPAT = ${EXPAT}") # find_package(Python) # Output # ${Python_VERSION} # ${Python_LIBRARIES} # ${Python_INCLUDE_DIRS} # ${Python_SITELIB} # ${Python_NumPy_VERSION} # ${Python_NumPy_INCLUDE_DIRS} # https://cmake.org/cmake/help/v3.12/module/FindPython.html function(FIND_BUNDLED_PYTHON) # FindPython supports Python_ROOT_DIR however vapor's bundled python distribution # does not conform to its requirements so this manually configures the results message("Using bundled python") message(" PYTHONDIR ${PYTHONDIR}") message(" PYTHONPATH ${PYTHONPATH}") set(Python_VERSION "${PYTHONVERSION}") set(Python_NumPy_INCLUDE_DIRS "${NUMPY_INCLUDE_DIR}") unset(Python_LIBRARIES) # This is required for find_library to work in certain cases if (APPLE) set(PYTHON_LIB_DIR "${PYTHONDIR}/lib") else() set(PYTHON_LIB_DIR "${PYTHONPATH}") endif() message(" PYTHON_LIB_DIR ${PYTHON_LIB_DIR}") find_library( Python_LIBRARIES NAMES python${PYTHONVERSION} python${PYTHONVERSION}m PATHS ${THIRD_PARTY_LIB_DIR} ${PYTHON_LIB_DIR} NO_DEFAULT_PATH ) if (WIN32) set(Python_SITELIB "${PYTHONPATH}/Lib/site-packages") set(Python_INCLUDE_DIRS "${THIRD_PARTY_DIR}/Python${PYTHONVERSION}/include") else() set(Python_SITELIB "${PYTHONPATH}/site-packages") if (NOT DEFINED Python_INCLUDE_DIRS) if (APPLE) set(Python_INCLUDE_DIRS "${PYTHONDIR}/include/python${PYTHONVERSION}") else() set(Python_INCLUDE_DIRS "${THIRD_PARTY_INC_DIR}/python${PYTHONVERSION}") endif() endif() endif() set(Python_VERSION "${Python_VERSION}" PARENT_SCOPE) set(Python_LIBRARIES "${Python_LIBRARIES}" PARENT_SCOPE) set(Python_INCLUDE_DIRS "${Python_INCLUDE_DIRS}" PARENT_SCOPE) set(Python_SITELIB "${Python_SITELIB}" PARENT_SCOPE) set(Python_NumPy_VERSION "UNUSED IN BUNDLED PYTHON" PARENT_SCOPE) set(Python_NumPy_INCLUDE_DIRS "${Python_NumPy_INCLUDE_DIRS}" PARENT_SCOPE) endfunction() function(DUMP_FOUND_PYTHON) set(PATHS "") list(APPEND PATHS Python_LIBRARIES Python_INCLUDE_DIRS Python_SITELIB Python_NumPy_INCLUDE_DIRS ) message("Python Found ${ARGV0}") message("\tPython_VERSION = '${Python_VERSION}'") message("\tPython_NumPy_VERSION = '${Python_NumPy_VERSION}'") foreach(V ${PATHS}) if (EXISTS "${${V}}") set(VE "OK") else() set(VE "**NOT FOUND**") endif() message("\t${V} = '${${V}}' ${VE}") endforeach() endfunction() # TODO # - Replace PYTHONVERSION with Python_VERSION if (BUILD_PYTHON) find_package(Python COMPONENTS Interpreter Development NumPy) # find_library (GETTEXT intl) else() find_bundled_python() endif() dump_found_python() include_directories ("${Python_INCLUDE_DIRS}") include_directories ("${Python_NumPy_INCLUDE_DIRS}") # if (BUILD_GUI OR BUILD_PYTHON) # find_package (OpenGL REQUIRED) # include_directories (${OPENGL_INCLUDE_DIRS}) # endif () if (WIN32) find_library(ASSIMP assimp-vc140-mt) find_library(TIFF libtiff) find_library(PROJ proj_6_1) else () find_library(ASSIMP assimp) find_library(TIFF tiff) find_library(PROJ proj) endif() if (WIN32) set (INSTALL_BIN_DIR .) set (INSTALL_LIB_DIR .) set (INSTALL_SHARE_DIR share) set (INSTALL_INCLUDE_DIR include/vapor) elseif (APPLE) # if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) if (DIST_INSTALLER AND NOT BUILD_PYTHON) set (CMAKE_INSTALL_PREFIX /Applications) set (INSTALL_BIN_DIR ./vapor.app/Contents/MacOS) set (INSTALL_SHARE_DIR ./vapor.app/Contents/share) set (INSTALL_INCLUDE_DIR ./vapor.app/Contents/include/vapor) set (INSTALL_LIB_DIR ./vapor.app/Contents/Frameworks) else () set (INSTALL_BIN_DIR bin) set (INSTALL_LIB_DIR lib) set (INSTALL_SHARE_DIR share) set (INSTALL_INCLUDE_DIR include/vapor) endif () if (BUILD_PYTHON) set (CMAKE_INSTALL_RPATH "@loader_path") else() set (CMAKE_INSTALL_RPATH "@executable_path/../Frameworks;@executable_path/../Resources/lib") endif () if (DIST_INSTALLER AND USE_OMP) message (WARNING "The build mode is set to distributable installer with OpenMP enabled and will not run from source") set (INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib") set (CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) set (CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) set (CMAKE_SKIP_BUILD_RPATH FALSE) endif() else () if (DIST_INSTALLER) set (INSTALL_BIN_DIR lib) else () set (CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) set (CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") set (INSTALL_BIN_DIR bin) endif () set (INSTALL_LIB_DIR lib) set (INSTALL_INCLUDE_DIR include/vapor) set (INSTALL_LAUNCHER_DIR bin) set (INSTALL_SHARE_DIR share) endif () add_subdirectory (lib) add_subdirectory (apps) add_subdirectory (include) add_subdirectory (share) add_subdirectory (scripts) add_subdirectory (test_apps) ############################################################################### # CPack Installation # ############################################################################### set (CPACK_PACKAGE_NAME ${PROJECT_NAME}) set (CPACK_PACKAGE_VENDOR "NCAR") set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "VAPOR - DESCRIPTION") set (CPACK_PACKAGE_VERSION ${VERSION_STRING}) set (CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR}) set (CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR}) set (CPACK_PACKAGE_VERSION_PATCH ${VERSION_RC}) set (CPACK_PACKAGE_INSTALL_DIRECTORY "VAPOR") set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt") set (CPACK_PACKAGE_EXECUTABLES vapor;vapor) set (CPACK_BINARY_STGZ OFF) set (CPACK_BINARY_TGZ OFF) set (CPACK_BINARY_TZ OFF) set (CPACK_BINARY_DRAGNDROP OFF) if (WIN32) set (PRE_INSTALL_LOCAL_PATH "buildutils/NSIS.preInstall.ini") set (PRE_INSTALL_PATH "${CMAKE_CURRENT_BINARY_DIR}/${PRE_INSTALL_LOCAL_PATH}") configure_file ("${PRE_INSTALL_LOCAL_PATH}.in" "${PRE_INSTALL_PATH}" @ONLY) set (PRE_UNINSTALL_LOCAL_PATH "buildutils/NSIS.preUnInstall.ini") set (PRE_UNINSTALL_PATH "${CMAKE_CURRENT_BINARY_DIR}/${PRE_UNINSTALL_LOCAL_PATH}") configure_file ("${PRE_UNINSTALL_LOCAL_PATH}.in" "${PRE_UNINSTALL_PATH}" @ONLY) if (GENERATE_FULL_INSTALLER) set (LIB_DIR ${THIRD_PARTY_DIR}/lib) file (GLOB WIN_INSTALL_DLLS ${LIB_DIR}/*.dll ${QTDIR}/bin/*.dll ${OSPRAYDIR}/bin/*.dll) install ( FILES ${WIN_INSTALL_DLLS} DESTINATION ${INSTALL_BIN_DIR} COMPONENT Dependencies ) install ( FILES ${PYTHONPATH}/python${PYTHONVERSION}.dll DESTINATION ${INSTALL_BIN_DIR} COMPONENT Dependencies ) install ( DIRECTORY ${PYTHONPATH} DESTINATION ${INSTALL_LIB_DIR} COMPONENT Dependencies ) install(FILES ${QTDIR}/plugins/platforms/qwindows.dll DESTINATION platforms ) install ( DIRECTORY ${THIRD_PARTY_DIR}/share/plugins DESTINATION ${INSTALL_LIB_DIR}/share COMPONENT Dependencies ) endif (GENERATE_FULL_INSTALLER) set (CPACK_NSIS_MODIFY_PATH OFF) set (CPACK_NSIS_URL_INFO_ABOUT "https://www.vapor.ucar.edu") set (CPACK_NSIS_EXECUTABLES_DIRECTORY ".") # Manually fixed in template file set (CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/share/images/vapor-win-icon.ico") set (CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON) set (CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS "${PRE_INSTALL_PATH}") set (CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "${PRE_UNINSTALL_PATH}") string (REGEX REPLACE "/" "\\\\" CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS "${CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS}") string (REGEX REPLACE "/" "\\\\" CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "${CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS}") set (CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION ".") include (InstallRequiredSystemLibraries) set (CPACK_MODULE_PATH "${CMAKE_SOURCE_DIR}/buildutils") endif (WIN32) if (APPLE) set (CPACK_BINARY_DRAGNDROP ON) if (DIST_INSTALLER AND GENERATE_FULL_INSTALLER) file (GLOB INSTALL_LIBS ${THIRD_PARTY_LIB_DIR}/*.dylib) install ( FILES ${INSTALL_LIBS} DESTINATION ${INSTALL_LIB_DIR} COMPONENT Dependencies ) set (FRAMEWORKS Core OpenGL Widgets Gui DBus Network PrintSupport) foreach(item IN LISTS FRAMEWORKS) list(APPEND FRAMEWORKS "${THIRD_PARTY_LIB_DIR}/Qt${item}.framework") list(REMOVE_ITEM FRAMEWORKS ${item}) endforeach(item IN LISTS ${FRAMEWORKS}) install ( DIRECTORY ${FRAMEWORKS} DESTINATION ${INSTALL_LIB_DIR} COMPONENT Dependencies ) if (BUILD_OSP) file (GLOB INSTALL_OSP_LIBS ${OSPRAYDIR}/lib/*.dylib) message (STATUS "OSPRAYDIR ${OSPRAYDIR}") install ( FILES ${INSTALL_OSP_LIBS} DESTINATION ${INSTALL_LIB_DIR} COMPONENT Dependencies ) endif () if (NOT BUILD_PYTHON) file (GLOB INSTALL_GUI_FRAMEWORKS ${PYTHONPATH}) set (PYTHON_DESTINATION "${INSTALL_LIB_DIR}/../Resources/lib") install ( DIRECTORY ${INSTALL_GUI_FRAMEWORKS} DESTINATION ${PYTHON_DESTINATION} COMPONENT Dependencies PATTERN "bin" EXCLUDE ) install ( FILES ${Python_LIBRARIES} DESTINATION ${PYTHON_DESTINATION} COMPONENT Dependencies ) file (GLOB COCOA_LIBS ${THIRD_PARTY_DIR}/plugins/platforms/libqcocoa.dylib) install ( FILES ${COCOA_LIBS} DESTINATION ${INSTALL_BIN_DIR}/platforms COMPONENT Dependencies ) file (GLOB STYLE_LIBS ${THIRD_PARTY_DIR}/plugins/styles/libqmacstyle.dylib) install ( FILES ${STYLE_LIBS} DESTINATION ${INSTALL_BIN_DIR}/styles COMPONENT Dependencies ) endif () if (USE_OMP) get_filename_component(OMP_PATH ${OpenMP_CXX_LIBRARIES} REALPATH) install ( FILES ${OMP_PATH} DESTINATION ${INSTALL_LIB_DIR} COMPONENT Dependencies ) endif () file (GLOB_RECURSE HDF5_PLUGINS "${THIRD_PARTY_DIR}/share/plugins/*.so") message (STATUS "plugins ${HDF5_PLUGINS}") install ( FILES ${HDF5_PLUGINS} DESTINATION "${INSTALL_SHARE_DIR}/plugins" COMPONENT Dependencies ) file (GLOB HDF5_LIBS ${THIRD_PARTY_DIR}/HDF_Group/HDF5/1.12.2/lib/*.dylib) install ( FILES ${HDF5_LIBS} DESTINATION ${INSTALL_LIB_DIR} COMPONENT Dependencies ) endif () endif (APPLE) if (UNIX AND NOT APPLE) set (CPACK_BINARY_STGZ ON) if (BUILD_VDC) set (EXTRA_LIBS_SEARCH ${EXTRA_LIBS_SEARCH} GLU glut expat omp) endif () if (BUILD_GUI) set (EXTRA_LIBS_SEARCH ${EXTRA_LIBS_SEARCH} quadmath) endif () if (DIST_INSTALLER) set (PARSE_BINARY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/vapor") if (BUILD_PYTHON) set (PARSE_BINARY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libvapi.so") endif() message( STATUS "${CMAKE_SOURCE_DIR}/buildutils/gen_linux_shared_libs.pl ${PARSE_BINARY} ${EXTRA_LIBS_SEARCH} > ${CMAKE_BINARY_DIR}/LinuxInstallLibs.txt") add_custom_target ( linuxpreinstall COMMAND ${CMAKE_SOURCE_DIR}/buildutils/gen_linux_shared_libs.pl ${PARSE_BINARY} ${EXTRA_LIBS_SEARCH} > ${CMAKE_BINARY_DIR}/LinuxInstallLibs.txt COMMAND touch ${CMAKE_SOURCE_DIR}/CMakeLists.txt ) endif () if (DIST_INSTALLER AND GENERATE_FULL_INSTALLER) if (EXISTS ${CMAKE_BINARY_DIR}/LinuxInstallLibs.txt) file (STRINGS ${CMAKE_BINARY_DIR}/LinuxInstallLibs.txt INSTALL_LIBS) endif () install ( FILES ${INSTALL_LIBS} DESTINATION ${INSTALL_LIB_DIR} COMPONENT Dependencies ) if (NOT BUILD_PYTHON) install ( DIRECTORY ${THIRD_PARTY_LIB_DIR}/python${PYTHONVERSION} DESTINATION ${INSTALL_LIB_DIR} COMPONENT Dependencies ) # Include libxcb-xinerama for Ubuntu 20/22 by reading /etc/issue if (EXISTS /etc/issue) file(READ "/etc/issue" ETC_ISSUE) string(REGEX MATCH "Ubuntu" DIST ${ETC_ISSUE}) if(DIST STREQUAL "Ubuntu") file (GLOB XCB_FILES ${THIRD_PARTY_LIB_DIR}/libxcb-xinerama.*) install ( FILES ${XCB_FILES} DESTINATION ${INSTALL_LIB_DIR} COMPONENT Dependencies ) endif(DIST STREQUAL "Ubuntu") endif (EXISTS /etc/issue) install ( FILES ${THIRD_PARTY_DIR}/plugins/platforms/libqxcb.so DESTINATION plugins/platforms COMPONENT Dependencies ) install ( DIRECTORY ${THIRD_PARTY_DIR}/plugins/xcbglintegrations DESTINATION ${INSTALL_LIB_DIR} COMPONENT Dependencies ) file (GLOB XCB_FILES ${THIRD_PARTY_LIB_DIR}/libxcb-xinput.*) install ( FILES ${XCB_FILES} DESTINATION ${INSTALL_LIB_DIR} COMPONENT Dependencies ) file (GLOB XCBQPA_FILES ${THIRD_PARTY_LIB_DIR}/libQt5XcbQpa.*) install ( FILES ${XCBQPA_FILES} DESTINATION ${INSTALL_LIB_DIR} COMPONENT Dependencies ) if (BUILD_OSP) file (GLOB INSTALL_OSPRAY_LIBS ${OSPRAYDIR}/lib/*.so*) install ( FILES ${INSTALL_OSPRAY_LIBS} DESTINATION ${INSTALL_LIB_DIR} COMPONENT Dependencies ) endif (BUILD_OSP) file (GLOB HDF5_PLUGINS "${THIRD_PARTY_DIR}/HDF_Group/HDF5/1.12.2/lib/plugin/*.so") install ( FILES ${HDF5_PLUGINS} DESTINATION "${INSTALL_SHARE_DIR}/plugins" COMPONENT Dependencies ) endif (NOT BUILD_PYTHON) endif (DIST_INSTALLER AND GENERATE_FULL_INSTALLER) endif (UNIX AND NOT APPLE) if (DIST_INSTALLER) if (UNIX AND NOT APPLE) if(DIST_APPIMAGE) set ( APPIMAGE_COMMAND bash ${CMAKE_SOURCE_DIR}/buildutils/genAppImage.sh ${VERSION_STRING} ${CMAKE_SOURCE_DIR} ) else() set (APPIMAGE_COMMAND echo Skipping AppImage generation) endif() add_custom_target ( installer WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" COMMAND cpack . COMMAND ${APPIMAGE_COMMAND} DEPENDS linuxpreinstall ) else () add_custom_target ( installer WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" COMMAND cpack . ) endif () endif () if (BUILD_PYTHON) # message("GENERATORS = '${CPACK_GENERATOR}'") set(CPACK_GENERATOR "External") # message("GENERATORS = '${CPACK_GENERATOR}'") # message("CPACK_TOPLEVEL_DIRECTORY = '${CPACK_TOPLEVEL_DIRECTORY}'") # message("CPACK_TEMPORARY_DIRECTORY = '${CPACK_TEMPORARY_DIRECTORY}'") # message("CPACK_PACKAGE_NAME = '${CPACK_PACKAGE_NAME}'") # message("CPACK_PACKAGE_FILE_NAME = '${CPACK_PACKAGE_FILE_NAME}'") # message("CPACK_PACKAGE_VERSION = '${CPACK_PACKAGE_VERSION}'") # These only work for some things, dont work for others, and they break other things still # set (CPACK_TOPLEVEL_DIRECTORY "${CMAKE_BINARY_DIR}/CPACK_TOPLEVEL_DIRECTORY") # set (CPACK_TEMPORARY_DIRECTORY "${CPACK_TOPLEVEL_DIRECTORY}/CPACK_TEMPORARY_DIRECTORY") # message("CPACK_TOPLEVEL_DIRECTORY = '${CPACK_TOPLEVEL_DIRECTORY}'") # message("CPACK_TEMPORARY_DIRECTORY = '${CPACK_TEMPORARY_DIRECTORY}'") set (CPACK_BINARY_DRAGNDROP OFF) # set (CPACK_BINARY_EXTERNAL ON) set (CPACK_EXTERNAL_REQUESTED_VERSIONS "1.0") set (CPACK_EXTERNAL_ENABLE_STAGING TRUE) if (NOT CONDA_BUILD) install ( DIRECTORY ${THIRD_PARTY_DIR}/include DESTINATION . COMPONENT Dependencies ) endif() endif () include (CPack) ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Project maintainers are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the project maintainers responsible for enforcement at vapor@ucar.edu. All complaints will be reviewed and investigated promptly and fairly. All project maintainers are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Project maintainers will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from project maintainers, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. ================================================ FILE: Contributing.md ================================================ # Contributing To make a contribution to Vapor, see our [Contributor's Guide](https://ncar.github.io/VaporDocumentationWebsite/contributingToVapor.html). ================================================ FILE: LICENSE.txt ================================================ BSD 3-Clause License Copyright (c) 2024, NSF National Center for Atmospheric Research Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: README.md ================================================ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.13332956.svg)](https://doi.org/10.5281/zenodo.13332956) [![CircleCI](https://circleci.com/gh/NCAR/VAPOR.svg?style=svg)](https://circleci.com/gh/NCAR/VAPOR) ## Vapor: **VAPOR** is the **V**isualization and **A**nalysis **P**latform for **O**cean, Atmosphere, and Solar **R**esearchers. VAPOR provides an interactive 3D visualization environment that can also produce animations and still frame images. VAPOR runs on most UNIX and Windows systems equipped with modern 3D graphics cards. The VAPOR Data Collection (**VDC**) data model allows users progressively access the fidelity of their data, allowing for the visualization of terascale data sets on commodity hardware. VAPOR can also directly import data formats including WRF, MOM, POP, ROMS, and some GRIB and NetCDF files. Users can perform ad-hoc analysis with VAPOR's interactive Python interpreter; which allows for the creation, modification, and visualization of new variables based on input model data. VAPOR is a product of the **NSF National Center for Atmospheric Research's Computational and Information Systems Lab**. Support for VAPOR is provided by the U.S. **National Science Foundation** (grants # 03-25934 and 09-06379, ACI-14-40412), and by the **Korea Institute of Science and Technology Information** Project homepage and binary releases can be found at [https://www.vapor.ucar.edu/](https://www.vapor.ucar.edu/) ## Citation If VAPOR benefits your research, please kindly cite [this publication](https://www.mdpi.com/2073-4433/10/9/488): ``` @Article{atmos10090488, AUTHOR = {Li, Shaomeng and Jaroszynski, Stanislaw and Pearse, Scott and Orf, Leigh and Clyne, John}, TITLE = {VAPOR: A Visualization Package Tailored to Analyze Simulation Data in Earth System Science}, JOURNAL = {Atmosphere}, VOLUME = {10}, YEAR = {2019}, NUMBER = {9}, ARTICLE-NUMBER = {488}, URL = {https://www.mdpi.com/2073-4433/10/9/488}, ISSN = {2073-4433}, ABSTRACT = {Visualization is an essential tool for analysis of data and communication of findings in the sciences, and the Earth System Sciences (ESS) are no exception. However, within ESS, specialized visualization requirements and data models, particularly for those data arising from numerical models, often make general purpose visualization packages difficult, if not impossible, to use effectively. This paper presents VAPOR: a domain-specific visualization package that targets the specialized needs of ESS modelers, particularly those working in research settings where highly-interactive exploratory visualization is beneficial. We specifically describe VAPOR’s ability to handle ESS simulation data from a wide variety of numerical models, as well as a multi-resolution representation that enables interactive visualization on very large data while using only commodity computing resources. We also describe VAPOR’s visualization capabilities, paying particular attention to features for geo-referenced data and advanced rendering algorithms suitable for time-varying, 3D data. Finally, we illustrate VAPOR’s utility in the study of a numerically- simulated tornado. Our results demonstrate both ease-of-use and the rich capabilities of VAPOR in such a use case.}, DOI = {10.3390/atmos10090488} } ``` ## Project Members: - Nihanth Cherukuru - John Clyne - Scott Pearse - Samuel Li - Stanislaw Jaroszynski - Kenny Gruchalla - Niklas Roeber - Pamela Gillman ![Vapor Banner](share/images/vapor_banner.png) ================================================ FILE: apps/CMakeLists.txt ================================================ if (BUILD_UTL) add_subdirectory (vaporversion) add_subdirectory (raw2wasp) add_subdirectory (wasp2raw) add_subdirectory (waspcreate) add_subdirectory (ncdf2wasp) add_subdirectory (wasp2ncdf) endif() if ((BUILD_VDC OR BUILD_GUI) AND BUILD_UTL) add_subdirectory (vdcdump) add_subdirectory (cf2vdc) add_subdirectory (cfvdccreate) add_subdirectory (raw2vdc) add_subdirectory (vdc2raw) add_subdirectory (vdccreate) add_subdirectory (wrf2vdc) add_subdirectory (wrfvdccreate) add_subdirectory (vdccompare) add_subdirectory (vapor_check_udunits) endif() if (BUILD_GUI) add_subdirectory (vaporgui) if (BUILD_UTL) add_subdirectory (tiff2geotiff) add_subdirectory (vaporpychecker) endif() endif() if (BUILD_PYTHON) add_subdirectory (pythonapi) endif() if (UNIX AND NOT APPLE AND DIST_INSTALLER) add_subdirectory (linuxlauncher) endif () ================================================ FILE: apps/asciitf2vtf/asciitf2vtf.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef WIN32 #pragma warning(disable : 4996) #endif using namespace Wasp; using namespace VAPoR; // // asciitf2vtf: // This is one of the commandline applications for VAPOR. // // Modified in April, 2011. // Added the ability for the program to use NCL colormaps as input. // Kendall Southwick // struct opt_t { char * omap; char * cmap; char * type; OptionParser::Boolean_T help; OptionParser::Boolean_T quiet; } opt; OptionParser::OptDescRec_T set_opts[] = {{"cmap", 1, "", "Path to ascii file containing color map"}, {"omap", 1, "", "Path to ascii file containing opacity map"}, {"type", 1, "vapor", "Type pf color maps being used, defaults to vapor"}, {"help", 0, "", "Print this message and exit"}, {"quiet", 0, "", "Operate quietly"}, {NULL}}; OptionParser::Option_T get_options[] = {{"cmap", Wasp::CvtToString, &opt.cmap, sizeof(opt.cmap)}, {"omap", Wasp::CvtToString, &opt.omap, sizeof(opt.omap)}, {"type", Wasp::CvtToString, &opt.type, sizeof(opt.type)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {NULL}}; const char *ProgName; void Usage(OptionParser &op, const char *msg) { if (msg) { cerr << ProgName << " : " << msg << endl; } cerr << "Usage: " << ProgName << " [options] (-cmap cmap.txt | -omap omap.txt) file.tf3" << endl; op.PrintOptionHelp(stderr); } void ErrMsgCBHandler(const char *msg, int) { cerr << ProgName << " : " << msg << endl; } // // This function will process the VAPOR color map files. // int ProcessVAPORCMAP(TransferFunctionLite *transFunct) { int RetVal = 0; vector pvec, hvec, svec, vvec; float point, h, s, v; ColorMap *cmap = transFunct->getColormap(); cmap->clear(); FILE *fp = fopen(opt.cmap, "r"); if (!fp) { MyBase::SetErrMsg("fopen(%s) : %M", opt.cmap); exit(1); } const char *format = "%f %f %f %f"; while ((RetVal = fscanf(fp, format, &point, &h, &s, &v)) == 4) { pvec.push_back(point); hvec.push_back(h); svec.push_back(s); vvec.push_back(v); } if (vvec.size() <= 0) { MyBase::SetErrMsg("Error parsing file %s , no data.", opt.cmap); exit(1); } vector tmpvec = pvec; sort(tmpvec.begin(), tmpvec.end()); // Apparently we need to set the min and max values in both // the transfer function and colormap class. Setting the // cmap bounds is needed so that addControlPointAt() will // correctly normalize the data value. transFunct->setMinColorMapValue(tmpvec[0]); transFunct->setMaxColorMapValue(tmpvec[tmpvec.size() - 1]); cmap->minValue(tmpvec[0]); cmap->maxValue(tmpvec[tmpvec.size() - 1]); ColorMap::Color color; for (int i = 0; i < pvec.size(); i++) { color.hue(hvec[i]); color.sat(svec[i]); color.val(vvec[i]); // cmap->addNormControlPoint(pvec[i], color); cmap->addControlPointAt(pvec[i], color); } // // Ugh. now we need to normalize the data bounds. // cmap->minValue(0.0); cmap->maxValue(1.0); if (ferror(fp)) { MyBase::SetErrMsg("Error parsing file %s", opt.cmap); exit(1); } fclose(fp); return (RetVal); } // End of ProcessVAPORCMAP. // // This function will process the NCL color map files. // int ProcessNCLCMAP(TransferFunctionLite *transFunct) { int RetVal = 0; int numColors = 0; int fileSize; int rc; int last_i = 0; float THRESHOLD = 0.10; float SLOPE_THRESHOLD = 0.010; float last_hsv[] = {0.0, 0.0, 0.0}; float rgb[] = {0.0, 0.0, 0.0}; float hsv[] = {0.0, 0.0, 0.0}; float comp_vals[] = {0.0, 0.0, 0.0}; vector pvec, hvec, svec, vvec; char * readLine; bool header_flag = false; bool h_slope_flag, slope_flag, interval_flag, delta_flag; ColorMap *cmap = transFunct->getColormap(); cmap->clear(); ifstream nclFile(opt.cmap, ios::in); if (!nclFile) { MyBase::SetErrMsg("Unable to open file %s: %M", opt.cmap); exit(1); } // // Start parsing the file. // There needs to be a line must be of the form // "ncolors=##" where ## is a number. // The header ends with a lines of the form // # r b g // There may a different number of spaces between the // # and the r. // nclFile.seekg(0, ios::end); fileSize = nclFile.tellg(); nclFile.seekg(0, ios::beg); readLine = (char *)malloc(fileSize * sizeof(char)); char *indexChar; while (!header_flag && !nclFile.eof()) { nclFile.getline(readLine, fileSize); indexChar = NULL; if (readLine[0] == '#') { indexChar = strstr(readLine, "r g b"); if (indexChar != NULL) { header_flag = true; } // end of headers. } // comment line. else { indexChar = strstr(readLine, "ncolors="); if (indexChar != NULL) { rc = sscanf(indexChar + 8, "%d", &numColors); } // have ncolors. } // non comment line. } // End of while. if (nclFile.eof() || numColors == 0 || !header_flag) { MyBase::SetErrMsg("Formating error in file %s", opt.cmap); exit(1); } // // Since it is hard to have more the ten color control points // in VAPOR, we need to trim the input down. // for (int i = 0; ((i < numColors) && !nclFile.eof()); i++) { nclFile.getline(readLine, fileSize); if (strlen(readLine) > 0) { rc = sscanf(readLine, "%f %f %f", &rgb[0], &rgb[1], &rgb[2]); if (rc != 3) { MyBase::SetErrMsg("Formating error in file %s", opt.cmap); exit(1); } h_slope_flag = slope_flag = interval_flag = delta_flag = false; rgb[0] = rgb[0] / 255.0; rgb[1] = rgb[1] / 255.0; rgb[2] = rgb[2] / 255.0; transFunct->rgbToHsv(rgb, hsv); if (i == 0) { comp_vals[0] = hsv[0]; comp_vals[1] = hsv[1]; comp_vals[2] = hsv[2]; last_hsv[0] = hsv[0]; last_hsv[1] = hsv[1]; last_hsv[2] = hsv[2]; last_i = -1; } if ((abs(hsv[0] - comp_vals[0]) >= THRESHOLD) || (abs(hsv[1] - comp_vals[1]) >= THRESHOLD) || (abs(hsv[2] - comp_vals[2]) >= THRESHOLD)) { delta_flag = true; } if ((abs((comp_vals[2] - hsv[2]) / (i - last_i) - (last_hsv[2] - hsv[2])) >= SLOPE_THRESHOLD) || (abs((comp_vals[1] - hsv[1]) / (i - last_i) - (last_hsv[1] - hsv[1])) >= SLOPE_THRESHOLD)) { slope_flag = true; } if ((i - last_i) > (0.07 * numColors)) { interval_flag = true; } if (slope_flag || interval_flag || (i == 0)) { comp_vals[0] = hsv[0]; comp_vals[1] = hsv[1]; comp_vals[2] = hsv[2]; last_i = i; pvec.push_back(((float)(i)) / ((float)(numColors))); hvec.push_back(hsv[0]); svec.push_back(hsv[1]); vvec.push_back(hsv[2]); } last_hsv[0] = hsv[0]; last_hsv[1] = hsv[1]; last_hsv[2] = hsv[2]; } // End if strlen. } // End for. if (vvec.size() <= 0) { MyBase::SetErrMsg("Error parsing file %s , no data.", opt.cmap); exit(1); } vector tmpvec = pvec; sort(tmpvec.begin(), tmpvec.end()); // Apparently we need to set the min and max values in both // the transfer function and colormap class. Setting the // cmap bounds is needed so that addControlPointAt() will // correctly normalize the data value. transFunct->setMinColorMapValue(tmpvec[0]); transFunct->setMaxColorMapValue(tmpvec[tmpvec.size() - 1]); cmap->minValue(tmpvec[0]); cmap->maxValue(tmpvec[tmpvec.size() - 1]); ColorMap::Color color; for (int i = 0; i < pvec.size(); i++) { color.hue(hvec[i]); color.sat(svec[i]); color.val(vvec[i]); // cmap->addNormControlPoint(pvec[i], color); cmap->addControlPointAt(pvec[i], color); } // // Ugh. now we need to normalize the data bounds. // cmap->minValue(0.0); cmap->maxValue(1.0); nclFile.close(); return (RetVal); } // End of ProcessNCLCMAP. // // This functions directs how the color maps is t be processed based on the // type of color maps, form the -type option. // int ProcessCMAP(TransferFunctionLite *transFunct, char *cmapType) { int RetVal; if (strcmp(cmapType, "vapor") == 0) { RetVal = ProcessVAPORCMAP(transFunct); } else if (strcmp(cmapType, "VAPOR") == 0) { RetVal = ProcessVAPORCMAP(transFunct); } else if (strcmp(cmapType, "ncl") == 0) { RetVal = ProcessNCLCMAP(transFunct); } else if (strcmp(cmapType, "NCL") == 0) { RetVal = ProcessNCLCMAP(transFunct); } else { RetVal = 1; MyBase::SetErrMsg("Invalid color map type."); } return (RetVal); } // End of ProcessCMAP. int main(int argc, char **argv) { OptionParser op; ProgName = Basename(argv[0]); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << OptionParser::GetErrMsg(); exit(1); } MyBase::SetErrMsgCB(ErrMsgCBHandler); if (opt.help) { Usage(op, NULL); exit(0); } if (argc != 2) { Usage(op, "Wrong number of arguments"); exit(1); } if ((strlen(opt.cmap) == 0) && (strlen(opt.omap) == 0)) { Usage(op, "Wrong number of arguments"); exit(1); } TransferFunctionLite tf(8); if (MyBase::GetErrCode() != 0) exit(1); tf.setMinColorMapValue(0.0); tf.setMaxColorMapValue(1.0); tf.setMinOpacMapValue(0.0); tf.setMaxOpacMapValue(1.0); string vtffile(argv[1]); int rc; if (strlen(opt.cmap) != 0) { ProcessCMAP(&tf, opt.type); } if (strlen(opt.omap) != 0) { float point, o; vector pvec, ovec; OpacityMap *omap = tf.getOpacityMap(0); omap->clear(); FILE *fp = fopen(opt.omap, "r"); if (!fp) { MyBase::SetErrMsg("fopen(%s) : %M", opt.omap); exit(1); } const char *format = "%f %f"; while ((rc = fscanf(fp, format, &point, &o)) == 2) { pvec.push_back(point); ovec.push_back(o); } vector tmpvec = pvec; sort(tmpvec.begin(), tmpvec.end()); tf.setMinOpacMapValue(tmpvec[0]); tf.setMaxOpacMapValue(tmpvec[tmpvec.size() - 1]); omap->minValue(tmpvec[0]); omap->maxValue(tmpvec[tmpvec.size() - 1]); for (int i = 0; i < pvec.size(); i++) { // omap->addNormControlPoint(pvec[i], ovec[i]); omap->addControlPoint(pvec[i], ovec[i]); } omap->minValue(0.0); omap->maxValue(1.0); if (ferror(fp)) { MyBase::SetErrMsg("Error parsing file %s", opt.omap); exit(1); } fclose(fp); } // End of if omap. // // Write output file. // ofstream fileout; fileout.open(vtffile.c_str()); if (!fileout) { MyBase::SetErrMsg("Can't open file \"%s\" for writing", vtffile.c_str()); exit(1); } if (!(tf.saveToFile(fileout))) exit(1); exit(0); } // End of Main. ================================================ FILE: apps/cf2vdc/CMakeLists.txt ================================================ add_executable (cf2vdc cf2vdc.cpp) target_link_libraries (cf2vdc common vdc) OpenMPInstall ( TARGETS cf2vdc DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/cf2vdc/cf2vdc.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; struct opt_t { int nthreads; int numts; std::vector vars; std::vector xvars; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"nthreads", 1, "0", "Specify number of execution threads " "0 => use number of cores"}, {"numts", 1, "-1", "Number of timesteps to be included in the VDC. Default (-1) includes all timesteps."}, {"vars", 1, "", "Colon delimited list of variable names " "to be copied to the VDC"}, {"xvars", 1, "", "Colon delimited list of variable names " "to exclude from copying the VDC"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"numts", Wasp::CvtToInt, &opt.numts, sizeof(opt.numts)}, {"vars", Wasp::CvtToStrVec, &opt.vars, sizeof(opt.vars)}, {"xvars", Wasp::CvtToStrVec, &opt.xvars, sizeof(opt.xvars)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; string ProgName; SmartBuf dataBuffer; SmartBuf maskBuffer; // Product of elements in a vector // size_t vproduct(vector a) { size_t ntotal = 1; for (int i = 0; i < a.size(); i++) ntotal *= a[i]; return (ntotal); } size_t gcd(size_t n1, size_t n2) { size_t tmp; while (n2 != 0) { tmp = n1; n1 = n2; n2 = tmp % n2; } return n1; } size_t lcm(size_t n1, size_t n2) { return ((n1 * n2) / gcd(n1, n2)); } int copyVarHelper(DC &dc, VDCNetCDF &vdc, int fdr, int fdw, vector &buffer_dims, vector &src_hslice_dims, vector &dst_hslice_dims, size_t src_nslice, size_t dst_nslice, double mv, float *buffer) { VAssert(buffer_dims.size() == src_hslice_dims.size()); VAssert(buffer_dims.size() == dst_hslice_dims.size()); size_t dim = buffer_dims.size() - 1; size_t src_slice_count = 0; size_t dst_slice_count = 0; while (src_slice_count < src_nslice) { float *bufptr = buffer; int n = buffer_dims[dim] / src_hslice_dims[dim]; int rCount; for (rCount = 0; rCount < n && src_slice_count < src_nslice; rCount++) { int rc = dc.ReadSlice(fdr, bufptr); if (rc < 0) return (-1); bufptr += vproduct(src_hslice_dims); src_slice_count++; } // In place replacmenet of missing value with 1-byte flag // size_t sz = rCount * vproduct(src_hslice_dims); unsigned char *cptr = (unsigned char *)buffer; for (int j = 0; j < sz; j++) { if (buffer[j] == mv) { cptr[j] = 0; // invalid data } else { cptr[j] = 1; // valid data } } cptr = (unsigned char *)buffer; n = buffer_dims[dim] / dst_hslice_dims[dim]; for (int i = 0; i < n && dst_slice_count < dst_nslice; i++) { int rc = vdc.WriteSlice(fdw, cptr); if (rc < 0) return (-1); cptr += vproduct(dst_hslice_dims); dst_slice_count++; } } return (0); } int CopyVar2d3dMask(DC &dc, VDCNetCDF &vdc, size_t ts, string varname, int lod) { // Only data variables can have masks // if (!vdc.IsDataVar(varname)) return (0); DC::DataVar varInfo; bool status = vdc.GetDataVarInfo(varname, varInfo); if (!status) { MyBase::SetErrMsg("Invalid destination variable name : %s", varname.c_str()); return (-1); } string maskvar = varInfo.GetMaskvar(); // Do nothing if mask variable already exists on disk // if (maskvar.empty() || vdc.VariableExists(ts, maskvar, 0, lod)) return (0); status = dc.GetDataVarInfo(varname, varInfo); if (!status) { MyBase::SetErrMsg("Invalid source variable name : %s", varname.c_str()); return (-1); } double mv = varInfo.GetMissingValue(); // Get the dimensions of a hyper slice for the source and destination // varible // vector src_hslice_dims; size_t src_nslice; int rc = dc.GetHyperSliceInfo(varname, -1, src_hslice_dims, src_nslice); if (rc < 0) return (rc); if (src_hslice_dims.size() < 2) return (0); vector dst_hslice_dims; size_t dst_nslice; rc = vdc.GetHyperSliceInfo(varname, -1, dst_hslice_dims, dst_nslice); if (rc < 0) return (rc); if (src_hslice_dims.size() != dst_hslice_dims.size()) { MyBase::SetErrMsg("Incompatible source and destination variable definitions"); return (-1); } // n-1 fastest varying dimensions must be the same for both hyper-slices. // Slowest dimension may be different. // int dim = src_hslice_dims.size() - 1; size_t src_dimlen = src_hslice_dims[dim]; size_t dst_dimlen = dst_hslice_dims[dim]; for (int i = 0; i < src_hslice_dims.size() - 1; i++) { if (src_hslice_dims[i] != dst_hslice_dims[i]) { MyBase::SetErrMsg("Incompatible source and destination variable definitions"); return (-1); } } // Find the slice dimension for slowest varying dimension, the Least // Common Multiple for the source and destination // size_t slice_dim = lcm(src_dimlen, dst_dimlen); // Common (fastest-varying) dimensions for both variables, plus // the lcm of the slowest varying dimension for the source // and destination. // vector buffer_dims = src_hslice_dims; buffer_dims.pop_back(); // Remove slowest varying dimension buffer_dims.push_back(slice_dim); int fdr = dc.OpenVariableRead(ts, varname, -1); if (fdr < 0) return (fdr); int fdw = vdc.OpenVariableWrite(ts, maskvar, lod); if (fdw < 0) { dc.CloseVariable(fdr); return (fdw); } size_t bufsize = vproduct(buffer_dims); float *buffer = (float *)dataBuffer.Alloc(bufsize * sizeof(*buffer)); rc = copyVarHelper(dc, vdc, fdr, fdw, buffer_dims, src_hslice_dims, dst_hslice_dims, src_nslice, dst_nslice, mv, buffer); dc.CloseVariable(fdr); vdc.CloseVariable(fdw); return (rc); } // Return a new vector containing elements of v1 with any elements from // v2 removed // vector remove_vector(vector v1, vector v2) { vector newvec; for (auto it = v1.begin(); it != v1.end(); ++it) { if (find(v2.begin(), v2.end(), *it) == v2.end()) { newvec.push_back(*it); } } return (newvec); } int main(int argc, char **argv) { VAPoR::SetHDF5PluginPath(); OptionParser op; MyBase::SetErrMsgFilePtr(stderr); // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { return (1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { return (1); } if (argc < 3) { cerr << "Usage: " << ProgName << " cffiles... master.vdc" << endl; op.PrintOptionHelp(stderr, 80, false); return (1); } if (opt.help) { cerr << "Usage: " << ProgName << " master.vdc" << endl; op.PrintOptionHelp(stderr, 80, false); return (0); } argc--; argv++; vector cffiles; for (int i = 0; i < argc - 1; i++) cffiles.push_back(argv[i]); string master = argv[argc - 1]; VDCNetCDF vdc(opt.nthreads); size_t chunksize = 1024 * 1024 * 4; vector bs; int rc = vdc.Initialize(master, vector(), VDC::A, bs, chunksize); if (rc < 0) return (1); DCCF dccf; rc = dccf.Initialize(cffiles, vector()); if (rc < 0) { return (1); } // // Copy coordinate variables first, checking to ensure that the // coordinate variable isn't also a data variable (a variable can // be both data and coordinate). If a coord variable is also // a data variable, skip it and handle below // vector varnames = dccf.GetCoordVarNames(); vector dvarnames = dccf.GetDataVarNames(); for (int i = 0; i < varnames.size(); i++) { // Skip coordinate varibles that are also data variables // if (find(dvarnames.begin(), dvarnames.end(), varnames[i]) != dvarnames.end()) continue; int nts = dccf.GetNumTimeSteps(varnames[i]); nts = opt.numts != -1 && nts > opt.numts ? opt.numts : nts; VAssert(nts >= 0); cout << "Copying variable " << varnames[i] << endl; for (int ts = 0; ts < nts; ts++) { cout << " Time step " << ts << endl; int rc = vdc.CopyVar(dccf, ts, varnames[i], -1, -1); if (rc < 0) { MyBase::SetErrMsg("Failed to copy variable %s", varnames[i].c_str()); return (1); } } } if (opt.vars.size()) { varnames = opt.vars; } else { varnames = dccf.GetDataVarNames(); } varnames = remove_vector(varnames, opt.xvars); // Now copy data variables // int estatus = 0; for (int i = 0; i < varnames.size(); i++) { int nts = dccf.GetNumTimeSteps(varnames[i]); nts = opt.numts != -1 && nts > opt.numts ? opt.numts : nts; VAssert(nts >= 0); cout << "Copying variable " << varnames[i] << endl; for (int ts = 0; ts < nts; ts++) { cout << " Time step " << ts << endl; int rc = CopyVar2d3dMask(dccf, vdc, ts, varnames[i], -1); if (rc < 0) { MyBase::SetErrMsg("Failed to copy variable %s", varnames[i].c_str()); continue; estatus = 1; } rc = vdc.CopyVar(dccf, ts, varnames[i], -1, -1); if (rc < 0) { MyBase::SetErrMsg("Failed to copy variable %s", varnames[i].c_str()); estatus = 1; } } } return (estatus); } ================================================ FILE: apps/cfvdccreate/CMakeLists.txt ================================================ add_executable (cfvdccreate cfvdccreate.cpp) target_link_libraries (cfvdccreate common vdc) OpenMPInstall ( TARGETS cfvdccreate DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/cfvdccreate/cfvdccreate.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; struct opt_t { OptionParser::Dimension3D_T dim; std::vector bs; std::vector cratios; string wname; int nthreads; std::vector vars; OptionParser::Boolean_T force; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"dimension", 1, "512x512x512", "Data volume dimensions expressed in " "grid points (NXxNYxNZ)"}, {"bs", 1, "64:64:64", "Internal storage blocking factor expressed in grid points (NX:NY:NZ)"}, {"cratios", 1, "1:10:100:500", "Colon delimited list compression ratios. " "for 3D variables. The default is 1:10:100:500. The maximum " "compression ratio is wavelet and block size dependent."}, {"wname", 1, "bior4.4", "Wavelet family used for compression " "Valid values are bior1.1, bior1.3, " "bior1.5, bior2.2, bior2.4 ,bior2.6, bior2.8, bior3.1, bior3.3, " "bior3.5, bior3.7, bior3.9, bior4.4"}, {"nthreads", 1, "0", "Specify number of execution threads " "0 => use number of cores"}, {"vars", 1, "", "Colon delimited list of 3D variable names (compressed) " "to be included in " "the VDC"}, {"force", 0, "", "Create a new VDC master file even if a VDC data " "directory already exists. Results may be undefined if settings between " "the new master file and old data directory do not match."}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"dimension", Wasp::CvtToDimension3D, &opt.dim, sizeof(opt.dim)}, {"bs", Wasp::CvtToSize_tVec, &opt.bs, sizeof(opt.bs)}, {"cratios", Wasp::CvtToSize_tVec, &opt.cratios, sizeof(opt.cratios)}, {"wname", Wasp::CvtToCPPStr, &opt.wname, sizeof(opt.wname)}, {"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"vars", Wasp::CvtToStrVec, &opt.vars, sizeof(opt.vars)}, {"force", Wasp::CvtToBoolean, &opt.force, sizeof(opt.force)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; string ProgName; // Construct a mask variable name // void maskvar(vector dimnames, string &name) { VAssert(dimnames.size() >= 1); name.clear(); name = "mask"; for (int i = 0; i < dimnames.size(); i++) { name += "_" + dimnames[i]; } } void DefineMaskVars(const DCCF &dccf, VDCNetCDF &vdc) { // Find all coordinate combinations for data with missing values // vector>> dimpairs; for (int d = 1; d < 4; d++) { vector datanames = dccf.DC::GetDataVarNames(d); for (int i = 0; i < datanames.size(); i++) { DC::DataVar dvar; dccf.GetDataVarInfo(datanames[i], dvar); // skip if no missing value defined for this variable // if (!dvar.GetHasMissing()) continue; // Assume missing values locations don't vary over time! // vector dimnames; bool ok = dccf.GetVarDimNames(datanames[i], true, dimnames); VAssert(ok); string maskvar_name; maskvar(dimnames, maskvar_name); pair> p1 = make_pair(maskvar_name, dimnames); dimpairs.push_back(p1); } } sort(dimpairs.begin(), dimpairs.end()); vector>>::iterator last; last = unique(dimpairs.begin(), dimpairs.end()); dimpairs.erase(last, dimpairs.end()); for (int i = 0; i < dimpairs.size(); i++) { string maskvar = dimpairs[i].first; vector dimnames = dimpairs[i].second; // // 1D coordinates are not blocked // string mywname; bool compress; if (dimnames.size() < 2) { mywname.clear(); compress = false; } else { mywname = "intbior2.2"; compress = true; } // Try to compute "reasonable" 1D & 2D compression ratios from 3D // compression ratios // vector cratios(1, 1); int rc = vdc.SetCompressionBlock(mywname, cratios); if (rc < 0) exit(1); rc = vdc.DefineDataVar(maskvar, dimnames, vector(), "", DC::INT8, compress); if (rc < 0) { exit(1); } } } void defineMapProjection(const DCCF &dc, VDCNetCDF &vdc) { vdc.SetMapProjection(dc.GetMapProjection()); } int main(int argc, char **argv) { VAPoR::SetHDF5PluginPath(); OptionParser op; MyBase::SetErrMsgFilePtr(stderr); // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { return (1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { return (1); } if (argc < 3) { cerr << "Usage: " << ProgName << " cf_files... master.vdc" << endl; op.PrintOptionHelp(stderr, 80, false); return (1); } if (opt.help) { cerr << "Usage: " << ProgName << " cf_files... master.vdc" << endl; op.PrintOptionHelp(stderr, 80, false); return (0); } argc--; argv++; vector cffiles; for (int i = 0; i < argc - 1; i++) cffiles.push_back(argv[i]); string master = argv[argc - 1]; if (FileUtils::Extension(master) != "vdc") { fprintf(stderr, "Warning: VDC files should the extension .vdc\n"); } VDCNetCDF vdc(opt.nthreads); if (vdc.DataDirExists(master) && !opt.force) { MyBase::SetErrMsg("Data directory exists and -force option not used. " "Remove directory %s or use -force", vdc.GetDataDir(master).c_str()); return (1); } if (FileUtils::Exists(master) && !opt.force) { MyBase::SetErrMsg("\"%s\" already exists and -force option not used.", master.c_str()); exit(1); } size_t chunksize = 1024 * 1024 * 4; int rc = vdc.Initialize(master, vector(), VDC::W, opt.bs, chunksize); if (rc < 0) return (1); DCCF dccf; rc = dccf.Initialize(cffiles, vector()); if (rc < 0) { return (1); } vector dimnames = dccf.GetDimensionNames(); for (int i = 0; i < dimnames.size(); i++) { DC::Dimension dim; dccf.GetDimension(dimnames[i], dim, -1); rc = vdc.DefineDimension(dim.GetName(), dim.GetLength()); if (rc < 0) { return (1); } } // // Define coordinate variables // vector cratios(1, 1); vector coordnames = dccf.GetCoordVarNames(); for (int i = 0; i < coordnames.size(); i++) { DC::CoordVar cvar; dccf.GetCoordVarInfo(coordnames[i], cvar); vector sdimnames; string time_dimname; bool ok = dccf.GetVarDimNames(coordnames[i], sdimnames, time_dimname); VAssert(ok); rc = vdc.SetCompressionBlock(opt.wname, cratios); if (rc < 0) return (1); if (cvar.GetUniform()) { rc = vdc.DefineCoordVarUniform(cvar.GetName(), sdimnames, time_dimname, cvar.GetUnits(), cvar.GetAxis(), cvar.GetXType(), false); } else { rc = vdc.DefineCoordVar(cvar.GetName(), sdimnames, time_dimname, cvar.GetUnits(), cvar.GetAxis(), cvar.GetXType(), false); } if (rc < 0) { return (1); } rc = vdc.CopyAtt(dccf, cvar.GetName()); if (rc < 0) { return (1); } } DefineMaskVars(dccf, vdc); defineMapProjection(dccf, vdc); // // Define data variables // for (int d = 0; d < 4; d++) { vector datanames = dccf.DC::GetDataVarNames(d); // // 1D coordinates are not blocked // string mywname; bool compress; if (d < 2) { mywname.clear(); compress = false; } else { mywname = opt.wname; compress = true; } // Try to compute "reasonable" 1D & 2D compression ratios from 3D // compression ratios // vector cratios = opt.cratios; for (int i = 0; i < cratios.size(); i++) { size_t c = (size_t)pow((double)cratios[i], (double)((float)d / 3.0)); cratios[i] = c; } rc = vdc.SetCompressionBlock(mywname, cratios); if (rc < 0) return (1); for (int i = 0; i < datanames.size(); i++) { DC::DataVar dvar; dccf.GetDataVarInfo(datanames[i], dvar); vector dimnames; bool ok = dccf.GetVarDimNames(datanames[i], false, dimnames); VAssert(ok); vector coordvars; ok = dccf.GetVarCoordVars(datanames[i], false, coordvars); VAssert(ok); // Don't compress the variable if it is also a coordinate variable // Compression errors in coordinate variables can lead to // non-conformant meshes // bool doCompress = compress; if (find(coordnames.begin(), coordnames.end(), datanames[i]) != coordnames.end()) { doCompress = false; } if (dvar.GetHasMissing() && doCompress) { vector sdimnames; bool ok = dccf.GetVarDimNames(datanames[i], true, sdimnames); VAssert(ok); string maskvar_name; maskvar(sdimnames, maskvar_name); rc = vdc.DefineDataVar(dvar.GetName(), dimnames, coordvars, dvar.GetUnits(), dvar.GetXType(), dvar.GetMissingValue(), maskvar_name); } else if (dvar.GetHasMissing() && !doCompress) { rc = vdc.DefineDataVar(dvar.GetName(), dimnames, coordvars, dvar.GetUnits(), dvar.GetXType(), dvar.GetMissingValue(), ""); } else { rc = vdc.DefineDataVar(dvar.GetName(), dimnames, coordvars, dvar.GetUnits(), dvar.GetXType(), doCompress); } if (rc < 0) { return (1); } rc = vdc.CopyAtt(dccf, dvar.GetName()); if (rc < 0) { return (1); } } } rc = vdc.EndDefine(); if (rc < 0) { MyBase::SetErrMsg("Failed to write VDC master file : %s", master.c_str()); return (1); } return (0); } ================================================ FILE: apps/linuxlauncher/CMakeLists.txt ================================================ set (TARGETS cf2vdc ncdf2wasp tiff2geotiff vaporversion vdccreate wasp2raw wrfvdccreate cfvdccreate raw2vdc vapor vdcdump waspcreate raw2wasp vdc2raw wasp2ncdf wrf2vdc vdccompare vaporpychecker vapor_check_udunits ) append (LAUNCHER_TARGETS _launcher ${TARGETS}) set_property (GLOBAL PROPERTY LAUNCHER_TARGETS ${LAUNCHER_TARGETS}) foreach (target ${TARGETS}) set (TARGET_NAME ${target}) configure_file (launcher.c ${target}_launcher.c) add_executable ( ${target}_launcher ${target}_launcher.c ) set_target_properties( ${target}_launcher PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launchers OUTPUT_NAME ${target} ) install ( TARGETS ${target}_launcher DESTINATION ${INSTALL_LAUNCHER_DIR} COMPONENT Utilites ) endforeach (target) ================================================ FILE: apps/linuxlauncher/launcher.c ================================================ #include #include #include #include #include int main(int argc, char **argv) { char path[PATH_MAX]; ssize_t rc = readlink("/proc/self/exe", path, PATH_MAX); (void)(rc); // Remove warning char *p = &path[strlen(path) - 1]; int up = 2; while (p != path && up) { if (*p == '/') { *p = 0; up--; } p--; } #ifndef NDEBUG int debug = 0; if (argc > 1 && !strcmp("--launcher-debug", argv[1])) { debug = 1; argc--; int i; for (i = 1; i < argc; i++) argv[i] = argv[i + 1]; argv[argc] = 0; } #endif setenv("VAPOR_HOME", path, 1); strcat(path, "/lib"); char *oldLibPath = getenv("LD_LIBRARY_PATH"); if (!oldLibPath) oldLibPath = ""; char *newLibPath = malloc(strlen(oldLibPath) + strlen(path) + 2); strcpy(newLibPath, path); strcat(newLibPath, ":"); strcat(newLibPath, oldLibPath); setenv("LD_LIBRARY_PATH", newLibPath, 1); #ifndef NDEBUG if (debug) printf("LD_LIBRARY_PATH=%s\n", newLibPath); #endif free(newLibPath); argv[0] = "@TARGET_NAME@"; strcat(path, "/@TARGET_NAME@"); if (access(path, X_OK) == -1) { fprintf(stderr, "Failed to run \"%s\"\n", path); exit(1); } execv(path, argv); return 0; } ================================================ FILE: apps/ncdf2wasp/CMakeLists.txt ================================================ add_executable (ncdf2wasp ncdf2wasp.cpp) target_link_libraries (ncdf2wasp common wasp) OpenMPInstall ( TARGETS ncdf2wasp DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/ncdf2wasp/ncdf2wasp.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; // // Command line argument stuff // struct opt_t { string varname; string wname; int lod; int nthreads; std::vector bs; std::vector bs2d; std::vector cratios; std::vector cratios2d; std::vector xvarnames; std::vector xdimnames; OptionParser::Boolean_T debug; OptionParser::Boolean_T quiet; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"varname", 1, "var1", "Name of variable"}, {"wname", 1, "bior4.4", "Wavelet family used for compression " "Valid values are bior1.1, bior1.3, " "bior1.5, bior2.2, bior2.4 ,bior2.6, bior2.8, bior3.1, bior3.3, " "bior3.5, bior3.7, bior3.9, bior4.4"}, {"lod", 1, "-1", "Compression levels saved. 0 => coarsest, 1 => " "next refinement, etc. -1 => all levels defined by the netcdf file"}, {"nthreads", 1, "0", "Specify number of execution threads " "0 => use number of cores"}, {"bs", 1, "64:64:64", "Internal storage blocking factor expressed in grid points (NZ:NY:NX) " "for 3D variables"}, {"bs2d", 1, "", "Internal storage blocking factor expressed in grid points (NZ:NY:NX) " "for 2D variables. If empty the 2D blocking factor uses the fastest " "varying dimensions of the 3D blocking factor"}, {"cratios", 1, "500:100:10:1", "Colon delimited list of compression " "ratios for 3D variables. The default is 500:100:10:1. The maximum " "compression ratio is wavelet and block size dependent."}, {"cratios2d", 1, "", "Colon delimited list of compression " "ratios for 2D variables. If empty the 2D compression ratio vector " "is calculated from the 3D compression vector."}, {"xvarnames", 1, "", "Colon delimited list of variable names " "to exclude from compression."}, {"xdimnames", 1, "", "Colon delimited list of dimension names " "to exclude from compression."}, {"debug", 0, "", "Enable diagnostic"}, {"quiet", 0, "", "Operate quietly"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"varname", Wasp::CvtToCPPStr, &opt.varname, sizeof(opt.varname)}, {"wname", Wasp::CvtToCPPStr, &opt.wname, sizeof(opt.wname)}, {"lod", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)}, {"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"bs", Wasp::CvtToSize_tVec, &opt.bs, sizeof(opt.bs)}, {"bs2d", Wasp::CvtToSize_tVec, &opt.bs2d, sizeof(opt.bs2d)}, {"cratios", Wasp::CvtToSize_tVec, &opt.cratios, sizeof(opt.cratios)}, {"cratios2d", Wasp::CvtToSize_tVec, &opt.cratios2d, sizeof(opt.cratios2d)}, {"xvarnames", Wasp::CvtToStrVec, &opt.xvarnames, sizeof(opt.xvarnames)}, {"xdimnames", Wasp::CvtToStrVec, &opt.xdimnames, sizeof(opt.xdimnames)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; const char *ProgName; // Return true if string 'name' contained in vector of strings, 'names' // bool name_in(string name, const vector &names) { return (find(names.begin(), names.end(), name) != names.end()); } // Given a list of dimemsion names and lengths (dimnames, dimlens) return // an ordered subset of the inputs that contains only the dimension // names and lenghts that will be compressed. // void get_compressed_dims(const vector &dimnames, const vector &dimlens, vector &cdimnames, vector &cdimlens) { VAssert(dimnames.size() == dimlens.size()); cdimnames = dimnames; cdimlens = dimlens; // if any excluded dimension names match the **slowest** // varying variable dimension name remove the matched dimension // name. // vector::iterator itr1 = cdimnames.begin(); vector::iterator itr2 = cdimlens.begin(); while (itr1 != cdimnames.end()) { if (name_in(*itr1, opt.xdimnames)) { cdimnames.erase(itr1); itr1 = cdimnames.begin(); cdimlens.erase(itr2); itr2 = cdimlens.begin(); } else { break; } } } // Compute the block size from opt.bs and opt.bs2d based on the number // of dimensions // vector get_bs(const vector &dimnames, const vector &dims) { vector cdimnames; vector cdims; get_compressed_dims(dimnames, dims, cdimnames, cdims); VAssert(cdims.size() == 2 || cdims.size() == 3); if (cdims.size() == 3) return (opt.bs); if (cdims.size() == 2 && opt.bs2d.size()) return (opt.bs2d); // Compute 2D block sizes from 3D block sizes // vector bs = opt.bs; bs.erase(bs.begin()); return (bs); } // Compute the compression ratios from opt.cratios and opt.cratios2d // based on the number of dimensions // vector get_cratios(const vector &dimnames, const vector &dims) { vector cdimnames; vector cdims; get_compressed_dims(dimnames, dims, cdimnames, cdims); VAssert(cdims.size() == 2 || cdims.size() == 3); if (cdims.size() == 3) return (opt.cratios); if (cdims.size() == 2 && opt.cratios2d.size()) return (opt.cratios2d); // Compute 2D compression ratios from 3D compression ratios // vector cratios = opt.cratios; for (int i = 0; i < cratios.size(); i++) { double v = cratios[i]; v = pow(v, 1.0 / 3.0); cratios[i] = (size_t)(v * v); } return (cratios); } // // Define the WASP output file using 'ncdf' as a template // int DefFile(const NetCDFCpp &ncdf, WASP &wasp) { vector dimnames; vector dimlens; int rc = ncdf.InqDims(dimnames, dimlens); if (rc < 0) return (-1); VAssert(dimnames.size() == dimlens.size()); for (int i = 0; i < dimnames.size(); i++) { rc = wasp.DefDim(dimnames[i], dimlens[i]); if (rc < 0) return (-1); } vector attnames; rc = ncdf.InqAttnames("", attnames); if (rc < 0) return (-1); for (int i = 0; i < attnames.size(); i++) { rc = ncdf.CopyAtt("", attnames[i], wasp, ""); if (rc < 0) return (-1); } return (0); } // Get all of the variable names, and based on command line arguments parse // the names into a vector of // variable names that will be copied verbatim, and a vector of variable // names that will be compressed. // int GetVarNames(const NetCDFCpp &ncdf, vector &vars, vector ©_vars, vector &compress_vars) { vars.clear(); copy_vars.clear(); compress_vars.clear(); int rc = ncdf.InqVarnames(vars); if (rc < 0) return (-1); for (int i = 0; i < vars.size(); i++) { vector dimnames; vector dimlens; nc_type xtype; rc = ncdf.InqVarDims(vars[i], dimnames, dimlens); if (rc < 0) return (-1); rc = ncdf.InqVartype(vars[i], xtype); if (rc < 0) return (-1); // Can only compress 3 different data types // if (!((xtype == NC_FLOAT) || (xtype == NC_DOUBLE) || (xtype == NC_INT))) { copy_vars.push_back(vars[i]); continue; } // Excluded variable names requested via command line // if (name_in(vars[i], opt.xvarnames)) { copy_vars.push_back(vars[i]); continue; } // if any excluded dimension names match the **slowest** // varying variable dimension name remove the matched dimension // name. // get_compressed_dims(dimnames, dimlens, dimnames, dimlens); if (!((dimnames.size() == 2) || (dimnames.size() == 3))) { copy_vars.push_back(vars[i]); continue; } // If we get this far the variable can be compressed // compress_vars.push_back(vars[i]); } return (0); } // Copy variables verbatim from 'ncdf' to 'wasp' // int CopyVars(const NetCDFCpp &ncdf, const vector ©_vars, WASP &wasp) { for (int i = 0; i < copy_vars.size(); i++) { if (!opt.quiet) { cout << "Copying variable " << copy_vars[i] << endl; } int rc = ncdf.CopyVar(copy_vars[i], wasp); if (rc < 0) return (-1); } return (0); } // Define a variable that will not be compressed (i.e copied verbatim) // int DefCopyVar(const NetCDFCpp &ncdf, string varname, NetCDFCpp &wasp) { vector dimnames; vector dimlens; int rc = ncdf.InqVarDims(varname, dimnames, dimlens); if (rc < 0) return (-1); nc_type xtype; rc = ncdf.InqVartype(varname, xtype); if (rc < 0) return (-1); rc = wasp.DefVar(varname, xtype, dimnames); if (rc < 0) return (-1); return (0); } // Define a variable that will be compressed // int DefCompressVar(const NetCDFCpp &ncdf, string varname, WASP &wasp) { vector dimnames; vector dimlens; int rc = ncdf.InqVarDims(varname, dimnames, dimlens); if (rc < 0) return (-1); nc_type xtype; rc = ncdf.InqVartype(varname, xtype); if (rc < 0) return (-1); vector bs = get_bs(dimnames, dimlens); vector cratios = get_cratios(dimnames, dimlens); rc = wasp.DefVar(varname, xtype, dimnames, opt.wname, bs, cratios); if (rc < 0) return (-1); return (0); } // Define all variables in 'wasp', preserving the variable order // in 'ncdf' // int DefVars(const NetCDFCpp &ncdf, const vector &vars, const vector ©_vars, const vector &comp_vars, WASP &wasp) { int rc; for (int i = 0; i < vars.size(); i++) { if (name_in(vars[i], copy_vars)) { rc = DefCopyVar(ncdf, vars[i], wasp); if (rc < 0) return (-1); } else if (name_in(vars[i], comp_vars)) { rc = DefCompressVar(ncdf, vars[i], wasp); if (rc < 0) return (-1); } else { continue; } // Now copy variable attributes // vector attnames; rc = ncdf.InqAttnames(vars[i], attnames); if (rc < 0) return (-1); for (int j = 0; j < attnames.size(); j++) { rc = ncdf.CopyAtt(vars[i], attnames[j], wasp, vars[i]); if (rc < 0) return (-1); } } return (0); } // Compress variables // int CompressVars(NetCDFCpp &ncdf, const vector ©_vars, WASP &wasp) { for (int i = 0; i < copy_vars.size(); i++) { if (!opt.quiet) { cout << "Compressing variable " << copy_vars[i] << endl; } int rc = wasp.CopyVarFrom(copy_vars[i], ncdf); if (rc < 0) return (-1); } return (0); } void Process(string ncdffile, string waspfile) { NetCDFCpp ncdf; WASP wasp; size_t chunksize = 1024 * 1024 * 4; int rc = ncdf.Open(ncdffile, NC_NOWRITE); if (rc < 0) { MyBase::SetErrMsg("Error opening %s for reading", ncdffile.c_str()); exit(1); } rc = wasp.Create(waspfile, NC_64BIT_OFFSET, 0, chunksize, opt.cratios.size()); if (rc < 0) { MyBase::SetErrMsg("Error opening %s for writing", waspfile.c_str()); exit(1); } rc = DefFile(ncdf, wasp); if (rc < 0) exit(1); vector vars, copy_vars, compress_vars; rc = GetVarNames(ncdf, vars, copy_vars, compress_vars); if (rc < 0) exit(1); rc = DefVars(ncdf, vars, copy_vars, compress_vars, wasp); if (rc < 0) exit(1); rc = wasp.EndDef(); if (rc < 0) exit(1); rc = CopyVars(ncdf, copy_vars, wasp); if (rc < 0) exit(1); rc = CompressVars(ncdf, compress_vars, wasp); if (rc < 0) exit(1); (void)ncdf.Close(); rc = wasp.Close(); if (rc < 0) exit(1); } int main(int argc, char **argv) { VAPoR::SetHDF5PluginPath(); OptionParser op; MyBase::SetErrMsgFilePtr(stderr); // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] netcdffile waspfile" << endl; op.PrintOptionHelp(stderr); exit(0); } if (argc != 3) { cerr << "Usage: " << ProgName << " [options] netcdffile waspfile" << endl; op.PrintOptionHelp(stderr); exit(1); } string ncdffile = argv[1]; // Path to a vdf file string waspfile = argv[2]; // Path to wasp file if (opt.debug) MyBase::SetDiagMsgFilePtr(stderr); Process(ncdffile, waspfile); return (0); } ================================================ FILE: apps/pythonapi/CMakeLists.txt ================================================ message("Python Found: '${Python_VERSION}' (${Python_LIBRARIES})") SET(PYTHON_API_DIR ${CMAKE_BINARY_DIR}/python) # CMake does not have proper support for copying files and its scripting language does not make adding it easy. function(COPY_HELPER FILE DESTINATION DEP_LIST) get_filename_component(BASENAME "${FILE}" NAME) if ("${BASENAME}" IN_LIST COPY_EXCLUDE) return() endif() if (IS_DIRECTORY "${FILE}") file(GLOB SUBFILES "${FILE}/*") foreach (SUBFILE ${SUBFILES}) COPY_HELPER("${SUBFILE}" "${DESTINATION}/${BASENAME}" "${DEP_LIST}") endforeach() else() set(OUTFILE "${DESTINATION}/${BASENAME}") add_custom_command( OUTPUT "${OUTFILE}" COMMAND ${CMAKE_COMMAND} -E copy "${FILE}" "${OUTFILE}" MAIN_DEPENDENCY "${FILE}" ) list(APPEND DEP_LIST "${OUTFILE}") # of course this does not work for custom targets # add_dependencies(target ${OUTFILE}) endif() set(DEP_LIST "${DEP_LIST}" PARENT_SCOPE) endfunction() set_property(GLOBAL PROPERTY COPY_HELPER_TARGET_COUNTER_PROPERTY "0") function(COPY FILE DESTINATION) include(CMakeParseArguments) cmake_parse_arguments(PARSE_ARGV 2 "COPY" "" "" "EXCLUDE" ) get_filename_component(FILE "${FILE}" REALPATH) list(APPEND DEP_LIST "") COPY_HELPER("${FILE}" "${DESTINATION}" "${DEP_LIST}") get_property(COPY_HELPER_TARGET_COUNTER GLOBAL PROPERTY COPY_HELPER_TARGET_COUNTER_PROPERTY) math(EXPR COPY_HELPER_TARGET_COUNTER "${COPY_HELPER_TARGET_COUNTER}+1") set_property(GLOBAL PROPERTY COPY_HELPER_TARGET_COUNTER_PROPERTY ${COPY_HELPER_TARGET_COUNTER}) add_custom_target( copy_helper_${COPY_HELPER_TARGET_COUNTER} ALL DEPENDS ${DEP_LIST} ) endfunction() copy(vapor ${PYTHON_API_DIR} EXCLUDE cmake.py __pycache__ widget.js jquery.js) copy(setup.py ${PYTHON_API_DIR}) copy(example_scripts ${PYTHON_API_DIR} EXCLUDE CMakeLists.txt) add_subdirectory (example_scripts) add_custom_command( OUTPUT "${PYTHON_API_DIR}/vapor/widget.js" COMMAND esbuild --log-level=warning --format=esm "${CMAKE_CURRENT_SOURCE_DIR}/vapor/widget.js" --bundle --outfile="${PYTHON_API_DIR}/vapor/widget.js" MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/vapor/widget.js" ) add_custom_target( widget_js ALL DEPENDS "${PYTHON_API_DIR}/vapor/widget.js" ) # copy(bld.bat ${PYTHON_API_DIR}) # copy(build.sh ${PYTHON_API_DIR}) # configure_file (meta.yaml ${PYTHON_API_DIR}/meta.yaml) # get_target_property(VAPI_PRIVATE_COMPILE_DEFS vapi COMPILE_DEFINITIONS) get_target_property(VAPI_COMPILE_DEFS vapi INTERFACE_COMPILE_DEFINITIONS) get_property(GLOBAL_COMPILE_DEFS DIRECTORY PROPERTY COMPILE_DEFINITIONS) # These don't quite work # get_target_property(VAPI_DEFS vapi COMPILE_DEFINITIONS) # get_target_property(VAPI_INT_DEFS vapi INTERFACE_COMPILE_DEFINITIONS) # get_property(DIR_DEFS DIRECTORY PROPERTY COMPILE_DEFINITIONS) configure_file (cmake.py ${PYTHON_API_DIR}/cmake.py) configure_file (vapor/cmake.py ${PYTHON_API_DIR}/vapor/cmake.py) if (CONDA_BUILD) set(CONDA_SITE_PACKAGE_DIR "$ENV{SP_DIR}") install( DIRECTORY "${PYTHON_API_DIR}/vapor" DESTINATION "${CONDA_SITE_PACKAGE_DIR}" COMPONENT Dependencies ) endif() # Fails to find either despite both being installed # list(APPEND CMAKE_MODULE_PATH "/usr/local/Caskroom/miniconda/base/envs/test/lib/python3.9/site-packages/cppyy_backend/cmake") # find_package (LibClang REQUIRED) # find_package (Cppyy REQUIRED) ================================================ FILE: apps/pythonapi/cmake.py ================================================ from pathlib import Path VERSION_RC = "@VERSION_RC@" VERSION_DATE = "@VERSION_DATE@" VERSION_COMMIT = "@VERSION_COMMIT@" VERSION_STRING = "@VERSION_STRING@" VERSION_STRING_FULL = "@VERSION_STRING_FULL@" BUILD_TYPE = "@CMAKE_BUILD_TYPE@" SOURCE_DIR = "@PROJECT_SOURCE_DIR@" BINARY_DIR = "@CMAKE_BINARY_DIR@" THIRD_PARTY_DIR = "@THIRD_PARTY_DIR@" PYTHON_VERSION = "@PYTHONVERSION@" PYTHON_DIR = "@PYTHONDIR@" PYTHON_PATH = "@PYTHONPATH@" SYSTEM_NAME = "@CMAKE_SYSTEM_NAME@" PYTHON_API_SOURCE_DIR = "@CMAKE_CURRENT_SOURCE_DIR@" #These do not work CPACK_TOPLEVEL_DIR = "@CPACK_TOPLEVEL_DIRECTORY@" CPACK_TEMPORARY_DIR = "@CPACK_TEMPORARY_DIRECTORY@" CPACK_INSTALLER_NAME = "@PROJECT_NAME@-@VERSION_STRING@-@CMAKE_SYSTEM_NAME@" CPACK_STAGING_DIR = f"{BINARY_DIR}/_CPack_Packages/{SYSTEM_NAME}/External/{CPACK_INSTALLER_NAME}" pkg = "@CPACK_PACKAGE_NAME@" pk2g = "@CPACK_PACKAGE_FILE_NAME@" PROJECT_NAME = "@PROJECT_NAME@" CPACK_PACKAGE_VERSION = "@CPACK_PACKAGE_VERSION@" for n in ['BINARY_DIR', 'PYTHON_API_SOURCE_DIR', 'CPACK_STAGING_DIR']: f = eval(n) if Path(f).exists(): print(f"{n} OK {f}") else: print(f"{n} NOT FOUND {f}") assert 0 ================================================ FILE: apps/pythonapi/example_scripts/CMakeLists.txt ================================================ set(ALL_NOTEBOOKS "") set(ALL_MARIMO_NOTEBOOKS "") function(NOTEBOOK FILE OUT) include(CMakeParseArguments) cmake_parse_arguments(PARSE_ARGV 2 "NOTEBOOK" "" "" "" ) get_filename_component(FILE "${FILE}" REALPATH) add_custom_command( OUTPUT "${OUT}" DEPENDS "${FILE}" COMMAND cat "${FILE}" | jupytext --to ipynb > "${OUT}" ) list(APPEND ALL_NOTEBOOKS "${OUT}") set(ALL_NOTEBOOKS "${ALL_NOTEBOOKS}" PARENT_SCOPE) endfunction() function(CONV_MARIMO FILE OUT) include(CMakeParseArguments) cmake_parse_arguments(PARSE_ARGV 2 "CONV_MARIMO" "" "" "" ) get_filename_component(FILE "${FILE}" REALPATH) add_custom_command( OUTPUT "${OUT}" DEPENDS "${FILE}" COMMAND marimo -q -y convert "${FILE}" -o "${OUT}" ) list(APPEND ALL_MARIMO_NOTEBOOKS "${OUT}") set(ALL_MARIMO_NOTEBOOKS "${ALL_MARIMO_NOTEBOOKS}" PARENT_SCOPE) endfunction() # copy(vapor ${PYTHON_API_DIR} EXCLUDE cmake.py __pycache__) # copy(setup.py ${PYTHON_API_DIR}) find_program(JUPYTEXT "jupytext") if (JUPYTEXT) set(EXAMPLE_NOTEBOOK_OUT_DIR "${PYTHON_API_DIR}/example_jupyter_notebooks") file(MAKE_DIRECTORY ${EXAMPLE_NOTEBOOK_OUT_DIR}) copy(example_utils.py ${EXAMPLE_NOTEBOOK_OUT_DIR}) notebook(numpy_example.py ${EXAMPLE_NOTEBOOK_OUT_DIR}/numpy_example.ipynb) notebook(xarray_example.py ${EXAMPLE_NOTEBOOK_OUT_DIR}/xarray_example.ipynb) notebook(dataset_example.py ${EXAMPLE_NOTEBOOK_OUT_DIR}/dataset_example.ipynb) notebook(flow_example.py ${EXAMPLE_NOTEBOOK_OUT_DIR}/flow_example.ipynb) notebook(annotation_example.py ${EXAMPLE_NOTEBOOK_OUT_DIR}/annotation_example.ipynb) notebook(camera_example.py ${EXAMPLE_NOTEBOOK_OUT_DIR}/camera_example.ipynb) notebook(transfer_function_example.py ${EXAMPLE_NOTEBOOK_OUT_DIR}/transfer_function_example.ipynb) notebook(workflow_example.py ${EXAMPLE_NOTEBOOK_OUT_DIR}/workflow_example.ipynb) notebook(animation_example.py ${EXAMPLE_NOTEBOOK_OUT_DIR}/animation_example.ipynb) notebook(visualizer_widget_example.py ${EXAMPLE_NOTEBOOK_OUT_DIR}/visualizer_widget_example.ipynb) notebook(rotate_video.py ${EXAMPLE_NOTEBOOK_OUT_DIR}/rotate_video.ipynb) add_custom_target( example_notebooks ALL DEPENDS ${ALL_NOTEBOOKS} ) else() message(WARNING "jupytext not found") message(WARNING "Skipping generation of jupyter notebooks") endif() find_program(MARIMO "marimo") if (JUPYTEXT AND MARIMO) set(EXAMPLE_MARIMO_OUT_DIR "${PYTHON_API_DIR}/example_marimo_notebooks") file(MAKE_DIRECTORY ${EXAMPLE_MARIMO_OUT_DIR}) copy(example_utils.py ${EXAMPLE_MARIMO_OUT_DIR}) conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/numpy_example.ipynb ${EXAMPLE_MARIMO_OUT_DIR}/numpy_example.py) conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/xarray_example.ipynb ${EXAMPLE_MARIMO_OUT_DIR}/xarray_example.py) conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/dataset_example.ipynb ${EXAMPLE_MARIMO_OUT_DIR}/dataset_example.py) conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/flow_example.ipynb ${EXAMPLE_MARIMO_OUT_DIR}/flow_example.py) conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/annotation_example.ipynb ${EXAMPLE_MARIMO_OUT_DIR}/annotation_example.py) conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/camera_example.ipynb ${EXAMPLE_MARIMO_OUT_DIR}/camera_example.py) conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/transfer_function_example.ipynb ${EXAMPLE_MARIMO_OUT_DIR}/transfer_function_example.py) conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/workflow_example.ipynb ${EXAMPLE_MARIMO_OUT_DIR}/workflow_example.py) conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/animation_example.ipynb ${EXAMPLE_MARIMO_OUT_DIR}/animation_example.py) conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/visualizer_widget_example.ipynb ${EXAMPLE_MARIMO_OUT_DIR}/visualizer_widget_example.py) conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/rotate_video.ipynb ${EXAMPLE_MARIMO_OUT_DIR}/rotate_video.py) add_custom_target( example_marimo_notebooks ALL DEPENDS ${ALL_MARIMO_NOTEBOOKS} ) else() message(WARNING "marimo (or jupytext) not found") message(WARNING "Skipping generation of marimo notebooks") endif() if (CONDA_BUILD) set(CONDA_SITE_PACKAGE_DIR "$ENV{SP_DIR}") install( DIRECTORY "${PYTHON_API_DIR}/example_scripts" DESTINATION "${CONDA_SITE_PACKAGE_DIR}/vapor" COMPONENT Dependencies ) if (JUPYTEXT) install( DIRECTORY "${EXAMPLE_NOTEBOOK_OUT_DIR}" DESTINATION "${CONDA_SITE_PACKAGE_DIR}/vapor" COMPONENT Dependencies ) endif() endif() ================================================ FILE: apps/pythonapi/example_scripts/animation_example.py ================================================ # %% [md] # # # Creating Animations # # %% import example_utils from vapor import session, renderer, dataset, camera from vapor.animation import Animation # %% ses = session.Session() data = example_utils.OpenExampleDataset(ses) dimension = 2 U,V = data.GetDataVarNames(dimension)[0:2] ren:renderer.FlowRenderer = data.NewRenderer(renderer.FlowRenderer) ren.SetFieldVariableNames([U, V]) ses.GetCamera().ViewAll() ren.SetRenderType(ren.RenderType.RenderTypeStream) ren.SetRenderRadiusScalar(3) ren.SetRenderGeom3D(True) ren.SetColorMapVariableName(U) # ses.Show() # %% anim = Animation(ses) for i in range(0, 200, 2): ren.SetSteadyNumOfSteps(i) anim.CaptureFrame() print(f"Rendering Animation [{'#'*round(i/5)}{' '*round(40-i/5)}] {(i+1)/2:.0f}%", end="\r") anim.Show() # %% anim.ShowInteractive() # %% anim.SaveMP4("test.mp4") ================================================ FILE: apps/pythonapi/example_scripts/annotation_example.py ================================================ # %% [md] # # # Annotations # # You can annotate your renderings using Vapor's build in annotations as well as MatPlotLib # # %% import example_utils from vapor import session, renderer, dataset, camera from vapor.utils import histogram ses = session.Session() data = example_utils.OpenExampleDataset(ses) ren = data.NewRenderer(renderer.TwoDDataRenderer) ren.SetVariableName(data.GetDataVarNames(2)[1]) ses.GetCamera().ViewAll() # %% [md] # # ## Vapor Colorbars # # %% # Show the basic colorbar annotation for a renderer colorbar = ren.GetColorbarAnnotation() colorbar.SetEnabled(True) ses.Show() # %% # Customized colorbar annotation colorbar.SetSize((0.2, 0.25)) colorbar.SetTitle("Colorbar Title") colorbar.SetCornerPosition((0.95, 0.95)) ses.Show() # %% [md] # # ## MatPlotLib Colorbars # # You can customize the histograms as you would MatPlotLib's `pylab.colorbar` # # %% tf = ren.GetPrimaryTransferFunction() tf.ShowMatPlotLibColorbar() # %% tf.ShowMatPlotLibColorbar(orientation="vertical", figsize=(1.5,4)) # %% # The MatPlotLib Colorbars are automatically synced to Vapor's transfer functions tf.LoadBuiltinColormap(tf.ListBuiltinColormaps()[7]) ses.Show() tf.ShowMatPlotLibColorbar() # %% colorbar.SetEnabled(False) # %% [md] # # ## MatPlotLib Histograms # # %% histogram.ShowMatPlotLibHistogram(ses, ren) # %% [md] # --- # You can customize the histograms as you would `matplotlib.pyplot.hist` # # %% plt = histogram.GetMatPlotLibHistogram(ses, ren, color ="red") plt.xlabel("X-Axis") plt.ylabel("Y-Axis") plt.title("Title\n", fontweight="bold") plt.show() # %% [md] # # ## Axis Annotations # # %% axis = ses.GetAxisAnnotations() axis.SetAxisAnnotationEnabled(True) ses.Show() # %% axis.SetNumTics((5,5)) axis.SetAxisFontSize(24) ses.Show() # This example dataset is not geo-referenced # axis.SetLatLonAxesEnabled(True) # %% axis.SetAxisAnnotationEnabled(False) # %% [md] # # ## Scene Annotations # # Scene annotations are other annotations and rendering options that apply to the entire rendering such as background color. # # %% scene = ses.GetSceneAnnotations() scene.SetBackgroundColor((1,1,1)) scene.SetUseDomainFrame(False) ses.Show() # %% scene.SetAxisArrowEnabled(True) scene.SetAxisArrowSize(0.4) scene.SetTimeType(scene.TimeAnnotationType.Timestep) scene.SetTimeColor((0,0,0)) scene.SetTimeLLX(0.7) ses.Show() ================================================ FILE: apps/pythonapi/example_scripts/camera_example.py ================================================ # %% [md] # # # Controlling the Camera # # %% import example_utils from vapor import session, renderer, dataset, camera ses = session.Session() data = example_utils.OpenExampleDataset(ses) ren = data.NewRenderer(renderer.VolumeIsoRenderer) ren.SetIsoValues([-0.10, 0.2]) # Show 3D orientation arrows. ses.GetSceneAnnotations().SetAxisArrowEnabled(True) # %% cam = ses.GetCamera() # %% help(cam.ViewAll) cam.ViewAll() ses.Show() # %% help(cam.AlignView) cam.AlignView("-X") ses.Show() # %% help(cam.Zoom) cam.Zoom(-0.4) ses.Show() # %% help(cam.LookAt) cam.LookAt((32, -100, 100), ren.GetTransform().GetOrigin()) ses.Show() ================================================ FILE: apps/pythonapi/example_scripts/dataset_example.py ================================================ # %% [md] # # # Opening Datasets # # Vapor supports a variety of scientific data formats. # This notebook shows how to open a dataset and query its metadata. # # %% import example_utils from vapor import session, renderer, dataset, camera # %% print("Supported dataset types:", dataset.Dataset.GetDatasetTypes()) # %% ses = session.Session() data = example_utils.OpenExampleDataset(ses) # Examples of opening real data # # data = ses.OpenDataset(dataset.WRF, ["data/wrf_out.0001", "data/wrf_out.0002"]) # data = ses.OpenDataset(dataset.VDC, ["master.vdc"]) # data = ses.OpenDataset(dataset.MPAS, ["x1.static.nc", "diag.2021-03-04_10.30.00.nc"]) # %% [md] # # ## Dump the dataset metadata # # %% print("Time Coordinate Variable Name:", data.GetTimeCoordVarName()) print("Coordinate Variable Names:", data.GetCoordVarNames()) print("Dimensions:") for dim in data.GetDimensionNames(): print(f" {dim}:", data.GetDimensionLength(dim, 0)) print("Data Variables:") for var in data.GetDataVarNames(): print(f" {var}") print(f" Time Varying:", bool(data.IsTimeVarying(var))) print(f" Dimensionality:", data.GetVarGeometryDim(var)) print(f" Coordinates:", data.GetVarCoordVars(var, True)) print(" Data Range:", data.GetDataRange(var)) # %% [md] # # ## Render the first 2D variable as a wireframe # # %% ren = data.NewRenderer(renderer.WireFrameRenderer) ren.SetVariableName(data.GetDataVarNames(2)[0]) # Set to first 2D data variable ses.GetCamera().ViewAll() ses.Show() ================================================ FILE: apps/pythonapi/example_scripts/example_utils.py ================================================ ########################################################### # NOTICE # # This is a utility file for running tests from source and # can be ignored when normally using vapor # ########################################################### try: import vapor except ImportError: import sys sys.path.append('..') from inspect import signature import numpy as np from math import sin def SampleFunctionOnRegularGrid(f, ext=None, shape=None): if not shape: shape = [64]*len(signature(f).parameters) if not ext: ext = [(0,1)]*len(signature(f).parameters) assert len(signature(f).parameters) == len(shape) and len(shape) == len(ext) d = [] for i in np.ndindex(*(shape)): d.append(f(*[v/s*(t-f)+f for v,s,(f,t) in zip(reversed(i), shape, ext)])) return np.asarray(d, dtype=np.float32).reshape(shape) def OpenExampleDataset(session): data = session.CreatePythonDataset() data.AddNumpyData("U10", SampleFunctionOnRegularGrid(lambda x, y: sin(6 * x) + sin(6 * y))) data.AddNumpyData("V10", SampleFunctionOnRegularGrid(lambda x, y: (x + y) * np.exp(-5.0 * (x ** 2 + y ** 2)), ext=[(-1, 1)] * 2)) data.AddNumpyData("V", SampleFunctionOnRegularGrid(lambda x, y, z: (x + y + z) * np.exp(-5.0 * (x ** 2 + y ** 2 + z ** 2)), ext=[(-1, 1)] * 3)) return data ================================================ FILE: apps/pythonapi/example_scripts/flow_example.py ================================================ # %% [md] # # # Advecting Flow Paths # # Vapor can advect and render flow paths through your data. # # %% import example_utils from vapor import session, renderer, dataset, camera ses = session.Session() data = example_utils.OpenExampleDataset(ses) # %% [md] # # ## Default advection # # When you create a Flow renderer, the default advection will create a regularly dispersed grid of seed points and simulate a streamline advection in 2D or 3D, depending on the provided variables. # # %% # Use first 2 2D variables as our U,V for the flow advection dimension = 2 U,V = data.GetDataVarNames(dimension)[0:2] ren:renderer.FlowRenderer = data.NewRenderer(renderer.FlowRenderer) ren.SetFieldVariableNames([U, V]) ses.GetCamera().ViewAll() ses.Show() # %% [md] # # ## Rendering techniques # # The rendering of the flow paths can be configured. A few examples are shown below. # Call help(renderer.FlowRenderer) to see additional options. # # %% ren.SetRenderType(ren.RenderType.RenderTypeStream) ren.SetRenderRadiusScalar(3) ren.SetRenderGeom3D(True) ren.SetColorMapVariableName(U) ses.Show() # %% [md] # # Rather than rendering the flow lines, you can also render the sample points that are taken along the flow path individually. # # %% ren.SetRenderType(ren.RenderType.RenderTypeSamples) ses.Show() # %% ren.SetRenderGlyphType(ren.GlpyhType.GlpyhTypeArrow) ren.SetRenderRadiusScalar(7) ses.Show() # %% # Reset the rendering style for the next section ren.SetRenderRadiusScalar(3) ren.SetRenderType(ren.RenderType.RenderTypeStream) # %% [md] # # ## Seeding the advection # # The seeds from which the advected particles start can be configured in a variety of manners. # Call help(renderer.FlowRenderer) to see additional options. # # %% [md] # # ### Uniform Distribution # # This is the default. It creates a uniformly distributed grid of seed points over the area/volume of the advected region. # # %% ren.SetSeedGenMode(ren.FlowSeedMode.UNIFORM) rake = ren.GetRakeRegion() defaultRakeExtents = rake.GetExtents() rake.SetExtents((20, 20), (40, 40)) print(f"Seeding a {ren.GetGridNumOfSeeds()} grid over {rake.GetExtents()}") ses.Show() rake.SetExtents(*defaultRakeExtents) # %% [md] # # ### Random Distribution # # %% ren.SetSeedGenMode(ren.FlowSeedMode.RANDOM) print(f"Seeding {ren.GetRandomNumOfSeeds()} random points over {rake.GetExtents()}") ses.Show() # %% [md] # # ### Biased Distribution # # This generates a random list of seed points however they are biased by a given variable. # The number of seed points can be higher or lower based on the value of the `RakeBiasVariable`. # You can set the `RakeBiasStrength` to a negative value to invert the bias. # # %% ren.SetSeedGenMode(ren.FlowSeedMode.RANDOM_BIAS) ren.SetRakeBiasVariable(V) ren.SetRakeBiasStrength(1) print(f"Seeding {ren.GetRandomNumOfSeeds()} random points biased by {ren.GetRakeBiasVariable()} over {rake.GetExtents()}") ses.Show() # %% [md] # # ### Manual List # # You can pass in a manually created list of seeds using a basic text file format. # The code below generates an example seed file and passes it to Vapor. # The full documentation for the seed file format can be found on Vapor's website. # # %% with open("flow_seeds.txt", "w") as f: print("# X, Y, Z, T (optional)", file=f) print("10, 10, 0", file=f) print("20, 20, 0", file=f) ren.SetSeedGenMode(ren.FlowSeedMode.LIST) ren.SetSeedInputFilename("flow_seeds.txt") ses.Show() # %% [md] # # ### Outputting Flow Lines # # The advected flow lines can be saved to a .csv file # # %% ren.SetFlowlineOutputFilename("flow_output.csv") # Needs to be set once per renderer ren.SetFlowOutputMoreVariables([U, V]) # Optionally specify additional variables to sample at each point ren.SetNeedFlowlineOutput(True) # Needs to be called before each render call that should output the computed flow in a .csv file _ = ses.RenderToImage() # This returns a PIL image variable that is not displayed by default and can be ignored if only saving flow output # %% import pandas as pd pd.read_csv("flow_output.csv", sep=",").head(10) ================================================ FILE: apps/pythonapi/example_scripts/numpy_example.py ================================================ # %% [md] # # # Rendering Numpy data with Vapor # # Vapor supports rendering 2D and 3D numpy data. # In order to pass Numpy data to Vapor, create a data set of the type `vapor.dataset.PYTHON` # This can also be done with the convenience function `Session.CreatePythonDataset()`. # You can add numpy arrays as variables to that dataset by using `Dataset.AddNumpyData`. # # These variables can then be rendered normally using any of Vapor's renderers. # # %% import example_utils from vapor import session, renderer, dataset, camera import numpy as np from math import sqrt ses = session.Session() data = ses.CreatePythonDataset() # %% # Create a 2D numpy array and add it to vapor's dataset np_array = example_utils.SampleFunctionOnRegularGrid( lambda x,y: abs(sqrt((x-0.5)**2+(y-0.5)**2)-0.4)<0.02 or y, shape=(64,65) ) data.AddNumpyData("variable_name", np_array) print(np_array) # %% # Create a renderer for the data ren = data.NewRenderer(renderer.TwoDDataRenderer) ren.SetVariableName("variable_name") # %% # Show the rendering ses.GetCamera().ViewAll() ses.Show() ================================================ FILE: apps/pythonapi/example_scripts/rotate_video.py ================================================ # %% [md] # # # Rotate Video # # This script will render an animated rotating view of your session file. # # Also requires the `scipy` package. # # %% import example_utils import cv2, os from vapor import session, animation from numpy import cross, eye, dot, radians, asarray, array from scipy.linalg import expm, norm UseValueFromSessionFile = None # %% [md] # # ## Configuration # # %% session_path = "/path/to/session.vs3" output = "animation.mp4" video_framerate = 30 video_resolution = (640, 480) data_timestep_framerate = 6 # set to zero to disable duration = 4 # seconds rotate_speed = 90 # deg/s rotation_axis = [0,0,1] # Z (up) rotation_center = UseValueFromSessionFile # Can be replaced with [x,y,z] coordinates here save_individual_frames = False # %% --------------------------------------------------------------------------------------- session_path, output = [os.path.expanduser(p) for p in (session_path, output)] n_frames = video_framerate * duration ses = session.Session() ses.Load(session_path) ses.SetResolution(*video_resolution) cam = ses.GetCamera() pos, dir, up, tgt = [asarray(x) for x in [cam.GetPosition(), cam.GetDirection(), cam.GetUp(), cam.GetTarget()]] if rotation_center: tgt = asarray(rotation_center) def rotation_matrix(axis, theta): return expm(cross(eye(3), axis / norm(axis) * theta)) anim = animation.Animation(ses) for i in range(0, n_frames): print(f"Rendering... [{'#'*round(40*i/(n_frames-1))}{' '*round(40*(1-i/(n_frames-1)))}] {100*(i+1)/n_frames:.0f}%", end="\r" if i < n_frames-1 else "\n") ses.SetTimestep(int(data_timestep_framerate * i / video_framerate)) M = rotation_matrix(rotation_axis, radians(rotate_speed) * i / video_framerate) cam.SetPosition(dot(M, pos - tgt) + tgt) cam.SetDirection(dot(M, dir)) cam.SetUp(dot(M, up)) anim.CaptureFrame() if save_individual_frames: ses.Render(f"{output}_{i:04}.png") anim.SaveMP4(output, video_framerate) ================================================ FILE: apps/pythonapi/example_scripts/transfer_function_example.py ================================================ # %% [md] # # # Transfer Functions # # %% import example_utils from vapor import session, renderer, dataset, camera, transferfunction from vapor.utils import histogram ses = session.Session() data = example_utils.OpenExampleDataset(ses) ren = data.NewRenderer(renderer.VolumeRenderer) ses.GetCamera().LookAt((32, 120, 120), (32, 32, 32)) ses.Show() # %% [md] # # We created a volume rendering however it is fully opaque. # We can use a transfer function to adjust the visible portions. # Before we adjust the opacity map of the TF, we get a histogram to help us determine what we want to hide. # # %% histogram.ShowMatPlotLibHistogram(ses, ren) # %% [md] # # Usually we want to hide the most common value so below we construct an opacity map that accomplishes this. # # %% # List of x,y pairs where x is the data value and y is the opacity for that data value opacities = [(-0.3, 1), (-0.1, 0), (0.1, 0), (0.3, 1)] # %% [md] # # We can get the matplotlib histogram plot and add our opacity map to it to compare. # # %% plt = histogram.GetMatPlotLibHistogram(ses, ren) plt.plot(*zip(*opacities)) plt.show() # %% [md] # # Now we apply the map to the transfer function # # %% # Renderers can have multiple transfer functions. # GetPrimaryTransferFunction returns the one that is usually the most useful. # You can use `tf.GetTransferFunction(var_name)` to get other transfer functions. tf = ren.GetPrimaryTransferFunction() tf.SetOpacityControlPoints(opacities) ses.Show() # %% [md] # # You can adjust the colormap in a similar fashion. Use `help(tf)` for more information. # Vapor includes a list of built-in colormaps and these can be applied with `tf.LoadBuiltinColormap(name)` # # ## Builtin Colormaps # # %% tf.LoadBuiltinColormap("Sequential/BlackBodyExtended") ses.Show() # %% [md] # # ## List of All Builtin Colormaps # # %% ses.DeleteRenderer(ren) ren = data.NewRenderer(renderer.TwoDDataRenderer) tf = ren.GetPrimaryTransferFunction() for cmap in transferfunction.TransferFunction.ListBuiltinColormaps(): tf.LoadBuiltinColormap(cmap) print(cmap) tf.ShowMatPlotLibColorbar() ================================================ FILE: apps/pythonapi/example_scripts/visualizer_widget_example.py ================================================ # %% [md] # # # Visualizer Widgets # # Visualizer widgets allow you to interactively explore a session as you would in a Vapor GUI visualizer. # This notebook shows how to use visualizer widgets and how to add additional dynamic parameter inputs. # # %% import example_utils from vapor import session, renderer, dataset, camera ses = session.Session() data = example_utils.OpenExampleDataset(ses) # %% [md] # # ## Render an Iso Surface # # %% ren = data.NewRenderer(renderer.VolumeIsoRenderer) ren.SetVariableName(data.GetDataVarNames(3)[0]) # Set to first 2D data variable ren.SetIsoValues([ren.GetIsoValues()[0]+0.1]) ses.GetCamera().ViewAll() ses.Show() # %% [md] # # ## Create a visualizer to explore the scene # # Try dragging the image to rotate the view. # Hover over the visualizer to see the full controls. # # %% from vapor import widget viz = widget.VaporVisualizerWidget(ses) viz # %% [md] # # ## Add an interactive iso value slider using **ipywidgets** # # %% import ipywidgets tf = ren.GetPrimaryTransferFunction() dataRange = tf.GetMinMaxMapValue() def sliderChanged(change): ren.SetIsoValues([change.new]) viz.Render(fast=True) slider = ipywidgets.FloatSlider(value=ren.GetIsoValues()[0], min=dataRange[0], max=dataRange[1], step=(dataRange[1]-dataRange[0])/100) slider.observe(sliderChanged, names='value') ipywidgets.VBox([ viz, ipywidgets.HBox([ipywidgets.Label("Iso value:"), slider]) ]) ================================================ FILE: apps/pythonapi/example_scripts/workflow_example.py ================================================ # %% [md] # # # Vapor Python Tutorial # # This shows an example workflow with vapor. # We begin by creating a session and opening a dataset. # You can have multiple sessions open at the same time. # # %% import example_utils from vapor import session, renderer, dataset, camera # %% ses = session.Session() data = example_utils.OpenExampleDataset(ses) # %% [md] # # ## Dump the dataset metadata # # %% print("Time Coordinate Variable Name:", data.GetTimeCoordVarName()) print("Coordinate Variable Names:", data.GetCoordVarNames()) print("Dimensions:") for dim in data.GetDimensionNames(): print(f" {dim}:", data.GetDimensionLength(dim, 0)) print("Data Variables:") for var in data.GetDataVarNames(): print(f" {var}") print(f" Time Varying:", bool(data.IsTimeVarying(var))) print(f" Dimensionality:", data.GetVarGeometryDim(var)) print(f" Coordinates:", data.GetVarCoordVars(var, True)) print(" Data Range:", data.GetDataRange(var)) # %% [md] # # ## Render the first 2D variable as a pseudocolor # # %% first_2d_var = data.GetDataVarNames(2)[0] print(f"Rendering 2D variable {first_2d_var}") ren = data.NewRenderer(renderer.TwoDDataRenderer) ren.SetVariableName(first_2d_var) ren.GetPrimaryTransferFunction().SetMinMapValue(-1) ren.GetPrimaryTransferFunction().SetMaxMapValue(1) ses.GetCamera().ViewAll() ses.Show() ses.DeleteRenderer(ren) # %% [md] # # ## Render U10 and V10 as barbs over a map # # %% # If your dataset is geo-referenced, this will automatically render a geographically correct map. # map_ren = data.NewRenderer(renderer.ImageRenderer) barbs = data.NewRenderer(renderer.BarbRenderer) barbs.SetDimensions(2) barbs.SetFieldVariableNames(['U10', 'V10']) barbs.SetLineThickness(2) ses.Show() ses.DeleteRenderer(barbs) # %% [md] # # ## Simulate and render a flow advection # # %% flow = data.NewRenderer(renderer.FlowRenderer) flow.SetFieldVariableNames(['U10', 'V10']) ses.Show() ses.DeleteRenderer(flow) # %% [md] # # ## Volume render a 3D variable # # %% volume = data.NewRenderer(renderer.VolumeRenderer) volume.SetVariableName("V") tf = volume.GetPrimaryTransferFunction() tf.SetOpacityList([1, 0, 0, 1]) ses.GetCamera().ViewAll() ses.Show() # Show a colorbar for the volume rendering tf.ShowMatPlotLibColorbar(label="V") # %% [md] # # ## Scale the dataset Z axis # # Vapor will automatically scale the Z axis of a dataset to produce reasonable results. # This can be manually adjusted as shown below. # # %% scales = data.GetTransform().GetScales() print("Default dataset scaling =", scales); scales[2] *= 0.3 data.GetTransform().SetScales(scales) print("New dataset scaling =", data.GetTransform().GetScales()); ses.Show() # %% [md] # # ## Add axis annotations to the rendering # # %% annotations = ses.GetAxisAnnotations() annotations.SetAxisAnnotationEnabled(True) ses.Show() # %% [md] # # ## Saving figures # # %% ses.Render("figure.png") ses.Render("figure.jpg") ses.Render("figure.tif") # %% [md] # # ## Export the session for use in the Vapor GUI application # # Sessions created in Python can be saved as a .vs3 file. # These files can then be opened in the Vapor GUI application and explored interactively. # Conversely, sessions created in the Vapor GUI can be loaded into Python with `Session.Load(path)` # # Since this example uses a dynamically generated dataset, the session cannot be saved as # it would point to a dataset that does not exist on disk. If you were using a physical dataset, # this would work. # # %% ses.Save("tutorial.vs3") ================================================ FILE: apps/pythonapi/example_scripts/xarray_example.py ================================================ # %% [md] # # # Rendering XArray data with Vapor # # Vapor supports render XArray data in a similar fashion to Numpy data # In order to pass XArray data to Vapor, create a data set of the type `vapor.dataset.PYTHON` # This can also be done with the convenience function `Session.CreatePythonDataset()`. # You can add XArray variables as vapor variables to that dataset by using `Dataset.AddXArrayData`. # # These variables can then be rendered normally using any of Vapor's renderers. # # %% import example_utils from vapor import session, renderer, dataset, camera import xarray as xr import numpy as np from math import cos, sin, pi ses = session.Session() data = ses.CreatePythonDataset() # %% [md] # # Below we generate an XArray variable that consists of a curvilinear 2D grid. # You can also open an existing dataset with `xarray.open_dataset` and use variables in that dataset. # # %% def gen2d(w,h,f): """Generate a 2D grid of size (w,h) by evaluating f(x,y) for every x,y coordinate""" ay = [] for y in range(0,h): ax = [] for x in range(0,w): ax += [f(x,y)] ay += [ax] return ay w = h = 8 curveVar = xr.DataArray( np.random.randn(8, 8), dims=("x", "y"), coords={ "x_coord": xr.DataArray(gen2d(8,8,lambda x,y: cos(y/(h-1)*pi) * (x+(w+1))), dims=("x", "y")), "y_coord": xr.DataArray(gen2d(8,8,lambda x,y: sin(y/(h-1)*pi) * (x+(w+1))), dims=("x", "y")) }) data.AddXArrayData("variable_name", curveVar) # %% # Create a renderer for the data ren = data.NewRenderer(renderer.WireFrameRenderer) ren.SetVariableName("variable_name") # %% # Show the rendering ses.GetCamera().ViewAll() ses.Show() # %% ses.DeleteRenderer(ren) # %% [md] # # Below we generate an XArray variable that consists of a curvilinear 3D grid. # # %% def gen3d(w,h,d,f): """Generate a 3D grid of size (w,h,d) by evaluating f(x,y,z) for every x,y,z coordinate""" az = [] for z in range(0,d): ay = [] for y in range(0,h): ax = [] for x in range(0,w): ax += [f(x,y,z)] ay += [ax] az += [ay] return az w = h = d = 8 curveVar = xr.DataArray( gen3d(w,h,d,lambda x,y,z: z*w*h + y*w + x), dims=("x", "y", "z"), coords={ "x_coord": xr.DataArray(gen2d(w,h,lambda x,y: x), dims=("x", "y")), "y_coord": xr.DataArray(gen2d(w,h,lambda x,y: y), dims=("x", "y")), "z_coord": xr.DataArray(gen3d(w,h,d,lambda x,y,z: z), dims=("x", "y", "z")), }) data.AddXArrayData("variable_3d", curveVar) # %% # Create a renderer for the data ren = data.NewRenderer(renderer.WireFrameRenderer) ren.SetVariableName("variable_3d") # %% # Show the rendering ses.GetCamera().ViewAll() ses.Show() ================================================ FILE: apps/pythonapi/setup.py ================================================ from distutils.core import setup from pathlib import Path import itertools import sys, os import cmake print("========================================================================") import sys; print(f"Python Version = {sys.version.split(' ')[0]} ({sys.prefix})") if cmake.BUILD_TYPE.lower() != "release": print("WARNING building wheel with non-release build") print("========================================================================") def GenerateSetupDataFilesFormattedListForDir(root, prefix=""): root = Path(root) prefix = Path(prefix) files = filter(Path.is_file, root.glob('**/*')) files = sorted(files, key=lambda f:f.parent) ret = [(str(prefix / g.relative_to(root)), [str(p) for p in f]) for g, f in itertools.groupby(files, lambda f:f.parent)] return ret def PrintSetupDataFilesFormattedList(l): for target, files in l: print(target) for f in files: print(f"\t{f}") cpackComponents = list(Path(cmake.CPACK_STAGING_DIR).iterdir()) cpackFormattedFiles = [GenerateSetupDataFilesFormattedListForDir(c, prefix='vapor') for c in cpackComponents] cpackFormattedFiles = list(itertools.chain(*cpackFormattedFiles)) def IsCondaBuild(): if os.environ.get('CONDA_BUILD', None) == '1': return True # if 'conda-bld' in sys.executable.lower(): return True # if 'conda-bld' in os.environ.get('PIP_CACHE_DIR', None).lower(): return True return False install_requires=[ 'cppyy', 'xarray', 'scipy', # Required for NetCDF support in xarray 'matplotlib', 'ipython', 'jupyter', ] # Disable pip requirements for conda build # Otherwise, conda needs to have these packages in its build requirements # and they need to be installed during build-time otherwise pip will try to # install them and break if IsCondaBuild(): install_requires = [] setup(name='vapor', version=cmake.VERSION_STRING, description='NCAR Vapor Python Interface', long_description=f"Detailed Version: {cmake.VERSION_STRING_FULL}.{cmake.BUILD_TYPE}", author='Vapor Team', author_email='vapor@ucar.edu', url='https://www.vapor.ucar.edu', packages=['vapor'], install_requires=install_requires, # Duplicates symlinked libraries (adds ~200MB to install) # Based on python mailing lists, this is intentional and currently the only option (https://discuss.python.org/t/symbolic-links-in-wheels/1945/12) data_files=cpackFormattedFiles, # data_files=[ # ('vapor/lib', list(map(str, chain(cmake_lib_dir.glob("*.dylib"), cmake_lib_dir.glob("*.so"))))), # ('vapor/doc', [str(cmake_doc_dir)]), # ('vapor', cmakeInstallFiles), # ], # package_data = {'vapor': [f"{cmake_lib_dir}/*.dylib"]}, # package_data = {'': ["/Users/stasj/Work/vapor-xcode/lib/Debug/libvdc.dylib"]}, # package_data = {'': ["*.dat", "test_folder/*.dat"]}, ) ================================================ FILE: apps/pythonapi/tests/CanvasStreamTest.ipynb ================================================ { "cells": [ { "cell_type": "code", "execution_count": null, "id": "1fccf099", "metadata": {}, "outputs": [], "source": [ "import example_utils\n", "from vapor import widget\n", "\n", "w = widget.CanvasStreamWidget(debug=True)\n", "w" ] }, { "cell_type": "code", "execution_count": null, "id": "a525e1bd", "metadata": {}, "outputs": [], "source": [ "w" ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "region_name,-all", "main_language": "python", "notebook_metadata_filter": "-all" } }, "nbformat": 4, "nbformat_minor": 5 } ================================================ FILE: apps/pythonapi/tests/bld.bat ================================================ "%PYTHON%" setup.py install if errorlevel 1 exit 1 ================================================ FILE: apps/pythonapi/tests/build.sh ================================================ $PYTHON setup.py install ================================================ FILE: apps/pythonapi/tests/cppyy-syntax-test.py ================================================ import cppyy from ctypes import c_int cppyy.cppdef(""" #include using std::string; void p(string s) { printf("CPP %s\\n", s.c_str()); } void testVoid(void (*cb)(void)) { printf("TEST VOID\\n"); cb(); } void testRet(string (*cb)(void)) { string s = cb(); printf("TEST RET = %s\\n", s.c_str()); } void testIn(string (*cb)(string)) { string s = cb("CPP STR"); printf("TEST RET = %s\\n", s.c_str()); } void testInConstRef(string (*cb)(const string &)) { string s = cb("CPP STR"); printf("CONST TEST RET = %s\\n", s.c_str()); } """) # cppyy.gbl.p("hello") def cb(): print("Python Callback") return "" def cb2(s): print(f"Python Callback({s})") # s = "d" return f"" # raise FileNotFoundError return None cppyy.gbl.testVoid(cb) cppyy.gbl.testRet(cb) cppyy.gbl.testIn(cb2) cppyy.gbl.testInConstRef(cb2) exit() cppyy.cppdef(""" void ref_int(int &a) { a = 42; } #include using std::string; void ref_str(string &s) { s = "hello"; } """) a = c_int(3) cppyy.gbl.ref_int(a) print(a) # does not work # s = "bye" # cppyy.gbl.ref_str(s) # print(s) s = cppyy.gbl.std.string("bye") cppyy.gbl.ref_str(s) print(s) ================================================ FILE: apps/pythonapi/tests/cppyy-test.py ================================================ import cppyy cppyy.add_include_path('/Users/stasj/Work/vapor/apps/vapi') cppyy.add_include_path('/Users/stasj/Work/vapor/include') cppyy.add_include_path('/usr/local/VAPOR-Deps/2019-Aug/include/') cppyy.load_library('/Users/stasj/Work/vapor-xcode/lib/Debug/libcommon.dylib') # class Session: # def __init__(self): # print("New Session") cppyy.include('vapor/Version.h') vaporVersion = cppyy.gbl.Wasp.Version() print(type(vaporVersion).__cpp_name__, "=", vaporVersion.GetVersionString()) cppyy.load_library('/Users/stasj/Work/vapor-xcode/lib/Debug/libvapi.dylib') cppyy.include('vapor/MyPython.h') cppyy.gbl.Wasp.MyPython.IsRunningFromPython = True cppyy.include('GLContextProvider.h') ctx = cppyy.gbl.GLContextProvider.CreateContext() print("GL Version =", ctx.GetVersion()) cppyy.include('Session.h') session = cppyy.gbl.Session() session.Load("/Users/stasj/Work/sessions/time.vs3") session.Render("/Users/stasj/Work/out-python-cppyy.png") print("HERERRER ====") exit(0) ================================================ FILE: apps/pythonapi/tests/meta.yaml ================================================ package: name: vapor version: "@VERSION_STRING@" source: path: . requirements: build: - python run: - python=@Python_VERSION@ - numpy=@Python_NumPy_VERSION@ - cppyy - xarray - scipy # Required for NetCDF support in xarray - matplotlib - ipython - jupyter # Conda will try to compile every python file in the proejct by default # Vapor has some misc python2 files left over which fail to compile build: skip_compile_pyc: - "*.py" about: home: "https://www.vapor.ucar.edu" ================================================ FILE: apps/pythonapi/tests/module-data-test.py ================================================ import numpy as np arr = np.arange(32**3, dtype=np.float32).reshape(32, 32, 32) print("Type =", arr.dtype) print(type(arr)) # exit(0) from vapor import session, renderer, dataset, camera ses = session.Session() data = ses.OpenDataset(dataset.PYTHON, "dataset_name") data.AddNumpyData("data_1", arr) ren = data.NewRenderer(renderer.WireFrameRenderer) ren.SetVariableName("data_1") cam = ses.GetCamera() # cam.ViewAll() cam.LookAt((50, 50, 40), (16, 16, 16)) # cam.LookAt((3, 3, 2), (0.5, 0.5, 0.5)) ses.Render("out-data-test-1.png") arr = np.arange(32**3*2, dtype=np.float32).reshape(32, 32*2, 32) data.AddNumpyData("data_1", arr) ren.SetVariableName("data_1") ses.Render("out-data-test-2.png") ren.SetEnabled(False) arr = np.arange(32**2, dtype=np.float32).reshape(32, 32) data.AddNumpyData("data_2d_1", arr) ren = data.NewRenderer(renderer.TwoDDataRenderer) ren.SetVariableName("data_2d_1") ses.Render("out-data-test-3.png") import xarray as xr xrd = xr.open_dataset("/Users/stasj/Work/data/time/time_01.nc") data.AddXArrayData("XR_Sphere", xrd.sphere) ren.SetVariableName("XR_Sphere") cam.ViewAll() ses.Render("out-data-test-4.png") def gen2d(w,h,f): ay = [] for y in range(0,h): ax = [] for x in range(0,w): ax += [f(x,y)] ay += [ax] return ay from math import cos, sin, pi w = h = 8 curveVar = xr.DataArray( np.random.randn(8, 8), dims=("x", "y"), coords={ "x_coord": xr.DataArray(gen2d(8,8,lambda x,y: cos(y/h*pi) * (x+(w+1))), dims=("x", "y")), "y_coord": xr.DataArray(gen2d(8,8,lambda x,y: sin(y/h*pi) * (x+(w+1))), dims=("x", "y")) }) data.AddXArrayData("XR_Curve", curveVar) ren.SetVariableName("XR_Curve") cam.ViewAll() ses.Render("out-data-test-5.png") ================================================ FILE: apps/pythonapi/tests/module-test.py ================================================ from vapor import session, renderer, dataset, camera ses = session.Session() data = ses.OpenDataset(dataset.VDC, "/not/found/data.vdc") print(f"Not found data = '{data}'") # ses.Load("/Users/stasj/Work/sessions/time-empty.vs3") # data = ses.GetDatasets()[0] data = ses.OpenDataset(dataset.VDC, "/Users/stasj/Work/data/time/time.vdc") ren = data.NewRenderer(renderer.TwoDDataRenderer) # ren = ses.NewRenderer(renderer.TwoDDataRenderer, "time.vdc") ren.SetEnabled(True) ses.Render("out-python-cppyy.png") ses.Show() ren.SetRefinementLevel(3) ren.SetCompressionLevel(3) tf:renderer.TransferFunction = ren.GetPrimaryTransferFunction() tf.LoadBuiltinColormap('Sequential/amp') tf.SetOpacityList([1, 0, 1]) print(f"TF Mapping Range for {ren.GetVariableName()} is {tf.GetMinMapValue()} - {tf.GetMaxMapValue()}") ses.SetTimestep(1) ses.Render("out-python-cppyy-2.png") ses.SetResolution(300,300) ses.Save("out-session-time.vs3") ses.Show() ################################# # Another session ses2 = session.Session() maycontrol = ses2.OpenDataset(dataset.VDC, "/Users/stasj/Work/data/24Maycontrol.01/24Maycontrol.01.vdc") vol = maycontrol.NewRenderer(renderer.VolumeRenderer) print(f"Volume var name = '{vol.GetVariableName()}'") cam = ses2.GetCamera() cam.LookAt((-2.5, -2.5, 20), (-2.5,-2.5, 2.5)) ses2.Render("out-python-cppyy-maycontrol.png") ses2.Save("out-session-dbz.vs3") ================================================ FILE: apps/pythonapi/tests/syntax-test.py ================================================ # import functools # # class Inner(): # def __init__(self): # self.x = 0 # # def SetX(self, x): # self.x = x # # def GetX(self): # return self.x # # class Outer(): # def __init__(self): # self.inner = Inner() # # expose = ["SetX", "GetX"] # for f in expose: # # def wrapper(func): # @functools.wraps(func) # def wrapper_do_twice(*args, **kwargs): # return func(*args, **kwargs) # return wrapper_do_twice # # return func(*args, **kwargs) # # func = getattr(Inner, f) # # setattr(Outer, f, wrapper(func)) # print("setattr(Outer, {}, {}".format(f, wrapper)) # # setattr(Outer, "SetX", lambda self, x: self.inner.SetX(x)) # # setattr(Outer, "GetX", lambda self: self.inner.GetX()) # # setattr(self, f, getattr(self.inner, f)) # # out = Outer() # help(out) # # out.inner.SetX(3) # print(out.inner.GetX()) # # out.SetX(5) # print(out.GetX()) ############################################################# import functools print("============ Define Classes ============") def log(func): @functools.wraps(func) def wrapper_debug(*args, **kwargs): args_repr = [repr(a) for a in args] # 1 kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()] # 2 signature = ", ".join(args_repr + kwargs_repr) # 3 value = func(*args, **kwargs) print(f"Call {func.__name__}({signature}) = {value!r}") return value return wrapper_debug # class Params(): # def Other(self): # print("Other") # # class SubParams(Params): # def __init__(self): # self.en = False # def SetEnabled(self, e): # self.en = e # def IsEnabled(self): # return self.en # # def funcWrapper(func): # @functools.wraps(func) # def f(self, *args, **kwargs): # ret = func(self._params, *args, **kwargs) # print(f"Call {func.__name__}({', '.join([repr(a) for a in args[1:]])}) = {ret!r}", ) # return ret # return f # # class ParamsWrapperMeta(type): # def __init__(cls, *args, **kwargs): # super().__init__(*args, **kwargs) # # for f in cls._wrap: # print("wrap", f) # func = getattr(Params, f) # setattr(cls, f, funcWrapper(func)) # # class ParamsWrapperMeta2(type): # @log # def __new__(cls, clsname, bases, clsdict): # wrapped = {f:funcWrapper(getattr(Params, f)) for f in clsdict['_wrap']} # clsdict.update(wrapped) # # # for f in clsdict['_wrap']: # # print("wrap", f) # # func = getattr(Params, f) # # clsdict.update({f:funcWrapper(func)}) # # return type.__new__(cls, clsname, bases, dict(clsdict)) # # @log # def __init__(cls, *args, **kwargs): # super().__init__(*args, **kwargs) # # class ParamsWrapper(object, metaclass=ParamsWrapperMeta2): # _paramsCls = Params # _wrap = [] # # def __init__(self, p:Params): # self._params = p # class Renderer(ParamsWrapper): # _paramsCls = SubParams # _wrap = ["SetEnabled", "IsEnabled"] # print("============ Test Script ============") # help(Renderer) # print([f for f in dir(Renderer) if not f.startswith('__')]) # r = Renderer(Params()) # r.SetEnabled(True) # r.IsEnabled() # print("r._params.en =", r._params.en) import re class ParentClass(): def printTest(self): """Prints test""" print(f"Test from {self.__class__.__name__}") class ChildClass(ParentClass): def printTest(self): """Overloaded prints test""" print(f"Overloaded test from {self.__class__.__name__}") def printTest2(self): """Prints test 2""" print(f"Test 2 from {self.__class__.__name__}") from vapor.smartwrapper import * class ParentWrapped(SmartWrapper, wrap=ParentClass): printTest = FuncWrapper() # a, b = [FuncWrapper]*2 # c, d, *_ = FuncWrappers() pass class ChildWrapped(ParentWrapped, wrap=ChildClass): _ = FuncWrapperWrapAll() printTestRenamed = FuncWrapperRename("printTest") # printTest2 = FuncWrapper() print() print("============ Test Script ============") pc = ParentClass() cc = ChildClass() pw = ParentWrapped(pc) cw = ChildWrapped(cc) pc.printTest() cc.printTest() pw.printTest() cw.printTest() cw.printTestRenamed() # help(ChildWrapped) ================================================ FILE: apps/pythonapi/tests/test.py ================================================ # jupytext --to notebook test.py # jupyter nbconvert --to notebook --inplace --execute test.ipynb # # cat test.py | jupytext --to ipynb | jupyter nbconvert --stdin --execute --no-input --to html --output notebook.html # jupyter nbconvert --to html --no-input --execute annotation_example.ipynb # jupyter nbconvert --to pdf --execute annotation_example.ipynb import numpy as np from math import * from vapor import session, renderer, dataset, camera, transferfunction, utils # help(renderer.VolumeRenderer) ses = session.Session() data = ses.CreatePythonDataset() from inspect import signature def sample(f, ext=None, shape=None): if not shape: shape = [64]*len(signature(f).parameters) if not ext: ext = [(0,1)]*len(signature(f).parameters) assert len(signature(f).parameters) == len(shape) and len(shape) == len(ext) d = [] for i in np.ndindex(*reversed(shape)): d.append(f(*[v/s*(t-f)+f for v,s,(f,t) in zip(reversed(i), shape, ext)])) return np.asarray(d, dtype=np.float32).reshape(shape) # arr = sample(lambda x,y: sin(6*x)+sin(6*y)) arr = sample(lambda x,y: (x+y)*np.exp(-5.0*(x**2+y**2)), ext=[(-1,1)]*2) data.AddNumpyData("data_2d_1", arr) ren = data.NewRenderer(renderer.TwoDDataRenderer) ren.SetVariableName("data_2d_1") ren.GetColorbarAnnotation().SetEnabled(True) # utils.ShowHistogram(ses, ren) # utils.ShowHistogram(ses, ren, bins=5) cam = ses.GetCamera() cam.ViewAll() tf = ren.GetPrimaryTransferFunction() # tf.SetColorNormalizedHSVControlPoints([(0, (0,1,1)), (1, (0.5,1,1))]) # tf.SetColorNormalizedHSVControlPoints([(h/20, (h/20,1,1)) for h in range(0,20)]) # tf.SetColorNormalizedRGBControlPoints([(0, (1,0,0)), (1, (0,1,0))]) tf.SetColorRGBList([(1,0,0), (0,1,0), (0,0,1)]) tf.LoadBuiltinColormap("Sequential/matter") # tf.ShowMatPlotLibColorbar() # exit() ses.Show() ren.SetEnabled(False) # ses.Render("out-data-test-3.png") # ren = data.NewRenderer(renderer.ImageRenderer) # for map in ren.ListBuiltinMaps(): # ren.SetBuiltinMap(map) # ses.Show() # ses.DeleteRenderer(ren) ren = data.NewRenderer(renderer.FlowRenderer) ren.SetFieldVariableNames(["data_2d_1"]*2) ren.SetRenderType(ren.RenderType.RenderTypeSamples) ren.SetRenderRadiusScalar(5) ren.SetRenderGeom3D(True) ren.SetGridNumOfSeeds([5,5]) ses.Show() ses.DeleteRenderer(ren) ren = data.NewRenderer(renderer.BarbRenderer) ren.SetFieldVariableNames(["data_2d_1"]*2) ren.GetRenderRegion().SetExtents([5,5],[40,40]) ren.SetXBarbsCount(3) ses.Show() ses.DeleteRenderer(ren) ren = data.NewRenderer(renderer.ContourRenderer) ren.SetVariableName("data_2d_1") dmin = ren.GetPrimaryTransferFunction().GetMinMapValue() dmax = ren.GetPrimaryTransferFunction().GetMaxMapValue() isos = [dmin + (dmax-dmin)*i/40 for i in range(40)] ren.SetIsoValues(isos) ses.Show() # ses.DeleteRenderer(ren) # arr = sample(lambda x,y,z: sin(10*x)+sin(10*y)+sin(10*z)) arr = sample(lambda x,y,z: (x+y+z)*np.exp(-5.0*(x**2+y**2+z**2)), ext=[(-1,1)]*3) data.AddNumpyData("data_3d_1", arr) ren = data.NewRenderer(renderer.VolumeRenderer) ren.SetVariableName("data_3d_1") tf = ren.GetPrimaryTransferFunction() # tf.SetOpacityList([0,0,1]) tf.SetOpacityList([1,0,1]) # cam.ViewAll() cam.LookAt((-120,120,120), (32,32,32)) ses.Show() ren.SetEnabled(False) ren:renderer.VolumeIsoRenderer = data.NewRenderer(renderer.VolumeIsoRenderer) print("Iso Algo=", ren.GetAlgorithm()) # ren.SetIsoValues([1.8]) ren.SetIsoValues([-0.1, 0.1]) ses.Show() ses.DeleteRenderer(ren) sa = ses.GetAxisAnnotations() sa.SetAxisAnnotationEnabled(True) ren:renderer.SliceRenderer = data.NewRenderer(renderer.SliceRenderer) ses.Show() ses.DeleteRenderer(ren) ================================================ FILE: apps/pythonapi/vapor/__init__.py ================================================ from . import link import sys import hdf5plugin link.include('vapor/Version.h') vaporVersion = link.Wasp.Version() print("Vapor", vaporVersion.GetVersionString()) print(f"Python {sys.version.split(' ')[0]} ({sys.prefix})") link.include('vapor/Log.h') link.Log.InfoLevelEnabled = False link.include('vapor/Session.h') link.Session.SetWaspMyBaseErrMsgFilePtrToSTDERR() from . import config link.include('vapor/ResourcePath.h') link.Wasp.RegisterResourceFinder(config.GetResourceSafe) link.include('vapor/MyPython.h') link.Wasp.MyPython.IsRunningFromPython = True link.include('vapor/RenderManager.h') ctx = link.RenderManager.GetOSGLContext() print("OpenGL", ctx.GetVersion()) ================================================ FILE: apps/pythonapi/vapor/animation.py ================================================ import os import cv2 import tempfile from base64 import b64encode from io import BytesIO from .session import * class Animation: def __init__(self, ses:Session): self._ses = ses self._frames = [] def CaptureFrame(self): frame = self._ses.RenderToImage() if self._frames and frame.size != self._frames[0].size: raise ValueError(f"Frame resolution {frame.size} is different from animation resolution {self._frames[0].size}") self._frames.append(frame) def ShowInteractive(self): self.__requireIPython() from IPython.display import display import ipywidgets as widgets # displayHandle = display(None, display_id=True) # def callback(frame): # displayHandle.update(self._frames[frame]) play = widgets.Play( value=0, min=0, max=len(self._frames) - 1, step=1, interval=80, # _repeat=True, ) def PILtoJPG(img): buf = BytesIO() img.save(buf, format="jpeg") return buf.getvalue() imageWidget = widgets.Image( value=PILtoJPG(self._frames[0]), format='jpg', width=self._frames[0].size[0], height=self._frames[0].size[1] ) # def callback(frame): # imageWidget.value = frame # return imageWidget frameSlider = widgets.IntSlider(0, 0, len(self._frames) - 1) widgets.jslink((play, 'value'), (frameSlider, 'value')) intervalSlider = widgets.IntSlider(80, 30, 1000) widgets.jslink((intervalSlider, 'value'), (play, 'interval')) intervalWidget = widgets.HBox([widgets.Label("Animation Interval"), intervalSlider]) # output = widgets.interactive_output(callback, {'frame': frameSlider}) def frameChanged(change): imageWidget.value = PILtoJPG(self._frames[change.new]) frameSlider.observe(frameChanged, names='value') w = widgets.VBox([imageWidget, widgets.HBox([play, frameSlider]), intervalWidget]) display(w) def Show(self, framerate=15): self.__requireIPython() import IPython.display f = tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) path = f.name f.close() self.SaveMP4(path, framerate) with open(path, "rb") as f: data = f.read() IPython.display.display(IPython.display.Video(data=data, embed=True, mimetype="video/mp4")) os.unlink(path) def SaveMP4(self, path:str, framerate=15): fourcc = cv2.VideoWriter_fourcc(*'avc1') video = cv2.VideoWriter(path, fourcc, framerate, self._frames[0].size) for i in self._frames: video.write(cv2.cvtColor(np.array(i), cv2.COLOR_RGB2BGR)) video.release() if config.IsRunningFromIPython(): import IPython.display return IPython.display.FileLink(path) def __requireIPython(self): if not config.IsRunningFromIPython(): raise RuntimeError(f"{self.__class__}.Show() only supported within an IPython environment") ================================================ FILE: apps/pythonapi/vapor/annotations.py ================================================ from . import link from .params import * link.include('vapor/ColorbarPbase.h') class ColorbarAnnotation(ParamsWrapper, wrap=link.VAPoR.ColorbarPbase): _wrap = FuncWrapperStrList(""" GetCornerPosition SetCornerPosition GetSize SetSize GetTitle SetTitle IsEnabled SetEnabled GetFontSize SetFontSize GetNumTicks SetNumTicks GetNumDigits SetNumDigits GetBackgroundColor SetBackgroundColor """) _tags = ParamsTagWrapperList(""" bool UseScientificNotationTag """) link.include('vapor/AnnotationParams.h') class SceneAnnotation(ParamsWrapper, wrap=link.VAPoR.AnnotationParams): _wrap = FuncWrapperStrList(""" GetDomainColor SetDomainColor GetUseDomainFrame SetUseDomainFrame GetUseRegionFrame SetUseRegionFrame GetRegionColor GetRegionColor GetBackgroundColor SetBackgroundColor GetCurrentAxisDataMgrName SetCurrentAxisDataMgrName SetAxisFontSize GetAxisFontSize GetTimeLLX SetTimeLLX GetTimeLLY SetTimeLLY GetTimeColor SetTimeColor GetTimeType SetTimeType GetTimeSize SetTimeSize GetAxisArrowEnabled GetAxisArrowSize GetAxisArrowXPos GetAxisArrowYPos SetAxisArrowEnabled SetAxisArrowSize SetAxisArrowXPos SetAxisArrowYPos """) _tags = ParamsTagWrapperList(""" """) class TimeAnnotationType: NoAnnotation = 0 Timestep = 1 User = 2 Formatted = 3 link.include('vapor/AxisAnnotation.h') class AxisAnnotation(ParamsWrapper, wrap=link.VAPoR.AxisAnnotation): _wrap = FuncWrapperStrList(""" SetAxisAnnotationEnabled GetAxisAnnotationEnabled GetAxisBackgroundColor GetAxisBackgroundColor SetAxisBackgroundColor GetAxisColor SetAxisColor SetNumTics GetNumTics SetAxisOrigin GetAxisOrigin SetMinTics GetMinTics SetMaxTics GetMaxTics SetTicSize GetTicSize SetXTicDir GetXTicDir SetYTicDir GetYTicDir SetZTicDir GetZTicDir SetTicDirs GetTicDirs GetTicWidth SetTicWidth GetAxisTextHeight SetAxisTextHeight GetAxisDigits SetAxisDigits SetLatLonAxesEnabled GetLatLonAxesEnabled GetShowAxisArrows SetShowAxisArrows SetAxisFontSize GetAxisFontSize """) _tags = ParamsTagWrapperList(""" """) ================================================ FILE: apps/pythonapi/vapor/camera.py ================================================ from . import link from .common import * import numpy as np link.include('vapor/ControlExecutive.h') link.include("vapor/NavigationUtils.h") NavigationUtils = link.NavigationUtils ViewpointParams = link.ViewpointParams class Camera(): __axisDict = { '+X': 2, '+Y': 3, '+Z': 4, '-X': 5, '-Y': 6, '-Z': 7 } def __init__(self, ce): self.ce: link.VAPoR.ControlExec = ce def LoadFromFile(self, path:str): """Save camera settings to file""" ViewpointParams.SetCameraFromFile(NavigationUtils.GetActiveViewpointParams(self.ce), path) def SaveToFile(self, path:str): """Load camera settings from file""" ViewpointParams.SaveCameraToFile(NavigationUtils.GetActiveViewpointParams(self.ce), path) def AlignView(self, axis:str): """ Align camera looking down an axis Axis format: [+-][XYZ] """ viewNum = self.__axisDict[axis.upper()] NavigationUtils.AlignView(self.ce, viewNum) def ViewAll(self): """Places the camera above the dataset looking down so that it is visible in its entirety. This is the default view when opening a new dataset.""" NavigationUtils.ViewAll(self.ce) def LookAt(self, camera_position:Vec3, target:Vec3, up:Vec3 = (0, 0, 1)): """Moves the camera to camera_position facing target. up can be used to adjust the camera roll.""" NavigationUtils.LookAt(self.ce, camera_position, target, up) def Zoom(self, fractionOfDistanceToTarget:float): """Moves the camera a fractionOfDistanceToTarget with positive zooming in and negative zooming out.""" tgt = self.GetTarget() pos = self.GetPosition() dist = np.linalg.norm(tgt - pos) newDist = dist * (1 - fractionOfDistanceToTarget) newPos = tgt + ((pos-tgt)/dist * newDist) self.SetPosition(newPos) def GetPosition (self): return np.array(NavigationUtils.GetCameraPosition(self.ce)) def GetDirection(self): return np.array(NavigationUtils.GetCameraDirection(self.ce)) def GetUp (self): return np.array(NavigationUtils.GetCameraUp(self.ce)) def GetTarget (self): return np.array(NavigationUtils.GetCameraTarget(self.ce)) def SetPosition (self, v:Vec3): NavigationUtils.SetCameraPosition(self.ce, v) def SetDirection(self, v:Vec3): NavigationUtils.SetCameraDirection(self.ce, v) def SetUp (self, v:Vec3): NavigationUtils.SetCameraUp(self.ce, v) def SetTarget (self, v:Vec3): NavigationUtils.SetCameraTarget(self.ce, v) def __GUIStateParams(self) -> link.GUIStateParams: pm = self.ce.GetParamsMgr() gsp = pm.GetParams(link.GUIStateParams.GetClassType()) return gsp def TrackMovingDomain(self, on=True): """Camera should follows the moving domain""" gsp = self.__GUIStateParams() gsp.SetValueLong(gsp.MovingDomainTrackCameraTag, "", on) print(f"{gsp.MovingDomainTrackCameraTag} = {bool(gsp.GetValueLong(gsp.MovingDomainTrackCameraTag, 0))}") def TrackMovingDomainRenderRegions(self, on=True): """Renderer regions will be tracked relative to the moving domain""" gsp = self.__GUIStateParams() gsp.SetValueLong(gsp.MovingDomainTrackRenderRegionsTag, "", on) ================================================ FILE: apps/pythonapi/vapor/cmake.py ================================================ from pathlib import Path SOURCE_DIR = "@PROJECT_SOURCE_DIR@" BINARY_DIR = "@CMAKE_BINARY_DIR@" THIRD_PARTY_DIR = "@THIRD_PARTY_DIR@" RELEASE = "@CMAKE_BUILD_TYPE@".lower() == "release" VAPI_COMPILE_DEFS = """@VAPI_COMPILE_DEFS@""" GLOBAL_COMPILE_DEFS = """@GLOBAL_COMPILE_DEFS@""" ================================================ FILE: apps/pythonapi/vapor/common.py ================================================ Vec3 = tuple[float, float, float] ================================================ FILE: apps/pythonapi/vapor/config.py ================================================ import sys, os import site import re from pathlib import Path from . import cmake sourcePaths = [ cmake.SOURCE_DIR, cmake.SOURCE_DIR + "/lib/osgl", cmake.SOURCE_DIR + "/lib/osgl/glad", cmake.BINARY_DIR, cmake.THIRD_PARTY_DIR, ] # Files installed using setup(data_files) are placed in one of the following two locations: # sys.prefix for system installations # site.USER_BASE for user installations # Conda installs files using setup(data_files) in a different location than pip. # Conda installs them in the module root like package_data installPaths = [ site.USER_BASE, sys.prefix, ] installPaths = [Path(p)/'vapor' for p in installPaths] modulePaths = [Path(__file__).parent] condaPaths = [os.getenv('CONDA_PREFIX', "/")] def PathExists(path): try: return path.exists() except PermissionError: return False roots = sourcePaths + installPaths + modulePaths + condaPaths allRoots = roots.copy() roots = map(Path, roots) roots = filter(PathExists, roots) roots = [*roots] # print("Resource Roots:\n\t" + "\n\t".join(map(str, roots))) if not roots: print("Error: Could not find any valid resource paths from", allRoots) quit(1) def GetAllResources(relPath): """For source builds where there can be, for example, multiple lib dirs""" ret = [] for root in roots: if (root / relPath).exists(): ret.append(str(root / relPath)) if ret: return ret raise FileNotFoundError def GetResource(relPath): for root in roots: if (root / relPath).exists(): return str(root / relPath) raise FileNotFoundError return None def GetResourceSafe(relPath): relPath = str(relPath) # If called from C++ this may be something other than a python str ret = "" try: ret = GetResource(relPath) except Exception: ret = "" if ret == None: ret = "" return ret def GetDoxygenRoot(): try: return GetResource('share/doc/xml') except FileNotFoundError: pass try: return GetResource('doc/xml') except FileNotFoundError: pass return None def GetLibraryDirs(): return GetAllResources('lib') def GetIncludeDirs(): return GetAllResources('include') def GetCompileDefinitions(debug=False): cmakeDefLists = [ cmake.VAPI_COMPILE_DEFS, cmake.GLOBAL_COMPILE_DEFS, ] cmakeDefLists = filter(lambda x: x and not x.endswith('-NOTFOUND'), cmakeDefLists) cmakeDefList = ';'.join(cmakeDefLists) defs = cmakeDefList.split(';') defs = filter(None, defs) cmds = ['#define ' + ' '.join(filter(bool, re.match(r'(\w+)=?(.*)', d).groups())) for d in defs] if debug: print('\n'.join([f"{d} -> '{s}'" for d,s in zip(defs, cmds)])) code = '\n'.join(cmds) return code def IsRunningFromIPython(): try: __IPYTHON__ return True except NameError: return False def IsRunningFromMarimo(): try: import marimo as mo return mo.app_meta().mode in ("edit", "run") except: return False def IsRunningFromNotebook(): return IsRunningFromIPython() or IsRunningFromMarimo() ================================================ FILE: apps/pythonapi/vapor/cppyyDoxygenWrapper.py ================================================ import xml.etree.ElementTree as ET import functools from . import config class CPPYYDoxygenWrapperMeta(type): __doxygenRootPath = config.GetDoxygenRoot() @classmethod @functools.cache def __GetDoxgenRoot(cls) -> ET.Element: if not cls.__doxygenRootPath: print("WARNING DOxygen not found") return None root = ET.parse(cls.__doxygenRootPath+'/index.xml').getroot() return root @classmethod @functools.cache def __GetClassIndexNode(cls, name:str) -> ET.Element: root: ET.Element = cls.__GetDoxgenRoot() if not root: return None return root.find(f"./compound/name[.='{name}']/..") @classmethod @functools.cache def __GetClassRoot(cls, name:str) -> ET.Element: classIndexNode = cls.__GetClassIndexNode(name) if not classIndexNode: return None relPath = classIndexNode.get('refid') + '.xml' absPath = f"{cls.__doxygenRootPath}/{relPath}" try: root = ET.parse(absPath).getroot() except IOError: return None return root @classmethod def __GetMemberNodes(cls, className:str, memberName:str) -> list[ET.Element]: """Returns list for overloaded functions""" root: ET.Element = cls.__GetClassRoot(className) if not root: return None return root.findall(f"./compounddef/sectiondef/memberdef/name[.='{memberName}']/..") @classmethod def __ParseDescriptionParameterList(cls, plist: ET.Element) -> str: return " ".join([t.strip() for t in plist.itertext() if t.strip()]).replace("\n","") @classmethod def __RenderParameterListSection(cls, title:str, kind:str, allLists:list[ET.Element]): ret = "" kindLists = [pl for pl in allLists if pl.get("kind") == kind] if kindLists: ret += f"\n{title}\n" for l in kindLists: ret += " " + cls.__ParseDescriptionParameterList(l) return ret @classmethod def __ParseDescriptionParagraph(cls, para: ET.Element, parameterLists: list[ET.Element] = []) -> str: if para.tag == "parameterlist" or (para.tag == "simplesect" and para.get("kind")): parameterLists.append(para) return "" text = "" if para.text: text += para.text.strip() for e in para: ret = cls.__ParseDescriptionParagraph(e, parameterLists) if ret.strip(): text += " " + ret if para.tail and para.tail.strip(): text += " " + para.tail.strip() return text @classmethod def __ParseMemberDetailedDescription(cls, member: ET.Element) -> str: ddNode = member.find('detaileddescription') paragraphs = ddNode.findall('para') parameterLists: list[ET.Element] = [] parsedParas = [cls.__ParseDescriptionParagraph(p, parameterLists) for p in paragraphs] ret = "\n".join([" "+p for p in parsedParas if p]) if parameterLists: ret += cls.__RenderParameterListSection("Parameters", "param", parameterLists) ret += cls.__RenderParameterListSection("Returns", "retval", parameterLists) ret += cls.__RenderParameterListSection("See Also", "see", parameterLists) return ret @classmethod def __CleanFunctionDefinition(cls, ds: str) -> str: ds = ds.removeprefix("virtual ") ds = ds.removesuffix(" const") return ds @classmethod def __GetDocumentationForMemberNode(cls, node: ET.Element) -> str: if node.get("kind") == "function": return cls.__GetDocumentationForFunctionNode(node) elif node.get("kind") == "variable": return cls.__GetDocumentationForVariableNode(node) @classmethod def __GetDocumentationForFunctionNode(cls, node: ET.Element) -> str: name = node.find('name').text definition = node.find('definition').text args = node.find('argsstring').text fullDefinition = cls.__CleanFunctionDefinition(definition+args) detailedDescription = cls.__ParseMemberDetailedDescription(node) return f""" {fullDefinition} {detailedDescription} """.strip() @classmethod def __GetDocumentationForVariableNode(cls, node: ET.Element) -> str: briefdescription = cls.__ParseClassDescription(node.find('briefdescription')) detaileddescription = cls.__ParseClassDescription(node.find('detaileddescription')) return f""" {briefdescription} {detaileddescription} """.strip() @classmethod def __GetFunctionDocumentation(cls, pCls:type, func) -> str: name = getattr(func, "__doxygen_name__",func.__name__) # if hasattr(func, "__doxygen_name__"): nodes = cls.__GetMemberNodes(pCls.__cpp_name__, name) if not nodes: # DOxygen does not inherit documentation so base classes need to be recursively queried if pCls.__base__ and cls.__GetClassRoot(pCls.__base__.__cpp_name__): return cls.__GetFunctionDocumentation(pCls.__base__, func) return func.__doc__ return "\n\n".join([cls.__GetDocumentationForMemberNode(node) for node in nodes]) @classmethod def __ParseClassDescription(cls, ddNode: ET.Element) -> str: paragraphs = ddNode.findall('para') parameterLists: list[ET.Element] = [] parsedParas = [cls.__ParseDescriptionParagraph(p, parameterLists) for p in paragraphs] ret = "\n".join([" " + p for p in parsedParas if p]) return ret @classmethod def __GetClassDocumentation(cls, pCls) -> str: className = pCls.__cpp_name__ root: ET.Element = cls.__GetClassRoot(className) if not root: return None root = root.find('compounddef') if not root: return None briefdescription = cls.__ParseClassDescription(root.find('briefdescription')) detaileddescription = cls.__ParseClassDescription(root.find('detaileddescription')) return f""" Wraps {className} {briefdescription} {detaileddescription} """.strip() @classmethod def _MakeFunctionWrapper(cls, pCls, func): @functools.wraps(func) def f(self, *args, **kwargs): ret = func(self, *args, **kwargs) return ret f.__doc__ = cls.__GetFunctionDocumentation(pCls, func) return f def __new__(cls, clsname, bases, clsdict:dict, wrap:type=None): if wrap: clsdict['__doc__'] = cls.__GetClassDocumentation(wrap) return super(CPPYYDoxygenWrapperMeta, cls).__new__(cls, clsname, bases, clsdict) ================================================ FILE: apps/pythonapi/vapor/dataset.py ================================================ from . import link from .smartwrapper import * from .renderer import * from .transform import * import numpy as np import xarray as xr link.include('vapor/PythonDataMgr.h') link.include('vapor/DCRAM.h') link.include('vapor/XmlNode.h') link.include('vapor/GUIStateParams.h') VDC = "vdc" WRF = "wrf" CF = "cf" MPAS = "mpas" BOV = "bov" DCP = "dcp" UGRID = "ugrid" PYTHON = "ram" class Dataset(SmartWrapper, wrap=link.VAPoR.DataMgr): _wrap = FuncWrapperStrList(""" GetDimensionNames GetDimensionLength GetDataVarNames GetCoordVarNames GetTimeCoordVarName GetVarGeometryDim GetVarTopologyDim GetVarCoordVars GetNumTimeSteps IsTimeVarying GetMeshNames GetMesh GetDimLens """) def __init__(self, dataMgr:link.VAPoR.DataMgr, id:str, ses): super().__init__(dataMgr) self.id = id self.ses = ses def NewRenderer(self, Class: Renderer) -> Renderer: return self.ses.NewRenderer(Class, self.id) def GetName(self): return str(self.id) def __str__(self): output = [] # Dataset Name output.append(f"Dataset: {self.GetName()}") # Dimensions output.append("Dimensions:") for dim in self.GetDimensionNames(): output.append(f" {dim}: {self.GetDimensionLength(dim, 0)}") # Coordinates coord_var_names = self.GetCoordVarNames() if len(coord_var_names) > 0: output.append(f"Coordinate Variable Names: {coord_var_names}") # Variables output.append("Data Variables:") for var in self.GetDataVarNames(): output.extend([ f" {var}", f" Dimensionality: {self.GetVarGeometryDim(var)}", f" Number of Timesteps: {self.GetNumTimeSteps(var)}", f" Coordinates: {self.GetVarCoordVars(var, True)}", f" Data Range: {self.GetDataRange(var)}" ]) return "\n".join(output) def __repr__(self): return self.__str__() def GetTransform(self): pm = self.ses.ce.GetParamsMgr() vp = pm.GetViewpointParams(self.ses.GetPythonWinName()) t = vp.GetTransform(self.id) return Transform(t) def GetDataRange(self, varname: str, atTimestep: int = 0): c_range = link.std.vector[link.double]() self._wrappedInstance.GetDataRange(atTimestep, varname, 0, 0, c_range) return list(c_range) @staticmethod def GetDatasetTypes(): return [VDC, WRF, CF, MPAS, BOV, UGRID] DC = link.VAPoR.DC class PythonDataset(Dataset, wrap=link.VAPoR.PythonDataMgr): def __checkNameValid(self, name): if not link.VAPoR.XmlNode.IsValidXMLElement(name): raise Exception(f"The variable name '{name}' must be a valid XML tag, i.e. [a-Z0-9_-]+") def AddNumpyData(self, name:str, arr:np.ndarray): """ Vapor expects data to be in order='C' with X as the fastest varying dimension. You can swap your axes with np.swapaxes(data, 0, -1). """ self.__checkNameValid(name) # assert arr.dtype == np.float32 if arr.__array_interface__['strides']: arr = arr.copy() # Flatten data self._wrappedInstance.AddRegularData(name, np.float32(arr), tuple(reversed(arr.shape))) # TODO: Only clear necessary renderers self.ses.ce.ClearAllRenderCaches() def AddXArrayData(self, varName:str, arr:xr.DataArray): """ Vapor supports grids commonly used in earth science data. It is recommended to import more complex datasets directly using Session.OpenDataset() as this will ensure coordinates and time varying data are handled automatically. Since xarray does not distinguish temporal dimensions your data will be interpeded as len(n.dims) space-dimensional, therefore arr must only contain spacial dimensions. Vapor expects data to be in order='C' with X as the fastest varying dimension. """ assert len(arr.coords) == 0 or len(arr.coords) >= len(arr.dims) if not arr.coords: return self.AddNumpyData(varName, arr.data) self.__checkNameValid(varName) # assert arr.dtype == np.float32 dc = self._wrappedInstance.GetDC() dimNames = [] dimNameMap = {} xDims = list(arr.sizes.items()) # DC::Mesh requires dimensions to be specified in reverse order # i.e. if data is slowest to fastest, DC::Mesh expects them in fastest to slowest xDims.reverse() for name,length in xDims: genName = f"__{varName}_dim_{name}" dim = DC.Dimension(genName, length) dc.AddDimension(dim) dimNames += [genName] dimNameMap[name] = genName coordNames = [] for axis,name in enumerate(arr.coords): genName = f"__{varName}_coord_{name}" xCoord = arr[name] # assert xCoord.dtype == np.float32 periodic = [False]*len(xCoord.dims) uniformHint = False timeDim = "" mappedDims = [dimNameMap[d] for d in xCoord.dims] mappedDims.reverse() # DC.CoordVar expects these in fastest to slowest coord = DC.CoordVar(genName, "m", DC.FLOAT, periodic, axis, uniformHint, mappedDims, timeDim) xCoordData = xCoord.data.astype(np.float32, copy=False) dc.AddCoordVar(coord, np.float32(xCoordData)) coordNames += [genName] meshGenName = f"__{varName}_mesh_{DC.Mesh.MakeMeshName(dimNames)}" mesh = DC.Mesh(meshGenName, dimNames, coordNames) dc.AddMesh(mesh) periodic = [False] * len(arr.dims) timeCoordVar = "" var = DC.DataVar(varName, "", DC.FLOAT, periodic, mesh.GetName(), timeCoordVar, DC.Mesh.NODE) dc.AddDataVar(var, np.float32(arr.data)); for v in [varName]+coordNames: self._wrappedInstance.ClearCache(v) # TODO: Only clear necessary renderers self.ses.ce.ClearAllRenderCaches() ================================================ FILE: apps/pythonapi/vapor/link.py ================================================ import wurlitzer, re with wurlitzer.pipes() as (out, err): import cppyy print(out.read(), end="") print("".join(l for l in err.read().splitlines() if not any(x in l for x in ("(ignoring for now)", "building pre-compiled headers"))), end="") from . import config for path in config.GetIncludeDirs(): cppyy.add_include_path(path) for path in config.GetLibraryDirs(): # print(f"Add lib path '{path}'") cppyy.add_library_path(path) cppyy.cppdef(config.GetCompileDefinitions()) cppyy.load_library('vapi') # if platform.system() == "Darwin": # cppyy.cppdef("#define Darwin 1") # from cppyy import include, gbl class Link: from cppyy import gbl def include(self, path): # print("- include", path) return cppyy.include(path) @staticmethod def FixModuleOwnership(Class): """ Classes that directly inherit from CPPYY C++ classes have an incorrect __module__ attr """ import inspect callerModule = inspect.getmodule(inspect.stack()[1][0]) Class.__module__ = callerModule.__name__ return Class def __getattr__(self, name): return getattr(cppyy.gbl, name) import sys sys.modules[__name__] = Link() ================================================ FILE: apps/pythonapi/vapor/params.py ================================================ from . import link from .smartwrapper import * link.include('vapor/ParamsBase.h') ParamsBase = link.VAPoR.ParamsBase class ParamsWrapper(SmartWrapper): def __init__(self, p:ParamsBase): self._params = p super().__init__(p) class ParamsTagWrapper(FuncWrapper): def __init__(self, tag:str): self._tag = tag def __getAccessorRootName(self): tagName = self._tag if tagName.lower().endswith("tag"): tagName = tagName[0:-3] if tagName.startswith("_"): tagName = tagName[1:] tagName = tagName[0].upper() + tagName[1:] return tagName def _getSetter(wself, cls): raise NotImplementedError def _getGetter(wself, cls): raise NotImplementedError def GetFunctionsToWrap(self, cls, name:str): assert hasattr(cls, self._tag) setter = self._getSetter(cls) getter = self._getGetter(cls) setter.__name__ = "Set" + self.__getAccessorRootName() getter.__name__ = "Get" + self.__getAccessorRootName() setter.__doxygen_name__ = self._tag getter.__doxygen_name__ = self._tag return [setter, getter] class ParamsTagWrapperLong(ParamsTagWrapper): def __init__(self, tag:str): self._tag = tag def _getSetter(wself, cls): # Self is params class def setter(self, value: int): return self.SetValueLong(getattr(cls, wself._tag), "", value) return setter def _getGetter(wself, cls): # Self is params class def getter(self) -> int: return self.GetValueLong(getattr(cls, wself._tag), 0) return getter class ParamsTagWrapperBool(ParamsTagWrapper): def __init__(self, tag:str): self._tag = tag def _getSetter(wself, cls): # Self is params class def setter(self, value: bool): return self.SetValueLong(getattr(cls, wself._tag), "", value) return setter def _getGetter(wself, cls): # Self is params class def getter(self) -> bool: return self.GetValueLong(getattr(cls, wself._tag), 0) return getter class ParamsTagWrapperDouble(ParamsTagWrapper): def __init__(self, tag:str): self._tag = tag def _getSetter(wself, cls): # Self is params class def setter(self, value: float): return self.SetValueDouble(getattr(cls, wself._tag), "", value) return setter def _getGetter(wself, cls): # Self is params class def getter(self) -> float: return self.GetValueDouble(getattr(cls, wself._tag), 0) return getter class ParamsTagWrapperString(ParamsTagWrapper): def __init__(self, tag:str): self._tag = tag def _getSetter(wself, cls): # Self is params class def setter(self, value: str): return self.SetValueString(getattr(cls, wself._tag), "", value) return setter def _getGetter(wself, cls): # Self is params class def getter(self) -> str: return self.GetValueString(getattr(cls, wself._tag), 0) return getter class ParamsTagWrapperList(FuncWrapper): """ Takes following format: long FirstTag long SecondTag string ThirdTag """ def __init__(self, slist:str): self._l = self.MakeList(slist) def MakeList(self, s: str): return list(filter(None, [str.strip(s) for s in s.split('\n')])) def __makeWrapper(self, typ, tag): if typ == "long": return ParamsTagWrapperLong(tag) elif typ == "bool": return ParamsTagWrapperBool(tag) elif typ == "double": return ParamsTagWrapperDouble(tag) elif typ == "string": return ParamsTagWrapperString(tag) else: raise TypeError def GetFunctionsToWrap(self, cls, name:str): return [func for entry in self._l for typ, tag in [entry.split()] for func in self.__makeWrapper(typ, tag).GetFunctionsToWrap(cls, name)] # for entry in self._l: # print(entry, "|", entry.split()) for entry in self._l: print(entry.split()) typ, tag = entry.split() for func in self.__makeWrapper(typ, tag).GetFunctionsToWrap(cls, name): print(func) ================================================ FILE: apps/pythonapi/vapor/renderer.py ================================================ from . import link from .params import * from .transferfunction import * from . import config from .annotations import * from .transform import * from pathlib import Path link.include('vapor/ControlExecutive.h') link.include('vapor/Box.h') class BoundingBox(): def __init__(self, toWrap:link.VAPoR.Box): self._params = toWrap def SetExtents(self, min, max): """Sets the region extents. min and max can be 2 or 3-element vectors depending on the dimension of the region.""" self._params.SetExtents(min, max) def GetExtents(self): """ Returns a tuple (min, max) containing the respective region bounds """ min = link.gbl.std.vector[link.gbl.double]() max = link.gbl.std.vector[link.gbl.double]() self._params.GetExtents(min, max) return list(min), list(max) RenderParams = link.VAPoR.RenderParams class Renderer(ParamsWrapper, wrap=RenderParams): _wrap = FuncWrapperStrList(""" SetEnabled IsEnabled GetVariableName SetAuxVariableNames GetAuxVariableNames SetFieldVariableNames GetFieldVariableNames SetXFieldVariableName SetYFieldVariableName SetZFieldVariableName GetXFieldVariableName GetYFieldVariableName GetZFieldVariableName SetHeightVariableName GetHeightVariableName SetColorMapVariableName GetColorMapVariableName SetUseSingleColor UseSingleColor GetConstantOpacity SetConstantOpacity GetTransform ResetUserExtentsToDataExents SetRefinementLevel GetRefinementLevel SetCompressionLevel GetCompressionLevel """) VaporName = None def __init__(self, renderParams:link.VAPoR.RenderParams, id:str): super().__init__(renderParams) self.id = id def GetTransferFunction(self, varname:str=None) -> TransferFunction: if varname is None: return self.GetPrimaryTransferFunction() return TransferFunction(self._params.GetMapperFunc(varname)) def GetPrimaryTransferFunction(self) -> TransferFunction: """Returns the transfer function for the primary rendered variable. This is usually the variable that is being colormapped and would be represented by the colorbar.""" return self.GetTransferFunction(self._params.GetActualColorMapVariableName()) def SetVariableName(self, name:str): # newDim = self._params._dataMgr.GetNumDimensions(name) # oldDim = self._params._dataMgr.GetNumDimensions(self.GetVariableName()) # if newDim != oldDim: # self.__setDimensions(newDim) self._params.SetVariableName(name) self._params.ResetUserExtentsToDataExents() def GetRenderRegion(self) -> BoundingBox: return BoundingBox(self._params.GetBox()) def GetColorbarAnnotation(self) -> ColorbarAnnotation: return ColorbarAnnotation(self._params.GetColorbarPbase()) def SetDimensions(self, dim:int): assert dim == 2 or dim == 3 self._params.BeginGroup("Change dim") if dim == 2: self._params.GetBox().SetPlanar(True) self._params.GetBox().SetOrientation(link.VAPoR.Box.XY) else: self._params.GetBox().SetPlanar(False) self._params.GetBox().SetOrientation(link.VAPoR.Box.XYZ) self._params.SetDefaultVariables(dim, True) self._params.EndGroup() link.include('vapor/BarbParams.h') link.include('vapor/BarbRenderer.h') class BarbRenderer(Renderer, wrap=link.VAPoR.BarbParams): _wrap = FuncWrapperStrList(""" GetGrid SetGrid GetLengthScale SetLengthScale GetLineThickness SetLineThickness """) _tags = ParamsTagWrapperList(""" long _xBarbsCountTag long _yBarbsCountTag long _zBarbsCountTag """) link.include('vapor/TwoDDataRenderer.h') class TwoDDataRenderer(Renderer, wrap=link.VAPoR.TwoDDataParams): pass link.include('vapor/ContourRenderer.h') class ContourRenderer(Renderer, wrap=link.VAPoR.ContourParams): def GetIsoValues(self) -> list[float]: return self._params.GetIsoValues(self.GetVariableName()) def SetIsoValues(self, values: list[float]): return self._params.SetIsoValues(self.GetVariableName(), values) link.include('vapor/VolumeRenderer.h') link.include('vapor/VolumeParams.h') class VolumeRenderer(Renderer, wrap=link.VAPoR.VolumeParams): _wrap = FuncWrapperStrList(""" GetAlgorithm GetSamplingMultiplier SetSamplingMultiplier SetLightingEnabled GetLightingEnabled SetPhongAmbient GetPhongAmbient SetPhongDiffuse GetPhongDiffuse SetPhongSpecular GetPhongSpecular SetPhongShininess GetPhongShininess """) _tags = ParamsTagWrapperList(""" double VolumeDensityTag bool UseColormapVariableTag """) def SetAlgorithm(self, algorithm: str): """Manually set the rendering algorithm. This is usually done automatically. Valid values in GetAlgorithmNames().""" if algorithm not in self.GetAlgorithmNames(): raise ValueError("Algorithm needs to be one of", self.GetAlgorithmNames()) self._params.SetAlgorithmByUser(algorithm) def GetAlgorithmNames(self, types=link.VAPoR.VolumeParams.Type.DVR): return link.VAPoR.VolumeParams.GetAlgorithmNames(types) link.include('vapor/VolumeIsoRenderer.h') link.include('vapor/VolumeIsoParams.h') class VolumeIsoRenderer(VolumeRenderer, wrap=link.VAPoR.VolumeIsoParams): _wrap = FuncWrapperStrList(""" """) def GetAlgorithmNames(self): return super().GetAlgorithmNames(link.VAPoR.VolumeParams.Type.Iso) def GetIsoValues(self) -> list[float]: return self._params.GetIsoValues(self.GetVariableName()) def SetIsoValues(self, values: list[float]): """Supports at most 4 simultaneous iso-surfaces per renderer""" return self._params.SetIsoValues(self.GetVariableName(), values) link.include('vapor/FlowRenderer.h') link.include('vapor/FlowParams.h') class FlowRenderer(Renderer, wrap=link.VAPoR.FlowParams): _wrap = FuncWrapperStrList(""" SetIsSteady GetIsSteady GetVelocityMultiplier SetVelocityMultiplier GetSteadyNumOfSteps SetSteadyNumOfSteps GetSeedGenMode SetSeedGenMode GetFlowDirection SetFlowDirection GetSeedInputFilename SetSeedInputFilename GetFlowlineOutputFilename SetFlowlineOutputFilename GetNeedFlowlineOutput SetNeedFlowlineOutput GetFlowOutputMoreVariables SetFlowOutputMoreVariables GetPeriodic SetPeriodic GetGridNumOfSeeds SetGridNumOfSeeds GetRandomNumOfSeeds SetRandomNumOfSeeds GetRakeBiasVariable SetRakeBiasVariable GetRakeBiasStrength SetRakeBiasStrength GetSeedInjInterval SetSeedInjInterval """) _tags = ParamsTagWrapperList(""" long RenderTypeTag double RenderRadiusScalarTag bool RenderGeom3DTag bool RenderShowStreamDirTag long RenderGlyphTypeTag long RenderGlyphStrideTag bool RenderGlyphOnlyLeadingTag double RenderDensityFalloffTag double RenderDensityToneMappingTag bool RenderFadeTailTag long RenderFadeTailStartTag long RenderFadeTailStopTag long RenderFadeTailLengthTag double PhongAmbientTag double PhongDiffuseTag double PhongSpecularTag double PhongShininessTag """) FlowDir = EnumWrapper(link.VAPoR.FlowDir) FlowSeedMode = EnumWrapper(link.VAPoR.FlowSeedMode) RenderType = EnumWrapper(link.VAPoR.FlowParams.RenderType) GlpyhType = EnumWrapper(link.VAPoR.FlowParams.GlpyhType) def GetRakeRegion(self) -> BoundingBox: return BoundingBox(self._params.GetRakeBox()) def GetIntegrationRegion(self) -> BoundingBox: return BoundingBox(self._params.GetIntegrationBox()) link.include('vapor/ParticleRenderer.h') link.include('vapor/ParticleParams.h') class ParticleRenderer(Renderer, wrap=link.VAPoR.ParticleParams): _tags = ParamsTagWrapperList(""" long StrideTag long ShowDirectionTag double RenderRadiusScalarTag double DirectionScaleTag double PhongAmbientTag double PhongDiffuseTag double PhongSpecularTag double PhongShininessTag """) link.include('vapor/WireFrameRenderer.h') link.include('vapor/WireFrameParams.h') class WireFrameRenderer(Renderer, wrap=link.VAPoR.WireFrameParams): pass link.include('vapor/ImageRenderer.h') link.include('vapor/ImageParams.h') class ImageRenderer(Renderer, wrap=link.VAPoR.ImageParams): _wrap = FuncWrapperStrList(""" SetImagePath GetImagePath SetIsGeoRef GetIsGeoRef SetIgnoreTransparency GetIgnoreTransparency """) def ListBuiltinMaps(self) -> list[str]: tms = config.GetResource("share/images/NaturalEarth.tms") if not tms: return [] tmsDir = Path(tms).parent return [f.stem for f in tmsDir.iterdir() if f.suffix == ".tms"] def SetBuiltinMap(self, name: str): path = config.GetResource(f"share/images/{name}.tms") self.SetImagePath(path) link.include('vapor/SliceRenderer.h') link.include('vapor/SliceParams.h') class SliceRenderer(Renderer, wrap=link.VAPoR.SliceParams): _wrap = FuncWrapperStrList(""" GetSlicePlaneRotation GetSlicePlaneOrigin GetSlicePlaneNormal """) _tags = ParamsTagWrapperList(""" double XSlicePlaneOriginTag double YSlicePlaneOriginTag double ZSlicePlaneOriginTag double XSlicePlaneRotationTag double YSlicePlaneRotationTag double ZSlicePlaneRotationTag double SampleRateTag double SliceOffsetTag double SlicePlaneNormalXTag double SlicePlaneNormalYTag double SlicePlaneNormalZTag long SlicePlaneOrientationModeTag """) SlicePlaneOrientationMode = link.VAPoR.RenderParams.SlicePlaneOrientationMode link.include('vapor/ModelRenderer.h') link.include('vapor/ModelParams.h') class ModelRenderer(Renderer, wrap=link.VAPoR.ModelParams): _wrap = FuncWrapperStrList(""" """) _tags = ParamsTagWrapperList(""" string FileTag """) SlicePlaneOrientationMode = link.VAPoR.RenderParams.SlicePlaneOrientationMode for Class in Renderer.__subclasses_rec__(): Class.VaporName = link.__getattr__(Class.__name__).GetClassType() # print("Renderer:", [f for f in dir(Renderer) if not f.startswith('__')]) # print("TwoDDataRenderer:", [f for f in dir(TwoDDataRenderer) if not f.startswith('__')]) ================================================ FILE: apps/pythonapi/vapor/session.py ================================================ from . import link from .renderer import Renderer from .renderer import * from .dataset import * from .camera import * from .annotations import * import PIL.Image link.include('vapor/Session.h') link.include('vapor/RenderManager.h') @link.FixModuleOwnership class Session(link.Session): def __init__(self): super().__init__(True) self.ce = super()._controlExec def NewRenderer(self, Class:Renderer, datasetName:str) -> Renderer: id = super().NewRenderer(Class.VaporName, datasetName) if not id: return None p = self.GetRenderer(id) p.SetEnabled(True) return p def DeleteRenderer(self, renderer:Renderer): super().DeleteRenderer(renderer.id) def GetRenderer(self, name): c_win = link.std.string() c_dat = link.std.string() c_typ = link.std.string() self.ce.RenderLookup(name, c_win, c_dat, c_typ) p = self.ce.GetRenderParams(c_win, c_dat, c_typ, name) assert p return SmartWrapper.AutoWrap(p, name) def GetRenderers(self) -> list[Renderer]: return [self.GetRenderer(name) for name in self.GetRendererNames()] def OpenDataset(self, datasetType:str, files:list[str]): """ Open a dataset of type datasetType from a list of files. A list of supported dataset types can be retrieved from Dataset.GetDatasetTypes() """ files = [files] if type(files) is not list else files files = [*map(str, files)] name = super().OpenDataset(datasetType, files) if (len(name) == 0): return None return self.GetDataset(name) def CreatePythonDataset(self): """ Creates a python dataset or returns one if it already exists for the current session. """ name = "PYTHON_RAM_DATASET" if self.GetDataset(name): return self.GetDataset(name) return self.OpenDataset(PYTHON, name) def GetDataset(self, name) -> Dataset: dataMgr = self.ce.GetDataStatus().GetDataMgr(name) if not dataMgr: return None return SmartWrapper.AutoWrap(dataMgr, name, self) def GetDatasets(self): return [self.GetDataset(name) for name in self.GetDatasetNames()] def GetCamera(self): return Camera(self.ce) def RenderToImage(self, fast=False) -> PIL.Image: from PIL import Image from array import array width, height = self._renderManager.GetResolution() nBytes = width * height * 3 buf = array('B', [0] * nBytes) address, length = buf.buffer_info() assert length == nBytes self.Render(f":RAM:{address:x}", fast) return Image.frombytes("RGB", (width, height), buf.tobytes()) def Show(self): from IPython.display import display img = self.RenderToImage() if config.IsRunningFromNotebook(): display(img) else: img.show() def SetResolution(self, width, height): self._renderManager.SetResolution(width, height) def GetSceneAnnotations(self) -> SceneAnnotation: pm = self.ce.GetParamsMgr() ap = pm.GetAnnotationParams(self.GetPythonWinName()) return SceneAnnotation(ap) def GetAxisAnnotations(self) -> AxisAnnotation: return AxisAnnotation(self.GetSceneAnnotations()._params.GetAxisAnnotation()) ================================================ FILE: apps/pythonapi/vapor/smartwrapper.py ================================================ import re, sys import functools from . import cppyyDoxygenWrapper import cppyy class FuncWrapper(): def GetFunctionsToWrap(self, cls, name): names = self.GetFunctionNamesToWrap(cls, name) return [getattr(cls, name) for name in names] def GetFunctionNamesToWrap(self, cls, name) -> list[str]: assert hasattr(cls, name) return [name] def GetWrappedFunctionName(self, memberName, func) -> str: return func.__name__ class FuncWrapperRename(FuncWrapper): def __init__(self, toWrapName:str): self._toWrapName = toWrapName def GetFunctionNamesToWrap(self, cls, name) -> list[str]: assert hasattr(cls, self._toWrapName) return [self._toWrapName] def GetWrappedFunctionName(self, memberName, func) -> str: return memberName class FuncWrapperWrapAll(FuncWrapper): def GetFunctionNamesToWrap(self, cls, name): return [f for f in dir(cls) if not f.startswith('_') and callable(getattr(cls, f))] class FuncWrapperRegex(FuncWrapper): def __init__(self, regex): self._r = re.compile(regex) def GetFunctionNamesToWrap(self, cls, name): return [f for f in dir(cls) if self._r.fullmatch(f) is not None and callable(getattr(cls, f))] class FuncWrapperStrList(FuncWrapper): def __init__(self, slist:str): self._l = self.MakeList(slist) self._ensureNamesStartUppercase = False def MakeList(self, s: str): return list(filter(None, [str.strip(s) for s in s.split('\n')])) def GetFunctionNamesToWrap(self, cls, name): for name in self._l: assert hasattr(cls, name) return self._l.copy() def GetWrappedFunctionName(self, memberName, func): name = super().GetWrappedFunctionName(memberName, func) if self._ensureNamesStartUppercase: name = name[0].upper() + name[1:] return name def EnsureNamesStartUppercase(self): self._ensureNamesStartUppercase = True return self def FuncWrappers(n: int = 32): for x in range(n): yield FuncWrapper class SmartWrapperMeta(cppyyDoxygenWrapper.CPPYYDoxygenWrapperMeta): __wrappedToWrapperRegistry = { cppyy.gbl.std.string: lambda s: str(s), cppyy.gbl.std.vector[str]: lambda v: list(map(str, v)), cppyy.gbl.std.vector[int]: lambda v: list(v), cppyy.gbl.std.vector[float]: lambda v: list(v), cppyy.gbl.std.vector[cppyy.gbl.long]: lambda v: list(v), cppyy.gbl.std.vector[cppyy.gbl.double]: lambda v: list(v), } def __new__(cls, clsname, bases, clsdict:dict, wrap:type=None): clsdict['_wrappedClass'] = wrap for name in list(clsdict.keys()): val = clsdict[name] if isinstance(val, FuncWrapper): assert wrap is not None toWrap = val.GetFunctionsToWrap(wrap, name) del clsdict[name] wrappedFunctions = [cls._MakeFunctionWrapper(wrap, f) for f in toWrap] wrappedDict = {val.GetWrappedFunctionName(name, f):f for f in wrappedFunctions} if any((duplicate_name:=n) in clsdict for n in wrappedDict): print(f'WARNING: Function "{duplicate_name}" exposed multiple times', file=sys.stderr) clsdict.update(wrappedDict) return super(SmartWrapperMeta, cls).__new__(cls, clsname, bases, clsdict, wrap=wrap) def __init__(cls, *args, **kwargs): cls.__wrappedToWrapperRegistry[cls._wrappedClass] = cls super().__init__(*args, **kwargs) @classmethod def AutoWrap(cls, toWrap, *args, **kwargs): if type(toWrap) in cls.__wrappedToWrapperRegistry: return cls.__wrappedToWrapperRegistry[type(toWrap)](toWrap, *args, **kwargs) return toWrap @classmethod def _MakeFunctionWrapper(cls, pCls, func): # assert hasattr(pCls, func.__name__) @functools.wraps(func) def f(self, *args, **kwargs): ret = func(self._wrappedInstance, *args, **kwargs) return cls.AutoWrap(ret) return super()._MakeFunctionWrapper(pCls, f) class SmartWrapper(metaclass=SmartWrapperMeta): def __init__(self, toWrap): if not type(toWrap) == self._wrappedClass: raise ValueError(f"{type(toWrap)} is not {self._wrappedClass}") self._wrappedInstance = toWrap @classmethod def __subclasses_rec__(cls): return set(cls.__subclasses__()).union([s for c in cls.__subclasses__() for s in c.__subclasses_rec__()]) class EnumWrapperMeta(type): def __repr__(self): return "Enum Class" def EnumWrapper(Class:type): d = dict(Class.__dict__) d['__doc__'] = "\n" + "Enum with the following options:" + "\n ".join([""]+[*filter(lambda x: not x.startswith("__"), d.keys())]) return EnumWrapperMeta(Class.__name__, Class.__bases__, d) ================================================ FILE: apps/pythonapi/vapor/transferfunction.py ================================================ from . import link from .params import * from .common import * from . import config from typing import Iterable, Any import functools from pathlib import Path import pylab as pl import numpy as np link.include('vapor/MapperFunction.h') class TransferFunction(ParamsWrapper, wrap=link.VAPoR.MapperFunction): _wrap = FuncWrapperStrList(""" getOpacityScale setOpacityScale getMinMapValue setMinMapValue getMaxMapValue setMaxMapValue getMinMaxMapValue LoadFromFile LoadColormapFromFile """).EnsureNamesStartUppercase() def LoadBuiltinColormap(self, name:str) -> None: """See ListBuiltinColormaps""" return self.LoadColormapFromFile(config.GetResource(f'share/palettes/{name}.tf3')) @classmethod def ListBuiltinColormaps(cls) -> list[str]: root = Path(config.GetResource(f'share/palettes')) return [f"{category.name}/{color.stem}" for category in root.iterdir() for color in category.iterdir()] def __normalizeControlPoints(self, cp: list[tuple[float, Any]]): rMin = self.GetMinMapValue() rMax = self.GetMaxMapValue() normalize = lambda x: (x - rMin) / (rMax - rMin) if rMax - rMin > 0 else x return [(normalize(x), y) for x, y in cp] @staticmethod def __enumerateNormDist(l: list[float]): if not l: return [] if len(l) == 1: return [(0.5, l[0])] return [(n / (len(l) - 1), v) for n, v in enumerate(l)] @staticmethod def __swapEachXY(l: list): return [(y, x) for x, y in l] @staticmethod def __flatten(l: list): def flatten(l): for i in l: if isinstance(i, Iterable): for j in flatten(i): yield j else: yield i return list(flatten(l)) def __rgbToHsv(self, rgb): if len(rgb) != 3: raise ValueError("rgb list must have 3 values") return [*self._params.rgbToHsv(rgb)] def SetOpacityNormalizedControlPoints(self, cp: list[tuple[float, float]]): """Sets opacities for normalized x,y values""" oMap = self._params.GetOpacityMap(0) # cp = [y0, x0, y1, x1, ...] oMap.SetControlPoints(self.__flatten(self.__swapEachXY(cp))) def SetOpacityList(self, opacities: list[float]): """Sets opacities as equally spaced control points""" self.SetOpacityNormalizedControlPoints(self.__enumerateNormDist(opacities)) def SetOpacityControlPoints(self, cp: list[tuple[float, float]]): """ Sets opacity points for x,y values where MinMapValue<=x<=MaxMapValue and 0<=y<=1 Expects a list of form [[x1, y1], [x2, y2], ...] with x representing data values and y representing opacity values Warning: The points are stored as normalized coordinates so if the MapValue range changes it will not be reflected in the mapping range """ self.SetOpacityNormalizedControlPoints(self.__normalizeControlPoints(cp)) def GetOpacityControlPoints(self): """ Returns opacity points in the form [[x1, y1], [x2, y2], ...] with x representing data values and y representing opacity values """ minv, maxv = self.GetMinMapValue(), self.GetMaxMapValue() opacities_normalized = np.array(self._params.GetOpacityMap(0).GetControlPoints()).reshape(-1, 2) y = opacities_normalized[:, 0] x_norm = opacities_normalized[:, 1] x_data = x_norm * (maxv - minv) + minv # undo normalization return np.stack([x_data, y], axis=1) def SetColorNormalizedHSVControlPoints(self, cp: list[tuple[float, Vec3]]): """Sets colormap for normalized data values""" cMap: link.VAPoR.ColorMap = self._params.GetColorMap() # cp = [h0, s0, v0, x0, h1, s1, v1, x1, ...] cMap.SetControlPoints(self.__flatten(self.__swapEachXY(cp))) def SetColorHSVList(self, colors: list[Vec3]): """Sets colormap as equally spaced control points""" self.SetColorNormalizedHSVControlPoints(self.__enumerateNormDist(colors)) def ReverseColormap(self): """Reverses the colormap""" self.SetColorRGBList([(r, g, b) for r, g, b, _ in list(reversed(self.GetMatPlotLibColormap().colors))]) def SetColorHSVControlPoints(self, cp: list[tuple[float, Vec3]]): """ Sets opacities for x,y values where MinMapValue<=x<=MaxMapValue and 0<=y<=1 Warning: The points are stored as normalized coordinates so if the MapValue range changes it will not be reflected in the mapping range """ self.SetColorNormalizedHSVControlPoints(self.__normalizeControlPoints(cp)) def __rgbEquivalent(func): def dec1(name): @functools.wraps(func) def dec(self, cp): if len(cp[0]) == 2: return func(self, [(v, self.__rgbToHsv(rgb)) for v, rgb in cp]) else: return func(self, [self.__rgbToHsv(rgb) for rgb in cp]) return dec return dec1 @__rgbEquivalent(SetColorHSVList) def SetColorRGBList(self): pass @__rgbEquivalent(SetColorNormalizedHSVControlPoints) def SetColorNormalizedRGBControlPoints(self): pass @__rgbEquivalent(SetColorHSVControlPoints) def SetColorRGBControlPoints(self):pass def GetMatPlotLibColormap(self): from matplotlib.colors import ListedColormap lut = self._params.makeLut() lut = [[*lut[i:i + 3], 1] for i in range(0, len(lut), 4)] return ListedColormap(lut) def GetMatPlotLibColorbar(self, axes="auto", figsize=(9,1.5), **kwargs): """ Shows a colorbar for Vapor's transfer function using pylab.colorbar. This function takes the same kwargs as pylab.colorbar and those parameters are passed onto the matplotlib function. """ cmap = self.GetMatPlotLibColormap() # a = [[0, 1]] a = [self.GetMinMaxMapValue()] pl.figure(figsize=figsize) img = pl.imshow(a, cmap=cmap) pl.gca().set_visible(False) kwargs.setdefault("orientation", "horizontal") if axes=="auto": if kwargs['orientation'] == "horizontal": cax = pl.axes([0.1, 0.2, 0.8, 0.6]) elif kwargs['orientation'] == "vertical": cax = pl.axes([0.2, 0.1, 0.6, 0.8]) else: raise ValueError else: cax = axes kwargs.setdefault("cax", cax) cbar = pl.colorbar(**kwargs) # pl.savefig("c.png") return cbar def ShowMatPlotLibColorbar(self, axes="auto", figsize=(9, 1.5), **kwargs): """ Shows a colorbar for Vapor's transfer function using pylab.colorbar. This function takes the same kwargs as pylab.colorbar and those parameters are passed onto the matplotlib function. """ self.GetMatPlotLibColorbar(axes, figsize, **kwargs) pl.show() ================================================ FILE: apps/pythonapi/vapor/transform.py ================================================ from . import link from .params import * link.include('vapor/Transform.h') class Transform(ParamsWrapper, wrap=link.VAPoR.Transform): _wrap = FuncWrapperStrList(""" GetRotations SetRotations GetTranslations SetTranslations GetScales SetScales GetOrigin SetOrigin """) _tags = ParamsTagWrapperList(""" """) ================================================ FILE: apps/pythonapi/vapor/utils/__init__.py ================================================ ================================================ FILE: apps/pythonapi/vapor/utils/histogram.py ================================================ from ..session import * import matplotlib.pyplot as plt import numpy as np import functools import bqplot as bq import ipywidgets as widgets from ..widget import VaporVisualizerWidget link.include('vapor/Histo.h') def GetSamples(session: Session, renderer: Renderer, varName: str): c_win = link.std.string() c_dat = link.std.string() c_typ = link.std.string() session.ce.RenderLookup(renderer.id, c_win, c_dat, c_typ) dataset = session.GetDataset(c_dat) return link.Histo(0).GetDataSamples(varName, dataset._wrappedInstance, renderer._params) def GetMatPlotLibHistogram(session: Session, renderer: Renderer, **kwargs): """ Shows a histogram for a given renderer. Wraps matplotlib.pyplot.hist(GetSamples(...)) """ varName = renderer._params.GetActualColorMapVariableName() samples = GetSamples(session, renderer, varName) kwargs.setdefault("range", renderer.GetPrimaryTransferFunction().GetMinMaxMapValue()) kwargs.setdefault("bins", 128) # density=True is supposed to create a probability density however it is broken so this is an alternative weights = np.ones_like(samples) / float(len(samples)) plt.hist(samples, weights=weights, **kwargs) return plt def ShowMatPlotLibHistogram(session: Session, renderer: Renderer, **kwargs): GetMatPlotLibHistogram(session, renderer, **kwargs).show() def transferFunctionWidget(ses, ren, preserveOpacities = True, nControlPoints=5): # Histogram setup data = np.array(GetSamples(ses, ren, ren._params.GetActualColorMapVariableName())) hist_values, edges = np.histogram(data, bins=50) hist_values = (hist_values / max(hist_values)) * 100 # Scale so y-axis is between 0 and 100. This mitigate's bqplot's auto-rounding hist_values = [np.ceil(y) for y in hist_values] # Round up to handle vanishing values bin_centers = (edges[:-1] + edges[1:]) / 2 x_sc = bq.LinearScale() y_sc = bq.LinearScale(min=0, max=100) bars = bq.Bars(x=bin_centers, y=hist_values, scales={'x': x_sc, 'y': y_sc}) # Create control points if(preserveOpacities): init_points = ren.GetPrimaryTransferFunction().GetOpacityControlPoints() * 100 else: init_points = [[x, 100] for x in np.linspace(min(data), max(data), nControlPoints)] # Or this control_x, control_y = zip(*init_points) ren.GetPrimaryTransferFunction().SetOpacityControlPoints([[x, float(y)/100] for x, y in init_points]) # Set up visualizer widget viz = VaporVisualizerWidget(ses) viz_box = widgets.Box([viz]) # Interactive scatter points scatter = bq.Scatter( x=list(control_x), y=list(control_y), scales={'x': x_sc, 'y': y_sc}, enable_move=True, colors=['white'], stroke='black', default_size=64, ) # Lines connecting control points lines = bq.Lines( x=list(control_x), y=list(control_y), scales={'x': x_sc, 'y': y_sc}, stroke='white', stroke_width=2 ) # Update figure and tf on drag def on_drag(change): control_points = list(zip(scatter.x, scatter.y)) control_points.sort(key=lambda p: p[0]) # Sort by x-values in case control points cross each other clamped_control_points = [(x, min(100, max(0, y))) for x, y in control_points] # Keep y within [0, 100] xs, ys = zip(*clamped_control_points) lines.x = xs lines.y = ys scatter.x = xs scatter.y = ys # Update transfer function ren.GetPrimaryTransferFunction().SetOpacityControlPoints([[x, float(y)/100] for x, y in control_points]) viz_box.children = [VaporVisualizerWidget(ses)] # Refresh widget for live update # Slider for histogram range x_min, x_max = np.min(data), np.max(data) range_slider = widgets.FloatRangeSlider( value=[x_min, x_max], min=x_min, max=x_max, step=(x_max - x_min) / 100, description='Range:', continuous_update=True, readout=False ) def update_histogram_range(change): x_low, x_high = range_slider.value # Remake histogram with given range bounds filtered_data = data[(data >= x_low) & (data <= x_high)] hist_y, new_edges = np.histogram(filtered_data, bins=50, range=(x_low, x_high)) hist_y = (hist_y / hist_y.max()) * 100 new_centers = (new_edges[:-1] + new_edges[1:]) / 2 bars.x = new_centers bars.y = [np.ceil(y) for y in hist_y] # Keep control points in same relative position new_cp = [[x, y] for x, y in zip(np.linspace(min(filtered_data), max(filtered_data), nControlPoints), scatter.y)] xs, ys = zip(*new_cp) scatter.x = xs scatter.y = ys lines.x = xs lines.y = ys # Update x-axis x_sc.min = x_low x_sc.max = x_high # Update tf with new cp ren.GetPrimaryTransferFunction().SetOpacityControlPoints([[x, float(y)/100] for x, y in new_cp]) # Set up interactivity scatter.observe(on_drag, names=['x', 'y']) range_slider.observe(update_histogram_range, names='value') # Create UI layout fig = bq.Figure( marks=[bars, lines, scatter], scales={'x': x_sc, 'y': y_sc}, animation_duration=0, title=str(ren._params.GetVariableName()) ) # Layout Style fig.layout = widgets.Layout( width='99%', height='300px', ) range_slider.layout = widgets.Layout( width='90%' ) tf_controls = widgets.VBox([fig, range_slider], layout=widgets.Layout( width='500px', align_items='center' )) UI = widgets.HBox([viz_box, tf_controls], layout=widgets.Layout( align_items='flex-start' )) return UI ================================================ FILE: apps/pythonapi/vapor/utils/keyframing.py ================================================ from ..session import Session from ..animation import Animation def animate_camera_keyframes(session_paths, steps = None, time_interpolation = 'static', time_frames = None): """ Given a list of file paths to sessions with different camera angles, returns an animation that performs keyframing with linear interpolation between those camera angles. Args: session_paths (list): List of file paths to sessions with different camera angles. steps (list, optional): List of number of frames to interpolate between each keyframe. Defaults to None, which will use 30 frames between each keyframe. time_interpolation (str, optional): How to handle time interpolation. Options are 'static', 'auto', or 'manual'. Defaults to 'static'. time_frames (list, optional): If time_interpolation is 'manual', this should be a list of timesteps corresponding to the frames in the animation. len(time_frames) should equal sum(steps). """ # Check time_interpolation if(time_interpolation not in ["static", "auto", 'manual']): raise ValueError("time_interpolation must be one of 'static', 'auto', or 'manual'") # Default for steps if steps == None: steps = [30] * (len(session_paths) - 1) # Check steps if len(session_paths) - len(steps) != 1: raise ValueError(f"With {len(session_paths)} keyframes given, 'steps' should be " + f"length {len(session_paths) - 1} (currently {len(steps)})") total_frames = sum(steps) # Load primary session primary_session = session.Session() primary_session.Load(session_paths[0]) # If time is interpolated, compute time frames if time_interpolation == "auto": total_timesteps = primary_session.GetTimesteps() # Compute base number of frames per timestep base = total_frames // total_timesteps remainder = total_frames % total_timesteps # Distribute the remainder by giving one extra frame to the first 'remainder' timesteps time_frames = [] for timestep in range(total_timesteps): count = base + (1 if timestep < remainder else 0) time_frames.extend([timestep] * count) if time_interpolation == "manual": if time_frames is None: raise ValueError("If time_interpolation is 'manual', time_frames must be provided") if len(time_frames) != total_frames: raise ValueError(f"With {len(session_paths)} steps given, 'time_frames' should be " + f"length {total_frames} (currently {len(time_frames)})") # Load key frames as sessions key_frames = [] for path in session_paths: ses = session.Session() ses.Load(path) key_frames.append(ses) # Visualization will use renderers from first session in list. Other sessions are only for camera angles primary_session = key_frames[0] anim = Animation(primary_session) cam = primary_session.GetCamera() # Interpolate camera information between each key frame n = 0 for i in range(len(key_frames) - 1): start = key_frames[i] end = key_frames[i+1] frames = steps[i] # Get starting information cam1 = start.GetCamera() dir1 = cam1.GetDirection() pos1 = cam1.GetPosition() up1 = cam1.GetUp() # Get ending information cam2 = end.GetCamera() dir2 = cam2.GetDirection() pos2 = cam2.GetPosition() up2 = cam2.GetUp() # Difference between camera positions on each axis dPositionX = (pos2[0] - pos1[0]) dPositionY = (pos2[1] - pos1[1]) dPositionZ = (pos2[2] - pos1[2]) # Difference between camera direction vectors on each axis dDirectionX = (dir2[0] - dir1[0]) dDirectionY = (dir2[1] - dir1[1]) dDirectionZ = (dir2[2] - dir1[2]) # Difference between camera up vectors on each axis dUpX = (up2[0] - up1[0]) dUpY = (up2[1] - up1[1]) dUpZ = (up2[2] - up1[2]) # Linear interpolation between start and end for j in range(frames): position = [ pos1[0]+dPositionX*j/frames, pos1[1]+dPositionY*j/frames, pos1[2]+dPositionZ*j/frames ] cam.SetPosition( position ) direction = [ dir1[0]+dDirectionX*j/frames, dir1[1]+dDirectionY*j/frames, dir1[2]+dDirectionZ*j/frames ] cam.SetDirection( direction ) up = [ up1[0]+dUpX*j/frames, up1[1]+dUpY*j/frames, up1[2]+dUpZ*j/frames ] cam.SetUp( up ) # If time is interpolated, advance the timestep if (time_interpolation == "auto") | (time_interpolation == "manual"): timestep = time_frames[n+j] primary_session.SetTimestep(int(timestep)) anim.CaptureFrame() # Print status print(f"Rendering Animation [{'#'*round((j+n)*40/total_frames)}{' '*round(40-((j+n)*40/total_frames))}] {(j+1+n)*100/total_frames:.0f}%", end="\r") n += steps[i] return anim def animate_camera_keyframes_camerafiles(primary_session, camera_paths, steps=None, time_interpolation='static', time_frames=None): """ Given a session and a list of paths to saved camera files, returns an animation that performs keyframing with linear interpolation on the saved camera angles. Can also handle time interpolation. Args: primary_session (Session): The primary session to render from. camera_paths (list): List of paths to saved camera files. steps (list, optional): Number of frames to interpolate between each keyframe. Defaults to 30 per segment. time_interpolation (str, optional): How to interpolate timestep. Options: 'static', 'auto', 'manual'. Default is 'static'. time_frames (list, optional): Required if time_interpolation is 'manual'. Should be a list of timesteps with length equal to total frames. """ # Validate time_interpolation mode if time_interpolation not in ["static", "auto", "manual"]: raise ValueError("time_interpolation must be one of 'static', 'auto', or 'manual'") # Default steps if steps is None: steps = [30] * (len(camera_paths) - 1) # Validate steps length if len(camera_paths) - len(steps) != 1: raise ValueError(f"With {len(camera_paths)} keyframes, 'steps' should have length {len(camera_paths) - 1} (got {len(steps)})") total_frames = sum(steps) # Handle time_interpolation: auto if time_interpolation == "auto": total_timesteps = primary_session.GetTimesteps() base = total_frames // total_timesteps remainder = total_frames % total_timesteps time_frames = [] for timestep in range(total_timesteps): count = base + (1 if timestep < remainder else 0) time_frames.extend([timestep] * count) # Handle time_interpolation: manual if time_interpolation == "manual": if time_frames is None: raise ValueError("If time_interpolation is 'manual', time_frames must be provided.") if len(time_frames) != total_frames: raise ValueError(f"time_frames length ({len(time_frames)}) must match total_frames ({total_frames})") anim = Animation(primary_session) cam = primary_session.GetCamera() n = 0 for i in range(len(camera_paths) - 1): start = camera_paths[i] end = camera_paths[i+1] frames = steps[i] # Load start camera cam.LoadFromFile(start) dir1 = cam.GetDirection() pos1 = cam.GetPosition() up1 = cam.GetUp() # Load end camera cam.LoadFromFile(end) dir2 = cam.GetDirection() pos2 = cam.GetPosition() up2 = cam.GetUp() # Compute deltas dPosition = [p2 - p1 for p1, p2 in zip(pos1, pos2)] dDirection = [d2 - d1 for d1, d2 in zip(dir1, dir2)] dUp = [u2 - u1 for u1, u2 in zip(up1, up2)] for j in range(frames): f = j / frames position = [pos1[k] + dPosition[k]*f for k in range(3)] direction = [dir1[k] + dDirection[k]*f for k in range(3)] up = [up1[k] + dUp[k]*f for k in range(3)] cam.SetPosition(position) cam.SetDirection(direction) cam.SetUp(up) # Set time if applicable if time_interpolation in ["auto", "manual"]: timestep = time_frames[n + j] primary_session.SetTimestep(int(timestep)) anim.CaptureFrame() print(f"Rendering Animation [{'#'*round((j+n)*40/total_frames)}{' '*round(40-((j+n)*40/total_frames))}] {(j+1+n)*100/total_frames:.0f}%", end="\r") n += frames return anim ================================================ FILE: apps/pythonapi/vapor/widget-jquery.js ================================================ /*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0 img { position: absolute; top: 0; left: 0; } ================================================ FILE: apps/pythonapi/vapor/widget.js ================================================ import $ from './widget-jquery'; function render({ model, el }) { let $root = $("
"); $root.addClass("vapor-jupyter-widget"); let $img = $('', {src:'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQImWNISUkBAAJcAS0OBgnuAAAAAElFTkSuQmCC'}); for (var i = 0; i < 2; i++) $root.append($img.clone().attr("id", ""+i)); let $imgs = $root.find('img'); var img_i = 0; $imgs.on("load", e=>{ let $e = $(e.target); $e.parent().append($e); }); $imgs.on("dragstart", e=>e.preventDefault()); function loadImage() { let width = model.get('resolution')[0]; let height = model.get('resolution')[1]; $root.width(width); $root.height(height); // console.log(`Image data received: ${width}x${height}`); if (model.get('imageFormat') !== "") { $($imgs[img_i]).attr("src", "data:image/" + model.get('imageFormat') + ";base64," + model.get('imageData')); img_i = (img_i+1)%2; } } model.on("change:imageData", loadImage); if (model.get('imageData')) loadImage(); $root.on("mousedown", e => { e.preventDefault(); var key = e.which; if (e.originalEvent.shiftKey && key == 1) key = 2; model.set('mouseButton', key); model.set('mouseDown', true); model.save_changes(); }); $root.on("mouseup", e => { e.preventDefault(); model.set('mouseDown', false); model.save_changes(); }); $root.on("mousemove", e => { e.preventDefault(); // this.$img.css('border', '2px solid orange'); var offset = $root.offset(); var nx = e.pageX - offset.left; var ny = e.pageY - offset.top; // console.log(`offset=(${offset.left}, ${offset.top}) e.page=(${e.pageX}, ${e.pageY}) n=(${nx}, ${ny})`) if ($root.width() !== 0 && $root.height() !== 0) { nx /= $root.width(); ny /= $root.height(); } else { nx = 0; ny = 0; } // console.log("mouse move " + nx + ", " + ny); model.set('mousePos', [nx, ny]); model.save_changes(); }); el.appendChild($root.get(0)); } export default { render }; ================================================ FILE: apps/pythonapi/vapor/widget.py ================================================ import anywidget from traitlets import Unicode, Bytes, Tuple, Bool, observe, Int import traitlets ########################################## # Development utility import importlib vapor_spec = importlib.util.find_spec("vapor") found = vapor_spec is not None if not found: import sys import os from pathlib import Path sys.path.append(os.path.expanduser('~/Work/build-work/python')) ######################################### from PIL import Image from PIL import ImageDraw from base64 import b64encode from io import BytesIO import pathlib import os, sys, random # class VaporVisualizerWidget(anywidget.AnyWidget): # _esm = pathlib.Path("widget.js") class CanvasStreamWidget(anywidget.AnyWidget): _esm = pathlib.Path(__file__).parent / "widget.js" _css = pathlib.Path(__file__).parent / "widget.css" imageData = Unicode('').tag(sync=True) resolution = Tuple((640, 480)).tag(sync=True) mousePos = Tuple((0.0, 0.0)).tag(sync=True) mouseDown = Bool(False).tag(sync=True) mouseButton = Int(1).tag(sync=True) _debugLog = Unicode('').tag(sync=True) value = Int(0).tag(sync=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if "debug" in kwargs and kwargs["debug"]: self.on_trait_change(self.valueChanged, "value") self.on_trait_change(self._DebugShowMousePos, "mousePos") def test(self): self.SetImage(Image.new('RGB', self.resolution, (0,0,100))) # self.value = 999 def valueChanged(self): print("VALUE CHANGED TO", self.value) self.SetImage(Image.new('RGB', self.resolution, (random.randint(0,255),random.randint(0,255),random.randint(0,255)))) def SetImage(self, img: Image): buf = BytesIO() img.save(buf, format="jpeg") self.resolution = img.size self.imageData = b64encode(buf.getvalue()) def _DebugShowMousePos(self): print("DEBUG SHOW MOUSE POS") print("DEBUG SHOW MOUSE POS", file=sys.stderr) image = Image.new('RGB', self.resolution) draw = ImageDraw.Draw(image) iw = int(image.size[0]) ih = int(image.size[1]) mx = int(self.mousePos[0] * iw) my = int(self.mousePos[1] * ih) # self.value = mx self._debugLog = f""" mousePos: {mx}, {my}
imagesize = {iw, ih}
self.res = {self.resolution} """ white = (255, 255, 255) red = (255, 0, 0) draw.rectangle([0, 0, iw, ih], outline=red, width=5) draw.line([mx, 0, mx, ih], fill=white, width=5) draw.line([0, my, iw, my], fill=white, width=5) self.SetImage(image) # widget setup.py installer will try to run tests which will fail # because CPPYY cannot be present at build time due to conda bugs import importlib if importlib.util.find_spec("cppyy") is not None: from vapor import session, renderer, dataset, camera, utils # from examples import example_utils from vapor import link link.include('vapor/TrackBall.h') link.include('vapor/ControlExecutive.h') link.include("vapor/NavigationUtils.h") NavigationUtils = link.NavigationUtils class VaporVisualizerWidget(CanvasStreamWidget): """ Creates an interactive visualizer widget for a Vapor session. Controls are the same as the Vapor GUI application (They are shown as a tooltip on the visualizer for reference). """ class TrackballButton: Left = 1 Right = 3 Middle = 2 def __init__(self, ses:session.Session, *args, **kwargs): # import sys # sys.stdout = open("stdout.txt", "w") # sys.stderr = open("stderr.txt", "w") super().__init__(*args, **kwargs) self._ses = ses self._trackball = link.Trackball() self.on_trait_change(self.mouseDownChanged, "mouseDown") self.on_trait_change(self.mousePosChanged, "mousePos") self.Render() def Render(self, fast=False): """ Update the visualizer with a current rendering of the session. :fast: renders with lower fidelity but faster. Useful for interactive rendering such as to observe a changing value with a slider. """ self.SetImage(self._ses.RenderToImage(fast=fast)) def mouseDownChanged(self): w, h = map(int, self.resolution) x, y = map(int, (lambda x,y:(x*w,y*h))(*self.mousePos)) if self.mouseDown: NavigationUtils.ConfigureTrackball(self._ses.ce, self._trackball) self._trackball.MouseOnTrackball(0, self.mouseButton, x, y, w, h) else: self._trackball.MouseOnTrackball(2, self.mouseButton, x, y, w, h) self._trackball.TrackballSetMatrix() NavigationUtils.SetAllCameras(self._ses.ce, self._trackball) self.Render(fast=False) # self.value = f"mouseDown change {change['old']} -> {change['new']}" def mousePosChanged(self): # self.value = f"mousePos change {change['old']} -> {change['new']}" w, h = map(int, self.resolution) x, y = map(int, (lambda x,y:(x*w,y*h))(*self.mousePos)) if self.mouseDown: self._trackball.MouseOnTrackball(1, self.mouseButton, x, y, w, h) self._trackball.TrackballSetMatrix() NavigationUtils.SetAllCameras(self._ses.ce, self._trackball) self.Render(fast=True) ================================================ FILE: apps/raw2vdc/CMakeLists.txt ================================================ add_executable (raw2vdc raw2vdc.cpp) target_link_libraries (raw2vdc common vdc) OpenMPInstall ( TARGETS raw2vdc DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/raw2vdc/raw2vdc.cpp ================================================ #include #include #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; // // Command line argument stuff // struct opt_t { string varname; string type; int lod; int nthreads; int ts; OptionParser::Boolean_T swapbytes; OptionParser::Boolean_T debug; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"varname", 1, "var1", "Name of variable"}, {"type", 1, "float32", "Primitive type of input data. Valid types are int8, float32, float64, and double"}, {"lod", 1, "-1", "Compression levels saved. 0 => coarsest, 1 => " "next refinement, etc. -1 => all levels defined by the netcdf file"}, {"nthreads", 1, "0", "Specify number of execution threads " "0 => use number of cores"}, {"ts", 1, "0", "Specify time step offset"}, {"swapbytes", 0, "", "Swap bytes in data as they are read from disk"}, {"debug", 0, "", "Enable diagnostic"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"varname", Wasp::CvtToCPPStr, &opt.varname, sizeof(opt.varname)}, {"type", Wasp::CvtToCPPStr, &opt.type, sizeof(opt.type)}, {"lod", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)}, {"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"ts", Wasp::CvtToInt, &opt.ts, sizeof(opt.ts)}, {"swapbytes", Wasp::CvtToBoolean, &opt.swapbytes, sizeof(opt.swapbytes)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; size_t size_of_type(string type) { if (type.compare("float32") == 0) return (4); if (type.compare("float64") == 0) return (8); if (type.compare("double") == 0) return (8); if (type.compare("int8") == 0) return (1); return (1); } void swapbytes(void *vptr, size_t size, size_t n) { unsigned char *ucptr = (unsigned char *)vptr; unsigned char uc; size_t i, j; for (j = 0; j < n; j++) { for (i = 0; i < size / 2; i++) { uc = ucptr[i]; ucptr[i] = ucptr[size - i - 1]; ucptr[size - i - 1] = uc; } ucptr += size; } } int read_data(FILE * fp, string type, // element type bool swap, size_t n, float *slice) { static SmartBuf smart_buf; size_t element_sz = size_of_type(type); unsigned char *buffer = (unsigned char *)smart_buf.Alloc(n * element_sz); size_t rc = fread(buffer, element_sz, n, fp); if (rc != n) { if (ferror(fp) != 0) { MyBase::SetErrMsg("Error reading input file : %M"); } else { MyBase::SetErrMsg("Short read on input file"); } return (-1); } // Swap bytes in place if needed // if (swap) { swapbytes(buffer, element_sz, n); } float *dptr = slice; if (type.compare("float32") == 0) { float *sptr = (float *)buffer; for (size_t i = 0; i < n; i++) { *dptr++ = (float)*sptr++; } } else if ((type.compare("float64") == 0) || (type.compare("double") == 0)) { double *sptr = (double *)buffer; for (size_t i = 0; i < n; i++) { *dptr++ = (float)*sptr++; } } else if (type.compare("int8") == 0) { char *sptr = (char *)buffer; for (size_t i = 0; i < n; i++) { *dptr++ = (float)*sptr++; } } return (0); } const char *ProgName; int main(int argc, char **argv) { OptionParser op; MyBase::SetErrMsgFilePtr(stderr); // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { return (1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { return (1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] vdcFile rawDataFile" << endl; op.PrintOptionHelp(stderr); return (0); } if (argc != 3) { cerr << "Usage: " << ProgName << " [options] vdcFile rawDataFile" << endl; op.PrintOptionHelp(stderr); return (1); } string master = argv[1]; // Path to VDC master file string datafile = argv[2]; // Path to raw data file if (opt.debug) MyBase::SetDiagMsgFilePtr(stderr); VDCNetCDF vdc(opt.nthreads); vector bs; int rc = vdc.Initialize(master, vector(), VDC::A, bs, 4 * 1024 * 1024); vector hslice_dims; size_t nslice; rc = vdc.GetHyperSliceInfo(opt.varname, -1, hslice_dims, nslice); if (rc < 0) { MyBase::SetErrMsg("Invalid variable name : %s", opt.varname.c_str()); return (1); } size_t nelements = 1; for (int i = 0; i < hslice_dims.size(); i++) { nelements *= hslice_dims[i]; } vector dimlens; bool ok = vdc.GetVarDimLens(opt.varname, true, dimlens); VAssert(ok == true); size_t ntotal = 1; for (int i = 0; i < dimlens.size(); i++) { ntotal *= dimlens[i]; } float *slice = new float[nelements]; FILE *fp = fopen(datafile.c_str(), "rb"); if (!fp) { MyBase::SetErrMsg("fopen(%s) : %M", datafile.c_str()); return (1); } int fdr = vdc.OpenVariableWrite(opt.ts, opt.varname, opt.lod); if (fdr < 0) return (1); for (size_t i = 0; i < nslice; i++) { nelements = nelements < ntotal ? nelements : ntotal; int rc = read_data(fp, opt.type, opt.swapbytes, nelements, slice); if (rc < 0) return (1); ntotal -= nelements; rc = vdc.WriteSlice(fdr, slice); if (rc < 0) return (1); } rc = vdc.CloseVariableWrite(fdr); if (rc < 0) return (1); fclose(fp); return (0); } ================================================ FILE: apps/raw2wasp/CMakeLists.txt ================================================ add_executable (raw2wasp raw2wasp.cpp) target_link_libraries (raw2wasp common wasp) OpenMPInstall ( TARGETS raw2wasp DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/raw2wasp/raw2wasp.cpp ================================================ #include #include #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; // // Command line argument stuff // struct opt_t { string varname; string type; int lod; int nthreads; OptionParser::Boolean_T debug; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"varname", 1, "var1", "Name of variable"}, {"type", 1, "float32", "Primitive type of input data"}, {"lod", 1, "-1", "Compression levels saved. 0 => coarsest, 1 => " "next refinement, etc. -1 => all levels defined by the netcdf file"}, {"nthreads", 1, "0", "Specify number of execution threads " "0 => use number of cores"}, {"debug", 0, "", "Enable diagnostic"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"varname", Wasp::CvtToCPPStr, &opt.varname, sizeof(opt.varname)}, {"type", Wasp::CvtToCPPStr, &opt.type, sizeof(opt.type)}, {"lod", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)}, {"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; const char *ProgName; template void CopyVar(string datafile, string ncdffile, T dummy) { WASP wasp(opt.nthreads); int rc = wasp.Open(ncdffile, NC_WRITE); vector dimnames; vector dims; rc = wasp.InqVarDims(opt.varname, dimnames, dims); if (rc < 0) exit(1); size_t nelements = 1; for (int i = 0; i < dims.size(); i++) nelements *= dims[i]; T *data = new T[nelements]; FILE *fp = fopen(datafile.c_str(), "rb"); if (!fp) { MyBase::SetErrMsg("fopen(%s) : %M", datafile.c_str()); exit(1); } rc = wasp.OpenVarWrite(opt.varname, -1); if (rc < 0) exit(1); rc = fread(data, sizeof(*data), nelements, fp); if (rc != nelements) { MyBase::SetErrMsg("fread() : %M"); exit(1); } vector count = dims; vector start(dims.size(), 0); rc = wasp.PutVara(start, count, data); if (rc < 0) exit(1); rc = wasp.CloseVar(); if (rc < 0) exit(1); rc = wasp.Close(); if (rc < 0) exit(1); } int main(int argc, char **argv) { OptionParser op; MyBase::SetErrMsgFilePtr(stderr); // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] netcdffile datafile" << endl; op.PrintOptionHelp(stderr); exit(0); } if (argc != 3) { cerr << "Usage: " << ProgName << " [options] netcdffile datafile" << endl; op.PrintOptionHelp(stderr); exit(1); } string ncdffile = argv[1]; // Path to a vdf file string datafile = argv[2]; // Path to raw data file if (opt.debug) MyBase::SetDiagMsgFilePtr(stderr); if (opt.type == "float32") { float dummy = 0.0; CopyVar(datafile, ncdffile, dummy); } else if (opt.type == "float64") { double dummy = 0.0; CopyVar(datafile, ncdffile, dummy); } else if (opt.type == "int32") { int dummy = 0.0; CopyVar(datafile, ncdffile, dummy); } else if (opt.type == "int16") { int16_t dummy = 0.0; CopyVar(datafile, ncdffile, dummy); } else if (opt.type == "uint8") { unsigned char dummy = 0.0; CopyVar(datafile, ncdffile, dummy); } else { cerr << "Invalid type " << opt.type << endl; } return (0); } ================================================ FILE: apps/tiff2geotiff/CMakeLists.txt ================================================ add_executable (tiff2geotiff tiff2geotiff.cpp geotiff_proj4.cpp getopt.cpp) if (WIN32) target_link_libraries (tiff2geotiff libtiff geotiff proj_6_1 common) else () target_link_libraries (tiff2geotiff tiff geotiff proj common) endif() OpenMPInstall ( TARGETS tiff2geotiff DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/tiff2geotiff/geotiff_proj4.cpp ================================================ /****************************************************************************** * $Id$ * * Project: libgeotiff * Purpose: Code to convert a normalized GeoTIFF definition into a PROJ.4 * (OGDI) compatible projection string. * Author: Frank Warmerdam, warmerda@home.com * ****************************************************************************** * Copyright (c) 1999, Frank Warmerdam * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************** * * $Log$ * Revision 1.7 2010/02/11 18:10:38 alannorton * * Cleaned up code to avoid extraneous compiler warnings on windows. * Fixed metadata merge and vdf write to work with new DataMgr * * Revision 1.6 2009/07/14 20:34:07 alannorton * Changes to compile on Windows * * Revision 1.5 2009/07/13 19:03:18 clynejp * * Ported to RHEL5 * * Revision 1.4 2009/05/22 22:25:54 alannorton * Added capability of handling lat/long projection, added option of specifying * corners as a command line argument. * * Revision 1.3 2009/04/06 22:12:03 alannorton * Modifications to geotiff to fix polar stereo and mercator projections. * * Revision 1.2 2009/04/03 20:56:13 alannorton * Changes to polar stereo projection parameters * * Revision 1.1 2009/04/03 18:00:05 alannorton * Added modified version of geotiff_proj4 because the library version did * not support mercator or polar stereographic projections. * * Revision 1.25 2008/05/21 04:25:01 fwarmerdam * avoid warnings. * * Revision 1.24 2008/05/21 04:12:57 fwarmerdam * added preliminary GTIFSetFromProj4() support * * Revision 1.23 2007/03/13 18:04:33 fwarmerdam * added new zealand map grid support per bug 1519 * * Revision 1.22 2005/03/04 04:32:37 fwarmerdam * added cylindricalequalarea support * * Revision 1.21 2003/08/21 18:42:39 warmerda * fixed support for ModelTypeGeographic as per email from Young Su, Cha * * Revision 1.20 2003/07/08 17:31:30 warmerda * cleanup various warnings * * Revision 1.19 2002/11/29 20:57:09 warmerda * added LCC1SP mapping * * Revision 1.18 2002/07/09 14:47:53 warmerda * fixed translation of polar stereographic * * Revision 1.17 2001/11/23 19:53:56 warmerda * free PROJ.4 definitions after use * * Revision 1.16 2000/12/05 19:21:45 warmerda * added cassini support * * Revision 1.15 2000/12/05 17:44:41 warmerda * Use +R_A for Miller and VanDerGrinten * * Revision 1.14 2000/10/13 18:06:51 warmerda * added econic support for PROJ.4 translation * * Revision 1.13 2000/09/15 19:30:48 warmerda * *** empty log message *** * * Revision 1.12 2000/09/15 18:21:07 warmerda * Fixed order of parameters for LCC 2SP. When parameters * were read from EPSG CSV files the standard parallels and origin * were mixed up. This affects alot of state plane zones! * * Revision 1.11 2000/06/06 17:39:45 warmerda * Modify to work with projUV version of library. * * Revision 1.10 1999/07/06 15:05:51 warmerda * Fixed up LCC_1SP notes. * * Revision 1.9 1999/05/04 16:24:49 warmerda * Fixed projection string formating with zones. * * Revision 1.8 1999/05/04 12:27:01 geotiff * only emit proj unsupported warning if DEBUG defined * * Revision 1.7 1999/05/04 03:14:59 warmerda * fixed use of foot instead of ft for units * * Revision 1.6 1999/05/03 17:50:31 warmerda * avoid warnings on IRIX * * Revision 1.5 1999/04/29 23:02:24 warmerda * added mapsys utm test. * * Revision 1.4 1999/03/18 21:35:42 geotiff * Added reprojection functions * * Revision 1.3 1999/03/10 18:11:17 geotiff * Removed comment about this not being the master ... now it is. * * Revision 1.2 1999/03/10 18:10:27 geotiff * Avoid use of cpl_serv.h and CPLStrdup(). * * Revision 1.1 1999/03/10 15:20:43 geotiff * New * */ #ifdef WIN32 #include "geotiff/cpl_serv.h" #include "geotiff/geotiff.h" #include "geotiff/geo_normalize.h" #include "geotiff/geovalues.h" #else #include "cpl_serv.h" #include "geotiff.h" #include "geo_normalize.h" #include "geovalues.h" #endif #ifdef WIN32 #pragma warning(disable : 4996) #endif /************************************************************************/ /* OSRProj4Tokenize() */ /* */ /* Custom tokenizing function for PROJ.4 strings. The main */ /* reason we can't just use CSLTokenizeString is to handle */ /* strings with a + sign in the exponents of parameter values. */ /************************************************************************/ static char **OSRProj4Tokenize(const char *pszFull) { char * pszStart = NULL; char * pszFullWrk; char **papszTokens = (char **)calloc(sizeof(char *), 200); int i; int nTokens = 0; if (pszFull == NULL) return NULL; pszFullWrk = strdup(pszFull); for (i = 0; pszFullWrk[i] != '\0'; i++) { switch (pszFullWrk[i]) { case '+': if (i == 0 || pszFullWrk[i - 1] == '\0') { if (pszStart != NULL) { if (strstr(pszStart, "=") != NULL) { papszTokens[nTokens++] = strdup(pszStart); } else { char szAsBoolean[100]; strcpy(szAsBoolean, pszStart); strcat(szAsBoolean, "=yes"); papszTokens[nTokens++] = strdup(szAsBoolean); } } pszStart = pszFullWrk + i + 1; } break; case ' ': case '\t': case '\n': pszFullWrk[i] = '\0'; break; default: break; } } if (pszStart != NULL && strlen(pszStart) > 0) { papszTokens[nTokens++] = strdup(pszStart); } free(pszFullWrk); return papszTokens; } /************************************************************************/ /* OSR_GSV() */ /************************************************************************/ static const char *OSR_GSV(char **papszNV, const char *pszField) { int field_len = (int)strlen(pszField); int i; if (!papszNV) return NULL; for (i = 0; papszNV[i] != NULL; i++) { if (EQUALN(papszNV[i], pszField, field_len)) { if (papszNV[i][field_len] == '=') return papszNV[i] + field_len + 1; if (strlen(papszNV[i]) == field_len) return ""; } } return NULL; } /************************************************************************/ /* OSR_GDV() */ /* */ /* Fetch a particular parameter out of the parameter list, or */ /* the indicated default if it isn't available. This is a */ /* helper function for importFromProj4(). */ /************************************************************************/ static double OSR_GDV(char **papszNV, const char *pszField, double dfDefaultValue) { const char *pszValue = OSR_GSV(papszNV, pszField); // special hack to use k_0 if available. if (pszValue == NULL && EQUAL(pszField, "k")) return OSR_GDV(papszNV, "k_0", dfDefaultValue); if (pszValue == NULL) return dfDefaultValue; else return atof(pszValue); } /************************************************************************/ /* OSRFreeStringList() */ /************************************************************************/ static void OSRFreeStringList(char **list) { int i; for (i = 0; list != NULL && list[i] != NULL; i++) free(list[i]); free(list); } /************************************************************************/ /* GTIFSetFromProj4_WRF() */ /* version modified from geotiff library version of GTIFSetFromPRoj4 */ /* to handle mercator and polar stereo projections as required in WRF */ /* Modifications by Alan Norton, April 2009 */ /************************************************************************/ int GTIFSetFromProj4_WRF(GTIF *gtif, const char *proj4) { char ** papszNV = OSRProj4Tokenize(proj4); short nSpheroid = KvUserDefined; double dfSemiMajor = 0.0, dfSemiMinor = 0.0, dfInvFlattening = 0.0; int nDatum = KvUserDefined; int nGCS = KvUserDefined; const char *value; /* -------------------------------------------------------------------- */ /* Get the ellipsoid definition. */ /* -------------------------------------------------------------------- */ value = OSR_GSV(papszNV, "ellps"); if (value == NULL) { nSpheroid = Ellipse_Sphere; } else if (EQUAL(value, "WGS84")) nSpheroid = Ellipse_WGS_84; else if (EQUAL(value, "clrk66")) nSpheroid = Ellipse_Clarke_1866; else if (EQUAL(value, "clrk80")) nSpheroid = Ellipse_Clarke_1880; else if (EQUAL(value, "GRS80")) nSpheroid = Ellipse_GRS_1980; if (nSpheroid == KvUserDefined) { dfSemiMajor = OSR_GDV(papszNV, "a", 0.0); dfSemiMinor = OSR_GDV(papszNV, "b", 0.0); dfInvFlattening = OSR_GDV(papszNV, "rf", 0.0); if (dfSemiMinor != 0.0 && dfInvFlattening == 0.0) dfInvFlattening = -1.0 / (dfSemiMinor / dfSemiMajor - 1.0); } /* -------------------------------------------------------------------- */ /* Get the GCS/Datum code. */ /* -------------------------------------------------------------------- */ value = OSR_GSV(papszNV, "datum"); if (value == NULL) { } else if (EQUAL(value, "WGS84")) { nGCS = GCS_WGS_84; nDatum = Datum_WGS84; } else if (EQUAL(value, "NAD83")) { nGCS = GCS_NAD83; nDatum = Datum_North_American_Datum_1983; } else if (EQUAL(value, "NAD27")) { nGCS = GCS_NAD27; nDatum = Datum_North_American_Datum_1927; } /* -------------------------------------------------------------------- */ /* Operate on the basis of the projection name. */ /* -------------------------------------------------------------------- */ value = OSR_GSV(papszNV, "proj"); if (value == NULL) { OSRFreeStringList(papszNV); return FALSE; } else if (EQUAL(value, "longlat") || EQUAL(value, "latlong")) { GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeGeographic); GTIFKeySet(gtif, GTRasterTypeGeoKey, TYPE_SHORT, 1, RasterPixelIsArea); GTIFKeySet(gtif, GeogAngularUnitsGeoKey, TYPE_SHORT, 1, Angular_Degree); } /* Handle just the WRF-required mercator tags:*/ else if (EQUAL(value, "merc")) { GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected); GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, ProjectionGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_Mercator); GTIFKeySet(gtif, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "lat_ts", 0.0)); GTIFKeySet(gtif, ProjNatOriginLongGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "lon_0", 0.0)); GTIFKeySet(gtif, ProjScaleAtNatOriginGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "k", 1.0)); GTIFKeySet(gtif, ProjFalseEastingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "x_0", 0.0)); GTIFKeySet(gtif, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "y_0", 0.0)); // specify lat_ts as standard parallel 1 (default 0? ????) GTIFKeySet(gtif, ProjStdParallel1GeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "lat_0", 0.0)); } else if (EQUAL(value, "tmerc")) { GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected); GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, ProjectionGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_TransverseMercator); GTIFKeySet(gtif, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "lat_0", 0.0)); GTIFKeySet(gtif, ProjNatOriginLongGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "lon_0", 0.0)); GTIFKeySet(gtif, ProjScaleAtNatOriginGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "k", 1.0)); GTIFKeySet(gtif, ProjFalseEastingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "x_0", 0.0)); GTIFKeySet(gtif, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "utm")) { int nZone = (int)OSR_GDV(papszNV, "zone", 0); const char *south = OSR_GSV(papszNV, "south"); GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected); GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, ProjectionGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_TransverseMercator); GTIFKeySet(gtif, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1, 0.0); GTIFKeySet(gtif, ProjNatOriginLongGeoKey, TYPE_DOUBLE, 1, nZone * 6 - 183.0); GTIFKeySet(gtif, ProjScaleAtNatOriginGeoKey, TYPE_DOUBLE, 1, 0.9996); GTIFKeySet(gtif, ProjFalseEastingGeoKey, TYPE_DOUBLE, 1, 500000.0); if (south != NULL) GTIFKeySet(gtif, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1, 10000000.0); else GTIFKeySet(gtif, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1, 0.0); } /* For polar stereo only handle pure north or south projections*/ else if (EQUAL(value, "stere")) { GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected); GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, ProjectionGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_PolarStereographic); // specify lat_ts as natural origin latitude GTIFKeySet(gtif, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "lat_ts", 90.0)); GTIFKeySet(gtif, ProjStraightVertPoleLongGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "lon_0", 0.0)); GTIFKeySet(gtif, ProjScaleAtNatOriginGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "k", 1.0)); GTIFKeySet(gtif, ProjFalseEastingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "x_0", 0.0)); GTIFKeySet(gtif, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "lcc") && OSR_GDV(papszNV, "lat_0", 0.0) == OSR_GDV(papszNV, "lat_1", 0.0)) { GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected); GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, ProjectionGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_LambertConfConic_1SP); GTIFKeySet(gtif, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "lat_0", 0.0)); GTIFKeySet(gtif, ProjNatOriginLongGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "lon_0", 0.0)); GTIFKeySet(gtif, ProjScaleAtNatOriginGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "k", 1.0)); GTIFKeySet(gtif, ProjFalseEastingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "x_0", 0.0)); GTIFKeySet(gtif, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "lcc") && OSR_GDV(papszNV, "lat_0", 0.0) != OSR_GDV(papszNV, "lat_1", 0.0)) { GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected); GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, ProjectionGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_LambertConfConic_2SP); GTIFKeySet(gtif, ProjFalseOriginLatGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "lat_0", 0.0)); GTIFKeySet(gtif, ProjFalseOriginLongGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "lon_0", 0.0)); GTIFKeySet(gtif, ProjStdParallel1GeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "lat_1", 0.0)); GTIFKeySet(gtif, ProjStdParallel2GeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "lat_2", 0.0)); GTIFKeySet(gtif, ProjFalseOriginEastingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "x_0", 0.0)); GTIFKeySet(gtif, ProjFalseOriginNorthingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, "y_0", 0.0)); } #ifdef notdef else if (EQUAL(value, "bonne")) { SetBonne(OSR_GDV(papszNV, "lat_1", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "cass")) { SetCS(OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "nzmg")) { SetNZMG(OSR_GDV(papszNV, "lat_0", -41.0), OSR_GDV(papszNV, "lon_0", 173.0), OSR_GDV(papszNV, "x_0", 2510000.0), OSR_GDV(papszNV, "y_0", 6023150.0)); } else if (EQUAL(value, "cea")) { SetCEA(OSR_GDV(papszNV, "lat_ts", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "merc") /* 2SP form */ && OSR_GDV(papszNV, "lat_ts", 1000.0) < 999.0) { SetMercator2SP(OSR_GDV(papszNV, "lat_ts", 0.0), 0.0, OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "merc")) /* 1SP form */ { SetMercator(0.0, OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "k", 1.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "stere") && ABS(OSR_GDV(papszNV, "lat_0", 0.0) - 90) < 0.001) { SetPS(OSR_GDV(papszNV, "lat_ts", 90.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "k", 1.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "stere") && ABS(OSR_GDV(papszNV, "lat_0", 0.0) + 90) < 0.001) { SetPS(OSR_GDV(papszNV, "lat_ts", -90.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "k", 1.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUALN(value, "stere", 5) /* mostly sterea */ && CSLFetchNameValue(papszNV, "k") != NULL) { SetOS(OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "k", 1.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "stere")) { SetStereographic(OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), 1.0, OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "eqc")) { if (OSR_GDV(papszNV, "lat_0", 0.0) != OSR_GDV(papszNV, "lat_ts", 0.0)) SetEquirectangular2(OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0) + dfFromGreenwich, OSR_GDV(papszNV, "lat_ts", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); else SetEquirectangular(OSR_GDV(papszNV, "lat_ts", 0.0), OSR_GDV(papszNV, "lon_0", 0.0) + dfFromGreenwich, OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "glabsgm")) { SetGaussLabordeReunion(OSR_GDV(papszNV, "lat_0", -21.116666667), OSR_GDV(papszNV, "lon_0", 55.53333333309) + dfFromGreenwich, OSR_GDV(papszNV, "k_0", 1.0), OSR_GDV(papszNV, "x_0", 160000.000), OSR_GDV(papszNV, "y_0", 50000.000)); } else if (EQUAL(value, "gnom")) { SetGnomonic(OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "ortho")) { SetOrthographic(OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "laea")) { SetLAEA(OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "aeqd")) { SetAE(OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "eqdc")) { SetEC(OSR_GDV(papszNV, "lat_1", 0.0), OSR_GDV(papszNV, "lat_2", 0.0), OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "mill")) { SetMC(OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "moll")) { SetMollweide(OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "eck4")) { SetEckertIV(OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "eck6")) { SetEckertVI(OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "poly")) { SetPolyconic(OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "aea")) { SetACEA(OSR_GDV(papszNV, "lat_1", 0.0), OSR_GDV(papszNV, "lat_2", 0.0), OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "robin")) { SetRobinson(OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "vandg")) { SetVDG(OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "sinu")) { SetSinusoidal(OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "gall")) { SetGS(OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "goode")) { SetGH(OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "geos")) { SetGEOS(OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "h", 35785831.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "lcc")) { if (OSR_GDV(papszNV, "lat_0", 0.0) == OSR_GDV(papszNV, "lat_1", 0.0)) { /* 1SP form */ SetLCC1SP(OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "k_0", 1.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else { /* 2SP form */ SetLCC(OSR_GDV(papszNV, "lat_1", 0.0), OSR_GDV(papszNV, "lat_2", 0.0), OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } } else if (EQUAL(value, "omerc")) { SetHOM(OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lonc", 0.0), OSR_GDV(papszNV, "alpha", 0.0), 0.0, /* ??? */ OSR_GDV(papszNV, "k", 1.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "somerc")) { SetHOM(OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), 90.0, 90.0, OSR_GDV(papszNV, "k", 1.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "krovak")) { SetKrovak(OSR_GDV(papszNV, "lat_0", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "alpha", 0.0), 0.0, // pseudo_standard_parallel_1 OSR_GDV(papszNV, "k", 1.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "iwm_p")) { SetIWMPolyconic(OSR_GDV(papszNV, "lat_1", 0.0), OSR_GDV(papszNV, "lat_2", 0.0), OSR_GDV(papszNV, "lon_0", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "wag1")) { SetWagner(1, 0.0, OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "wag2")) { SetWagner(2, 0.0, OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "wag3")) { SetWagner(3, OSR_GDV(papszNV, "lat_ts", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "wag1")) { SetWagner(4, 0.0, OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "wag1")) { SetWagner(5, 0.0, OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "wag1")) { SetWagner(6, 0.0, OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "wag1")) { SetWagner(7, 0.0, OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } else if (EQUAL(value, "tpeqd")) { SetTPED(OSR_GDV(papszNV, "lat_1", 0.0), OSR_GDV(papszNV, "lon_1", 0.0), OSR_GDV(papszNV, "lat_2", 0.0), OSR_GDV(papszNV, "lon_2", 0.0), OSR_GDV(papszNV, "x_0", 0.0), OSR_GDV(papszNV, "y_0", 0.0)); } #endif else { /* unsupported coordinate system */ OSRFreeStringList(papszNV); return FALSE; } /* -------------------------------------------------------------------- */ /* Write the GCS if we have it, otherwise write the datum. */ /* -------------------------------------------------------------------- */ if (nGCS != KvUserDefined) { GTIFKeySet(gtif, GeographicTypeGeoKey, TYPE_SHORT, 1, nGCS); } else { GTIFKeySet(gtif, GeographicTypeGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, GeogGeodeticDatumGeoKey, TYPE_SHORT, 1, nDatum); } /* -------------------------------------------------------------------- */ /* Write the ellipsoid if we don't know the GCS. */ /* -------------------------------------------------------------------- */ if (nGCS == KvUserDefined) { if (nSpheroid != KvUserDefined) GTIFKeySet(gtif, GeogEllipsoidGeoKey, TYPE_SHORT, 1, nSpheroid); else { GTIFKeySet(gtif, GeogEllipsoidGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, GeogSemiMajorAxisGeoKey, TYPE_DOUBLE, 1, dfSemiMajor); if (dfInvFlattening == 0.0) GTIFKeySet(gtif, GeogSemiMinorAxisGeoKey, TYPE_DOUBLE, 1, dfSemiMajor); else GTIFKeySet(gtif, GeogInvFlatteningGeoKey, TYPE_DOUBLE, 1, dfInvFlattening); } } /* -------------------------------------------------------------------- */ /* Linear units translation */ /* -------------------------------------------------------------------- */ value = OSR_GSV(papszNV, "units"); if (value == NULL) { value = OSR_GSV(papszNV, "to_meter"); if (value) { GTIFKeySet(gtif, ProjLinearUnitsGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, ProjLinearUnitSizeGeoKey, TYPE_DOUBLE, 1, atof(value)); } } else if (EQUAL(value, "meter") || EQUAL(value, "m")) { GTIFKeySet(gtif, ProjLinearUnitsGeoKey, TYPE_SHORT, 1, Linear_Meter); } else if (EQUAL(value, "us-ft")) { GTIFKeySet(gtif, ProjLinearUnitsGeoKey, TYPE_SHORT, 1, Linear_Foot_US_Survey); } else if (EQUAL(value, "ft")) { GTIFKeySet(gtif, ProjLinearUnitsGeoKey, TYPE_SHORT, 1, Linear_Foot); } OSRFreeStringList(papszNV); return TRUE; } /************************************************************************/ /* GTIFGetProj4Defn() */ /************************************************************************/ char *GTIFGetProj4Defn(GTIFDefn *psDefn) { char szProjection[512]; char szUnits[24]; double dfFalseEasting, dfFalseNorthing; szProjection[0] = '\0'; /* ==================================================================== */ /* Translate the units of measure. */ /* */ /* Note that even with a +units, or +to_meter in effect, it is */ /* still assumed that all the projection parameters are in */ /* meters. */ /* ==================================================================== */ if (psDefn->UOMLength == Linear_Meter) { strcpy(szUnits, "+units=m "); } else if (psDefn->UOMLength == Linear_Foot) { strcpy(szUnits, "+units=ft "); } else if (psDefn->UOMLength == Linear_Foot_US_Survey) { strcpy(szUnits, "+units=us-ft "); } else if (psDefn->UOMLength == Linear_Foot_Indian) { strcpy(szUnits, "+units=ind-ft "); } else if (psDefn->UOMLength == Linear_Link) { strcpy(szUnits, "+units=link "); } else if (psDefn->UOMLength == Linear_Yard_Indian) { strcpy(szUnits, "+units=ind-yd "); } else if (psDefn->UOMLength == Linear_Fathom) { strcpy(szUnits, "+units=fath "); } else if (psDefn->UOMLength == Linear_Mile_International_Nautical) { strcpy(szUnits, "+units=kmi "); } else { sprintf(szUnits, "+to_meter=%.10f", psDefn->UOMLengthInMeters); } /* -------------------------------------------------------------------- */ /* false easting and northing are in meters and that is what */ /* PROJ.4 wants regardless of the linear units. */ /* -------------------------------------------------------------------- */ dfFalseEasting = psDefn->ProjParm[5]; dfFalseNorthing = psDefn->ProjParm[6]; /* ==================================================================== */ /* Handle general projection methods. */ /* ==================================================================== */ /* -------------------------------------------------------------------- */ /* Geographic. */ /* -------------------------------------------------------------------- */ if (psDefn->Model == ModelTypeGeographic) { sprintf(szProjection + strlen(szProjection), "+proj=latlong "); } /* -------------------------------------------------------------------- */ /* UTM - special case override on transverse mercator so things */ /* will be more meaningful to the user. */ /* -------------------------------------------------------------------- */ else if (psDefn->MapSys == MapSys_UTM_North) { sprintf(szProjection + strlen(szProjection), "+proj=utm +zone=%d ", psDefn->Zone); } /* -------------------------------------------------------------------- */ /* Transverse Mercator */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_TransverseMercator) { sprintf(szProjection + strlen(szProjection), "+proj=tmerc +lat_0=%.9f +lon_0=%.9f +k=%f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[4], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* Mercator */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_Mercator) { sprintf(szProjection + strlen(szProjection), "+proj=merc +lat_ts=%.9f +lon_0=%.9f +k=%f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[4], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* Cassini/Soldner */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_CassiniSoldner) { sprintf(szProjection + strlen(szProjection), "+proj=cass +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* Oblique Stereographic - Should this really map onto */ /* Stereographic? */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_ObliqueStereographic) { sprintf(szProjection + strlen(szProjection), "+proj=stere +lat_0=%.9f +lon_0=%.9f +k=%f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[4], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* Stereographic */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_Stereographic) { sprintf(szProjection + strlen(szProjection), "+proj=stere +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* Polar Stereographic */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_PolarStereographic) { if (psDefn->ProjParm[0] > 0.0) sprintf(szProjection + strlen(szProjection), "+proj=stere +lat_0=90 +lat_ts=%.9f +lon_0=%.9f " "+k=%.9f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[4], dfFalseEasting, dfFalseNorthing); else sprintf(szProjection + strlen(szProjection), "+proj=stere +lat_0=-90 +lat_ts=%.9f +lon_0=%.9f " "+k=%.9f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[4], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* Equirectangular */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_Equirectangular) { sprintf(szProjection + strlen(szProjection), "+proj=eqc +lat_ts=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* Gnomonic */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_Gnomonic) { sprintf(szProjection + strlen(szProjection), "+proj=gnom +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* Orthographic */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_Orthographic) { sprintf(szProjection + strlen(szProjection), "+proj=ortho +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* Lambert Azimuthal Equal Area */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_LambertAzimEqualArea) { sprintf(szProjection + strlen(szProjection), "+proj=laea +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* Azimuthal Equidistant */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_AzimuthalEquidistant) { sprintf(szProjection + strlen(szProjection), "+proj=aeqd +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* Miller Cylindrical */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_MillerCylindrical) { sprintf(szProjection + strlen(szProjection), "+proj=mill +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f +R_A ", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* Polyconic */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_Polyconic) { sprintf(szProjection + strlen(szProjection), "+proj=poly +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* AlbersEqualArea */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_AlbersEqualArea) { sprintf(szProjection + strlen(szProjection), "+proj=aea +lat_1=%.9f +lat_2=%.9f +lat_0=%.9f +lon_0=%.9f" " +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[2], psDefn->ProjParm[3], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* EquidistantConic */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_EquidistantConic) { sprintf(szProjection + strlen(szProjection), "+proj=eqdc +lat_1=%.9f +lat_2=%.9f +lat_0=%.9f +lon_0=%.9f" " +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[2], psDefn->ProjParm[3], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* Robinson */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_Robinson) { sprintf(szProjection + strlen(szProjection), "+proj=robin +lon_0=%.9f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* VanDerGrinten */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_VanDerGrinten) { sprintf(szProjection + strlen(szProjection), "+proj=vandg +lon_0=%.9f +x_0=%.3f +y_0=%.3f +R_A ", psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* Sinusoidal */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_Sinusoidal) { sprintf(szProjection + strlen(szProjection), "+proj=sinu +lon_0=%.9f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* LambertConfConic_2SP */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_LambertConfConic_2SP) { sprintf(szProjection + strlen(szProjection), "+proj=lcc +lat_0=%.9f +lon_0=%.9f +lat_1=%.9f +lat_2=%.9f " " +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[2], psDefn->ProjParm[3], dfFalseEasting, dfFalseNorthing); } /* -------------------------------------------------------------------- */ /* LambertConfConic_1SP */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_LambertConfConic_1SP) { sprintf(szProjection + strlen(szProjection), "+proj=lcc +lat_0=%.9f +lat_1=%.9f +lon_0=%.9f" " +k_0=%.9f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[4], psDefn->ProjParm[5], psDefn->ProjParm[6]); } /* -------------------------------------------------------------------- */ /* CT_CylindricalEqualArea */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_CylindricalEqualArea) { sprintf(szProjection + strlen(szProjection), "+proj=cea +lat_ts=%.9f +lon_0=%.9f " " +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[5], psDefn->ProjParm[6]); } /* -------------------------------------------------------------------- */ /* NewZealandMapGrid */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_NewZealandMapGrid) { sprintf(szProjection + strlen(szProjection), "+proj=nzmg +lat_0=%.9f +lon_0=%.9f" " +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[5], psDefn->ProjParm[6]); } /* -------------------------------------------------------------------- */ /* Transverse Mercator - south oriented. */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_TransvMercator_SouthOriented) { /* this appears to be an unsupported formulation with PROJ.4 */ } /* -------------------------------------------------------------------- */ /* ObliqueMercator (Hotine) */ /* -------------------------------------------------------------------- */ else if (psDefn->CTProjection == CT_ObliqueMercator) { /* not clear how ProjParm[3] - angle from rectified to skewed grid - should be applied ... see the +not_rot flag for PROJ.4. Just ignoring for now. */ sprintf(szProjection + strlen(szProjection), "+proj=omerc +lat_0=%.9f +lonc=%.9f +alpha=%.9f" " +k=%.9f +x_0=%.3f +y_0=%.3f ", psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[2], psDefn->ProjParm[4], psDefn->ProjParm[5], psDefn->ProjParm[6]); } /* ==================================================================== */ /* Handle ellipsoid information. */ /* ==================================================================== */ if (psDefn->Ellipsoid == Ellipse_WGS_84) strcat(szProjection, "+ellps=WGS84 "); else if (psDefn->Ellipsoid == Ellipse_Clarke_1866) strcat(szProjection, "+ellps=clrk66 "); else if (psDefn->Ellipsoid == Ellipse_Clarke_1880) strcat(szProjection, "+ellps=clrk80 "); else if (psDefn->Ellipsoid == Ellipse_GRS_1980) strcat(szProjection, "+ellps=GRS80 "); else { if (psDefn->SemiMajor != 0.0 && psDefn->SemiMinor != 0.0) { sprintf(szProjection + strlen(szProjection), "+a=%.3f +b=%.3f ", psDefn->SemiMajor, psDefn->SemiMinor); } } strcat(szProjection, szUnits); return (strdup(szProjection)); } #if !defined(HAVE_LIBPROJ) || !defined(HAVE_PROJECTS_H) int GTIFProj4ToLatLong(GTIFDefn *psDefn, int nPoints, double *padfX, double *padfY) { (void)psDefn; (void)nPoints; (void)padfX; (void)padfY; #ifdef DEBUG fprintf(stderr, "GTIFProj4ToLatLong() - PROJ.4 support not compiled in.\n"); #endif return FALSE; } int GTIFProj4FromLatLong(GTIFDefn *psDefn, int nPoints, double *padfX, double *padfY) { (void)psDefn; (void)nPoints; (void)padfX; (void)padfY; #ifdef DEBUG fprintf(stderr, "GTIFProj4FromLatLong() - PROJ.4 support not compiled in.\n"); #endif return FALSE; } #else #include "proj_api.h" #ifdef USE_PROJUV #define UV projUV #endif /************************************************************************/ /* GTIFProj4FromLatLong() */ /* */ /* Convert lat/long values to projected coordinate for a */ /* particular definition. */ /************************************************************************/ int GTIFProj4FromLatLong(GTIFDefn *psDefn, int nPoints, double *padfX, double *padfY) { char * pszProjection, **papszArgs; projPJ psPJ; int i; /* -------------------------------------------------------------------- */ /* Get a projection definition. */ /* -------------------------------------------------------------------- */ pszProjection = GTIFGetProj4Defn(psDefn); if (pszProjection == NULL) return FALSE; /* -------------------------------------------------------------------- */ /* Parse into tokens for pj_init(), and initialize the projection. */ /* -------------------------------------------------------------------- */ papszArgs = CSLTokenizeStringComplex(pszProjection, " +", TRUE, FALSE); free(pszProjection); psPJ = pj_init(CSLCount(papszArgs), papszArgs); CSLDestroy(papszArgs); if (psPJ == NULL) { return FALSE; } /* -------------------------------------------------------------------- */ /* Process each of the points. */ /* -------------------------------------------------------------------- */ for (i = 0; i < nPoints; i++) { projUV sUV; sUV.u = padfX[i] * DEG_TO_RAD; sUV.v = padfY[i] * DEG_TO_RAD; sUV = pj_fwd(sUV, psPJ); padfX[i] = sUV.u; padfY[i] = sUV.v; } pj_free(psPJ); return TRUE; } /************************************************************************/ /* GTIFProj4ToLatLong() */ /* */ /* Convert projection coordinates to lat/long for a particular */ /* definition. */ /************************************************************************/ int GTIFProj4ToLatLong(GTIFDefn *psDefn, int nPoints, double *padfX, double *padfY) { char * pszProjection, **papszArgs; projPJ psPJ; int i; /* -------------------------------------------------------------------- */ /* Get a projection definition. */ /* -------------------------------------------------------------------- */ pszProjection = GTIFGetProj4Defn(psDefn); if (pszProjection == NULL) return FALSE; /* -------------------------------------------------------------------- */ /* Parse into tokens for pj_init(), and initialize the projection. */ /* -------------------------------------------------------------------- */ papszArgs = CSLTokenizeStringComplex(pszProjection, " +", TRUE, FALSE); free(pszProjection); psPJ = pj_init(CSLCount(papszArgs), papszArgs); CSLDestroy(papszArgs); if (psPJ == NULL) { return FALSE; } /* -------------------------------------------------------------------- */ /* Process each of the points. */ /* -------------------------------------------------------------------- */ for (i = 0; i < nPoints; i++) { projUV sUV; sUV.u = padfX[i]; sUV.v = padfY[i]; sUV = pj_inv(sUV, psPJ); padfX[i] = sUV.u * RAD_TO_DEG; padfY[i] = sUV.v * RAD_TO_DEG; } pj_free(psPJ); return TRUE; } #endif /* has projects.h and -lproj */ ================================================ FILE: apps/tiff2geotiff/getopt.cpp ================================================ /* * Copyright (c) 1987 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)getopt.c 4.13 (Berkeley) 2/23/91"; #endif /* LIBC_SCCS and not lint */ #include #include const char *myoptarg = 0; int optind = 1; /* * get option letter from argument vector */ int opterr = 1; /* if error message should be printed */ int optopt; /* character checked for validity */ #define BADCH (int)'?' #define EMSG "" int getopt(int nargc, char **nargv, const char *ostr) { const static char *place = EMSG; /* option letter processing */ const char * oli; /* option letter list index */ char * p; if (!*place) { /* update scanning pointer */ if (optind >= nargc || *(place = nargv[optind]) != '-') { place = EMSG; return (EOF); } if (place[1] && *++place == '-') { /* found "--" */ ++optind; place = EMSG; return (EOF); } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) { /* * if the user didn't specify '-' as an option, * assume it means EOF. */ if (optopt == (int)'-') return (EOF); if (!*place) ++optind; if (opterr) { if (!(p = strrchr(*nargv, '/'))) p = *nargv; else ++p; (void)fprintf(stderr, "%s: illegal option -- %c\n", p, optopt); } return (BADCH); } if (*++oli != ':') { /* don't need argument */ myoptarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) /* no white space */ myoptarg = place; else if (nargc <= ++optind) { /* no arg */ place = EMSG; if (!(p = strrchr(*nargv, '/'))) p = *nargv; else ++p; if (opterr) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", p, optopt); return (BADCH); } else /* white space */ myoptarg = nargv[optind]; place = EMSG; ++optind; } return (optopt); /* dump back option letter */ } ================================================ FILE: apps/tiff2geotiff/tiff2geotiff.cpp ================================================ /* tiff2geotiff.c -- based on Sam Leffler's "tiffcp" and "geotifcp" codes */ /* * Original code had this copyright notice: * * Copyright (c) 1988-1995 Sam Leffler * Copyright (c) 1991-1995 Silicon Graphics, Inc. * * and a lot of legal stuff denying liability for anything. * This version modified (by A. Norton) to enable specifying a file of lon-lat extents * and timesteps that can be inserted to georeference and date the * separate directories in the output geotiff file. */ #include #include #include #include #include #include "vapor/VAssert.h" #define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H 1 /* GeoTIFF overrides */ #ifdef WIN32 #include "geotiff/geotiff.h" #include "geotiff/geo_normalize.h" #include "geotiff/geo_tiffp.h" #include "geotiff/geo_keyp.h" #include "geotiff/xtiffio.h" #include "geotiff/cpl_serv.h" #include "proj_api.h" #else #include "geotiff.h" #include "geo_normalize.h" #include "geo_tiffp.h" #include "geo_keyp.h" #include "xtiffio.h" #include "cpl_serv.h" #include "proj_api.h" #endif #ifdef WIN32 #include #pragma warning(disable : 4996) #endif #define TIFFOpen XTIFFOpen #define TIFFClose XTIFFClose #if defined(VMS) #define unlink delete #endif #define streq(a, b) (strcmp(a, b) == 0) #define strneq(a, b, n) (strncmp(a, b, n) == 0) #define TRUE 1 #define FALSE 0 int getopt(int nargc, char **nargv, const char *ostr); static int outtiled = -1; static uint32_t tilewidth; static uint32_t tilelength; static int convert_8_to_4 = 0; static uint16_t config; static uint16_t compression; static uint16_t predictor; static uint16_t fillorder; static uint32_t rowsperstrip; static uint32_t g3opts; static int ignore = FALSE; /* if true, ignore read errors */ static uint32_t defg3opts = (uint32_t)-1; static int quality = 75; /* JPEG quality */ static int jpegcolormode = JPEGCOLORMODE_RGB; static uint16_t defcompression = (uint16_t)-1; static uint16_t defpredictor = (uint16_t)-1; static const char *geofile = (char *)0; static const char *timeLonLatName = (char *)0; static const char *timeName = (char *)0; static FILE * timeLonLatFile = (FILE *)0; static FILE * timeFile = (FILE *)0; static float lonLatExts[4] = {999.f, 999.f, 999.f, 999.f}; static uint32_t currentImageWidth; static uint32_t currentImageHeight; static const char *proj4_string = (char *)0; static const char *p4string; static const char *worldfile = (char *)0; static int dirnum = 0; static void ApplyWorldFile(const char *worldfile, TIFF *out); static int tiffcp(TIFF *, TIFF *); static int processCompressOptions(const char *); static void usage(void); static int applyCorners(float cors[4], float relpos[4], TIFF *out); extern int GTIFSetFromProj4_WRF(GTIF *gtif, const char *proj4); int main(int argc, char *argv[]) { uint16_t defconfig = (uint16_t)-1; uint16_t deffillorder = 0; uint32_t deftilewidth = (uint32_t)-1; uint32_t deftilelength = (uint32_t)-1; uint32_t defrowsperstrip = (uint32_t)-1; uint32_t diroff = 0; TIFF * in; TIFF * out; const char * mode = "w"; int c; extern int optind; extern const char *myoptarg; while ((c = getopt(argc, argv, "c:f:l:m:M:n:o:p:r:w:e:g:4:aistd")) != -1) switch (c) { case 'a': /* append to output */ mode = "a"; break; case 'd': /* down cast 8bit to 4bit */ convert_8_to_4 = 1; break; case 'c': /* compression scheme */ if (!processCompressOptions(myoptarg)) usage(); break; case 'e': worldfile = myoptarg; break; case 'f': /* fill order */ if (streq(myoptarg, "lsb2msb")) deffillorder = FILLORDER_LSB2MSB; else if (streq(myoptarg, "msb2lsb")) deffillorder = FILLORDER_MSB2LSB; else usage(); break; case 'i': /* ignore errors */ ignore = TRUE; break; case 'g': /* GeoTIFF metadata file */ geofile = myoptarg; break; case 'm': /*multiple times and latlon extents file */ timeLonLatName = myoptarg; timeLonLatFile = fopen(timeLonLatName, "r"); if (!timeLonLatFile) { fprintf(stderr, "Failure to open %s\n", timeLonLatName); exit(-1); } break; case 'M': /*multiple timestamps file */ timeName = myoptarg; timeFile = fopen(timeName, "r"); if (!timeFile) { fprintf(stderr, "Failure to open %s\n", timeName); exit(-1); } break; case 'n': /* single latlong extents, requires option 4 */ { int retval = sscanf(myoptarg, "%f %f %f %f", lonLatExts, lonLatExts + 1, lonLatExts + 2, lonLatExts + 3); if (retval != 4) { fprintf(stderr, "Four lon/lat extent values required\n"); exit(-1); } } break; case '4': proj4_string = myoptarg; break; case 'l': /* tile length */ outtiled = TRUE; deftilelength = atoi(myoptarg); break; case 'o': /* initial directory offset */ diroff = strtoul(myoptarg, NULL, 0); break; case 'p': /* planar configuration */ if (streq(myoptarg, "separate")) defconfig = PLANARCONFIG_SEPARATE; else if (streq(myoptarg, "contig")) defconfig = PLANARCONFIG_CONTIG; else usage(); break; case 'r': /* rows/strip */ defrowsperstrip = atoi(myoptarg); break; case 's': /* generate stripped output */ outtiled = FALSE; break; case 't': /* generate tiled output */ outtiled = TRUE; break; case 'w': /* tile width */ outtiled = TRUE; deftilewidth = atoi(myoptarg); break; case '?': usage(); /*NOTREACHED*/ } if (argc - optind < 2) usage(); out = TIFFOpen(argv[argc - 1], mode); if (out == NULL) return (-2); for (; optind < argc - 1; optind++) { in = TIFFOpen(argv[optind], "r"); if (in == NULL) return (-3); if (diroff != 0 && !TIFFSetSubDirectory(in, diroff)) { TIFFError(TIFFFileName(in), "Error, setting subdirectory at %#x", diroff); (void)TIFFClose(out); return (1); } do { config = defconfig; compression = defcompression; predictor = defpredictor; fillorder = deffillorder; rowsperstrip = defrowsperstrip; tilewidth = deftilewidth; tilelength = deftilelength; g3opts = defg3opts; if (!tiffcp(in, out) || !TIFFWriteDirectory(out)) { (void)TIFFClose(out); return (1); } } while (TIFFReadDirectory(in)); (void)TIFFClose(in); } (void)TIFFClose(out); return (0); } static void ApplyWorldFile(const char *worldfilename, TIFF *out) { FILE * tfw; double pixsize[3], xoff, yoff, tiepoint[6], x_rot, y_rot; /* * Read the world file. Note we currently ignore rotational coefficients! */ tfw = fopen(worldfilename, "rt"); if (tfw == NULL) { perror(worldfilename); return; } int rt; rt = std::fscanf(tfw, "%lf", pixsize + 0); VAssert(rt > 0 && rt != EOF); rt = std::fscanf(tfw, "%lf", &y_rot); VAssert(rt > 0 && rt != EOF); rt = std::fscanf(tfw, "%lf", &x_rot); VAssert(rt > 0 && rt != EOF); rt = std::fscanf(tfw, "%lf", pixsize + 1); VAssert(rt > 0 && rt != EOF); rt = std::fscanf(tfw, "%lf", &xoff); VAssert(rt > 0 && rt != EOF); rt = std::fscanf(tfw, "%lf", &yoff); VAssert(rt > 0 && rt != EOF); fclose(tfw); /* * Write out pixel scale, and tiepoint information. */ if (x_rot == 0.0 && y_rot == 0.0) { pixsize[1] = ABS(pixsize[1]); pixsize[2] = 0.0; TIFFSetField(out, GTIFF_PIXELSCALE, 3, pixsize); tiepoint[0] = 0.5; tiepoint[1] = 0.5; tiepoint[2] = 0.0; tiepoint[3] = xoff; tiepoint[4] = yoff; tiepoint[5] = 0.0; TIFFSetField(out, GTIFF_TIEPOINTS, 6, tiepoint); } else { double adfMatrix[16]; memset(adfMatrix, 0, sizeof(double) * 16); adfMatrix[0] = pixsize[0]; adfMatrix[1] = x_rot; adfMatrix[3] = xoff - (pixsize[0] + x_rot) * 0.5; adfMatrix[4] = y_rot; adfMatrix[5] = pixsize[1]; adfMatrix[7] = yoff - (pixsize[1] + y_rot) * 0.5; adfMatrix[15] = 1.0; TIFFSetField(out, TIFFTAG_GEOTRANSMATRIX, 16, adfMatrix); } } static void InstallGeoTIFF(TIFF *out) { GTIF *gtif = (GTIF *)0; /* GeoKey-level descriptor */ FILE *fd; gtif = GTIFNew(out); if (!gtif) { printf("failed in GTIFNew\n"); return; } if (geofile) { /* Install keys and tags */ fd = fopen(geofile, "r"); if (fd == NULL) { perror(geofile); exit(-1); } if (!GTIFImport(gtif, 0, fd)) { fprintf(stderr, "Failure in GTIFImport\n"); exit(-1); } fclose(fd); } else if (proj4_string) { // Make sure ellps is in string: int pos; for (pos = 0; pos < (int)strlen(proj4_string) - 6; pos++) { if (strncmp(proj4_string + pos, "+ellps", 6) == 0) { pos = -1; break; } } p4string = proj4_string; if (pos >= 0) { char *newString = new char[strlen(proj4_string) + 15]; strcpy(newString, proj4_string); strcat(newString, " +ellps=sphere"); p4string = newString; } if (!GTIFSetFromProj4_WRF(gtif, p4string)) { fprintf(stderr, "Failure in GTIFSetFromProj4_WRF\n"); exit(-1); } if (timeLonLatFile) { // get next timestamp and latlon extents from timeLonLatFile float lonlat[4]; float relPos[4]; char timestamp[20]; // double modelPixelScale[3] = {0.,0.,0.}; // double tiePoint[6] = {0.,0.,0.,0.,0.,0.}; int rc = fscanf(timeLonLatFile, "%19s %f %f %f %f %f %f %f %f", timestamp, lonlat, lonlat + 1, lonlat + 2, lonlat + 3, relPos, relPos + 1, relPos + 2, relPos + 3); dirnum++; if (rc != 9) { fprintf(stderr, "Failed to read line %d of time-lon-lat file\n", dirnum); if (rc == 0) fprintf(stderr, "time-lon-lat file has fewer entries than images in tiff file\n"); exit(-3); } else { // convert the latlon and time and put into geotiff // insert time stamp from file TIFFSetField(out, TIFFTAG_DATETIME, timestamp); // Use proj4 to calculate the corner coordinates of the // image from the lonlat extents int rc = applyCorners(lonlat, relPos, out); if (rc) exit(rc); } } else if (lonLatExts[0] != 999.f) { // Use proj4 to calculate the corner coordinates of the // image from the lonlat extents float relpos[4] = {0.f, 0.f, 1.f, 1.f}; int rc = applyCorners(lonLatExts, relpos, out); if (rc) exit(rc); } } else if (timeFile) { // get next timestamp from timeFile char timestamp[20]; int rc = fscanf(timeFile, "%19s", timestamp); dirnum++; if (rc != 1) { fprintf(stderr, "Failed to read line %d of timestamp file\n", dirnum); if (rc == 0) fprintf(stderr, "timestamp file has fewer entries than images in tiff file\n"); exit(-3); } else { // put timestamp into tiff // insert time stamp from file TIFFSetField(out, TIFFTAG_DATETIME, timestamp); } } GTIFWriteKeys(gtif); GTIFFree(gtif); return; } // static int applyCorners(float lonlat[4], float relPos[4], TIFF *out) { void * p; double modelPixelScale[3] = {0., 0., 0.}; double tiePoint[6] = {0., 0., 0., 0., 0., 0.}; p = pj_init_plus(p4string); if (!p && !ignore) { // Invalid string. Get the error code: int *pjerrnum = pj_get_errno_ref(); fprintf(stderr, "Invalid Proj4 string %s; message:\n %s\n", p4string, pj_strerrno(*pjerrnum)); return -1; } if (p) { // reproject latlon to specified coord projection. // unless it's already a lat/lon projection double dbextents[4]; if (pj_is_latlong(static_cast(p))) { for (int j = 0; j < 4; j++) { dbextents[j] = lonlat[j]; } } else { // Must convert to radians: const double DEG2RAD = 3.141592653589793 / 180.; const char * latLongProjString = "+proj=latlong +ellps=sphere"; projPJ latlon_p = pj_init_plus(latLongProjString); // convert to radians... for (int j = 0; j < 4; j++) dbextents[j] = lonlat[j] * DEG2RAD; // convert the latlons to coordinates in the projection. double dummy[1] = {0.0}; int rc = pj_transform(latlon_p, static_cast(p), 2, 2, dbextents, dbextents + 1, dummy); if (rc && !ignore) { int *pjerrnum = pj_get_errno_ref(); fprintf(stderr, "Error converting lonlat to projection\n %s\n", pj_strerrno(*pjerrnum)); return (-1); } } // Now the extents in projection space must be scaled, to // allow for the corners being in the interior of the page. // If R0 and R1 are the relative positions of the plot corners // in the page, and X0 and X1 are the x-coords of the plot corners // then the page corners are at: // LOWER = (X0*R1 - X1*R0)/(R1-R0) // UPPER = LOWER + (X1-X0)/(R1-R0) // When dealing with x coordinates, // R0 and R1 are relPos[0] and [2] , X0 and X1 are dbextents[0] and [2] // similarly the y coordinates use the [1] and [3] indices double newDBExtents[4]; newDBExtents[0] = (dbextents[0] * relPos[2] - dbextents[2] * relPos[0]) / (relPos[2] - relPos[0]); newDBExtents[2] = newDBExtents[0] + (dbextents[2] - dbextents[0]) / (relPos[2] - relPos[0]); newDBExtents[1] = (dbextents[1] * relPos[3] - dbextents[3] * relPos[1]) / (relPos[3] - relPos[1]); newDBExtents[3] = newDBExtents[1] + (dbextents[3] - dbextents[1]) / (relPos[3] - relPos[1]); // calculate scale and model tie point modelPixelScale[0] = (newDBExtents[2] - newDBExtents[0]) / ((double)currentImageWidth - 1.); modelPixelScale[1] = (newDBExtents[3] - newDBExtents[1]) / ((double)currentImageHeight - 1.); tiePoint[3] = newDBExtents[0]; // Following is just dbextents[1] + dbextents[3]-dbextents[1] = dbextents[3]. // tiePoint[4] = dbextents[1] + ((double)currentImageHeight -1.)*modelPixelScale[1]; tiePoint[4] = newDBExtents[3]; TIFFSetField(out, GTIFF_TIEPOINTS, 6, tiePoint); TIFFSetField(out, GTIFF_PIXELSCALE, 3, modelPixelScale); } return 0; } static void CopyGeoTIFF(TIFF *in, TIFF *out) { GTIF * gtif = (GTIF *)0; /* GeoKey-level descriptor */ double *d_list = NULL; int16_t d_list_count; /* read definition from source file. */ gtif = GTIFNew(in); if (!gtif) return; if (TIFFGetField(in, GTIFF_TIEPOINTS, &d_list_count, &d_list)) TIFFSetField(out, GTIFF_TIEPOINTS, d_list_count, d_list); if (TIFFGetField(in, GTIFF_PIXELSCALE, &d_list_count, &d_list)) TIFFSetField(out, GTIFF_PIXELSCALE, d_list_count, d_list); if (TIFFGetField(in, GTIFF_TRANSMATRIX, &d_list_count, &d_list)) TIFFSetField(out, GTIFF_TRANSMATRIX, d_list_count, d_list); /* Here we violate the GTIF abstraction to retarget on another file. We should just have a function for copying tags from one GTIF object to another. */ gtif->gt_tif = out; gtif->gt_flags |= FLAG_FILE_MODIFIED; /* Install keys and tags */ GTIFWriteKeys(gtif); GTIFFree(gtif); return; } static void processG3Options(const char *cp) { if ((cp = strchr(cp, ':')) != NULL) { if (defg3opts == (uint32_t)-1) defg3opts = 0; do { cp++; if (strneq(cp, "1d", 2)) defg3opts &= ~GROUP3OPT_2DENCODING; else if (strneq(cp, "2d", 2)) defg3opts |= GROUP3OPT_2DENCODING; else if (strneq(cp, "fill", 4)) defg3opts |= GROUP3OPT_FILLBITS; else usage(); } while ((cp = strchr(cp, ':')) != NULL); } } static int processCompressOptions(const char *opt) { if (streq(opt, "none")) defcompression = COMPRESSION_NONE; else if (streq(opt, "packbits")) defcompression = COMPRESSION_PACKBITS; else if (strneq(opt, "jpeg", 4)) { const char *cp = strchr(opt, ':'); if (cp && isdigit(cp[1])) quality = atoi(cp + 1); if (cp && strchr(cp, 'r')) jpegcolormode = JPEGCOLORMODE_RAW; defcompression = COMPRESSION_JPEG; } else if (strneq(opt, "g3", 2)) { processG3Options(opt); defcompression = COMPRESSION_CCITTFAX3; } else if (streq(opt, "g4")) defcompression = COMPRESSION_CCITTFAX4; else if (strneq(opt, "lzw", 3)) { const char *cp = strchr(opt, ':'); if (cp) defpredictor = atoi(cp + 1); defcompression = COMPRESSION_LZW; } else if (strneq(opt, "zip", 3)) { const char *cp = strchr(opt, ':'); if (cp) defpredictor = atoi(cp + 1); defcompression = COMPRESSION_DEFLATE; } else return (0); return (1); } const char *stuff[] = {"usage: tiff2geotiff [options] input... output", "where options are:", " -g file install GeoTIFF metadata from ", " -4 proj4_str install GeoTIFF metadata from proj4 string", " -e file install positioning info from ESRI Worldfile ", " -a append to output instead of overwriting", " -m file Specify filename with multiple timestamps and image placement info:", " Each line of file has date/timestamp, and 8 floats;", " first four are lon/lat corners of plot area,", " second four are relative positions of plot corners in page.", " This option requires option -4", " -M file Specify filename with multiple timestamps, w/o georeferencing:", " Each line of file has date/timestamp only", " Option -4 must not be specified.", " -n llx lly urx ury", " Install longitude/latitude extents;", " Four lon and lat values must in quotes in the order:", " lower-left longitude, lower-left latitude,", " upper-right longitute, upper-right latitude", " This option requires option -4", " Option '-m' overrides this option", " -o offset set initial directory offset", " -p contig pack samples contiguously (e.g. RGBRGB...)", " -p separate store samples separately (e.g. RRR...GGG...BBB...)", " -s write output in strips", " -t write output in tiles", " -i ignore read errors", " -d truncate 8 bitspersample to 4bitspersample", "", " -r # make each strip have no more than # rows", " -w # set output tile width (pixels)", " -l # set output tile length (pixels)", "", " -f lsb2msb force lsb-to-msb FillOrder for output", " -f msb2lsb force msb-to-lsb FillOrder for output", "", " -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding", " -c zip[:opts] compress output with deflate encoding", " -c jpeg[:opts]compress output with JPEG encoding", " -c packbits compress output with packbits encoding", " -c g3[:opts] compress output with CCITT Group 3 encoding", " -c g4 compress output with CCITT Group 4 encoding", " -c none use no compression algorithm on output", "", "Group 3 options:", " 1d use default CCITT Group 3 1D-encoding", " 2d use optional CCITT Group 3 2D-encoding", " fill byte-align EOL codes", "For example, -c g3:2d:fill to get G3-2D-encoded data with byte-aligned EOLs", "", "JPEG options:", " # set compression quality level (0-100, default 75)", " r output color image as RGB rather than YCbCr", "For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality", "", "LZW and deflate options:", " # set predictor value", "For example, -c lzw:2 to get LZW-encoded data with horizontal differencing", NULL}; static void usage(void) { char buf[BUFSIZ]; int i; setbuf(stderr, buf); for (i = 0; stuff[i] != NULL; i++) fprintf(stderr, "%s\n", stuff[i]); exit(-1); } static void CheckAndCorrectColormap(TIFF *tif, int n, uint16_t *r, uint16_t *g, uint16_t *b) { int i; for (i = 0; i < n; i++) if (r[i] >= 256 || g[i] >= 256 || b[i] >= 256) return; TIFFWarning(TIFFFileName(tif), "Scaling 8-bit colormap"); #define CVT(x) (((x) * ((1L << 16) - 1)) / 255) for (i = 0; i < n; i++) { r[i] = CVT(r[i]); g[i] = CVT(g[i]); b[i] = CVT(b[i]); } #undef CVT } #define CopyField(tag, v) \ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v) #define CopyField2(tag, v1, v2) \ if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2) #define CopyField3(tag, v1, v2, v3) \ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3) #define CopyField4(tag, v1, v2, v3, v4) \ if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4) static struct cpTag { uint16_t tag; uint16_t count; TIFFDataType type; } tags[] = { {TIFFTAG_SUBFILETYPE, 1, TIFF_LONG}, {TIFFTAG_THRESHHOLDING, 1, TIFF_SHORT}, {TIFFTAG_DOCUMENTNAME, 1, TIFF_ASCII}, {TIFFTAG_IMAGEDESCRIPTION, 1, TIFF_ASCII}, {TIFFTAG_MAKE, 1, TIFF_ASCII}, {TIFFTAG_MODEL, 1, TIFF_ASCII}, {TIFFTAG_ORIENTATION, 1, TIFF_SHORT}, {TIFFTAG_MINSAMPLEVALUE, 1, TIFF_SHORT}, {TIFFTAG_MAXSAMPLEVALUE, 1, TIFF_SHORT}, {TIFFTAG_XRESOLUTION, 1, TIFF_RATIONAL}, {TIFFTAG_YRESOLUTION, 1, TIFF_RATIONAL}, {TIFFTAG_PAGENAME, 1, TIFF_ASCII}, {TIFFTAG_XPOSITION, 1, TIFF_RATIONAL}, {TIFFTAG_YPOSITION, 1, TIFF_RATIONAL}, {TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG}, {TIFFTAG_RESOLUTIONUNIT, 1, TIFF_SHORT}, {TIFFTAG_PAGENUMBER, 2, TIFF_SHORT}, {TIFFTAG_SOFTWARE, 1, TIFF_ASCII}, {TIFFTAG_DATETIME, 1, TIFF_ASCII}, {TIFFTAG_ARTIST, 1, TIFF_ASCII}, {TIFFTAG_HOSTCOMPUTER, 1, TIFF_ASCII}, {TIFFTAG_WHITEPOINT, 1, TIFF_RATIONAL}, {TIFFTAG_PRIMARYCHROMATICITIES, (uint16_t)-1, TIFF_RATIONAL}, {TIFFTAG_HALFTONEHINTS, 2, TIFF_SHORT}, {TIFFTAG_BADFAXLINES, 1, TIFF_LONG}, {TIFFTAG_CLEANFAXDATA, 1, TIFF_SHORT}, {TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG}, {TIFFTAG_INKSET, 1, TIFF_SHORT}, {TIFFTAG_INKNAMES, 1, TIFF_ASCII}, {TIFFTAG_DOTRANGE, 2, TIFF_SHORT}, {TIFFTAG_TARGETPRINTER, 1, TIFF_ASCII}, {TIFFTAG_SAMPLEFORMAT, 1, TIFF_SHORT}, {TIFFTAG_YCBCRCOEFFICIENTS, (uint16_t)-1, TIFF_RATIONAL}, {TIFFTAG_YCBCRSUBSAMPLING, 2, TIFF_SHORT}, {TIFFTAG_YCBCRPOSITIONING, 1, TIFF_SHORT}, {TIFFTAG_REFERENCEBLACKWHITE, (uint16_t)-1, TIFF_RATIONAL}, {TIFFTAG_EXTRASAMPLES, (uint16_t)-1, TIFF_SHORT}, {TIFFTAG_SMINSAMPLEVALUE, 1, TIFF_DOUBLE}, {TIFFTAG_SMAXSAMPLEVALUE, 1, TIFF_DOUBLE}, }; #define NTAGS (sizeof(tags) / sizeof(tags[0])) static void cpOtherTags(TIFF *in, TIFF *out) { struct cpTag *p = tags; for (int i = 0; i < NTAGS; i++, p++) { switch (p->type) { case TIFF_SHORT: if (p->count == 1) { uint16_t shortv; CopyField(p->tag, shortv); } else if (p->count == 2) { uint16_t shortv1, shortv2; CopyField2(p->tag, shortv1, shortv2); } else if (p->count == (uint16_t)-1) { uint16_t shortv1; uint16_t *shortav; CopyField2(p->tag, shortv1, shortav); } break; case TIFF_LONG: { uint32_t longv; CopyField(p->tag, longv); } break; case TIFF_RATIONAL: if (p->count == 1) { float floatv; // CopyField(tag, v) replaced by following // Workaround a tiff lib bug: TIFFGetField gets a very small float if (TIFFGetField(in, p->tag, &floatv) && floatv >= .00001) TIFFSetField(out, p->tag, floatv); } else if (p->count == (uint16_t)-1) { float *floatav; CopyField(p->tag, floatav); } break; case TIFF_ASCII: { char *stringv; CopyField(p->tag, stringv); } break; case TIFF_DOUBLE: if (p->count == 1) { double doublev; CopyField(p->tag, doublev); } else if (p->count == (uint16_t)-1) { double *doubleav; CopyField(p->tag, doubleav); } break; default: break; } } } typedef int (*copyFunc)(TIFF *in, TIFF *out, uint32_t l, uint32_t w, uint16_t samplesperpixel); static copyFunc pickCopyFunc(TIFF *, TIFF *, uint16_t, uint16_t); static int tiffcp(TIFF *in, TIFF *out) { uint16_t samplesperpixel, shortv; uint16_t bitspersample = 0; copyFunc cf; uint32_t w, l; CopyField(TIFFTAG_IMAGEWIDTH, w); CopyField(TIFFTAG_IMAGELENGTH, l); currentImageWidth = w; currentImageHeight = l; if (convert_8_to_4) { TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 4); } else { CopyField(TIFFTAG_BITSPERSAMPLE, bitspersample); } if (compression != (uint16_t)-1) TIFFSetField(out, TIFFTAG_COMPRESSION, compression); else CopyField(TIFFTAG_COMPRESSION, compression); if (compression == COMPRESSION_JPEG && jpegcolormode == JPEGCOLORMODE_RGB) TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR); else CopyField(TIFFTAG_PHOTOMETRIC, shortv); if (fillorder != 0) TIFFSetField(out, TIFFTAG_FILLORDER, fillorder); else CopyField(TIFFTAG_FILLORDER, shortv); CopyField(TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); /* * Choose tiles/strip for the output image according to * the command line arguments (-tiles, -strips) and the * structure of the input image. */ if (outtiled == -1) outtiled = TIFFIsTiled(in); if (outtiled) { /* * Setup output file's tile width&height. If either * is not specified, use either the value from the * input image or, if nothing is defined, use the * library default. */ if (tilewidth == (uint32_t)-1) TIFFGetField(in, TIFFTAG_TILEWIDTH, &tilewidth); if (tilelength == (uint32_t)-1) TIFFGetField(in, TIFFTAG_TILELENGTH, &tilelength); TIFFDefaultTileSize(out, &tilewidth, &tilelength); TIFFSetField(out, TIFFTAG_TILEWIDTH, tilewidth); TIFFSetField(out, TIFFTAG_TILELENGTH, tilelength); } else { /* * RowsPerStrip is left unspecified: use either the * value from the input image or, if nothing is defined, * use the library default. */ if (rowsperstrip == (uint32_t)-1) TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip); TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip); } if (config != (uint16_t)-1) TIFFSetField(out, TIFFTAG_PLANARCONFIG, config); else CopyField(TIFFTAG_PLANARCONFIG, config); if (g3opts != (uint32_t)-1) TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, g3opts); else CopyField(TIFFTAG_GROUP3OPTIONS, g3opts); if (samplesperpixel <= 4) { uint16_t *tr, *tg, *tb, *ta; CopyField4(TIFFTAG_TRANSFERFUNCTION, tr, tg, tb, ta); } { uint16_t *red, *green, *blue; if (TIFFGetField(in, TIFFTAG_COLORMAP, &red, &green, &blue)) { CheckAndCorrectColormap(in, 1 << bitspersample, red, green, blue); TIFFSetField(out, TIFFTAG_COLORMAP, red, green, blue); } } /* SMinSampleValue & SMaxSampleValue */ switch (compression) { case COMPRESSION_JPEG: TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality); TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode); break; case COMPRESSION_LZW: case COMPRESSION_DEFLATE: if (predictor != (uint16_t)-1) TIFFSetField(out, TIFFTAG_PREDICTOR, predictor); else CopyField(TIFFTAG_PREDICTOR, predictor); break; } cpOtherTags(in, out); if (geofile || proj4_string || timeFile) InstallGeoTIFF(out); else CopyGeoTIFF(in, out); if (worldfile) ApplyWorldFile(worldfile, out); cf = pickCopyFunc(in, out, bitspersample, samplesperpixel); return (cf ? (*cf)(in, out, l, w, samplesperpixel) : FALSE); } /* * Copy Functions. */ #define DECLAREcpFunc(x) static int x(TIFF *in, TIFF *out, uint32_t imagelength, uint32_t imagewidth, tsample_t spp) #define DECLAREreadFunc(x) static void x(TIFF *in, unsigned char *buf, uint32_t imagelength, uint32_t imagewidth, tsample_t spp) typedef void (*readFunc)(TIFF *, unsigned char *, uint32_t, uint32_t, tsample_t); #define DECLAREwriteFunc(x) static int x(TIFF *out, unsigned char *buf, uint32_t imagelength, uint32_t imagewidth, tsample_t spp) typedef int (*writeFunc)(TIFF *, unsigned char *, uint32_t, uint32_t, tsample_t); /* * Contig -> contig by scanline for rows/strip change. */ DECLAREcpFunc(cpContig2ContigByRow) { unsigned char *buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in)); uint32_t row; (void)imagewidth; (void)spp; for (row = 0; row < imagelength; row++) { if (TIFFReadScanline(in, buf, row, 0) < 0 && !ignore) goto done; if (TIFFWriteScanline(out, buf, row, 0) < 0) goto bad; } done: _TIFFfree(buf); return (TRUE); bad: _TIFFfree(buf); return (FALSE); } /* * Contig -> contig by scanline for rows/strip change. */ DECLAREcpFunc(cpContig2ContigByRow_8_to_4) { unsigned char *buf_in = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in)); unsigned char *buf_out = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out)); uint32_t row; printf("Downsample\n"); (void)imagewidth; (void)spp; for (row = 0; row < imagelength; row++) { int i_in, i_out_byte; if (TIFFReadScanline(in, buf_in, row, 0) < 0 && !ignore) goto done; for (i_in = 0, i_out_byte = 0; i_in < (int)imagewidth; i_in += 2, i_out_byte++) { buf_out[i_out_byte] = (buf_in[i_in] & 0xf) * 16 + (buf_in[i_in + 1] & 0xf); } if (TIFFWriteScanline(out, buf_out, row, 0) < 0) goto bad; } done: _TIFFfree(buf_in); _TIFFfree(buf_out); return (TRUE); bad: _TIFFfree(buf_in); _TIFFfree(buf_out); return (FALSE); } /* * Strip -> strip for change in encoding. */ DECLAREcpFunc(cpDecodedStrips) { tsize_t stripsize = TIFFStripSize(in); unsigned char *buf = (unsigned char *)_TIFFmalloc(stripsize); (void)imagewidth; (void)spp; if (buf) { tstrip_t s, ns = TIFFNumberOfStrips(in); uint32_t row = 0; for (s = 0; s < ns; s++) { tsize_t cc = (row + rowsperstrip > imagelength) ? TIFFVStripSize(in, imagelength - row) : stripsize; if (TIFFReadEncodedStrip(in, s, buf, cc) < 0 && !ignore) break; if (TIFFWriteEncodedStrip(out, s, buf, cc) < 0) { _TIFFfree(buf); return (FALSE); } row += rowsperstrip; } _TIFFfree(buf); return (TRUE); } return (FALSE); } /* * Separate -> separate by row for rows/strip change. */ DECLAREcpFunc(cpSeparate2SeparateByRow) { unsigned char *buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in)); uint32_t row; tsample_t s; (void)imagewidth; for (s = 0; s < spp; s++) { for (row = 0; row < imagelength; row++) { if (TIFFReadScanline(in, buf, row, s) < 0 && !ignore) goto done; if (TIFFWriteScanline(out, buf, row, s) < 0) goto bad; } } done: _TIFFfree(buf); return (TRUE); bad: _TIFFfree(buf); return (FALSE); } /* * Contig -> separate by row. */ DECLAREcpFunc(cpContig2SeparateByRow) { unsigned char *inbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in)); unsigned char *outbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out)); unsigned char *inp, *outp; uint32_t n; uint32_t row; tsample_t s; /* unpack channels */ for (s = 0; s < spp; s++) { for (row = 0; row < imagelength; row++) { if (TIFFReadScanline(in, inbuf, row, 0) < 0 && !ignore) goto done; inp = inbuf + s; outp = outbuf; for (n = imagewidth; n-- > 0;) { *outp++ = *inp; inp += spp; } if (TIFFWriteScanline(out, outbuf, row, s) < 0) goto bad; } } done: if (inbuf) _TIFFfree(inbuf); if (outbuf) _TIFFfree(outbuf); return (TRUE); bad: if (inbuf) _TIFFfree(inbuf); if (outbuf) _TIFFfree(outbuf); return (FALSE); } /* * Separate -> contig by row. */ DECLAREcpFunc(cpSeparate2ContigByRow) { unsigned char *inbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in)); unsigned char *outbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out)); unsigned char *inp, *outp; uint32_t n; uint32_t row; tsample_t s; for (row = 0; row < imagelength; row++) { /* merge channels */ for (s = 0; s < spp; s++) { if (TIFFReadScanline(in, inbuf, row, s) < 0 && !ignore) goto done; inp = inbuf; outp = outbuf + s; for (n = imagewidth; n-- > 0;) { *outp = *inp++; outp += spp; } } if (TIFFWriteScanline(out, outbuf, row, 0) < 0) goto bad; } done: if (inbuf) _TIFFfree(inbuf); if (outbuf) _TIFFfree(outbuf); return (TRUE); bad: if (inbuf) _TIFFfree(inbuf); if (outbuf) _TIFFfree(outbuf); return (FALSE); } static void cpStripToTile(unsigned char *out, unsigned char *in, uint32_t rows, uint32_t cols, int outskew, int inskew) { while (rows-- > 0) { uint32_t j = cols; while (j-- > 0) *out++ = *in++; out += outskew; in += inskew; } } static void cpContigBufToSeparateBuf(unsigned char *out, unsigned char *in, uint32_t rows, uint32_t cols, int outskew, int inskew, tsample_t spp) { while (rows-- > 0) { uint32_t j = cols; while (j-- > 0) *out++ = *in, in += spp; out += outskew; in += inskew; } } static void cpSeparateBufToContigBuf(unsigned char *out, unsigned char *in, uint32_t rows, uint32_t cols, int outskew, int inskew, tsample_t spp) { while (rows-- > 0) { uint32_t j = cols; while (j-- > 0) *out = *in++, out += spp; out += outskew; in += inskew; } } static int cpImage(TIFF *in, TIFF *out, readFunc fin, writeFunc fout, uint32_t imagelength, uint32_t imagewidth, tsample_t spp) { int status = FALSE; unsigned char *buf = (unsigned char *)_TIFFmalloc(TIFFRasterScanlineSize(in) * imagelength); if (buf) { (*fin)(in, buf, imagelength, imagewidth, spp); status = (fout)(out, buf, imagelength, imagewidth, spp); _TIFFfree(buf); } return (status); } DECLAREreadFunc(readContigStripsIntoBuffer) { tsize_t scanlinesize = TIFFScanlineSize(in); unsigned char *bufp = buf; uint32_t row; (void)imagewidth; (void)spp; for (row = 0; row < imagelength; row++) { if (TIFFReadScanline(in, bufp, row, 0) < 0 && !ignore) break; bufp += scanlinesize; } } DECLAREreadFunc(readSeparateStripsIntoBuffer) { tsize_t scanlinesize = TIFFScanlineSize(in); unsigned char *scanline = (unsigned char *)_TIFFmalloc(scanlinesize); (void)imagewidth; if (scanline) { unsigned char *bufp = buf; uint32_t row; tsample_t s; for (row = 0; row < imagelength; row++) { /* merge channels */ for (s = 0; s < spp; s++) { unsigned char *sp = scanline; unsigned char *bp = bufp + s; tsize_t n = scanlinesize; if (TIFFReadScanline(in, sp, row, s) < 0 && !ignore) goto done; while (n-- > 0) *bp = *bufp++, bp += spp; } bufp += scanlinesize; } done: _TIFFfree(scanline); } } DECLAREreadFunc(readContigTilesIntoBuffer) { unsigned char *tilebuf = (unsigned char *)_TIFFmalloc(TIFFTileSize(in)); uint32_t imagew = TIFFScanlineSize(in); uint32_t tilew = TIFFTileRowSize(in); int iskew = imagew - tilew; unsigned char *bufp = buf; uint32_t tw, tl; uint32_t row; (void)spp; if (tilebuf == 0) return; (void)TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw); (void)TIFFGetField(in, TIFFTAG_TILELENGTH, &tl); for (row = 0; row < imagelength; row += tl) { uint32_t nrow = (row + tl > imagelength) ? imagelength - row : tl; uint32_t colb = 0; uint32_t col; for (col = 0; col < imagewidth; col += tw) { if (TIFFReadTile(in, tilebuf, col, row, 0, 0) < 0 && !ignore) goto done; if (colb + tilew > imagew) { uint32_t width = imagew - colb; uint32_t oskew = tilew - width; cpStripToTile(bufp + colb, tilebuf, nrow, width, oskew + iskew, oskew); } else cpStripToTile(bufp + colb, tilebuf, nrow, tilew, iskew, 0); colb += tilew; } bufp += imagew * nrow; } done: _TIFFfree(tilebuf); } DECLAREreadFunc(readSeparateTilesIntoBuffer) { uint32_t imagew = TIFFScanlineSize(in); uint32_t tilew = TIFFTileRowSize(in); int iskew = imagew - tilew; unsigned char *tilebuf = (unsigned char *)_TIFFmalloc(TIFFTileSize(in)); unsigned char *bufp = buf; uint32_t tw, tl; uint32_t row; if (tilebuf == 0) return; (void)TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw); (void)TIFFGetField(in, TIFFTAG_TILELENGTH, &tl); for (row = 0; row < imagelength; row += tl) { uint32_t nrow = (row + tl > imagelength) ? imagelength - row : tl; uint32_t colb = 0; uint32_t col; for (col = 0; col < imagewidth; col += tw) { tsample_t s; for (s = 0; s < spp; s++) { if (TIFFReadTile(in, tilebuf, col, row, 0, s) < 0 && !ignore) goto done; /* * Tile is clipped horizontally. Calculate * visible portion and skewing factors. */ if (colb + tilew > imagew) { uint32_t width = imagew - colb; int oskew = tilew - width; cpSeparateBufToContigBuf(bufp + colb + s, tilebuf, nrow, width, oskew + iskew, oskew, spp); } else cpSeparateBufToContigBuf(bufp + colb + s, tilebuf, nrow, tw, iskew, 0, spp); } colb += tilew; } bufp += imagew * nrow; } done: _TIFFfree(tilebuf); } DECLAREwriteFunc(writeBufferToContigStrips) { tsize_t scanline = TIFFScanlineSize(out); uint32_t row; (void)imagewidth; (void)spp; for (row = 0; row < imagelength; row++) { if (TIFFWriteScanline(out, buf, row, 0) < 0) return (FALSE); buf += scanline; } return (TRUE); } DECLAREwriteFunc(writeBufferToSeparateStrips) { unsigned char *obuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out)); tsample_t s; if (obuf == NULL) return (0); for (s = 0; s < spp; s++) { uint32_t row; for (row = 0; row < imagelength; row++) { unsigned char *inp = buf + s; unsigned char *outp = obuf; uint32_t n = imagewidth; while (n-- > 0) *outp++ = *inp, inp += spp; if (TIFFWriteScanline(out, obuf, row, s) < 0) { _TIFFfree(obuf); return (FALSE); } } } _TIFFfree(obuf); return (TRUE); } DECLAREwriteFunc(writeBufferToContigTiles) { uint32_t imagew = TIFFScanlineSize(out); uint32_t tilew = TIFFTileRowSize(out); int iskew = imagew - tilew; unsigned char *obuf = (unsigned char *)_TIFFmalloc(TIFFTileSize(out)); unsigned char *bufp = buf; uint32_t tl, tw; uint32_t row; (void)spp; if (obuf == NULL) return (FALSE); (void)TIFFGetField(out, TIFFTAG_TILELENGTH, &tl); (void)TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw); for (row = 0; row < imagelength; row += tilelength) { uint32_t nrow = (row + tl > imagelength) ? imagelength - row : tl; uint32_t colb = 0; uint32_t col; for (col = 0; col < imagewidth; col += tw) { /* * Tile is clipped horizontally. Calculate * visible portion and skewing factors. */ if (colb + tilew > imagew) { uint32_t width = imagew - colb; int oskew = tilew - width; cpStripToTile(obuf, bufp + colb, nrow, width, oskew, oskew + iskew); } else cpStripToTile(obuf, bufp + colb, nrow, tilew, 0, iskew); if (TIFFWriteTile(out, obuf, col, row, 0, 0) < 0) { _TIFFfree(obuf); return (FALSE); } colb += tilew; } bufp += nrow * imagew; } _TIFFfree(obuf); return (TRUE); } DECLAREwriteFunc(writeBufferToSeparateTiles) { uint32_t imagew = TIFFScanlineSize(out); tsize_t tilew = TIFFTileRowSize(out); int iskew = imagew - tilew; unsigned char *obuf = (unsigned char *)_TIFFmalloc(TIFFTileSize(out)); unsigned char *bufp = buf; uint32_t tl, tw; uint32_t row; if (obuf == NULL) return (FALSE); (void)TIFFGetField(out, TIFFTAG_TILELENGTH, &tl); (void)TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw); for (row = 0; row < imagelength; row += tl) { uint32_t nrow = (row + tl > imagelength) ? imagelength - row : tl; uint32_t colb = 0; uint32_t col; for (col = 0; col < imagewidth; col += tw) { tsample_t s; for (s = 0; s < spp; s++) { /* * Tile is clipped horizontally. Calculate * visible portion and skewing factors. */ if (colb + tilew > imagew) { uint32_t width = imagew - colb; int oskew = tilew - width; cpContigBufToSeparateBuf(obuf, bufp + colb + s, nrow, width, oskew / spp, oskew + imagew, spp); } else cpContigBufToSeparateBuf(obuf, bufp + colb + s, nrow, tilewidth, 0, iskew, spp); if (TIFFWriteTile(out, obuf, col, row, 0, s) < 0) { _TIFFfree(obuf); return (FALSE); } } colb += tilew; } bufp += nrow * imagew; } _TIFFfree(obuf); return (TRUE); } /* * Contig strips -> contig tiles. */ DECLAREcpFunc(cpContigStrips2ContigTiles) { return cpImage(in, out, readContigStripsIntoBuffer, writeBufferToContigTiles, imagelength, imagewidth, spp); } /* * Contig strips -> separate tiles. */ DECLAREcpFunc(cpContigStrips2SeparateTiles) { return cpImage(in, out, readContigStripsIntoBuffer, writeBufferToSeparateTiles, imagelength, imagewidth, spp); } /* * Separate strips -> contig tiles. */ DECLAREcpFunc(cpSeparateStrips2ContigTiles) { return cpImage(in, out, readSeparateStripsIntoBuffer, writeBufferToContigTiles, imagelength, imagewidth, spp); } /* * Separate strips -> separate tiles. */ DECLAREcpFunc(cpSeparateStrips2SeparateTiles) { return cpImage(in, out, readSeparateStripsIntoBuffer, writeBufferToSeparateTiles, imagelength, imagewidth, spp); } /* * Contig strips -> contig tiles. */ DECLAREcpFunc(cpContigTiles2ContigTiles) { return cpImage(in, out, readContigTilesIntoBuffer, writeBufferToContigTiles, imagelength, imagewidth, spp); } /* * Contig tiles -> separate tiles. */ DECLAREcpFunc(cpContigTiles2SeparateTiles) { return cpImage(in, out, readContigTilesIntoBuffer, writeBufferToSeparateTiles, imagelength, imagewidth, spp); } /* * Separate tiles -> contig tiles. */ DECLAREcpFunc(cpSeparateTiles2ContigTiles) { return cpImage(in, out, readSeparateTilesIntoBuffer, writeBufferToContigTiles, imagelength, imagewidth, spp); } /* * Separate tiles -> separate tiles (tile dimension change). */ DECLAREcpFunc(cpSeparateTiles2SeparateTiles) { return cpImage(in, out, readSeparateTilesIntoBuffer, writeBufferToSeparateTiles, imagelength, imagewidth, spp); } /* * Contig tiles -> contig tiles (tile dimension change). */ DECLAREcpFunc(cpContigTiles2ContigStrips) { return cpImage(in, out, readContigTilesIntoBuffer, writeBufferToContigStrips, imagelength, imagewidth, spp); } /* * Contig tiles -> separate strips. */ DECLAREcpFunc(cpContigTiles2SeparateStrips) { return cpImage(in, out, readContigTilesIntoBuffer, writeBufferToSeparateStrips, imagelength, imagewidth, spp); } /* * Separate tiles -> contig strips. */ DECLAREcpFunc(cpSeparateTiles2ContigStrips) { return cpImage(in, out, readSeparateTilesIntoBuffer, writeBufferToContigStrips, imagelength, imagewidth, spp); } /* * Separate tiles -> separate strips. */ DECLAREcpFunc(cpSeparateTiles2SeparateStrips) { return cpImage(in, out, readSeparateTilesIntoBuffer, writeBufferToSeparateStrips, imagelength, imagewidth, spp); } /* * Select the appropriate copy function to use. */ static copyFunc pickCopyFunc(TIFF *in, TIFF *out, uint16_t bitspersample, uint16_t samplesperpixel) { uint16_t shortv; uint32_t w, l, tw, tl; int bychunk; (void)TIFFGetField(in, TIFFTAG_PLANARCONFIG, &shortv); if (shortv != config && bitspersample != 8 && samplesperpixel > 1) { fprintf(stderr, "%s: Can not handle different planar configuration w/ bits/sample != 8\n", TIFFFileName(in)); return (NULL); } TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(in, TIFFTAG_IMAGELENGTH, &l); if (TIFFIsTiled(out)) { if (!TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw)) tw = w; if (!TIFFGetField(in, TIFFTAG_TILELENGTH, &tl)) tl = l; bychunk = (tw == tilewidth && tl == tilelength); } else if (TIFFIsTiled(in)) { TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(in, TIFFTAG_TILELENGTH, &tl); bychunk = (tw == w && tl == rowsperstrip); } else { uint32_t irps = (uint32_t)-1L; TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &irps); bychunk = (rowsperstrip == irps); } #define T 1 #define F 0 #define pack(a, b, c, d, e) ((long)(((a) << 11) | ((b) << 3) | ((c) << 2) | ((d) << 1) | (e))) switch (pack(shortv, config, TIFFIsTiled(in), TIFFIsTiled(out), bychunk)) { /* Strips -> Tiles */ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F, T, F): case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F, T, T): return cpContigStrips2ContigTiles; case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F, T, F): case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F, T, T): return cpContigStrips2SeparateTiles; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F, T, F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F, T, T): return cpSeparateStrips2ContigTiles; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F, T, F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F, T, T): return cpSeparateStrips2SeparateTiles; /* Tiles -> Tiles */ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T, T, F): case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T, T, T): return cpContigTiles2ContigTiles; case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T, T, F): case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T, T, T): return cpContigTiles2SeparateTiles; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T, T, F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T, T, T): return cpSeparateTiles2ContigTiles; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T, T, F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T, T, T): return cpSeparateTiles2SeparateTiles; /* Tiles -> Strips */ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T, F, F): case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T, F, T): return cpContigTiles2ContigStrips; case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T, F, F): case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T, F, T): return cpContigTiles2SeparateStrips; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T, F, F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T, F, T): return cpSeparateTiles2ContigStrips; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T, F, F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T, F, T): return cpSeparateTiles2SeparateStrips; /* Strips -> Strips */ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F, F, F): if (convert_8_to_4) return cpContig2ContigByRow_8_to_4; else return cpContig2ContigByRow; case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F, F, T): if (convert_8_to_4) return cpContig2ContigByRow_8_to_4; else return cpDecodedStrips; case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F, F, F): case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F, F, T): return cpContig2SeparateByRow; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F, F, F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F, F, T): return cpSeparate2ContigByRow; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F, F, F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F, F, T): return cpSeparate2SeparateByRow; } #undef pack #undef F #undef T fprintf(stderr, "tiffcp: %s: Don't know how to copy/convert image.\n", TIFFFileName(in)); return (NULL); } ================================================ FILE: apps/vapor_check_udunits/CMakeLists.txt ================================================ add_executable (vapor_check_udunits vapor_check_udunits.cpp) target_link_libraries (vapor_check_udunits common vdc) OpenMPInstall ( TARGETS vapor_check_udunits DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/vapor_check_udunits/vapor_check_udunits.cpp ================================================ #include #include #include #include #include using namespace Wasp; using namespace VAPoR; struct opt_t { OptionParser::Boolean_T quiet; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"quiet", 0, "", "Don't print anything, just exit with status"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; string ProgName; int main(int argc, char **argv) { OptionParser op; MyBase::SetErrMsgFilePtr(stderr); // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { return 1; } if (op.ParseOptions(&argc, argv, get_options) < 0) { return 1; } if (argc != 1 || opt.help) { cerr << "Usage: " << ProgName << endl; op.PrintOptionHelp(stderr, 80, false); return 1; } string path = UDUnits::GetDatabasePath(); if (!opt.quiet && !path.empty()) printf("VAPOR UDUnits database path: \"%s\"\n", path.c_str()); UDUnits ud; int rc = ud.Initialize(); if (rc < 0) return 1; if (!opt.quiet) { printf("UDUnits passed\n"); } return 0; } ================================================ FILE: apps/vaporgui/.gitignore ================================================ vaporgui_autogen ================================================ FILE: apps/vaporgui/AbstractWidgetGroup.cpp ================================================ #include "AbstractWidgetGroup.h" ================================================ FILE: apps/vaporgui/AbstractWidgetGroup.h ================================================ #pragma once #include #include //! \class AbstractWidgetGroup //! \brief Provides an interface that standardizes widget grouping classes //! \author Stas Jaroszynski template class AbstractWidgetGroup { protected: std::vector _children; public: typedef std::initializer_list List; //! Adds a widget. virtual This *Add(Widget *w) { _children.push_back(w); return (This *)this; } //! Adds multiple widgets. //! Has a different name for compiler reasons. This *AddM(const List &list) { for (const auto &w : list) Add(w); return (This *)this; } }; //! \class WidgetGroupWrapper //! \brief Automates the creation of widget groups that wrap other widget groups //! \author Stas Jaroszynski template class WidgetGroupWrapper : public AbstractWidgetGroup { protected: That *_group; public: WidgetGroupWrapper(That *group) : _group(group) {} virtual This *Add(Widget *w) override { _group->Add(w); return AbstractWidgetGroup::Add(w); } }; ================================================ FILE: apps/vaporgui/AnimationController.cpp ================================================ #include "AnimationController.h" #include #include #include #include #include using namespace VAPoR; AnimationController::AnimationController(VAPoR::ControlExec *ce) : _controlExec(ce), _myTimer(new QTimer(this)) {} using glm::vec3; void AnimationController::setCurrentTimestep(size_t ts) const { NavigationUtils::SetTimestep(_controlExec, ts); } // Insert values from params into tab panel // void AnimationController::Update() { DataStatus * dataStatus = _controlExec->GetDataStatus(); AnimationParams *aParams = (AnimationParams *)GetActiveParams(); size_t numTS = dataStatus->GetTimeCoordinates().size(); if (numTS == 0) { // no data return; } size_t startFrame = aParams->GetStartTimestep(); size_t endFrame = aParams->GetEndTimestep(); size_t currentFrame = aParams->GetCurrentTimestep(); if (startFrame >= numTS) { startFrame = numTS - 1; aParams->SetStartTimestep(startFrame); } if (endFrame >= numTS) { endFrame = numTS - 1; aParams->SetEndTimestep(endFrame); } if (startFrame > endFrame) { startFrame = endFrame; aParams->SetStartTimestep(startFrame); } if (currentFrame < startFrame) { currentFrame = startFrame; setCurrentTimestep(currentFrame); } if (currentFrame > endFrame) { currentFrame = endFrame; setCurrentTimestep(currentFrame); } } void AnimationController::AnimationPause() { _animationOn = false; setPlay(0); } void AnimationController::AnimationPlayReverse() { _animationOn = true; setPlay(-1); } void AnimationController::AnimationPlayForward() { _capturingImageSequence = qobject_cast(sender()) ? false : true; _animationOn = true; setPlay(1); } void AnimationController::AnimationStepForward() { AnimationParams *aParams = (AnimationParams *)GetActiveParams(); int currentFrame = aParams->GetCurrentTimestep(); int endFrame = aParams->GetEndTimestep(); currentFrame++; if (currentFrame > endFrame) return; setCurrentTimestep(currentFrame); } void AnimationController::AnimationStepReverse() { AnimationParams *aParams = (AnimationParams *)GetActiveParams(); int currentFrame = aParams->GetCurrentTimestep(); int startFrame = aParams->GetStartTimestep(); currentFrame--; if (currentFrame < startFrame) return; setCurrentTimestep(currentFrame); } void AnimationController::SetTimeStep(int ts) { setCurrentTimestep((size_t)ts); } // Following are set by gui, result in save history state. // Whenever play is pressed, it wakes up the animation controller. void AnimationController::setPlay(int direction) { _direction = direction; if (_direction) { // If on is true send notification (signal) that we are in // animation mode. Set a timer to go off at the appropriate // interval based on the frame rate. The timer slot will advance // the frame, etc. // emit AnimationOnOffSignal(true); emit AnimationDrawSignal(); AnimationParams *aParams = (AnimationParams *)GetActiveParams(); int frameRate = aParams->GetMaxFrameRate(); int msec = (int)(1.0 / (float)frameRate * 1000.0); connect(_myTimer, SIGNAL(timeout()), this, SLOT(playNextFrame())); _myTimer->start(msec); } else { // Done animating. Disable timer and send notification // disconnect(_myTimer, 0, 0, 0); GUIStateParams* gsp = NavigationUtils::GetGUIStateParams(_controlExec); string windowName = gsp->GetActiveVizName(); _controlExec->EnableAnimationCapture(windowName, false); _controlExec->GetParamsMgr()->ManuallyAddCurrentStateToUndoStack("End animation playback"); _capturingImageSequence = false; emit AnimationOnOffSignal(false); } } // TODO Refactor void AnimationController::playNextFrame() { VAssert(_direction == -1 || _direction == 1); // Draw the frame, and then advance the frame count // ^? AnimationParams *aParams = (AnimationParams *)GetActiveParams(); int startFrame, endFrame; if (_capturingImageSequence) { startFrame = aParams->GetValueLong(AnimationParams::CaptureStartTag, aParams->GetStartTimestep()); endFrame = aParams->GetValueLong(AnimationParams::CaptureEndTag, aParams->GetEndTimestep()); } else { startFrame = aParams->GetStartTimestep(); endFrame = aParams->GetEndTimestep(); } int currentFrame = aParams->GetCurrentTimestep(); currentFrame += (int)(_direction); if ((currentFrame < startFrame || currentFrame > endFrame)) { AnimationPause(); return; } if (currentFrame < startFrame) currentFrame = endFrame; if (currentFrame > endFrame) currentFrame = startFrame; bool undoEnabled = _controlExec->GetParamsMgr()->GetSaveStateUndoEnabled(); _controlExec->GetParamsMgr()->SetSaveStateUndoEnabled(false); setCurrentTimestep(currentFrame); _controlExec->GetParamsMgr()->SetSaveStateUndoEnabled(undoEnabled); emit AnimationDrawSignal(); } AnimationParams *AnimationController::GetActiveParams() const { return NavigationUtils::GetAnimationParams(_controlExec); } void AnimationController::_updateTab() { Update(); } ================================================ FILE: apps/vaporgui/AnimationController.h ================================================ #pragma once #include #include class AnimationParams; namespace VAPoR { class ControlExec; } //! \class AnimationController //! \brief This class is just migrated legacy code to de-spaghetti other legacy code. //! (It is not written by me) class AnimationController : public QObject { Q_OBJECT VAPoR::ControlExec *_controlExec; QTimer * _myTimer; int _direction; bool _animationOn = false; bool _capturingImageSequence; public: AnimationController(VAPoR::ControlExec *ce); void Update(); public slots: void AnimationPause(); void AnimationPlayReverse(); void AnimationPlayForward(); void AnimationStepForward(); void AnimationStepReverse(); void SetTimeStep(int ts); signals: // Emitted when animation is turned on (true) or off (false) // void AnimationOnOffSignal(bool onOff); // Emitted when the client should draw a frame during animation. Only // Emitted if AnimationOnOffChanged() was most recently called with // onOff == true; // void AnimationDrawSignal(); private: void setCurrentTimestep(size_t ts) const; void setPlay(int direction); AnimationParams *GetActiveParams() const; void _updateTab(); private slots: void playNextFrame(); }; ================================================ FILE: apps/vaporgui/AnnotationEventRouter.cpp ================================================ #include "AnnotationEventRouter.h" #include #include #include "VSection.h" #include "PWidgets.h" #include "PEnumDropdownHLI.h" #include "PSliderEditHLI.h" #include "VPushButton.h" #include "PCopyRegionAnnotationWidget.h" #include "PAxisAnnotationWidget.h" using namespace VAPoR; AnnotationEventRouter::AnnotationEventRouter(ControlExec *ce) : _controlExec(ce) { setLayout(new QVBoxLayout); PGroup *timeAnnotationGroup = new PGroup({new PSection( "Time Annotation", {new PEnumDropdown(AnnotationParams::_timeTypeTag, {"No annotation", "Time step number", "User time", "Formatted date/time"}, {0, 1, 2, 3}, "Annotation type"), (new PIntegerSliderEdit(VAPoR::AnnotationParams::_timeSizeTag, "Font Size"))->SetRange(24, 100)->EnableDynamicUpdate(), (new PDoubleSliderEdit(AnnotationParams::_timeLLXTag, "X Position"))->EnableDynamicUpdate(), (new PDoubleSliderEdit(AnnotationParams::_timeLLYTag, "Y Position"))->EnableDynamicUpdate(), new PColorSelector(AnnotationParams::_timeColorTag, "Text Color")}) }); layout()->addWidget(timeAnnotationGroup); _groups.push_back(timeAnnotationGroup); VSection *axisAnnotationTab = new VSection("Axis Annotations"); PGroup * axisAnnotationGroup1 = new PGroup( {new PCheckbox(AxisAnnotation::_annotationEnabledTag, "Axis Annotations Enabled"), new PCheckbox(AxisAnnotation::_latLonAxesTag, "Annotate with lat/lon"), new PAxisAnnotationWidget(ce) }); axisAnnotationTab->layout()->addWidget(axisAnnotationGroup1); _axisGroups.push_back(axisAnnotationGroup1); PGroup *axisAnnotationGroup2 = new PGroup({ new PColorSelector(AxisAnnotation::_colorTag, "Axis Text Color"), new PColorSelector(AxisAnnotation::_backgroundColorTag, "Text Background Color"), (new PIntegerSliderEditHLI("Font Size", &AxisAnnotation::GetAxisFontSize, &AxisAnnotation::SetAxisFontSize))->SetRange(2, 48)->EnableDynamicUpdate(), (new PIntegerSliderEdit(AxisAnnotation::_digitsTag, "Digits"))->SetRange(0, 8)->EnableDynamicUpdate(), //(new PIntegerSliderEdit(AxisAnnotation::_ticWidthTag, "Tic Width"))->SetRange(0, 10)->EnableDynamicUpdate(), // Broken, see 2711 new PEnumDropdownHLI("X Tickmark Orientation", {"Y axis", "Z axis"}, {1, 2}, &AxisAnnotation::GetXTicDir, &AxisAnnotation::SetXTicDir), new PEnumDropdownHLI("Y Tickmark Orientation", {"X axis", "Z axis"}, {0, 2}, &AxisAnnotation::GetYTicDir, &AxisAnnotation::SetYTicDir), new PEnumDropdownHLI("Z Tickmark Orientation", {"X axis", "Y axis"}, {0, 1}, &AxisAnnotation::GetZTicDir, &AxisAnnotation::SetZTicDir), }); axisAnnotationTab->layout()->addWidget(axisAnnotationGroup2); _axisGroups.push_back(axisAnnotationGroup2); layout()->addWidget(axisAnnotationTab); PGroup* copyRegionGroup = new PGroup({ new PCopyRegionAnnotationWidget(ce) }); layout()->addWidget(copyRegionGroup); _groups.push_back(copyRegionGroup); PGroup *axisArrowGroup = new PGroup({new PSection("Orientation Arrows", {(new PCheckbox(AnnotationParams::AxisArrowEnabledTag, "Show arrows (XYZ->RGB)")), (new PDoubleSliderEdit(AnnotationParams::AxisArrowSizeTag, "Size"))->SetRange(0.f, 1.f)->EnableDynamicUpdate(), (new PDoubleSliderEdit(AnnotationParams::AxisArrowXPosTag, "X Position"))->SetRange(0.f, 1.f)->EnableDynamicUpdate(), (new PDoubleSliderEdit(AnnotationParams::AxisArrowYPosTag, "Y Position"))->SetRange(0.f, 1.f)->EnableDynamicUpdate()})}); layout()->addWidget(axisArrowGroup); _groups.push_back(axisArrowGroup); PGroup *ThreeDGeometryGroup = new PGroup( {new PSection("3D Geometry", {new PCheckbox(AnnotationParams::_domainFrameTag, "Display Domain Bounds"), new PColorSelector(AnnotationParams::_domainColorTag, "Domain Frame Color"), new PColorSelector(AnnotationParams::_backgroundColorTag, "Background Color"), // new PColorSelector(AnnotationParams::_regionColorTag, "Region Frame Color") Broken. See #1742 })}); layout()->addWidget(ThreeDGeometryGroup); _groups.push_back(ThreeDGeometryGroup); } void AnnotationEventRouter::Update() { AnnotationParams *aParams = (AnnotationParams *)_controlExec->GetParamsMgr()->GetParams(AnnotationParams::GetClassType()); AxisAnnotation * aa = aParams->GetAxisAnnotation(); for (PGroup *group : _groups) group->Update(aParams); for (PGroup *group : _axisGroups) group->Update(aa, _controlExec->GetParamsMgr()); } ================================================ FILE: apps/vaporgui/AnnotationEventRouter.h ================================================ #pragma once #include "VaporFwd.h" #include #include "Updatable.h" class PGroup; class AnnotationEventRouter : public QWidget, public Updatable { Q_OBJECT ControlExec *_controlExec; std::vector _groups; std::vector _axisGroups; public: AnnotationEventRouter(VAPoR::ControlExec *ce); void Update() override; }; ================================================ FILE: apps/vaporgui/AppSettingsMenu.cpp ================================================ #include #include #include #include #include "PWidgets.h" #include "PGroup.h" #include "PFileSelectorHLI.h" #include "PIntegerInputHLI.h" #include "PCheckboxHLI.h" #include "VPushButton.h" #include "ErrorReporter.h" #include "CheckForUpdate.h" #include #ifndef _WIN32 #include #endif #include "vapor/STLUtils.h" class PUpdateChecker : public PWidget { VGroup * _group; QLabel * _label; VPushButton *_checkButton; VPushButton *_getButton; UpdateInfo _updateInfo; void updateGUI() const override {} void openURL() { if (!_updateInfo.url.empty()) _updateInfo.OpenURL(); } void checkForUpdate() { _label->setText("Checking..."); _checkButton->setHidden(true); _label->setVisible(true); CheckForUpdate([=](bool updateAvailable, UpdateInfo info) { if (updateAvailable) { DisplayUpdateAvailable(info); } else { if (info.error) DisplayError(); else DisplayUpToDate(); } }); } public: PUpdateChecker() : PWidget("", _group = new VGroup()) { _checkButton = new VPushButton("Check for update"); _group->Add(_checkButton); _label = new QLabel; _label->setHidden(true); _group->Add(_label); _getButton = new VPushButton("Get Latest Version"); _getButton->setHidden(true); _group->Add(_getButton); QObject::connect(_checkButton, &VPushButton::ButtonClicked, this, &PUpdateChecker::checkForUpdate); QObject::connect(_getButton, &VPushButton::ButtonClicked, this, &PUpdateChecker::openURL); } void DisplayUpToDate() { _label->setText("Vapor is up to date"); _checkButton->setHidden(true); _label->setVisible(true); _getButton->setHidden(true); } void DisplayUpdateAvailable(UpdateInfo info) { _updateInfo = info; _label->setText(QString::fromStdString("New version available: " + info.version)); _checkButton->setHidden(true); _label->setVisible(true); _getButton->setVisible(true); } void DisplayError() { _label->setText("Unable to check for new version."); _checkButton->setHidden(true); _label->setVisible(true); _getButton->setHidden(true); } }; AppSettingsMenu::AppSettingsMenu(QWidget *parent) : QDialog(parent), ParamsUpdatable(), _params(nullptr) { int nthreads = 1; #pragma omp parallel { if (omp_get_thread_num() == 0) nthreads = omp_get_num_threads(); } PSection *startupSettings; _settings = new PGroup({ new PSection("Automatic Session Recovery", { new PCheckboxHLI("Automatically save session", &SettingsParams::GetSessionAutoSaveEnabled, &SettingsParams::SetSessionAutoSaveEnabled), (new PIntegerInputHLI("Changes per auto-save", &SettingsParams::GetChangesPerAutoSave, &SettingsParams::SetChangesPerAutoSave)) ->EnableBasedOnParam(SettingsParams::_sessionAutoSaveEnabledTag), (new PFileSaveSelectorHLI("Auto-save file", &SettingsParams::GetAutoSaveSessionFile, &SettingsParams::SetAutoSaveSessionFile)) ->EnableBasedOnParam(SettingsParams::_sessionAutoSaveEnabledTag), }), startupSettings = new PSection("Vapor's Startup Settings", { new PLabel("*Vapor must be restarted for these settings to take effect"), new PCheckboxHLI("Automatically stretch domain", &SettingsParams::GetAutoStretchEnabled, &SettingsParams::SetAutoStretchEnabled), new PCheckbox(SettingsParams::UseAllCoresTag, "Use all (" + std::to_string(nthreads) + ") available cores for multithreaded tasks"), new PSubGroup({(new PIntegerInputHLI("Limit threads to", &SettingsParams::GetNumThreads, &SettingsParams::SetNumThreads)) ->SetRange(1, 1024) ->EnableBasedOnParam(SettingsParams::UseAllCoresTag, false)}), new PIntegerInputHLI("Cache size (Megabytes)", &SettingsParams::GetCacheMB, &SettingsParams::SetCacheMB), new PCheckboxHLI("Check for and show notices on startup", &SettingsParams::GetAutoCheckForNotices, &SettingsParams::SetAutoCheckForNotices), }), new PSection("Default Search Paths", {new PDirectorySelectorHLI("Session file path", &SettingsParams::GetSessionDir, &SettingsParams::SetSessionDir), new PDirectorySelectorHLI("Data set path", &SettingsParams::GetMetadataDir, &SettingsParams::SetMetadataDir)}), // clang-format off new PSection("Updates", { new PCheckboxHLI("Automatically check for updates", &SettingsParams::GetAutoCheckForUpdates, &SettingsParams::SetAutoCheckForUpdates), new PUpdateChecker, }), // clang-format on new PButton("Restore defaults", [](VAPoR::ParamsBase *p) { dynamic_cast(p)->Init(); }), }); #ifndef _WIN32 char hostname[1024]; hostname[1023] = '\0'; gethostname(hostname, 1023); if (STLUtils::BeginsWith(hostname, "casper")) startupSettings->Add(new PCheckboxHLI("Check for VGL on Casper", &SettingsParams::GetCasperCheckForVGL, &SettingsParams::SetCasperCheckForVGL)); #endif setLayout(new QVBoxLayout); layout()->addWidget(_settings); VPushButton *close = new VPushButton("Close"); connect(close, &VPushButton::ButtonClicked, this, &AppSettingsMenu::accept); layout()->addWidget(close); setFocusPolicy(Qt::ClickFocus); } // Handle the pressing of the escape key // Since settings are applied when changed in the gui, // we still want to save the settings file, even if esc is pressed void AppSettingsMenu::reject() { accept(); } void AppSettingsMenu::accept() { VAssert(_params != nullptr); int rc = _params->SaveSettings(); if (rc < 0) { std::string settingsPath = _params->GetSettingsPath(); MSG_ERR("Unable to write to settings file " + settingsPath); } QDialog::accept(); } void AppSettingsMenu::Update(VAPoR::ParamsBase *p, VAPoR::ParamsMgr *paramsMgr, VAPoR::DataMgr *dataMgr) { _params = dynamic_cast(p); VAssert(_params != nullptr); _settings->Update(_params); } ================================================ FILE: apps/vaporgui/AppSettingsMenu.h ================================================ #pragma once #include #include "PWidget.h" #include "ParamsUpdatable.h" #include "PFileSelectorHLI.h" #include "VFileSelector.h" class QWidget; class SettingsParams; class PGroup; class PSection; class SettingsParams; //! \class Preferences Menu //! \ingroup Public_GUI //! \brief Menu for global application preferences //! \author Scott Pearse class AppSettingsMenu : public QDialog, public ParamsUpdatable { Q_OBJECT public: AppSettingsMenu(QWidget *parent); virtual void Update(VAPoR::ParamsBase *p, VAPoR::ParamsMgr *paramsMgr = nullptr, VAPoR::DataMgr *dataMgr = nullptr) override; private: void accept() override; void reject() override; PGroup * _settings; SettingsParams *_params; }; ================================================ FILE: apps/vaporgui/AppSettingsParams.cpp ================================================ //************************************************************************ // * // Copyright (C) 2015 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: AppSettingsparams.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: November 2015 // // Description: Implements the AppSettingsParams class. // This class supports application settings // #ifdef WIN32 // Annoying unreferenced formal parameter warning #pragma warning(disable : 4100) #endif #include #include "AppSettingsParams.h" using namespace VAPoR; const string AppSettingsParams::m_classType = "ApplicationSettings"; const string AppSettingsParams::_shortName = "AppSettings"; const string AppSettingsParams::_currentJpegQualityTag = "CurrentJpegQuality"; const string AppSettingsParams::_currentAutosaveEnabledTag = "CurrentAutosaveEnabled"; const string AppSettingsParams::_currentAutosaveIntervalTag = "CurrentAutosaveInterval"; const string AppSettingsParams::_currentShowDataWarningTag = "CurrentWarnMissingData"; const string AppSettingsParams::_currentUseLessAccurateTag = "CurrentUseLessAccurateData"; const string AppSettingsParams::_currentTrackMouseTag = "CurrentTrackMouse"; const string AppSettingsParams::_currentShowCitationTag = "CurrentShowCitation"; const string AppSettingsParams::_currentLogFileNameTag = "CurrentLogfileName"; const string AppSettingsParams::_currentAutosaveFileNameTag = "CurrentAutosaveName"; const string AppSettingsParams::_currentMessagesSilencedTag = "CurrentMessageSilence"; const string AppSettingsParams::_currentLogfileEnabledTag = "CurrentLogfileEnabled"; const string AppSettingsParams::_logFileNameTag = "LogfileName"; const string AppSettingsParams::_logfileEnabledTag = "LogfileEnabled"; const string AppSettingsParams::_autosaveFileNameTag = "AutosaveName"; const string AppSettingsParams::_jpegQualityTag = "JpegQuality"; const string AppSettingsParams::_autosaveEnabledTag = "AutosaveEnabled"; const string AppSettingsParams::_autosaveIntervalTag = "AutosaveInterval"; const string AppSettingsParams::_showDataWarningTag = "WarnMissingData"; const string AppSettingsParams::_useLessAccurateTag = "UseLessAccurateData"; const string AppSettingsParams::_trackMouseTag = "TrackMouse"; const string AppSettingsParams::_showCitationTag = "ShowCitation"; const string AppSettingsParams::_messagesSilencedTag = "MessageSilence"; static ParamsRegistrar registrar(AppSettingsParams::GetClassType()); // Reset AppSettings settings to initial state void AppSettingsParams::_init() { SetJpegQuality(99); SetAutosaveInterval(10); SetAutosaveEnabled(true); SetShowWarning(false); SetUseLessAccurate(true); SetTrackMouse(true); SetShowCitation(true); SetLogFileName(string("/tmp/logfile.txt")); SetAutosaveName(string("/tmp/autosave.vs3")); SetMessageSilence(false); SetLogfileEnabled(false); } //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- AppSettingsParams::AppSettingsParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, m_classType) { _init(); } AppSettingsParams::AppSettingsParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) { // If node isn't tagged correctly we correct the tag and reinitialize // from scratch; // if (node->GetTag() != AppSettingsParams::GetClassType()) { node->SetTag(AppSettingsParams::GetClassType()); _init(); } } //---------------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------------- AppSettingsParams::~AppSettingsParams() { MyBase::SetDiagMsg("AppSettingsParams::~AppSettingsParams() this=%p", this); } void AppSettingsParams::restoreDefaults() { _init(); } #ifdef VAPOR3_0_0_ALPHA void AppSettingsParams::saveCurrentSettings() { // This copying should not be saved as a command; // It cannot be undone. Copy all the current settings to the permanent settings. SetJpegQuality(GetCurrentJpegQuality()); SetAutosaveInterval(GetCurrentAutosaveInterval()); SetAutosaveEnabled(GetCurrentAutosaveEnabled()); SetShowWarning(GetCurrentShowWarning()); SetUseLessAccurate(GetCurrentUseLessAccurate()); SetTrackMouse(GetCurrentTrackMouse()); SetShowCitation(GetCurrentShowCitation()); SetMessageSilence(GetCurrentMessageSilence()); SetLogFileName(GetCurrentLogFileName()); SetAutosaveName(GetCurrentAutosaveName()); SetLogfileEnabled(GetCurrentLogfileEnabled()); } void AppSettingsParams::copySavedSettings() { SetCurrentJpegQuality(GetJpegQuality()); SetCurrentAutosaveInterval(GetAutosaveInterval()); SetCurrentAutosaveEnabled(GetAutosaveEnabled()); SetCurrentShowWarning(GetShowWarning()); SetCurrentUseLessAccurate(GetUseLessAccurate()); SetCurrentTrackMouse(GetTrackMouse()); SetCurrentShowCitation(GetShowCitation()); SetCurrentMessageSilence(GetMessageSilence()); SetCurrentLogfileEnabled(GetLogfileEnabled()); } #endif void AppSettingsParams::SetJpegQuality(int val) { if (val < 1 || val > 99) val = 99; SetValueLong(_jpegQualityTag, "Set jpeg quality", val); } long AppSettingsParams::GetJpegQuality() const { int defaultv = 99; int val = GetValueLong(_jpegQualityTag, defaultv); if (val < 1 || val > 99) val = defaultv; return (val); } void AppSettingsParams::SetAutosaveInterval(int val) { if (val < 1) val = 1; SetValueLong(_autosaveIntervalTag, "Set autosave interval", val); } long AppSettingsParams::GetAutosaveInterval() const { int defaultv = 5; int val = GetValueLong(_autosaveIntervalTag, defaultv); if (val < 1) val = defaultv; return (val); } void AppSettingsParams::SetCurrentJpegQuality(int val) { if (val < 1 || val > 99) val = 99; SetValueLong(_currentJpegQualityTag, "Set current jpeg quality", val); } long AppSettingsParams::GetCurrentJpegQuality() const { int defaultv = 99; int val = GetValueLong(_currentJpegQualityTag, defaultv); if (val < 1 || val > 99) val = defaultv; return (val); } void AppSettingsParams::SetCurrentAutosaveInterval(int val) { if (val < 1) val = 1; SetValueLong(_currentAutosaveIntervalTag, "Set current autosave interval", val); } long AppSettingsParams::GetCurrentAutosaveInterval() const { int defaultv = 5; int val = GetValueLong(_currentAutosaveIntervalTag, defaultv); if (val < 1) val = defaultv; return (val); } ================================================ FILE: apps/vaporgui/AppSettingsParams.h ================================================ //************************************************************************ // * // Copyright (C) 2015 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: AppSettingsParams.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: June 2015 // // Description: Defines the AppSettingsParams class. // This class supports parameters associted with the // AppSettings panel, describing the visual features in the visualizer // #ifndef APPSETTINGSPARAMS_H #define APPSETTINGSPARAMS_H #include #include //! \class AppSettingsParams //! \ingroup Public_Params //! \brief A class for describing visual features displayed in the visualizer. //! \author Alan Norton //! \version 3.0 //! \date June 2015 //! The AppSettingsParams class controls various features displayed in the visualizers //! There is a global AppSettingsParams, that //! is shared by all windows whose AppSettings is set to "global". There is also //! a local AppSettingsParams for each window, that users can select whenever there are multiple windows. //! When local settings are used, they only affect one currently active visualizer. //! The AppSettingsParams class also has several methods that are useful in setting up data requests from the DataMgr. //! class AppSettingsParams : public VAPoR::ParamsBase { public: AppSettingsParams(VAPoR::ParamsBase::StateSave *ssave); AppSettingsParams(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node); virtual ~AppSettingsParams(); //! Pure virtual method on Params. Provide a short name suitable for use in the GUI //! \retval string name const std::string getShortName() { return _shortName; } #ifdef VAPOR3_0_0_ALPHA //! Copy the current settings to the saved settings //! Needed whenever user wants to make current settings default //! All of the settings in this Params have an additional "current" state //! The current state is what is shown in the tab panel void saveCurrentSettings(); //! Copy the saved settings to the current settings. //! Needed whenever settings are loaded. void copySavedSettings(); #endif //! Restore default settings //! performed on user request. void restoreDefaults(); //! Specify jpeg quality level //! \param[in] val quality level (1-99) void SetJpegQuality(int val); //! Obtain jpeg quality //! \return jpeg quality level long GetJpegQuality() const; //! Specify autosave interval //! \param[in] val autosave interval >= 1 void SetAutosaveInterval(int val); //! Obtain autosave interval //! \return interval between autosaves long GetAutosaveInterval() const; bool GetAutosaveEnabled() { return (0 != GetValueLong(_autosaveEnabledTag, (long)true)); } void SetAutosaveEnabled(bool onOff) { SetValueLong(_autosaveEnabledTag, "toggle autosave enabled", (long)onOff); } bool GetShowWarning() const { return (0 != GetValueLong(_showDataWarningTag, (long)true)); } void SetShowWarning(bool onOff) { SetValueLong(_showDataWarningTag, "toggle warn data missing", (long)onOff); } bool GetUseLessAccurate() const { return (0 != GetValueLong(_useLessAccurateTag, (long)false)); } void SetUseLessAccurate(bool onOff) { SetValueLong(_useLessAccurateTag, "toggle use lower accuracy", (long)onOff); } bool GetTrackMouse() const { return (0 != GetValueLong(_trackMouseTag, (long)true)); } void SetTrackMouse(bool onOff) { SetValueLong(_trackMouseTag, "toggle track mouse", (long)onOff); } bool GetShowCitation() const { return (0 != GetValueLong(_showCitationTag, (long)true)); } void SetShowCitation(bool onOff) { SetValueLong(_showCitationTag, "toggle show citation info", (long)onOff); } void SetMessageSilence(bool val) { SetValueLong(_messagesSilencedTag, "(Un)Silence messages", (long)val); } bool GetMessageSilence() const { return (0 != GetValueLong(_messagesSilencedTag, (long)false)); } string GetAutosaveName() { return GetValueString(_autosaveFileNameTag, string("/tmp/vapor_autosave.vs3")); } void SetAutosaveName(string name) { SetValueString(_autosaveFileNameTag, "set autosave file", name); } string GetLogFileName() const { return GetValueString(_logFileNameTag, string("/tmp/vaporLog.txt")); } void SetLogFileName(string name) { SetValueString(_logFileNameTag, "set log file", name); } bool GetLogfileEnabled() const { return (0 != GetValueLong(_logfileEnabledTag, (long)false)); } void SetLogfileEnabled(bool val) { SetValueLong(_logfileEnabledTag, "toggle logfile enabled", (long)val); } //! Specify current jpeg quality level //! \param[in] val quality level (1-99) void SetCurrentJpegQuality(int val); long GetCurrentJpegQuality() const; //! Specify current autosave interval //! \param[in] val autosave interval >= 1 void SetCurrentAutosaveInterval(int val); //! Obtain Current autosave interval //! \return interval between autosaves long GetCurrentAutosaveInterval() const; bool GetCurrentAutosaveEnabled() const { return (0 != GetValueLong(_currentAutosaveEnabledTag, (long)true)); } void SetCurrentAutosaveEnabled(bool onOff) { SetValueLong(_currentAutosaveEnabledTag, "Toggle current autosave enabled", (long)onOff); } bool GetCurrentShowWarning() const { return (0 != GetValueLong(_currentShowDataWarningTag, (long)true)); } void SetCurrentShowWarning(bool onOff) { SetValueLong(_currentShowDataWarningTag, "toggle current show warning", (long)onOff); } bool GetCurrentUseLessAccurate() const { return (0 != GetValueLong(_currentUseLessAccurateTag, (long)false)); } void SetCurrentUseLessAccurate(bool onOff) { SetValueLong(_currentUseLessAccurateTag, "toggle current use less accuracy", (long)onOff); } bool GetCurrentTrackMouse() const { return (0 != GetValueLong(_currentTrackMouseTag, (long)true)); } void SetCurrentTrackMouse(bool onOff) { SetValueLong(_currentTrackMouseTag, "toggle current track mouse", (long)onOff); } bool GetCurrentShowCitation() const { return (0 != GetValueLong(_currentShowCitationTag, (long)true)); } void SetCurrentShowCitation(bool onOff) { SetValueLong(_currentShowCitationTag, "toggle current show citation", (long)onOff); } string GetCurrentAutosaveName() const { return GetValueString(_currentAutosaveFileNameTag, string("/tmp/vapor_autosave.vs3")); } void SetCurrentAutosaveName(string name) { SetValueString(_currentAutosaveFileNameTag, "set current autosave file", name); } string GetCurrentLogFileName() const { return GetValueString(_currentLogFileNameTag, string("/tmp/vaporLog.txt")); } void SetCurrentLogFileName(string name) { SetValueString(_currentLogFileNameTag, "set current log file", name); } void SetCurrentMessageSilence(bool val) { SetValueLong(_currentMessagesSilencedTag, "(Un)Silence current messages", (long)val); } bool GetCurrentMessageSilence() const { return (0 != GetValueLong(_currentMessagesSilencedTag, (long)false)); } bool GetCurrentLogfileEnabled() const { return (0 != GetValueLong(_currentLogfileEnabledTag, (long)false)); } void SetCurrentLogfileEnabled(bool val) { SetValueLong(_currentLogfileEnabledTag, "toggle current logfile enabled", (long)val); } // Get static string identifier for this params class // static string GetClassType() { return (m_classType); } private: static const string m_classType; static const string _shortName; static const string _jpegQualityTag; static const string _autosaveEnabledTag; static const string _autosaveIntervalTag; static const string _showDataWarningTag; static const string _useLessAccurateTag; static const string _trackMouseTag; static const string _showCitationTag; static const string _logFileNameTag; static const string _logfileEnabledTag; static const string _autosaveFileNameTag; static const string _messagesSilencedTag; static const string _currentLogFileNameTag; static const string _currentLogfileEnabledTag; static const string _currentAutosaveFileNameTag; static const string _currentJpegQualityTag; static const string _currentAutosaveEnabledTag; static const string _currentAutosaveIntervalTag; static const string _currentShowDataWarningTag; static const string _currentUseLessAccurateTag; static const string _currentTrackMouseTag; static const string _currentShowCitationTag; static const string _currentMessagesSilencedTag; void _init(); }; #endif // APPSETTINGSPARAMS_H ================================================ FILE: apps/vaporgui/BannerGUI.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #include "BannerGUI.h" BannerGUI::BannerGUI(QWidget *parent, std::string imagefile, int maxwait, bool center, QString text, QString url) { _parent = parent; this->url = url; if (maxwait >= 0) this->setWindowFlags(Qt::FramelessWindowHint); if (maxwait > 0) QTimer::singleShot(maxwait, this, SLOT(on_timer_end())); central = new QWidget(); setCentralWidget(central); mainLayout = new QVBoxLayout(); central->setLayout(mainLayout); buttonLayout = new QHBoxLayout(); textLabel = new QLabel(text, this); textLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); imageLabel = new QLabel("", this); imageLabel->setBackgroundRole(QPalette::Base); imageLabel->setScaledContents(true); infoButton = new QPushButton("More Info"); connect(infoButton, SIGNAL(released()), this, SLOT(infoButton_action())); closeButton = new QPushButton("Close"); connect(closeButton, SIGNAL(released()), this, SLOT(closeButton_action())); if (!imagefile.empty()) { QImage image(Wasp::GetSharePath("images/" + imagefile).c_str()); // QImage image(imagefile.c_str()); if (image.isNull()) { QMessageBox::information(this, tr("VAPoR Banner"), tr("Could not load banner image.\n")); } else { imageLabel->setPixmap(QPixmap::fromImage(image)); // setCentralWidget(imageLabel); if (text.compare("") != 0) mainLayout->addWidget(textLabel); mainLayout->addWidget(imageLabel); if (maxwait < 0 || url.compare("") != 0) mainLayout->addLayout(buttonLayout); if (url.compare("") != 0) buttonLayout->addWidget(infoButton); if (maxwait < 0) buttonLayout->addWidget(closeButton); if (center) { QPoint mpos = parent->pos(); move(mpos.x() + (this->width() / 2) - (image.width() / 2), mpos.y() + (this->height() / 2) - (image.height() / 2)); } else { QScreen *screen = QGuiApplication::primaryScreen(); QRect screenGeometry = screen->geometry(); int x = (screenGeometry.width() - image.size().width()) / 2; int y = (screenGeometry.height() - image.size().height()) / 2; move(x, y); } mainLayout->setSizeConstraint(QLayout::SetFixedSize); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); show(); } } } void BannerGUI::request_close() { close(); } void BannerGUI::on_timer_end() { close(); } void BannerGUI::infoButton_action() { // TODO: THIS APPEARS NOT TO WORK. FIND OUT HOW OTHERS DO IT. QDesktopServices::openUrl(QUrl(url)); } void BannerGUI::closeButton_action() { close(); } ================================================ FILE: apps/vaporgui/BannerGUI.h ================================================ #ifndef BANNERGUI_H #define BANNERGUI_H #include #include #include #include class BannerGUI : QMainWindow { Q_OBJECT public: BannerGUI(QWidget *parent, std::string imagefile, int maxwait = 0, bool center = false, QString text = "", QString url = ""); void request_close(); private: QWidget * central; QVBoxLayout *mainLayout; QLabel * textLabel; QLabel * imageLabel; QHBoxLayout *buttonLayout; QPushButton *closeButton; QPushButton *infoButton; QString url; QWidget * _parent; private slots: void on_timer_end(); void infoButton_action(); void closeButton_action(); }; #endif // BANNERGUI_H ================================================ FILE: apps/vaporgui/BarbEventRouter.cpp ================================================ #include "BarbEventRouter.h" #include "vapor/BarbParams.h" #include "PWidgets.h" #include "PConstantColorWidget.h" #include "PMetadataClasses.h" using namespace VAPoR; typedef BarbParams BP; static RenderEventRouterRegistrar registrar(BarbEventRouter::GetClassType()); BarbEventRouter::BarbEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, BarbParams::GetClassType()) { // clang-format off AddVariablesSubtab(new PGroup({ new PSection("Variable Selection", { new PDimensionSelector, new PXFieldVariableSelector, new PYFieldVariableSelector, new PZFieldVariableSelector, new PHeightVariableSelector, new PColorMapVariableSelector, }), new PFidelitySection, new POpenVariableMetadataWidget })); AddAppearanceSubtab(new PGroup({ new PColormapTFEditor, new PSection("Barbs", { (new PIntegerSliderEdit(BP::_xBarbsCountTag, "X Barbs"))->SetRange(1, 50), (new PIntegerSliderEdit(BP::_yBarbsCountTag, "Y Barbs"))->SetRange(1, 50), (new PIntegerSliderEdit(BP::_zBarbsCountTag, "Z Barbs"))->SetRange(1, 50), (new PDoubleSliderEdit(BP::_lengthScaleTag, "Length Scale"))->SetRange(0.01, 4)->EnableDynamicUpdate(), (new PDoubleSliderEdit(BP::_thicknessScaleTag, "Thickness Scale"))->SetRange(0.01, 4)->EnableDynamicUpdate(), new PCheckbox(BP::LightingEnabledTag, "Enable Lighting"), new PConstantColorWidget, new PCheckbox(BP::DrawInFrontTag, "Draw renderer in front") }), })); AddGeometrySubtab(new PGeometrySubtab); AddColorbarSubtab(new PAnnotationColorbarWidget); // clang-format on } string BarbEventRouter::_getDescription() const { return ("Displays an " "array of arrows with the users domain, with custom dimensions that are " "defined by the user in the X, Y, and Z axes. The arrows represent a vector " "whos direction is determined by up to three user-defined variables.\n\nBarbs " "can have a constant color applied to them, or they may be colored according " "to an additional user-defined variable.\n\n"); } ================================================ FILE: apps/vaporgui/BarbEventRouter.h ================================================ #pragma once #include "RenderEventRouterGUI.h" #include "vapor/BarbRenderer.h" //! \class BarbEventRouter //! \ingroup Public_GUI //! \brief Barb renderer GUI //! \author Stas Jaroszynski class BarbEventRouter : public RenderEventRouterGUI { public: BarbEventRouter(QWidget *parent, VAPoR::ControlExec *ce); static string GetClassType() { return VAPoR::BarbRenderer::GetClassType(); } string GetType() const { return GetClassType(); } bool Supports2DVariables() const { return true; } bool Supports3DVariables() const { return true; } protected: virtual string _getDescription() const; virtual string _getSmallIconImagePath() const { return "Barbs_small.png"; } virtual string _getIconImagePath() const { return "Barbs.png"; } }; ================================================ FILE: apps/vaporgui/BookmarkManager.cpp ================================================ #include "BookmarkManager.h" #include #include #include #include #include #include #include #include "VizWinMgr.h" #include "QCustomIconSizeProxyStyle.h" BookmarkManager::BookmarkManager(QObject *parent, VAPoR::ControlExec *ce, VizWinMgr *vizWinMgr) : QObject(parent), _controlExec(ce), _paramsMgr(ce->GetParamsMgr()), _vizWinMgr(vizWinMgr), _loadBookmarkMenu(new QMenu("Load Bookmark")), _deleteBookmarkMenu(new QMenu("Delete Bookmark")) { _loadBookmarkMenu->setStyle(new QCustomIconSizeProxyStyle(BookmarkParams::DefaultIconSize())); _deleteBookmarkMenu->setStyle(new QCustomIconSizeProxyStyle(BookmarkParams::DefaultIconSize())); } void BookmarkManager::RegisterToMenu(QMenu *menu) { menu->addAction("Create Bookmark", this, &BookmarkManager::createBookmark); menu->addMenu(_loadBookmarkMenu); menu->addMenu(_deleteBookmarkMenu); } void BookmarkManager::Update() { populateBookmarkList(); } void BookmarkManager::createBookmark() { bool ok; QString input = QInputDialog::getText(nullptr, "New Bookmark", "Bookmark Name:", QLineEdit::Normal, "", &ok); if (!ok) return; string title = input.toStdString(); if (title.empty()) title = "Unnamed Bookmark"; auto p = _controlExec->GetParams(); p->BeginGroup("Create Bookmark"); vector bookmarks; for (auto *b : p->GetBookmarks()) bookmarks.push_back(BookmarkParams(*b)); p->ClearBookmarks(); Base16StringStream ss; XmlNode::streamOut(ss, *_paramsMgr->GetXMLRoot()); for (auto &b : bookmarks) p->AddBookmark(&b); string activeVizWin = p->GetActiveVizName(); ViewpointParams *vpp = _paramsMgr->GetViewpointParams(activeVizWin); bool useCustomViewport = vpp->GetValueLong(vpp->UseCustomFramebufferTag, 0); int customViewportWidth = vpp->GetValueLong(vpp->CustomFramebufferWidthTag, 0); int customViewportHeight = vpp->GetValueLong(vpp->CustomFramebufferHeightTag, 0); const int iconSize = BookmarkParams::DefaultIconSize(); const int iconDataSize = iconSize * iconSize * 3; auto iconData = std::unique_ptr(new unsigned char[iconDataSize]); char iconDataString[64]; snprintf(iconDataString, 64, ":RAM:%p", iconData.get()); // The above string is a "file path" that points to an address in memory // which tells the visualizer to save the resulting image to ram rather than // to disk. The current "image capture" implementation is very buggy spaghetti // and this is the cleanest solution without major refactoring. vpp->SetValueLong(vpp->UseCustomFramebufferTag, "", true); vpp->SetValueLong(vpp->CustomFramebufferWidthTag, "", iconSize); vpp->SetValueLong(vpp->CustomFramebufferHeightTag, "", iconSize); _vizWinMgr->EnableImageCapture(iconDataString, activeVizWin); vpp->SetValueLong(vpp->UseCustomFramebufferTag, "", useCustomViewport); vpp->SetValueLong(vpp->CustomFramebufferWidthTag, "", customViewportWidth); vpp->SetValueLong(vpp->CustomFramebufferHeightTag, "", customViewportHeight); Base16StringStream is; is.write((char *)iconData.get(), iconDataSize); BookmarkParams *b = p->CreateBookmark(); b->SetName(title); b->SetIcon(iconSize, is.ToString()); b->SetData(ss.ToString()); p->EndGroup(); } void BookmarkManager::populateBookmarkList() { auto bookmarks = _controlExec->GetParams()->GetBookmarks(); _loadBookmarkMenu->clear(); _deleteBookmarkMenu->clear(); if (bookmarks.empty()) { _loadBookmarkMenu->addAction("(empty)")->setEnabled(false); _deleteBookmarkMenu->addAction("(empty)")->setEnabled(false); } unsigned char *buf = nullptr; size_t bufSize = 0; int i = 0; for (auto b : bookmarks) { if (bufSize != b->GetIconDataSize()) { if (buf) delete[] buf; buf = new unsigned char[b->GetIconDataSize()]; bufSize = b->GetIconDataSize(); } Base16DecoderStream ds(b->GetIconData()); ds.read((char *)buf, bufSize); int s = b->GetIconSize(); QImage iconImage(buf, s, s, s * 3, QImage::Format_RGB888); QIcon icon(QPixmap::fromImage(iconImage)); _loadBookmarkMenu->addAction(icon, QString::fromStdString(b->GetName()), [this, i]() { loadBookmark(i); }); _deleteBookmarkMenu->addAction(icon, QString::fromStdString(b->GetName()), [this, i]() { deleteBookmark(i); }); i++; } if (buf) delete[] buf; } void BookmarkManager::loadBookmark(int i) { auto p = _controlExec->GetParams(); XmlNode root; XmlParser parser; Base16DecoderStream stream(p->GetBookmark(i)->GetData()); parser.LoadFromFile(&root, stream); bool paramsStateSaveEnabled = _controlExec->GetSaveStateEnabled(); _controlExec->SetSaveStateEnabled(false); vector bookmarks; for (auto *b : p->GetBookmarks()) bookmarks.push_back(BookmarkParams(*b)); _controlExec->LoadState(&root); p = _controlExec->GetParams(); p->ClearBookmarks(); for (auto &b : bookmarks) p->AddBookmark(&b); _controlExec->SetDataCacheDirty(); // TODO determine if necessary _controlExec->SetSaveStateEnabled(paramsStateSaveEnabled); _paramsMgr->UndoRedoClear(); _paramsMgr->TriggerManualStateChangeEvent(); } void BookmarkManager::deleteBookmark(int i) { auto p = _controlExec->GetParams(); p->DeleteBookmark(i); } ================================================ FILE: apps/vaporgui/BookmarkManager.h ================================================ #pragma once #include "Updatable.h" #include class QMenu; class VizWinMgr; class BookmarkManager : public QObject, public Updatable { Q_OBJECT public: BookmarkManager(QObject *parent, ControlExec *ce, VizWinMgr *vizWinMgr); void RegisterToMenu(QMenu *menu); void Update() override; private: ControlExec * const _controlExec; ParamsMgr * const _paramsMgr; VizWinMgr * const _vizWinMgr; QMenu * const _loadBookmarkMenu; QMenu * const _deleteBookmarkMenu; void createBookmark(); void populateBookmarkList(); void loadBookmark(int i); void deleteBookmark(int i); }; ================================================ FILE: apps/vaporgui/CLIToolInstaller.cpp ================================================ #include "CLIToolInstaller.h" #include #include #include #ifdef WIN32 #include "windowsUtils.h" #endif using namespace std; using namespace Wasp; void CLIToolInstaller::Install() { QMessageBox box; box.addButton(QMessageBox::Ok); #ifdef Darwin string home = GetResourcePath(""); string binPath = home + "/MacOS"; home.erase(home.size() - strlen("Contents/"), strlen("Contents/")); vector profilePaths = { string(getenv("HOME")) + "/.profile", string(getenv("HOME")) + "/.zshrc", }; bool success = true; for (auto profilePath : profilePaths) { FILE *prof = fopen(profilePath.c_str(), "a"); success &= (bool)prof; if (prof) { fprintf(prof, "\n\n"); fprintf(prof, "export VAPOR_HOME=\"%s\"\n", home.c_str()); fprintf(prof, "export PATH=\"%s:$PATH\"\n", binPath.c_str()); fclose(prof); } } if (success) { box.setText("Installation Successful"); box.setInformativeText("Environmental variables set in ~/.profile and ~/.zshrc. The vapor command line utilities should be available from the terminal."); box.setIcon(QMessageBox::Information); } else { box.setText("Unable to set environmental variables"); box.setIcon(QMessageBox::Critical); } #endif #ifdef WIN32 HKEY key; long error; long errorClose; bool pathWasModified = false; string home = GetResourcePath(""); error = Windows_OpenRegistry(WINDOWS_HKEY_CURRENT_USER, "Environment", key); if (error == WINDOWS_SUCCESS) { string path; error = Windows_GetRegistryString(key, "Path", path, ""); if (error == WINDOWS_ERROR_FILE_NOT_FOUND) { error = WINDOWS_SUCCESS; path = ""; } if (error == WINDOWS_SUCCESS) { bool alreadyExists = false; size_t index; if (path.find(";" + home + ";") != std::string::npos) alreadyExists = true; else if ((index = path.find(";" + home)) != std::string::npos && index + home.length() + 1 == path.length()) alreadyExists = true; else if ((index = path.find(home + ";")) != std::string::npos && index == 0) alreadyExists = true; else if (path == home) alreadyExists = true; if (!alreadyExists) { if (path.length() > 0) path += ";"; path += home; error = Windows_SetRegistryString(key, "Path", path); if (error == WINDOWS_SUCCESS) pathWasModified = true; } } errorClose = Windows_CloseRegistry(key); } if (error == WINDOWS_SUCCESS && errorClose == WINDOWS_SUCCESS) { // This tells windows to re-load the environment variables SendMessage(HWND_BROADCAST, WM_WININICHANGE, NULL, (LPARAM) "Environment"); box.setIcon(QMessageBox::Information); if (pathWasModified) box.setText("Vapor conversion utilities were added to your path"); else box.setText("Your path is properly configured"); } else { box.setIcon(QMessageBox::Critical); box.setText("Unable to set environmental variables"); string errString = ""; if (error != WINDOWS_SUCCESS) errString += Windows_GetErrorString(error) + "\n"; if (errorClose != WINDOWS_SUCCESS) errString += "CloseRegistry: " + Windows_GetErrorString(errorClose); box.setInformativeText(QString::fromStdString(errString)); } #endif box.exec(); } ================================================ FILE: apps/vaporgui/CLIToolInstaller.h ================================================ #pragma once class CLIToolInstaller { public: static void Install(); }; ================================================ FILE: apps/vaporgui/CMakeLists.txt ================================================ # TODO REMOVE add_definitions (-DNEW_GUI) set (SRCS RenderEventRouter.cpp RenderHolder.cpp GLWidget.cpp ErrorReporter.cpp AnnotationEventRouter.cpp ExportTab.cpp ExportTab.h TwoDDataEventRouter.cpp TwoDDataEventRouter.h WireFrameEventRouter.cpp PythonVariables.cpp Statistics.cpp Plot.cpp CopyRegionWidget.cpp CopyRegionAnnotationWidget.cpp RangeCombos.cpp BarbEventRouter.cpp BarbEventRouter.h BannerGUI.cpp main.cpp MainForm.cpp MainForm_isOpenGLContextActive.cpp VizWin.cpp VizWinMgr.cpp ImageEventRouter.cpp ImageEventRouter.h ContourEventRouter.cpp ContourEventRouter.h SliceEventRouter.cpp SliceEventRouter.h PlotParams.cpp StatisticsParams.cpp VaporTable.cpp FidelityWidget.cpp QSliderEdit.cpp QRange.cpp QSinglePoint.cpp QIntValidatorWithFixup.cpp FileOperationChecker.cpp Combo.cpp windowsUtils.cpp Manip.cpp FlowEventRouter.cpp VolumeEventRouter.cpp VolumeEventRouter.h VolumeIsoEventRouter.cpp VolumeIsoEventRouter.h ParamsMenuItems.cpp ParamsMenuItems.h TFOpacityWidget.cpp TFOpacityWidget.h TFColorWidget.cpp TFColorWidget.h QRangeSlider.cpp QRangeSlider.h TFHistogramWidget.cpp TFHistogramWidget.h TFInfoWidget.cpp TFInfoWidget.h QColorWidget.cpp QColorWidget.h TFColorInfoWidget.cpp TFColorInfoWidget.h TFOpacityInfoWidget.cpp TFOpacityInfoWidget.h TFMapWidget.cpp TFMapWidget.h TFMapGroupWidget.cpp TFMapGroupWidget.h TFHistogramInfoWidget.cpp TFHistogramInfoWidget.h TFIsoValueWidget.cpp TFIsoValueWidget.h TFIsoValueInfoWidget.cpp TFIsoValueInfoWidget.h TFUtils.cpp TFUtils.h TFMappingRangeSelector.cpp TFMappingRangeSelector.h QRangeSliderTextCombo.cpp QRangeSliderTextCombo.h QPaintUtils.cpp QPaintUtils.h VSection.cpp VSection.h VFrame.h VFrame.cpp VLineItem.cpp VLineItem.h VHBoxWidget.cpp VHBoxWidget.h VComboBox.cpp VComboBox.h VIntSpinBox.cpp VIntSpinBox.h VCheckBox.cpp VCheckBox.h VLineEdit_Deprecated.cpp VLineEdit_Deprecated.h VActions.h VActions.cpp VSlider.cpp VSlider.h VSliderEdit.cpp VSliderEdit.h VSliderEditInterface.cpp VSliderEditInterface.h VStringLineEdit.h VStringLineEdit.cpp VIntLineEdit.h VIntLineEdit.cpp VDoubleLineEdit.h VDoubleLineEdit.cpp VDoubleSliderEdit.cpp VDoubleSliderEdit.h VDoubleSliderEditMenu.cpp VDoubleSliderEditMenu.h VIntSliderEditMenu.cpp VIntSliderEditMenu.h VIntSliderEdit.cpp VIntSliderEdit.h VNumericLineEdit.cpp VNumericLineEdit.h VIntRangeMenu.cpp VIntRangeMenu.h VDoubleRangeMenu.cpp VDoubleRangeMenu.h VNumericFormatMenu.cpp VNumericFormatMenu.h VPushButton.cpp VPushButton.h QPushButtonWithDoubleClick.h VFileSelector.cpp VFileSelector.h V3DInput.cpp V3DInput.h V3DIntInput.cpp V3DIntInput.h VGroup.cpp VGroup.h ParamsUpdatable.cpp ParamsUpdatable.h POrientationSelector.cpp POrientationSelector.h PWidget.cpp PWidget.h PWidgetHLI.h PGroup.cpp PGroup.h PSection.cpp PSection.h PCheckbox.cpp PCheckbox.h PCheckboxHLI.h PDoubleInput.cpp PDoubleInput.h PDoubleInputHLI.h PIntegerInput.cpp PIntegerInput.h PIntegerInputHLI.h PDisplay.cpp PDisplay.h PDisplayHLI.h PLabel.cpp PLabel.h PLineItem.cpp PLineItem.h PEnumDropdown.cpp PEnumDropdown.h PEnumDropdownHLI.h PStringDropdown.cpp PStringDropdown.h PStringDropdownHLI.h PColorSelector.cpp PColorSelector.h PFileButton.cpp PFileButton.h PFileSelector.cpp PFileSelector.h PFileSelectorHLI.h PDynamicMixin.cpp PDynamicMixin.h PSliderEdit.cpp PSliderEdit.h PSliderEditHLI.h PRegionSelector.cpp PRegionSelector.h ParamsWidgetDemo.cpp ParamsWidgetDemo.h PTFEditor.cpp PTFEditor.h PFidelitySection.cpp PFidelitySection.h PAxisAnnotationWidget.cpp PAxisAnnotationWidget.h PTMSLODInput.h PMovingDomainSettings.cpp PMovingDomainSettings.h ModelEventRouter.cpp ModelEventRouter.h VDoubleValidator.cpp VDoubleValidator.h hide_std_error_util.cpp hide_std_error_util.h VContainer.cpp VContainer.h UWidget.cpp UWidget.h AbstractWidgetGroup.cpp AbstractWidgetGroup.h PTransformWidget.cpp PTransformWidget.h PCopyRegionAnnotationWidget.cpp PCopyRegionAnnotationWidget.h PCopyRegionWidget.cpp PCopyRegionWidget.h PSliceController.cpp PSliceController.h PAnnotationColorbarWidget.cpp PAnnotationColorbarWidget.h PStringInput.cpp PStringInput.h PWidgets.h PWidgetsFwd.h PGeometrySubtab.cpp PGeometrySubtab.h PDimensionSelector.cpp PDimensionSelector.h PVariableSelector.cpp PVariableSelector.h PShowIf.cpp PShowIf.h PWidgetWrapper.cpp PWidgetWrapper.h PButton.cpp PButton.h PFlowRakeRegionSelector.cpp PFlowRakeRegionSelector.h PFlowIntegrationRegionSelector.cpp PFlowIntegrationRegionSelector.h PMultiVarSelector.cpp PMultiVarSelector.h AppSettingsMenu.cpp AppSettingsMenu.h PConstantColorWidget.cpp PConstantColorWidget.h PCornerSelector.cpp PCornerSelector.h RenderEventRouterGUI.cpp RenderEventRouterGUI.h CheckForUpdate.cpp CheckForUpdate.h PDatasetTransformWidget.cpp PDatasetTransformWidget.h PCameraControlsSection.cpp PCameraControlsSection.h PProjectionStringWidget.cpp PProjectionStringWidget.h VProjectionStringFrame.cpp VProjectionStringFrame.h POutputResolutionSection.cpp POutputResolutionSection.h VLabel.cpp VLabel.h VLabelPair.cpp VLabelPair.h VHyperlink.cpp VHyperlink.h PTimestepInput.cpp PTimestepInput.h PTotalTimestepsDisplay.cpp PTotalTimestepsDisplay.h AnimationController.cpp AnimationController.h CaptureController.cpp CaptureController.h DatasetImportController.cpp DatasetImportController.h CheckForNotices.cpp CheckForNotices.h NoticeBoard.cpp NoticeBoard.h ParticleEventRouter.cpp ParticleEventRouter.h PTimestepSliderEdit.cpp PTimestepSliderEdit.h PMetadataClasses.cpp PMetadataClasses.h VVisibilityCheckbox.cpp VVisibilityCheckbox.h RendererList.cpp RendererList.h VRouter.cpp VRouter.h RenderersPanel.cpp RenderersPanel.h RendererInspector.cpp RendererInspector.h DatasetInspector.cpp DatasetInspector.h VScrollArea.cpp VScrollArea.h VScrollGroup.h NewRendererDialogManager.cpp NewRendererDialogManager.h PVisualizerSelector.cpp PVisualizerSelector.h QtVizWinGLContextManager.cpp QtVizWinGLContextManager.h common.cpp common.h Updatable.h ProgressStatusBar.h LeftPanel.cpp LeftPanel.h CLIToolInstaller.cpp CLIToolInstaller.h BookmarkManager.cpp BookmarkManager.h UCloseVDCMenu.cpp UCloseVDCMenu.h NcarCasperUtils.cpp NcarCasperUtils.h ViewpointToolbar.cpp ViewpointToolbar.h CheckForUpdateUI.cpp CheckForUpdateUI.h VRadioButton.h VRadioButton.cpp PRadioButtons.h PRadioButtons.cpp PImportDataWidget.h PImportDataWidget.cpp PImportDataButton.h PImportDataButton.cpp PTimeRangeSelector.cpp PTimeRangeSelector.h PCaptureWidget.h PCaptureWidget.cpp ImportTab.h ImportTab.cpp DatasetTypeLookup.h DatasetTypeLookup.cpp # Need to include all files that request .ui files Statistics.h Plot.h PythonVariables.h VaporTable.h FidelityWidget.h QSliderEdit.h QRange.h QSinglePoint.h MainForm.h VizWinMgr.h windowsUtils.h ErrorReporter.h GLWidget.h VizWin.h Core3_2_context.h Manip.h AnnotationEventRouter.h BannerGUI.h FlowEventRouter.h Combo.h CopyRegionWidget.h CopyRegionAnnotationWidget.h FileOperationChecker.h PlotParams.h PythonVariablesParams.h QIntValidatorWithFixup.h RangeCombos.h RenderEventRouter.h RenderHolder.h StatisticsParams.h WireFrameEventRouter.h Flags.h QMontereySlider.h CitationReminder.h QCustomIconSizeProxyStyle.h ) set (UIS NewRendererDialog.ui statsWindow.ui plotWindow.ui PythonVariablesGUI.ui FidelityWidgetGUI.ui QSliderEdit.ui QRange.ui QSinglePoint.ui ) source_group (UIs FILES ${UIS}) find_package(Qt5 REQUIRED COMPONENTS Core OpenGL Widgets Gui DBus Network) set (CMAKE_AUTOUIC ON) # This needs to appear before adding sources to work properly set (CMAKE_AUTOMOC ON) set (CMAKE_AUTORCC ON) set (CMAKE_INCLUDE_CURRENT_DIR ON) set (ASSIMP_LIB assimp) set (TIFF_LIB tiff) if (APPLE) set (SRCS ${SRCS} core_profile_attributes.mm mac_helpers.mm mac_helpers.h ) set (MACOSX_BUNDLE_GUI_IDENTIFIER Vapor3) set (MACOSX_BUNDLE_SHORT_VERSION_STRING ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}}) set (MACOSX_BUNDLE_BUNDLE_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}.${VERSION_RC}) set (MACOSX_BUNDLE_ICON_FILE VAPOR.icns) set (MACOSX_BUNDLE_ICON_FILE_PATH ${CMAKE_SOURCE_DIR}/share/images/VAPOR.icns) set_source_files_properties(${MACOSX_BUNDLE_ICON_FILE_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") add_executable (vapor MACOSX_BUNDLE ${MACOSX_BUNDLE_ICON_FILE_PATH} ${SRCS} ${UIS}) set (INSTALL_BIN_DIR ".") elseif (WIN32) set (ASSIMP_LIB assimp-vc140-mt) set (TIFF_LIB libtiff) set (WINDOWS_ICON_PATH "${CMAKE_SOURCE_DIR}/share/images/vapor-win-icon.ico") configure_file (vapor.rc.in ${CMAKE_CURRENT_BINARY_DIR}/vaporgui.rc) add_executable (vapor WIN32 ${SRCS} ${UIS} ${CMAKE_CURRENT_BINARY_DIR}/vaporgui.rc) else () add_executable (vapor ${SRCS} ${UIS}) endif() target_link_libraries ( vapor common vdc wasp render params jpeg ${TIFF_LIB} geotiff ${ASSIMP_LIB} Qt5::Widgets Qt5::OpenGL Qt5::Core Qt5::Gui Qt5::DBus Qt5::Network ${Python_LIBRARIES} ) if (APPLE) find_library (CORESERVICES CoreServices) find_library (FOUNDATION Foundation) find_library (COCOA Cocoa) # target_link_libraries (vapor "-framework CoreServices") target_link_libraries (vapor ${CORESERVICES} ${FOUNDATION} ${COCOA}) elseif (UNIX AND NOT APPLE) target_link_libraries (vapor quadmath) target_compile_options(vapor PRIVATE -Wno-conversion-null) target_link_options(vapor PRIVATE "LINKER:--no-as-needed") endif () OpenMPInstall ( TARGETS vapor DESTINATION ${INSTALL_BIN_DIR} COMPONENT vaporgui ) ================================================ FILE: apps/vaporgui/CaptureController.cpp ================================================ #include "CaptureController.h" #include #include #include #include #include "CitationReminder.h" #include "ErrorReporter.h" #include "vapor/ControlExecutive.h" #include "vapor/AnimationParams.h" #include "vapor/GUIStateParams.h" #include "vapor/FileUtils.h" #include "vapor/STLUtils.h" const std::string TiffStrings::FileFilter = "TIFF (*.tif)"; const std::string TiffStrings::FileSuffix = "tif"; const std::string PngStrings::FileFilter = "PNG (*.png)"; const std::string PngStrings::FileSuffix = "png"; CaptureController::CaptureController(VAPoR::ControlExec *ce) : _ce(ce) {} std::string CaptureController::GetCaptureFileName() { ShowCitationReminder(); auto *ap = _ce->GetParams(); std::string filter = ap->GetValueLong(AnimationParams::CaptureTypeTag, AnimationParams::TIFF) == false ? TiffStrings::FileFilter : PngStrings::FileFilter; std::string suffix = ap->GetValueLong(AnimationParams::CaptureTypeTag, AnimationParams::TIFF) == false ? TiffStrings::FileSuffix : PngStrings::FileSuffix; std::string defaultPath = ap->GetValueString(AnimationParams::CaptureFileDirTag, FileUtils::HomeDir()); // - For this QFileDialog, QFileDialog::DontConfirmOverwrite is needed because we do file overwrite confirmation // manually after modifying the user's input filename for capturing time series // // - QFileDialog::DontUseNativeDialog is needed becuase QFileDialog::DontConfirmOverwrite will not work on MacOS without it // std::string file = QFileDialog::getSaveFileName(nullptr, "Select Filename", QString::fromStdString(defaultPath), QString::fromStdString(filter), nullptr, QFileDialog::DontConfirmOverwrite | QFileDialog::DontUseNativeDialog).toStdString(); if (file.empty()) return ""; // Qt does not always append the filetype to the selection from the QFileDialog, so manually add it if this happens if (file.find(suffix) == std::string::npos) file += "." + suffix; // Add zero padding if we are capturing TimeSeries if (ap->GetValueLong(AnimationParams::CaptureModeTag, AnimationParams::SingleImage) == AnimationParams::TimeSeries) { std::ostringstream oss; oss << FileUtils::RemoveExtension(FileUtils::Basename(file)) << std::setw(5) << std::setfill('0') << "." << FileUtils::Extension(file); file = FileUtils::JoinPaths({FileUtils::Dirname(file), oss.str()}); } // Warn user about overwriting file if (FileUtils::Exists(file)) { QMessageBox::StandardButton confirm = QMessageBox::question(nullptr, "File exists", QString::fromStdString(FileUtils::Basename(file) + " exists. Overwrite?"), QMessageBox::Yes | QMessageBox::No); if (confirm == QMessageBox::No) return ""; } ap->SetValueString(AnimationParams::CaptureFileDirTag, "Capture animation file directory", FileUtils::Dirname(file)); if (ap->GetValueLong(AnimationParams::CaptureModeTag, AnimationParams::SingleImage) == AnimationParams::SingleImage) { ap->SetValueString(AnimationParams::CaptureFileNameTag, "Capture animation file name", FileUtils::Basename(file)); ap->SetValueString(AnimationParams::CaptureFileTimeTag, "Capture file time", STLUtils::GetCurrentDateTimestamp()); } else { ap->SetValueString(AnimationParams::CaptureTimeSeriesFileNameTag, "Capture animation file name", FileUtils::Basename(file)); ap->SetValueString(AnimationParams::CaptureTimeSeriesTimeTag, "Capture file time", STLUtils::GetCurrentDateTimestamp()); } return file; } bool CaptureController::EnableAnimationCapture(std::string baseFile) { if (baseFile.empty()) baseFile = GetCaptureFileName(); if (baseFile.empty()) return false; string vizName = _ce->GetParams()->GetActiveVizName(); bool rc = _ce->EnableAnimationCapture(vizName, true, baseFile) >= 0; if (rc) emit captureStarted(); return rc; } void CaptureController::CaptureSingleImage() { std::string filePath = GetCaptureFileName(); if (filePath.empty()) return; string vizName = _ce->GetParams()->GetActiveVizName(); if (_ce->EnableImageCapture(filePath, vizName) < 0) MSG_ERR("Error capturing image"); } void CaptureController::EndAnimationCapture() { string vizName = _ce->GetParams()->GetActiveVizName(); if (_ce->EnableAnimationCapture(vizName, false)) MSG_WARN("Image Capture Warning; active visualizer not capturing images"); } void CaptureController::ShowCitationReminder() { #ifndef NDEBUG return; #endif static bool askForCitation = true; if (!askForCitation) return; askForCitation = false; CitationReminder::Show(); } ================================================ FILE: apps/vaporgui/CaptureController.h ================================================ #pragma once #include #include namespace VAPoR { class ControlExec; } struct TiffStrings { static const std::string FileFilter; static const std::string FileSuffix; }; struct PngStrings { static const std::string FileFilter; static const std::string FileSuffix; }; class CaptureController : public QObject { Q_OBJECT VAPoR::ControlExec *_ce; public: explicit CaptureController(VAPoR::ControlExec *ce); std::string GetCaptureFileName(); bool EnableAnimationCapture(std::string baseFile = ""); void CaptureSingleImage(); void EndAnimationCapture(); void ShowCitationReminder(); signals: void captureStarted(); }; ================================================ FILE: apps/vaporgui/CheckForNotices.cpp ================================================ #include "CheckForNotices.h" #include #include #include #include #include #include #include #include #include #include #include #include using std::cout; using std::endl; using std::function; using std::string; using Wasp::Version; void CheckForGHNotices(std::function &)> callback) { static QNetworkAccessManager * manager = nullptr; static std::function &)> _callback; static std::vector _notices; static std::stack _noticesToGet; _callback = callback; if (!manager) { manager = new QNetworkAccessManager; QObject::connect(manager, &QNetworkAccessManager::finished, manager, [&](QNetworkReply *reply) { if (reply->error()) { #ifndef NDEBUG printf("%s\n", reply->errorString().toStdString().c_str()); #endif return; } #ifdef TESTING_API if (STLUtils::Contains(reply->url().toString().toStdString(), "list.json")) { #else if (STLUtils::Contains(reply->url().toString().toStdString(), "api.github.com")) { #endif _notices.clear(); _noticesToGet = {}; QString content = reply->readAll(); QJsonDocument json = QJsonDocument::fromJson(content.toUtf8()); QJsonArray array = json.array(); for (const QJsonValue value : array) { QJsonObject file = value.toObject(); Notice notice; notice.url = file["download_url"].toString().toStdString(); if (STLUtils::Contains(notice.url, "__example-notice")) continue; _noticesToGet.push(notice); } } else { QString content = reply->readAll(); QJsonObject json = QJsonDocument::fromJson(content.toUtf8()).object(); #define TIME_FORMAT "yyyy-MM-dd" Notice notice; notice.url = reply->url().toString().toStdString(); notice.content = json["content"].toString().toStdString(); notice.date = QDate::fromString(json["date"].toString(), TIME_FORMAT); notice.until = QDate::fromString(json["until"].toString(), TIME_FORMAT); auto now = QDate::currentDate(); if (notice.date <= now && notice.until >= now) _notices.push_back(notice); } if (_noticesToGet.empty()) { sort(_notices.begin(), _notices.end(), [](const Notice &a, const Notice &b) { return a.date > b.date; }); _callback(_notices); } else { QNetworkRequest req; req.setUrl(QUrl(QString::fromStdString(_noticesToGet.top().url))); _noticesToGet.pop(); manager->get(req); } }); } QNetworkRequest req; #ifdef TESTING_API req.setUrl(QUrl("http://localhost:8000/list.json")); #else req.setUrl(QUrl("https://api.github.com/repos/NCAR/VAPOR-SupportPage/contents/notices")); #endif manager->get(req); } ================================================ FILE: apps/vaporgui/CheckForNotices.h ================================================ #pragma once #include #include #include #include struct Notice { std::string url; std::string content; QDate date; QDate until; }; //! Uses the GitHub API to check for any notices which are json files on the main branch in share/notices. //! There is an example file there which specifies the format and features. void CheckForGHNotices(std::function &)> callback); ================================================ FILE: apps/vaporgui/CheckForUpdate.cpp ================================================ #include "CheckForUpdate.h" #include #include #include #include #include #include #include #include #include #include using std::cout; using std::endl; using std::function; using std::string; using Wasp::Version; void CheckForUpdate(function callback) { static QNetworkAccessManager * manager = nullptr; static function _callback; _callback = callback; if (!manager) { manager = new QNetworkAccessManager; QObject::connect(manager, &QNetworkAccessManager::finished, manager, [&](QNetworkReply *reply) { if (reply->error()) { #ifndef NDEBUG printf("%s\n", reply->errorString().toStdString().c_str()); #endif UpdateInfo info; info.error = true; _callback(false, info); return; } string currentVersion = Version::GetVersionString(); bool updateAvailable = false; UpdateInfo info; QString content = reply->readAll(); QJsonDocument json = QJsonDocument::fromJson(content.toUtf8()); QJsonArray array = json.array(); for (const QJsonValue value : array) { QJsonObject release = value.toObject(); bool preRelease = release["prerelease"].toBool(); info.version = release["tag_name"].toString().toStdString(); info.url = release["html_url"].toString().toStdString(); updateAvailable = !preRelease && Version::Compare(currentVersion, info.version) < 0; if (updateAvailable) break; } _callback(updateAvailable, info); }); } QNetworkRequest req; #ifdef TESTING_API req.setUrl(QUrl("http://localhost:8000/api.json")); #else req.setUrl(QUrl("https://api.github.com/repos/NCAR/VAPOR/releases")); #endif manager->get(req); } void UpdateInfo::OpenURL() { QDesktopServices::openUrl(QUrl(QString::fromStdString(url))); } ================================================ FILE: apps/vaporgui/CheckForUpdate.h ================================================ #pragma once #include #include class QNetworkAccessManager; struct UpdateInfo { std::string version; std::string url; bool error = false; void OpenURL(); }; //! Uses the GitHub API to check Vapor's latest release version and compares it against the current version. If an update //! is available, info will be populated. void CheckForUpdate(std::function callback); ================================================ FILE: apps/vaporgui/CheckForUpdateUI.cpp ================================================ #include "CheckForUpdateUI.h" #include "CheckForUpdate.h" #include #include #include #include #include void CheckForAndShowUpdate(ControlExec *ce) { #ifndef NDEBUG return; // Don't check for updates in debug builds #endif CheckForUpdate([ce](bool updateAvailable, UpdateInfo info) { if (!updateAvailable) return; QCheckBox *cb = new QCheckBox("Automatically check for updates"); cb->setChecked(true); QMessageBox popup; popup.setText(QString::fromStdString("A newer version of Vapor is available: " + info.version)); QPushButton *get = popup.addButton("Get Latest Version", QMessageBox::ActionRole); popup.addButton("Ok", QMessageBox::AcceptRole); popup.setCheckBox(cb); popup.exec(); if (popup.clickedButton() == get) info.OpenURL(); if (!cb->isChecked()) { ce->GetParams()->SetValueLong(SettingsParams::AutoCheckForUpdatesTag, "", false); ce->GetParams()->SaveSettings(); } }); } ================================================ FILE: apps/vaporgui/CheckForUpdateUI.h ================================================ #pragma once #include void CheckForAndShowUpdate(ControlExec *ce); ================================================ FILE: apps/vaporgui/CitationReminder.h ================================================ #pragma once #include class CitationReminder { public: static void Show() { QMessageBox msgBox; QString reminder("VAPOR is developed as an Open Source application by NCAR, "); reminder.append("under the sponsorship of the National Science Foundation.\n\n"); reminder.append("We depend on evidence of the software's value to the scientific community. "); reminder.append("You are free to use VAPOR as permitted under the terms and conditions of the licence.\n\n "); reminder.append("Please cite VAPOR in your publications and presentations. "); reminder.append("Citation details:\n https://www.vapor.ucar.edu/pages/vaporCitationPage.html"); msgBox.setText(reminder); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.exec(); } }; ================================================ FILE: apps/vaporgui/Combo.cpp ================================================ ////////////////////////////////////////////////////// // // Combo // ////////////////////////////////////////////////////// #include "Combo.h" #include #include #include "vapor/VAssert.h" Combo::Combo(QLineEdit *edit, QSlider *slider, bool intType) { _minValid = 0.0; _maxValid = 1.0; _value = _minValid; _intType = intType; _floatPrecision = 6; // 6 is default in QT _lineEdit = NULL; _lineEditValidator = NULL; _slider = NULL; _lineEdit = edit; if (_intType) _lineEditValidator = new QIntValidator(this); else _lineEditValidator = new QDoubleValidator(this); _lineEdit->setValidator(_lineEditValidator); // Set up slot for changes to _lineEdit // connect(_lineEdit, SIGNAL(returnPressed()), this, SLOT(setLineEdit())); _slider = slider; _slider->setFocusPolicy(Qt::StrongFocus); _slider->setSingleStep(1); _slider->setMinimum(0); _slider->setMaximum(999); _slider->setTracking(true); // Get bizzare double sliders without this // Set up slot for changes to _slider // connect(_slider, SIGNAL(sliderReleased()), this, SLOT(setSlider())); // update values displayed in the _lineEdit without incurring any state upate. connect(_slider, SIGNAL(sliderMoved(int)), this, SLOT(setSliderMini(int))); // This is the aggregate slot that is fired when either the _slider // or the _lineEdit object change value // connect(this, SIGNAL(valueChanged(double)), this, SLOT(SetSliderLineEdit(double))); } void Combo::Update(double min, double max, double value) { // Make sure all parameters are valid. If not make them valid // // Should we issue a signal to notify the change of input // parameters? // if (min >= max) max = min; if (value < min) value = min; if (value > max) value = max; _minValid = min; _maxValid = max; _value = value; // Update validator // // Note: The QDoubleValidator has unexpected behavior and permits // values outside of the the valid range. Possible to options to correct // this are: // // 1. Subclass QDoubleValidator to perform the expected behavior // 2. Use QDoubleValidator only to ensure that input is a double, // and perform range checking inside the slot for returnPressed() // // Currently we use option (2) // Update the GUI to reflect the new values // bool oldState = _lineEdit->blockSignals(true); if (_intType) { _lineEdit->setText(QString::number((int)value)); } else { _lineEdit->setText(QString::number(value, 'g', _floatPrecision)); } _lineEdit->blockSignals(oldState); int pos = 0; if (_minValid != _maxValid) { pos = (int)(((value - _minValid) / (_maxValid - _minValid)) * (_slider->maximum() - _slider->minimum()) + _slider->minimum()); } oldState = _slider->blockSignals(true); _slider->setSliderPosition(pos); _slider->blockSignals(oldState); } void Combo::SetEnabled(bool on) { _lineEdit->setEnabled(on); _slider->setEnabled(on); } void Combo::setLineEdit() { double value = _lineEdit->text().toDouble(); // The Qt QDoubleValidator class doesn't work as expected. Values // outside of valid range (set with setTop() and setBottom()) do not // trigger the returnPressed() slot, but the QLineEdit will still // display the out-of-range value. Below, we force out of range // values to be in range, and update the GUI to reflect the valid value // if (value < _minValid) { value = _minValid; if (_intType) { _lineEdit->setText(QString::number((int)value)); } else { _lineEdit->setText(QString::number(value, 'g', _floatPrecision)); } } if (value > _maxValid) { value = _maxValid; if (_intType) { _lineEdit->setText(QString::number((int)value)); } else { _lineEdit->setText(QString::number(value, 'g', _floatPrecision)); } } if (value == _value) return; _value = value; if (_intType) { emit valueChanged((int)value); } else { emit valueChanged(value); } } void Combo::setSlider() { int pos = _slider->sliderPosition(); int min = _slider->minimum(); int max = _slider->maximum(); VAssert(min <= pos && max >= pos); double value = ((double)(pos - min) / (double)(max - min)) * (_maxValid - _minValid) + _minValid; if (value == _value) return; _value = value; if (_intType) { emit valueChanged((int)value); } else { emit valueChanged(value); } } // This mini version only changes the values displayed in _lineEdit, // but not emit any other signals. void Combo::setSliderMini(int pos) { int min = _slider->minimum(); int max = _slider->maximum(); VAssert(min <= pos && max >= pos); double value = ((double)(pos - min) / (double)(max - min)) * (_maxValid - _minValid) + _minValid; bool oldState = _lineEdit->blockSignals(true); if (_intType) _lineEdit->setText(QString::number((int)value)); else _lineEdit->setText(QString::number(value, 'g', _floatPrecision)); _lineEdit->blockSignals(oldState); } void Combo::SetSliderLineEdit(double value) { // Update the class with the current min and max valid values, // and the new value // Update(_minValid, _maxValid, value); } void Combo::SetPrecision(int precision) { if (precision > 0) _floatPrecision = precision; } void Combo::SetIntType(bool val) { if (val != _intType) { _intType = val; delete _lineEditValidator; if (_intType) _lineEditValidator = new QIntValidator(this); else _lineEditValidator = new QDoubleValidator(this); _lineEdit->setValidator(_lineEditValidator); } } ================================================ FILE: apps/vaporgui/Combo.h ================================================ #ifndef COMBO_H #define COMBO_H #include #include #include #include // Fix for Qt bug https://bugreports.qt.io/browse/QTBUG-98093 // Apply a style sheet to QSlider to make it work on OSX Monterey #ifdef Darwin #include "QMontereySlider.h" #define QSlider QMontereySlider #endif // class Combo // // Manages a paired QSlider and QLineEdit class, synchronizing values // across both such that a single value is represented. The value // must be within a specified range. // class Combo : public QWidget { Q_OBJECT public: Combo(QLineEdit *edit, QSlider *slider, bool intType = false); // This method must be called whenever the minimax or maximum allowable // valid value changes, or the current value // is changed externally. I.e. Update() provides a means to change // the internal state of the class. If minValid > maxValid, maxValid // will be set to minValid. If value is outside of minValid and maxValid // it will be set to minValid. // void Update(double minValid, double maxValid, double value); void Update(double value) { Update(_minValid, _maxValid, value); } // Returns a pointer the QSlider object // QSlider *GetSlider() const { return (_slider); }; // Returns a pointer the QLineEdit object // QLineEdit *GetLineEdit() const { return (_lineEdit); }; // Returns the currently set value // double GetValue() const { return (_value); }; // Set how many digits to show for floating-point precision // This setting won't change anything for displaying integers. // The input precision value should be at least 1. // void SetPrecision(int precision); // switch IntType void SetIntType(bool); void SetEnabled(bool); private slots: // Slot for QLineEdit events // void setLineEdit(); // Slot for QSlider events // void setSlider(); void setSliderMini(int pos); public slots: // Public slot for changing the class's value // void SetSliderLineEdit(double); signals: // This signal is emitted whenever the value of the class changes // void valueChanged(double value); void valueChanged(int value); private: double _minValid; double _maxValid; double _value; bool _intType; int _floatPrecision; // how many digits after the decimal point? QLineEdit * _lineEdit; QValidator *_lineEditValidator; QSlider * _slider; }; #endif ================================================ FILE: apps/vaporgui/ContourEventRouter.cpp ================================================ #include "ContourEventRouter.h" #include "vapor/ContourParams.h" #include "PWidgets.h" #include "PSliderEditHLI.h" #include "PConstantColorWidget.h" #include "PSliceController.h" #include "PMetadataClasses.h" using namespace VAPoR; typedef ContourParams CP; static RenderEventRouterRegistrar registrar(ContourEventRouter::GetClassType()); ContourEventRouter::ContourEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, ContourParams::GetClassType()) { // clang-format off AddVariablesSubtab(new PGroup({ new PSection("Variable Selection", { new PDimensionSelector, new PScalarVariableSelector, new PHeightVariableSelector, }), new PFidelitySection, new POpenVariableMetadataWidget })); AddAppearanceSubtab(new PGroup({ new PTFEditor(RenderParams::_variableNameTag, { PTFEditor::Default, PTFEditor::RegularIsoArray }), new PSection("Contour Lines", { _spacingSlider = new PDoubleSliderEditHLI("Spacing", &CP::GetContourSpacing, &CP::SetContourSpacing), (new PIntegerSliderEditHLI("Count", &CP::GetContourCount, &CP::SetContourCount))->SetRange(1, 50), _minValueSlider = new PDoubleSliderEditHLI("Minimum Value", &CP::GetContourMin, &CP::SetContourMin), new PConstantColorWidget }), (new PShowIf(""))->DimensionEquals(3)->Then(new PGroup({ new PSection("Slice", { (new PDoubleSliderEdit(RenderParams::SampleRateTag, "N Samples"))->SetRange(32, 2000) }) })), new PCheckbox(RenderParams::DrawInFrontTag, "Draw renderer in front") })); AddGeometrySubtab(new PGroup({ (new PShowIf(""))->DimensionEquals(3)->Then(new PGroup({ new PSliceController })), new PGeometrySubtab, })); AddColorbarSubtab(new PAnnotationColorbarWidget); // clang-format on } void ContourEventRouter::Update() { RenderParams *rp = GetActiveParams(); string varname = rp->GetVariableName(); size_t ts = rp->GetCurrentTimestep(); int level = rp->GetRefinementLevel(); int lod = rp->GetCompressionLevel(); CoordType minExt = {0.0, 0.0, 0.0}; CoordType maxExt = {0.0, 0.0, 0.0}; rp->GetBox()->GetExtents(minExt, maxExt); vector dataExts(2, 0); GetActiveDataMgr()->GetDataRange(ts, varname, level, lod, minExt, maxExt, dataExts); _spacingSlider->SetRange(0, dataExts[1] - dataExts[0]); _minValueSlider->SetRange(dataExts[0], dataExts[1]); RenderEventRouterGUI::Update(); } string ContourEventRouter::_getDescription() const { return ("Displays " "a series of user defined contours along a two dimensional plane within the " "user's domain.\n\nContours may hae constant coloration, or may be colored " "according to a secondary variable.\n\nContours may be displaced by a height " "variable.\n\n "); } ================================================ FILE: apps/vaporgui/ContourEventRouter.h ================================================ #pragma once #include "RenderEventRouterGUI.h" #include "vapor/ContourRenderer.h" class PDoubleSliderEdit; //! \class ContourEventRouter //! \ingroup Public_GUI //! \brief Contour renderer GUI //! \author Stas Jaroszynski class ContourEventRouter : public RenderEventRouterGUI { public: ContourEventRouter(QWidget *parent, VAPoR::ControlExec *ce); bool Supports2DVariables() const { return true; } bool Supports3DVariables() const { return true; } static string GetClassType() { return VAPoR::ContourRenderer::GetClassType(); } string GetType() const { return GetClassType(); } void Update(); protected: virtual string _getDescription() const; string _getSmallIconImagePath() const { return "Contours_small.png"; } string _getIconImagePath() const { return "Contours.png"; } private: PDoubleSliderEdit *_spacingSlider; PDoubleSliderEdit *_minValueSlider; }; ================================================ FILE: apps/vaporgui/CopyRegionAnnotationWidget.cpp ================================================ #include #include #include #include "vapor/Renderer.h" #include "vapor/ParamsMgr.h" #include "vapor/RenderParams.h" #include #include "vapor/DataMgrUtils.h" #include #include "CopyRegionAnnotationWidget.h" #include "VLineItem.h" #define X 0 #define Y 1 #define Z 2 using namespace VAPoR; namespace { template void split(const std::string &s, char delim, Out result) { std::stringstream ss; ss.str(s); std::string item; while (std::getline(ss, item, delim)) { *(result++) = item; } } std::vector split(const std::string &s, char delim) { std::vector elems; split(s, delim, std::back_inserter(elems)); return elems; } } // namespace CopyRegionAnnotationWidget::CopyRegionAnnotationWidget(VAPoR::ControlExec *ce) : CopyRegionWidget() { _controlExec = ce; } void CopyRegionAnnotationWidget::Update() { _paramsMgr = _controlExec->GetParamsMgr(); VAssert(_paramsMgr); updateCopyCombo(); } void CopyRegionAnnotationWidget::copyRegion() { string copyString = copyCombo->currentText().toStdString(); if (copyString != "") { std::vector elems = split(copyString, ':'); string visualizer = _visNames[elems[0]]; string dataSetName = elems[1]; string renType = _renTypeNames[elems[2]]; string renderer = elems[3]; RenderParams *copyParams = _paramsMgr->GetRenderParams(visualizer, dataSetName, renType, renderer); VAssert(copyParams); Box * copyBox = copyParams->GetBox(); std::vector minExtentsVec, maxExtentsVec; copyBox->GetExtents(minExtentsVec, maxExtentsVec); CoordType minExtents = {0.0, 0.0, 0.0}; CoordType maxExtents = {0.0, 0.0, 0.0}; Grid::CopyToArr3(minExtentsVec, minExtents); Grid::CopyToArr3(maxExtentsVec, maxExtents); AnnotationParams *a = _paramsMgr->GetAnnotationParams(visualizer); AxisAnnotation * aa = a->GetAxisAnnotation(); AnimationParams *aParams = dynamic_cast(_paramsMgr->GetParams(AnimationParams::GetClassType())); VAssert(aParams); int timeStep = aParams->GetCurrentTimestep(); _scaleWorldCoordsToNormalized(minExtentsVec, maxExtentsVec, timeStep); aa->SetAxisOrigin(minExtentsVec); aa->SetMinTics(minExtentsVec); aa->SetMaxTics(maxExtentsVec); emit valueChanged(); } } void CopyRegionAnnotationWidget::_scaleWorldCoordsToNormalized(std::vector &minCoords, std::vector &maxCoords, int timeStep) { VAssert(minCoords.size() == maxCoords.size()); VAPoR::CoordType minDomainExts, maxDomainExts; DataStatus * dataStatus = _controlExec->GetDataStatus(); dataStatus->GetActiveExtents(_paramsMgr, timeStep, minDomainExts, maxDomainExts); for (int i = 0; i < minCoords.size(); i++) { double minPoint = minCoords[i] - minDomainExts[i]; double maxPoint = maxCoords[i] - minDomainExts[i]; double magnitude = maxDomainExts[i] - minDomainExts[i]; minCoords[i] = minPoint / magnitude; maxCoords[i] = maxPoint / magnitude; } } ================================================ FILE: apps/vaporgui/CopyRegionAnnotationWidget.h ================================================ #pragma once #include "CopyRegionWidget.h" namespace VAPoR { class ControlExec; class RenderParams; class ParamsMgr; class DataMgr; } // namespace VAPoR class CopyRegionAnnotationWidget : public CopyRegionWidget { Q_OBJECT public: CopyRegionAnnotationWidget(VAPoR::ControlExec *ce); QString toolTip() const { return tr("A widget for copying one renderer's " "region to axis annotations"); } void Update(); protected slots: void copyRegion() override; private: void _scaleWorldCoordsToNormalized(std::vector &minExts, std::vector &maxExts, int timeStep); VAPoR::ControlExec *_controlExec; }; ================================================ FILE: apps/vaporgui/CopyRegionWidget.cpp ================================================ //************************************************************************ // * // Copyright (C) 2017 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: CopyRegionWidget.cpp // // Author: Scott Pearse // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: March 2017 // // Description: Implements the CopyRegionWidget class. This provides // a widget that is inserted in the "Appearance" tab of various Renderer GUIs // #include #include #include #include "vapor/Renderer.h" #include "vapor/ParamsMgr.h" #include "vapor/RenderParams.h" #include "vapor/DataMgrUtils.h" #include "CopyRegionWidget.h" #include "VLineItem.h" #define X 0 #define Y 1 #define Z 2 using namespace VAPoR; namespace { template void split(const std::string &s, char delim, Out result) { std::stringstream ss; ss.str(s); std::string item; while (std::getline(ss, item, delim)) { *(result++) = item; } } std::vector split(const std::string &s, char delim) { std::vector elems; split(s, delim, std::back_inserter(elems)); return elems; } } // namespace CopyRegionWidget::CopyRegionWidget(QWidget *parent) : VSectionGroup("Copy region from renderer") { Add(new VLineItem("Renderer", copyCombo = new QComboBox)); Add(new VLineItem("", copyButton = new QPushButton("Copy"))); _paramsMgr = NULL; _rParams = NULL; connect(copyButton, SIGNAL(released()), this, SLOT(copyRegion())); } CopyRegionWidget::~CopyRegionWidget() {} void CopyRegionWidget::updateCopyCombo() { copyCombo->clear(); std::vector visNames = _paramsMgr->GetVisualizerNames(); _visNames.clear(); _dataSetNames = _paramsMgr->GetDataMgrNames(); for (int i = 0; i < visNames.size(); i++) { for (int ii = 0; ii < _dataSetNames.size(); ii++) { // Create a mapping of abreviated visualizer names to their // actual string values. // string visAbb = "Vis" + std::to_string(i); _visNames[visAbb] = visNames[i]; string dataSetName = _dataSetNames[ii]; std::vector typeNames; typeNames = _paramsMgr->GetRenderParamsClassNames(visNames[i]); for (int j = 0; j < typeNames.size(); j++) { // Abbreviate Params names by removing 'Params" from them. // Then store them in a map for later reference. // string typeAbb; typeAbb = RendererFactory::Instance()->GetRenderClassFromParamsClass(typeNames[j]); _renTypeNames[typeAbb] = typeNames[j]; std::vector renNames; renNames = _paramsMgr->GetRenderParamInstances(visNames[i], _dataSetNames[ii], typeNames[j]); for (int k = 0; k < renNames.size(); k++) { string displayName = visAbb + ":" + dataSetName + ":" + typeAbb + ":" + renNames[k]; QString qDisplayName = QString::fromStdString(displayName); copyCombo->addItem(qDisplayName); } } } } } void CopyRegionWidget::_configurePlanarBox(const VAPoR::Box *myBox, std::vector *myMin, std::vector *myMax) const { VAssert((*myMin).size() == (*myMax).size()); int planarAxis; int orientation = myBox->GetOrientation(); if (orientation == Box::XY) planarAxis = Z; else if (orientation == Box::XZ) planarAxis = Y; else if (orientation == Box::YZ) planarAxis = X; else return; // If our region is planar (IE SliceRenderer), then we need to set a // reasonable Z coordinate, midway between the minimum and maximum. // If we are dealing with a 2-D variable or renderer, there is no Z // coordinate, so we don't do anything and return. if (planarAxis < Z || // Not true for TwoD, Contour, and Image renderers (*myMin).size() == 3) { double min = (*myMin)[planarAxis]; double max = (*myMax)[planarAxis]; double plane = (min + max) / 2.f; (*myMin)[planarAxis] = plane; (*myMax)[planarAxis] = plane; } } void CopyRegionWidget::copyRegion() { string copyString = copyCombo->currentText().toStdString(); if (copyString != "") { std::vector elems = split(copyString, ':'); string visualizer = _visNames[elems[0]]; string dataSetName = elems[1]; string renType = _renTypeNames[elems[2]]; string renderer = elems[3]; RenderParams *copyParams = _paramsMgr->GetRenderParams(visualizer, dataSetName, renType, renderer); VAssert(copyParams); Box * copyBox = copyParams->GetBox(); std::vector minExtents, maxExtents; copyBox->GetExtents(minExtents, maxExtents); Box * myBox = _rParams->GetBox(); std::vector myMin, myMax; myBox->GetExtents(myMin, myMax); VAssert(minExtents.size() == maxExtents.size()); VAssert(myMin.size() == myMax.size()); for (int i = 0; i < myMin.size(); i++) { myMin[i] = minExtents[i]; myMax[i] = maxExtents[i]; } _configurePlanarBox(myBox, &myMin, &myMax); myBox->SetExtents(myMin, myMax); emit valueChanged(); } } void CopyRegionWidget::Update(ParamsMgr *paramsMgr, RenderParams *rParams) { VAssert(paramsMgr); VAssert(rParams); _paramsMgr = paramsMgr; _rParams = rParams; updateCopyCombo(); } ================================================ FILE: apps/vaporgui/CopyRegionWidget.h ================================================ #ifndef COPYREGIONWIDGET_H #define COPYREGIONWIDGET_H #include #include "VSection.h" #include #include namespace VAPoR { class RenderParams; class ParamsMgr; class DataMgr; } // namespace VAPoR class CopyRegionWidget : public VSectionGroup { Q_OBJECT public: CopyRegionWidget(QWidget *parent = 0); ~CopyRegionWidget(); QString name() const { return "CopyRegionWidget"; } QString includeFile() const { return "CopyRegionWidget.h"; } QString group() const { return tr("A widget for copying one renderer's region to another"); } QString toolTip() const { return tr("A widget for copying one renderer's " "region to another"); } QString whatsThis() const { return tr("This widget contains all widgets " "necessary for copying renderer regions"); } bool isContainer() const { return true; } virtual void Update(VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams); signals: void valueChanged(); protected slots: virtual void copyRegion(); protected: QPushButton *copyButton; QComboBox * copyCombo; void updateCopyCombo(); // Configures a box to have equal minimum and maximum // extents along an axis, if the box is planar. If not, // the function returns. void _configurePlanarBox(const VAPoR::Box *myBox, std::vector *myMin, std::vector *myMax) const; VAPoR::ParamsMgr * _paramsMgr; VAPoR::RenderParams *_rParams; std::vector _dataSetNames; std::map _visNames; std::map _renTypeNames; }; #endif // COPYREGIONWIDGET_H ================================================ FILE: apps/vaporgui/Core3_2_context.h ================================================ #pragma once #include #if defined(Q_OS_MAC) #if QT_VERSION < 0x050000 && QT_VERSION >= 0x040800 // if less than 5.0.0 void *select_3_2_mac_visual(GDHandle handle, int depthBufferSize); #endif #endif struct Core3_2_context : public QGLContext { Core3_2_context(const QGLFormat &format, QPaintDevice *device) : QGLContext(format, device) {} Core3_2_context(const QGLFormat &format) : QGLContext(format) {} #if defined(Q_OS_MAC) #if QT_VERSION < 0x050000 && QT_VERSION >= 0x040800 // if less than 5.0.0 virtual void *chooseMacVisual(GDHandle handle) { return select_3_2_mac_visual(handle, this->format().depthBufferSize()); } #endif #endif }; ================================================ FILE: apps/vaporgui/DatasetImportController.cpp ================================================ #include "DatasetImportController.h" #include "ErrorReporter.h" #include "DatasetTypeLookup.h" #include "vapor/ControlExecutive.h" #include "vapor/DataStatus.h" #include "vapor/GUIStateParams.h" #include "vapor/AnimationParams.h" #include "vapor/NavigationUtils.h" #include "vapor/FileUtils.h" #include using namespace std; using namespace VAPoR; std::string DatasetImportController::GetDatasetName(ParamsMgr *pm, std::string file, DatasetExistsAction existsAction) { auto names = pm->GetDataMgrNames(); if (names.empty() || existsAction == DatasetExistsAction::AddNew) return ControlExec::MakeStringConformant(FileUtils::Basename(file)); if (existsAction == DatasetExistsAction::ReplaceFirst) return names[0]; QStringList items; items << "New Dataset"; for (auto &n : names) items << QString::fromStdString(n); bool ok; QString choice = QInputDialog::getItem(nullptr, "Load Data", "Load as new dataset or replace existing", items, 0, false, &ok); if (!ok || choice.isEmpty()) return ""; std::string name = choice.toStdString(); if (name == "New Dataset") return ControlExec::MakeStringConformant(FileUtils::Basename(file)); return name; } bool DatasetImportController::ImportDataset(ControlExec *ce, const vector &files, std::string format, DatasetExistsAction action) { ParamsMgr *pm = ce->GetParamsMgr(); pm->BeginSaveStateGroup("Import Dataset"); std::string name = GetDatasetName(pm, files[0], action); if (name.empty()) { pm->EndSaveStateGroup(); return false; } if (ce->OpenData(files, name, format) < 0) { pm->EndSaveStateGroup(); MSG_ERR("Failed to load data"); return false; } auto gsp = ce->GetParams(); gsp->InsertOpenDataSet(name, format, files); auto ds = ce->GetDataStatus(); auto ap = ce->GetParams(); ap->SetEndTimestep(ds->GetTimeCoordinates().size() - 1); if (gsp->GetValueLong(GUIStateParams::SessionNewTag, false)) { NavigationUtils::ViewAll(ce); NavigationUtils::SetHomeViewpoint(ce); gsp->SetProjectionString(ds->GetMapProjection()); } gsp->SetValueLong(GUIStateParams::SessionNewTag, "Reset SessionNewTag to false after data import", false); pm->EndSaveStateGroup(); emit datasetImported(); return true; } ================================================ FILE: apps/vaporgui/DatasetImportController.h ================================================ #pragma once #include #include #include namespace VAPoR { class ControlExec; class ParamsMgr; } class DatasetImportController : public QObject { Q_OBJECT public: enum class DatasetExistsAction { Prompt, ReplaceFirst, AddNew }; bool ImportDataset(VAPoR::ControlExec *ce, const std::vector &files, std::string format, DatasetExistsAction action); std::string GetDatasetName(VAPoR::ParamsMgr *pm, std::string file, DatasetExistsAction existsAction); signals: void datasetImported(); }; ================================================ FILE: apps/vaporgui/DatasetInspector.cpp ================================================ #include "DatasetInspector.h" #include #include #include "PTransformWidget.h" #include "VLabel.h" #include #include "PMetadataClasses.h" #include "VScrollGroup.h" using namespace VAPoR; DatasetInspector::DatasetInspector(VAPoR::ControlExec *ce) : _ce(ce) { VScrollGroup *g = new VScrollGroup; g->Add(new VSectionGroup("Info", { _name = new VLabel, _type = new VLabel, _path = new VLabel })); g->Add(new VSectionGroup("Transform", {_tw = new PTransformWidget})); addTab(_dataTab = g, "Dataset"); addTab(_metaTab = new VScrollGroup({ _metaAttrs = new VGlobalAttributeMetadataTree, _metaDims = new VDimensionMetadataTree, _metaVars = new VVariableMetadataTree, _metaCoords = new VCoordinateVariableMetadataTree, }), "Metadata"); connect(this, &QTabWidget::currentChanged, this, &DatasetInspector::Update); } void DatasetInspector::Update() { ParamsMgr *pm = _ce->GetParamsMgr(); GUIStateParams *guiParams = (GUIStateParams *)pm->GetParams(GUIStateParams::GetClassType()); ViewpointParams *vp = pm->GetViewpointParams(guiParams->GetActiveVizName()); DataStatus *dataStatus = _ce->GetDataStatus(); string dataset = guiParams->GetActiveDataset(); if (!vp || dataset.empty()) return; if (currentWidget() == _dataTab) { _name->SetText("Name: " + dataset); _type->SetText("Type: " + DatasetTypeDescriptiveName(guiParams->GetOpenDataSetFormat(dataset))); _path->SetText("Path: " + guiParams->GetOpenDataSetPaths(dataset)[0]); Transform *transform = vp->GetTransform(dataset); _tw->Update(transform); } else if (currentWidget() == _metaTab) { auto dataMgr = dataStatus->GetDataMgr(dataset); _metaAttrs->Update(guiParams, pm, dataMgr); _metaDims->Update(guiParams, pm, dataMgr); _metaVars->Update(guiParams, pm, dataMgr); _metaCoords->Update(guiParams, pm, dataMgr); } } std::string DatasetInspector::DatasetTypeDescriptiveName(std::string type) { if (type == "vdc") return "VDC"; if (type == "wrf") return "WRF-ARW"; if (type == "cf") return "NetCDF-CF"; if (type == "mpas") return "MPAS"; if (type == "bov") return "Brick of Values (BOV)"; if (type == "dcp") return "Data Collection Particles (DCP)"; if (type == "ugrid") return "Unstructured Grid (UGRID)"; return type; } ================================================ FILE: apps/vaporgui/DatasetInspector.h ================================================ #pragma once #include "VSection.h" namespace VAPoR { class ControlExec; } class PTransformWidget; class VLabel; class QTreeWidget; class VMetadataTree; class DatasetInspector : public QTabWidget { Q_OBJECT VAPoR::ControlExec *_ce; QWidget *_dataTab, *_metaTab; PTransformWidget *_tw; VLabel *_name, *_type, *_path; VMetadataTree *_metaAttrs, *_metaDims, *_metaVars, *_metaCoords; public: DatasetInspector(VAPoR::ControlExec *ce); void Update(); static std::string DatasetTypeDescriptiveName(std::string type); }; ================================================ FILE: apps/vaporgui/DatasetTypeLookup.cpp ================================================ #include "DatasetTypeLookup.h" #include "vapor/ParamsBase.h" namespace { const std::vector> datasets = { { "wrf" , "WRF-ARW" }, { "cf" , "NetCDF-CF" }, { "bov" , "Brick of Values (BOV)" }, { "dcp" , "Data Collection Particles (DCP)" }, { "mpas" , "MPAS" }, { "ugrid" , "Unstructured Grid (UGRID)" }, { "vdc" , "VDC" } }; } const std::vector>& GetDatasets() { return datasets; } std::vector GetDatasetTypeDescriptions() { std::vector descriptions; for (const auto& pair : datasets) descriptions.push_back(pair.second); return descriptions; } std::string DatasetTypeDescriptiveName(const std::string& type) { auto it = std::find_if(datasets.begin(), datasets.end(), [&type](const auto& pair) { return pair.first==type; }); return (it != datasets.end()) ? it->second : "No description for given data type " + type ; } std::string DatasetTypeShortName(const std::string& descriptiveName) { auto it = std::find_if(datasets.begin(), datasets.end(), [&descriptiveName](const auto& pair) { return pair.second==descriptiveName; }); return (it != datasets.end()) ? it->first : "No shortName for given description " + descriptiveName; } ================================================ FILE: apps/vaporgui/DatasetTypeLookup.h ================================================ #pragma once #include #include const std::vector>& GetDatasets(); std::vector GetDatasetTypeDescriptions(); std::string DatasetTypeDescriptiveName(const std::string& type); std::string DatasetTypeShortName(const std::string& descriptiveName); ================================================ FILE: apps/vaporgui/ErrorReporter.cpp ================================================ //************************************************************************ // * // Copyright (C) 2017 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************ // // File: ErrorReporter.cpp // // Author: Stas Jaroszynski (stasj@ucar.edu) // National Center for Atmospheric Research // 1850 Table Mesa Drive // PO 3000, Boulder, Colorado // // Date: July 2017 // // Description: Implements the ErrorReporter class #include #include #include #include #if !defined(WIN32) #include #include #endif #if defined(Darwin) #include #elif defined(linux) #include #elif defined(WIN32) #include #endif #include #include #include #include #include #include #include "vapor/MyBase.h" #include "vapor/Version.h" #include "ErrorReporter.h" #include "MainForm.h" using std::string; using std::vector; ErrorReporter *ErrorReporter::_instance = NULL; void _segFaultHandler(int sig) { string details; #if !defined(WIN32) void * array[128]; size_t size; size = backtrace(array, 128); backtrace_symbols_fd(array, size, STDERR_FILENO); char **backtrace_str = backtrace_symbols(array, 128); for (int i = 0; i < size; i++) { if (strlen(backtrace_str[i]) == 0) break; details += string(backtrace_str[i]) + "\n"; } #endif ErrorReporter::Report("A memory error occured", ErrorReporter::Error, details); exit(1); } void _myBaseErrorCallback(const char *msg, int err_code) { ErrorReporter *e = ErrorReporter::GetInstance(); e->_log.push_back(ErrorReporter::Message(ErrorReporter::Error, string(msg), err_code)); e->_fullLog.push_back(ErrorReporter::Message(ErrorReporter::Error, string(msg), err_code)); if (e->_logFile) { fprintf(e->_logFile, "Error[%i]: %s\n", err_code, msg); } } void _myBaseDiagCallback(const char *msg) { ErrorReporter *e = ErrorReporter::GetInstance(); e->_fullLog.push_back(ErrorReporter::Message(ErrorReporter::Diagnostic, string(msg))); if (e->_logFile) { fprintf(e->_logFile, "Diagnostic: %s\n", msg); } } #define ErrorReporterPopup_OK_BUTTON_TEXT "Ok" #define ErrorReporterPopup_SAVE_BUTTON_TEXT "Save Log" ErrorReporterPopup::ErrorReporterPopup(QWidget *parent, int id, bool fatal) : QMessageBox(parent), dead(false), fatal(fatal) { addButton(ErrorReporterPopup_OK_BUTTON_TEXT, QMessageBox::AcceptRole); addButton(ErrorReporterPopup_SAVE_BUTTON_TEXT, QMessageBox::ApplyRole); setText("An error has occured"); connect(this, SIGNAL(buttonClicked(QAbstractButton *)), this, SLOT(doAction(QAbstractButton *))); } void ErrorReporterPopup::doAction(QAbstractButton *button) { dead = true; if (ErrorReporterPopup_SAVE_BUTTON_TEXT == button->text().toStdString()) { QString fileName = QFileDialog::getSaveFileName(NULL, "Save Error Log", QString(), "Text (*.txt);;All Files (*)"); if (fileName.isEmpty()) { return; } else { QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { QMessageBox::information(NULL, "Unable to open file", file.errorString()); return; } QTextStream out(&file); out << QString(_logText.c_str()); } } else if (ErrorReporterPopup_OK_BUTTON_TEXT == button->text().toStdString()) { } else { printf("Unknown ErrorReporterPopup button pressed: [%s]\n", button->text().toStdString().c_str()); } if (fatal) exit(1); } void ErrorReporterPopup::setLogText(std::string text) { _logText = text; } void ErrorReporter::ShowErrors() { Report(ERRORREPORTER_DEFAULT_MESSAGE); } void ErrorReporter::Report(string msg, Type severity, string details) { ErrorReporter *e = GetInstance(); if (e->_logFile) { fprintf(e->_logFile, "Report[%i]: %s\n%s\n", (int)severity, msg.c_str(), details.c_str()); } for (int i = 0; i < e->_boxes.size(); i++) { if (e->_boxes[i]->isDead()) { delete e->_boxes[i]; e->_boxes.erase(e->_boxes.begin() + i); i--; } } static int i = 0; ErrorReporterPopup *box = new ErrorReporterPopup(e->_parent, i++, severity == Fatal); e->_boxes.push_back(box); box->setInformativeText(msg.c_str()); if (details == "") { while (e->_log.size()) { details += e->_log.back().value + "\n"; if (e->_log.back().type > severity) severity = e->_log.back().type; e->_log.pop_back(); } } const string sysInfo = GetSystemInformation(); details += "------------------\n"; details += sysInfo + "\n"; box->setDetailedText(details.c_str()); switch (severity) { case Diagnostic: case Info: box->setIcon(QMessageBox::Information); break; case Warning: box->setIcon(QMessageBox::Warning); break; case Fatal: case Error: box->setIcon(QMessageBox::Critical); break; } string logText; logText = sysInfo + "\n"; logText += "-------------------\n"; logText += msg + "\n"; logText += "-------------------\n"; logText += details; box->setLogText(logText); box->show(); // This will immediately return } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" string ErrorReporter::GetSystemInformation() { string ret = "Vapor " + Wasp::Version::GetFullVersionString() + "\n"; #if defined(Darwin) SInt32 major, minor, rev; Gestalt(gestaltSystemVersionMajor, &major); Gestalt(gestaltSystemVersionMinor, &minor); Gestalt(gestaltSystemVersionBugFix, &rev); ret += "OS: Mac OS X " + to_string(major) + "." + to_string(minor) + "." + to_string(rev) + "\n"; #elif defined(linux) struct utsname info; uname(&info); ret += "OS: " + string(info.sysname) + " " + string(info.release) + " " + string(info.version) + "\n"; ret += "Distro:\n"; char buffer[128]; FILE *pipe = popen("lsb_release", "r"); if (pipe) { while (!feof(pipe)) { if (fgets(buffer, 128, pipe) != 0) { ret += string(buffer); } } pclose(pipe); } else { fprintf(stderr, "popen failed\n"); } #elif defined(WIN32) DWORD version = 0; DWORD major = 0; DWORD minor = 0; DWORD build = 0; version = GetVersion(); major = (DWORD)(LOBYTE(LOWORD(version))); minor = (DWORD)(HIBYTE(LOWORD(version))); if (version < 0x80000000) { build = (DWORD)(HIWORD(version)); } ret += "OS: Windows " + to_string(major) + "." + to_string(minor) + " (" + to_string(build) + ")\n"; #else return "Unsupported Platform"; #endif return ret; } #pragma GCC diagnostic pop int ErrorReporter::OpenLogFile(std::string path) { ErrorReporter *e = ErrorReporter::GetInstance(); e->_logFilePath = path; e->_logFile = fopen(path.c_str(), "w"); if (!e->_logFile) { Wasp::MyBase::SetErrMsg(errno, "Failed to open log file \"%s\"", path.c_str()); return -1; } return 0; } ErrorReporter *ErrorReporter::GetInstance() { if (!_instance) _instance = new ErrorReporter(MainForm::Instance()); return _instance; } ErrorReporter::ErrorReporter(QWidget *parent) { VAssert(parent != NULL); if (_instance) return; _parent = parent; _instance = this; signal(SIGSEGV, _segFaultHandler); Wasp::MyBase::SetErrMsgCB(_myBaseErrorCallback); Wasp::MyBase::SetDiagMsgCB(_myBaseDiagCallback); _logFilePath = ""; _logFile = NULL; } ErrorReporter::~ErrorReporter() { if (_logFile) fclose(_logFile); for (int i = 0; i < _boxes.size(); i++) delete _boxes[i]; } ================================================ FILE: apps/vaporgui/ErrorReporter.h ================================================ //************************************************************************ // * // Copyright (C) 2017 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************ // // File: ErrorReporter.h // // Author: Stas Jaroszynski (stasj@ucar.edu) // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: July 2017 // // Description: Defines the ErrorReporting class. This is used for // posting various messages that can occur during the operation of the Vapor GUI // This is a singleton class that registers callbacks with the Vapor error api // and keeps tracks of errors that occur. The GUI can then invoke an error message // which will display the GUI provided message and provide a details area which // contains the full error log accumilated since the last error message which can // be saved to a text file. // This class also registeres a signal handler for SIGSEGV and displays an error // window with the current backtrace. #ifndef ERRORREPORTER_H #define ERRORREPORTER_H #include #include #include "vapor/VAssert.h" #include //! \class ErrorReporterPopup //! \ingroup Public_GUI //! \brief A helper class for ErrorReporter that is neccessary because the Qt gui is in a separate thread //! \author Stas Jaroszynski //! \version 1.0 //! \date May 2018 class ErrorReporterPopup : public QMessageBox { Q_OBJECT; public: ErrorReporterPopup(QWidget *parent, int id, bool fatal = false); void setLogText(std::string text); bool isDead() const { return dead; }; private slots: void doAction(QAbstractButton *button); private: bool dead, fatal; std::string _logText; }; #define ERRORREPORTER_DEFAULT_MESSAGE "The action failed" //! \class ErrorReporter //! \ingroup Public_GUI //! \brief A utility singleton class that provides error reporting functinality //! \author Stas Jaroszynski //! \version 3.0 //! \date July 2017 //! ErrorReporter class provides error reporting functionality. Registers error //! callbacks with MyBase and registers signal handler for SIGSEGV #define MSG_ERR(M) (ErrorReporter::GetInstance()->Report(M, ErrorReporter::Error)) #define MSG_WARN(M) (ErrorReporter::GetInstance()->Report(M, ErrorReporter::Warning)) #define MSG_DIAG(M) (ErrorReporter::GetInstance()->Report(M, ErrorReporter::Diagnostic)) #define MSG_FATAL(M) (ErrorReporter::GetInstance()->Report(M, ErrorReporter::Fatal)) class ErrorReporter { public: enum Type { Diagnostic = 0, Info = 1, Warning = 2, Error = 3, Fatal = 4 }; struct Message { Type type; std::string value; int err_code; Message(Type type_, std::string value_, int err_code_ = 0) : type(type_), value(value_), err_code(err_code_) {} }; ErrorReporter(QWidget *parent); //! Returns the singleton instance of this class with lazy initialization //! \retval ErrorReporter instance static ErrorReporter *GetInstance(); //! Displays the current log of errors with the default message ERRORREPORTER_DEFAULT_MESSAGE static void ShowErrors(); //! Displays an error message with the log of errors and outputs the message to the log file //! \param string msg to display explaining error cause/implications //! \param Type severity of message //! \param string details of error. Default to current erros in log static void Report(std::string msg, Type severity = Diagnostic, std::string details = ""); //! Returns basic system OS information //! \retval string containing OS information static std::string GetSystemInformation(); //! Opens log file and begins logging error and diagnostic messages //! \retval int returns -1 on failure static int OpenLogFile(std::string path); protected: ~ErrorReporter(); private: ErrorReporter(); static ErrorReporter * _instance; std::vector _log; std::vector _fullLog; std::string _logFilePath; FILE * _logFile; QWidget * _parent; std::vector _boxes; friend void _myBaseErrorCallback(const char *msg, int err_code); friend void _myBaseDiagCallback(const char *msg); }; #endif ================================================ FILE: apps/vaporgui/ExportTab.cpp ================================================ #include "ExportTab.h" #include "PCheckbox.h" #include "PIntegerInput.h" #include "PSliderEdit.h" #include "PCameraControlsSection.h" #include "POutputResolutionSection.h" #include "PTimestepSliderEdit.h" #include "PTotalTimestepsDisplay.h" #include "PCaptureWidget.h" #include "PMovingDomainSettings.h" #include "CaptureController.h" #include #include ExportTab::ExportTab(ControlExec *ce, CaptureController *captureController) : _ce(ce) { _pg = new PGroup({ new PCaptureWidget(_ce, captureController), new POutputResolutionSection(_ce), new PCameraControlsSection(_ce), _movingDomainSection = new PMovingDomainSettings(_ce), new PGroup({ new PSection("Animation", { new PTimestepSliderEdit(_ce), new PTotalTimestepsDisplay(_ce), }) }) }); layout()->addWidget(_pg); } void ExportTab::Update() { if (_pg) _pg->Update(_ce->GetParams()); } ================================================ FILE: apps/vaporgui/ExportTab.h ================================================ #pragma once #include "VaporFwd.h" #include "PWidgetsFwd.h" #include "Updatable.h" #include "VGroup.h" class CaptureController; class ExportTab : public VGroup, public Updatable { Q_OBJECT ControlExec *_ce; PWidget *_pg = nullptr; PWidget *_movingDomainSection = nullptr; public: ExportTab(VAPoR::ControlExec *ce, CaptureController *captureController); void Update() override; }; ================================================ FILE: apps/vaporgui/FidelityWidget.cpp ================================================ //************************************************************************* // * // Copyright (C) 2015 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: FidelityWidget.cpp // // Author: John Clyne // Scott Pearse // Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: December 2017 // // Description: Implements the FidelityWidget class. // #include #include #include #include #include #include #include #include "vapor/RenderParams.h" #include "vapor/ParamsMgr.h" #include "vapor/DataMgr.h" #include "FidelityWidget.h" using namespace VAPoR; FidelityWidget::FidelityWidget(QWidget *parent) : QWidget(parent), Ui_FidelityWidgetGUI() { setupUi(this); _fidelityButtons = new QButtonGroup(fidelityBox); _fidelityButtons->setExclusive(true); QHBoxLayout *hlay = new QHBoxLayout(fidelityBox); hlay->setAlignment(Qt::AlignHCenter); fidelityBox->setLayout(hlay); int dpi = qApp->desktop()->logicalDpiX(); if (dpi > 96) fidelityFrame->setMinimumHeight(100); connect(refinementCombo, SIGNAL(activated(int)), this, SLOT(setNumRefinements(int))); connect(lodCombo, SIGNAL(activated(int)), this, SLOT(setCompRatio(int))); connect(fidelityDefaultButton, SIGNAL(clicked()), this, SLOT(SetFidelityDefault())); connect(_fidelityButtons, SIGNAL(buttonClicked(int)), this, SLOT(setFidelity(int))); } void FidelityWidget::setNumRefinements(int num) { VAssert(_rParams); _rParams->SetRefinementLevel(num); // Fidelity settings no longer valid // uncheckFidelity(); } // Occurs when user clicks a fidelity radio button // void FidelityWidget::setFidelity(int buttonID) { VAssert(_rParams); VAssert(buttonID >= 0 && buttonID < _fidelityLodIdx.size()); int lod = _fidelityLodIdx[buttonID]; int ref = _fidelityMultiresIdx[buttonID]; _paramsMgr->BeginSaveStateGroup("Set variable fidelity"); _rParams->SetCompressionLevel(lod); _rParams->SetRefinementLevel(ref); _paramsMgr->EndSaveStateGroup(); // Need to update the GUI // lodCombo->setCurrentIndex(lod); refinementCombo->setCurrentIndex(ref); } QButtonGroup *FidelityWidget::GetFidelityButtons() { return _fidelityButtons; } std::vector FidelityWidget::GetFidelityLodIdx() const { return _fidelityLodIdx; } // User clicks on SetDefault button, need to make current // fidelity settings the default. void FidelityWidget::SetFidelityDefault() { #ifdef VAPOR3_0_0_ALPHA // Check current values of LOD and refinement and their combos. _dataStatus->setFidelityDefault(rParams); StartupParams *sParams = (StartupParams *)_paramsMgr->GetDefaultParams(StartupParams::_startupParamsTag); _controlExec->SavePreferences(sParams->GetCurrentPrefsPath()); updateTab(rParams); #endif } void FidelityWidget::getCmpFactors(string varname, vector &lodCF, vector &lodStr, vector &multiresCF, vector &multiresStr) const { VAssert(!varname.empty()); lodCF.clear(); lodStr.clear(); multiresCF.clear(); multiresStr.clear(); int numLevels = _dataMgr->GetNumRefLevels(varname); // First get compression factors that are based on grid multiresolution // // Compute sorted list of number of grids points // at each level in multiresolution hierarchy // vector nGridPts; for (int l = 0; l < numLevels; l++) { vector dims_at_level; int rc = _dataMgr->GetDimLensAtLevel(varname, l, dims_at_level, -1); VAssert(rc >= 0); size_t n = 1; ostringstream oss; oss << l << " ("; for (int j = 0; j < dims_at_level.size(); j++) { n *= dims_at_level[j]; oss << dims_at_level[j]; if (j < dims_at_level.size() - 1) oss << "x"; } nGridPts.push_back(n); oss << ")"; multiresStr.push_back(oss.str()); } for (int i = 0; i < nGridPts.size() - 1; i++) { float cf = 1.0 / (nGridPts[nGridPts.size() - 1] / nGridPts[i]); multiresCF.push_back(cf); } multiresCF.push_back(1.0); // Now get the "levels of detail" compression factors // vector cratios = _dataMgr->GetCRatios(varname); for (int i = 0; i < cratios.size(); i++) { ostringstream oss; lodCF.push_back((float)1.0 / cratios[i]); oss << i << " (" << cratios[i] << ":1)"; lodStr.push_back(oss.str()); } } void FidelityWidget::uncheckFidelity() { // Unset all fidelity buttons // if (!_fidelityButtons) return; QList btns = _fidelityButtons->buttons(); for (int i = 0; i < btns.size(); i++) { if (btns[i]->isChecked()) { btns[i]->setChecked(false); } } } void FidelityWidget::setCompRatio(int num) { VAssert(_rParams); _rParams->SetCompressionLevel(num); lodCombo->setCurrentIndex(num); // Fidelity no longer valid // uncheckFidelity(); } void FidelityWidget::Update(const DataMgr *dataMgr, ParamsMgr *paramsMgr, RenderParams *rParams) { VAssert(dataMgr); VAssert(paramsMgr); VAssert(rParams); _dataMgr = dataMgr; _paramsMgr = paramsMgr; _rParams = rParams; string varname; if (_variableFlags & SCALAR) { varname = _rParams->GetVariableName(); } else if (_variableFlags & VECTOR) { vector varnames = _rParams->GetFieldVariableNames(); if (varnames.size() > 0) { varname = varnames[0]; size_t vardim; for (int i = 0; i < varnames.size(); i++) { vardim = _dataMgr->GetNumDimensions(varnames[i]); if (vardim == 3) { varname = varnames[i]; break; } } } } else if (_variableFlags & HEIGHT) { varname = _rParams->GetHeightVariableName(); } else if (_variableFlags & AUXILIARY) { vector varnames = _rParams->GetAuxVariableNames(); if (varnames.size() > 0) { varname = varnames[0]; size_t vardim; for (int i = 0; i < varnames.size(); i++) { vardim = _dataMgr->GetNumDimensions(varnames[i]); if (vardim == 3) { varname = varnames[i]; break; } } } } else if (_variableFlags & COLOR) { varname = _rParams->GetColorMapVariableName(); } if (varname.empty()) { fidelityTab->setEnabled(false); return; } fidelityTab->setEnabled(true); fidelityTab->show(); vector cratios = _dataMgr->GetCRatios(varname); // Get the effective compression rates as a floating point value, // and as a string that can be displayed, for the LOD and refinement // control // vector lodCFs, multiresCFs; vector lodStrs, multiresStrs; getCmpFactors(varname, lodCFs, lodStrs, multiresCFs, multiresStrs); int lodReq = _rParams->GetCompressionLevel(); int refLevelReq = _rParams->GetRefinementLevel(); int lod = lodReq < 0 ? 0 : lodReq; lod = lodReq >= lodCFs.size() ? lodCFs.size() - 1 : lodReq; int refLevel = refLevelReq < 0 ? 0 : refLevelReq; refLevel = refLevelReq >= multiresCFs.size() ? multiresCFs.size() - 1 : refLevelReq; // set up the refinement and LOD combos // lodCombo->blockSignals(true); lodCombo->clear(); for (int i = 0; i < lodStrs.size(); i++) { QString s = QString::fromStdString(lodStrs[i]); lodCombo->addItem(s); } lodCombo->setCurrentIndex(lod); _currentLodStr = lodStrs.at(lod); lodCombo->blockSignals(false); refinementCombo->blockSignals(true); refinementCombo->clear(); for (int i = 0; i < multiresStrs.size(); i++) { refinementCombo->addItem(QString(multiresStrs[i].c_str())); } refinementCombo->setCurrentIndex(refLevel); _currentMultiresStr = multiresStrs.at(refLevel); refinementCombo->blockSignals(false); if (lodReq != lod) { _rParams->SetCompressionLevel(lod); } if (refLevelReq != refLevel) { _rParams->SetRefinementLevel(refLevel); } fidelityBox->adjustSize(); // Linearize the LOD and refinement compression ratios so that // when combined they increase (decrease) monotonically // _fidelityLodIdx.clear(); _fidelityMultiresIdx.clear(); _fidelityLodStrs.clear(); _fidelityMultiresStrs.clear(); int l = 0; int m = 0; do { _fidelityLodIdx.push_back(l); _fidelityMultiresIdx.push_back(m); _fidelityLodStrs.push_back(lodStrs[l]); _fidelityMultiresStrs.push_back(multiresStrs[m]); if (lodCFs[l] < multiresCFs[m]) { l++; } else { m++; } } while (l < lodCFs.size() && m < multiresCFs.size()); _fidelityButtons->blockSignals(true); // Remove buttons from the group // QList btns = _fidelityButtons->buttons(); for (int i = 0; i < btns.size(); i++) { _fidelityButtons->removeButton(btns[i]); } // Remove and delete buttons from the layout // QHBoxLayout *hlay = (QHBoxLayout *)fidelityBox->layout(); QLayoutItem *child; while ((child = hlay->takeAt(0)) != 0) { delete child->widget(); delete child; } int numButtons = _fidelityLodStrs.size(); for (int i = 0; i < numButtons; i++) { QRadioButton *rd = new QRadioButton(); hlay->addWidget(rd); _fidelityButtons->addButton(rd, i); QString qs = "Refinement " + QString::fromStdString(_fidelityMultiresStrs[i]) + "\nLOD " + QString::fromStdString(_fidelityLodStrs[i]); rd->setToolTip(qs); if (lod == _fidelityLodIdx[i] && refLevel == _fidelityMultiresIdx[i]) { rd->setChecked(true); } } _fidelityButtons->blockSignals(false); } std::string FidelityWidget::GetCurrentLodString() const { return _currentLodStr; } std::string FidelityWidget::GetCurrentMultiresString() const { return _currentMultiresStr; } ================================================ FILE: apps/vaporgui/FidelityWidget.h ================================================ #ifndef FIDELITYWIDGET_H #define FIDELITYWIDGET_H #include #include "vapor/MyBase.h" #include "ui_FidelityWidgetGUI.h" #include "Flags.h" QT_USE_NAMESPACE namespace VAPoR { class RenderParams; class ParamsMgr; class DataMgr; } // namespace VAPoR class RenderEventRouter; //! //! \class FidelityWidget //! \ingroup Public_GUI //! \brief A Widget that can be reused to provide fidelity //! selection in any renderer EventRouter class //! \author Scott Pearse //! \version 3.0 //! \date December 2017 class FidelityWidget : public QWidget, public Ui_FidelityWidgetGUI { Q_OBJECT public: FidelityWidget(QWidget *parent); void Reinit(VariableFlags variableFlags) { _variableFlags = variableFlags; } virtual void Update(const VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams); QButtonGroup * GetFidelityButtons(); std::vector GetFidelityLodIdx() const; std::string GetCurrentLodString() const; std::string GetCurrentMultiresString() const; protected slots: //! Connected to the image file text editor void setNumRefinements(int num); //! Connected to the compression ratio selector, setting the lod index. void setCompRatio(int num); //! Connected to the fidelity button selector, setting the fidelity index. void setFidelity(int buttonID); //! Connected to the fidelity setDefault button, setting current //! fidelity as default void SetFidelityDefault(); private: VariableFlags _variableFlags; const VAPoR::DataMgr *_dataMgr; VAPoR::ParamsMgr * _paramsMgr; VAPoR::RenderParams * _rParams; // Get the compression rates as a fraction for both the LOD and // Refinment parameters. Also format these factors into a displayable // string // void getCmpFactors(string varname, vector &lodCF, vector &lodStr, vector &multiresCF, vector &multiresStr) const; void uncheckFidelity(); void setupFidelity(VAPoR::RenderParams *dParams); QButtonGroup *_fidelityButtons; // Support for fidelity settings // std::vector _fidelityLodIdx; std::vector _fidelityMultiresIdx; std::vector _fidelityLodStrs; std::vector _fidelityMultiresStrs; std::string _currentLodStr; std::string _currentMultiresStr; }; #endif // FIDELITYWIDGET_H ================================================ FILE: apps/vaporgui/FidelityWidgetGUI.ui ================================================ FidelityWidgetGUI 0 0 421 187 0 0 Form 0 0 0 0 0 0 Data Fidelity 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 Select either contours of 3D or 2D variables Fidelity Qt::Horizontal 197 20 0 55 The fidelity setting controls both refinement levels and level of detail (LOD). Click on the "Set Default Fidelity" button to establish a fidelity level that is interactive on the current platform. low < - - - > high Qt::AlignCenter QFrame::NoFrame QFrame::Raised 0 0 Level of Detail Qt::Horizontal 139 20 150 0 <html><head/><body><p>Specify the approximation level (compression) for the data being used to calculate contour lines.</p></body></html> The refinement level parameter and (in the case of VDC2 data) the level of detail (LOD) parameter control the quality of the approximation used when visualizing a variable. The Refinement parameter selects the grid resolutiion. Coarser resolutions require less memory (RAM); less computation by the visualization algorithms; and for VDC1 data, less storage space on disk, therefore less time to read the data. For VDC2 data the Refinement level has no impact on disk storage. The LOD parameter, which is only available for VDC2 data sets, selects a compression level. Variables with greater compression require less disk storage and can thus be read from disk by vaporgui more quickly, but have no impact on memory (RAM) or computation time required by the visualziation algorithms. For both LOD and Refinement, level 0 corresponds to the coarsest approximation available. QFrame::NoFrame QFrame::Raised 0 0 Refinement Level Qt::Horizontal 121 20 150 0 <html><head/><body><p>Select the refinement level (resolution) of the data used to calculate contour lines.</p></body></html> The refinement level parameter and (in the case of VDC2 data) the level of detail (LOD) parameter control the quality of the approximation used when visualizing a variable. The Refinement parameter selects the grid resolutiion. Coarser resolutions require less memory (RAM); less computation by the visualization algorithms; and for VDC1 data, less storage space on disk, therefore less time to read the data. For VDC2 data the Refinement level has no impact on disk storage. The LOD parameter, which is only available for VDC2 data sets, selects a compression level. Variables with greater compression require less disk storage and can thus be read from disk by vaporgui more quickly, but have no impact on memory (RAM) or computation time required by the visualziation algorithms. For both LOD and Refinement, level 0 corresponds to the coarsest approximation available. QFrame::NoFrame QFrame::Raised 0 0 Qt::Horizontal 231 20 155 0 <html><head/><body><p>Click to set default Fidelity to current LOD and refinement levels. The default can optionally be saved in user preferences.</p></body></html> The fidelity setting controls both refinement levels and level of detail (LOD). Click on the "Set Default Fidelity" button to establish a fidelity level that is interactive on the current platform. Default ================================================ FILE: apps/vaporgui/FileOperationChecker.cpp ================================================ #include #include "FileOperationChecker.h" QString FileOperationChecker::_message(""); bool FileOperationChecker::DirectoryGoodToRead(const QString &filename) { QFileInfo fileInfo(filename); // Test if this filename exists if (!fileInfo.exists()) { QString msg(" The following input does not exist! \n"); msg += filename; _message = msg; return false; } // Test if this is a directory if (!fileInfo.isDir()) { QString msg(" The following input is NOT a directory! \n"); msg += filename; _message = msg; return false; } // Test if this directory is readable if (!fileInfo.isReadable()) { QString msg(" The following input is NOT readable! \n"); msg += filename; _message = msg; return false; } // Test if this directory is executable if (!fileInfo.isExecutable()) { QString msg(" The following input is NOT executable! \n"); msg += filename; _message = msg; return false; } return true; } bool FileOperationChecker::FileGoodToRead(const QString &filename) { QFileInfo fileInfo(filename); // Test if this filename exists if (!fileInfo.exists()) { QString msg(" The following input does not exist! \n"); msg += filename; _message = msg; return false; } // Test if this is a file if (!fileInfo.isFile()) { QString msg(" The following input is NOT a file! \n"); msg += filename; _message = msg; return false; } // Test if this file is readable if (!fileInfo.isReadable()) { QString msg(" The following input is NOT readable! \n"); msg += filename; _message = msg; return false; } return true; } bool FileOperationChecker::FileGoodToWrite(const QString &filename) { QFileInfo fileInfo(filename); // In case this file does not exist if (!fileInfo.exists()) { std::FILE *f = std::fopen(filename.toLatin1(), "w"); if (f) // able to write { std::fclose(f); std::remove(filename.toLatin1()); return true; } else { QString msg(" The following file cannot be created! \n"); msg += filename; _message = msg; return false; } } // The input exists when the program reaches here // Test if this is a file if (!fileInfo.isFile()) { QString msg(" The following is NOT a file! \n"); msg += filename; _message = msg; return false; } // Test if this file is readable if (!fileInfo.isReadable()) { QString msg(" The following file is NOT readable! \n"); msg += filename; _message = msg; return false; } // Test if this file is writable if (!fileInfo.isWritable()) { QString msg(" The following file is NOT writable! \n"); msg += filename; _message = msg; return false; } return true; } bool FileOperationChecker::FileHasCorrectSuffix(const QString &filename, const QString &expectedSuffix) { QFileInfo fileInfo(filename); if (fileInfo.suffix().compare(expectedSuffix) == 0) return true; else { QString msg(" The following input does NOT have the expected suffix: "); msg += expectedSuffix; msg += "\n"; msg += filename; _message = msg; return false; } } QString FileOperationChecker::GetLastErrorMessage() { return _message; } ================================================ FILE: apps/vaporgui/FileOperationChecker.h ================================================ /* * This class provides a set of functions that check if a file/directory * is good to read/write. * * The rational is recorded in this post: * https://github.com/NCAR/VAPOR/wiki/Robust-File-Operations-with-VAPOR-and-Qt * */ #ifndef FILEOPERATIONCHECKER_H #define FILEOPERATIONCHECKER_H #include class FileOperationChecker { public: static bool DirectoryGoodToRead(const QString &filename); static bool FileGoodToRead(const QString &filename); static bool FileGoodToWrite(const QString &filename); static bool FileHasCorrectSuffix(const QString &filename, const QString &expectedSuffix); static QString GetLastErrorMessage(); private: static QString _message; }; #endif ================================================ FILE: apps/vaporgui/Flags.h ================================================ #ifndef FLAGS_H #define FLAGS_H //! Bit masks to indicate what type of variables are to be supported by //! a particular VariablesWidget instance. These flags correspond //! to variable names returned by methods: //! //! SCALAR : RenderParams::GetVariableName() //! VECTOR : RenderParams::GetFieldVariableNames() //! HGT : RenderParams::GetHeightVariableName() //! COLOR : RenderParams::GetColorMapVariableNames() //! enum VariableFlags { SCALAR = (1u << 0), VECTOR = (1u << 1), COLOR = (1u << 2), AUXILIARY = (1u << 3), HEIGHT = (1u << 4), }; //! Bit mask to indicate whether 2D, 3D, or 2D and 3D variables are to //! be supported // enum DimFlags { TWOD = (1u << 0), TWODXY = (1u << 1), TWODXZ = (1u << 2), TWODYZ = (1u << 3), THREED = (1u << 4), }; //! Bit mask to indicate whether the GeometryWidget should control a //! single point, or 3D extents with Min/Max controllers enum GeometryFlags { PLANAR = (1u << 0), RAKE_HACK = (1u << 1), }; #endif ================================================ FILE: apps/vaporgui/FlowEventRouter.cpp ================================================ #include "FlowEventRouter.h" #include "vapor/FlowParams.h" #include "PWidgets.h" #include "PFlowRakeRegionSelector.h" #include "PFlowIntegrationRegionSelector.h" #include "PMultiVarSelector.h" #include "PConstantColorWidget.h" #include "PMetadataClasses.h" #include "PSliderEditHLI.h" using namespace VAPoR; typedef FlowParams FP; static RenderEventRouterRegistrar registrar(FlowEventRouter::GetClassType()); const string FlowEventRouter::SeedingTabName = "Seeding"; const string FlowEventRouter::IntegrationTabName = "Integration"; FlowEventRouter::FlowEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, FlowParams::GetClassType()) { // clang-format off AddVariablesSubtab(new PGroup({ new PSection("Variable Selection", { new PDimensionSelector, new PXFieldVariableSelector, new PYFieldVariableSelector, (new PZFieldVariableSelector)->OnlyShowForDim(3), new PColorMapVariableSelector, }), new PFidelitySection, new POpenVariableMetadataWidget })); _seedingTab = AddSubtab(SeedingTabName, new PGroup({ new PSection("Flow Integration Settings", { new PEnumDropdown(FP::_isSteadyTag, {"Streamlines", "Pathlines"}, {true, false}, "Flow Type"), (new PShowIf(FP::_isSteadyTag))->Equals(true)->Then({ new PEnumDropdown(FP::_flowDirectionTag, {"Forward", "Backward", "Bi-Directional"}, {(int)FlowDir::FORWARD, (int)FlowDir::BACKWARD, (int)FlowDir::BI_DIR}, "Flow Direction"), (new PIntegerInput(FP::_steadyNumOfStepsTag, "Integration Steps"))->SetRange(0, 10000), })->Else({ _pathlineLengthSlider = new PIntegerSliderEdit(FP::_pastNumOfTimeSteps, "Pathline Length"), _pathlineInjectionSlider = new PIntegerSliderEdit(FP::_seedInjInterval, "Injection Interval"), }), new PCheckbox(FP::_xPeriodicTag, "X axis periodicity"), new PCheckbox(FP::_yPeriodicTag, "Y axis periodicity"), new PCheckbox(FP::_zPeriodicTag, "Z axis periodicity"), }), new PSection("Seed Distribution Settings", { new PEnumDropdown(FP::_seedGenModeTag, {"Gridded", "Random", "Random w/ Bias", "List of seeds"}, {(int)FlowSeedMode::UNIFORM, (int)FlowSeedMode::RANDOM, (int)FlowSeedMode::RANDOM_BIAS, (int)FlowSeedMode::LIST}, "Seed distribution type"), (new PShowIf(FP::_seedGenModeTag))->Equals((int)FlowSeedMode::UNIFORM)->Then({ (new PIntegerSliderEdit(FP::_xGridNumOfSeedsTag, "X axis seeds"))->SetRange(1, 50), (new PIntegerSliderEdit(FP::_yGridNumOfSeedsTag, "Y axis seeds"))->SetRange(1, 50), (new PIntegerSliderEdit(FP::_zGridNumOfSeedsTag, "Z axis seeds"))->SetRange(1, 50), }), (new PShowIf(FP::_seedGenModeTag))->Equals((int)FlowSeedMode::RANDOM)->Then({ (new PIntegerSliderEdit(FP::_randomNumOfSeedsTag, "Seed count"))->SetRange(1, 2500) ->AllowUserRange(true), }), (new PShowIf(FP::_seedGenModeTag))->Equals((int)FlowSeedMode::RANDOM_BIAS)->Then({ (new PIntegerSliderEdit(FP::_randomNumOfSeedsTag, "Seed count"))->SetRange(1, 2500) ->AllowUserRange(true), (new PIntegerSliderEdit(FP::_rakeBiasStrength, "Bias weight"))->SetRange(-10000, 10000) ->AllowUserRange(true), new PVariableSelector(FP::_rakeBiasVariable, "Bias Variable") }), (new PShowIf(FP::_seedGenModeTag))->Equals((int)FlowSeedMode::LIST)->Then({ (new PFileOpenSelector(FP::_seedInputFilenameTag, "List of seeds file"))->SetTooltip( "Seed injection points within your domain may be defined in this text file with the following definition: \n" "1. Each line specifies the location of one seed. \n" "2. Empty lines and lines starting with a pound sign is ignored. \n" "3. Seed locations are specified using comma separated X,Y,Z coordinates. \n" "4. A line with less than 3 comma separated values is invalid, which also invalidates the entire file. \n" "5. A line can have more than 3 comma separated values, with additional values being ignored. \n" "6. X, Y, Z coordinates use the same unit of the dataset's spatial domain. \n" " Note: lat-lon coordinates may be converted to meters via a map projection. \n" "Finally, the listOfSeeds.txt demo file provides a starting point to specify your own seeds." ) }), }), (new PShowIf(FP::_seedGenModeTag))->Not()->Equals((int)FlowSeedMode::LIST)->Then({ new PSection("Rake Region", { new PFlowRakeRegionSelector1D(0), new PFlowRakeRegionSelector1D(1), new PFlowRakeRegionSelector1D(2), }), (new PSection("Rake Center", { (_xRakeCenterSlider = new PDoubleSliderEditHLI("X", &FlowParams::GetXRakeCenter, &FlowParams::SetXRakeCenter))->AllowDynamicUpdate(), (_yRakeCenterSlider = new PDoubleSliderEditHLI("Y", &FlowParams::GetYRakeCenter, &FlowParams::SetYRakeCenter))->AllowDynamicUpdate(), (_zRakeCenterSlider = new PDoubleSliderEditHLI("Z", &FlowParams::GetZRakeCenter, &FlowParams::SetZRakeCenter))->AllowDynamicUpdate(), }))->SetTooltip("Controls the location of the Rake's Center. To control\n the range of values that the Rake Center can traverse, adjust\n the Flow Renderer's Region in the Geometry tab"), }), new PSection("Write Flowlines to File", { new PFileSaveSelector(FP::_flowlineOutputFilenameTag, "Target file"), (new PButton("Write to file", [](ParamsBase *p){p->SetValueLong(FP::_needFlowlineOutputTag, "", true);}))->DisableUndo(), new PLabel("Specify variables to sample and output along the flowlines"), new PMultiVarSelector(FP::_flowOutputMoreVariablesTag) }), new PSection("Advanced Options", { (new PDoubleInput(FP::_velocityMultiplierTag, "Vector Field Multiplier"))->SetTooltip( "Apply a multiplier to the velocity field."), (new PDoubleInput(FP::_firstStepSizeMultiplierTag, "First Step Size Multiplier"))->SetTooltip( "Apply a multiplier to the auto-calculated first step size. Very occasionally a value bigger than 1.0 is needed here."), (new PCheckbox(FP::_fixedAdvectionStepTag, "Use Fixed Advection Steps"))->SetTooltip( "The user may provide an advection step size, so that VAPOR disables dynamic step size adjustments and always uses the fixed step size."), (new PShowIf(FP::_fixedAdvectionStepTag))->Then(new PDoubleInput(FP::_fixedAdvectionStepSizeTag, " |--- Fixed Advection Step Size"))->SetTooltip( "Use this specific value as the fixed advection step size."), }), })); AddAppearanceSubtab(new PGroup({ (new PTFEditor(RenderParams::_colorMapVariableNameTag)), new PSection("Appearance", { new PConstantColorWidget, new PEnumDropdown(FP::RenderTypeTag, {"Tubes", "Samples", "KLGWTH"}, {FP::RenderTypeStream, FP::RenderTypeSamples, FP::RenderTypeDensity}, "Render Type"), (new PShowIf(FP::RenderTypeTag))->Equals(FP::RenderTypeStream)->Then({ new PCheckbox(FP::RenderGeom3DTag, "3D Geometry"), (new PDoubleSliderEdit(FP::RenderRadiusScalarTag, "Radius Scalar"))->SetRange(0.1, 5)->EnableDynamicUpdate(), new PCheckbox(FP::RenderShowStreamDirTag, "Show Stream Direction"), (new PSubGroup({(new PIntegerSliderEdit(FP::RenderGlyphStrideTag, "Every N Samples"))->SetRange(1, 20)->EnableDynamicUpdate()}))->ShowBasedOnParam(FP::RenderShowStreamDirTag), }), (new PShowIf(FP::RenderTypeTag))->Equals(FP::RenderTypeSamples)->Then({ new PEnumDropdown(FP::RenderGlyphTypeTag, {"Circle", "Arrow"}, {FP::GlpyhTypeSphere, FP::GlpyhTypeArrow}, "Glyph Type"), new PCheckbox(FP::RenderGeom3DTag, "3D Geometry"), (new PDoubleSliderEdit(FP::RenderRadiusScalarTag, "Radius Scalar"))->SetRange(0.1, 5)->EnableDynamicUpdate(), (new PIntegerSliderEdit(FP::RenderGlyphStrideTag, "Every N Samples"))->SetRange(1, 20)->EnableDynamicUpdate(), new PCheckbox(FP::RenderGlyphOnlyLeadingTag, "Only Show Leading Sample"), }), (new PShowIf(FP::RenderTypeTag))->Equals(FP::RenderTypeDensity)->Then({ new PLabel("May not render correctly with other renderers"), (new PDoubleSliderEdit(FP::RenderRadiusScalarTag, "Radius Scalar"))->SetRange(0.1, 5)->EnableDynamicUpdate(), (new PDoubleSliderEdit(FlowParams::RenderDensityFalloffTag, "Density Falloff"))->SetRange(0.5, 10)->EnableDynamicUpdate()->SetTooltip("The exponential factor at which the intensity falls off along the width of the line"), (new PDoubleSliderEdit(FlowParams::RenderDensityToneMappingTag, "Tone Mapping"))->SetRange(0, 1)->EnableDynamicUpdate()->SetTooltip("The overall color intensity of the line"), (new PCheckbox("Invert"))->SetTooltip("For rendering on light backgrounds"), }), (new PShowIf(FP::RenderTypeTag))->Not()->Equals(FP::RenderTypeSamples)->Then({ new PCheckbox(FP::RenderFadeTailTag, "Fade Flow Tails"), (new PShowIf(FP::RenderFadeTailTag))->Equals(true)->Then(new PSubGroup({ (new PIntegerSliderEdit(FP::RenderFadeTailStartTag, "Fade Start Sample"))->SetRange(0, 100)->EnableDynamicUpdate()->SetTooltip("How far behind leading sample fade begins."), (new PIntegerSliderEdit(FP::RenderFadeTailLengthTag, "Fade Over N Samples"))->SetRange(1, 100)->EnableDynamicUpdate()->SetTooltip("Number of samples from opaque to transparent."), (new PIntegerSliderEdit(FP::RenderFadeTailStopTag, "Animate Steady"))->SetRange(0, 200)->EnableDynamicUpdate()->SetTooltip("Temporary solution for animating steady flow particles."), })), }), }), (new PShowIf(FP::RenderGeom3DTag))->Then(new PSection("Lighting", { (new PDoubleSliderEdit(FP::PhongAmbientTag, "Ambient" ))->EnableDynamicUpdate(), (new PDoubleSliderEdit(FP::PhongDiffuseTag, "Diffuse" ))->EnableDynamicUpdate(), (new PDoubleSliderEdit(FP::PhongSpecularTag, "Specular" ))->EnableDynamicUpdate(), (new PDoubleSliderEdit(FP::PhongShininessTag, "Shininess"))->EnableDynamicUpdate(), })), #ifndef NDEBUG (new PSection("Debug", { new PCheckbox("old_render", "Old Render Code (Regressing Testing)") }))->SetTooltip("Only accessible in debug build."), #endif })); AddSubtab(IntegrationTabName, new PGroup({ new PSection("Integration Settings", { new PCheckbox(FP::_doIntegrationTag, "Integrate particle values along trajectory"), new PCheckbox(FP::_integrationSetAllToFinalValueTag, "Set entire stream value to integrated total"), (new PVariableSelector(RenderParams::_colorMapVariableNameTag, "Scalar to Integrate"))->EnableBasedOnParam(FP::_doIntegrationTag), (new PDoubleInput(FP::_integrationScalarTag, "Integration distance scale"))->EnableBasedOnParam(FP::_doIntegrationTag), }), (new PSection("Integration Region", { new PFlowIntegrationRegionSelector1D(0), new PFlowIntegrationRegionSelector1D(1), new PFlowIntegrationRegionSelector1D(2), }))->EnableBasedOnParam(FP::_doIntegrationTag), })); AddGeometrySubtab(new PGeometrySubtab); AddColorbarSubtab(new PAnnotationColorbarWidget); // clang-format on } void FlowEventRouter::Update() { RenderEventRouterGUI::Update(); int numTS = GetActiveDataMgr()->GetNumTimeSteps(); _pathlineLengthSlider->SetRange(0, std::max(1, numTS - 1)); _pathlineInjectionSlider->SetRange(0, numTS); VAPoR::CoordType min, max; FlowParams * fp = dynamic_cast(GetActiveParams()); fp->GetBox()->GetExtents(min, max); double xCenter = fp->GetXRakeCenter(); double yCenter = fp->GetYRakeCenter(); double zCenter = fp->GetZRakeCenter(); if (xCenter > max[0]) fp->SetXRakeCenter(max[0]); if (xCenter < min[0]) fp->SetXRakeCenter(min[0]); _xRakeCenterSlider->SetRange(min[0], max[0]); if (yCenter > max[1]) fp->SetYRakeCenter(max[1]); if (yCenter < min[1]) fp->SetYRakeCenter(min[1]); _yRakeCenterSlider->SetRange(min[1], max[1]); if (zCenter > max[2]) fp->SetZRakeCenter(max[2]); if (zCenter < min[2]) fp->SetZRakeCenter(min[2]); _zRakeCenterSlider->SetRange(min[2], max[2]); } string FlowEventRouter::_getDescription() const { return "Computes and displays steady or unsteady flow trajectories.\n"; } ================================================ FILE: apps/vaporgui/FlowEventRouter.h ================================================ #pragma once #include "RenderEventRouterGUI.h" #include class PIntegerSliderEdit; class PDoubleSliderEdit; //! \class FlowEventRouter //! \ingroup Public_GUI //! \brief Flow renderer GUI //! \author Stas Jaroszynski class FlowEventRouter : public RenderEventRouterGUI { QWidget * _seedingTab; PIntegerSliderEdit *_pathlineLengthSlider; PIntegerSliderEdit *_pathlineInjectionSlider; PDoubleSliderEdit * _xRakeCenterSlider; PDoubleSliderEdit * _yRakeCenterSlider; PDoubleSliderEdit * _zRakeCenterSlider; public: static const std::string SeedingTabName; static const std::string IntegrationTabName; FlowEventRouter(QWidget *parent, VAPoR::ControlExec *ce); static string GetClassType() { return VAPoR::FlowRenderer::GetClassType(); } string GetType() const { return GetClassType(); } bool Supports2DVariables() const { return true; } bool Supports3DVariables() const { return true; } void Update(); protected: string _getDescription() const; string _getSmallIconImagePath() const { return "Flow_small.png"; } string _getIconImagePath() const { return "Flow.png"; } }; ================================================ FILE: apps/vaporgui/GLWidget.cpp ================================================ //-- GLWidget.cpp ------------------------------------------------------- // // Copyright (C) 2006 Kenny Gruchalla. All rights reserved. // // Abstract base class for OpenGL-based widgets that provides a common // interface for selecting, moving, and drawing. // //---------------------------------------------------------------------------- #include "GLWidget.h" #include using namespace std; //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- GLWidget::GLWidget(QWidget *parent) : QObject(parent), _id(createId()), _selected(NONE), _enabled(true) {} //---------------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------------- GLWidget::~GLWidget() {} //---------------------------------------------------------------------------- // Set the widget's geometry //---------------------------------------------------------------------------- void GLWidget::setGeometry(float x0, float x1, float y0, float y1) { _minX = x0 <= x1 ? x0 : x1; _maxX = x1 > x0 ? x1 : x0; _minY = y0 <= y1 ? y0 : y1; _maxY = y1 > y0 ? y1 : y0; } //- static ------------------------------------------------------------------- // // Generate a unique identifier. //---------------------------------------------------------------------------- unsigned int GLWidget::createId() { static unsigned int id = 1; return id++; } ================================================ FILE: apps/vaporgui/GLWidget.h ================================================ //-- GLWidget.h --------------------------------------------------------- // // Copyright (C) 2006 Kenny Gruchalla. All rights reserved. // // Abstract base class for OpenGL-based widgets that provides a common // interface for selecting, moving, and drawing. // //---------------------------------------------------------------------------- #ifndef GLWidget_H #define GLWidget_H #include #include #include class QWidget; class GLWidget : public QObject { Q_OBJECT protected: enum { NONE = -1 }; public: GLWidget(QWidget *parent = 0); virtual ~GLWidget(); virtual int paintGL() = 0; virtual void move(float dx, float dy = 0.0, float dz = 0.0) = 0; virtual void drag(float dx, float dy = 0.0, float dz = 0.0) = 0; virtual bool selected() { return _selected != NONE; } virtual void deselect() { _selected = NONE; } virtual void select(int handle, Qt::KeyboardModifiers) { _selected = handle; } virtual bool enabled() const { return _enabled; } virtual void enable(bool flag) { _enabled = flag; } virtual void setGeometry(float x0, float x1, float y0, float y1); int id() const { return _id; } signals: void startChange(QString); void endChange(); protected: static unsigned int createId(); unsigned int _id; int _selected; bool _enabled; float _minX; float _maxX; float _minY; float _maxY; }; #endif // GLWidget_H ================================================ FILE: apps/vaporgui/ImageEventRouter.cpp ================================================ #include #include #include "PWidgets.h" #include "PTMSLODInput.h" #include "PMetadataClasses.h" using namespace VAPoR; typedef ImageParams IP; static RenderEventRouterRegistrar registrar(ImageEventRouter::GetClassType()); ImageEventRouter::ImageEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, ImageParams::GetClassType()) { // clang-format off AddVariablesSubtab(new PGroup({ new PSection("Variable Selection", { new PHeightVariableSelector }), new PFidelitySection, new POpenVariableMetadataWidget })); AddAppearanceSubtab(new PSection("Image", { new PCheckbox(IP::_isGeoRefTag, "Geo Reference"), new PCheckbox(IP::_ignoreTransparencyTag, "Ignore Transparency"), (new PDoubleSliderEdit(IP::_constantOpacityTag, "Opacity"))->EnableDynamicUpdate(), (new PFileOpenSelector(IP::_fileNameTag, "Image File"))->SetFileTypeFilter("TIFF files, tiled images (*.tiff *.tif *.gtif *.tms)"), new PTMSLODInput(), new PCheckbox(IP::DrawInFrontTag, "Draw renderer in front") })); AddGeometrySubtab(new PGeometrySubtab); // clang-format on } string ImageEventRouter::_getDescription() const { return ("Displays a " "georeferenced image that is automatically reprojected and fit to the user's" "data, as long as the data contains georeference metadata. The image " "renderer may be offset by a height variable to show bathymetry or mountainous" " terrain.\n\n "); } ================================================ FILE: apps/vaporgui/ImageEventRouter.h ================================================ #pragma once #include #include //! \class ImageEventRouter //! \ingroup Public_GUI //! \brief Image Renderer GUI //! \author Stas Jaroszynski class ImageEventRouter : public RenderEventRouterGUI { public: ImageEventRouter(QWidget *parent, VAPoR::ControlExec *ce); static std::string GetClassType() { return VAPoR::ImageRenderer::GetClassType(); } std::string GetType() const { return GetClassType(); } bool Supports2DVariables() const { return true; } bool Supports3DVariables() const { return true; } bool SupportsParticleVariables() const { return true; } protected: string _getDescription() const; string _getSmallIconImagePath() const { return "Image_small.png"; } string _getIconImagePath() const { return "Image.png"; } }; ================================================ FILE: apps/vaporgui/ImportTab.cpp ================================================ #include "ImportTab.h" #include "PImportDataWidget.h" #include "DatasetImportController.h" #include "PProjectionStringWidget.h" #include "VHyperlink.h" #include "VSection.h" #include #include #include using namespace VAPoR; ImportTab::ImportTab(VAPoR::ControlExec *ce, DatasetImportController *datasetImportController) : _ce(ce) { QVBoxLayout *l = new QVBoxLayout; l->setContentsMargins(0, 0, 0, 0); l->addWidget(new VSectionGroup("Import Data", {_importer = new PImportDataWidget(_ce, datasetImportController)})); VSectionGroup *sg = new VSectionGroup("Tips", { new VHyperlink( "How to convert Non-Compliant NetCDF Files?", "https://vapordocumentationwebsite.readthedocs.io/en/latest/dataFormatRequirements/netCDF/nonCompliantNetCDF.html", true ), new VHyperlink( "Download example Datasets", "https://vapordocumentationwebsite.readthedocs.io/en/latest/downloads/sampleData.html", true ), new VHyperlink( "Additional information on supported data formats", "https://vapordocumentationwebsite.readthedocs.io/en/latest/dataFormatRequirements.html", true ), new VHyperlink( "Get Help", "https://vapor.discourse.group/", true ), }); sg->setEnabled(true); l->addWidget(sg); l->addWidget(_projectionWidget = new PProjectionStringWidget(_ce)); l->addStretch(1); setLayout(l); } void ImportTab::Update() { GUIStateParams *guiParams = (GUIStateParams *)_ce->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()); _importer->Update(guiParams); bool noDatasetLoaded = guiParams->GetOpenDataSetNames().empty(); if (noDatasetLoaded) _projectionWidget->hide(); else _projectionWidget->Update(guiParams); } ================================================ FILE: apps/vaporgui/ImportTab.h ================================================ #pragma once #include "Updatable.h" #include class PImportDataWidget; class PProjectionStringWidget; class DatasetImportController; class ImportTab : public QWidget, public Updatable { Q_OBJECT VAPoR::ControlExec *_ce; PImportDataWidget *_importer; PProjectionStringWidget *_projectionWidget; public: ImportTab(VAPoR::ControlExec *ce, DatasetImportController *datasetImportController); void Update() override; }; ================================================ FILE: apps/vaporgui/LeftPanel.cpp ================================================ #include "LeftPanel.h" #include #include "RenderersPanel.h" #include "ImportTab.h" #include "ExportTab.h" #include "CaptureController.h" #include "DatasetImportController.h" #include "AnnotationEventRouter.h" #include "vapor/ControlExecutive.h" #include "vapor/GUIStateParams.h" LeftPanel::LeftPanel(ControlExec *ce, CaptureController *captureController, DatasetImportController *datasetImportController) { auto add = [this](auto &&w, auto &&t) constexpr { QScrollArea *scrollArea = new QScrollArea; scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); scrollArea->setWidget(w); scrollArea->setWidgetResizable(true); addTab(scrollArea, t); _uTabs.push_back(w); }; _importTab = new ImportTab(ce, datasetImportController); add(_importTab, "Import"); add(new RenderersPanel(ce), "Render"); add(new AnnotationEventRouter(ce), "Annotate"); add(new ExportTab(ce, captureController), "Export"); for (int i=1 ; isetEnabled(true); setCurrentIndex(0); for (int tabNum=1; tabNum < count(); tabNum++) setTabEnabled(tabNum, false); } else { // Otherwise enable all tabs for (int i = 0; i < count(); ++i) setTabEnabled(i, true); } } void LeftPanel::Update() { if (_uTabs.empty()) return; _uTabs[currentIndex()]->Update(); } void LeftPanel::tabChanged(int i) { _uTabs[i]->Update(); } void LeftPanel::GoToRendererTab() { setCurrentIndex(1); } ================================================ FILE: apps/vaporgui/LeftPanel.h ================================================ #pragma once #include #include #include "Updatable.h" #include "VaporFwd.h" class ImportTab; class CaptureController; class DatasetImportController; class LeftPanel : public QTabWidget, public Updatable { Q_OBJECT std::vector _uTabs; ImportTab* _importTab; public: LeftPanel(ControlExec *ce, CaptureController *captureController, DatasetImportController *datasetImportController); void Update() override; void GoToRendererTab(); void ConfigureEnabledState(bool enabled); private: void tabChanged(int i); }; ================================================ FILE: apps/vaporgui/MainForm.cpp ================================================ #include // Must be included first!!! #include "vapor/VAssert.h" #include #include #include #ifndef _WIN32 #include #include "windowsUtils.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "VizWinMgr.h" #include "BannerGUI.h" #include "Statistics.h" #include "PythonVariables.h" #include "PProjectionStringWidget.h" #include "VProjectionStringFrame.h" #include "Plot.h" #include "ErrorReporter.h" #include "MainForm.h" #include "FileOperationChecker.h" #include "ParamsWidgetDemo.h" #include "AppSettingsMenu.h" #include "CheckForUpdateUI.h" #include "NoticeBoard.h" #include "PVisualizerSelector.h" #include "QtVizWinGLContextManager.h" #include "ProgressStatusBar.h" #include "LeftPanel.h" #include "CLIToolInstaller.h" #include "Updatable.h" #include "CitationReminder.h" #include "BookmarkManager.h" #include "UCloseVDCMenu.h" #include "PTimestepInput.h" #include "NcarCasperUtils.h" #include "ViewpointToolbar.h" #include "DatasetTypeLookup.h" #include "CaptureController.h" #include "DatasetImportController.h" #include #include #include #include #include #include "images/vapor-icon-32.xpm" #include "images/playreverse.xpm" #include "images/playforward.xpm" #include "images/pauseimage.xpm" #include "images/stepfwd.xpm" #include "images/stepback.xpm" using namespace std; using namespace VAPoR; const QEvent::Type MainForm::ParamsChangeEvent = (QEvent::Type)QEvent::registerEventType(); const QEvent::Type MainForm::ParamsIntermediateChangeEvent = (QEvent::Type)QEvent::registerEventType(); MainForm *MainForm::_instance = nullptr; MainForm::MainForm(vector files, QApplication *app, bool interactive, string filesType, QWidget *parent) : QMainWindow(parent) { _App = app; _begForCitation = true; assert(!_instance); _instance = this; setWindowTitle(tr("VAPoR: NCAR Visualization and Analysis Platform for Research")); setAttribute(Qt::WA_DeleteOnClose); // For vertical screens, reverse aspect ratio for window size QScreen *screen = QGuiApplication::primaryScreen(); QRect screenSize = screen->geometry(); if (screenSize.width() < screenSize.height()) { resize(screenSize.width() * .7, screenSize.width() * .7 * screenSize.width() / (float)screenSize.height()); } else { resize(screenSize.width() * .7, screenSize.height() * .7); } setWindowIcon(QPixmap(vapor_icon___)); auto sideDockWidgetArea = new QDockWidget(this); addDockWidget(Qt::LeftDockWidgetArea, sideDockWidgetArea); sideDockWidgetArea->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); sideDockWidgetArea->setFeatures(QDockWidget::NoDockWidgetFeatures); vector myParams; myParams.push_back(GUIStateParams::GetClassType()); myParams.push_back(SettingsParams::GetClassType()); myParams.push_back(AnimationParams::GetClassType()); myParams.push_back(AnnotationParams::GetClassType()); vector myRenParams; myRenParams.push_back(StatisticsParams::GetClassType()); myRenParams.push_back(PlotParams::GetClassType()); _paramsMgr = new ParamsMgr(myParams, myRenParams); _paramsMgr->RegisterStateChangeCB(std::bind(&MainForm::_stateChangeCB, this)); _paramsMgr->RegisterIntermediateStateChangeCB(std::bind(&MainForm::_intermediateStateChangedCB, this)); _paramsMgr->RegisterStateChangeFlag(&_stateChangeFlag); _controlExec = new ControlExec(_paramsMgr); _controlExec->SetSaveStateEnabled(false); _appSettingsMenu = new AppSettingsMenu(this); _vizWinMgr = new VizWinMgr(_controlExec); _controlExec->SetVisualizerGLContextManager(_vizWinMgr->visualizerGLContextManager); setCentralWidget(_vizWinMgr); _dependOnLoadedData_insert(_vizWinMgr); _animationController = new AnimationController(_controlExec); connect(_animationController, SIGNAL(AnimationOnOffSignal(bool)), this, SLOT(_setAnimationOnOff(bool))); connect(_animationController, &AnimationController::AnimationDrawSignal, [this]() { setUpdatesEnabled(false); _controlExec->SyncWithParams(); updateUI(); setUpdatesEnabled(true); Render(false, true); }); _captureController = new CaptureController(_controlExec); connect(_captureController, &CaptureController::captureStarted, [this]() { AnimationParams* ap = (AnimationParams*)_controlExec->GetParamsMgr()->GetParams(AnimationParams::GetClassType()); NavigationUtils::SetTimestep(_controlExec, ap->GetValueLong(AnimationParams::CaptureStartTag, ap->GetStartTimestep())); _animationController->AnimationPlayForward(); }); _datasetImportController = new DatasetImportController(); connect(_datasetImportController, &DatasetImportController::datasetImported, this, [this](){_leftPanel->GoToRendererTab();}); _leftPanel = new LeftPanel(_controlExec, _captureController, _datasetImportController); const int dpi = qApp->desktop()->logicalDpiX(); _leftPanel->setMinimumWidth(dpi > 96 ? 675 : 460); _leftPanel->setMinimumHeight(500); _updatableElements.insert(_leftPanel); _status = new ProgressStatusBar; _status->hide(); sideDockWidgetArea->setWidget(new VGroup({_leftPanel, _status})); // Only this specific resize method works for dock widgets, all other resize methods are noops resizeDocks({sideDockWidgetArea}, {_leftPanel->minimumWidth()}, Qt::Horizontal); createMenus(); createToolBars(); _createProgressWidget(); // Force creation of the static error reporter, which registers // callback's with the MyBase error logger used by the vapor render // library. // new ErrorReporter(this); GetSettingsParams()->FindDefaultSettingsPath(); setUpdatesEnabled(true); // Command line options: // // - Session file // - Session file + data file // - data file // if (files.size() && files[0].endsWith(".vs3")) { if (!FileUtils::Exists(files[0].toStdString())) { fprintf(stderr, "Session file \"%s\" does not exist\n", files[0].toStdString().c_str()); exit(1); } bool loadDatasetsFromSession = files.size() == 1; openSession(files[0].toStdString(), loadDatasetsFromSession); files.erase(files.begin()); if (!loadDatasetsFromSession && _controlExec->GetDataNames().size() > 1) { fprintf(stderr, "Cannot replace dataset from command line in session which contains multiple open datasets."); exit(1); } } else { sessionNew(); } if (files.size()) { vector paths; for (auto &f : files) paths.push_back(f.toStdString()); string fmt; if (filesType == "auto") { if (!determineDatasetFormat(paths, &fmt)) { fmt = ""; MSG_ERR("Could not determine dataset format for command line parameters"); } } else { fmt = filesType; } if (!fmt.empty()) _datasetImportController->ImportDataset(_controlExec, paths, fmt, DatasetImportController::DatasetExistsAction::ReplaceFirst); } app->installEventFilter(this); _controlExec->SetSaveStateEnabled(true); _controlExec->RebaseStateSave(); _paramsMgr->TriggerManualStateChangeEvent("Init"); _stateChangeFlag = false; if (interactive && GetSettingsParams()->GetAutoCheckForUpdates()) CheckForAndShowUpdate(_controlExec); if (interactive && GetSettingsParams()->GetAutoCheckForNotices()) NoticeBoard::CheckForAndShowNotices(_controlExec); NcarCasperUtils::CheckForCasperVGL(_controlExec); } int MainForm::RenderAndExit(int start, int end, const std::string &baseFile, int width, int height) { if (start == 0 && end == 0) end = INT_MAX; start = std::max(0, start); if (GetStateParams()->GetValueLong(GUIStateParams::SessionNewTag, false)) { fprintf(stderr, "No session loaded\n"); return -1; } QString dir = QString::fromStdString(FileUtils::Dirname(baseFile)); QFileInfo dirInfo(dir); if (!dirInfo.isWritable()) { fprintf(stderr, "Do not have write permissions\n"); return -1; } auto baseFileWithTS = FileUtils::RemoveExtension(baseFile) + "-" + to_string(start) + "." + FileUtils::Extension(baseFile); auto ap = GetAnimationParams(); auto vpp = _paramsMgr->GetViewpointParams(GetStateParams()->GetActiveVizName()); _paramsMgr->BeginSaveStateGroup("test"); ap->SetStartTimestep(start); ap->SetEndTimestep(end); vpp->SetValueLong(vpp->UseCustomFramebufferTag, "", true); vpp->SetValueLong(vpp->CustomFramebufferWidthTag, "", width); vpp->SetValueLong(vpp->CustomFramebufferHeightTag, "", height); if (_captureController->EnableAnimationCapture(baseFileWithTS)) { GUIStateParams *p = (GUIStateParams*)_paramsMgr->GetParams(GUIStateParams::GetClassType()); _capturingAnimationVizName = p->GetActiveVizName(); _animationController->AnimationPlayForward(); } _paramsMgr->EndSaveStateGroup(); connect(_animationController, &AnimationController::AnimationOnOffSignal, this, [this]() { _captureController->EndAnimationCapture(); _capturingAnimationVizName = ""; close(); }); connect(_animationController, &AnimationController::AnimationDrawSignal, this, [this]() { printf("Rendering timestep %li\n", GetAnimationParams()->GetCurrentTimestep()); }); return 0; } MainForm::~MainForm() { QApplication::closeAllWindows(); if (_banner) delete _banner; if (_controlExec) delete _controlExec; // This is required since if the user quits during the progressbar update, // qt will process the quit event and delete things, and then it will // return to the original event loop. // When Qt does recursive event loops like this, it has backend code that // prevents users from quiting. if (_insideMessedUpQtEventLoop) exit(0); } template bool MainForm::isDatasetValidFormat(const std::vector &paths) const { T dc; bool errReportingEnabled = Wasp::MyBase::EnableErrMsg(false); int ret = dc.Initialize(paths); Wasp::MyBase::EnableErrMsg(errReportingEnabled); return ret == 0; } bool MainForm::determineDatasetFormat(const std::vector &paths, std::string *fmt) const { vector> formats = { {"vdc", isDatasetValidFormat(paths)}, {"wrf", isDatasetValidFormat(paths)}, {"mpas", isDatasetValidFormat(paths)}, {"dcp", isDatasetValidFormat(paths)}, {"ugrid", isDatasetValidFormat(paths)}, {"cf", isDatasetValidFormat(paths)}, {"bov", isDatasetValidFormat(paths)}, }; int nOk = 0; for (auto &f : formats) { if (f.second) { nOk++; *fmt = f.first; } } if (nOk == 1) return true; MyBase::SetErrMsg("Unable to confidently determine the dataset format. Please load it manually in the GUI"); return false; } void MainForm::_createAnimationToolBar() { _animationToolBar = addToolBar("Animation Control"); _timeStepEdit = (new PTimestepInput(_controlExec))->SetTooltip("Edit/Display current time step"); _dependOnLoadedData_insert(_timeStepEdit); _animationToolBar->addWidget(_timeStepEdit); _dependOnLoadedData_insert(_animationToolBar); _guiStateParamsUpdatableElements.insert(_timeStepEdit); _playBackwardAction = _animationToolBar->addAction(QPixmap(playreverse), "Play Backward", _animationController, SLOT(AnimationPlayReverse())); _stepBackAction = _animationToolBar->addAction(QPixmap(stepback), "Step Backward", _animationController, SLOT(AnimationStepReverse())); _pauseAction = _animationToolBar->addAction(QPixmap(pauseimage), "Pause", _animationController, SLOT(AnimationPause())); _stepForwardAction = _animationToolBar->addAction(QPixmap(stepfwd), "Step Forward", _animationController, SLOT(AnimationStepForward())); _playForwardAction = _animationToolBar->addAction(QPixmap(playforward), "Play Forward", _animationController, SLOT(AnimationPlayForward())); _playForwardAction->setCheckable(true); _playBackwardAction->setCheckable(true); } void MainForm::createToolBars() { _createAnimationToolBar(); auto vt = new ViewpointToolbar(this, _controlExec, _vizWinMgr); _dependOnLoadedData_insert(vt); _updatableElements.insert(vt); addToolBar(vt); } void MainForm::_createProgressWidget() { #define MAX_UPDATES_PER_SEC 10 #define MILLIS_BETWEEN_UPDATES (1000 / MAX_UPDATES_PER_SEC) _progressLastUpdateTime = std::chrono::system_clock::now(); Progress::Update_t update = [this](long done, bool *cancelled) { if (!_progressEnabled) return; // Limit updates per second for perfomance reasons since this is on the same // thread as the calculation auto now = std::chrono::system_clock::now(); auto duration = chrono::duration_cast(now - _progressLastUpdateTime); if (duration.count() < MILLIS_BETWEEN_UPDATES || _insideMessedUpQtEventLoop) return; _progressLastUpdateTime = now; // Qt will clear the currently bound framebuffer for some reason bool insideOpenGL = isOpenGLContextActive(); if (insideOpenGL && _progressSavedFB < 0) { glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &_progressSavedFB); glBindFramebuffer(GL_FRAMEBUFFER, 0); } _status->SetDone(done); _disableUserInputForAllExcept = _status->GetCancelButtonObject(); _insideMessedUpQtEventLoop = true; QCoreApplication::processEvents(); _disableUserInputForAllExcept = nullptr; _insideMessedUpQtEventLoop = false; *cancelled = _status->Cancelled(); if (insideOpenGL && _progressSavedFB >= 0) { glBindFramebuffer(GL_FRAMEBUFFER, _progressSavedFB); _progressSavedFB = -1; } }; Progress::Start_t start = [this, update](const std::string &name, long total, bool cancelable) { if (!_progressEnabled) return; _status->StartTask(name, total, cancelable); update(0, &cancelable); }; Progress::Finish_t finish = [this, update]() { if (!_progressEnabled) return; _status->Finish(); bool b; update(0, &b); }; Progress::SetHandlers(start, update, finish); _status->show(); if (_progressEnabledMenuItem) _progressEnabledMenuItem->setChecked(true); } void MainForm::_disableProgressWidget() { Progress::Finish(); Progress::SetHandlers([](const string &, long, bool) {}, [](long, bool *) {}, []() {}); _status->hide(); if (_progressEnabledMenuItem) _progressEnabledMenuItem->setChecked(false); } void MainForm::_createFileMenu() { auto fileMenu = menuBar()->addMenu(tr("File")); fileMenu->addAction("New Session", this, &MainForm::sessionNew, QKeySequence("Ctrl+N")); fileMenu->addAction("Open Session", this, &MainForm::showOpenSessionGUI, QKeySequence("Ctrl+O")); fileMenu->addAction("Save Session", this, qOverload<>(&MainForm::SaveSession), QKeySequence("Ctrl+S")); fileMenu->addAction("Save Session As...", this, &MainForm::SaveSessionAs); fileMenu->addSeparator(); auto importMenu = fileMenu->addMenu("Import Dataset"); _updatableElements.insert(new UCloseVDCMenu(fileMenu, _controlExec)); auto addImport = [this, importMenu](const auto &fmt, const auto &label) { importMenu->addAction(label, this, [this, fmt]() { showImportDatasetGUI(fmt); }); }; addImport("vdc", "VDC"); addImport("wrf", "WRF-ARW"); addImport("cf", "NetCDF-CF"); addImport("mpas", "MPAS"); addImport("bov", "Brick of Values (BOV)"); addImport("dcp", "Data Collection Particles (DCP)"); addImport("ugrid", "Unstructured Grid (UGRID)"); fileMenu->addSeparator(); fileMenu->addAction("Exit", this, SLOT(close())); } void MainForm::_createEditMenu() { auto editMenu = menuBar()->addMenu(tr("Edit")); _editUndoAction = editMenu->addAction("Undo", this, [this](){ _paramsMgr->Undo(); }, QKeySequence("Ctrl+Z")); _editRedoAction = editMenu->addAction("Redo", this, [this](){ _paramsMgr->Redo(); }); #ifdef WIN32 _editRedoAction->setShortcut(QKeySequence("Ctrl+Y")); #else _editRedoAction->setShortcut(QKeySequence("Ctrl+Shift+Z")); #endif editMenu->addSeparator(); editMenu->addAction("Preferences", _appSettingsMenu, &QDialog::open); editMenu->addSeparator(); auto bm = new BookmarkManager(this, _controlExec, _vizWinMgr); bm->RegisterToMenu(editMenu); _updatableElements.insert(bm); } void MainForm::_createToolsMenu() { auto toolMenu = menuBar()->addMenu("Tools"); _dependOnLoadedData_insert(toolMenu->addAction("Plot Utility", this, SLOT(launchPlotUtility()))); _dependOnLoadedData_insert(toolMenu->addAction("Data Statistics", this, SLOT(launchStats()))); _dependOnLoadedData_insert(toolMenu->addAction("Python Variables", this, SLOT(launchPythonVariables()))); _dependOnLoadedData_insert(toolMenu->addAction("Dataset Projection", this, SLOT(launchProjectionFrame()))); #ifdef WIN32 #define ADD_INSTALL_CLI_TOOLS_ACTION 1 #endif #ifdef Darwin #define ADD_INSTALL_CLI_TOOLS_ACTION 1 #endif #ifdef ADD_INSTALL_CLI_TOOLS_ACTION toolMenu->addSeparator(); auto installCLIToolsAction = toolMenu->addAction("Install Command Line Tools", [](){ CLIToolInstaller::Install(); }); installCLIToolsAction->setToolTip("Add VAPOR_HOME to environment and add current utilities " "location to path. Needs to updated if app bundle moved"); #endif } void MainForm::_createHelpMenu() { auto helpMenu = menuBar()->addMenu(tr("Help")); helpMenu->addAction("Online Documentation", [](){ bool success = QDesktopServices::openUrl(QString::fromStdString("https://ncar.github.io/VaporDocumentationWebsite/")); if (!success) { MSG_ERR("Unable to launch Web browser for URL"); } }); helpMenu->addSeparator(); helpMenu->addAction("About VAPOR", this, &MainForm::helpAbout); } void MainForm::_createDeveloperMenu() { _paramsWidgetDemo = new ParamsWidgetDemo; _guiStateParamsUpdatableElements.insert(_paramsWidgetDemo); _developerMenu = menuBar()->addMenu("Developer"); _developerMenu->addAction("Show PWidget Demo", _paramsWidgetDemo, &QWidget::show); QAction *enableProgress = new QAction(QString("Enable Progress Bar"), nullptr); enableProgress->setCheckable(true); QObject::connect(enableProgress, &QAction::toggled, [this](bool checked) { if (checked) _createProgressWidget(); else _disableProgressWidget(); }); _developerMenu->addAction(enableProgress); _progressEnabledMenuItem = enableProgress; #ifdef BUILD_OSPRAY _developerMenu->addAction(QString::fromStdString("OSPRay " + VOSP::Version()))->setDisabled(true); #endif } void MainForm::createMenus() { _createFileMenu(); _createEditMenu(); _createToolsMenu(); _captureMenu = menuBar()->addMenu(tr("Capture")); QAction* a = new QAction("Image capture controls have been moved to the Export Tab", _captureMenu); a->setEnabled(false); _captureMenu->addAction(a); _createHelpMenu(); #ifndef NDEBUG _createDeveloperMenu(); #endif menuBar()->adjustSize(); } void MainForm::openSession(const string &path, bool loadData) { closeAllParamsDatasets(); closeProjectionFrame(); auto datasetConflictAction = loadData ? ControlExec::LoadStateRelAndAbsPathsExistAction::Ask : ControlExec::LoadStateRelAndAbsPathsExistAction::LoadAbs; retryLoad: try { int rc = _controlExec->LoadState(path, datasetConflictAction); if (rc < 0) { MSG_ERR("Failed to restore session from file"); _controlExec->LoadState(); return; } } catch(ControlExec::RelAndAbsPathsExistException const &e) { auto a = showSelectRelVAbsDataLoadGUI(e); if (!a) { sessionNew(); return; } datasetConflictAction = a.value(); goto retryLoad; } auto gsp = GetStateParams(); GetSettingsParams()->LoadFromSettingsFile(); gsp->SetCurrentSessionFile(path); if (loadData) checkSessionDatasetsExist(); else for (auto name : gsp->GetOpenDataSetNames()) gsp->RemoveOpenDataSet(name); _paramsMgr->UndoRedoClear(); gsp->SetValueLong(GUIStateParams::SessionNewTag, "Open dataset as a new session", false); _stateChangeFlag = false; _paramsMgr->TriggerManualStateChangeEvent("Session Opened"); _leftPanel->GoToRendererTab(); } void MainForm::showOpenSessionGUI() { if (_stateChangeFlag) { QMessageBox msgBox; msgBox.setWindowTitle("Are you sure?"); msgBox.setText("The current session settings are not saved. Do you want to continue? \nYou can choose \"No\" now to go back and save the current session."); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); if (msgBox.exec() == QMessageBox::No) { return; } } string sessionDir = GetStateParams()->GetCurrentSessionFile(); if (sessionDir.empty()) sessionDir = GetSettingsParams()->GetSessionDir(); const vector files = getUserFileSelection("Choose a VAPOR session file to restore a session", sessionDir, "Vapor 3 Session Save Files (*.vs3)", false); if (files.empty()) return; const string path = files[0]; if (!FileOperationChecker::FileGoodToRead(path.c_str())) { MSG_ERR(FileOperationChecker::GetLastErrorMessage().toStdString()); return; } openSession(path); } optional MainForm::showSelectRelVAbsDataLoadGUI(const ControlExec::RelAndAbsPathsExistException &e) { QStringList items({QString::fromStdString(e.AbsolutePath), QString::fromStdString(e.RelativePath)}); bool ok; QString item = QInputDialog::getItem(this, tr("Load Data"), tr("Multiple dataset options found. Select which to load."), items, 0, false, &ok); if (!ok || item.isEmpty()) return {}; if (item.toStdString() == e.RelativePath) return ControlExec::LoadStateRelAndAbsPathsExistAction::LoadRel; if (item.toStdString() == e.AbsolutePath) return ControlExec::LoadStateRelAndAbsPathsExistAction::LoadAbs; return {}; } void MainForm::checkSessionDatasetsExist() { GUIStateParams *sp = GetStateParams(); for (const auto & dataset : sp->GetOpenDataSetNames()) { vector paths = sp->GetOpenDataSetPaths(dataset); if (!std::all_of(paths.begin(), paths.end(), [](string path) { return FileUtils::Exists(path); })) { sp->RemoveOpenDataSet(dataset); string err = "This session links to the dataset " + dataset + " which was not found. Please open this dataset if it is in a different location"; string details; for (const auto &path : paths) if (!FileUtils::Exists(path)) details += "\"" + path + "\" not found.\n"; ErrorReporter::GetInstance()->Report(err, ErrorReporter::Warning, details); } } } void MainForm::closeAllParamsDatasets() { GUIStateParams *p = GetStateParams(); vector dataSetNames = p->GetOpenDataSetNames(); for (int i = 0; i < dataSetNames.size(); i++) { _controlExec->CloseData(dataSetNames[i]); } } void MainForm::SaveSession() { const auto currentSessionPath = GetStateParams()->GetCurrentSessionFile(); if (currentSessionPath.empty()) SaveSessionAs(); else SaveSession(currentSessionPath); } void MainForm::SaveSession(string path) { assert(!path.empty()); if (!FileOperationChecker::FileGoodToWrite(QString::fromStdString(path))) { MSG_ERR(FileOperationChecker::GetLastErrorMessage().toStdString()); return; } if (_controlExec->SaveSession(path) < 0) { MSG_ERR("Saving session file failed"); return; } GUIStateParams *p = GetStateParams(); _paramsMgr->PushSaveStateEnabled(false); p->SetCurrentSessionFile(path); _paramsMgr->PopSaveStateEnabled(); _stateChangeFlag = false; } void MainForm::SaveSessionAs() { SettingsParams *sP = GetSettingsParams(); GUIStateParams *guiStateParams = GetStateParams(); string dir; if (!guiStateParams->GetCurrentSessionFile().empty()) dir = guiStateParams->GetCurrentSessionFile(); else dir = sP->GetSessionDir(); QFileDialog fileDialog(this, "Save VAPOR session file", QString::fromStdString(dir), QString("Vapor 3 Session Save file (*.vs3)")); fileDialog.setAcceptMode(QFileDialog::AcceptSave); fileDialog.setDefaultSuffix(QString("vs3")); if (fileDialog.exec() != QDialog::Accepted) return; QStringList files = fileDialog.selectedFiles(); if (files.isEmpty() || files.size() > 1) return; SaveSession(files[0].toStdString()); } void MainForm::_stateChangeCB() { if (_paramsEventQueued) return; _paramsEventQueued = true; QEvent *event = new QEvent(ParamsChangeEvent); QApplication::postEvent(this, event); _eventsSinceLastSave++; } void MainForm::_intermediateStateChangedCB() { if (_paramsEventQueued) return; _paramsEventQueued = true; QEvent *event = new QEvent(ParamsIntermediateChangeEvent); QApplication::postEvent(this, event); } void MainForm::helpAbout() { std::string banner_file_name = "vapor_banner.png"; if (_banner) delete _banner; std::string banner_text = "Visualization and Analysis Platform for atmospheric, Oceanic and " "solar Research.\n\n" "Developed by the National Center for Atmospheric Research's (NCAR) \n" "Computational and Information Systems Lab. \n\n" "Boulder, Colorado 80305, U.S.A.\n" "Web site: http://www.vapor.ucar.edu\n" "Contact: vapor@ucar.edu\n" "Version: " + string(Version::GetFullVersionString().c_str()); _banner = new BannerGUI(this, banner_file_name, -1, true, banner_text.c_str(), "http://www.vapor.ucar.edu"); } void MainForm::showImportDatasetGUI(string format) { static vector> prompts = GetDatasets(); string defaultPath; auto openDatasets = GetStateParams()->GetOpenDataSetNames(); if (!openDatasets.empty()) defaultPath = GetStateParams()->GetOpenDataSetPaths(openDatasets.back())[0]; else defaultPath = GetSettingsParams()->GetMetadataDir(); auto files = getUserFileSelection(DatasetTypeDescriptiveName(format), defaultPath, "", format!="vdc"); if (files.empty()) return; _datasetImportController->ImportDataset(_controlExec, files, format, DatasetImportController::DatasetExistsAction::Prompt); } bool MainForm::doesQStringContainNonASCIICharacter(const QString &s) { for (int i = 0; i < s.length(); i++) if (s.at(i).unicode() > 127) return true; return false; } int MainForm::checkQStringContainsNonASCIICharacter(const QString &s) { if (doesQStringContainNonASCIICharacter(s)) { #ifdef WIN32 MyBase::SetErrMsg("Windows will convert a colon (common in WRF timestamps) to a non-ASCII dot character. This needs to be renamed.\n"); #endif MyBase::SetErrMsg("Vapor does not support paths with non-ASCII characters.\n"); MSG_ERR("Non ASCII Character in path"); return -1; } return 0; } vector MainForm::getUserFileSelection(string prompt, string dir, string filter, bool multi) { QString qPrompt(prompt.c_str()); QString qDir(dir.c_str()); QString qFilter(filter.c_str()); vector files; if (multi) { QStringList fileNames = QFileDialog::getOpenFileNames(this, qPrompt, qDir, qFilter); QStringList list = fileNames; QStringList::Iterator it = list.begin(); while (it != list.end()) { if (!it->isNull()) { if (checkQStringContainsNonASCIICharacter(*it) < 0) return {}; files.push_back((*it).toStdString()); } ++it; } } else { QString fileName = QFileDialog::getOpenFileName(this, qPrompt, qDir, qFilter); if (!fileName.isNull()) { if (checkQStringContainsNonASCIICharacter(fileName) < 0) return {}; files.push_back(fileName.toStdString()); } } for (int i = 0; i < files.size(); i++) { QFileInfo fInfo(files[i].c_str()); if (!fInfo.isReadable() || !fInfo.isFile()) { MyBase::SetErrMsg("File %s not readable", files[i].c_str()); MSG_ERR("Invalid file selection"); return {}; } } return (files); } void MainForm::sessionNew() { // Disable "Are you sure?" popup in debug build #ifdef NDEBUG if (_stateChangeFlag) { QMessageBox msgBox; msgBox.setWindowTitle("Are you sure?"); msgBox.setText("The current session settings are not saved. Do you want to continue? \nYou can choose \"No\" now to go back and save the current session."); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); if (msgBox.exec() == QMessageBox::No) { return; } } #endif closeProjectionFrame(); _controlExec->LoadState(); GetStateParams()->SetActiveVizName(_paramsMgr->CreateVisualizerParamsInstance()); _paramsMgr->UndoRedoClear(); _stateChangeFlag = false; GetStateParams()->SetValueLong(GUIStateParams::SessionNewTag, "Toggle SessionNewTag to true for a new session", true); } void MainForm::_setAnimationOnOff(bool on) { if (on) { enableAnimationWidgets(false); _App->removeEventFilter(this); } else { _playForwardAction->setChecked(false); _playBackwardAction->setChecked(false); enableAnimationWidgets(true); _App->installEventFilter(this); _paramsEventQueued = false; } } void MainForm::showCitationReminder() { // Disable citation reminder in Debug build #ifndef NDEBUG return; #endif if (!_begForCitation) return; _begForCitation = false; CitationReminder::Show(); } void MainForm::Render(bool fast, bool skipSync) { bool wasMenuBarEnabled = menuBar()->isEnabled(); bool wasProgressEnabled = _progressEnabled; menuBar()->setEnabled(false); _progressEnabled = true; if (!skipSync) { setUpdatesEnabled(false); _controlExec->SyncWithParams(); setUpdatesEnabled(true); } _vizWinMgr->Update(fast); _progressEnabled = wasProgressEnabled; menuBar()->setEnabled(wasMenuBarEnabled); } bool MainForm::eventFilter(QObject *obj, QEvent *event) { VAssert(_controlExec && _vizWinMgr); if (event->type() == ParamsChangeEvent || event->type() == ParamsIntermediateChangeEvent) { _controlExec->EnforceDefaultAppState(); _paramsEventQueued = false; } if (_insideMessedUpQtEventLoop) { // Prevent menu item actions from running if (event->type() == QEvent::MetaCall) return true; // Prevent queued ParamsChangedEvents from recursively running if (event->type() == ParamsChangeEvent || event->type() == ParamsIntermediateChangeEvent) return true; // Prevent user input for all widgets except the cancel button. This is essentially // the same behavior as we had before because the application would // freeze during a render so all user input was essentially blocked. // Since the events are processed top-down, we need to check to check // if this is not only the cancel button, but any of its parents if (_disableUserInputForAllExcept != nullptr && obj->isWidgetType()) { if (dynamic_cast(event)) { const QObject *test = _disableUserInputForAllExcept; do { if (obj == test) return false; // Approve input } while (test = test->parent()); return true; // Reject input } } } if (event->type() == ParamsChangeEvent) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); setUpdatesEnabled(false); _controlExec->SyncWithParams(); updateUI(); setUpdatesEnabled(true); Render(false, true); QApplication::restoreOverrideCursor(); return true; } if (event->type() == ParamsIntermediateChangeEvent) { // Rendering the GUI becomes a bottleneck and generally should not be affected by intermediate changes // updateUI(); #ifndef NDEBUG // Normally GUI doesn't get intermediate changes but this is for testing only _paramsWidgetDemo->Update(GetStateParams(), _paramsMgr); #endif Render(true); return true; } return false; } void MainForm::updateMenus() { _editUndoAction->setEnabled((bool)_paramsMgr->UndoSize()); _editRedoAction->setEnabled((bool)_paramsMgr->RedoSize()); } void MainForm::_performSessionAutoSave() { if (_paramsMgr == NULL) return; SettingsParams *sParams = GetSettingsParams(); if (sParams == NULL) return; int eventCountForAutoSave = sParams->GetChangesPerAutoSave(); if (eventCountForAutoSave == 0) return; if (!sParams->GetSessionAutoSaveEnabled()) return; if (_eventsSinceLastSave >= eventCountForAutoSave) { string autoSaveFile = sParams->GetAutoSaveSessionFile(); int rc = _paramsMgr->SaveToFile(autoSaveFile); if (rc < 0) { MSG_ERR("Unable to write settings file " + autoSaveFile); } _eventsSinceLastSave = 0; } } void MainForm::updateUI() { VAssert(_controlExec); _widgetsEnabled = !GetStateParams()->GetOpenDataSetNames().empty(); for (auto &e : _dependOnLoadedData) e->setEnabled(_widgetsEnabled); _leftPanel->ConfigureEnabledState(_widgetsEnabled); for (const auto &e : _updatableElements) e->Update(); auto sp= _widgetsEnabled ? GetStateParams() : nullptr; for (const auto &e : _guiStateParamsUpdatableElements) e->Update(sp, _paramsMgr); _timeStepEdit->Update(GetStateParams()); // TODO this needs special handling for animation playback updateMenus(); _appSettingsMenu->Update(GetSettingsParams()); _performSessionAutoSave(); } void MainForm::enableAnimationWidgets(bool on) { if (on) { _playBackwardAction->setEnabled(true); _stepBackAction->setEnabled(true); _stepForwardAction->setEnabled(true); _playForwardAction->setEnabled(true); } else { _animationToolBar->setEnabled(true); _playBackwardAction->setEnabled(false); _stepBackAction->setEnabled(false); _stepForwardAction->setEnabled(false); _playForwardAction->setEnabled(false); } } void MainForm::launchStats() { if (!_stats) { _stats = new Statistics(this); _updatableElements.insert(_stats); connect(_stats, &QDialog::finished, this, &MainForm::_statsClosed); } if (_controlExec) { _stats->initControlExec(_controlExec); } _stats->showMe(); } void MainForm::_statsClosed() { _updatableElements.erase(_stats); delete _stats; _stats = nullptr; } void MainForm::launchPlotUtility() { if (!_plot) { _plot = new Plot(_controlExec->GetDataStatus(), _controlExec->GetParamsMgr(), this); _updatableElements.insert(_plot); connect(_plot, &QDialog::finished, this, &MainForm::_plotClosed); } _plot->Update(); _plot->open(); } void MainForm::_plotClosed() { _updatableElements.erase(_plot); delete _plot; _plot = nullptr; } void MainForm::launchPythonVariables() { if (!_pythonVariables){ _pythonVariables = new PythonVariables(this); _updatableElements.insert(_pythonVariables); } _pythonVariables->InitControlExec(_controlExec); _pythonVariables->ShowMe(); } void MainForm::launchProjectionFrame() { if (_projectionFrame == nullptr){ _projectionFrame = new VProjectionStringFrame(new PProjectionStringWidget(_controlExec)); connect(_projectionFrame, &VProjectionStringFrame::closed, this, &MainForm::closeProjectionFrame); _projectionFrame->adjustSize(); _projectionFrame->Update(GetStateParams()); _guiStateParamsUpdatableElements.insert(_projectionFrame); } _projectionFrame->raise(); } void MainForm::closeProjectionFrame() { if (_projectionFrame != nullptr) { _guiStateParamsUpdatableElements.erase(_projectionFrame); _projectionFrame->close(); _projectionFrame = nullptr; } } void MainForm::AnimationPlayForward() const { _animationController->AnimationPlayForward(); } ================================================ FILE: apps/vaporgui/MainForm.h ================================================ #pragma once #include "vapor/VAssert.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AnimationController.h" #include "PWidgetsFwd.h" #include "QEnableable.h" class QApplication; class QSpacerItem; class QMenu; class QToolBar; class QWidget; class QMdiArea; class QLabel; class QSpinBox; class ProgressStatusBar; class QTimer; class QDialog; class VizWinMgr; class Updatable; class ParamsUpdatable; class BannerGUI; class Statistics; class Plot; class PythonVariables; class VProjectionStringFrame; class ErrorReporter; class ParamsWidgetDemo; class AppSettingsMenu; class CaptureController; class DatasetImportController; class LeftPanel; using namespace VAPoR; using std::optional; class MainForm : public QMainWindow { Q_OBJECT public: MainForm(vector files, QApplication *app, bool interactive = true, string filesType = "auto", QWidget *parent = 0); ~MainForm(); int RenderAndExit(int start, int end, const std::string &baseFile, int width, int height); static QWidget* Instance() { assert(_instance); return _instance; } // Needed for Export/Capture widget void AnimationPlayForward() const; protected: void Render(bool fast=false, bool skipSync=false); bool eventFilter(QObject *obj, QEvent *event); private: static const QEvent::Type ParamsChangeEvent; static const QEvent::Type ParamsIntermediateChangeEvent; QApplication *_App; static MainForm *_instance; QAction *_playForwardAction; QAction *_playBackwardAction; QAction *_pauseAction; QAction * _editUndoAction; QAction * _editRedoAction; PWidget * _timeStepEdit; QMenu * _captureMenu; QMenu * _developerMenu; QToolBar *_animationToolBar; QAction *_stepForwardAction; QAction *_stepBackAction; int _progressSavedFB = -1; bool _progressEnabled = false; QAction *_progressEnabledMenuItem = nullptr; ProgressStatusBar * _status = nullptr; std::chrono::time_point _progressLastUpdateTime; const QObject * _disableUserInputForAllExcept = nullptr; bool _insideMessedUpQtEventLoop = false; LeftPanel *_leftPanel; Statistics * _stats = nullptr; Plot * _plot = nullptr; PythonVariables * _pythonVariables = nullptr; VProjectionStringFrame* _projectionFrame = nullptr; AppSettingsMenu * _appSettingsMenu = nullptr; BannerGUI * _banner = nullptr; std::set _updatableElements; std::set _guiStateParamsUpdatableElements; std::set> _dependOnLoadedData; template void _dependOnLoadedData_insert(T *o) { _dependOnLoadedData.insert(std::make_unique>(o)); } VAPoR::ControlExec *_controlExec; VAPoR::ParamsMgr * _paramsMgr; CaptureController *_captureController; DatasetImportController *_datasetImportController; AnimationController *_animationController; VizWinMgr * _vizWinMgr; string _capturingAnimationVizName; bool _stateChangeFlag = false; bool _sessionNewFlag = false; bool _begForCitation = false; int _eventsSinceLastSave = 0; bool _paramsEventQueued = false; bool _widgetsEnabled; ParamsWidgetDemo *_paramsWidgetDemo = nullptr; void _performSessionAutoSave(); void _stateChangeCB(); void _intermediateStateChangedCB(); QApplication *getApp() { return _App; } void setPause() { _playForwardAction->setChecked(false); _playBackwardAction->setChecked(false); _pauseAction->setChecked(true); } void showCitationReminder(); GUIStateParams *GetStateParams() const { return ((GUIStateParams *)_paramsMgr->GetParams(GUIStateParams::GetClassType())); } SettingsParams *GetSettingsParams() const { return ((SettingsParams *)_paramsMgr->GetParams(SettingsParams::GetClassType())); } AnimationParams *GetAnimationParams() const { return ((AnimationParams *)_paramsMgr->GetParams(AnimationParams::GetClassType())); } void updateMenus(); void updateUI(); static bool doesQStringContainNonASCIICharacter(const QString &s); static int checkQStringContainsNonASCIICharacter(const QString &s); std::vector getUserFileSelection(string prompt, string dir, string filter, bool multi); void showImportDatasetGUI(string format); void openSession(const string &path, bool loadData=true); void showOpenSessionGUI(); optional showSelectRelVAbsDataLoadGUI(const ControlExec::RelAndAbsPathsExistException &e); void checkSessionDatasetsExist(); void _createToolsMenu(); void _createEditMenu(); void _createFileMenu(); void _createHelpMenu(); void _createDeveloperMenu(); void createMenus(); void _createAnimationToolBar(); void createToolBars(); void _createProgressWidget(); void _disableProgressWidget(); void closeAllParamsDatasets(); template bool isDatasetValidFormat(const std::vector &paths) const; bool determineDatasetFormat(const std::vector &paths, std::string *fmt) const; bool isOpenGLContextActive() const; void enableAnimationWidgets(bool onOff); void SaveSession(); void SaveSession(string path); void SaveSessionAs(); private slots: void _plotClosed(); void _statsClosed(); void closeProjectionFrame(); void helpAbout(); void sessionNew(); void launchStats(); void launchPlotUtility(); void launchPythonVariables(); void launchProjectionFrame(); void _setAnimationOnOff(bool onOff); }; ================================================ FILE: apps/vaporgui/MainForm_isOpenGLContextActive.cpp ================================================ #include "MainForm.h" #include // This is to address a warning caused by QOpenGLContext and vapor/glutil.h // being imported in the same file. bool MainForm::isOpenGLContextActive() const { return (bool)QOpenGLContext::currentContext(); } ================================================ FILE: apps/vaporgui/Manip.cpp ================================================ /************************************************************************/ // * // Copyright (C) 2005 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: Manip.cpp // // Author: Alan Norton, Scott Pearse // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: June, 2018 // // Description: Implements the Manip class and some of its subclasses #include #include #include #include "vapor/VAssert.h" #include #include "Manip.h" #include "vapor/GLManager.h" #include "vapor/LegacyGL.h" #define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH #include #include using glm::vec3; using namespace VAPoR; const float Manip::_faceSelectionColor[4] = {0.8f, 0.8f, 0.0f, 0.5f}; const float Manip::_unselectedFaceColor[4] = {0.8f, 0.2f, 0.0f, 0.5f}; #ifndef M_PI #define M_PI (3.14159265358979323846) #endif // X, Y, and Z axes are indexed 0, 1, and 2 #define X 0 #define Y 1 #define Z 2 // 6 element arrays that describe 3D extents have the ordering // MINX, MINY, MINZ, MAXX, MAXY, MAXZ #define MINX 0 #define MINY 1 #define MINZ 2 #define MAXX 3 #define MAXY 4 #define MAXZ 5 // Handle mapping #define X_Neg 2 #define X_Pos 3 #define Y_Neg 4 #define Y_Pos 1 #define Z_Neg 0 #define Z_Pos 5 #define INVALID_HANDLE -1 TranslateStretchManip::TranslateStretchManip(GLManager *glManager) : Manip(glManager) { _buttonNum = 0; _selectedHandle = -1; _isStretching = false; _tempRotation = 0.f; _tempRotAxis = -1; _handleSizeInScene = 1.; _dragDistance = 0.f; _mouseDownHere = false; for (int i = 0; i < 3; i++) { _initialSelectionRay[i] = 0.; _cameraPosition[i] = 0.; _handleMid[i] = 0.f; _selection[i] = 0.; _selection[i + 3] = 0.; _extents[i] = 0.; _extents[i + 3] = 0.; } } void TranslateStretchManip::transformMatrix(VAPoR::Transform *transform, std::vector parentScales) { MatrixManager *mm = _glManager->matrixManager; mm->MatrixModeModelView(); // Use the ModelViewMatrix passed in upon Update(), // not what is currently held in the gl state mm->LoadMatrixd(_modelViewMatrix); mm->PushMatrix(); if (transform == NULL) return; vector translations = transform->GetTranslations(); vector rotations = transform->GetRotations(); vector scales = transform->GetScales(); vector origin = transform->GetOrigin(); VAssert(translations.size() == 3); VAssert(rotations.size() == 3); VAssert(scales.size() == 3); VAssert(origin.size() == 3); mm->Translate(translations[0], translations[1], translations[2]); mm->Scale(1 / parentScales[0], 1 / parentScales[1], 1 / parentScales[2]); mm->Translate(origin[0], origin[1], origin[2]); mm->Rotate(glm::radians(rotations[0]), 1, 0, 0); mm->Rotate(glm::radians(rotations[1]), 0, 1, 0); mm->Rotate(glm::radians(rotations[2]), 0, 0, 1); mm->Scale(scales[0], scales[1], scales[2]); mm->Translate(-origin[0], -origin[1], -origin[2]); mm->Scale(parentScales[0], parentScales[1], parentScales[2]); // Retrieve the transformed matrix and stick it back into // our _modelViewMatrix array mm->GetDoublev(MatrixManager::Mode::ModelView, _modelViewMatrix); } void TranslateStretchManip::Update(std::vector llc, std::vector urc, std::vector minExts, std::vector maxExts, VAPoR::Transform *rpTransform, VAPoR::Transform *dmTransform, bool constrain) { MatrixManager *mm = _glManager->matrixManager; mm->GetDoublev(MatrixManager::Mode::Projection, _projectionMatrix); mm->GetDoublev(MatrixManager::Mode::ModelView, _modelViewMatrix); GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); _windowSize[0] = viewport[2]; _windowSize[1] = viewport[3]; double minv[16]; int rc = minvert(_modelViewMatrix, minv); VAssert(rc >= 0); _cameraPosition[X] = minv[12]; _cameraPosition[Y] = minv[13]; _cameraPosition[Z] = minv[14]; double defaultZ = 0; if (llc.size() == 2) llc.push_back(defaultZ); if (urc.size() == 2) urc.push_back(defaultZ); if (minExts.size() == 2) minExts.push_back(defaultZ); if (maxExts.size() == 2) maxExts.push_back(defaultZ); std::copy(llc.begin(), llc.end(), _selection); std::copy(urc.begin(), urc.end(), _selection + 3); std::copy(minExts.begin(), minExts.end(), _extents); std::copy(maxExts.begin(), maxExts.end(), _extents + 3); _rpTransform = rpTransform; _dmTransform = dmTransform; _constrain = constrain; } void TranslateStretchManip::GetBox(std::vector &llc, std::vector &urc) const { llc.resize(3); urc.resize(3); llc[X] = _selection[MINX]; llc[Y] = _selection[MINY]; llc[Z] = _selection[MINZ]; urc[X] = _selection[MAXX]; urc[Y] = _selection[MAXY]; urc[Z] = _selection[MAXZ]; } bool TranslateStretchManip::MouseEvent(int buttonNum, std::vector vscreenCoords, double handleMidpoint[3], bool release) { double screenCoords[2] = {vscreenCoords[0], vscreenCoords[1]}; if (_selectedHandle < 0) _selectedHandle = _mouseIsOverHandle(screenCoords, handleMidpoint); if (_selectedHandle < 0) return false; if (release) { // Release _mouseRelease(screenCoords); } else if (buttonNum == _buttonNum) { // Dragging if (!_mouseDownHere) return false; _mouseDrag(screenCoords, handleMidpoint); } else if (_buttonNum == 0) { // Press _mousePress(screenCoords, handleMidpoint, buttonNum); } return true; } void TranslateStretchManip::_mouseDrag(double screenCoords[2], double handleMidpoint[3]) { if (_selectedHandle >= 0) { double projScreenCoords[2]; bool success = projectPointToLine(screenCoords, projScreenCoords); if (success) { double dirVec[3]; double mouseWorldPos[3]; pixelToVector(projScreenCoords, dirVec, handleMidpoint, mouseWorldPos); vec3 norm(0, 0, 1); if (_selectedHandle == X_Neg || _selectedHandle == X_Pos) norm = vec3(1, 0, 0); if (_selectedHandle == Y_Neg || _selectedHandle == Y_Pos) norm = vec3(0, 1, 0); vec3 mouseWorld(mouseWorldPos[0], mouseWorldPos[1], mouseWorldPos[2]); vec3 handleWorld(handleMidpoint[0], handleMidpoint[1], handleMidpoint[2]); float handleProjToNorm = glm::dot(norm, handleWorld); float mouseProjToNorm = glm::dot(norm, mouseWorld); _dragDistance = mouseProjToNorm - handleProjToNorm; if (_buttonNum == 3) { // Don't restrict movement if using the manip to drag // Copied from old code // Prevent handle from going through opposite handle int oppositeHandle = (_selectedHandle < 3) ? (2 - _selectedHandle) : (_selectedHandle - 3); if (_selectedHandle < 3) { if (_dragDistance + _selection[oppositeHandle] > _selection[oppositeHandle + 3]) { _dragDistance = _selection[oppositeHandle + 3] - _selection[oppositeHandle]; } } else { // Moving "high" handle: if (_dragDistance + _selection[oppositeHandle + 3] < _selection[oppositeHandle]) { _dragDistance = _selection[oppositeHandle] - _selection[oppositeHandle + 3]; } } } } } } void TranslateStretchManip::_mousePress(double screenCoords[2], double handleMidpoint[3], int buttonNum) { double dirVec[3]; pixelToVector(screenCoords, dirVec, handleMidpoint); _captureMouseDown(_selectedHandle, buttonNum, handleMidpoint); startHandleSlide(screenCoords, _selectedHandle); setMouseDown(true); } void TranslateStretchManip::_mouseRelease(double screenCoords[2]) { if (_selectedHandle >= 0) { int axis = (_selectedHandle < 3) ? (2 - _selectedHandle) : (_selectedHandle - 3); // Convert _dragDistance to world coords: float dist = _dragDistance; // Check if we are stretching. If so, only move coords associated with // handle: if (_isStretching) { // boxMin gets changed for nearHandle, boxMax for farHandle if (_selectedHandle < 3) { _selection[axis] += dist; } else { _selection[axis + 3] += dist; } } else { // boxMin gets changed for nearHandle, boxMax for farHandle _selection[axis] += dist; _selection[axis + 3] += dist; } } if (_constrain) _constrainExtents(); _dragDistance = 0.f; _selectedHandle = -1; _buttonNum = 0; setMouseDown(false); } int TranslateStretchManip::_mouseIsOverHandle(const double screenCoords[2], double handleMid[3]) const { double handle[8][3]; int octant = 0; int face, handleNum; for (int axis = 0; axis < 3; axis++) { double axisBoundary = 0.5f * (_selection[axis] + _selection[axis + 3]); if (_cameraPosition[axis] > axisBoundary) { octant |= 1 << axis; } } // Front handles for (int sortNum = 0; sortNum < 3; sortNum++) { handleNum = makeHandleFaces(sortNum, handle, octant, _selection); if ((face = pointIsOnBox(handle, screenCoords)) >= 0) { for (int i = 0; i < 3; i++) { handleMid[i] = 0.; for (int k = 0; k < 8; k++) handleMid[i] += handle[k][i]; handleMid[i] /= 8.; } return handleNum; } } // Back handles for (int sortNum = 3; sortNum < 6; sortNum++) { handleNum = makeHandleFaces(sortNum, handle, octant, _selection); if ((face = pointIsOnBox(handle, screenCoords)) >= 0) { for (int i = 0; i < 3; i++) { handleMid[i] = 0.; for (int k = 0; k < 8; k++) handleMid[i] += handle[k][i]; handleMid[i] /= 8.; } return handleNum; } } return -1; } void TranslateStretchManip::_constrainExtents() { for (int i = 0; i < 3; i++) { // correct selection minimum if (_selection[i] < _extents[i]) _selection[i] = _extents[i]; if (_selection[i] > _extents[i + 3]) _selection[i] = _extents[i + 3]; // correct selection maximum if (_selection[i + 3] < _extents[i]) _selection[i + 3] = _extents[i]; if (_selection[i + 3] > _extents[i + 3]) _selection[i + 3] = _extents[i + 3]; } } bool TranslateStretchManip::pointIsOnQuad(double cor1[3], double cor2[3], double cor3[3], double cor4[3], const double pickPt[2]) const { double winCoord1[2]; double winCoord2[2]; double winCoord3[2]; double winCoord4[2]; bool returnValue = true; if (!_projectPointToWin(cor1, winCoord1)) returnValue = false; if (!_projectPointToWin(cor2, winCoord2)) returnValue = false; if (pointOnRight(winCoord1, winCoord2, pickPt)) returnValue = false; if (!_projectPointToWin(cor3, winCoord3)) returnValue = false; if (pointOnRight(winCoord2, winCoord3, pickPt)) returnValue = false; if (!_projectPointToWin(cor4, winCoord4)) returnValue = false; if (pointOnRight(winCoord3, winCoord4, pickPt)) returnValue = false; if (pointOnRight(winCoord4, winCoord1, pickPt)) returnValue = false; #ifdef DEBUG drawHitBox(winCoord1, winCoord2, winCoord3, winCoord4); #endif return returnValue; } int TranslateStretchManip::pointIsOnBox(double corners[8][3], const double pickPt[2]) const { // front (-Z) if (pointIsOnQuad(corners[0], corners[1], corners[3], corners[2], pickPt)) return 2; // back (+Z) if (pointIsOnQuad(corners[4], corners[6], corners[7], corners[5], pickPt)) return 3; // right (+X) if (pointIsOnQuad(corners[1], corners[5], corners[7], corners[3], pickPt)) return 5; // left (-X) if (pointIsOnQuad(corners[0], corners[2], corners[6], corners[4], pickPt)) return 0; // top (+Y) if (pointIsOnQuad(corners[2], corners[3], corners[7], corners[6], pickPt)) return 4; // bottom (-Y) if (pointIsOnQuad(corners[0], corners[4], corners[5], corners[1], pickPt)) return 1; return -1; } // Construct one of 6 cube-handles. The first 3 (0,1,2) are those in front of the probe // the octant (between 0 and 7) is a binary representation of the viewer relative to // the probe center. In binary, this value is ZYX, where Z is 1 if the viewer is above, // 0 if the viewer is below, similarly for Y and X. The handles are numbered from 0 to 5, // in the order -X, +X, -Y, +Y, -Z, +Z. // // We provide the handle in the appropriate sort order, based on the octant // in which the viewer is located. The sort position of a handle is either // N or (5-N) where N is the order sorted on x,y,z axes. It is 5-N if the // corresponding bit in the octant is 1. Octant is between 0 and 7 // with a bit for each axis (Z,Y,X order). // Return value is the absolute handle index, which may differ from the sort order. // If you want the faces in absolute order, just specify octant = 0 // // We make the handles in cube coords, since rendering and picking use that system. // This requires that we have boxCenter and boxWidth in cube coords. // HANDLE_DIAMETER is measured in pixels // These can be calculated from the boxRegion int TranslateStretchManip::makeHandleFaces(int sortPosition, double handle[8][3], int octant, const double boxRegion[6]) const { // Identify the axis this handle is on: int axis = (sortPosition < 3) ? (2 - sortPosition) : (sortPosition - 3); int newPosition = sortPosition; // If octant and axis share their sign, we invert the sortPosition to get newPosition...? if ((octant >> axis) & 1) newPosition = 5 - sortPosition; // Now create the cube associated with newPosition. It's just the handle translated // in the direction associated with newPosition float translateSign = (newPosition > 2) ? 1.f : -1.f; for (int vertex = 0; vertex < 8; vertex++) { for (int coord = 0; coord < 3; coord++) { float worldHandleDiameter = _handleSizeInScene; // Obtain the coordinate of unit cube corner. It's either +0.5 or -0.5 // multiplied by the handle diameter, then translated along the // specific axis corresponding to double fltCoord = (((double)((vertex >> coord) & 1) - 0.5f) * worldHandleDiameter); //_handleSizeInScene); // First offset it from the probeCenter: fltCoord += 0.5f * (boxRegion[coord + 3] + boxRegion[coord]); deScaleScalarOnAxis(worldHandleDiameter, coord); // Displace all the c - coords of this handle if this handle is on the c-axis if (coord == axis) { double boxWidth = (boxRegion[coord + 3] - boxRegion[coord]); // Note we are putting the handle 2 diameters from the box edge fltCoord += translateSign * (boxWidth * 0.5f + 2.f * worldHandleDiameter); //_handleSizeInScene); } handle[vertex][coord] = fltCoord; } } deScaleExtents(handle); return newPosition; } bool TranslateStretchManip::startHandleSlide(const double mouseCoords[2], int handleNum) { // When the mouse is first pressed over a handle, // need to save the // windows coordinates of the click, as well as // calculate a 2D unit vector in the direction of the slide, // projected into the window. _mouseDownPoint[0] = mouseCoords[0]; _mouseDownPoint[1] = mouseCoords[1]; // Get the cube coords of the rotation center: double boxCtr[3]; double winCoords[2] = {0., 0.}; double dispCoords[2]; if (handleNum > 2) handleNum = handleNum - 3; else handleNum = 2 - handleNum; for (int i = 0; i < 3; i++) { boxCtr[i] = (_selection[i] + _selection[i + 3]) * 0.5f; } // project the boxCtr and one more point, to get a direction vector if (!_projectPointToWin(boxCtr, winCoords)) return false; boxCtr[handleNum] *= 1.1f; if (!_projectPointToWin(boxCtr, dispCoords)) return false; // Direction vector is difference: _handleProjVec[0] = dispCoords[0] - winCoords[0]; _handleProjVec[1] = dispCoords[1] - winCoords[1]; float vecNorm = sqrt(_handleProjVec[0] * _handleProjVec[0] + _handleProjVec[1] * _handleProjVec[1]); if (vecNorm == 0.f) return false; _handleProjVec[0] /= vecNorm; _handleProjVec[1] /= vecNorm; return true; } // Project the current mouse coordinates to a line in screen space. // The line starts at the mouseDownPosition, and points in the // direction resulting from projecting to the screen the axis // associated with the dragHandle. Returns false on error. bool TranslateStretchManip::projectPointToLine(const double mouseCoords[2], double projCoords[2]) { // State saved at a mouse press is: // mouseDownPoint[2] = P // _handleProjVec[2] unit vector (U) // // When the mouse is moved, project to the line: // point Q projects to P + aU, where a = (Q-P).U = dotprod double diff[2]; if (!_mouseDownHere) return false; diff[0] = mouseCoords[0] - _mouseDownPoint[0]; diff[1] = mouseCoords[1] - _mouseDownPoint[1]; double dotprod = diff[0] * _handleProjVec[0] + diff[1] * _handleProjVec[1]; projCoords[0] = _mouseDownPoint[0] + dotprod * _handleProjVec[0]; projCoords[1] = _mouseDownPoint[1] + dotprod * _handleProjVec[1]; return true; } // Convert a screen coord to a vector, representing the displacedment // from the camera associated with the screen coords. Note screen coords // are OpenGL style. strHandleMid is in stretched coordinates. // bool TranslateStretchManip::pixelToVector(double winCoords[2], double dirVec[3], const double strHandleMid[3], double mouseWorldPos[3]) { GLdouble pt[3]; // Project handleMid to find its z screen coordinate: GLdouble screenz; GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" // gluProject(strHandleMid[0], strHandleMid[1], strHandleMid[2], _modelViewMatrix, _projectionMatrix, viewport, &screenx, &screeny, &screenz); glm::vec3 obj(strHandleMid[0], strHandleMid[1], strHandleMid[2]); glm::mat4 model, proj; for (int i = 0; i < 16; i++) ((float *)glm::value_ptr(model))[i] = _modelViewMatrix[i]; for (int i = 0; i < 16; i++) ((float *)glm::value_ptr(proj ))[i] = _projectionMatrix[i]; glm::vec4 vp(viewport[0], viewport[1], viewport[2], viewport[3]); vec3 screen = glm::project(obj, model, proj, vp); screenz = screen.z; // Obtain the coords of a point in view: // bool success = (0 != gluUnProject((GLdouble)winCoords[0], (GLdouble)winCoords[1], screenz, _modelViewMatrix, _projectionMatrix, viewport, pt, pt + 1, pt + 2)); glm::vec3 win(winCoords[0], winCoords[1], screenz); auto r = glm::unProject(win, model, proj, vp); pt[0] = r.x; pt[1] = r.y; pt[2] = r.z; _dragDistance = pt[2] - strHandleMid[2]; if (mouseWorldPos) memcpy(mouseWorldPos, pt, sizeof(double) * 3); #pragma GCC diagnostic pop // Subtract camera coords to get a direction vector: vsub(pt, _cameraPosition, dirVec); GL_ERR_BREAK(); return true; } // Find the handle extents using the boxExtents in world coords // Set the octant to be 0 if the sortPosition is just the // handleNum // If this is on the same axis as the selected handle it is displaced by _dragDistance // void TranslateStretchManip::makeHandleExtents(int sortPosition, double handleExtents[6], int octant, double boxExtents[6]) { // Identify the axis this handle is on: int axis = (sortPosition < 3) ? (2 - sortPosition) : (sortPosition - 3); int newPosition = sortPosition; if ((octant >> axis) & 1) newPosition = 5 - sortPosition; // Now create the cube associated with newPosition. It's just the handle translated // up or down in the direction associated with newPosition for (int coord = 0; coord < 3; coord++) { float worldHandleDiameter = _handleSizeInScene; // Start at the box center position handleExtents[coord] = .5f * (-worldHandleDiameter + (boxExtents[coord + 3] + boxExtents[coord])); handleExtents[coord + 3] = .5f * (worldHandleDiameter + (boxExtents[coord + 3] + boxExtents[coord])); deScaleScalarOnAxis(worldHandleDiameter, coord); if (coord == axis) { // Translate up or down along this axis // The translation is 2 handles + .5 box thickness double boxWidth = (boxExtents[coord + 3] - boxExtents[coord]); if (newPosition < 3) { //"low" handles are shifted down in the coord: handleExtents[coord] -= (boxWidth * 0.5f + 2.f * worldHandleDiameter); handleExtents[coord + 3] -= (boxWidth * 0.5f + 2.f * worldHandleDiameter); } else { handleExtents[coord] += (boxWidth * 0.5f + 2.f * worldHandleDiameter); handleExtents[coord + 3] += (boxWidth * 0.5f + 2.f * worldHandleDiameter); } } } deScaleExtents(handleExtents); return; } void TranslateStretchManip::deScaleScalarOnAxis(float &whd, int axis) const { if (_dmTransform == NULL) return; if (_rpTransform == NULL) return; vector dmScales = _dmTransform->GetScales(); vector rpScales = _rpTransform->GetScales(); whd /= dmScales[axis]; // whd /= rpScales[axis]; } // If we are deScaling a cube of the form extents[8][3], then that // cube will (apparently) contain its corner coordinates in the following form: // j = 0 1 2 (XYZ) // i // 0 min min min // 1 max min min // 2 min max min // 3 max max min // 4 min min max // 5 max min max // 6 min max max // 7 max max max // // This lookup table is how the extents are being rescaled in the for // loop below. // void TranslateStretchManip::deScaleExtents(double extents[8][3]) const { if (_dmTransform == NULL) return; if (_rpTransform == NULL) return; vector dmScales = _dmTransform->GetScales(); vector rpScales = _rpTransform->GetScales(); VAssert(rpScales.size() == 3); VAssert(dmScales.size() == 3); double size, midpoint, min, max; for (int i = 0; i < 3; i++) { // Vertex 0 contains the XYZ minimum coordinates // Vertex 7 contains the XYZ maximum coordinates size = extents[7][i] - extents[0][i]; size /= dmScales[i]; size /= rpScales[i]; midpoint = (extents[7][i] + extents[0][i]) / 2.f; min = midpoint - size / 2.f; max = midpoint + size / 2.f; for (int j = 0; j < 8; j++) { if (i == 0) { // X axis if (j % 2) extents[j][i] = min; else extents[j][i] = max; } else if (i == 1) { // Y axis if (j / 2 % 2) extents[j][i] = min; else extents[j][i] = max; } else if (i == 2) { // Z axis if (j < 4) extents[j][i] = min; else extents[j][i] = max; } } } } void TranslateStretchManip::deScaleExtents(double *extents) const { if (_dmTransform == NULL) return; if (_rpTransform == NULL) return; vector dmScales = _dmTransform->GetScales(); vector rpScales = _rpTransform->GetScales(); VAssert(rpScales.size() == 3); VAssert(dmScales.size() == 3); double size, midpoint; for (int i = 0; i < 3; i++) { size = extents[i + 3] - extents[i]; midpoint = (extents[i + 3] + extents[i]) / 2.f; size /= dmScales[i]; size /= rpScales[i]; extents[i] = midpoint - size / 2.f; extents[i + 3] = midpoint + size / 2.f; } } // Draw all the faces of a cube with specified extents. // Currently just used for handles. void TranslateStretchManip::drawCubeFaces(double *extents, bool isSelected) { LegacyGL *lgl = _glManager->legacy; GLfloat lineWidthRange[2] = {0.0f, 0.0f}; glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, lineWidthRange); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // Do left (x=0) if (isSelected) lgl->Color4fv(_faceSelectionColor); else lgl->Color4fv(_unselectedFaceColor); lgl->Begin(LGL_QUADS); lgl->Vertex3f(extents[MINX], extents[MINY], extents[MINZ]); lgl->Vertex3f(extents[MINX], extents[MINY], extents[MAXZ]); lgl->Vertex3f(extents[MINX], extents[MAXY], extents[MAXZ]); lgl->Vertex3f(extents[MINX], extents[MAXY], extents[MINZ]); lgl->End(); // do right if (isSelected) lgl->Color4fv(_faceSelectionColor); else lgl->Color4fv(_unselectedFaceColor); lgl->Begin(LGL_QUADS); lgl->Vertex3f(extents[MAXX], extents[MINY], extents[MINZ]); lgl->Vertex3f(extents[MAXX], extents[MINY], extents[MAXZ]); lgl->Vertex3f(extents[MAXX], extents[MAXY], extents[MAXZ]); lgl->Vertex3f(extents[MAXX], extents[MAXY], extents[MINZ]); lgl->End(); // top if (isSelected) lgl->Color4fv(_faceSelectionColor); else lgl->Color4fv(_unselectedFaceColor); lgl->Begin(LGL_QUADS); lgl->Vertex3f(extents[MINX], extents[MAXY], extents[MINZ]); lgl->Vertex3f(extents[MAXX], extents[MAXY], extents[MINZ]); lgl->Vertex3f(extents[MAXX], extents[MAXY], extents[MAXZ]); lgl->Vertex3f(extents[MINX], extents[MAXY], extents[MAXZ]); lgl->End(); // bottom if (isSelected) lgl->Color4fv(_faceSelectionColor); else lgl->Color4fv(_unselectedFaceColor); lgl->Begin(LGL_QUADS); lgl->Vertex3f(extents[MINX], extents[MINY], extents[MINZ]); lgl->Vertex3f(extents[MINX], extents[MINY], extents[MAXZ]); lgl->Vertex3f(extents[MAXX], extents[MINY], extents[MAXZ]); lgl->Vertex3f(extents[MAXX], extents[MINY], extents[MINZ]); lgl->End(); // back if (isSelected) lgl->Color4fv(_faceSelectionColor); else lgl->Color4fv(_unselectedFaceColor); lgl->Begin(LGL_QUADS); lgl->Vertex3f(extents[MINX], extents[MINY], extents[MINZ]); lgl->Vertex3f(extents[MAXX], extents[MINY], extents[MINZ]); lgl->Vertex3f(extents[MAXX], extents[MAXY], extents[MINZ]); lgl->Vertex3f(extents[MINX], extents[MAXY], extents[MINZ]); lgl->End(); // do the front: // if (isSelected) lgl->Color4fv(_faceSelectionColor); else lgl->Color4fv(_unselectedFaceColor); lgl->Begin(LGL_QUADS); lgl->Vertex3f(extents[MINX], extents[MINY], extents[MAXZ]); lgl->Vertex3f(extents[MAXX], extents[MINY], extents[MAXZ]); lgl->Vertex3f(extents[MAXX], extents[MAXY], extents[MAXZ]); lgl->Vertex3f(extents[MINX], extents[MAXY], extents[MAXZ]); lgl->End(); lgl->Color4f(1, 1, 1, 1); glDisable(GL_BLEND); } // Renders handles and box // If it is stretching, it only moves the one handle that is doing the stretching void TranslateStretchManip::Render() { transformMatrix(_dmTransform); if (_rpTransform != NULL) transformMatrix(_rpTransform, _dmTransform->GetScales()); _handleSizeInScene = getPixelSize() * (float)HANDLE_DIAMETER; double handleExtents[6]; for (int handleNum = 0; handleNum < 6; handleNum++) { makeHandleExtents(handleNum, handleExtents, 0 /*octant*/, _selection); if (_selectedHandle >= 0) { int axis = (_selectedHandle < 3) ? (2 - _selectedHandle) : (_selectedHandle - 3); // displace handleExtents appropriately if (_isStretching) { // modify the extents for the one grabbed handle if (_selectedHandle == handleNum) { handleExtents[axis] += _dragDistance; handleExtents[axis + 3] += _dragDistance; } // and make the handles on the non-grabbed axes move half as far: else if (handleNum != (5 - _selectedHandle)) { handleExtents[axis] += 0.5f * _dragDistance; handleExtents[axis + 3] += 0.5f * _dragDistance; } } else { handleExtents[axis] += _dragDistance; handleExtents[axis + 3] += _dragDistance; } } drawCubeFaces(handleExtents, (handleNum == _selectedHandle)); drawHandleConnector(handleNum, handleExtents, _selection); } // Then render the full box, unhighlighted and displaced drawBoxFaces(); MatrixManager *mm = _glManager->matrixManager; mm->PopMatrix(); // Pop the matrix applied for the DataMgr's transform if (_rpTransform != NULL) // Pop the matrix applied for the RenderParams' transform mm->PopMatrix(); } double TranslateStretchManip::getPixelSize() const { double temp[3]; // Window height is subtended by viewing angle (45 degrees), // at viewer distance (dist from camera to view center) size_t height = _windowSize[1]; double origin[3]; std::vector vorigin(3, 0.f); if (_dmTransform != NULL) vorigin = _dmTransform->GetOrigin(); for (int i = 0; i < 3; i++) { origin[i] = vorigin[i]; } vsub(origin, _cameraPosition, temp); float distToScene = vlength(temp); // tan(45 deg *0.5) is ratio between half-height and dist to scene double halfHeight = tan(M_PI * 0.125) * distToScene; return (2.f * halfHeight / (double)height); } // Draw the main box, just rendering the lines. // the highlightedFace is not the same as the selectedFace!! // void TranslateStretchManip::drawBoxFaces() const { double corners[8][3]; // -X -Y -Z corners[0][X] = _selection[MINX]; corners[0][Y] = _selection[MINY]; corners[0][Z] = _selection[MINZ]; // -X -Y +Z corners[1][X] = _selection[MINX]; corners[1][Y] = _selection[MINY]; corners[1][Z] = _selection[MAXZ]; // -X +Y -Z corners[2][X] = _selection[MINX]; corners[2][Y] = _selection[MAXY]; corners[2][Z] = _selection[MINZ]; // -X +Y +Z corners[3][X] = _selection[MINX]; corners[3][Y] = _selection[MAXY]; corners[3][Z] = _selection[MAXZ]; // +X -Y -Z corners[4][X] = _selection[MAXX]; corners[4][Y] = _selection[MINY]; corners[4][Z] = _selection[MINZ]; // +X -Y +Z corners[5][X] = _selection[MAXX]; corners[5][Y] = _selection[MINY]; corners[5][Z] = _selection[MAXZ]; // +X +Y -Z corners[6][X] = _selection[MAXX]; corners[6][Y] = _selection[MAXY]; corners[6][Z] = _selection[MINZ]; // +X +Y +Z corners[7][X] = _selection[MAXX]; corners[7][Y] = _selection[MAXY]; corners[7][Z] = _selection[MAXZ]; if (_selectedHandle >= 0) { if (_isStretching) _stretchCorners(corners); else if (_dragDistance != 0.) _translateCorners(corners); } // Now render the edges: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); // glLineWidth( 2.0 ); LegacyGL *lgl = _glManager->legacy; lgl->Color3f(1.f, 0.f, 0.f); lgl->Begin(GL_LINES); lgl->Vertex3dv(corners[0]); lgl->Vertex3dv(corners[1]); lgl->Vertex3dv(corners[0]); lgl->Vertex3dv(corners[2]); lgl->Vertex3dv(corners[0]); lgl->Vertex3dv(corners[4]); lgl->Vertex3dv(corners[1]); lgl->Vertex3dv(corners[3]); lgl->Vertex3dv(corners[1]); lgl->Vertex3dv(corners[5]); lgl->Vertex3dv(corners[2]); lgl->Vertex3dv(corners[3]); lgl->Vertex3dv(corners[2]); lgl->Vertex3dv(corners[6]); lgl->Vertex3dv(corners[3]); lgl->Vertex3dv(corners[7]); lgl->Vertex3dv(corners[4]); lgl->Vertex3dv(corners[5]); lgl->Vertex3dv(corners[4]); lgl->Vertex3dv(corners[6]); lgl->Vertex3dv(corners[5]); lgl->Vertex3dv(corners[7]); lgl->Vertex3dv(corners[6]); lgl->Vertex3dv(corners[7]); lgl->End(); glDisable(GL_BLEND); glDepthMask(GL_TRUE); } void TranslateStretchManip::_stretchCorners(double corners[8][3]) const { int axis = (_selectedHandle < 3) ? (2 - _selectedHandle) : (_selectedHandle - 3); // X axis if (axis == 0) { if (_selectedHandle == 2) _moveMinusXCorners(corners); else if (_selectedHandle == 3) _movePlusXCorners(corners); } // Y axis else if (axis == 1) { if (_selectedHandle == 4) _moveMinusYCorners(corners); else if (_selectedHandle == 1) _movePlusYCorners(corners); } // Z axis else if (axis == 2) { if (_selectedHandle == 0) _moveMinusZCorners(corners); else if (_selectedHandle == 5) _movePlusZCorners(corners); } } void TranslateStretchManip::_translateCorners(double corners[8][3]) const { int axis = (_selectedHandle < 3) ? (2 - _selectedHandle) : (_selectedHandle - 3); if (axis == 0) { _moveMinusXCorners(corners); _movePlusXCorners(corners); } else if (axis == 1) { _moveMinusYCorners(corners); _movePlusYCorners(corners); } else if (axis == 2) { _moveMinusZCorners(corners); _movePlusZCorners(corners); } } void TranslateStretchManip::_moveMinusXCorners(double corners[8][3]) const { corners[2][X] += _dragDistance; corners[0][X] += _dragDistance; corners[1][X] += _dragDistance; corners[3][X] += _dragDistance; } void TranslateStretchManip::_movePlusXCorners(double corners[8][3]) const { corners[4][X] += _dragDistance; corners[5][X] += _dragDistance; corners[6][X] += _dragDistance; corners[7][X] += _dragDistance; } void TranslateStretchManip::_moveMinusYCorners(double corners[8][3]) const { corners[2][Y] += _dragDistance; corners[3][Y] += _dragDistance; corners[6][Y] += _dragDistance; corners[7][Y] += _dragDistance; } void TranslateStretchManip::_movePlusYCorners(double corners[8][3]) const { corners[0][Y] += _dragDistance; corners[1][Y] += _dragDistance; corners[4][Y] += _dragDistance; corners[5][Y] += _dragDistance; } void TranslateStretchManip::_moveMinusZCorners(double corners[8][3]) const { corners[0][Z] += _dragDistance; corners[2][Z] += _dragDistance; corners[4][Z] += _dragDistance; corners[6][Z] += _dragDistance; } void TranslateStretchManip::_movePlusZCorners(double corners[8][3]) const { corners[1][Z] += _dragDistance; corners[3][Z] += _dragDistance; corners[5][Z] += _dragDistance; corners[7][Z] += _dragDistance; } // Note: This is performed in local (unstretched) world coordinates! void TranslateStretchManip::_captureMouseDown(int handleNum, int buttonNum, const double strHandleMid[3]) { _buttonNum = buttonNum; // Grab a probe handle _selectedHandle = handleNum; _dragDistance = 0.f; // Calculate intersection of ray with specified plane in unstretched coords // The selection ray is the vector from the camera to the intersection point for (int i = 0; i < 3; i++) _initialSelectionRay[i] = strHandleMid[i] - _cameraPosition[i]; if (buttonNum > 1) _isStretching = true; else _isStretching = false; // Reset any active rotation _tempRotation = 0.f; _tempRotAxis = -1; } // Draw a line connecting the specified handle to the box center. // Highlight both ends of the line to the selected handle // Note that handleExtents have already been displaced. // if _isStretching is true, // the box center only moves half as far. void TranslateStretchManip::drawHandleConnector(int handleNum, double *handleExtents, double *boxExtents) { LegacyGL *lgl = _glManager->legacy; // Determine the side of the handle and the side of the box that is connected: int axis = (handleNum < 3) ? (2 - handleNum) : (handleNum - 3); bool posSide = (handleNum > 2); double handleDisp[3], boxDisp[3]; // Every handle gets a line from its inside face to the center of the box. for (int i = 0; i < 3; i++) { // determine the box displacement, based on dimension: if ((i == (2 - _selectedHandle)) || (i == (_selectedHandle - 3))) { if (_isStretching) boxDisp[i] = 0.5f * _dragDistance; else boxDisp[i] = _dragDistance; } else boxDisp[i] = 0.f; // The line to the handle is displaced according to what axis the // handle is on (independent of the _dragDistance) // if (i == axis) { if (posSide) { // displace to lower (in-) side of handle handleDisp[i] = -0.5f * (handleExtents[i + 3] - handleExtents[i]); } else { // displace to upper (out-) side of handle handleDisp[i] = 0.5f * (handleExtents[i + 3] - handleExtents[i]); } } else { // don't displace other coordinates handleDisp[i] = 0.f; } } // glLineWidth( 2.0 ); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); if ((handleNum == _selectedHandle) || (handleNum == (5 - _selectedHandle))) lgl->Color4fv(_faceSelectionColor); else lgl->Color4fv(_unselectedFaceColor); lgl->Begin(GL_LINES); lgl->Vertex3f(0.5f * (handleExtents[MAXX] + handleExtents[MINX]) + handleDisp[X], 0.5f * (handleExtents[MAXY] + handleExtents[MINY]) + handleDisp[Y], 0.5f * (handleExtents[MAXZ] + handleExtents[MINZ]) + handleDisp[Z]); lgl->Vertex3f(0.5f * (boxExtents[MAXX] + boxExtents[MINX]) + boxDisp[X], 0.5f * (boxExtents[MAXY] + boxExtents[MINY]) + boxDisp[Y], 0.5f * (boxExtents[MAXZ] + boxExtents[MINZ]) + boxDisp[Z]); lgl->End(); glDisable(GL_BLEND); } // This is a utility to draw the hitbox over the handle. It can be // called from TranslateStretchManip::pointIsOnQuad(), but with a caveat. // Hitboxes are calculated during mouse events, at which time we are not // in a good state to perform rendering. // // VizWin has an openGL setup and cleanup sequence which must be applied // during VizWin::_mousePressEvent(). When done as shown below, the hitboxes // will be colored green during mouse press events. Hold the mouse to // illuminate the boxes. // // VizWin setup sequence: // // void VizWin:;_mousePressEvent(QMouseEvent* e) { // ... // ... // glMatrixMode(GL_PROJECTION); // Begin setup sequence // glPushMatrix(); // _setUpProjMatrix(); // glMatrixMode(GL_MODELVIEW); // glPushMatrix(); // _setUpModelViewMatrix(); // End setup sequence // // std::vector screenCoords = getScreenCoords(e); // bool mouseOnManip = _manip->MouseEvent( // _buttonNum, screenCoords, _strHandleMid // ); // // swapBuffers(); // Begin cleanup sequence // glMatrixMode(GL_PROJECTION); // glPopMatrix(); // glMatrixMode(GL_MODELVIEW); // glPopMatrix(); // End cleanup sequence // ... // ... // #ifdef DEBUG void TranslateStretchManip::drawHitBox(double winCoord1[2], double winCoord2[2], double winCoord4[2], double winCoord3[2]) const { glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glPushAttrib(GL_ALL_ATTRIB_BITS); GLint dims[4] = {0}; glGetIntegerv(GL_VIEWPORT, dims); GLint width = dims[2]; GLint height = dims[3]; gluOrtho2D(0, width, 0, height); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glBegin(GL_QUADS); // Each set of 4 vertices form a quad glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(winCoord1[0], winCoord1[1]); glVertex2f(winCoord2[0], winCoord2[1]); glVertex2f(winCoord3[0], winCoord3[1]); glVertex2f(winCoord4[0], winCoord4[1]); glEnd(); glFlush(); glPopAttrib(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glDisable(GL_BLEND); } #endif //_projectPointToWin returns true if point is in front of camera // resulting screen coords returned in 2nd argument. Note that // OpenGL coords are 0 at bottom of window! // bool TranslateStretchManip::_projectPointToWin(const double cubeCoords[3], double winCoords[2]) const { double depth; GLdouble wCoords[2]; GLdouble cbCoords[3]; for (int i = 0; i < 3; i++) cbCoords[i] = (double)cubeCoords[i]; GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" // bool success = (0 != gluProject(cbCoords[0], cbCoords[1], cbCoords[2], _modelViewMatrix, _projectionMatrix, viewport, wCoords, (wCoords + 1), (GLdouble *)(&depth))); glm::vec3 obj(cbCoords[0], cbCoords[1], cbCoords[2]); glm::mat4 model, proj; for (int i = 0; i < 16; i++) ((float *)glm::value_ptr(model))[i] = _modelViewMatrix[i]; for (int i = 0; i < 16; i++) ((float *)glm::value_ptr(proj ))[i] = _projectionMatrix[i]; glm::vec4 vp(viewport[0], viewport[1], viewport[2], viewport[3]); auto r = glm::project(obj, model, proj, vp); wCoords[0] = r.x; wCoords[1] = r.y; depth = r.z; #pragma GCC diagnostic pop // if (!success) return false; winCoords[0] = wCoords[0]; winCoords[1] = wCoords[1]; return (depth > 0.0); } ================================================ FILE: apps/vaporgui/Manip.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: Manip.h // // Author: Alan Norton // Scott Pearse // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: Vapor3 implementation - May 2018 // Vapor2 implementation - November 2005 // // Description: Defines the pure virtual Manip class // Subclasses of this class provide in-scene manipulators // for positioning and setting properties of objects // in the scene. #ifndef MANIP_H #define MANIP_H #include #include "vapor/Transform.h" // Handle diameter in pixels: #define HANDLE_DIAMETER 15 //#define HANDLE_DIAMETER 3 namespace VAPoR { struct GLManager; // class Visualizer; // class DataStatus; //! \class Manip //! \ingroup Public_Render //! \brief A class that supports manipulators in in a VAPOR Visualizer //! \author Alan Norton, Scott Pearse //! \version 3.0 //! \date July 2015, June 2018 //! //! Manip class is a pure virtual class that supports //! manipulators in the VAPOR Visualizer scene //! class Manip { public: Manip(GLManager *glManager) : _glManager(glManager){}; virtual ~Manip() {} //! Pure virtual function renders the geometry of the Manip. virtual void Render() = 0; //! Update the box manipulator's extents //! \param[in] llc : The lower-left corner to update the manipulator with //! \param[in] urc : The upper-right corner to update the manipulator with //! \param[in] minExtents : The minimum extents that the manipulator can draw to //! \param[in] maxExtents : The maximum extents that the manipulator can draw to /*! \param[in] rpTransform: The current scene transform used by the current * RenderParams */ /*! \param[in] dmTransform: The current scene transform used by the current * DataMgr */ /*! \param[in] constrain: Indicates whether the manipulator box is bound by * domain extents */ virtual void Update(std::vector llc, std::vector urc, std::vector minExtents, std::vector maxExtents, VAPoR::Transform *rpTransform, VAPoR::Transform *dmTransform, bool constrain) = 0; //! Notify that manipulator that is being moved with the mouse //! \param[in] buttonNum - The mouse button being used to move the manipulator //! \param[in] screenCoords - The current coordinates of the mouse cursor virtual bool MouseEvent(int buttonNum, std::vector screenCoords, double handleMidpoint[3], bool release = false) = 0; //! Method to retrieve the manipulator's current extents //! \param[out] llc - The lower-left coordinates of the manipulator //! \param[out] urc - The upper-right coordinates of the manipulator virtual void GetBox(std::vector &llc, std::vector &urc) const = 0; protected: //! Pure virtual method: Determine which handle (if any) is under mouse //! \param[in] mouse coordinates in screen /*! \param[out] handleMid is the coordinates of the center of the selected * handle (if selected). */ //! \return handle index, or -1 if no intersection virtual int _mouseIsOverHandle(const double screenCoords[2], double handleMid[3]) const = 0; //! General utility function for drawing axis-aligned cubes. //! \param[in] extents : extents of box to be drawn /*! \param[in] isSelected indicates if this box is to be drawn with the * selection color or not */ void _drawCubeFaces(double *extents, bool isSelected); //! Handles logic for a mouse-press event on one of the manip handles //! \param[in] screenCoords is a pixel location on the visualizer window /*! \param[in] handleMidpoint is the center of a handle to test that gets * tested against the screenCoords array. */ /*! param[in] buttonNum is the button of the mouse that is clicked, which * determines whether we are moving or stretching the manipulator. */ virtual void _mousePress(double screenCoords[2], double handleMidpoint[3], int buttonNum) = 0; //! Handles logic for moving a handle while a mouse button is held down. //! param[in] screenCoords is the current position of the mouse cursor //! param[in] handleMidpoint is the center of the handle being moved virtual void _mouseDrag(double screenCoords[2], double handleMidpoint[3]) = 0; /*! Handles logic to set the current extents of the manipulator, held in * the _selection array */ //! param[in] screenCoords - coordinates of the cursor upon mose release virtual void _mouseRelease(double screenCoords[2]) = 0; //! Adjust the corners of the manipulator extents according to _dragDistance //! param[in] corners describes the bounding box of the manipulator virtual void _stretchCorners(double corners[8][3]) const = 0; GLManager * _glManager; int _buttonNum; int _selectedHandle; double _dragDistance; double _handleMid[3]; double _selection[6]; double _extents[6]; double _cameraPosition[3]; static const float _faceSelectionColor[4]; static const float _unselectedFaceColor[4]; }; //! \class TranslateStretchManip //! \ingroup Public_Render //! \brief A Manip subclass for manipulators that stretch and translate //! \author Alan Norton, Scott Pearse //! \version 3.0 //! \date July 2015, June 2018 //! This subclass handles translation and stretching manip. Works //! with ArrowParams (rake). //! When you slide a handle with the right mouse it stretches the region class TranslateStretchManip : public Manip { public: TranslateStretchManip(GLManager *glManager); virtual ~TranslateStretchManip() {} virtual void Render(); //! @copydoc Manip::Update(std::vector, std::vector std::vector, std::vector) virtual void Update(std::vector llc, std::vector urc, std::vector minExtents, std::vector maxExtents, VAPoR::Transform *rpTransform, VAPoR::Transform *dmTransform, bool constrain); //! @copydoc Manip::MoveEvent(int, std::vector) virtual bool MouseEvent(int buttonNum, std::vector screenCoords, double handleMidpoint[3], bool release = false); //! @copydoc Manip::GetBox(std::vector, std::vector); virtual void GetBox(std::vector &llc, std::vector &urc) const; private: //! Determine if the mouse is over one of the manip handles. //! \param[in] screenCoords x,y screen position of mouse //! \param[out] handleMid coordinates of handle selected //! \return index of handle, or -1 if none. int _mouseIsOverHandle(const double screenCoords[2], double handleMid[3]) const; //! Method to be invoked when the mouse if first pressed over a handle. //! \param[in] handleNum is handle index 0..5 //! \param[in] buttonNum indicates which mouse button was pressed. /*! \param[out] strHandleMid specified 3D coordinates of handle middle in * stretched coordinates. */ void _captureMouseDown(int handleNum, int buttonNum, const double strHandleMid[3]); //! Method invoked when manip handle drag begins, invoked from VizWin. //! \param[in] mouseCoords coordinates where mouse is pressed. //! \param[in] handleNum index over which the mouse is pressed //! \return true if successful bool startHandleSlide(const double mouseCoords[2], int handleNum); /*! Set the status of the mouse, invoked when the mouse is pressed or * released. */ //! \param downUp true is the mouse is pressed for this manipulator. void setMouseDown(bool downUp) { _mouseDownHere = downUp; } //! Project the current mouse coordinates to a line in screen space. //! The line starts at the mouseDownPosition, and points in the //! direction resulting from projecting to the screen the axis //! associated with the dragHandle. Returns false on error. //! Invoked during mouseMoveEvent, uses values of mouseDownPoint(), //! handleProjVec(), mouseDownHere() //! \param[in] mouseCoords coordinates of mouse //! \param[out] projCoords coordinates of projected point. bool projectPointToLine(const double mouseCoords[2], double projCoords[2]); //! Determine a vector associated with a pixel, pointing from the //! camera, through the pixel into the scene to a manip handle. Uses OpenGL //! screencoords. //! I.e. y = 0 at bottom. Returns false on failure. Used during mouse Events. //! \param[in] winCoords pixel coordinates (converted to double) //! \param[out] dirVec resulting vector, from camera to handle //! \param[in] strHandleMid is middle of handle in stretched coordinates. //! \return true if successful bool pixelToVector(double winCoords[2], double dirVec[3], const double strHandleMid[3], double mouseWorldPos[3] = NULL); //! Method to render the faces of the manipulator handlebars virtual void drawBoxFaces() const; //! Method to indicate whether a screencoordinate that is projected //! into the scene intersects the coordinates of a cube face //! \param[in] cor1 first corner //! \param[in] cor2 second corner //! \param[in] cor3 third corner //! \param[in] cor4 fourth corner //! \param[in] pickPt the screen coordinate being projected into the scene //! \return true if the projected point intesects the quad virtual bool pointIsOnQuad(double cor1[3], double cor2[3], double cor3[3], double cor4[3], const double pickPt[2]) const; //! Method to indicate whether a screencoordinate that is projected //! into the scene intersects the coordinates of a 3D cube //! \param[in] corners The corners constraining the extents of a handlebar //! \param[in] pickPt the screen coordinate being projected into the scene virtual int pointIsOnBox(double corners[8][3], const double pkPt[2]) const; double getPixelSize() const; //! Method to scale, translate, or rotate the coordinates of the manipulator //! param[in] - the current dataset or renderer transform to operate upon void transformMatrix(VAPoR::Transform *transform, std::vector parentScales = {1, 1, 1}); //! Method to remove the scaling of the manipulator extents //! param[in] extents are the current region of the manipulator void deScaleExtents(double *extents) const; //! Method to remove the scaling of the manipulator extents //! param[in] extents are the current region of the manipulator void deScaleExtents(double extents[8][3]) const; //! Method to apply the inverse-scaling factor to the worldHandleDiameter //! used in makeHandleExtents() //! param[in] worldHandleDiameter - the size of the manipulator handle //! param[in] axis - The axis to descale the manipulator handle size upon void deScaleScalarOnAxis(float &scalar, int axis) const; //! Debug tool to draw the hitbox of a manipulator handle. This should //! align with the window-coordinates of the actual handle. //! param[in] winCoord1 - first corner of a 2D quad on the screen //! param[in] winCoord2 - secdond corner of a 2D quad on the screen //! param[in] winCoord3 - third corner of a 2D quad on the screen //! param[in] winCoord4 - fourth corner of a 2D quad on the screen void drawHitBox(double winCoord1[2], double winCoord2[2], double winCoord3[2], double winCoord4[2]) const; //! Method that draws a line connecting a handle to the box center //! \param[in] handleNum index of handle //! \param[in] handleExtents are extents of handle being drawn //! \param[in] extents are the full box extents void drawHandleConnector(int handleNum, double *handleExtents, double *extents); //! Utility to construct the extents of a handle //! \param[in] handleNum handle index //! \param[out] handleExtents the extents of the specified handle //! \param[in] octant The octant (0-7) associated with the handle //! \param[in] extents The extents of the full box. void makeHandleExtents(int handleNum, double *handleExtents, int octant, double *extents); //! Method to draw the faces of a cube (used as a handle) //! \param[in] handleExtents are the extents of the handle /*! \param[in] isSelected indicates if the handle should be drawn using * selected color. */ void drawCubeFaces(double *handleExtents, bool isSelected); //! Construct the vertices of a handle, to be used to draw its faces. //! \param[in] handleNum is the index of the handle //! \param[out] handle are the 8 3D coordinates of the handle's vertices //! \param[in] octant is the handle octant (between 0 and 5) //! \param[in] boxExtents are the extents of the full box. //! \return absolute handle index int makeHandleFaces(int handleNum, double handle[8][3], int octant, const double *boxExtents) const; //! Project a 3D point (in user coord system) to window coords. /*! Return true if in front of camera. Used by pointIsOnQuad, as well as * in building Axis labels. */ //! \param[in] userCoords[3] coordinates of point //! \param[out] winCoords[2] window coordinates of projection //! \return true if point is in front of camera. bool _projectPointToWin(const double cubeCoords[3], double winCoords[2]) const; void _mousePress(double screenCoords[2], double handleMidpoint[3], int buttonNum); void _mouseDrag(double screenCoords[2], double handleMidpoint[3]); void _mouseRelease(double screenCoords[2]); void _stretchCorners(double corners[8][3]) const; void _translateCorners(double corners[8][3]) const; void _moveMinusXCorners(double corners[8][3]) const; void _moveMinusYCorners(double corners[8][3]) const; void _moveMinusZCorners(double corners[8][3]) const; void _movePlusXCorners(double corners[8][3]) const; void _movePlusYCorners(double corners[8][3]) const; void _movePlusZCorners(double corners[8][3]) const; void _constrainExtents(); bool _isStretching; bool _constrain; double _handleSizeInScene; double _cameraPosition[3]; double _modelViewMatrix[16]; double _projectionMatrix[16]; int _windowSize[2]; VAPoR::Transform *_rpTransform; VAPoR::Transform *_dmTransform; // screen coords where mouse is pressed: float _mouseDownPoint[2]; // unit vector in direction of handle float _handleProjVec[2]; bool _mouseDownHere; // Vector from camera to handle, when mouse is initially clicked. double _initialSelectionRay[3]; // Following only used by rotating manip subclasses: double _tempRotation; int _tempRotAxis; }; }; // namespace VAPoR #endif // MANIP_H ================================================ FILE: apps/vaporgui/ModelEventRouter.cpp ================================================ #include "ModelEventRouter.h" #include "vapor/ModelParams.h" #include "PWidgets.h" using namespace VAPoR; static RenderEventRouterRegistrar registrar(ModelEventRouter::GetClassType()); ModelEventRouter::ModelEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, ModelParams::GetClassType()) { // clang-format off AddSubtab("Model", new PGroup({ new PSection("Model File", { (new PFileOpenSelector(ModelParams::FileTag, "Model/Scene File")) ->SetFileTypeFilter("3D Models/Scenes (*.vms *.3d *.3ds *.3mf *.ac *.ac3d *.acc *.amj *.ase *.ask *.b3d *.blend *.bvh *.cms *.cob *.dae *.dxf *.enff *.fbx *.hmb *.ifc *.irr *.lwo *.lws *.lxo *.md2 *.md3 *.md5 *.mdc *.mdl *.mesh *.mot *.ms3d *.ndo *.nff *.obj *.off *.ogex *.ply *.pmx *.prj *.q3o *.q3s *.raw *.scn *.sib *.smd *.stp *.stl *.ter *.uc *.vta *.x *.x3d *.xml *.xgl *.zgl)") }), new PRendererTransformSection, })); // clang-format on } string ModelEventRouter::_getDescription() const { return ("Allows the import of 3D model files as well as more complex scenes that " "can be modified per timestep by using .vms files"); } ================================================ FILE: apps/vaporgui/ModelEventRouter.h ================================================ #pragma once #include "RenderEventRouterGUI.h" #include "vapor/ModelRenderer.h" //! \class ModelEventRouter //! \ingroup Public_GUI //! \brief Model renderer GUI //! \author Stas Jaroszynski class ModelEventRouter : public RenderEventRouterGUI { public: ModelEventRouter(QWidget *parent, VAPoR::ControlExec *ce); static string GetClassType() { return VAPoR::ModelRenderer::GetClassType(); } string GetType() const { return GetClassType(); } bool Supports2DVariables() const { return true; } bool Supports3DVariables() const { return true; } bool SupportsParticleVariables() const { return true; } protected: string _getDescription() const; string _getSmallIconImagePath() const { return "Model_small.png"; } string _getIconImagePath() const { return "Model.png"; } }; ================================================ FILE: apps/vaporgui/NcarCasperUtils.cpp ================================================ #include "NcarCasperUtils.h" #include #include #include #include #include #include #include "ErrorReporter.h" #ifndef _WIN32 #include #endif void NcarCasperUtils::CheckForCasperVGL(VAPoR::ControlExec *ce) { #ifndef Darwin #ifndef WIN32 auto sp = ce->GetParams(); char hostname[1024]; hostname[1023] = '\0'; gethostname(hostname, 1023); if (!STLUtils::BeginsWith(hostname, "casper")) return; if (getenv("VGL_ISACTIVE")) return; const char *message = "In order to utilize Casper's GPU fully, Vapor needs to be launched using vglrun. The button below will relaunch Vapor with vglrun."; printf("WARNING: %s\n", message); if (!sp->GetCasperCheckForVGL()) return; printf("\t Displaying warning popup in GUI\n"); QMessageBox *popup = new QMessageBox( QMessageBox::Icon::Warning, "Warning", message ); QCheckBox *cb = new QCheckBox("Don't show again"); cb->setChecked(false); popup->addButton("Dismiss", QMessageBox::RejectRole); popup->addButton("Relaunch", QMessageBox::AcceptRole); popup->setCheckBox(cb); auto finish = [sp, cb](int result) { if (cb->isChecked()) { sp->SetCasperCheckForVGL(false); sp->SaveSettings(); } if (result == QMessageBox::Rejected) return; auto qtArgs = QApplication::instance()->arguments(); string appPath; // This information is supposed to be in qtArgs but AppImage will overwrite it. if (getenv("APPIMAGE")) appPath = getenv("APPIMAGE"); else appPath = QApplication::instance()->applicationFilePath().toStdString(); vector prepend = {"vglrun"}; char ** args = new char*[prepend.size() + qtArgs.size() + 1]; for (int i = 0; i < prepend.size(); i++) args[i] = strdup(prepend[i]); args[0+prepend.size()] = strdup(appPath.c_str()); for (int i = 1; i < qtArgs.size(); i++) args[i+prepend.size()] = strdup(qtArgs[i].toStdString().c_str()); args[prepend.size() + qtArgs.size()] = nullptr; // string s = ""; // for (int i=0; i < prepend.size() + qtArgs.size(); i++) // s += string() + args[i] + " "; // printf("COMMAND = %s\n", s.c_str()); execvp(args[0], args); MSG_WARN("Failed to restart vapor using vglrun"); }; QObject::connect(popup, &QMessageBox::finished, finish); popup->show(); #endif #endif } ================================================ FILE: apps/vaporgui/NcarCasperUtils.h ================================================ #pragma once #include class NcarCasperUtils { public: static void CheckForCasperVGL(ControlExec *ce); }; ================================================ FILE: apps/vaporgui/NewRendererDialog.ui ================================================ NewRendererDialog 0 0 628 630 Select New Renderer 0 Data Source: 0 0 0 0 true 0 Renderer Name: 0 0 0 0 16777215 16777215 <html><head/><body><p>Type in proposed name of renderer.</p></body></html> 20 0 0 0 0 0 0 0 0 0 Qt::Vertical 20 40 0 0 16777215 16777215 -1 0 0 0 0 0 0 0 0 16777215 16777215 Image Qt::AlignCenter 0 0 300 16777215 75 true TextLabel Qt::AlignCenter 0 0 300 16777215 QFrame::NoFrame true 0 0 291 181 0 0 0 0 0 0 16777215 16777215 Description Qt::AlignCenter true Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok false buttonBox accepted() NewRendererDialog accept() 248 254 157 274 buttonBox rejected() NewRendererDialog reject() 316 260 286 274 ================================================ FILE: apps/vaporgui/NewRendererDialogManager.cpp ================================================ #include "NewRendererDialogManager.h" #include #include #include "ErrorReporter.h" NewRendererDialogManager::NewRendererDialogManager(VAPoR::ControlExec *ce, QWidget *parent) : _ce(ce), _nrd(ConstructNewRendererDialog(ce)){ _nrd->setVisible(false); _nrd->setParent(parent); _nrd->setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint); connect(_nrd, &NewRendererDialog::accepted, this, [this](){RenderHolder::_newRendererDialogAccepted(_ce, _nrd);}); } void NewRendererDialogManager::Show() { _nrd->InitializeDataSources(_ce); _nrd->open(); } NewRendererDialog* NewRendererDialogManager::ConstructNewRendererDialog(vector routers) { vector widgetNames; vector descriptions; vector iconPaths; vector smallIconPaths; vector dim2dSupport; vector dim3dSupport; vector particleSupport; for (int i = 0; i < routers.size(); i++) { RenderEventRouter *re = routers[i]; widgetNames.push_back(re->GetType()); descriptions.push_back(re->GetDescription()); iconPaths.push_back(re->GetIconImagePath()); smallIconPaths.push_back(re->GetSmallIconImagePath()); dim2dSupport.push_back(re->Supports2DVariables()); dim3dSupport.push_back(re->Supports3DVariables()); particleSupport.push_back(re->SupportsParticleVariables()); } return new NewRendererDialog(nullptr, widgetNames, descriptions, iconPaths, smallIconPaths, dim2dSupport, dim3dSupport, particleSupport); } NewRendererDialog *NewRendererDialogManager::ConstructNewRendererDialog(ControlExec *ce) { vector rendererNames = RenderEventRouterFactory::Instance()->GetFactoryNames(); vector> routersOwner; vector routers; for (auto name : rendererNames) { RenderEventRouter *re = RenderEventRouterFactory::Instance()->CreateInstance(name, NULL, ce); routersOwner.push_back(std::unique_ptr(re)); routers.push_back(re); } return ConstructNewRendererDialog(routers); } ================================================ FILE: apps/vaporgui/NewRendererDialogManager.h ================================================ #pragma once #include "RenderHolder.h" #include "RenderEventRouter.h" namespace VAPoR {class ControlExec;} using namespace VAPoR; class NewRendererDialogManager : public QObject { Q_OBJECT ControlExec *_ce; NewRendererDialog *_nrd; public: NewRendererDialogManager(ControlExec *ce, QWidget *parent); public slots: void Show(); private: static NewRendererDialog* ConstructNewRendererDialog(vector routers); static NewRendererDialog* ConstructNewRendererDialog(ControlExec *ce); }; ================================================ FILE: apps/vaporgui/NoticeBoard.cpp ================================================ #include "NoticeBoard.h" #include "CheckForNotices.h" #include #include #include #include #include #include #include "VPushButton.h" #include "VGroup.h" NoticeBoard::NoticeBoard(const std::vector ¬ices) : _notices(notices) { setWindowTitle("Notice Board"); setBaseSize(500, 500); auto *layout = new QVBoxLayout; setLayout(layout); _browser = new QTextBrowser; layout->addWidget(_browser); _browser->setOpenExternalLinks(true); auto *check = new QCheckBox("Don't check for notices on startup"); layout->addWidget(check); connect(check, &QCheckBox::stateChanged, this, [this](int b) { this->_wasDisableCheckingRequested = b; }); // Qt provides a "QDialogButtonBox" but it is buggy. // For example the following: // auto *disableButton = box->addButton("Check", QDialogButtonBox::RejectRole); // box->addButton(QDialogButtonBox::StandardButton::Close); // box->addButton("<", QDialogButtonBox::YesRole); // box->addButton(">", QDialogButtonBox::YesRole); // Results in: // [*Close*] [Check] [>] [<] // While if you swap the first 2 lines you get: // [*Check*] [Close] [>] [<] // While in itself, the above behaviour is unintuative and confusing, // the kicker is that the behavior is not consistent between systems. auto *buttonsWidget = new QWidget; auto *buttons = new QHBoxLayout; buttons->setMargin(0); buttonsWidget->setLayout(buttons); layout->addWidget(buttonsWidget); auto *prev = new QPushButton("<"); auto *disp = new QLabel("1/2"); auto *next = new QPushButton(">"); auto *clos = new QPushButton("Close"); clos->setDefault(true); _numberDisplay = disp; buttons->addWidget(prev); buttons->addWidget(disp); buttons->addWidget(next); buttons->addStretch(); buttons->addWidget(clos); connect(clos, &QPushButton::clicked, this, &QWidget::close); connect(prev, &QPushButton::clicked, this, [this]() { showNotice(_displayedNotice - 1); }); connect(next, &QPushButton::clicked, this, [this]() { showNotice(_displayedNotice + 1); }); if (notices.size() == 1) { prev->hide(); disp->hide(); next->hide(); } showNotice(0); } void NoticeBoard::showNotice(int i) { if (i < 0) i = _notices.size() - 1; if (i >= _notices.size()) i = 0; _browser->setText(QString::fromStdString(_notices[i].content)); _numberDisplay->setText(QString("%1/%2").arg(i + 1).arg(_notices.size())); _displayedNotice = i; } #include #include void NoticeBoard::CheckForAndShowNotices(ControlExec *ce) { #ifndef NDEBUG return; // Don't check for notices in debug builds #endif CheckForGHNotices([ce](const std::vector ¬ices) { if (notices.empty()) return; NoticeBoard board(notices); board.exec(); if (board.WasDisableCheckingRequested()) { ce->GetParams()->SetAutoCheckForNotices(false); ce->GetParams()->SaveSettings(); } }); } ================================================ FILE: apps/vaporgui/NoticeBoard.h ================================================ #pragma once #include #include struct Notice; class QTextBrowser; class QLabel; class NoticeBoard : public QDialog { bool _wasDisableCheckingRequested = false; const std::vector _notices; int _displayedNotice; QTextBrowser *_browser; QLabel * _numberDisplay; void showNotice(int i); public: NoticeBoard(const std::vector ¬ices); bool WasDisableCheckingRequested() const { return _wasDisableCheckingRequested; } static void CheckForAndShowNotices(ControlExec *ce); }; ================================================ FILE: apps/vaporgui/PAnnotationColorbarWidget.cpp ================================================ #include "PAnnotationColorbarWidget.h" #include "PWidgets.h" #include "PCornerSelector.h" #include "PColorSelector.h" #include #include using VAPoR::ColorbarPbase; using VAPoR::RenderParams; typedef ColorbarPbase CBP; PAnnotationColorbarWidget::PAnnotationColorbarWidget() : PWidget("", _pSection = new PSection("Colorbar Settings")) { // clang-format off _pSection->Add({ new PColorbarCornerSelector, new PCheckbox(CBP::_colorbarEnabledTag, "Show Colorbar"), (new PDoubleSliderEdit(CBP::_colorbarPositionXTag, "X Position"))->EnableDynamicUpdate(), (new PDoubleSliderEdit(CBP::_colorbarPositionYTag, "Y Position"))->EnableDynamicUpdate(), (new PDoubleSliderEdit(CBP::_colorbarSizeYTag, "Height"))->EnableDynamicUpdate(), (new PDoubleSliderEdit(CBP::_colorbarSizeXTag, "Scale"))->EnableDynamicUpdate(), (new PIntegerSliderEdit(CBP::_colorbarNumTicksTag, "Ticks"))->SetRange(2, 20)->EnableDynamicUpdate(), new PStringInput(CBP::_colorbarTitleTag, "Title"), new PCheckbox(CBP::UseScientificNotationTag, "Scientific Notation"), (new PIntegerInput(CBP::_colorbarNumDigitsTag, "Significant Figures"))->SetRange(1, 7), new PColorSelector(CBP::_colorbarFrontColorTag, "Font Color"), (new PColorSelector(CBP::_colorbarBackColorTag, "Background Color"))->ShowAlpha(), #ifdef MANUAL_FONT_CONTROL new PCheckbox("manual_font", "Manual Font Size"), (new PShowIf("manual_font"))->Equals(true)->Then(new PSubGroup({ (new PIntegerInput(CBP::_colorbarFontSizeTag, "Font Size"))->SetRange(6, 80), })), #endif }); // clang-format on } void PAnnotationColorbarWidget::updateGUI() const { RenderParams * rp = getParams(); ColorbarPbase *cbp = rp->GetColorbarPbase(); _pSection->Update(cbp, getParamsMgr(), getDataMgr()); } ================================================ FILE: apps/vaporgui/PAnnotationColorbarWidget.h ================================================ #pragma once #include "PWidget.h" class PSection; //! \class PAnnotationColorbarWidget //! \brief Widget that provides controls for configuring the colorbar legend. //! \author Stas Jaroszynski class PAnnotationColorbarWidget : public PWidget { PSection *_pSection; public: PAnnotationColorbarWidget(); protected: void updateGUI() const override; }; ================================================ FILE: apps/vaporgui/PAxisAnnotationWidget.cpp ================================================ #include #include #include #include #include "PAxisAnnotationWidget.h" #include "VSection.h" #include "V3DInput.h" #include "V3DIntInput.h" #include "VLineItem.h" #include #include "ErrorReporter.h" PAxisAnnotationWidget::PAxisAnnotationWidget(VAPoR::ControlExec *controlExec) : PWidget("", _group = new VGroup()) { _controlExec = controlExec; _group->Add(new VLineItem("# tics ", _numTics = new V3DIntInput)); _group->Add(new VLineItem("Size ", _size = new V3DInput)); _group->Add(new VLineItem("Min ", _min = new V3DInput)); _group->Add(new VLineItem("Max ", _max = new V3DInput)); _group->Add(new VLineItem("Origin ", _origin = new V3DInput)); QObject::connect(_numTics, &V3DIntInput::ValueChangedVec, this, &PAxisAnnotationWidget::_numTicsChanged); QObject::connect(_size, &V3DInput::ValueChangedVec, this, &PAxisAnnotationWidget::_sizeChanged); QObject::connect(_min, &V3DInput::ValueChangedVec, this, &PAxisAnnotationWidget::_minChanged); QObject::connect(_max, &V3DInput::ValueChangedVec, this, &PAxisAnnotationWidget::_maxChanged); QObject::connect(_origin, &V3DInput::ValueChangedVec, this, &PAxisAnnotationWidget::_originChanged); } void PAxisAnnotationWidget::updateGUI() const { VAPoR::AxisAnnotation *aa = getParams(); std::vector dTics = aa->GetNumTics(); std::vector iTics(dTics.begin(), dTics.end()); _numTics->SetValue(iTics); _size->SetValue(aa->GetTicSize()); std::vector minTics = aa->GetMinTics(); std::vector maxTics = aa->GetMaxTics(); std::vector origin = aa->GetAxisOrigin(); _scaleNormalizedCoordsToWorld(minTics); _scaleNormalizedCoordsToWorld(maxTics); _scaleNormalizedCoordsToWorld(origin); if (aa->GetLatLonAxesEnabled()) { _convertPCSToLonLat(minTics[0], minTics[1]); _convertPCSToLonLat(maxTics[0], maxTics[1]); _convertPCSToLonLat(origin[0], origin[1]); } _min->SetValue(minTics); _max->SetValue(maxTics); _origin->SetValue(origin); } void PAxisAnnotationWidget::_numTicsChanged(const std::vector xyz) { std::vector dTics(xyz.begin(), xyz.end()); getParams()->SetNumTics(dTics); } void PAxisAnnotationWidget::_sizeChanged(const std::vector xyz) { getParams()->SetTicSize(xyz); } void PAxisAnnotationWidget::_minChanged(std::vector xyz) { VAPoR::AxisAnnotation *aa = getParams(); if (aa->GetLatLonAxesEnabled()) _convertLonLatToPCS(xyz[0], xyz[1]); _scaleWorldCoordsToNormalized(xyz); getParams()->SetMinTics(xyz); } void PAxisAnnotationWidget::_maxChanged(std::vector xyz) { VAPoR::AxisAnnotation *aa = getParams(); if (aa->GetLatLonAxesEnabled()) _convertLonLatToPCS(xyz[0], xyz[1]); _scaleWorldCoordsToNormalized(xyz); getParams()->SetMaxTics(xyz); } void PAxisAnnotationWidget::_originChanged(std::vector xyz) { VAPoR::AxisAnnotation *aa = getParams(); if (aa->GetLatLonAxesEnabled()) _convertLonLatToPCS(xyz[0], xyz[1]); _scaleWorldCoordsToNormalized(xyz); getParams()->SetAxisOrigin(xyz); } void PAxisAnnotationWidget::_scaleNormalizedCoordsToWorld(std::vector &coords) const { std::vector extents = _getDomainExtents(); int size = extents.size() / 2; for (int i = 0; i < size; i++) { double offset = coords[i] * (extents[i + 3] - extents[i]); double minimum = extents[i]; coords[i] = offset + minimum; } } void PAxisAnnotationWidget::_scaleWorldCoordsToNormalized(std::vector &coords) const { std::vector extents = _getDomainExtents(); int size = extents.size() / 2; for (int i = 0; i < size; i++) { double point = coords[i] - extents[i]; double magnitude = extents[i + 3] - extents[i]; coords[i] = point / magnitude; } } std::vector PAxisAnnotationWidget::_getDomainExtents() const { VAPoR::ParamsMgr *paramsMgr = _controlExec->GetParamsMgr(); AnimationParams * aParams = dynamic_cast(paramsMgr->GetParams(AnimationParams::GetClassType())); VAssert(aParams); int ts = aParams->GetCurrentTimestep(); VAPoR::DataStatus * dataStatus = _controlExec->GetDataStatus(); VAPoR::CoordType minExts, maxExts; dataStatus->GetActiveExtents(paramsMgr, ts, minExts, maxExts); std::vector extents = {minExts[0], minExts[1], minExts[2], maxExts[0], maxExts[1], maxExts[2]}; return extents; } void PAxisAnnotationWidget::_convertPCSToLonLat(double &xCoord, double &yCoord) const { VAPoR::DataStatus *dataStatus = _controlExec->GetDataStatus(); string projString = dataStatus->GetMapProjection(); double coords[2] = {xCoord, yCoord}; double coordsForError[2] = {coords[0], coords[1]}; int rc = VAPoR::DataMgrUtils::ConvertPCSToLonLat(projString, coords, 1); if (rc < 0) { MyBase::SetErrMsg("Could not convert point %f, %f to Lon/Lat", coordsForError[0], coordsForError[1]); MSG_ERR("Error converting PCS to Lat-Lon coordinates"); } xCoord = coords[0]; yCoord = coords[1]; } void PAxisAnnotationWidget::_convertLonLatToPCS(double &xCoord, double &yCoord) const { VAPoR::DataStatus *dataStatus = _controlExec->GetDataStatus(); string projString = dataStatus->GetMapProjection(); double coords[2] = {xCoord, yCoord}; double coordsForError[2] = {coords[0], coords[1]}; int rc = VAPoR::DataMgrUtils::ConvertLonLatToPCS(projString, coords, 1); if (rc < 0) { MyBase::SetErrMsg("Could not convert point %f, %f to PCS", coordsForError[0], coordsForError[1]); MSG_ERR("Error converting from Lat-Lon to PCS coordinates"); } xCoord = coords[0]; yCoord = coords[1]; } ================================================ FILE: apps/vaporgui/PAxisAnnotationWidget.h ================================================ #pragma once #include "PWidget.h" #include class V3DInput; class V3DIntInput; class VGroup; namespace VAPoR { class ControlExec; } class PAxisAnnotationWidget : public PWidget { VAPoR::ControlExec *_controlExec; VGroup * _group; V3DIntInput * _numTics; V3DInput * _size; V3DInput * _min; V3DInput * _max; V3DInput * _origin; public: PAxisAnnotationWidget(VAPoR::ControlExec *controlExec); protected: void updateGUI() const override; private: void _numTicsChanged(const std::vector xyz); void _sizeChanged(const std::vector xyz); void _minChanged(const std::vector xyz); void _maxChanged(const std::vector xyz); void _originChanged(const std::vector xyz); std::vector _getDomainExtents() const; void _convertPCSToLonLat(double &xCoord, double &yCoord) const; void _convertLonLatToPCS(double &xCoord, double &yCoord) const; void _scaleNormalizedCoordsToWorld(std::vector &coords) const; void _scaleWorldCoordsToNormalized(std::vector &coords) const; }; ================================================ FILE: apps/vaporgui/PButton.cpp ================================================ #include "PButton.h" #include "VPushButton.h" #include PButton::PButton(std::string label, Callback cb) : PWidget("", _button = new VPushButton(label)), _cb(cb) { QObject::connect(_button, &VPushButton::ButtonClicked, this, &PButton::clicked); } PButton *PButton::DisableUndo() { _disableUndo = true; return this; } void PButton::clicked() { if (_disableUndo) { auto pm = getParamsMgr(); bool state = pm->GetSaveStateUndoEnabled(); pm->SetSaveStateUndoEnabled(false); _cb(getParams()); pm->SetSaveStateUndoEnabled(state); } else { _cb(getParams()); } } ================================================ FILE: apps/vaporgui/PButton.h ================================================ #pragma once #include "PWidget.h" #include class VPushButton; //! \class PButton //! \brief PWidget wrapper for VPushButton. //! \author Stas Jaroszynski //! //! Calls the callback when clicked. //! Please don't capture in the callback. class PButton : public PWidget { typedef std::function Callback; VPushButton * _button; const Callback _cb; bool _disableUndo = false; public: PButton(std::string label, Callback cb); // @copydoc VAPoR::ParamsMgr::SetSaveStateUndoEnabled(bool) PButton *DisableUndo(); protected: void updateGUI() const override {} bool requireParamsMgr() const override { return _disableUndo; } private: void clicked(); }; ================================================ FILE: apps/vaporgui/PCameraControlsSection.cpp ================================================ #include #include "ErrorReporter.h" #include "PCameraControlsSection.h" #include "PFileButton.h" #include "VLineItem.h" #include "V3DInput.h" #include "VGroup.h" // ===================================== // PTrackballWidget // ===================================== using namespace VAPoR; using namespace Wasp; PCameraFileGroup::PCameraFileGroup(ControlExec *ce) : PGroup(), _ce(ce) { Add((new PFileWriter("Save camera settings to file", [this](std::string path) { NavigationUtils::GetActiveViewpointParams(this->_ce)->SaveCameraToFile(path); }))->SetFileTypeFilter("Vapor Camera File (*.vc3)")); Add((new PFileReader("Load camera settings from file", [this](std::string path) { PCameraFileGroup::SetAllCameras(path); }))->SetFileTypeFilter("Vapor Camera File (*.vc3)")); } void PCameraFileGroup::updateGUI() const { auto params = NavigationUtils::GetActiveViewpointParams(_ce); for (PWidget *child : _children) child->Update(params); } void PCameraFileGroup::SetAllCameras(std::string &fileName) { XmlParser xmlparser; XmlNode *node = new XmlNode(); int rc = xmlparser.LoadFromFile(node, fileName); if (rc < 0) { MSG_ERR("Failed to read file " + fileName); return; } // Ensure ModelViewMatrix and RotationCenter tags exist const std::string mvmTag = "ModelViewMatrix"; const std::string rcTag = "RotationCenter"; if (!node->HasElementDouble(mvmTag)) { MSG_ERR("Invalid camera file" + fileName + ". Missing XML node: " + mvmTag); return; } if (!node->HasElementDouble(rcTag)) { MSG_ERR("Invalid camera file" + fileName + ". Missing XML node: " + rcTag); return; } // Check for valid matrix and origin values std::vector matrix = node->GetElementDouble(mvmTag); std::vector origin = node->GetElementDouble(rcTag); if (matrix.size() != 16) { MSG_ERR("Invalid camera file" + fileName + ". Tag " + mvmTag + " must have 16 elements."); return; } if (origin.size() != 3) { MSG_ERR("Invalid camera file" + fileName + ". Tag " + rcTag + " must have 3 elements."); return; } NavigationUtils::SetAllCameras(_ce, matrix, origin); } PTrackballWidget::PTrackballWidget(ControlExec *ce) : PWidget("", _group = new VGroup()), _ce(ce) { _group->Add(new VLineItem("Direction", _direction = new V3DInput)); _group->Add(new VLineItem("Up Vector", _up = new V3DInput)); _group->Add(new VLineItem("Position ", _position = new V3DInput)); _group->Add(new VLineItem("Origin ", _origin = new V3DInput)); connect(_direction, &V3DInput::ValueChanged, this, &PTrackballWidget::cameraChanged); connect(_up, &V3DInput::ValueChanged, this, &PTrackballWidget::cameraChanged); connect(_position, &V3DInput::ValueChanged, this, &PTrackballWidget::cameraChanged); connect(_origin, &V3DInput::ValueChanged, this, &PTrackballWidget::cameraChanged); } void PTrackballWidget::updateGUI() const { ViewpointParams *vp = NavigationUtils::GetActiveViewpointParams(_ce); double m[16], position[3], up[3], direction[3], origin[3]; vp->GetModelViewMatrix(m); bool status = vp->ReconstructCamera(m, position, up, direction); vp->GetRotationCenter(origin); if (!status) { MSG_ERR("Failed to get camera parameters"); return; } _position->SetValue(position); _up->SetValue(up); _direction->SetValue(direction); _origin->SetValue(origin); } void PTrackballWidget::cameraChanged() { NavigationUtils::SetAllCameras(_ce, _position->GetValue(), _direction->GetValue(), _up->GetValue(), _origin->GetValue()); } // ===================================== // PCameraProjectionWidget // ===================================== #include "VComboBox.h" #include const string PCameraProjectionWidget::Perspective = "Perspective"; const string PCameraProjectionWidget::MapOrthographic = "Map Orthographic"; PCameraProjectionWidget::PCameraProjectionWidget(ControlExec *ce) : PWidget("", new VLineItem("Projection Mode", _dropdown = new VComboBox({Perspective, MapOrthographic}))), _ce(ce) { connect(_dropdown, &VComboBox::ValueChanged, this, &PCameraProjectionWidget::dropdownChanged); } void PCameraProjectionWidget::updateGUI() const { ViewpointParams::ProjectionType t = NavigationUtils::GetActiveViewpointParams(_ce)->GetProjectionType(); if (t == ViewpointParams::Perspective) _dropdown->SetValue(Perspective); else if (t == ViewpointParams::MapOrthographic) _dropdown->SetValue(MapOrthographic); } void PCameraProjectionWidget::dropdownChanged(string s) { ViewpointParams::ProjectionType type; if (s == Perspective) type = ViewpointParams::Perspective; else if (s == MapOrthographic) type = ViewpointParams::MapOrthographic; else type = ViewpointParams::Perspective; ParamsMgr *pm = _ce->GetParamsMgr(); auto vizNames = pm->GetVisualizerNames(); pm->BeginSaveStateGroup("Projection Mode Set"); for (auto &viz : vizNames) { ViewpointParams *vp = pm->GetViewpointParams(viz); vp->SetProjectionType(type); } NavigationUtils::ViewAll(_ce); NavigationUtils::SetHomeViewpoint(_ce); pm->EndSaveStateGroup(); } ================================================ FILE: apps/vaporgui/PCameraControlsSection.h ================================================ #pragma once // ===================================== // PTrackballWidget // ===================================== #include "PWidget.h" #include "PGroup.h" #include class VGroup; class V3DInput; class PTrackballWidget : public PWidget { ControlExec *_ce; VGroup * _group; V3DInput * _direction; V3DInput * _up; V3DInput * _position; V3DInput * _origin; public: PTrackballWidget(ControlExec *ce); protected: void updateGUI() const override; void cameraChanged(); }; // ===================================== // PCameraProjectionWidget // ===================================== class VComboBox; class PCameraProjectionWidget : public PWidget { ControlExec * _ce; VComboBox * _dropdown; static const string Perspective; static const string MapOrthographic; public: PCameraProjectionWidget(ControlExec *ce); protected: void updateGUI() const override; void dropdownChanged(string s); }; class PCameraFileGroup : public PGroup { ControlExec* _ce; public: PCameraFileGroup(ControlExec* ce); void SetAllCameras(std::string& path); protected: void updateGUI() const override; }; // ===================================== // PCameraControlsSection // ===================================== #include "PSection.h" class PCameraControlsSection : public PSection { public: // clang-format off PCameraControlsSection(ControlExec *ce) : PSection("Camera Controls", { new PTrackballWidget(ce), new PCameraProjectionWidget(ce), new PCameraFileGroup(ce) }) {} // clang-format on }; ================================================ FILE: apps/vaporgui/PCaptureWidget.cpp ================================================ #include "CaptureController.h" #include "PCaptureWidget.h" #include "PTimeRangeSelector.h" #include "PRadioButtons.h" #include "PButton.h" #include "PSection.h" #include "PEnumDropdown.h" #include "VComboBox.h" #include "VLabel.h" #include "VHBoxWidget.h" #include "vapor/AnimationParams.h" #include "vapor/ControlExecutive.h" #include "vapor/STLUtils.h" #include "vapor/FileUtils.h" #include "vapor/NavigationUtils.h" #include #include PCaptureHBox::PCaptureHBox(VAPoR::ControlExec *ce, CaptureController *captureController) : PWidget("", _hBox = new VHBoxWidget()), _ce(ce), _captureController(captureController) { _hBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); _typeCombo = new PEnumDropdownStandalone(AnimationParams::CaptureTypeTag, {"TIFF", "PNG"}, {0, 1}); _fileLabel = new VLabel(""); _fileLabel->MakeSelectable(); _captureButton = new PButton("Export", [this](VAPoR::ParamsBase*){_captureController->CaptureSingleImage();}); _captureButton->ShowBasedOnParam(AnimationParams::CaptureModeTag, AnimationParams::SingleImage); _captureTimeSeriesButton = new PButton("Export", [this](VAPoR::ParamsBase*){_captureController->EnableAnimationCapture();}); _captureTimeSeriesButton->ShowBasedOnParam(AnimationParams::CaptureModeTag, AnimationParams::TimeSeries); QHBoxLayout* layout = qobject_cast(_hBox->layout()); layout->addWidget(_typeCombo,1); layout->addWidget(_fileLabel,3); layout->addWidget(_captureButton,1); layout->addWidget(_captureTimeSeriesButton,1); } void PCaptureHBox::_dropdownIndexChanged(int index) { int value; if (_enumMap.empty()) value = index; else value = _enumMap[index]; setParamsLong(value); } void PCaptureHBox::updateGUI() const { AnimationParams* ap = (AnimationParams*)_ce->GetParamsMgr()->GetParams(AnimationParams::GetClassType()); _typeCombo->Update(ap); // Format the label for the saved file std::string file, time; std::string dir = ap->GetValueString(AnimationParams::CaptureFileDirTag, ""); if (ap->GetValueLong(AnimationParams::CaptureModeTag, AnimationParams::SingleImage) == AnimationParams::SingleImage) { // Capture signle frame file = ap->GetValueString(AnimationParams::CaptureFileNameTag, ""); time = ap->GetValueString(AnimationParams::CaptureFileTimeTag, ""); } else { // Capture timeseries file = ap->GetValueString(AnimationParams::CaptureTimeSeriesFileNameTag, ""); if (file != "") { file = FileUtils::Basename(ap->GetValueString(AnimationParams::CaptureTimeSeriesFileNameTag, "")); size_t pos = file.rfind("0000"); if (pos != std::string::npos) file.replace(pos, 4, "####"); // Replace last instance of 0000 with #### for file label time = ap->GetValueString(AnimationParams::CaptureTimeSeriesTimeTag, ""); } } if (!file.empty()) file = "Saved: " + file + "\nDir: " + dir + "\nOn: " + time; _fileLabel->SetText(file); _captureButton->Update(ap); _captureTimeSeriesButton->Update(ap); } PCaptureWidget::PCaptureWidget(VAPoR::ControlExec *ce, CaptureController *captureController) : PWidget("", _section = new PSection("Image(s)")), _ce(ce) { _section->Add(new PRadioButtons(AnimationParams::CaptureModeTag, {"Current frame", "Time series range"})); PTimeRangeSelector *t = new PTimeRangeSelector(_ce); t->EnableBasedOnParam(AnimationParams::CaptureModeTag, 1); _section->Add(t); _section->Add(new PCaptureHBox(ce, captureController)); } void PCaptureWidget::updateGUI() const { AnimationParams* ap = (AnimationParams*)_ce->GetParamsMgr()->GetParams(AnimationParams::GetClassType()); _section->Update(ap); } ================================================ FILE: apps/vaporgui/PCaptureWidget.h ================================================ #pragma once #include "PWidget.h" namespace VAPoR { class ControlExec; } class PSection; class PEnumDropdownStandalone; class VLabel; class PButton; class VHBoxWidget; class VComboBox; class VLabel; class CaptureController; class PCaptureHBox : public PWidget { Q_OBJECT; ControlExec *_ce; CaptureController *_captureController; VHBoxWidget *_hBox; PStringDropdown *_fileTypeSelector; const std::vector _enumMap; PEnumDropdownStandalone *_typeCombo; VLabel *_fileLabel; PButton *_captureButton; PButton *_captureTimeSeriesButton; public: PCaptureHBox(VAPoR::ControlExec *ce, CaptureController *captureController); protected: virtual void updateGUI() const; private slots: void _dropdownIndexChanged(int index); }; class PCaptureWidget : public PWidget { Q_OBJECT ControlExec *_ce; PSection *_section; public: PCaptureWidget(VAPoR::ControlExec *ce, CaptureController *captureController); protected: virtual void updateGUI() const; }; ================================================ FILE: apps/vaporgui/PCheckbox.cpp ================================================ #include "PCheckbox.h" #include "VCheckBox.h" #include "VLineItem.h" #include PCheckbox::PCheckbox(const std::string &tag, const std::string &label) : PLineItem(tag, label, _vcheckbox = new VCheckBox) { connect(_vcheckbox, &VCheckBox::ValueChanged, this, &PCheckbox::checkboxStateChanged); } void PCheckbox::updateGUI() const { bool on = getParamsLong(); _vcheckbox->SetValue(on); } void PCheckbox::checkboxStateChanged(bool on) { setParamsLong(on); } ================================================ FILE: apps/vaporgui/PCheckbox.h ================================================ #pragma once #include "PLineItem.h" class VCheckBox; //! \class PCheckbox //! Creates a Qt Checkbox synced with the paramsdatabase using the PWidget interface. //! \copydoc PWidget class PCheckbox : public PLineItem { Q_OBJECT VCheckBox *_vcheckbox; public: PCheckbox(const std::string &tag, const std::string &label = ""); protected: void updateGUI() const override; private slots: void checkboxStateChanged(bool on); }; ================================================ FILE: apps/vaporgui/PCheckboxHLI.h ================================================ #pragma once #include "PWidgetHLI.h" #include "PCheckbox.h" CreateHLI(PCheckbox, bool); ================================================ FILE: apps/vaporgui/PColorSelector.cpp ================================================ #include "PColorSelector.h" #include "QColorWidget.h" #include #include PColorSelector::PColorSelector(const std::string &tag, const std::string &label) : PLineItem(tag, label, _colorWidget = new QColorWidget) { connect(_colorWidget, SIGNAL(colorChanged(QColor)), this, SLOT(colorChanged(QColor))); } PColorSelector *PColorSelector::ShowAlpha() { _colorWidget->ShowAlpha = true; return this; } QColor PColorSelector::VectorToQColor(const std::vector &v) { if (v.size() == 3) return QColor::fromRgbF(v[0], v[1], v[2]); if (v.size() == 4) return QColor::fromRgbF(v[0], v[1], v[2], v[3]); return QColor::fromRgbF(0, 0, 0); } std::vector PColorSelector::QColorToVector(const QColor &c) { std::vector v(4, 0); v[0] = c.redF(); v[1] = c.greenF(); v[2] = c.blueF(); v[3] = c.alphaF(); return v; } void PColorSelector::updateGUI() const { QColor color = VectorToQColor(getParams()->GetValueDoubleVec(getTag())); _colorWidget->setColor(color); } void PColorSelector::colorChanged(QColor color) { getParams()->SetValueDoubleVec(getTag(), "", QColorToVector(color)); } ================================================ FILE: apps/vaporgui/PColorSelector.h ================================================ #pragma once #include "PLineItem.h" class QColorWidget; //! \class PColorSelector //! Creates a Qt Color Selector synced with the paramsdatabase using the PWidget interface. //! \copydoc PWidget class PColorSelector : public PLineItem { Q_OBJECT QColorWidget *_colorWidget; public: PColorSelector(const std::string &tag, const std::string &label = ""); PColorSelector *ShowAlpha(); protected: void updateGUI() const override; static QColor VectorToQColor(const std::vector &v); static std::vector QColorToVector(const QColor &c); private slots: void colorChanged(QColor color); }; ================================================ FILE: apps/vaporgui/PConstantColorWidget.cpp ================================================ #include "PConstantColorWidget.h" #include "PCheckbox.h" #include "PColorSelector.h" #include using VAPoR::RenderParams; PConstantColorWidget::PConstantColorWidget() { Add(new PCheckbox(RenderParams::_useSingleColorTag, "Use Constant Color")); Add((new PSubGroup({new PColorSelector(RenderParams::_constantColorTag, "Constant Color")}))->ShowBasedOnParam(RenderParams::_useSingleColorTag)); } ================================================ FILE: apps/vaporgui/PConstantColorWidget.h ================================================ #pragma once #include "PGroup.h" class PConstantColorWidget : public PGroup { public: PConstantColorWidget(); }; ================================================ FILE: apps/vaporgui/PCopyRegionAnnotationWidget.cpp ================================================ #include "PCopyRegionAnnotationWidget.h" #include "CopyRegionAnnotationWidget.h" #include #include using namespace VAPoR; PCopyRegionAnnotationWidget::PCopyRegionAnnotationWidget(ControlExec *ce) : PWidget("", _widget = new CopyRegionAnnotationWidget(ce)) {} void PCopyRegionAnnotationWidget::updateGUI() const { _widget->Update(); } ================================================ FILE: apps/vaporgui/PCopyRegionAnnotationWidget.h ================================================ #pragma once #include "PWidget.h" namespace VAPoR { class ControlExec; } class CopyRegionAnnotationWidget; //! \class PPCopyRegionAnnotationWidget //! \brief PWidget wrapper for the PCopyRegionAnnotationWidget class PCopyRegionAnnotationWidget : public PWidget { CopyRegionAnnotationWidget *_widget; public: PCopyRegionAnnotationWidget(VAPoR::ControlExec *ce); private: void updateGUI() const override; }; ================================================ FILE: apps/vaporgui/PCopyRegionWidget.cpp ================================================ #include "PCopyRegionWidget.h" #include "CopyRegionWidget.h" #include PCopyRegionWidget::PCopyRegionWidget() : PWidget("", _widget = new CopyRegionWidget) {} void PCopyRegionWidget::updateGUI() const { _widget->Update(getParamsMgr(), getParams()); } ================================================ FILE: apps/vaporgui/PCopyRegionWidget.h ================================================ #pragma once #include "PWidget.h" class CopyRegionWidget; //! \class PCopyRegionWidget //! \brief PWidget wrapper for the CopyRegionWidget //! \author Stas Jaroszynski class PCopyRegionWidget : public PWidget { CopyRegionWidget *_widget; public: PCopyRegionWidget(); protected: void updateGUI() const override; bool requireParamsMgr() const override { return true; } }; ================================================ FILE: apps/vaporgui/PCornerSelector.cpp ================================================ #include "PCornerSelector.h" #include "VCheckBox.h" #include #include #include #include using VAPoR::ColorbarPbase; class PCornerSelector::Check : public VCheckBox { public: float x, y; Check(float x, float y) : x(x), y(y) { setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum); } }; template class Line : public QFrame { public: Line() { setFrameShape(T); setFrameShadow(QFrame::Sunken); } }; typedef Line HLine; typedef Line VLine; PCornerSelector::PCornerSelector(std::string tag, std::string title) : PLineItem(tag, title, _w = new QWidget) { QGridLayout *l = new QGridLayout; // l->setSpacing(0); This breaks the layout whereas setting H and V manually works... Thanks Qt. l->setVerticalSpacing(0); l->setHorizontalSpacing(0); _w->setLayout(l); auto add = [&](int x, int y, QWidget *w) { l->addWidget(w, y, x); w->setContentsMargins(0, 0, 0, 0); if (auto c = dynamic_cast(w)) _checks.push_back(c); else if (dynamic_cast(w)) l->setAlignment(w, Qt::AlignHCenter); }; add(0, 0, new Check(0, 1)); add(1, 0, new HLine); add(2, 0, new Check(0.5, 1)); add(3, 0, new HLine); add(4, 0, new Check(1, 1)); add(0, 1, new VLine); add(4, 1, new VLine); add(0, 2, new Check(0, 0.5)); add(4, 2, new Check(1, 0.5)); add(0, 3, new VLine); add(4, 3, new VLine); add(0, 4, new Check(0, 0)); add(1, 4, new HLine); add(2, 4, new Check(0.5, 0)); add(3, 4, new HLine); add(4, 4, new Check(1, 0)); l->setRowMinimumHeight(1, l->itemAtPosition(0, 0)->minimumSize().height() / 1.618); l->setRowMinimumHeight(3, l->itemAtPosition(0, 0)->minimumSize().height() / 1.618); for (auto c : _checks) connect(c, &VCheckBox::ValueChanged, this, &PCornerSelector::checked); } void PCornerSelector::updateGUI() const { auto d = getValue(); if (d.size() != 2) return; float x = d[0], y = d[1]; for (auto c : _checks) { float cx = c->x - (c->x - 0.5) * 2 * padding; float cy = c->y - (c->y - 0.5) * 2 * padding; c->SetValue(equalsf(cx, x) && equalsf(cy, y)); } } void PCornerSelector::checked(bool on) { Check *c = dynamic_cast(sender()); assert(c); if (!c) return; if (!on) c->SetValue(true); float cx = c->x - (c->x - 0.5) * 2 * padding; float cy = c->y - (c->y - 0.5) * 2 * padding; setValue({cx, cy}); } std::vector PCornerSelector::getValue() const { return getParams()->GetValueDoubleVec(getTag()); } void PCornerSelector::setValue(const std::vector &v) { getParams()->SetValueDoubleVec(getTag(), "", v); } PColorbarCornerSelector::PColorbarCornerSelector() : PCornerSelector("", "Position") {} std::vector PColorbarCornerSelector::getValue() const { return getParams()->GetCornerPosition(); } void PColorbarCornerSelector::setValue(const std::vector &v) { getParams()->SetCornerPosition(v); } ================================================ FILE: apps/vaporgui/PCornerSelector.h ================================================ #pragma once #include "PLineItem.h" #include //! \class PCornerSelector //! \brief Widget for selecting a corner or side of a square //! \author Stas Jaroszynski //! //! Widget that presents a collection of checkboxes orientated in a square, allowing the user to //! to select either a corner or side. class PCornerSelector : public PLineItem { class Check; QWidget * _w; std::vector _checks; float padding = 0.03; public: PCornerSelector(std::string tag, std::string title); protected: static bool equalsf(float a, float b) { return (std::abs(b - a) <= 0.05); } void updateGUI() const override; void checked(bool on); virtual std::vector getValue() const; virtual void setValue(const std::vector &v); }; //! \class PColorbarCornerSelector //! \brief Specialization of PCornerSelector for ColorbarPbase //! \author Stas Jaroszynski //! \copydoc PCornerSelector class PColorbarCornerSelector : public PCornerSelector { public: PColorbarCornerSelector(); virtual std::vector getValue() const override; virtual void setValue(const std::vector &v) override; }; ================================================ FILE: apps/vaporgui/PDatasetTransformWidget.cpp ================================================ #include "PDatasetTransformWidget.h" #include #include #include #include "VSection.h" #include "PStringDropdown.h" #include "PTransformWidget.h" using namespace VAPoR; const std::string PDatasetTransformWidget::SelectedDatasetTag = "transformWidgetDatasetTag"; PDatasetTransformWidget::PDatasetTransformWidget(VAPoR::ControlExec *ce) : PWidget("", _section = new VSectionGroup("Transform", { _twDataset = new PStringDropdown(SelectedDatasetTag, {}, "Dataset"), _tw = new PTransformWidget, })), _ce(ce) { } void PDatasetTransformWidget::updateGUI() const { ParamsMgr * pm = _ce->GetParamsMgr(); auto stateParams = ((GUIStateParams *)pm->GetParams(GUIStateParams::GetClassType())); auto activeViz = stateParams->GetActiveVizName(); ViewpointParams *vp = pm->GetViewpointParams(activeViz); if (!vp) return; DataStatus * dataStatus = _ce->GetDataStatus(); vector datasets = dataStatus->GetDataMgrNames(); if (datasets.empty()) { _section->setEnabled(false); return; } else { _section->setEnabled(true); } _twDataset->SetItems(datasets); _twDataset->Update(vp); string dataset = vp->GetValueString(SelectedDatasetTag, datasets[0]); if (!STLUtils::Contains(datasets, dataset)) dataset = datasets[0]; Transform *transform = vp->GetTransform(dataset); _tw->Update(transform); } ================================================ FILE: apps/vaporgui/PDatasetTransformWidget.h ================================================ #pragma once #include "PWidget.h" namespace VAPoR { class ControlExec; } class VSection; class PStringDropdown; class PTransformWidget; class PDatasetTransformWidget : public PWidget { VAPoR::ControlExec * _ce; VSection * _section; PStringDropdown * _twDataset; PTransformWidget * _tw; static const std::string SelectedDatasetTag; public: PDatasetTransformWidget(VAPoR::ControlExec *ce); void updateGUI() const override; }; ================================================ FILE: apps/vaporgui/PDimensionSelector.cpp ================================================ #include "PDimensionSelector.h" #include #include "VComboBox.h" using namespace VAPoR; PDimensionSelector::PDimensionSelector() : PLineItem("", "Variable Dimension", _vComboBox = new VComboBox({"2D", "3D"})) { connect(_vComboBox, &VComboBox::ValueChanged, this, &PDimensionSelector::dropdownTextChanged); } void PDimensionSelector::updateGUI() const { if (getParams()->GetRenderDim() == 3) _vComboBox->SetValue("3D"); else _vComboBox->SetValue("2D"); } void PDimensionSelector::dropdownTextChanged(std::string text) { RenderParams *rp = getParams(); int dim = text == "2D" ? 2 : 3; rp->BeginGroup("Change dim"); if (dim == 2) { rp->GetBox()->SetPlanar(true); rp->GetBox()->SetOrientation(VAPoR::Box::XY); } else { rp->GetBox()->SetPlanar(false); rp->GetBox()->SetOrientation(VAPoR::Box::XYZ); } rp->SetDefaultVariables(dim, true); rp->EndGroup(); } ================================================ FILE: apps/vaporgui/PDimensionSelector.h ================================================ #pragma once #include "PLineItem.h" class VComboBox; class PDimensionSelector : public PLineItem { VComboBox *_vComboBox; public: PDimensionSelector(); protected: virtual void updateGUI() const override; bool requireDataMgr() const override { return true; } private: void dropdownTextChanged(std::string text); }; ================================================ FILE: apps/vaporgui/PDisplay.cpp ================================================ #include "PDisplay.h" #include "VCheckBox.h" #include "VLineItem.h" #include "VLabel.h" #include PDisplay::PDisplay(const std::string &tag, const std::string &label) : PWidget(tag, new VLineItem(label == "" ? tag : label, _label = new VLabel)) {} PDisplay *PDisplay::Selectable() { _label->MakeSelectable(); return this; } void PDisplay::setText(std::string text) const { if (text.empty()) setText(""); else _label->SetText(text); } void PStringDisplay::updateGUI() const { std::string text = getParamsString(); setText(text); } void PIntegerDisplay::updateGUI() const { long value = getParamsLong(); setText(QString::number(value).toStdString()); } void PDoubleDisplay::updateGUI() const { double value = getParamsDouble(); setText(QString::number(value).toStdString()); } void PBooleanDisplay::updateGUI() const { bool on = getParamsLong(); setText(on ? "True" : "False"); } ================================================ FILE: apps/vaporgui/PDisplay.h ================================================ #pragma once #include "PWidget.h" class VLabel; //! @class PDisplay //! Creates a label that displays a value in the params database. //! Does not allow for editing of said value. class PDisplay : public PWidget { Q_OBJECT public: PDisplay(const std::string &tag, const std::string &label = ""); PDisplay *Selectable(); protected: VLabel *_label; void setText(std::string text) const; }; //! @class PStringDisplay //! @copydoc PDisplay class PStringDisplay : public PDisplay { Q_OBJECT public: using PDisplay::PDisplay; protected: void updateGUI() const override; }; //! @class PIntegerDisplay //! @copydoc PDisplay class PIntegerDisplay : public PDisplay { Q_OBJECT public: using PDisplay::PDisplay; protected: void updateGUI() const override; }; //! @class PDoubleDisplay //! @copydoc PDisplay class PDoubleDisplay : public PDisplay { Q_OBJECT public: using PDisplay::PDisplay; protected: void updateGUI() const override; }; //! @class PBooleanDisplay //! @copydoc PDisplay class PBooleanDisplay : public PDisplay { Q_OBJECT public: using PDisplay::PDisplay; protected: void updateGUI() const override; }; ================================================ FILE: apps/vaporgui/PDisplayHLI.h ================================================ #pragma once #include "PWidgetHLI.h" #include "PDisplay.h" CreateHLI(PStringDisplay, std::String); CreateHLI(PIntegerDisplay, long); CreateHLI(PDoubleDisplay, double); CreateHLI(PBooleanDisplay, bool); ================================================ FILE: apps/vaporgui/PDoubleInput.cpp ================================================ #include "PDoubleInput.h" #include "VLineItem.h" #include #include "VLineEdit_Deprecated.h" PDoubleInput::PDoubleInput(const std::string &tag, const std::string &label) : PLineItem(tag, label, _doubleInput = new VLineEdit_Deprecated) { _doubleInput->SetIsDouble(true); connect(_doubleInput, &VLineEdit_Deprecated::ValueChanged, this, &PDoubleInput::doubleInputValueChanged); } void PDoubleInput::updateGUI() const { double value = getParamsDouble(); _doubleInput->SetValue(to_string(value)); } void PDoubleInput::doubleInputValueChanged(const std::string &v) { double d = stod(v); setParamsDouble(d); } ================================================ FILE: apps/vaporgui/PDoubleInput.h ================================================ #pragma once #include "PLineItem.h" //#include "VaporWidgetsFwd.h" class VLineEdit_Deprecated; //! \class PDoubleInput //! Creates a Qt text input for double values synced with the paramsdatabase using the PWidget interface. //! \copydoc PWidget class PDoubleInput : public PLineItem { Q_OBJECT VLineEdit_Deprecated *_doubleInput; public: PDoubleInput(const std::string &tag, const std::string &label = ""); protected: void updateGUI() const override; private slots: void doubleInputValueChanged(const std::string &v); }; ================================================ FILE: apps/vaporgui/PDoubleInputHLI.h ================================================ #pragma once #include "PWidgetHLI.h" #include "PDoubleInput.h" CreateHLI(PDoubleInput, double); ================================================ FILE: apps/vaporgui/PDynamicMixin.cpp ================================================ #include "PDynamicMixin.h" #include #include "PWidget.h" #include PWidget *PDynamicMixin::EnableDynamicUpdate(bool enabled) { PWidget *pw = getPWidget(); pw->_dynamicUpdateIsOn = enabled; return pw; } void PDynamicMixin::dynamicSetParamsDouble(double v) { PWidget *pw = getPWidget(); if (pw->_dynamicUpdateIsOn) { pw->dynamicUpdateBegin(); pw->_setParamsDouble(v); pw->getParams()->IntermediateChange(); } } void PDynamicMixin::dynamicSetParamsLong(long v) { PWidget *pw = getPWidget(); if (pw->_dynamicUpdateIsOn) { pw->dynamicUpdateBegin(); pw->_setParamsLong(v); pw->getParams()->IntermediateChange(); } } void PDynamicMixin::dynamicSetParamsString(const std::string &v) { PWidget *pw = getPWidget(); if (pw->_dynamicUpdateIsOn) { pw->dynamicUpdateBegin(); pw->_setParamsString(v); pw->getParams()->IntermediateChange(); } } PWidget *PDynamicMixin::getPWidget() { PWidget *pw = dynamic_cast(this); VAssert(pw != nullptr); return pw; } ================================================ FILE: apps/vaporgui/PDynamicMixin.h ================================================ #pragma once #include class PWidget; //! \class PDynamicMixin //! Internal class for PWidgets. Enables dynamic updating of the params database //! as the user edits a value through intermediate updates. class PDynamicMixin { public: //! Turns on dynamic update. PWidget *EnableDynamicUpdate(bool enabled=true); virtual ~PDynamicMixin() = default; protected: void dynamicSetParamsDouble(double v); void dynamicSetParamsLong(long v); void dynamicSetParamsString(const std::string &v); private: PWidget *getPWidget(); }; ================================================ FILE: apps/vaporgui/PEnumDropdown.cpp ================================================ #include "PEnumDropdown.h" #include #include #include "VComboBox.h" PEnumDropdownStandalone::PEnumDropdownStandalone(const std::string &tag, const std::vector &items, const std::vector &itemValues) : PWidget(tag, _vComboBox = new VComboBox(items)), _enumMap(itemValues) { VAssert(itemValues.empty() || items.size() == itemValues.size()); connect(_vComboBox, &VComboBox::IndexChanged, this, &PEnumDropdownStandalone::dropdownIndexChanged); } void PEnumDropdownStandalone::updateGUI() const { int value = getParamsLong(); int index = value; for (int i = 0; i < _enumMap.size(); i++) { if (_enumMap[i] == value) { index = i; break; } } _vComboBox->SetIndex(index); } void PEnumDropdownStandalone::dropdownIndexChanged(int index) { int value; if (_enumMap.empty()) { value = index; } else { VAssert(index >= 0 && index < _enumMap.size()); value = _enumMap[index]; } setParamsLong(value); } PEnumDropdown::PEnumDropdown(const std::string &tag, const std::vector &items, const std::vector &itemValues, const std::string &label) : PLineItem(label, new PEnumDropdownStandalone(tag, items, itemValues)) {} ================================================ FILE: apps/vaporgui/PEnumDropdown.h ================================================ #pragma once #include "PLineItem.h" #include //#include "VaporWidgetsFwd.h" class VComboBox; //! \class PEnumDropdownStandalone //! Creates a Qt dropdown for selecting enum values synced with the paramsdatabase using the PWidget interface. //! \copydoc PWidget class PEnumDropdownStandalone : public PWidget { Q_OBJECT VComboBox * _vComboBox; const std::vector _enumMap; public: PEnumDropdownStandalone(const std::string& tag, const std::vector &items, const std::vector &itemValues = {}); protected: void updateGUI() const override; private slots: void dropdownIndexChanged(int index); }; //! \class PEnumDropdown //! Creates a Qt dropdown in a PLineItem for selecting enum values synced with the paramsdatabase using the PWidget interface. //! \copydoc PWidget class PEnumDropdown : public PLineItem { Q_OBJECT public: //! If itemValues is empty, the item values will be initialized to the index of each item. PEnumDropdown(const std::string &tag, const std::vector &items, const std::vector &itemValues = {}, const std::string &label = ""); }; ================================================ FILE: apps/vaporgui/PEnumDropdownHLI.h ================================================ #pragma once #include "PWidgetHLI.h" #include "PEnumDropdown.h" template class PEnumDropdownHLI : public PEnumDropdown, public PWidgetHLIBase { public: PEnumDropdownHLI(const std::string &label, const std::vector &items, const std::vector &values, typename PWidgetHLIBase::GetterType getter, typename PWidgetHLIBase::SetterType setter) : PEnumDropdown("", items, values, label), PWidgetHLIBase((PWidget *)this, getter, setter) { } }; ================================================ FILE: apps/vaporgui/PFidelitySection.cpp ================================================ #include "PFidelitySection.h" #include "VComboBox.h" #include "PCheckbox.h" #include using namespace VAPoR; // ================================== // PFidelitySection // ================================== PFidelitySection::PFidelitySection() : PSection("Data Fidelity") { Add(new PQuickFidelitySelector); Add(new PCheckbox("FidelityUseAdvanced", "Advanced")); Add((new PLODSelector)->EnableBasedOnParam("FidelityUseAdvanced")); Add((new PRefinementSelector)->EnableBasedOnParam("FidelityUseAdvanced")); } // ================================== // PQuickFidelitySelector // ================================== PQuickFidelitySelector::PQuickFidelitySelector() : PLineItem("", "Fidelity", _vComboBox = new VComboBox({"Medium"})) { connect(_vComboBox, &VComboBox::ValueChanged, this, &PQuickFidelitySelector::dropdownTextChanged); } void PQuickFidelitySelector::updateGUI() const { RenderParams *rp = dynamic_cast(getParams()); VAssert(rp && "Params must be RenderParams"); auto dm = getDataMgr(); auto vn = rp->GetFirstVariableName(); int nLod = dm->GetCRatios(vn).size(); int nRef = dm->GetNumRefLevels(vn); int minOptions = vn.empty() ? 0 : max(nLod, nRef); vector items; if (minOptions >= 2) items.push_back("Low"); if (minOptions >= 3) items.push_back("Medium"); if (minOptions >= 1) items.push_back("High"); else items.push_back(""); _vComboBox->SetOptions(items); int lod = rp->GetCompressionLevel(); int ref = rp->GetRefinementLevel(); int n = items.size(); _vComboBox->SetIndex(paramsToSimple(n, nLod, nRef, lod, ref)); long ts = rp->GetCurrentTimestep(); for (int i = 0; i < n; i++) { simpleToParams(n, nLod, nRef, i, &lod, &ref); bool exists = dm->VariableExists(ts, vn, 0, ref); if (!exists) _vComboBox->SetItemEnabled(i, false); } } void PQuickFidelitySelector::dropdownTextChanged(std::string) { auto *rp = (RenderParams *)getParams(); auto dm = getDataMgr(); auto vn = rp->GetFirstVariableName(); int nLod = dm->GetCRatios(vn).size(); int nRef = dm->GetNumRefLevels(vn); int lod, ref; simpleToParams(_vComboBox->GetCount(), nLod, nRef, _vComboBox->GetCurrentIndex(), &lod, &ref); rp->BeginGroup("Change lod/cRatio"); rp->SetCompressionLevel(lod); rp->SetRefinementLevel(ref); rp->EndGroup(); } void PQuickFidelitySelector::simpleToParams(int nSimple, int nLod, int nRef, int simple, int *lod, int *ref) { if (nSimple == 1) { *lod = 0; *ref = 0; } else { *lod = simple * (nLod - 1) / (nSimple - 1); *ref = simple * (nRef - 1) / (nSimple - 1); } } int PQuickFidelitySelector::paramsToSimple(int nSimple, int nLod, int nRef, int lod, int ref) { int div = nLod + nRef - 2; if (div == 0) return 0; return (1 + lod + ref) * (nSimple - 1) / div; } // ================================== // PLODSelector // ================================== PLODSelector::PLODSelector() : PLineItem("", "Level of Detail", _vComboBox = new VComboBox({"0 (1000:1)"})) { connect(_vComboBox, &VComboBox::IndexChanged, this, &PLODSelector::dropdownIndexChanged); } void PLODSelector::updateGUI() const { RenderParams *rp = dynamic_cast(getParams()); VAssert(rp && "Params must be RenderParams"); auto varName = rp->GetFirstVariableName(); auto dm = getDataMgr(); auto cr = dm->GetCRatios(varName); long timestep = rp->GetCurrentTimestep(); vector items; for (int i = 0; i < cr.size(); i++) items.push_back(to_string(i) + " (" + to_string(cr[i]) + ":1)"); _vComboBox->SetOptions(items); _vComboBox->SetIndex(rp->GetCompressionLevel()); for (int i = 0; i < cr.size(); i++) { bool exists = dm->VariableExists(timestep, varName, 0, i); if (!exists) _vComboBox->SetItemEnabled(i, false); } } void PLODSelector::dropdownIndexChanged(int i) { RenderParams *rp = (RenderParams *)getParams(); rp->SetCompressionLevel(i); } // ================================== // PRefinementSelector // ================================== PRefinementSelector::PRefinementSelector() : PLineItem("", "Refinement Level", _vComboBox = new VComboBox({"0 (100x100x100)"})) { connect(_vComboBox, &VComboBox::IndexChanged, this, &PRefinementSelector::dropdownIndexChanged); } void PRefinementSelector::updateGUI() const { RenderParams *rp = dynamic_cast(getParams()); VAssert(rp && "Params must be RenderParams"); auto varName = rp->GetFirstVariableName(); auto dm = getDataMgr(); int nrf = dm->GetNumRefLevels(varName); vector items; for (int i = 0; i < nrf; i++) { vector dims; dm->GetDimLensAtLevel(varName, i, dims, rp->GetCurrentTimestep()); if (dims.empty()) continue; auto itr = dims.begin(); string item = to_string(i) + " (" + to_string(*itr++); for (; itr != dims.end(); ++itr) item += "x" + to_string(*itr); item += ")"; items.push_back(item); } _vComboBox->SetOptions(items); _vComboBox->SetIndex(rp->GetRefinementLevel()); } void PRefinementSelector::dropdownIndexChanged(int i) { RenderParams *rp = (RenderParams *)getParams(); rp->SetRefinementLevel(i); } ================================================ FILE: apps/vaporgui/PFidelitySection.h ================================================ #pragma once #include "vapor/RenderParams.h" #include "PSection.h" #include "PLineItem.h" #include "PWidgetHLI.h" class VComboBox; class PFidelitySection : public PSection { public: PFidelitySection(); }; class PQuickFidelitySelector : public PLineItem { Q_OBJECT VComboBox *_vComboBox; public: PQuickFidelitySelector(); protected: virtual void updateGUI() const override; bool requireDataMgr() const override { return true; } private: void dropdownTextChanged(std::string); static void simpleToParams(int nSimple, int nLod, int nRef, int simple, int *lod, int *ref); static int paramsToSimple(int nSimple, int nLod, int nRef, int lod, int ref); }; class PLODSelector : public PLineItem { Q_OBJECT VComboBox *_vComboBox; public: PLODSelector(); protected: virtual void updateGUI() const override; bool requireDataMgr() const override { return true; } private slots: void dropdownIndexChanged(int i); }; class PRefinementSelector : public PLineItem { Q_OBJECT VComboBox *_vComboBox; public: PRefinementSelector(); protected: virtual void updateGUI() const override; bool requireDataMgr() const override { return true; } private slots: void dropdownIndexChanged(int i); }; ================================================ FILE: apps/vaporgui/PFileButton.cpp ================================================ #include "PFileButton.h" #include "VPushButton.h" #include #include #include PFileButton::PFileButton(const std::string label, Callback cb) : PWidget("", _button= new VPushButton(label)), _cb(cb) { QObject::connect(_button, &VPushButton::ButtonClicked, this, &PFileButton::clicked); } void PFileButton::updateGUI() const {} PFileButton *PFileButton::SetFileTypeFilter(const std::string &filter) { _fileTypeFilter = QString::fromStdString(filter); return this; } void PFileButton::clicked() { std::string defaultPath = Wasp::FileUtils::HomeDir(); QString qSelectedPath = selectPath(defaultPath); if (qSelectedPath.isNull()) return; _cb(qSelectedPath.toStdString()); } bool PFileButton::requireParamsMgr() const { return false; } QString PFileWriter::selectPath(const std::string &defaultPath) const { return QFileDialog::getSaveFileName(nullptr, "Select a file", QString::fromStdString(defaultPath), _fileTypeFilter); } QString PFileReader::selectPath(const std::string &defaultPath) const { return QFileDialog::getOpenFileName(nullptr, "Select a save file", QString::fromStdString(defaultPath), _fileTypeFilter); } ================================================ FILE: apps/vaporgui/PFileButton.h ================================================ #pragma once #include "PWidget.h" class VPushButton; class QString; //! \class PFileButton //! Creates a Qt text box and select button that allows users to pick a file path synced with the paramsdatabase using the PWidget interface. //! \copydoc PWidget class PFileButton : public PWidget { Q_OBJECT private: typedef std::function Callback; Callback _cb; VPushButton* _button; public: PFileButton(const std::string label, Callback cb); //! Sets the fileTypeFilter parameter in the QFileDialog popup functions. PFileButton *SetFileTypeFilter(const std::string &filter); // PFileButton *UseDefaultPathSetting(const std::string &tag); protected: QString _fileTypeFilter = "All Files (*)"; void updateGUI() const override; bool requireParamsMgr() const override; virtual QString selectPath(const std::string &defaultPath) const = 0; //private slots: void clicked(); }; //! \class PFileOpenSelector //! A PFileButton that provides an Open File dialog //! \copydoc PFileReader class PFileReader : public PFileButton { Q_OBJECT public: using PFileButton::PFileButton; protected: virtual QString selectPath(const std::string &defaultPath) const override; }; //! \class PFileSaveSelector //! A PFileButton that provides a Save File dialog //! \copydoc PFileReader class PFileWriter : public PFileButton { Q_OBJECT public: using PFileButton::PFileButton; protected: virtual QString selectPath(const std::string &defaultPath) const override; }; ================================================ FILE: apps/vaporgui/PFileSelector.cpp ================================================ #include "PFileSelector.h" #include "VPushButton.h" #include "VLineEdit_Deprecated.h" #include #include #include #include PFileSelector::PFileSelector(const std::string &tag, const std::string &label) : PLineItem(tag, label, _pathTexbox = new VLineEdit_Deprecated, _button = new VPushButton("Select")) { _pathTexbox->SetReadOnly(true); _pathTexbox->setSizePolicy(QSizePolicy::Expanding, _pathTexbox->sizePolicy().verticalPolicy()); connect(_button, &VPushButton::ButtonClicked, this, &PFileSelector::buttonClicked); } void PFileSelector::updateGUI() const { const string path = getParamsString(); _pathTexbox->SetValue(path); _pathTexbox->setToolTip(QString::fromStdString(path)); } PFileSelector *PFileSelector::SetFileTypeFilter(const std::string &filter) { _fileTypeFilter = QString::fromStdString(filter); return this; } // PFileSelector *PFileSelector::UseDefaultPathSetting(const std::string &tag) //{ // _syncWithSettings = true; // _syncWithSettingsTag = tag; // return this; //} void PFileSelector::buttonClicked() { string defaultPath; string selectedFile = getParamsString(); if (_syncWithSettings) { // Too hardcoded in settings params to bother } else { if (Wasp::FileUtils::Exists(selectedFile)) defaultPath = Wasp::FileUtils::Dirname(selectedFile); else defaultPath = Wasp::FileUtils::HomeDir(); } QString qSelectedPath = selectPath(defaultPath); if (qSelectedPath.isNull()) return; setParamsString(qSelectedPath.toStdString()); } bool PFileSelector::requireParamsMgr() const { return _syncWithSettings; } QString PFileOpenSelector::selectPath(const std::string &defaultPath) const { return QFileDialog::getOpenFileName(nullptr, "Select a file", QString::fromStdString(defaultPath), _fileTypeFilter); } QString PFileSaveSelector::selectPath(const std::string &defaultPath) const { return QFileDialog::getSaveFileName(nullptr, "Select save file", QString::fromStdString(defaultPath), _fileTypeFilter); } QString PDirectorySelector::selectPath(const std::string &defaultPath) const { return QFileDialog::getExistingDirectory(nullptr, "Select a directory", QString::fromStdString(defaultPath)); } ================================================ FILE: apps/vaporgui/PFileSelector.h ================================================ #pragma once #include "PLineItem.h" class VPushButton; class VLineEdit_Deprecated; class QString; //! \class PFileSelector //! Creates a Qt text box and select button that allows users to pick a file path synced with the paramsdatabase using the PWidget interface. //! \copydoc PWidget class PFileSelector : public PLineItem { Q_OBJECT VPushButton * _button; VLineEdit_Deprecated *_pathTexbox; bool _syncWithSettings = false; std::string _syncWithSettingsTag; public: PFileSelector(const std::string &tag, const std::string &label = ""); //! Sets the fileTypeFilter parameter in the QFileDialog popup functions. PFileSelector *SetFileTypeFilter(const std::string &filter); // PFileSelector *UseDefaultPathSetting(const std::string &tag); protected: QString _fileTypeFilter = "All Files (*)"; void updateGUI() const override; bool requireParamsMgr() const override; virtual QString selectPath(const std::string &defaultPath) const = 0; private slots: void buttonClicked(); }; //! \class PFileOpenSelector //! A PFileSelector that provides an Open File dialog //! \copydoc PFileSelector class PFileOpenSelector : public PFileSelector { Q_OBJECT public: using PFileSelector::PFileSelector; protected: virtual QString selectPath(const std::string &defaultPath) const override; }; //! \class PFileSaveSelector //! A PFileSelector that provides a Save File dialog //! \copydoc PFileSelector class PFileSaveSelector : public PFileSelector { Q_OBJECT public: using PFileSelector::PFileSelector; protected: virtual QString selectPath(const std::string &defaultPath) const override; }; //! \class PDirectorySelector //! A PFileSelector that provides a Select Directory dialog //! \copydoc PFileSelector class PDirectorySelector : public PFileSelector { Q_OBJECT public: using PFileSelector::PFileSelector; PFileSelector *SetFileTypeFilter(const std::string &filter) = delete; protected: virtual QString selectPath(const std::string &defaultPath) const override; }; ================================================ FILE: apps/vaporgui/PFileSelectorHLI.h ================================================ #pragma once #include "PFileSelector.h" #include "PWidgetHLI.h" CreateHLI(PFileOpenSelector, std::string); CreateHLI(PFileSaveSelector, std::string); CreateHLI(PDirectorySelector, std::string); ================================================ FILE: apps/vaporgui/PFlowIntegrationRegionSelector.cpp ================================================ #include "PFlowIntegrationRegionSelector.h" #include using VAPoR::FlowParams; VAPoR::Box *PFlowIntegrationRegionSelector1D::getBox() const { return getParams()->GetIntegrationBox(); } ================================================ FILE: apps/vaporgui/PFlowIntegrationRegionSelector.h ================================================ #pragma once #include "PRegionSelector.h" class PFlowIntegrationRegionSelector1D : public PRegionSelector1D { public: using PRegionSelector1D::PRegionSelector1D; protected: VAPoR::Box *getBox() const override; }; ================================================ FILE: apps/vaporgui/PFlowRakeRegionSelector.cpp ================================================ #include "PFlowRakeRegionSelector.h" #include using VAPoR::FlowParams; VAPoR::Box *PFlowRakeRegionSelector1D::getBox() const { return getParams()->GetRakeBox(); } ================================================ FILE: apps/vaporgui/PFlowRakeRegionSelector.h ================================================ #pragma once #include "PRegionSelector.h" class PFlowRakeRegionSelector1D : public PRegionSelector1D { public: using PRegionSelector1D::PRegionSelector1D; protected: VAPoR::Box *getBox() const override; }; ================================================ FILE: apps/vaporgui/PGeometrySubtab.cpp ================================================ #include "PGeometrySubtab.h" #include "PRegionSelector.h" #include "PCopyRegionWidget.h" #include "PTransformWidget.h" PGeometrySubtab::PGeometrySubtab() : PGroup({new PRegionSelector, new PCopyRegionWidget, new PRendererTransformSection}) {} ================================================ FILE: apps/vaporgui/PGeometrySubtab.h ================================================ #pragma once #include "PGroup.h" class PGeometrySubtab : public PGroup { public: PGeometrySubtab(); }; ================================================ FILE: apps/vaporgui/PGroup.cpp ================================================ #include "PGroup.h" #include #include #include "VGroup.h" PGroup::PGroup() : PGroup(new VGroup()) {} PGroup::PGroup(const List &widgets) : PGroup() { AddM(widgets); } PGroup::PGroup(VGroup *w) : PWidget("", _widget = w), WidgetGroupWrapper(w) {} void PGroup::updateGUI() const { auto params = getParams(); auto paramsMgr = getParamsMgr(); auto dataMgr = getDataMgr(); for (PWidget *child : _children) child->Update(params, paramsMgr, dataMgr); } PSubGroup::PSubGroup() : PGroup(new VSubGroup()) {} PSubGroup::PSubGroup(const List &widgets) : PSubGroup() { AddM(widgets); } ================================================ FILE: apps/vaporgui/PGroup.h ================================================ #pragma once #include "PWidget.h" #include "AbstractWidgetGroup.h" #include #include "VGroup.h" class VGroup; //! \class PGroup //! Groups together PWidgets. See ParamsWidgetDemo for example use cases. //! \copydoc PWidget class PGroup : public PWidget, public WidgetGroupWrapper { Q_OBJECT VGroup *_widget; public: PGroup(); PGroup(const List &widgets); protected: PGroup(VGroup *w); void updateGUI() const override; }; //! \class PSubGroup //! Groups together PWidgets in a subgroup. //! \copydoc PGroup class PSubGroup : public PGroup { Q_OBJECT public: PSubGroup(); PSubGroup(const List &widgets); }; ================================================ FILE: apps/vaporgui/PImportDataButton.cpp ================================================ #include "PImportDataButton.h" #include "DatasetImportController.h" #include "VHBoxWidget.h" #include "VLabel.h" #include "DatasetTypeLookup.h" #include "vapor/ControlExecutive.h" #include "vapor/GUIStateParams.h" #include "vapor/FileUtils.h" #include #include PImportDataButton::PImportDataButton(VAPoR::ControlExec* ce, DatasetImportController *datasetImportController) : PWidget("", _hBox = new VHBoxWidget()), _ce(ce), _datasetImportController(datasetImportController) { _hBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); QHBoxLayout* layout = qobject_cast(_hBox->layout()); QPushButton *button = new QPushButton("Select File(s)", this); connect(button, &QPushButton::clicked, this, &PImportDataButton::_importDataset); layout->addWidget(button, 1); layout->addWidget(_fileLabel = new VLabel(""),3); _fileLabel->MakeSelectable(); } void PImportDataButton::_importDataset() { GUIStateParams* gsp = dynamic_cast(getParams()); std::vector dataSetNames = gsp->GetOpenDataSetNames(); std::string defaultPath = dataSetNames.size() ? gsp->GetOpenDataSetPaths(dataSetNames.back())[0] : FileUtils::HomeDir(); QStringList qfileNames = QFileDialog::getOpenFileNames(this, "Select Filename Prefix", QString::fromStdString(defaultPath)); std::vector fileNames; for (const QString &qStr : qfileNames) fileNames.push_back(qStr.toStdString()); if (fileNames.empty()) return; std::string format = GetDatasets()[getParams()->GetValueLong(GUIStateParams::ImportDataTypeTag, 0)].first; _datasetImportController->ImportDataset(_ce, fileNames, format, DatasetImportController::DatasetExistsAction::Prompt); } void PImportDataButton::updateGUI() const { GUIStateParams* gsp = dynamic_cast(getParams()); std::vector dataSetNames = gsp->GetOpenDataSetNames(); if (!dataSetNames.size()) { _fileLabel->SetText(""); return; } std::vector paths = gsp->GetOpenDataSetPaths(dataSetNames[0]); int count = paths.size(); if (count > 0) { std::string dir = FileUtils::Dirname(paths[0]); _fileLabel->SetText("Imported: " + std::to_string(count) + " file(s)\nFrom: " + dir); } } ================================================ FILE: apps/vaporgui/PImportDataButton.h ================================================ #pragma once #include "PLineItem.h" namespace VAPoR { class ControlExec; } class DatasetImportController; class VHBoxWidget; class VLabel; class PButton; class PImportDataButton : public PWidget { Q_OBJECT VAPoR::ControlExec *_ce; DatasetImportController *_datasetImportController; VHBoxWidget *_hBox; VLabel *_fileLabel; PButton *_importButton; void _importDataset(); public: PImportDataButton(VAPoR::ControlExec* ce, DatasetImportController *datasetImportController); protected: void updateGUI() const override; }; ================================================ FILE: apps/vaporgui/PImportDataWidget.cpp ================================================ #include "DatasetTypeLookup.h" #include "DatasetImportController.h" #include "PImportDataWidget.h" #include "PImportDataButton.h" #include "PRadioButtons.h" #include "PGroup.h" #include "vapor/ControlExecutive.h" #include "vapor/GUIStateParams.h" PImportDataWidget::PImportDataWidget(VAPoR::ControlExec* ce, DatasetImportController *datasetImportController) : PGroup() { std::vector types = GetDatasetTypeDescriptions(); PRadioButtons* prb = new PRadioButtons(GUIStateParams::ImportDataTypeTag, types); Add(prb); Add(new PImportDataButton(ce, datasetImportController)); } ================================================ FILE: apps/vaporgui/PImportDataWidget.h ================================================ #pragma once #include "PGroup.h" #include "PSection.h" #include "PLineItem.h" namespace VAPoR { class ControlExec; } class DatasetImportController; class PImportDataWidget : public PGroup { Q_OBJECT public: PImportDataWidget(VAPoR::ControlExec* ce, DatasetImportController *datasetImportController); }; ================================================ FILE: apps/vaporgui/PIntegerInput.cpp ================================================ #include #include "PIntegerInput.h" #include "VLineItem.h" #include #include "VIntSpinBox.h" PIntegerInput::PIntegerInput(const std::string &tag, const std::string &label) : PLineItem(tag, label, _spinbox = new VIntSpinBox(INT_MIN, INT_MAX)) { connect(_spinbox, &VIntSpinBox::ValueChanged, this, &PIntegerInput::spinboxValueChanged); connect(_spinbox, &VIntSpinBox::ValueChangedIntermediate, this, &PIntegerInput::valueChangedIntermediate); } PIntegerInput *PIntegerInput::SetRange(int min, int max) { _spinbox->SetRange(min, max); return this; } void PIntegerInput::updateGUI() const { int value = getParamsLong(); _spinbox->SetValue(value); } void PIntegerInput::spinboxValueChanged(int i) { setParamsLong(i); } void PIntegerInput::valueChangedIntermediate(int v) { dynamicSetParamsLong(v); } ================================================ FILE: apps/vaporgui/PIntegerInput.h ================================================ #pragma once #include "PLineItem.h" #include "PDynamicMixin.h" class VIntSpinBox; //! \class PIntegerInput //! Creates a Qt text input for double values using a spinbox synced with the paramsdatabase using the PWidget interface. //! \copydoc PWidget class PIntegerInput : public PLineItem, public PDynamicMixin { Q_OBJECT VIntSpinBox *_spinbox; public: PIntegerInput(const std::string &tag, const std::string &label = ""); //! @copydoc VIntSpinBox::SetRange PIntegerInput *SetRange(int min, int max); protected: void updateGUI() const override; private slots: void spinboxValueChanged(int i); void valueChangedIntermediate(int i); }; ================================================ FILE: apps/vaporgui/PIntegerInputHLI.h ================================================ #pragma once #include "PWidgetHLI.h" #include "PIntegerInput.h" CreateHLI(PIntegerInput, long); ================================================ FILE: apps/vaporgui/PLabel.cpp ================================================ #include "PLabel.h" #include "VLabel.h" PLabel::PLabel(const std::string &text) : PWidget("", _label = new VLabel(text)) {} ================================================ FILE: apps/vaporgui/PLabel.h ================================================ #pragma once #include "PWidget.h" class VLabel; //! \class PLabel //! \brief Displays static text. //! \author Stas Jaroszynski class PLabel : public PWidget { VLabel *_label; public: PLabel(const std::string &text); void updateGUI() const override {} }; ================================================ FILE: apps/vaporgui/PLineItem.cpp ================================================ #include "PLineItem.h" #include "VLineItem.h" #include PLineItem::PLineItem(const std::string &tag, const std::string &label, QWidget *centerWidget, QWidget *rightWidget) : PWidget(tag, new VLineItem(label.empty() ? tag : label, centerWidget, rightWidget)) { } PLineItem::PLineItem(const std::string &tag, const std::string &label, QWidget *rightWidget) : PWidget(tag, new VLineItem(label.empty() ? tag : label, rightWidget)) {} PLineItem::PLineItem(const std::string &label, PWidget *rightWidget) : PLineItem("", label, rightWidget) { _child = rightWidget; } void PLineItem::updateGUI() const { assert(_child); _child->Update(getParams(), getParamsMgr(), getDataMgr()); } ================================================ FILE: apps/vaporgui/PLineItem.h ================================================ #pragma once #include "PWidget.h" //! \class PLineItem //! Internal PWidget class. Standardizes PWidgets that take up a single line with a label, spacer, input. //! \copydoc PWidget class PLineItem : public PWidget { Q_OBJECT PWidget *_child = nullptr; public: PLineItem(const std::string &tag, const std::string &label, QWidget *centerWidget, QWidget *rightWidget); PLineItem(const std::string &tag, const std::string &label, QWidget *rightWidget); PLineItem(const std::string &label, PWidget *rightWidget); protected: void updateGUI() const override; }; ================================================ FILE: apps/vaporgui/PMetadataClasses.cpp ================================================ #include #include #include #include "ErrorReporter.h" #include "PMetadataClasses.h" #include "PSection.h" #include "PStringDropdown.h" #include "PSliderEdit.h" #include #include #include #include #include #include namespace { std::vector xtypeLookup = { "INVALID", "FLOAT", "DOUBLE", "UINT8", "INT8", "INT32", "INT64", "TEXT" }; std::vector axisLookup = { "X", "Y", "Z", "T"}; } const std::string PMetadataSection::SelectedDatasetTag = "metadataDatasetTag"; const std::string PMetadataSection::MetadataTimestepTag = "metadataTimestepTag"; POpenVariableMetadataWidget::POpenVariableMetadataWidget() : PWidget("", _varTree = new VOpenVariableMetadataTree()) {} void POpenVariableMetadataWidget::updateGUI() const { _varTree->Update(getParams(),nullptr,getDataMgr()); } PMetadataSection::PMetadataSection(VAPoR::ControlExec* ce) : PWidget("", _section = new VSectionGroup("Dataset Metadata", { _metadataDataset = new PStringDropdown(SelectedDatasetTag, {}, "Dataset"), (_metadataTimestep = new PIntegerSliderEdit(MetadataTimestepTag, "Generate metadata\nfor timestep #"))->AllowUserRange(false), _dimTree = new VDimensionMetadataTree(), _varTree = new VVariableMetadataTree(), _coordTree = new VCoordinateVariableMetadataTree(), _globalTree = new VGlobalAttributeMetadataTree(), }) ) { VAssert(ce != nullptr); _ce = ce; connect(_varTree, &VVariableMetadataTree::_timestepRejected, this, &PMetadataSection::updateGUI); } void PMetadataSection::updateGUI() const { VAPoR::ParamsMgr * pm = _ce->GetParamsMgr(); auto stateParams = ((GUIStateParams*)pm->GetParams(GUIStateParams::GetClassType())); auto activeViz = stateParams->GetActiveVizName(); VAPoR::ViewpointParams *vp = pm->GetViewpointParams(activeViz); if (!vp) return; VAPoR::DataStatus * dataStatus = _ce->GetDataStatus(); vector datasets = dataStatus->GetDataMgrNames(); if (datasets.empty()) { _metadataDataset->setEnabled(false); _metadataTimestep->setEnabled(false); _varTree->setEnabled(false); _coordTree->setEnabled(false); return; } else { _metadataDataset->setEnabled(true); _metadataTimestep->setEnabled(true); _varTree->setEnabled(true); _coordTree->setEnabled(true); } _metadataDataset->SetItems(datasets); _metadataDataset->SetItems(datasets); _metadataDataset->Update(vp); VAPoR::DataMgr* dm; string dataset = vp->GetValueString(SelectedDatasetTag, datasets[0]); if (!STLUtils::Contains(datasets, dataset)) dataset = datasets[0]; dm = _ce->GetDataStatus()->GetDataMgr(dataset); _dimTree->Update(getParams(), nullptr, dm); _varTree->Update(getParams(), nullptr, dm); _coordTree->Update(getParams(), nullptr, dm); _globalTree->Update(getParams(), nullptr, dm); _metadataTimestep->SetRange(0,dm->GetNumTimeSteps()-1); _metadataTimestep->Update(getParams()); } VMetadataTree::VMetadataTree() : VSectionGroup(""), ParamsUpdatable(), _tree(new QTreeWidget), _dm(nullptr), _ts(-1), _topLevelBranches({}) { _group->AddM({_tree}); _tree->setHeaderHidden(true); _tree->header()->setStretchLastSection(false); _tree->setColumnCount(2); _tree->header()->setSectionResizeMode(QHeaderView::ResizeToContents); connect(_tree, &QTreeWidget::itemExpanded, this, &VMetadataTree::_generateMetadata); } void VMetadataTree::Update(VAPoR::ParamsBase* p, VAPoR::ParamsMgr* pm, VAPoR::DataMgr* dm) { // Check if we need to update our tree. // Note: This function also generates the _topLevelBranches variable list, who's metadata will be shown. if (!_checkNeedUpdate(p, dm)) return; QStringList qbranches; for (auto branch : _topLevelBranches) qbranches << QString::fromStdString(branch); qbranches.removeDuplicates(); qbranches.removeAll(QString("")); _tree->clear(); for (auto qbranch : qbranches){ QTreeWidgetItem* varItem = new QTreeWidgetItem(_tree, {qbranch}); // Add a blank "leaf" on each branch so they can be expanded (and therefore populated) QTreeWidgetItem* leaf = new QTreeWidgetItem(varItem, {""}); (void)leaf; // Silence unused variable warning _tree->insertTopLevelItem(0,varItem); } } void VVariableMetadataTree::_generateMetadata(QTreeWidgetItem* item) const { if (item->childCount() > 1) return; // This branch contains more than an empty leaf, and has already been computed QTreeWidgetItem* leaf = item->takeChild(0); if (leaf != 0) delete leaf; QString qvar = item->text(0); std::vector range; int rc = _dm->GetDataRange(_ts, qvar.toStdString(), -1, -1, range); if (rc < 0) return; QTreeWidgetItem* varItem = item; new QTreeWidgetItem(varItem, {"Min:", QString::number(range[0])}); new QTreeWidgetItem(varItem, {"Max:", QString::number(range[1])}); std::vector dims; _dm->GetDimLensAtLevel(qvar.toStdString(), -1, dims, _ts); QString qDims = QString::number(dims[0]); if (dims.size()>1) qDims = qDims + ":" + QString::number(dims[1]); if (dims.size()>2) qDims = qDims + ":" + QString::number(dims[2]); new QTreeWidgetItem(varItem, {"Dims (XYZ):", qDims}); VAPoR::DC::Mesh mesh; QTreeWidgetItem* coords = new QTreeWidgetItem(varItem, {"Coordinates"}); VAPoR::DC::DataVar dataVar; _dm->GetDataVarInfo(qvar.toStdString(), dataVar); _dm->GetMesh(dataVar.GetMeshName(), mesh); std::vector coordVars = mesh.GetCoordVars(); QStringList qCoordVars; for (auto coordVar : coordVars) qCoordVars << QString::fromStdString(coordVar); qCoordVars.removeDuplicates(); qCoordVars.removeAll(QString("")); for (auto qCoordVar : qCoordVars ) _generateCoordVarInfo(coords, qCoordVar); _generateAttributeInfo(varItem, dataVar); } bool VMetadataTree::_checkNeedUpdate(VAPoR::ParamsBase* p, VAPoR::DataMgr* dm) { bool needsUpdate = false; if (dm != _dm ) { _dm = dm; needsUpdate = true; } VAPoR::RenderParams* rp = dynamic_cast(p); size_t ts; if (rp != nullptr) { ts = rp->GetCurrentTimestep(); } else { ts = p->GetValueLong(PMetadataSection::MetadataTimestepTag, 0); } if (ts != _ts ) { _ts=ts; needsUpdate = true; } if (ts > _dm->GetNumTimeSteps()-1) { _ts = _dm->GetNumTimeSteps()-1; needsUpdate = true; } std::vector topLevelBranches; _gatherBranches(topLevelBranches, p); // Sort branches alphabetically std::sort( topLevelBranches.begin(), topLevelBranches.end(), [](const std::string& a, const std::string& b) -> bool { return aGetCoordVarInfo(qCoordVar.toStdString(), coordVar)) return; QTreeWidgetItem* coordItem; if (parent->text(0) == qCoordVar) coordItem = parent; else coordItem = new QTreeWidgetItem(parent, {qCoordVar}); std::vector dimNames = coordVar.GetDimNames(); QString qDimNames; for (auto dimName : dimNames) qDimNames += QString::fromStdString(dimName) + " "; new QTreeWidgetItem(coordItem, {"Dimension name(s):", qDimNames}); std::vector dims = {1}; _dm->GetDimLensAtLevel(qCoordVar.toStdString(), -1, dims, _ts); QString qDims = QString::number(dims[0]); if (dims.size()>1) qDims = qDims + ":" + QString::number(dims[1]); if (dims.size()>2) qDims = qDims + ":" + QString::number(dims[2]); new QTreeWidgetItem(coordItem, {"Dimension size(s):", qDims}); new QTreeWidgetItem(coordItem, {"Unit:", QString::fromStdString(coordVar.GetUnits())}); new QTreeWidgetItem(coordItem, {"Axis:", QString::fromStdString(axisLookup[coordVar.GetAxis()])}); new QTreeWidgetItem(coordItem, {"Time dim:", QString::fromStdString(coordVar.GetTimeDimName())}); new QTreeWidgetItem(coordItem, {"Data type:", QString::fromStdString(xtypeLookup[coordVar.GetXType()+1])}); new QTreeWidgetItem(coordItem, {"Uniform sampling:", QVariant(coordVar.GetUniform()).toString()}); } void VVariableMetadataTree::_generateAttributeInfo(QTreeWidgetItem* parent, const VAPoR::DC::BaseVar baseVar) const { QTreeWidgetItem* attrs = new QTreeWidgetItem(parent, {"Attributes"}); std::map attributes = baseVar.GetAttributes(); std::map::iterator it; std::stringstream s; for(auto const& attribute : attributes) { s.str(std::string()); VAPoR::DC::XType xType = attribute.second.GetXType(); if ( xType == VAPoR::DC::XType::INVALID ) continue; else if ( xType == VAPoR::DC::XType::TEXT ) { std::string values; attribute.second.GetValues(values); s.str(values); } else if (xType == VAPoR::DC::XType::FLOAT || xType == VAPoR::DC::XType::DOUBLE ) { std::vector values; attribute.second.GetValues(values); copy(values.begin(), values.end(), ostream_iterator(s," ")); } else { std::vector values; attribute.second.GetValues(values); copy(values.begin(), values.end(), ostream_iterator(s," ")); } new QTreeWidgetItem(attrs, {QString::fromStdString(attribute.first), QString::fromStdString(s.str())}); } } VOpenVariableMetadataTree::VOpenVariableMetadataTree() : VVariableMetadataTree() { setTabText(0,"Open Variable Metadata"); } void VOpenVariableMetadataTree::_gatherBranches(std::vector &vars, VAPoR::ParamsBase* p) const { VAPoR::RenderParams* rp = dynamic_cast(p); vars.clear(); vars.push_back( rp->GetVariableName() ); vars.push_back( rp->GetXFieldVariableName() ); vars.push_back( rp->GetYFieldVariableName() ); vars.push_back( rp->GetZFieldVariableName() ); vars.push_back( rp->GetHeightVariableName() ); vars.push_back( rp->GetColorMapVariableName() ); std::vector auxs = rp->GetAuxVariableNames(); vars.insert(vars.end(), auxs.begin(), auxs.end()); } VVariableMetadataTree::VVariableMetadataTree() : VMetadataTree() { setTabText(0,"Variable Metadata"); } void VVariableMetadataTree::_gatherBranches(std::vector &vars, VAPoR::ParamsBase* p /*unused*/) const { vars.clear(); std::vector v = _dm->GetDataVarNames(); vars.insert(vars.end(),v.begin(),v.end()); } VCoordinateVariableMetadataTree::VCoordinateVariableMetadataTree() : VVariableMetadataTree() { setTabText(0,"Coordinate Variable Metadata"); } void VCoordinateVariableMetadataTree::_generateMetadata(QTreeWidgetItem* item) const { if (item->childCount() > 1) return; // This branch has already been computed QTreeWidgetItem* leaf = item->takeChild(0); if (leaf != 0) delete leaf; QString qvar = item->text(0); _generateCoordVarInfo(item, qvar); } void VCoordinateVariableMetadataTree::_gatherBranches(std::vector &vars, VAPoR::ParamsBase* p /*unused*/) const { vars.clear(); std::vector v = _dm->GetCoordVarNames(); vars.insert(vars.end(),v.begin(),v.end()); } VGlobalAttributeMetadataTree::VGlobalAttributeMetadataTree() : VMetadataTree() { setTabText(0,"Global Attributes"); } void VGlobalAttributeMetadataTree::_generateMetadata(QTreeWidgetItem* item) const { if (item->childCount() > 1) return; // This branch contains more than an empty leaf, and has already been computed QTreeWidgetItem* leaf = item->takeChild(0); if (leaf != 0) delete leaf; QString qattribute = item->text(0); VAPoR::DC::XType xType = _dm->GetAttType("",qattribute.toStdString()); QString qvalue; if (xType == VAPoR::DC::XType::INVALID) { return; } if (xType == VAPoR::DC::XType::TEXT) { std::string values; if (!_dm->GetAtt("", qattribute.toStdString(), values)) return; qvalue = QString::fromStdString(values); } else if (xType == VAPoR::DC::XType::FLOAT || xType == VAPoR::DC::XType::DOUBLE ) { std::vector values; if (!_dm->GetAtt("", qattribute.toStdString(), values)) return; for (auto value : values) qvalue += QString::number(value) + " "; } else { // UINT8, INT8, INT32, INT64 std::vector values; if (!_dm->GetAtt("", qattribute.toStdString(), values)) return; for (auto value : values) qvalue += QString::number(value) + " "; } new QTreeWidgetItem(item, {"Value:", qvalue}); new QTreeWidgetItem(item, {"Type:", QString::fromStdString(xtypeLookup[_dm->GetAttType("",qattribute.toStdString())+1])}); } void VGlobalAttributeMetadataTree::_gatherBranches(std::vector &vars, VAPoR::ParamsBase* p /*unused*/) const { vars.clear(); std::vector v = _dm->GetAttNames(""); vars.insert(vars.end(),v.begin(),v.end()); } VDimensionMetadataTree::VDimensionMetadataTree() : VMetadataTree() { setTabText(0,"Dimension Metadata"); } void VDimensionMetadataTree::_generateMetadata(QTreeWidgetItem* item) const { if (item->childCount() > 1) return; // This branch contains more than an empty leaf, and has already been computed QTreeWidgetItem* leaf = item->takeChild(0); if (leaf != 0) delete leaf; VAPoR::DC::Dimension dim; _dm->GetDimension(item->text(0).toStdString(), dim, _ts); new QTreeWidgetItem(item, {"Length:", QString::number(dim.GetLength())}); new QTreeWidgetItem(item, {"Is time varying:", QVariant(dim.IsTimeVarying()).toString()}); /*std::vector dims; _dm->GetDimLens(item->text(0).toStdString(), dims, _ts); QString dimLens; if (dims.size()) dimLens = " = " + QString::number(dims[0]); else if (item->text(0).toStdString() == "Time" || item->text(0).toStdString() == "time") dimLens = " = UNLIMITED"; item->setText(1,dimLens);*/ } void VDimensionMetadataTree::_gatherBranches(std::vector &dims, VAPoR::ParamsBase* p /*unused*/) const { dims.clear(); std::vector d = _dm->GetDimensionNames(); dims.insert(dims.end(),d.begin(),d.end()); } ================================================ FILE: apps/vaporgui/PMetadataClasses.h ================================================ #pragma once #include "PSection.h" #include "VContainer.h" #include "VSection.h" #include class QTreeWidget; class QTreeWidgetItem; class PStringDropdown; class PIntegerSliderEdit; class VDimensionMetadataTree; class VVariableMetadataTree; class VOpenVariableMetadataTree; class VCoordinateVariableMetadataTree; class VGlobalAttributeMetadataTree; namespace VAPoR { class ControlExec; class RenderParams; class DataMgr; } //! \class POpenVariableMetadataWidget //! Allows the user view variable metadata that is currently //! in use by an instantiated renderer. class POpenVariableMetadataWidget : public PWidget { Q_OBJECT VOpenVariableMetadataTree* _varTree; public: POpenVariableMetadataWidget(); protected: bool requireDataMgr() const override { return true; } void updateGUI() const override; }; //! \class PMetadataSection //! Allows the user view all variable metadata that is in the //! dataset selected by a drop-down menu. It also displays //! coordinate variable metadata and global attributes for the //! given dataset, at the given timestep. class PMetadataSection : public PWidget { Q_OBJECT VAPoR::ControlExec* _ce; VSection* _section; VDimensionMetadataTree* _dimTree; VVariableMetadataTree* _varTree; VCoordinateVariableMetadataTree* _coordTree; VGlobalAttributeMetadataTree* _globalTree; PStringDropdown* _metadataDataset; PIntegerSliderEdit* _metadataTimestep; public: PMetadataSection(VAPoR::ControlExec* ce); static const std::string SelectedDatasetTag; static const std::string MetadataTimestepTag; protected: void updateGUI() const override; }; //! \class VMetadataTree //! Abstract base class for VWidgets that wrap QTreeWidgets. //! Only updates QTreeWidgets when the user's selected DataMgr, //! timestep, or variable list change. class VMetadataTree : public VSectionGroup, public ParamsUpdatable { Q_OBJECT public: VMetadataTree(); virtual void Update(VAPoR::ParamsBase* p, VAPoR::ParamsMgr* pm, VAPoR::DataMgr* dm) override; signals: void _timestepRejected(); protected: QTreeWidget* _tree; VAPoR::DataMgr* _dm; size_t _ts; bool _needUpdate; std::vector _topLevelBranches; virtual void _gatherBranches(std::vector &branches, VAPoR::ParamsBase* rp = nullptr) const = 0; virtual void _generateMetadata(QTreeWidgetItem* item) const = 0; bool _checkNeedUpdate(VAPoR::ParamsBase* p, VAPoR::DataMgr* dm); }; //! \class VVariableMetadataTree //! Displays metadata for all variables in a given DataMgr instance. class VVariableMetadataTree : public VMetadataTree { Q_OBJECT public: VVariableMetadataTree(); protected: void _gatherBranches(std::vector &branches, VAPoR::ParamsBase* p = nullptr) const override; void _generateMetadata(QTreeWidgetItem* item) const override; void _generateCoordVarInfo(QTreeWidgetItem* parent, const QString& qCoordVar) const; void _generateAttributeInfo(QTreeWidgetItem* parent, const VAPoR::DC::BaseVar baseVar) const; }; //! \class VVariableMetadataTree //! Displays metadata for all variables open in a given RenderParams instance. class VOpenVariableMetadataTree : public VVariableMetadataTree { Q_OBJECT public: VOpenVariableMetadataTree(); protected: void _gatherBranches(std::vector &branches, VAPoR::ParamsBase* p = nullptr) const override; }; //! \class VVariableMetadataTree //! Displays metadata for all coordinate variables in a given DataMgr instance. class VCoordinateVariableMetadataTree : public VVariableMetadataTree { Q_OBJECT public: VCoordinateVariableMetadataTree(); protected: void _gatherBranches(std::vector &branches, VAPoR::ParamsBase* p) const override; void _generateMetadata(QTreeWidgetItem* item) const override; }; //! \class VDimensionMetadataTree //! Displays dimension metadata for a given DataMgr instance. class VDimensionMetadataTree : public VMetadataTree { Q_OBJECT public: VDimensionMetadataTree(); //void Update(VAPoR::ParamsBase* p, VAPoR::ParamsMgr* pm, VAPoR::DataMgr* dm) override; protected: void _gatherBranches(std::vector &dims, VAPoR::ParamsBase* p) const override; void _generateMetadata(QTreeWidgetItem* item) const override; }; //! \class VVariableMetadataTree //! Displays global attribute metadata for a given DataMgr instance. class VGlobalAttributeMetadataTree : public VMetadataTree { Q_OBJECT public: VGlobalAttributeMetadataTree(); protected: void _gatherBranches(std::vector &vars, VAPoR::ParamsBase* p) const override; void _generateMetadata(QTreeWidgetItem* item) const override; }; ================================================ FILE: apps/vaporgui/PMovingDomainSettings.cpp ================================================ #include "PMovingDomainSettings.h" #include "PCheckbox.h" #include #include PMovingDomainSettings::PMovingDomainSettings(ControlExec *ce) : PSection("Moving Domain", { (new PCheckbox(GUIStateParams::MovingDomainTrackCameraTag, "Track Camera"))->SetTooltip("Camera should follow the moving domain"), (new PCheckbox(GUIStateParams::MovingDomainTrackRenderRegionsTag, "Track Rendered Regions"))->SetTooltip("Renderer regions should be relative to the moving domain"), }), _ce(ce) { SetTooltip("Control behaviors related to moving domains. Disabled if dataset does not contain a moving domain."); } bool PMovingDomainSettings::isEnabled() const { for (auto name : _ce->GetDataStatus()->GetDataMgrNames()) if (_ce->GetDataStatus()->GetDataMgr(name)->HasMovingDomain()) return true; return false; } ================================================ FILE: apps/vaporgui/PMovingDomainSettings.h ================================================ #pragma once #include "PSection.h" //! \class PMovingDomainSettings //! Applies parameters for moving domains //! \copydoc PSection class PMovingDomainSettings : public PSection { ControlExec *_ce; public: PMovingDomainSettings(ControlExec *ce); protected: bool isEnabled() const override; }; ================================================ FILE: apps/vaporgui/PMultiVarSelector.cpp ================================================ #include "PMultiVarSelector.h" #include #include #include using VAPoR::RenderParams; PMultiVarSelector::PMultiVarSelector(std::string tag) : PWidget(tag, _listWidget = new QListWidget) { _listWidget->setSelectionMode(QAbstractItemView::NoSelection); connect(_listWidget, &QListWidget::itemChanged, this, &PMultiVarSelector::_itemChanged); } PMultiVarSelector *PMultiVarSelector::DisplayVars(Mode mode) { _mode = mode; return this; } void PMultiVarSelector::updateGUI() const { vector varNames; const auto nDims = getParams()->GetRenderDim(); switch (_mode) { default: case Auto: varNames = getDataMgr()->GetDataVarNames(nDims); break; case D2: varNames = getDataMgr()->GetDataVarNames(2); break; case D3: varNames = getDataMgr()->GetDataVarNames(3); break; case Both: varNames = getDataMgr()->GetDataVarNames(2); const auto other = getDataMgr()->GetDataVarNames(3); varNames.insert(varNames.end(), other.begin(), other.end()); break; } _listWidget->blockSignals(true); _listWidget->clear(); for (const auto &var : varNames) _addVarToList(var); const auto selectedVars = getParams()->GetValueStringVec(getTag()); for (const auto &var : selectedVars) { const auto items = _listWidget->findItems(QString::fromStdString(var), Qt::MatchExactly); QListWidgetItem *item; if (items.isEmpty()) item = _addVarToList(var); else item = items[0]; item->setCheckState(Qt::Checked); } _listWidget->blockSignals(false); } QSize PMultiVarSelector::minimumSizeHint() const { QSize s = PWidget::minimumSizeHint(); int count = _listWidget->count(); int rowHeight = _listWidget->sizeHintForRow(0); int height = count * rowHeight; s.setHeight(std::max(s.height(), std::min(s.height() * 3, height))); return s; } QListWidgetItem *PMultiVarSelector::_addVarToList(const std::string &var) const { QListWidgetItem *item = new QListWidgetItem(QString::fromStdString(var)); item->setFlags(item->flags() | Qt::ItemIsUserCheckable); item->setCheckState(Qt::Unchecked); _listWidget->addItem(item); return item; } void PMultiVarSelector::_itemChanged(QListWidgetItem *) { std::vector selected; for (int i = 0; i < _listWidget->count(); i++) { QListWidgetItem *item = _listWidget->item(i); if (item->checkState() == Qt::Checked) selected.push_back(item->text().toStdString()); } getParams()->SetValueStringVec(getTag(), "", selected); } ================================================ FILE: apps/vaporgui/PMultiVarSelector.h ================================================ #pragma once #include "PWidget.h" class QListWidget; class QListWidgetItem; //! \class PMultiVarSelector //! \brief Allows the selection of multiple variables. To add a title, use a PLabel. //! \author Stas Jaroszynski //! By default this shows the vars with the same dimension as the renderer. This can be changed //! with DisplayVars(Mode) class PMultiVarSelector : public PWidget { public: enum Mode { Auto, D2, D3, Both }; PMultiVarSelector(std::string tag); PMultiVarSelector *DisplayVars(Mode mode); protected: void updateGUI() const override; QSize minimumSizeHint() const override; bool requireDataMgr() const override { return true; } private: QListWidget *_listWidget; Mode _mode = Auto; QListWidgetItem *_addVarToList(const std::string &var) const; void _itemChanged(QListWidgetItem *); }; ================================================ FILE: apps/vaporgui/POrientationSelector.cpp ================================================ #include "POrientationSelector.h" #include "PEnumDropdown.h" #include #include using namespace VAPoR; POrientationSelector::POrientationSelector() : PWidget("", _dropdown = new PEnumDropdown(Box::m_orientationTag, {"XY", "XZ", "YZ"}, {Box::XY, Box::XZ, Box::YZ}, "Orientation")) {} void POrientationSelector::updateGUI() const { RenderParams *rp = dynamic_cast(getParams()); VAssert(rp); _dropdown->Update(rp->GetBox(), getParamsMgr(), getDataMgr()); } ================================================ FILE: apps/vaporgui/POrientationSelector.h ================================================ #pragma once #include "PWidget.h" class PEnumDropdown; //! \class POrientationSelector //! \brief Widget provides the user the option of switching a renderer between 2D and 3D. //! \author Stas Jaroszynski class POrientationSelector : public PWidget { PEnumDropdown *_dropdown; public: POrientationSelector(); protected: void updateGUI() const override; }; ================================================ FILE: apps/vaporgui/POutputResolutionSection.cpp ================================================ #include "POutputResolutionSection.h" #include "PWidgets.h" #include #include #include typedef VAPoR::ViewpointParams VP; // clang-format off POutputResolutionSection::POutputResolutionSection(VAPoR::ControlExec *ce) : PWidgetWrapper( new PSection("Output Resolution", { new PCheckbox(VP::UseCustomFramebufferTag, "Use Custom Output Size"), (new PIntegerInput(VP::CustomFramebufferWidthTag, "Output Width (px)"))->SetRange(1, 16384)->EnableBasedOnParam(VP::UseCustomFramebufferTag), (new PIntegerInput(VP::CustomFramebufferHeightTag, "Output Height (px)"))->SetRange(1, 16384)->EnableBasedOnParam(VP::UseCustomFramebufferTag), } )), _ce(ce) {} // clang-format on VAPoR::ParamsBase *POutputResolutionSection::getWrappedParams() const { return NavigationUtils::GetActiveViewpointParams(_ce); } ================================================ FILE: apps/vaporgui/POutputResolutionSection.h ================================================ #pragma once #include "PWidgetWrapper.h" namespace VAPoR { class ControlExec; } class POutputResolutionSection : public PWidgetWrapper { VAPoR::ControlExec *_ce; public: POutputResolutionSection(VAPoR::ControlExec *ce); protected: VAPoR::ParamsBase *getWrappedParams() const override; }; ================================================ FILE: apps/vaporgui/PProjectionStringWidget.cpp ================================================ #include "PProjectionStringWidget.h" #include #include #include "VSection.h" #include "VLineItem.h" #include "VComboBox.h" #include "VPushButton.h" #include "PDisplay.h" #include #include #include #include #include "VLabel.h" using namespace VAPoR; PProjectionStringWidget::PProjectionStringWidget(ControlExec *ce) : PWidget("", new VSectionGroup("Data Projection", { _currentProjDisp = (new PStringDisplay(GUIStateParams::m_proj4StringTag, "Current Projection String"))->Selectable(), new VLabel(""), new VLabel("Change Projection String"), new VLineItem("Change projection to", _datasetDropdown = new VComboBox), new VLineItem("Selected Projection String", _selectedProjDisp = new VLabel), _customStrEdit = new QPlainTextEdit, _applyButton = new VPushButton("Apply"), })), _ce(ce) { _selectedProjDisp->MakeSelectable(); connect(_datasetDropdown, &VComboBox::ValueChanged, this, &PProjectionStringWidget::datasetDropdownChanged); connect(_applyButton, &VPushButton::ButtonClicked, this, &PProjectionStringWidget::applyClicked); } void PProjectionStringWidget::updateGUI() const { ParamsMgr *pm = _ce->GetParamsMgr(); auto stateParams = ((GUIStateParams *)pm->GetParams(GUIStateParams::GetClassType())); auto activeViz = stateParams->GetActiveVizName(); DataStatus * dataStatus = _ce->GetDataStatus(); vector datasets = dataStatus->GetDataMgrNames(); vector datasetProjStrs; string currentProjStr = dataStatus->GetMapProjection(); for (auto &dataset : datasets) datasetProjStrs.push_back(dataStatus->GetMapProjectionDefault(dataset)); datasets.push_back("Custom"); _datasetDropdown->SetOptions(datasets); _datasetDropdown->SetValue("Custom"); if (_changeToDataset.empty()) { for (int i = 0; i < datasetProjStrs.size(); i++) if (datasetProjStrs[i] == currentProjStr) _datasetDropdown->SetIndex(i); } else { _datasetDropdown->SetValue(_changeToDataset); } _currentProjDisp->Update(stateParams); auto selected = _datasetDropdown->GetValue(); if (selected == "Custom") { _customStrEdit->setVisible(true); _selectedProjDisp->setVisible(false); } else { auto proj = dataStatus->GetMapProjectionDefault(selected); _selectedProjDisp->SetText(proj.size() ? proj : ""); _customStrEdit->setVisible(false); _selectedProjDisp->setVisible(true); } } void PProjectionStringWidget::datasetDropdownChanged(std::string value) { _changeToDataset = value; updateGUI(); } void PProjectionStringWidget::applyClicked() { DataStatus * dataStatus = _ce->GetDataStatus(); const string selected = _datasetDropdown->GetValue(); string proj; if (selected == "Custom") { proj = _customStrEdit->toPlainText().toStdString(); } else { proj = dataStatus->GetMapProjectionDefault(selected); } ParamsMgr *pm = _ce->GetParamsMgr(); auto p = ((GUIStateParams *)pm->GetParams(GUIStateParams::GetClassType())); if (proj == p->GetProjectionString()) return; p->SetProjectionString(proj); } ================================================ FILE: apps/vaporgui/PProjectionStringWidget.h ================================================ #pragma once #include "PWidget.h" #include "PWidgetsFwd.h" #include "VFrame.h" #include "Updatable.h" namespace VAPoR { class ControlExec; }; using VAPoR::ControlExec; class QLabel; class QPlainTextEdit; class VComboBox; class VPushButton; class VLabel; class PProjectionStringWidget : public PWidget { Q_OBJECT ControlExec * _ce; PDisplay * _currentProjDisp; VLabel * _selectedProjDisp; VComboBox * _datasetDropdown; QPlainTextEdit *_customStrEdit; VPushButton * _applyButton; std::string _changeToDataset; public: PProjectionStringWidget(ControlExec *ce); protected: void updateGUI() const override; void datasetDropdownChanged(std::string value); void applyClicked(); }; ================================================ FILE: apps/vaporgui/PRadioButtons.cpp ================================================ #include "PRadioButtons.h" #include "VRadioButton.h" #include "VGroup.h" PRadioButtons::PRadioButtons(const std::string &tag, const std::vector labels) : PWidget(tag, _vg = new VGroup()), _labels(labels) { bool first = true; for (auto l : _labels) { VRadioButton *rb = new VRadioButton(l, false); if (first) { rb->SetValue(true); first = false; } connect(rb, &VRadioButton::ValueChanged, this, &PRadioButtons::radioButtonStateChanged); _vg->Add(rb); } } void PRadioButtons::updateGUI() const { for (int i =0; i< _vg->layout()->count(); i++) { VRadioButton *rb = dynamic_cast(_vg->layout()->itemAt(i)->widget()); if (_labels[getParamsLong()] == rb->GetText()) rb->SetValue(true); else rb->SetValue(false); } } void PRadioButtons::radioButtonStateChanged() { VRadioButton *rb = dynamic_cast(sender()); auto it = std::find(_labels.begin(), _labels.end(), rb->GetText()); int index = std::distance(_labels.begin(), it); setParamsLong(index); } ================================================ FILE: apps/vaporgui/PRadioButtons.h ================================================ #pragma once #include "PWidget.h" //class VRadioButton; class VGroup; //! \class PRadioButtons //! Creates a Qt RadioButton synced with the paramsdatabase using the PWidget interface. //! \copydoc PWidget class PRadioButtons : public PWidget { Q_OBJECT VGroup *_vg; std::vector _labels; int _paramValue; public: PRadioButtons(const std::string &tag, const std::vector labels); protected: void updateGUI() const override; private slots: void radioButtonStateChanged(); }; ================================================ FILE: apps/vaporgui/PRegionSelector.cpp ================================================ #include #include "PRegionSelector.h" #include "QRangeSliderTextCombo.h" #include #include #include #include "POrientationSelector.h" using namespace VAPoR; PRegionSelector::PRegionSelector(const std::string &label) : PSection(label) { Add(new PRegionSelectorX); Add(new PRegionSelectorY); Add(new PRegionSelectorZ); } PRegionSelector1D::PRegionSelector1D(int dim) : PLineItem("", dim == 0 ? "X" : dim == 1 ? "Y" : "Z", _slider = new QRangeSliderTextCombo), _dim(dim) { QObject::connect(_slider, &QRangeSliderTextCombo::ValueChanged, this, &PRegionSelector1D::sliderValueChanged); _slider->AllowCustomRange(); } void PRegionSelector1D::updateGUI() const { RenderParams *rp = getParams(); VAPoR::CoordType min, max; size_t ts = rp->GetCurrentTimestep(); int level = rp->GetRefinementLevel(); int lod = rp->GetCompressionLevel(); string varName = rp->GetFirstVariableName(); Box *box = getBox(); // In some cases (ImageRenderer), there may be no 2D variable to configure extents with. // Therefore, configure the sliders with the extents of a random 3D variable if (varName == "") { string varName; VAPoR::DataMgrUtils::GetFirstExistingVariable(getDataMgr(), 0, 0, 0, 3, varName); std::vector axes; VAPoR::CoordType minExts, maxExts; vector vvarName = {varName}; VAPoR::DataMgrUtils::GetExtents(getDataMgr(), 0, vvarName, 0, 0, minExts, maxExts, axes); box->GetExtents(min, max); _slider->SetValue(min[_dim], max[_dim]); _slider->SetRange(minExts[_dim], maxExts[_dim]); return; } int ret = getDataMgr()->GetVariableExtents(ts, varName, level, lod, min, max); if (ret < 0) { _slider->SetRange(0, 0); _slider->SetValue(0, 0); return; } _slider->SetRange(min[_dim], max[_dim]); box->GetExtents(min, max); _slider->SetValue(min[_dim], max[_dim]); } bool PRegionSelector1D::isShown() const { Box *box = getBox(); const Box::Orientation o = (Box::Orientation)box->GetOrientation(); const int d = _dim; switch (o) { case Box::XYZ: return true; case Box::XY: return d == 0 || d == 1; case Box::XZ: return d == 0 || d == 2; case Box::YZ: return d == 1 || d == 2; default: assert(0); } return false; } VAPoR::Box *PRegionSelector1D::getBox() const { return getParams()->GetBox(); } void PRegionSelector1D::sliderValueChanged(float v0, float v1) { Box *box = getBox(); CoordType min, max; box->GetExtents(min, max); min[_dim] = v0; max[_dim] = v1; box->SetExtents(min, max); } ================================================ FILE: apps/vaporgui/PRegionSelector.h ================================================ #pragma once #include "PSection.h" #include "PLineItem.h" class QRangeSliderTextCombo; namespace VAPoR { class Box; } //! \class PRegionSelector class PRegionSelector : public PSection { public: PRegionSelector(const std::string &label = "Region"); }; class PRegionSelector1D : public PLineItem { QRangeSliderTextCombo *_slider; const int _dim; public: PRegionSelector1D(int dim); protected: virtual void updateGUI() const override; virtual bool isShown() const override; virtual bool requireDataMgr() const override { return true; } virtual VAPoR::Box *getBox() const; private: void sliderValueChanged(float v0, float v1); }; template class __PRegionSelector1D : public PRegionSelector1D { public: __PRegionSelector1D() : PRegionSelector1D(dim) {} }; typedef __PRegionSelector1D<0> PRegionSelectorX; typedef __PRegionSelector1D<1> PRegionSelectorY; typedef __PRegionSelector1D<2> PRegionSelectorZ; ================================================ FILE: apps/vaporgui/PSection.cpp ================================================ #include "PSection.h" #include "VSection.h" #include "PGroup.h" #include PSection::PSection(const std::string &label, const PGroup::List &widgets) : PWidget("", _vsection = new VSection(label)) { _pgroup = new PGroup; _vsection->layout()->addWidget(_pgroup); _pgroup->AddM(widgets); } void PSection::updateGUI() const { _pgroup->Update(getParams(), getParamsMgr(), getDataMgr()); } PSection *PSection::Add(PWidget *pw) { _pgroup->Add(pw); return this; } PSection *PSection::Add(const PGroup::List &widgets) { _pgroup->AddM(widgets); return this; } ================================================ FILE: apps/vaporgui/PSection.h ================================================ #pragma once #include "PWidget.h" #include "PGroup.h" class VSection; //! \class PSection //! Same as a PGroup however collated inside of a VSection //! \copydoc PGroup //! \copydoc VSection class PSection : public PWidget { Q_OBJECT VSection *_vsection; PGroup * _pgroup; public: PSection(const std::string &label = "", const PGroup::List &widgets = {}); //! @copydoc PGroup::Add PSection *Add(PWidget *pw); PSection *Add(const PGroup::List &widgets); protected: void updateGUI() const override; }; ================================================ FILE: apps/vaporgui/PShowIf.cpp ================================================ #include "PShowIf.h" #include "PGroup.h" #include #include PShowIf::PShowIf(std::string tag) : PWidgetWrapper(tag, _group = new PGroup) { _test = std::unique_ptr(new TestLongEquals(getTag(), true)); } PShowIf *PShowIf::Equals(long l) { _test = std::unique_ptr(new TestLongEquals(getTag(), l)); return this; } PShowIf *PShowIf::Equals(std::string s) { _test = std::unique_ptr(new TestStringEquals(getTag(), s)); return this; } PShowIf *PShowIf::DimensionEquals(unsigned int dim) { _test = std::unique_ptr(new TestDimensionEquals(dim)); return this; } PShowIf *PShowIf::Not() { _negate = !_negate; return this; } PShowIf *PShowIf::Then(PWidget *p) { _hasThen = true; _group->Add(new Helper(this, p)); return this; } PShowIf *PShowIf::Else(PWidget *p) { _hasElse = true; _group->Add(new Helper(this, p, true)); return this; } PShowIf *PShowIf::Then(const PGroup::List &list) { return Then(new PGroup(list)); } PShowIf *PShowIf::Else(const PGroup::List &list) { return Else(new PGroup(list)); } bool PShowIf::isShown() const { bool result = evaluate(); return (result && _hasThen) || (!result && _hasElse); } bool PShowIf::evaluate() const { VAssert(_test); return _test->Evaluate(getParams()) != _negate; } PShowIf::Helper::Helper(PShowIf *parent, PWidget *widget, bool negate) : PWidgetWrapper(widget), _parent(parent), _negate(negate) {} bool PShowIf::Helper::isShown() const { return _parent->evaluate() != _negate; } bool PShowIf::TestLongEquals::Evaluate(VAPoR::ParamsBase *params) const { return params->GetValueLong(_tag, 0) == _val; } bool PShowIf::TestStringEquals::Evaluate(VAPoR::ParamsBase *params) const { return params->GetValueString(_tag, "") == _val; } #include bool PShowIf::TestDimensionEquals::Evaluate(VAPoR::ParamsBase *params) const { VAPoR::RenderParams *rp = dynamic_cast(params); return rp->GetRenderDim() == _val; } ================================================ FILE: apps/vaporgui/PShowIf.h ================================================ #pragma once #include "PWidgetWrapper.h" #include "PGroup.h" #include //! \class PShowIf //! \brief Shows and hides PWidgets based on a logic test. //! \author Stas Jaroszynski //! //! For example: //! (new PShowIf("param_tag"))->Not()->Equals("Hi")->Then( //! PWidgets here will only show if param_tag != "Hi" //! )->Else( //! PWidgets here will only show if param_tag == "Hi" //! ); class PShowIf : public PWidgetWrapper { PGroup *_group; bool _negate = false; bool _hasThen = false; bool _hasElse = false; public: PShowIf(std::string tag); PShowIf *Equals(long l); PShowIf *Equals(std::string s); PShowIf *DimensionEquals(unsigned int dim); // PShowIf *Or(PShowIf *); PShowIf *Not(); PShowIf *Then(PWidget *p); PShowIf *Else(PWidget *p); PShowIf *Then(const PGroup::List &list); PShowIf *Else(const PGroup::List &list); protected: bool isShown() const override; private: bool evaluate() const; class Helper : public PWidgetWrapper { const PShowIf *_parent; const bool _negate; public: Helper(PShowIf *parent, PWidget *widget, bool negate = false); protected: bool isShown() const override; }; struct Test { const std::string _tag; Test(std::string tag) : _tag(tag) {} virtual bool Evaluate(VAPoR::ParamsBase *params) const = 0; virtual ~Test() {} }; struct TestLongEquals : public Test { const long _val; TestLongEquals(std::string tag, long val) : Test(tag), _val(val) {} bool Evaluate(VAPoR::ParamsBase *params) const override; }; struct TestStringEquals : public Test { const std::string _val; TestStringEquals(std::string tag, std::string val) : Test(tag), _val(val) {} bool Evaluate(VAPoR::ParamsBase *params) const override; }; struct TestDimensionEquals : public Test { const long _val; TestDimensionEquals(long val) : Test(""), _val(val) {} bool Evaluate(VAPoR::ParamsBase *params) const override; }; std::unique_ptr _test; }; ================================================ FILE: apps/vaporgui/PSliceController.cpp ================================================ #include "PSliceController.h" #include "PEnumDropdown.h" #include "PSliderEditHLI.h" #include "PLabel.h" #include "PShowIf.h" #include "PCheckbox.h" #include #include using namespace VAPoR; PSliceController::PSliceController() : PGroup() { Add(new PSliceOrientationSelector); Add(new PSliceOffsetSelector); Add(new PSliceOriginSelector); } PSliceOrientationSelector::PSliceOrientationSelector() : PSection("Slice Orientation") { Add(new PEnumDropdown(RenderParams::SlicePlaneOrientationModeTag, {"Rotation", "Normal"}, {(int)RenderParams::SlicePlaneOrientationMode::Rotation, (int)RenderParams::SlicePlaneOrientationMode::Normal}, "Orientation Mode")); Add((new PShowIf(RenderParams::SlicePlaneOrientationModeTag)) ->Equals((int)RenderParams::SlicePlaneOrientationMode::Rotation) ->Then({ (new PDoubleSliderEdit(RenderParams::XSlicePlaneRotationTag, "X"))->SetRange(-90., 90.)->EnableDynamicUpdate(), (new PDoubleSliderEdit(RenderParams::YSlicePlaneRotationTag, "Y"))->SetRange(-90., 90.)->EnableDynamicUpdate(), (new PDoubleSliderEdit(RenderParams::ZSlicePlaneRotationTag, "Z"))->SetRange(-90., 90.)->EnableDynamicUpdate(), }) ->Else({ (new PDoubleSliderEdit(RenderParams::SlicePlaneNormalXTag, "X"))->SetRange(-1, 1)->EnableDynamicUpdate(), (new PDoubleSliderEdit(RenderParams::SlicePlaneNormalYTag, "Y"))->SetRange(-1, 1)->EnableDynamicUpdate(), (new PDoubleSliderEdit(RenderParams::SlicePlaneNormalZTag, "Z"))->SetRange(-1, 1)->EnableDynamicUpdate(), })); SetTooltip("The plane normal of the slice. The offset will move the slice along this normal as well."); } PSliceOriginSelector::PSliceOriginSelector() : PSection("Slice Origin") { _xSlider = new PDoubleSliderEditHLI("X", &RenderParams::GetXSlicePlaneOrigin, &RenderParams::SetXSlicePlaneOrigin); _ySlider = new PDoubleSliderEditHLI("Y", &RenderParams::GetYSlicePlaneOrigin, &RenderParams::SetYSlicePlaneOrigin); _zSlider = new PDoubleSliderEditHLI("Z", &RenderParams::GetZSlicePlaneOrigin, &RenderParams::SetZSlicePlaneOrigin); _xSlider->EnableDynamicUpdate(); _ySlider->EnableDynamicUpdate(); _zSlider->EnableDynamicUpdate(); Add({ new PLabel("Slice origin is shown in-scene as a yellow crosshair"), new PCheckbox("GUI_ShowOrigin", "Show Origin Controls"), (new PShowIf("GUI_ShowOrigin")) ->Then({ _xSlider, _ySlider, _zSlider, }), }); SetTooltip("The slice plane will pass through this point. \nThe plane can be offset from this point along the plane normal determined by the orientation."); } void PSliceOriginSelector::updateGUI() const { RenderParams *rp = getParams(); CoordType min, max; size_t ts = rp->GetCurrentTimestep(); int level = rp->GetRefinementLevel(); int lod = rp->GetCompressionLevel(); string varName = rp->GetVariableName(); int ret = getDataMgr()->GetVariableExtents(ts, varName, level, lod, min, max); if (ret) return; _xSlider->SetRange(min[0], max[0]); _ySlider->SetRange(min[1], max[1]); _zSlider->SetRange(min[2], max[2]); PSection::updateGUI(); } #include PSliceOffsetSelector::PSliceOffsetSelector() : PSection("Slice Offset") { _offsetSlider = new PDoubleSliderEdit(RenderParams::SliceOffsetTag, "Offset"); _offsetSlider->EnableDynamicUpdate(); Add(_offsetSlider); SetTooltip("Offset the plane from its origin \n along its normal (set by the orientation)."); } void PSliceOffsetSelector::updateGUI() const { RenderParams *rp = getParams(); planeDescription pd; size_t ts = rp->GetCurrentTimestep(); int level = rp->GetRefinementLevel(); int lod = rp->GetCompressionLevel(); string varName = rp->GetVariableName(); int ret = getDataMgr()->GetVariableExtents(ts, varName, level, lod, pd.boxMin, pd.boxMax); if (ret) return; pd.origin = rp->GetSlicePlaneOrigin(); if (rp->GetValueLong(rp->SlicePlaneOrientationModeTag, 0) == (int)RenderParams::SlicePlaneOrientationMode::Normal) { pd.normal = rp->GetSlicePlaneNormal(); } else { auto n = ArbitrarilyOrientedRegularGrid::GetNormalFromRotations(rp->GetSlicePlaneRotation()); pd.normal = {n[0], n[1], n[2]}; } auto range = ArbitrarilyOrientedRegularGrid::GetOffsetRange(pd); _offsetSlider->SetRange(range.first, range.second); PSection::updateGUI(); } ================================================ FILE: apps/vaporgui/PSliceController.h ================================================ #pragma once #include "PSection.h" //! \class PSliceController //! \brief Provides controls for rotating slices, offsetting them, and positioning their origin class PDoubleSliderEdit; class PSliceController : public PGroup { public: PSliceController(); }; class PSliceOrientationSelector : public PSection { public: PSliceOrientationSelector(); }; class PSliceOriginSelector : public PSection { public: PSliceOriginSelector(); protected: PDoubleSliderEdit *_xSlider; PDoubleSliderEdit *_ySlider; PDoubleSliderEdit *_zSlider; virtual void updateGUI() const override; virtual bool requireDataMgr() const override { return true; } }; class PSliceOffsetSelector : public PSection { public: PSliceOffsetSelector(); protected: PDoubleSliderEdit *_offsetSlider; virtual void updateGUI() const override; virtual bool requireDataMgr() const override { return true; } }; ================================================ FILE: apps/vaporgui/PSliderEdit.cpp ================================================ #include "PSliderEdit.h" #include "VLineItem.h" #include #include "VSliderEdit.h" #include "VDoubleSliderEdit.h" #include "VIntSliderEdit.h" #define USER_RANGE_MIN_TAG "_PWidget_UserRangeMinimum" #define USER_RANGE_MAX_TAG "_PWidget_UserRangeMaximum" // =============================== // PDoubleSliderEdit // =============================== PDoubleSliderEdit::PDoubleSliderEdit(const std::string &tag, const std::string &label) : PLineItem(tag, label, _sliderEdit = new VDoubleSliderEdit(0, 1, 0, true)) { connect(_sliderEdit, &VDoubleSliderEdit::ValueChanged, this, &PDoubleSliderEdit::valueChanged); connect(_sliderEdit, &VDoubleSliderEdit::ValueChangedIntermediate, this, &PDoubleSliderEdit::valueChangedIntermediate); connect(_sliderEdit, &VDoubleSliderEdit::MinimumChanged, this, &PDoubleSliderEdit::minimumChanged); connect(_sliderEdit, &VDoubleSliderEdit::MaximumChanged, this, &PDoubleSliderEdit::maximumChanged); connect(_sliderEdit, &VDoubleSliderEdit::DynamicUpdateChanged, this, &PDoubleSliderEdit::_enableDynamicUpdate); } PDoubleSliderEdit *PDoubleSliderEdit::SetRange(double min, double max) { _defaultRangeMin = min; _defaultRangeMax = max; _sliderEdit->SetMinimum(min); _sliderEdit->SetMaximum(max); return this; } PDoubleSliderEdit *PDoubleSliderEdit::AllowUserRange(bool allowed) { _sliderEdit->AllowUserRange(allowed); return this; } PDoubleSliderEdit* PDoubleSliderEdit::AllowDynamicUpdate() { _sliderEdit->AllowDynamicUpdate(); return this; } void PDoubleSliderEdit::_enableDynamicUpdate(bool enabled) { EnableDynamicUpdate(enabled); } void PDoubleSliderEdit::updateGUI() const { auto p = getParams(); _sliderEdit->SetMinimum(p->GetValueDouble(getTag() + USER_RANGE_MIN_TAG, _defaultRangeMin)); _sliderEdit->SetMaximum(p->GetValueDouble(getTag() + USER_RANGE_MAX_TAG, _defaultRangeMax)); _sliderEdit->SetValue(getParamsDouble()); } void PDoubleSliderEdit::valueChanged(double v) { setParamsDouble(v); } void PDoubleSliderEdit::valueChangedIntermediate(double v) { dynamicSetParamsDouble(v); } void PDoubleSliderEdit::minimumChanged(double v) { auto p = getParams(); p->SetValueDouble(getTag() + USER_RANGE_MIN_TAG, "", v); } void PDoubleSliderEdit::maximumChanged(double v) { auto p = getParams(); p->SetValueDouble(getTag() + USER_RANGE_MAX_TAG, "", v); } // =============================== // PIntegerSliderEdit // =============================== PIntegerSliderEdit::PIntegerSliderEdit(const std::string &tag, const std::string &label) : PLineItem(tag, label, _sliderEdit = new VIntSliderEdit(0, 1, 0, true)) { connect(_sliderEdit, &VIntSliderEdit::ValueChanged, this, &PIntegerSliderEdit::valueChanged); connect(_sliderEdit, &VIntSliderEdit::ValueChangedIntermediate, this, &PIntegerSliderEdit::valueChangedIntermediate); connect(_sliderEdit, &VIntSliderEdit::MinimumChanged, this, &PIntegerSliderEdit::minimumChanged); connect(_sliderEdit, &VIntSliderEdit::MaximumChanged, this, &PIntegerSliderEdit::maximumChanged); connect(_sliderEdit, &VIntSliderEdit::DynamicUpdateChanged, this, &PIntegerSliderEdit::_enableDynamicUpdate); } PIntegerSliderEdit *PIntegerSliderEdit::SetRange(int min, int max) { _defaultRangeMin = min; _defaultRangeMax = max; _sliderEdit->SetMinimum(min); _sliderEdit->SetMaximum(max); return this; } PIntegerSliderEdit *PIntegerSliderEdit::AllowUserRange(bool allowed) { _sliderEdit->AllowUserRange(allowed); return this; } PIntegerSliderEdit* PIntegerSliderEdit::AllowDynamicUpdate() { _sliderEdit->AllowDynamicUpdate(); return this; } void PIntegerSliderEdit::_enableDynamicUpdate(bool enabled) { EnableDynamicUpdate(enabled); } void PIntegerSliderEdit::updateGUI() const { auto p = getParams(); _sliderEdit->SetMinimum(p->GetValueLong(getTag() + USER_RANGE_MIN_TAG, _defaultRangeMin)); _sliderEdit->SetMaximum(p->GetValueLong(getTag() + USER_RANGE_MAX_TAG, _defaultRangeMax)); _sliderEdit->SetValue(getParamsLong()); } void PIntegerSliderEdit::valueChanged(int v) { setParamsLong(v); } void PIntegerSliderEdit::valueChangedIntermediate(int v) { dynamicSetParamsLong(v); } void PIntegerSliderEdit::minimumChanged(int v) { auto p = getParams(); p->SetValueLong(getTag() + USER_RANGE_MIN_TAG, "", v); } void PIntegerSliderEdit::maximumChanged(int v) { auto p = getParams(); p->SetValueLong(getTag() + USER_RANGE_MAX_TAG, "", v); } ================================================ FILE: apps/vaporgui/PSliderEdit.h ================================================ #pragma once #include "PLineItem.h" #include "PDynamicMixin.h" class VDoubleSliderEdit; class VIntSliderEdit; //! \class PDoubleSliderEdit //! Creates a slider and text input combo synced with the paramsdatabase. //! Due to the way VDoubleSliderEdit and VIntSliderEdit are implemented, //! duplicating the code was simpler than templatizing. class PDoubleSliderEdit : public PLineItem, public PDynamicMixin { VDoubleSliderEdit *_sliderEdit; double _defaultRangeMin = 0, _defaultRangeMax = 1; public: PDoubleSliderEdit(const std::string &tag, const std::string &label = ""); //! @copydoc VSliderEdit::SetRange PDoubleSliderEdit *SetRange(double min, double max); PDoubleSliderEdit *AllowUserRange(bool allowed = true); PDoubleSliderEdit *AllowDynamicUpdate(); protected: void updateGUI() const override; private: void valueChanged(double v); void valueChangedIntermediate(double v); void minimumChanged(double v); void maximumChanged(double v); private slots: void _enableDynamicUpdate(bool enabled); }; //! \class PIntegerSliderEdit //! Creates a slider and text input combo synced with the paramsdatabase. //! Due to the way VDoubleSliderEdit and VIntSliderEdit are implemented, //! duplicating the code was simpler than templatizing. class PIntegerSliderEdit : public PLineItem, public PDynamicMixin { VIntSliderEdit *_sliderEdit; int _defaultRangeMin = 0, _defaultRangeMax = 1; public: PIntegerSliderEdit(const std::string &tag, const std::string &label = ""); //! @copydoc VSliderEdit::SetRange PIntegerSliderEdit *SetRange(int min, int max); PIntegerSliderEdit *AllowUserRange(bool allowed = true); PIntegerSliderEdit *AllowDynamicUpdate(); protected: void updateGUI() const override; private: void valueChanged(int v); void valueChangedIntermediate(int v); void minimumChanged(int v); void maximumChanged(int v); private slots: void _enableDynamicUpdate(bool enabled); }; ================================================ FILE: apps/vaporgui/PSliderEditHLI.h ================================================ #pragma once #include "PWidgetHLI.h" #include "PSliderEdit.h" CreateHLI(PDoubleSliderEdit, double); CreateHLI(PIntegerSliderEdit, long); ================================================ FILE: apps/vaporgui/PStringDropdown.cpp ================================================ #include "PStringDropdown.h" #include #include #include "VComboBox.h" PStringDropdown::PStringDropdown(const std::string &tag, const std::vector &items, const std::string &label) : PLineItem(tag, label, _vComboBox = new VComboBox(items)) { connect(_vComboBox, &VComboBox::ValueChanged, this, &PStringDropdown::dropdownTextChanged); } void PStringDropdown::SetItems(const std::vector &items) const { _vComboBox->SetOptions(items); } void PStringDropdown::updateGUI() const { auto val = getParamsString(); if (val.empty()) val = _customBlankText; _vComboBox->SetValue(val); } void PStringDropdown::setCustomBlankText(std::string text) { _customBlankText = text; } void PStringDropdown::dropdownTextChanged(std::string text) { setParamsString(text); } ================================================ FILE: apps/vaporgui/PStringDropdown.h ================================================ #pragma once #include "PLineItem.h" #include //#include "VaporWidgetsFwd.h" class VComboBox; //! \class PStringDropdown same as PEnumDropdown except it sets the param //! to directly reflect the string in the drowdown. //! \copydoc PEnumDropdown class PStringDropdown : public PLineItem { Q_OBJECT VComboBox *_vComboBox; std::string _customBlankText; public: PStringDropdown(const std::string &tag, const std::vector &items, const std::string &label = ""); //! Sets the items presented in the dropdown void SetItems(const std::vector &items) const; protected: virtual void updateGUI() const override; void setCustomBlankText(std::string text); protected slots: virtual void dropdownTextChanged(std::string text); }; ================================================ FILE: apps/vaporgui/PStringDropdownHLI.h ================================================ #pragma once #include "PWidgetHLI.h" #include "PStringDropdown.h" template class PStringDropdownHLI : public PStringDropdown, public PWidgetHLIBase { public: PStringDropdownHLI(const std::string &label, const std::vector &items, typename PWidgetHLIBase::GetterType getter, typename PWidgetHLIBase::SetterType setter) : PStringDropdown("", items, label), PWidgetHLIBase((PWidget *)this, getter, setter) { } }; ================================================ FILE: apps/vaporgui/PStringInput.cpp ================================================ #include "PStringInput.h" #include "VLineItem.h" #include #include "VStringLineEdit.h" PStringInput::PStringInput(const std::string &tag, const std::string &label) : PLineItem(tag, label, _stringLineEdit = new VStringLineEdit) { connect(_stringLineEdit, &VStringLineEdit::ValueChanged, this, &PStringInput::inputValueChanged); } void PStringInput::updateGUI() const { const string value = getParamsString(); _stringLineEdit->SetValueString(value); } void PStringInput::inputValueChanged(const std::string &v) { setParamsString(v); } ================================================ FILE: apps/vaporgui/PStringInput.h ================================================ #pragma once #include "PLineItem.h" //#include "VaporWidgetsFwd.h" class VStringLineEdit; //! \class PStringInput //! Creates a Qt text input for string values synced with the paramsdatabase using the PWidget interface. //! \copydoc PWidget class PStringInput : public PLineItem { VStringLineEdit *_stringLineEdit; public: PStringInput(const std::string &tag, const std::string &label = ""); protected: void updateGUI() const override; private: void inputValueChanged(const std::string &v); }; ================================================ FILE: apps/vaporgui/PTFEditor.cpp ================================================ #include "PTFEditor.h" #include #include #include "TFColorWidget.h" #include "TFOpacityWidget.h" #include "TFHistogramWidget.h" #include "TFIsoValueWidget.h" #include "TFMappingRangeSelector.h" #include "TFMapGroupWidget.h" #include "VSection.h" #include "PDisplay.h" #include "mac_helpers.h" using VAPoR::RenderParams; template PTFMapWidget::PTFMapWidget(const std::string &tag) : PWidget(tag, _tfWidget = new TFColorWidget(tag)) {} template void PTFMapWidget::updateGUI() const { RenderParams *rp = dynamic_cast(getParams()); VAssert(rp); _tfWidget->Update(getDataMgr(), getParamsMgr(), rp); } template class PTFMapWidget; template class PTFMapWidget; template class PTFMapWidget; template class PTFMapWidget; PTFEditor::PTFEditor() : PTFEditor(RenderParams::_variableNameTag) {} PTFEditor::PTFEditor(const std::string &tag, const std::set elements, const std::string &label, bool expandable) : PWidget(tag, _section = new VSection(label.empty() ? tag : label)), _expandable(expandable) { setMaximumSize(1200,720); _maps = new TFMapGroupWidget; _histogram = new TFHistogramMap(tag); _opacityMap = new TFOpacityMap(tag); _colorMap = new TFColorMap(tag); _isoMap = new TFIsoValueMap(tag); _range = new TFMappingRangeSelector(tag); _elements = elements; _maps->Add({_opacityMap, _histogram}); _maps->Add(_isoMap); _maps->Add(_colorMap); _section->layout()->addWidget(_maps, 1); _section->layout()->addWidget(_mapsInfo = _maps->CreateInfoGroup()); _section->layout()->addWidget(_range, 0); connect(_range, SIGNAL(ValueChangedIntermediate(float, float)), _histogram, SLOT(update())); int start = 0; QMenu *menu = new QMenu; _colorMap->PopulateSettingsMenu(menu); for (int i = start; i < menu->actions().size(); i++) _colorMapActions.push_back(menu->actions()[i]); menu->addSeparator(); start = menu->actions().size(); _opacityMap->PopulateSettingsMenu(menu); for (int i = start; i < menu->actions().size(); i++) _opacityMapActions.push_back(menu->actions()[i]); menu->addSeparator(); start = menu->actions().size(); _histogram->PopulateSettingsMenu(menu); for (int i = start; i < menu->actions().size(); i++) _histogramActions.push_back(menu->actions()[i]); if (_expandable) { _section->enableExpandedSection(); connect(_section, &VSection::expandButtonClicked, this, &PTFEditor::showExpandedPTFEditor); } _section->setMenu(menu); _histogram->hide(); _opacityMap->hide(); _colorMap->hide(); _isoMap->hide(); if (elements.count(Opacity)) _opacityMap->show(); if (elements.count(Colormap)) _colorMap->show(); if (elements.count(Histogram)) _histogram->show(); if (elements.count(IsoValues) || elements.count(RegularIsoArray)) _isoMap->show(); if (elements.count(RegularIsoArray)) _isoMap->SetEquidistantIsoValues(true); else _isoMap->SetEquidistantIsoValues(false); if (elements.count(Default)) { _histogram->show(); _opacityMap->show(); _colorMap->show(); _isoMap->show(); } } PTFEditor *PTFEditor::ShowOpacityBasedOnParam(const std::string &tag, int value) { _showOpacityBasedOnParam = true; _showOpacityBasedOnParamTag = tag; _showOpacityBasedOnParamValue = value; return this; } PTFEditor *PTFEditor::ShowColormapBasedOnParam(const std::string &tag, int value) { _showColormapBasedOnParam = true; _showColormapBasedOnParamTag = tag; _showColormapBasedOnParamValue = value; return this; } void PTFEditor::updateGUI() const { VAPoR::DataMgr * dm = getDataMgr(); VAPoR::ParamsMgr * pm = getParamsMgr(); VAPoR::RenderParams *rp = dynamic_cast(getParams()); VAssert(rp); _maps->Update(dm, pm, rp); _mapsInfo->Update(rp); _range->Update(dm, pm, rp); if (_showOpacityBasedOnParam) { if (rp->GetValueLong(_showOpacityBasedOnParamTag, 0) == _showOpacityBasedOnParamValue) _opacityMap->show(); else _opacityMap->hide(); } if (_showColormapBasedOnParam) { if (rp->GetValueLong(_showColormapBasedOnParamTag, 0) == _showColormapBasedOnParamValue) _colorMap->show(); else _colorMap->hide(); } for (auto a : _colorMapActions) a->setEnabled(_colorMap->IsShown()); for (auto a : _opacityMapActions) a->setEnabled(_opacityMap->IsShown()); for (auto a : _histogramActions) a->setEnabled(_histogram->IsShown()); } void PTFEditor::Update(VAPoR::ParamsBase *params, VAPoR::ParamsMgr *paramsMgr, VAPoR::DataMgr *dataMgr) { if (getParams() != params) { closeExpandedPTFEditor(); } PWidget::Update(params, paramsMgr, dataMgr); if (_expandable==true) { std::string name, inst; getExpandedPTFEditorInfo(name, inst); if (_expandedPTFEditor!=nullptr) { _expandedPTFEditor->setWindowTitle(QString::fromStdString(name)); _expandedPTFEditor->Update(params, paramsMgr, dataMgr); } } } void PTFEditor::getExpandedPTFEditorInfo(std::string &name, std::string& type) { ParamsMgr* pm = getParamsMgr(); GUIStateParams* p = dynamic_cast(pm->GetParams(GUIStateParams::GetClassType())); type = p->GetActiveRendererInst(); p->GetActiveRenderer(p->GetActiveVizName(), type, name); if (dynamic_cast(this)) { name+="_Colormap"; type+="_Colormap"; } } void PTFEditor::showExpandedPTFEditor() { if (_expandedPTFEditor==nullptr) { _expandedPTFEditor = new ExpandedPTFEditor(getTag(), _elements, _section->getTitle(), false); connect(_expandedPTFEditor, SIGNAL(closed()), this, SLOT(closeExpandedPTFEditor())); if (_showColormapBasedOnParam==true) _expandedPTFEditor->ShowColormapBasedOnParam(_showColormapBasedOnParamTag, _showColormapBasedOnParamValue); if (_showOpacityBasedOnParam==true) _expandedPTFEditor->ShowOpacityBasedOnParam(_showOpacityBasedOnParamTag, _showOpacityBasedOnParamValue); _expandedPTFEditor->setAttribute(Qt::WA_ShowWithoutActivating); _expandedPTFEditor->setAttribute(Qt::WA_DeleteOnClose); } _expandedPTFEditor->raise(); Update(getParams(), getParamsMgr(), getDataMgr()); } void PTFEditor::closeExpandedPTFEditor() { if (_expandedPTFEditor != nullptr) { _expandedPTFEditor->close(); _expandedPTFEditor=nullptr; } } void PTFEditor::hideEvent(QHideEvent* event) { closeExpandedPTFEditor(); } PColormapTFEditor::PColormapTFEditor() : PTFEditor(RenderParams::_colorMapVariableNameTag, {PTFEditor::Histogram, PTFEditor::Colormap}, "Colormap Transfer Function") {} ExpandedPTFEditor::ExpandedPTFEditor(const std::string &tag, const std::set elements, const std::string &label, bool expandable) : PTFEditor(tag, elements, label, expandable) { #ifdef Q_OS_MAC DisableMacFullscreen(this); #endif } void ExpandedPTFEditor::closeEvent(QCloseEvent *event) { emit closed(); QWidget::closeEvent(event); } ================================================ FILE: apps/vaporgui/PTFEditor.h ================================================ #pragma once #include "PWidget.h" #include class TFMap; class TFColorMap; class TFOpacityMap; class TFHistogramMap; class TFIsoValueMap; class TFMapWidget; class TFColorWidget; class TFOpacityWidget; class TFHistogramWidget; class TFIsoValueWidget; //! \class PTFMapWidget //! Wrapper class that allows TFMapsWidgets to be used as PWidgets //! \copydoc TFMapsWidget template class PTFMapWidget : public PWidget { TFMapWidget *_tfWidget; public: PTFMapWidget(const std::string &tag); protected: virtual void updateGUI() const override; virtual bool requireParamsMgr() const override { return true; } virtual bool requireDataMgr() const override { return true; } }; typedef PTFMapWidget PTFColorWidget; typedef PTFMapWidget PTFOpacityWidget; typedef PTFMapWidget PTFHistogramWidget; typedef PTFMapWidget PTFIsoValueWidget; class VSection; class TFMappingRangeSelector; class TFMapGroupWidget; class TFMapInfoGroupWidget; class PStringDisplay; //! \class PTFEditor //! PWidget wrapper for TFEditor //! \copydoc TFEditor class PTFEditor : public PWidget { Q_OBJECT; VSection * _section; TFMapGroupWidget * _maps; TFMapInfoGroupWidget * _mapsInfo; TFHistogramMap * _histogram; TFOpacityMap * _opacityMap; TFColorMap * _colorMap; TFIsoValueMap * _isoMap; TFMappingRangeSelector *_range; PTFEditor* _expandedPTFEditor = nullptr; bool _expandable; std::vector _colorMapActions; std::vector _opacityMapActions; std::vector _histogramActions; bool _showOpacityBasedOnParam = false; std::string _showOpacityBasedOnParamTag; int _showOpacityBasedOnParamValue; bool _showColormapBasedOnParam = false; std::string _showColormapBasedOnParamTag; bool _showColormapBasedOnParamValue; public: enum Element { Opacity, Histogram, Colormap, IsoValues, RegularIsoArray, Default }; PTFEditor(); PTFEditor(const std::string &tag, const std::set elements = {Default}, const std::string &label = "Transfer Function", bool expandable = true); //! Behaves the same as PWidget::ShowBasedOnParam except shows/hides the opacity controls. //! @copydoc PWidget::ShowBasedOnParam PTFEditor *ShowOpacityBasedOnParam(const std::string &tag, int value); //! Behaves the same as PWidget::ShowBasedOnParam except shows/hides the colormap controls. //! @copydoc PWidget::ShowBasedOnParam PTFEditor *ShowColormapBasedOnParam(const std::string &tag, int value); protected: std::set _elements; std::string _label; void hideEvent(QHideEvent *event) override; void updateGUI() const override; void Update(VAPoR::ParamsBase* p, VAPoR::ParamsMgr* pm, VAPoR::DataMgr* dm) override; void getExpandedPTFEditorInfo(std::string &name, std::string &type); private slots: void showExpandedPTFEditor(); void closeExpandedPTFEditor(); }; class PColormapTFEditor : public PTFEditor { public: PColormapTFEditor(); }; //! \class Expanded PTFEditor //! A sublcass of PTFEditor that emits a signal when closed //! \copydoc PTFEditor class ExpandedPTFEditor : public PTFEditor { Q_OBJECT public: ExpandedPTFEditor(const std::string &tag, const std::set elements = {Default}, const std::string &label = "Transfer Function", bool expandable = false); signals: void closed(); protected: void closeEvent(QCloseEvent *event) override; }; ================================================ FILE: apps/vaporgui/PTMSLODInput.h ================================================ #pragma once #include #include "vapor/ImageParams.h" #include "vapor/GeoImageTMS.h" #include "vapor/TMSUtils.h" #include "PGroup.h" #include "VComboBox.h" // // PWidget for selecting TMS file level-of-detail // class PTMSLODInput : public PLineItem { Q_OBJECT VComboBox *_vComboBox; public: PTMSLODInput() : PLineItem("", "TMS level of detail", _vComboBox = new VComboBox({"0"})) { QString tooltip = "TMS images can be displayed at varying resolutions.\n" "This setting allows for manual resolution selection."; _vComboBox->setToolTip(tooltip); connect(_vComboBox, &VComboBox::IndexChanged, this, &PTMSLODInput::dropdownIndexChanged); } protected: virtual void updateGUI() const override { VAPoR::ImageParams *rp = dynamic_cast(getParams()); VAssert(rp && "Params must be ImageParams"); std::string imageFile = rp->GetImagePath(); if (Wasp::TMSUtils::IsTMSFile(imageFile)) { _vComboBox->setEnabled(true); } else { _vComboBox->setEnabled(false); // Disable if not using a TMS image return; } std::vector options{"default"}; int lods = rp->GetNumTMSLODs(); for (int i = 0; i < lods; i++) { options.push_back(std::to_string(i)); } _vComboBox->SetOptions(options); _vComboBox->SetIndex(rp->GetTMSLOD() + 1); }; private slots: void dropdownIndexChanged(int i) { VAPoR::ImageParams *rp = dynamic_cast(getParams()); VAssert(rp && "Params must be ImageParams"); rp->SetTMSLOD(i - 1); } }; ================================================ FILE: apps/vaporgui/PTimeRangeSelector.cpp ================================================ #include "PTimeRangeSelector.h" #include "vapor/ControlExecutive.h" #include "vapor/AnimationParams.h" #include "QRangeSliderTextCombo.h" #include "VLabelPair.h" #include PTimeRangeSelector::PTimeRangeSelector(ControlExec* ce) : PWidget("", new VGroup({ _slider = new QRangeSliderTextCombo(), _timeStampPair = new VLabelPair(), }) ), _ce(ce) { _slider->SetNumDigits(0); connect(_slider, SIGNAL(ValueChanged(float, float)), this, SLOT(setTimes(float, float))); } void PTimeRangeSelector::updateGUI() const { _slider->SetRange(0, _ce->GetDataStatus()->GetTimeCoordinates().size()-1); AnimationParams* ap = dynamic_cast(getParams()); size_t start = ap->GetValueLong(AnimationParams::CaptureStartTag, ap->GetStartTimestep()); size_t end = ap->GetValueLong(AnimationParams::CaptureEndTag, ap->GetEndTimestep()); _slider->SetValue(start, end); std::vector timeCoords = _ce->GetDataStatus()->GetTimeCoordsFormatted(); _timeStampPair->SetLeftText(timeCoords[start]); _timeStampPair->SetRightText(timeCoords[end]); } void PTimeRangeSelector::setTimes(float start, float end) { start = std::round(start); end = std::round(end); _slider->SetValue(start, end); AnimationParams* ap = dynamic_cast(getParams()); ap->SetValueLong(AnimationParams::CaptureStartTag, "Set value for capturing imagery start time", start); ap->SetValueLong(AnimationParams::CaptureEndTag, "Set value for capturing imagery end time", end); } ================================================ FILE: apps/vaporgui/PTimeRangeSelector.h ================================================ #pragma once #include "PGroup.h" #include "VContainer.h" #include "ParamsUpdatable.h" #include "VHBoxWidget.h" namespace VAPoR { class ControlExec; } class QRangeSliderTextCombo; class VLabelPair; class VLineItem; //! \class PTimeRangeSelector //! \brief A PWidget that maintains a TimeRangeSelector class PTimeRangeSelector : public PWidget { Q_OBJECT ControlExec* _ce; QRangeSliderTextCombo* _slider; VLabelPair* _timeStampPair; public: PTimeRangeSelector(ControlExec* ce); void updateGUI() const override; private slots: void setTimes(float start, float end); }; ================================================ FILE: apps/vaporgui/PTimestepInput.cpp ================================================ #include "PTimestepInput.h" #include #include "VIntSpinBox.h" #include PTimestepInput::PTimestepInput(VAPoR::ControlExec *ce) : PWidget("", _input = new VIntSpinBox(0, 1)), _ce(ce) { connect(_input, &VIntSpinBox::ValueChangedIntermediate, this, &PTimestepInput::inputChanged); _input->setMinimumWidth(40); } void PTimestepInput::updateGUI() const { auto p = NavigationUtils::GetAnimationParams(_ce); const int start = p->GetStartTimestep(); const int end = p->GetEndTimestep(); const int ts = p->GetCurrentTimestep(); // int end = _ce->GetDataStatus()->GetTimeCoordinates().size() - 1; _input->SetRange(start, end); _input->SetValue(ts); } void PTimestepInput::inputChanged(int v) { NavigationUtils::SetTimestep(_ce, v); } ================================================ FILE: apps/vaporgui/PTimestepInput.h ================================================ #pragma once #include "PWidget.h" namespace VAPoR { class ControlExec; } class VIntSpinBox; class PTimestepInput : public PWidget { VAPoR::ControlExec *_ce; VIntSpinBox * _input; public: PTimestepInput(VAPoR::ControlExec *ce); protected: void updateGUI() const override; void inputChanged(int v); }; ================================================ FILE: apps/vaporgui/PTimestepSliderEdit.cpp ================================================ #include "PTimestepSliderEdit.h" #include "VLineItem.h" #include #include "VIntSliderEdit.h" #include #include // =============================== // PTimestepSliderEdit // =============================== PTimestepSliderEdit::PTimestepSliderEdit(VAPoR::ControlExec *ce) : PLineItem("", "Current Timestep", _sliderEdit = new VIntSliderEdit(0, 1, 0, false)) { _ce = ce; connect(_sliderEdit, &VIntSliderEdit::ValueChanged, this, &PTimestepSliderEdit::valueChanged); } void PTimestepSliderEdit::updateGUI() const { auto p = NavigationUtils::GetAnimationParams(_ce); const int start = p->GetStartTimestep(); const int end = p->GetEndTimestep(); const int ts = p->GetCurrentTimestep(); _sliderEdit->SetMinimum(start); _sliderEdit->SetMaximum(end); _sliderEdit->SetValue(ts); } void PTimestepSliderEdit::valueChanged(int v) { NavigationUtils::SetTimestep(_ce, v); } ================================================ FILE: apps/vaporgui/PTimestepSliderEdit.h ================================================ #pragma once #include "PLineItem.h" class VIntSliderEdit; namespace VAPoR { class ControlExec; }; //! \class PTimestepSliderEdit //! Creates a timestep slider input class PTimestepSliderEdit : public PLineItem { VIntSliderEdit * _sliderEdit; VAPoR::ControlExec *_ce; public: PTimestepSliderEdit(VAPoR::ControlExec *ce); protected: void updateGUI() const override; private: void valueChanged(int v); }; ================================================ FILE: apps/vaporgui/PTotalTimestepsDisplay.cpp ================================================ #include "PTotalTimestepsDisplay.h" #include #include "VLabel.h" PTotalTimestepsDisplay::PTotalTimestepsDisplay(VAPoR::ControlExec *ce) : PWidget("", _label = new VLabel), _ce(ce) {} void PTotalTimestepsDisplay::updateGUI() const { size_t totalTs = _ce->GetDataStatus()->GetTimeCoordinates().size(); _label->SetText("Total timesteps: " + std::to_string(totalTs)); } ================================================ FILE: apps/vaporgui/PTotalTimestepsDisplay.h ================================================ #pragma once #include "PWidget.h" namespace VAPoR { class ControlExec; } class VLabel; class PTotalTimestepsDisplay : public PWidget { VAPoR::ControlExec *_ce; VLabel * _label; public: PTotalTimestepsDisplay(VAPoR::ControlExec *ce); protected: void updateGUI() const override; }; ================================================ FILE: apps/vaporgui/PTransformWidget.cpp ================================================ #include "PTransformWidget.h" #include "VSection.h" #include "V3DInput.h" #include "VLineItem.h" #include #include using VAPoR::RenderParams; using VAPoR::Transform; PTransformWidget::PTransformWidget() : PWidget("", _group = new VGroup()) { _group->Add(new VLineItem("Translate", _translate = new V3DInput)); _group->Add(new VLineItem("Scale ", _scale = new V3DInput)); _group->Add(new VLineItem("Origin ", _origin = new V3DInput)); QObject::connect(_translate, &V3DInput::ValueChangedVec, this, &PTransformWidget::translateChanged); QObject::connect(_scale, &V3DInput::ValueChangedVec, this, &PTransformWidget::scaleChanged); QObject::connect(_origin, &V3DInput::ValueChangedVec, this, &PTransformWidget::originChanged); } void PTransformWidget::updateGUI() const { Transform *t = getParams(); _translate->SetValue(t->GetTranslations()); _scale->SetValue(t->GetScales()); _origin->SetValue(t->GetOrigin()); } void PTransformWidget::translateChanged(const std::vector xyz) { getParams()->SetTranslations(xyz); } void PTransformWidget::scaleChanged(const std::vector xyz) { getParams()->SetScales(xyz); } void PTransformWidget::originChanged(const std::vector xyz) { getParams()->SetOrigin(xyz); } PRendererTransformWidget::PRendererTransformWidget() : PWidget("", _widget = new PTransformWidget) {} void PRendererTransformWidget::updateGUI() const { RenderParams *rp = getParams(); Transform * t = rp->GetTransform(); _widget->Update(t, getParamsMgr(), getDataMgr()); } #include "PSection.h" PRendererTransformSection::PRendererTransformSection() : PWidgetWrapper(new PSection("Transform", {new PRendererTransformWidget})) {} ================================================ FILE: apps/vaporgui/PTransformWidget.h ================================================ #pragma once #include "PWidget.h" #include class V3DInput; class VGroup; namespace VAPoR { class Transform; } class PTransformWidget : public PWidget { VGroup * _group; V3DInput * _translate; V3DInput * _scale; V3DInput * _origin; public: PTransformWidget(); protected: void updateGUI() const override; private: void translateChanged(const std::vector xyz); void scaleChanged(const std::vector xyz); void originChanged(const std::vector xyz); }; class PRendererTransformWidget : public PWidget { PTransformWidget *_widget; public: PRendererTransformWidget(); protected: void updateGUI() const override; }; #include "PWidgetWrapper.h" class PRendererTransformSection : public PWidgetWrapper { public: PRendererTransformSection(); }; ================================================ FILE: apps/vaporgui/PVariableSelector.cpp ================================================ #include "PVariableSelector.h" #include #include using VAPoR::Box; using VAPoR::RenderParams; typedef VAPoR::DataMgr::VarType VarType; #define NULL_TEXT "" PVariableSelector::PVariableSelector(const std::string &tag, const std::string &label) : PStringDropdown(tag, {}, label) { setCustomBlankText(NULL_TEXT); } void PVariableSelector::updateGUI() const { int nDims = getDimensionality(); auto varNames = getDataMgr()->GetDataVarNames(nDims, (VarType)getVarType()); if (_addNull || getParamsString().empty()) varNames.insert(varNames.begin(), NULL_TEXT); SetItems(varNames); PStringDropdown::updateGUI(); } bool PVariableSelector::isShown() const { if (_onlyShowForDim > 0) return getRendererDimension() == _onlyShowForDim; return true; } int PVariableSelector::getVarType() const { if (_showParticleVars) return (int)VarType::Particle; else return (int)VarType::Scalar; } int PVariableSelector::getRendererDimension() const { return getParams()->GetRenderDim(); } int PVariableSelector::getDimensionality() const { return getRendererDimension(); } void PVariableSelector::dropdownTextChanged(std::string text) { if (_addNull && text == NULL_TEXT) text = ""; PStringDropdown::dropdownTextChanged(text); } PScalarVariableSelector::PScalarVariableSelector() : PVariableSelector(RenderParams::_variableNameTag, "Variable Name") {} PColorMapVariableSelector::PColorMapVariableSelector() : PVariableSelector(RenderParams::_colorMapVariableNameTag, "Color mapped variable") {} PHeightVariableSelector::PHeightVariableSelector() : PVariableSelector2D(RenderParams::_heightVariableNameTag, "Height variable") { AddNullOption(); OnlyShowForDim(2); } PXFieldVariableSelector::PXFieldVariableSelector() : PVariableSelector(RenderParams::_xFieldVariableNameTag, "X Field") { AddNullOption(); } PYFieldVariableSelector::PYFieldVariableSelector() : PVariableSelector(RenderParams::_yFieldVariableNameTag, "Y Field") { AddNullOption(); } PZFieldVariableSelector::PZFieldVariableSelector() : PVariableSelector(RenderParams::_zFieldVariableNameTag, "Z Field") { AddNullOption(); } ================================================ FILE: apps/vaporgui/PVariableSelector.h ================================================ #pragma once #include "PStringDropdown.h" //! \class PVariableSelector //! \author Stas Jaroszynski //! Allows the user to select variables. Automatically switches between 2D and 3D //! based on the currently selected variable. //! //! Designed to be used with a RenderParams object. class PVariableSelector : public PStringDropdown { bool _addNull = false; int _onlyShowForDim = -1; bool _showParticleVars = false; public: PVariableSelector(const std::string &tag, const std::string &label = ""); PVariableSelector *AddNullOption() { _addNull = true; return this; } PVariableSelector *OnlyShowForDim(int dim) { _onlyShowForDim = dim; return this; } PVariableSelector *ShowParticleVars() { _showParticleVars = true; return this; } protected: void updateGUI() const override; bool isShown() const override; bool requireDataMgr() const override { return true; } int getVarType() const; int getRendererDimension() const; virtual int getDimensionality() const; virtual void dropdownTextChanged(std::string text) override; }; //! \class PVariableSelector2D //! \author Stas Jaroszynski //! 2D only version of PVariableSelector //! \copydoc PVariableSelector class PVariableSelector2D : public PVariableSelector { public: using PVariableSelector::PVariableSelector; protected: int getDimensionality() const override { return 2; } }; //! \class PVariableSelector3D //! \author Stas Jaroszynski //! 3D only version of PVariableSelector //! \copydoc PVariableSelector class PVariableSelector3D : public PVariableSelector { public: using PVariableSelector::PVariableSelector; protected: int getDimensionality() const override { return 3; } }; class PScalarVariableSelector : public PVariableSelector { public: PScalarVariableSelector(); }; class PColorMapVariableSelector : public PVariableSelector { public: PColorMapVariableSelector(); }; class PHeightVariableSelector : public PVariableSelector2D { public: PHeightVariableSelector(); }; class PXFieldVariableSelector : public PVariableSelector { public: PXFieldVariableSelector(); }; class PYFieldVariableSelector : public PVariableSelector { public: PYFieldVariableSelector(); }; class PZFieldVariableSelector : public PVariableSelector { public: PZFieldVariableSelector(); }; ================================================ FILE: apps/vaporgui/PVisualizerSelector.cpp ================================================ #include "PVisualizerSelector.h" #include "VComboBox.h" #include "vapor/ParamsMgr.h" #include "vapor/GUIStateParams.h" #ifndef NDEBUG #include "vapor/STLUtils.h" #endif PVisualizerSelector::PVisualizerSelector() : PWidget("", _dropdown = new VComboBox) { connect(_dropdown, &VComboBox::ValueChanged, this, &PVisualizerSelector::dropdownTextChanged); } void PVisualizerSelector::updateGUI() const { GUIStateParams *gsp = (GUIStateParams*)getParamsMgr()->GetParams(GUIStateParams::GetClassType()); auto options = getParamsMgr()->GetVisualizerNames(); options.push_back("New Visualizer"); _dropdown->SetOptions(options); _dropdown->SetValue(gsp->GetActiveVizName()); #ifndef NDEBUG if (!STLUtils::Contains(options, gsp->GetActiveVizName())) { options.push_back("ERR: \"" + gsp->GetActiveVizName() + "\""); _dropdown->SetOptions(options); _dropdown->SetValue("ERR: \"" + gsp->GetActiveVizName() + "\""); } #endif } void PVisualizerSelector::dropdownTextChanged(std::string text) { GUIStateParams *gsp = (GUIStateParams*)getParamsMgr()->GetParams(GUIStateParams::GetClassType()); if (text == "New Visualizer") { getParamsMgr()->BeginSaveStateGroup("New Visualizer"); text = getParamsMgr()->CreateVisualizerParamsInstance(); gsp->SetActiveVizName(text); getParamsMgr()->EndSaveStateGroup(); } else { gsp->SetActiveVizName(text); } } ================================================ FILE: apps/vaporgui/PVisualizerSelector.h ================================================ #pragma once #include "PWidget.h" class VComboBox; class PVisualizerSelector : public PWidget { Q_OBJECT VComboBox *_dropdown; public: PVisualizerSelector(); protected: void updateGUI() const override; bool requireParamsMgr() const override { return true; } private: void dropdownTextChanged(std::string text); }; ================================================ FILE: apps/vaporgui/PWidget.cpp ================================================ #include "PWidget.h" #include #include #include #include #include #include PWidget::PWidget(const std::string &tag, QWidget *widget) : UWidget(widget), _tag(tag) { this->setDisabled(true); } void PWidget::Update(VAPoR::ParamsBase *params, VAPoR::ParamsMgr *paramsMgr, VAPoR::DataMgr *dataMgr) { _params = params; _paramsMgr = paramsMgr; _dataMgr = dataMgr; if (_dynamicUpdateInsideGroup) return; if (params == nullptr) { this->setDisabled(true); return; } if (requireDataMgr() && !dataMgr) VAssert(!"Data manager required but missing"); if (requireParamsMgr() && !paramsMgr) VAssert(!"Params manager required but missing"); bool paramsVisible = isShown(); if (paramsVisible && _showBasedOnParam) paramsVisible = _showBasedOnParamValue == params->GetValueLong(_showBasedOnParamTag, 0); if (paramsVisible) { setVisible(true); } else { setVisible(false); return; } bool enabled = isEnabled(); if (enabled && _enableBasedOnParam) enabled = params->GetValueLong(_enableBasedOnParamTag, 0) == _enableBasedOnParamValue; setEnabled(enabled); updateGUI(); } const std::string &PWidget::getTag() const { return _tag; } PWidget *PWidget::ShowBasedOnParam(const std::string &tag, int whenEqualTo) { _showBasedOnParam = true; _showBasedOnParamTag = tag; _showBasedOnParamValue = whenEqualTo; return this; } PWidget *PWidget::EnableBasedOnParam(const std::string &tag, int whenEqualTo) { _enableBasedOnParam = true; _enableBasedOnParamTag = tag; _enableBasedOnParamValue = whenEqualTo; return this; } PWidget *PWidget::SetTooltip(const std::string &text) { QWidget::setToolTip(QString::fromStdString(text)); return this; } VAPoR::ParamsBase *PWidget::getParams() const { return _params; } VAPoR::ParamsMgr * PWidget::getParamsMgr() const { return _paramsMgr; } VAPoR::DataMgr * PWidget::getDataMgr() const { return _dataMgr; } SettingsParams *PWidget::getSettingsParams() const { VAssert(requireParamsMgr()); return (SettingsParams *)_paramsMgr->GetParams(SettingsParams::GetClassType()); } void PWidget::setParamsDouble(double v) { dynamicUpdateFinish(); _setParamsDouble(v); } void PWidget::setParamsLong(long v) { dynamicUpdateFinish(); _setParamsLong(v); } void PWidget::setParamsString(const std::string &v) { dynamicUpdateFinish(); _setParamsString(v); } double PWidget::getParamsDouble() const { if (_usingHLI) return _getterDouble(_params); else return _params->GetValueDouble(_tag, 0.0); } long PWidget::getParamsLong() const { if (_usingHLI) return _getterLong(_params); else return _params->GetValueLong(_tag, 0); } std::string PWidget::getParamsString() const { if (_usingHLI) return _getterString(_params); else return _params->GetValueString(_tag, ""); } void PWidget::dynamicUpdateBegin() { assert(_dynamicUpdateIsOn); if (!_dynamicUpdateInsideGroup) { getParams()->BeginGroup(getTag() + " dynamic change"); _dynamicUpdateInsideGroup = true; } } void PWidget::dynamicUpdateFinish() { if (_dynamicUpdateIsOn && _dynamicUpdateInsideGroup) { getParams()->EndGroup(); _dynamicUpdateInsideGroup = false; } } void PWidget::_setParamsDouble(double v) { if (_usingHLI) _setterDouble(_params, v); else getParams()->SetValueDouble(getTag(), "", v); } void PWidget::_setParamsLong(long v) { if (_usingHLI) _setterLong(_params, v); else getParams()->SetValueLong(getTag(), "", v); } void PWidget::_setParamsString(const std::string &v) { if (_usingHLI) _setterString(_params, v); else getParams()->SetValueString(getTag(), "", v); } ================================================ FILE: apps/vaporgui/PWidget.h ================================================ #pragma once #include #include #include "UWidget.h" #include #include //! \class PWidget //! A Qt Widget that is automatically synced with the Params database. //! The Update method must be called as per Vapor's convensions //! All other public methods are self-explanitory. To see a demo and example //! of how to use these widgets, see ParamsWidgetDemo class PWidget : public UWidget { Q_OBJECT VAPoR::ParamsBase *_params = nullptr; VAPoR::ParamsMgr * _paramsMgr = nullptr; VAPoR::DataMgr * _dataMgr = nullptr; const std::string _tag; bool _showBasedOnParam = false; std::string _showBasedOnParamTag = ""; int _showBasedOnParamValue; bool _enableBasedOnParam = false; std::string _enableBasedOnParamTag = ""; int _enableBasedOnParamValue; bool _dynamicUpdateIsOn = false; bool _dynamicUpdateInsideGroup = false; bool _usingHLI = false; std::function _setterLong; std::function _getterLong; std::function _setterDouble; std::function _getterDouble; std::function _setterString; std::function _getterString; public: PWidget(const std::string &tag, QWidget *widget); //! Follows the Vapor GUI update function convention. Update the element. void Update(VAPoR::ParamsBase *params, VAPoR::ParamsMgr *paramsMgr = nullptr, VAPoR::DataMgr *dataMgr = nullptr) override; //! tag must be a key referencing a long value in the Params Database. If the associated value is equal //! to whenEqualTo, the current widget will be shown/enabled, and hidden/disabled otherwise. PWidget *ShowBasedOnParam(const std::string &tag, int whenEqualTo = true); //! @copydoc PWidget::ShowBasedOnParam() PWidget *EnableBasedOnParam(const std::string &tag, int whenEqualTo = true); //! Wrapping QWidget::setToolTip in case we want to add additional functionality such as automatic tool-tips //! without having to refactor. PWidget *SetTooltip(const std::string &text); void setToolTip(const QString &) = delete; protected: virtual void updateGUI() const = 0; virtual bool requireParamsMgr() const { return false; } virtual bool requireDataMgr() const { return false; } virtual bool isShown() const { return true; } virtual bool isEnabled() const { return true; } const std::string &getTag() const; VAPoR::ParamsBase *getParams() const; VAPoR::ParamsMgr * getParamsMgr() const; VAPoR::DataMgr * getDataMgr() const; SettingsParams * getSettingsParams() const; void setParamsDouble(double v); void setParamsLong(long v); void setParamsString(const std::string &v); double getParamsDouble() const; long getParamsLong() const; std::string getParamsString() const; private: void dynamicUpdateBegin(); void dynamicUpdateFinish(); void _setParamsDouble(double v); void _setParamsLong(long v); void _setParamsString(const std::string &v); friend class PDynamicMixin; template friend class PWidgetHLIBase; protected: template T *getParams() const { T *p = dynamic_cast(getParams()); VAssert(p); return p; } }; ================================================ FILE: apps/vaporgui/PWidgetHLI.h ================================================ #pragma once //! Creates the framework for creating Params Widgets that use the Params Database high level interface. #define CreateHLIBase(T, LT) \ template class PWidgetHLIBase { \ protected: \ typedef std::function GetterType; \ typedef std::function SetterType; \ \ public: \ PWidgetHLIBase(PWidget *w, GetterType getter, SetterType setter) \ { \ w->_usingHLI = true; \ w->_setter##LT = [setter](void *p, T v) { setter((P *)p, v); }; \ w->_getter##LT = [getter](void *p) { return getter((P *)p); }; \ } \ }; #define CreateInferredTemplateConstructor(className, T, constModifier) \ template className##HLI

*new_##className##HLI(const std::string &label, T (P::*getter)() constModifier, void (P::*setter)(T)) { return new className##HLI

(label, getter, setter); } #define CreateHLI(className, T) \ template class className##HLI final : public className, public PWidgetHLIBase { \ public: \ className##HLI(const std::string &label, typename PWidgetHLIBase::GetterType getter, typename PWidgetHLIBase::SetterType setter) \ : className("", label), PWidgetHLIBase((PWidget *)this, getter, setter) \ { \ } \ }; \ CreateInferredTemplateConstructor(className, T, ); \ CreateInferredTemplateConstructor(className, T, const); CreateHLIBase(long, Long); CreateHLIBase(bool, Long); CreateHLIBase(int, Long); CreateHLIBase(double, Double); CreateHLIBase(float, Double); CreateHLIBase(std::string, String); // // My attempt at implementing this using purely function templates and no defines. Below is pretty close. // It works but requires too much specilization code so I stopped working on it for now. // #ifdef SAVED_FOR_LATER template void AssertInheritance() { (void)static_cast((Derived *)0); } template class PWidgetHLI : public PW { typedef std::function GetterType; typedef std::function SetterType; GetterType _getter; SetterType _setter; public: PWidgetHLI(std::string label, Args... args, GetterType getter, SetterType setter) : PW("", args..., label) { printf("PWidgetHLI Constructor (%s)\n", label.c_str()); AssertInheritance(); AssertInheritance(); this->_usingHLI = true; this->_getter = getter; this->_setter = setter; } virtual long getParamsLong() const override { static_assert(std::is_convertible(), ""); // return this->_getterLong(this->getParams()); return this->_getter((P *)this->getParams()); } virtual void _setParamsLong(long v) override { static_assert(std::is_convertible(), ""); // return this->_setterLong(this->getParams(), v); this->_setter((P *)this->getParams(), v); } // template ::type>> virtual std::string getParamsString() const override { static_assert(std::is_convertible(), ""); // return this->_getterLong(this->getParams()); return this->_getter((P *)this->getParams()); } virtual void _setParamsString(const std::string &v) override { static_assert(std::is_convertible(), ""); // return this->_setterLong(this->getParams(), v); this->_setter((P *)this->getParams(), v); } }; template class PWidgetHLI2 : public PWidgetHLI { using PWidgetHLI::PWidgetHLI; }; template class PWidgetHLI2 : public PWidgetHLI { using PWidgetHLI::PWidgetHLI; virtual std::string getParamsString() const override {} }; template typename std::enable_if::value, T>::type class PWidgetHLI2 : public PWidgetHLI { virtual long getParamsLong() const override {} }; // template // class PWidgetHLI2 : public PWidgetHLI { // //}; #endif ================================================ FILE: apps/vaporgui/PWidgetWrapper.cpp ================================================ #include "PWidgetWrapper.h" PWidgetWrapper::PWidgetWrapper(PWidget *p) : PWidgetWrapper("", p) {} PWidgetWrapper::PWidgetWrapper(std::string tag, PWidget *p) : PWidget(tag, _child = p) {} void PWidgetWrapper::updateGUI() const { _child->Update(getWrappedParams(), getParamsMgr(), getDataMgr()); } VAPoR::ParamsBase *PWidgetWrapper::getWrappedParams() const { return getParams(); } ================================================ FILE: apps/vaporgui/PWidgetWrapper.h ================================================ #pragma once #include "PWidget.h" //! \class PWidgetWrapper //! \brief Provides a streamlined interface for a PWidget that wraps another PWidget. //! \author Stas Jaroszynski class PWidgetWrapper : public PWidget { PWidget *_child; public: PWidgetWrapper(PWidget *p); PWidgetWrapper(std::string tag, PWidget *p); protected: void updateGUI() const override; virtual VAPoR::ParamsBase *getWrappedParams() const; }; ================================================ FILE: apps/vaporgui/PWidgets.h ================================================ #pragma once #include "PWidgetsFwd.h" #include "PTransformWidget.h" #include "PAnnotationColorbarWidget.h" #include "PButton.h" #include "PCheckbox.h" #include "PColorSelector.h" #include "PCopyRegionWidget.h" #include "PDisplay.h" #include "PDoubleInput.h" #include "PEnumDropdown.h" #include "PFidelitySection.h" #include "PFileSelector.h" #include "PGeometrySubtab.h" #include "PGroup.h" #include "PIntegerInput.h" #include "PLabel.h" #include "PMultiVarSelector.h" #include "POrientationSelector.h" #include "PRegionSelector.h" #include "PSection.h" #include "PSliderEdit.h" #include "PStringDropdown.h" #include "PStringInput.h" #include "PTFEditor.h" #include "PShowIf.h" #include "PDimensionSelector.h" #include "PVariableSelector.h" ================================================ FILE: apps/vaporgui/PWidgetsFwd.h ================================================ #pragma once class PWidget; class PTransformWidget; class PAnnotationColorbarWidget; class PButton; class PCheckbox; class PColorSelector; class PCopyRegionWidget; class PDisplay; class PDoubleInput; class PEnumDropdown; class PFidelitySection; class PFileSelector; class PGeometrySubtab; class PGroup; class PIntegerInput; class PLabel; class PMultiVarSelector; class POrientationSelector; class PRegionSelector; class PSection; class PSliderEdit; class PStringDropdown; class PStringInput; class PTFEditor; class PVariableWidgets; class PShowIf; ================================================ FILE: apps/vaporgui/ParamsMenuItems.cpp ================================================ #include "ParamsMenuItems.h" #include #include using namespace VAPoR; // ****************************** // ParamsMenuItem // ****************************** ParamsMenuItem::ParamsMenuItem(QObject *parent, const std::string &tag, const std::string &label) : QAction(parent) { assert(!tag.empty()); _tag = tag; if (label.empty()) _label = tag; else _label = label; setText(QString::fromStdString(_label)); } // ****************************** // ParamsCheckboxMenuItem // ****************************** ParamsCheckboxMenuItem::ParamsCheckboxMenuItem(QObject *parent, const std::string &tag, const std::string &label) : ParamsMenuItem(parent, tag, label) { this->setCheckable(true); connect(this, SIGNAL(toggled(bool)), this, SLOT(wasToggled(bool))); } void ParamsCheckboxMenuItem::Update(VAPoR::ParamsBase *p) { _params = p; blockSignals(true); setChecked(p->GetValueLong(_tag, 0)); blockSignals(false); } void ParamsCheckboxMenuItem::wasToggled(bool b) { if (_params) _params->SetValueLong(_tag, _tag, b); } // ****************************** // ParamsDropdownMenuItem // ****************************** ParamsDropdownMenuItem::ParamsDropdownMenuItem(QObject *parent, const std::string &tag, const std::vector &items, const std::vector &itemValues, const std::string &labelText) : ParamsMenuItem(parent, tag, labelText) { QMenu *menu = new QMenu; for (string item : items) { QAction *action = menu->addAction(QString::fromStdString(item), this, SLOT(itemSelected())); action->setCheckable(true); _items.push_back(action); } if (!itemValues.empty()) { assert(itemValues.size() == items.size()); _itemValues = itemValues; } this->setMenu(menu); } void ParamsDropdownMenuItem::Update(VAPoR::ParamsBase *p) { _params = p; int value = p->GetValueLong(_tag, 0); _selectIndex(_getIndexForValue(value)); } void ParamsDropdownMenuItem::itemSelected() { if (!_params) return; int index = -1; for (int i = 0; i < _items.size(); i++) { if (_items[i] == sender()) { index = i; break; } } VAssert(index != -1); _selectIndex(index); _params->SetValueLong(_tag, _tag, _getValueForIndex(index)); } void ParamsDropdownMenuItem::_selectIndex(int index) { assert(index >= 0 && index < _items.size()); if (!(index >= 0 && index < _items.size())) return; for (int i = 0; i < _items.size(); i++) _items[i]->setChecked(false); _items[index]->setChecked(true); } int ParamsDropdownMenuItem::_getValueForIndex(int index) const { if (_itemValues.empty()) return index; if (index >= _itemValues.size() || index < 0) VAssert("Invalid menu index"); return _itemValues[index]; } int ParamsDropdownMenuItem::_getIndexForValue(int value) const { if (_itemValues.empty()) return value; const int N = _itemValues.size(); for (int i = 0; i < N; i++) if (_itemValues[i] == value) return i; VAssert("Invalid params value"); return -1; } ================================================ FILE: apps/vaporgui/ParamsMenuItems.h ================================================ #pragma once #include #include #include namespace VAPoR { class ParamsBase; } // ****************************** // ParamsMenuItem // ****************************** //! \class ParamsMenuItem //! Provides the same functionality as ParamsWidget except inside of a QMenu class ParamsMenuItem : public QAction { Q_OBJECT public: ParamsMenuItem(QObject *parent, const std::string &tag, const std::string &label = ""); virtual void Update(VAPoR::ParamsBase *p) = 0; protected: VAPoR::ParamsBase *_params = nullptr; std::string _tag; std::string _label; }; // ****************************** // ParamsCheckboxMenuItem // ****************************** class ParamsCheckboxMenuItem : public ParamsMenuItem { Q_OBJECT public: ParamsCheckboxMenuItem(QObject *parent, const std::string &tag, const std::string &label = ""); void Update(VAPoR::ParamsBase *p); private slots: void wasToggled(bool b); }; // ****************************** // ParamsDropdownMenuItem // ****************************** class ParamsDropdownMenuItem : public ParamsMenuItem { Q_OBJECT std::vector _itemValues; std::vector _items; public: ParamsDropdownMenuItem(QObject *parent, const std::string &tag, const std::vector &items, const std::vector &itemValues = {}, const std::string &label = ""); void Update(VAPoR::ParamsBase *p); private: void _selectIndex(int index); int _getValueForIndex(int index) const; int _getIndexForValue(int value) const; private slots: void itemSelected(); }; ================================================ FILE: apps/vaporgui/ParamsUpdatable.cpp ================================================ #include "ParamsUpdatable.h" ================================================ FILE: apps/vaporgui/ParamsUpdatable.h ================================================ #pragma once namespace VAPoR { class ParamsBase; class ParamsMgr; class DataMgr; } // namespace VAPoR //! \class ParamsUpdatable //! \brief Provides an interface that standardizes objects that support params updates. //! \author Stas Jaroszynski class ParamsUpdatable { public: virtual void Update(VAPoR::ParamsBase *params, VAPoR::ParamsMgr *paramsMgr = nullptr, VAPoR::DataMgr *dataMgr = nullptr) = 0; }; ================================================ FILE: apps/vaporgui/ParamsWidgetDemo.cpp ================================================ #include "ParamsWidgetDemo.h" #include #include #include #include #include #include "PGroup.h" #include "PSection.h" #include "PCheckbox.h" #include "PIntegerInput.h" #include "PDoubleInput.h" #include "PSliderEdit.h" #include "PFileSelector.h" #include "PDisplay.h" #include "PColorSelector.h" #include "PEnumDropdown.h" #include "PStringDropdown.h" #include "PFileSelectorHLI.h" #include "PEnumDropdownHLI.h" ParamsWidgetDemo::ParamsWidgetDemo() { setWindowTitle("Params Widget Demo"); setLayout(new QVBoxLayout); layout()->addWidget(pg = new PGroup); PSection *section; section = new PSection("Numbers"); section->Add(new PIntegerInput("demo_int", "PIntegerInput")); section->Add(new PDoubleInput("demo_double", "PDoubleInput")); section->Add((new PIntegerSliderEdit("demo_int", "PIntegerSliderEdit"))->SetRange(0, 100)); section->Add((new PDoubleSliderEdit("demo_double", "Dynamic Double"))->EnableDynamicUpdate()); pg->Add(section); section = new PSection("Files"); section->Add(new PFileOpenSelector("demo_path", "Open File")); section->Add(new PFileSaveSelector("demo_path", "Save File")); section->Add(new PDirectorySelector("demo_path", "Select Directory")); pg->Add(section); section = new PSection("Show or Enable"); section->Add(new PCheckbox("demo_bool", "Enable Dropdown")); section->Add((new PEnumDropdown("demo_drop", {"Double Input", "Color Input"}, {}, "Show Widget"))->EnableBasedOnParam("demo_bool")); section->Add((new PDoubleSliderEdit("demo_double", "Double"))->ShowBasedOnParam("demo_drop", 0)); section->Add((new PColorSelector("demo_color", "Color"))->ShowBasedOnParam("demo_drop", 1)); pg->Add(section); section = new PSection("Other"); section->Add(new PColorSelector("demo_color", "Color")); section->Add(new PStringDropdown("demo_path", {"One", "Two", "Three"}, "String Dropdown")); section->Add(new PStringDropdown("demo_var", {"Automatically", "presents", "2D or 3D", "Variables", "----------", "Only works for", "RenderParams", "so cannot", "demo"}, "PVariableSelector")); section->Add((new PCheckbox("demo_bool", "Tooltips"))->SetTooltip("This is a tooltip")); pg->Add(section); section = new PSection("Labels"); section->Add(new PIntegerDisplay("demo_int", "PIntegerDisplay")); section->Add(new PDoubleDisplay("demo_double", "PDoubleDisplay")); section->Add(new PStringDisplay("demo_path", "PStringDisplay")); section->Add(new PBooleanDisplay("demo_bool", "PBooleanDisplay")); pg->Add(section); section = new PSection("High Level Interface"); section->Add(new_PDirectorySelectorHLI("Image Output Dir", &GUIStateParams::GetCurrentImagePath, &GUIStateParams::SetCurrentImagePath)); section->Add(new PEnumDropdownHLI("Flow Dimensions", {"2", "3"}, {2, 3}, &GUIStateParams::GetFlowDimensionality, &GUIStateParams::SetFlowDimensionality)); pg->Add(section); } void ParamsWidgetDemo::Update(VAPoR::ParamsBase *params, VAPoR::ParamsMgr *paramsMgr, VAPoR::DataMgr *dataMgr) { pg->Update(params, paramsMgr); } ================================================ FILE: apps/vaporgui/ParamsWidgetDemo.h ================================================ #pragma once #include #include "ParamsUpdatable.h" namespace VAPoR { class ParamsBase; class ParamsMgr; class DataMgr; } // namespace VAPoR class PGroup; //! \class ParamsWidgetDemo //! Shows a demo kitchen sink for Params Widgets //! To view, from the menu bar press Developer > Show PWidget Demo class ParamsWidgetDemo : public QWidget, public ParamsUpdatable { Q_OBJECT PGroup *pg; public: ParamsWidgetDemo(); void Update(VAPoR::ParamsBase *params, VAPoR::ParamsMgr *paramsMgr = nullptr, VAPoR::DataMgr *dataMgr = nullptr); }; ================================================ FILE: apps/vaporgui/ParticleEventRouter.cpp ================================================ #include "ParticleEventRouter.h" #include "vapor/BarbParams.h" #include "PWidgets.h" #include "PConstantColorWidget.h" #include "PCheckbox.h" using namespace VAPoR; static RenderEventRouterRegistrar registrar(ParticleEventRouter::GetClassType()); struct PParticleRadiusVariableSelector : public PVariableSelector { PParticleRadiusVariableSelector() : PVariableSelector(ParticleParams::RenderRadiusVariableTag, "Particle Radius Scalar") { AddNullOption(); ShowParticleVars(); } }; ParticleEventRouter::ParticleEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, BarbParams::GetClassType()) { // clang-format off AddVariablesSubtab(new PGroup({ new PSection("Variable Selection", { (new PScalarVariableSelector)->ShowParticleVars(), (new PXFieldVariableSelector)->ShowParticleVars(), (new PYFieldVariableSelector)->ShowParticleVars(), (new PZFieldVariableSelector)->ShowParticleVars(), (new PParticleRadiusVariableSelector()), }), new PSection("Data Fidelity", { (new PIntegerInput(ParticleParams::StrideTag, "Stride"))->SetRange(1, 1000) }), })); AddAppearanceSubtab(new PGroup({ new PTFEditor, new PSection("Particles", { (new PDoubleSliderEdit(ParticleParams::RenderRadiusScalarTag, "Radius"))->SetRange(0.5, 25)->AllowUserRange(true)->EnableDynamicUpdate()->EnableBasedOnParam(ParticleParams::RenderLegacyTag, false), (new PParticleRadiusVariableSelector()), // (new PShowIf(ParticleParams::RenderRadiusVariableTag))->Not()->Equals("")->Then({ // (new PDoubleSliderEdit(ParticleParams::RenderRadiusVariableStrengthTag, "Radius Variable Strength"))->SetRange(0.001, 1)->AllowUserRange(true)->EnableDynamicUpdate() // }), (new PButton("Recalculate Base Radius", [](ParamsBase *p){ p->SetValueLong(ParticleParams::RecalculateRadiusBaseRequestTag, "", true); })), new PCheckbox(ParticleParams::ShowDirectionTag, "Show direction"), (new PDoubleSliderEdit(ParticleParams::DirectionScaleTag, "Length scale"))->SetRange(0.0001, 10)->AllowUserRange(true)->EnableDynamicUpdate()->EnableBasedOnParam(ParticleParams::ShowDirectionTag), (new PXFieldVariableSelector)->ShowParticleVars()->EnableBasedOnParam(ParticleParams::ShowDirectionTag), (new PYFieldVariableSelector)->ShowParticleVars()->EnableBasedOnParam(ParticleParams::ShowDirectionTag), (new PZFieldVariableSelector)->ShowParticleVars()->EnableBasedOnParam(ParticleParams::ShowDirectionTag), }), new PSection("Lighting", { (new PCheckbox(ParticleParams::LightingEnabledTag,"Enable Lighting"))->EnableBasedOnParam(ParticleParams::RenderLegacyTag, false), (new PDoubleSliderEdit(ParticleParams::PhongAmbientTag, "Ambient" ))->EnableDynamicUpdate()->EnableBasedOnParam(ParticleParams::RenderLegacyTag, false), (new PDoubleSliderEdit(ParticleParams::PhongDiffuseTag, "Diffuse" ))->EnableDynamicUpdate()->EnableBasedOnParam(ParticleParams::RenderLegacyTag, false), (new PDoubleSliderEdit(ParticleParams::PhongSpecularTag, "Specular" ))->EnableDynamicUpdate()->EnableBasedOnParam(ParticleParams::RenderLegacyTag, false), (new PDoubleSliderEdit(ParticleParams::PhongShininessTag, "Shininess"))->EnableDynamicUpdate()->EnableBasedOnParam(ParticleParams::RenderLegacyTag, false) }), new PSection("Legacy code", { new PCheckbox(ParticleParams::RenderLegacyTag,"Enable legacy renderer") }), })); AddGeometrySubtab(new PGeometrySubtab); AddColorbarSubtab(new PAnnotationColorbarWidget); // clang-format on } string ParticleEventRouter::_getDescription() const { return ("Render particle data"); } ================================================ FILE: apps/vaporgui/ParticleEventRouter.h ================================================ #pragma once #include "RenderEventRouterGUI.h" #include "vapor/ParticleRenderer.h" //! \class ParticleEventRouter //! \ingroup Public_GUI //! \brief Particle renderer GUI //! \author Stas Jaroszynski class ParticleEventRouter : public RenderEventRouterGUI { public: ParticleEventRouter(QWidget *parent, VAPoR::ControlExec *ce); static string GetClassType() { return VAPoR::ParticleRenderer::GetClassType(); } string GetType() const { return GetClassType(); } bool Supports2DVariables() const { return false; } bool Supports3DVariables() const { return false; } bool SupportsParticleVariables() const { return true; } protected: virtual string _getDescription() const; virtual string _getSmallIconImagePath() const { return "Particles_small.png"; } virtual string _getIconImagePath() const { return "Particles.png"; } }; ================================================ FILE: apps/vaporgui/Plot.cpp ================================================ //************************************************************************ // * // Copyright (C) 2016 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // Author: Samuel Li // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: January 2018 // #include #include #include #include #include #include #include "ErrorReporter.h" #include "Plot.h" #include "Flags.h" #include "VPushButton.h" // Constructor Plot::Plot(VAPoR::DataStatus *status, VAPoR::ParamsMgr *manager, QWidget *parent) : QDialog(parent), Ui_PlotWindow() { _dataStatus = status; _paramsMgr = manager; // Get the active dataset name std::string currentDatasetName; std::vector dmNames = _dataStatus->GetDataMgrNames(); if (dmNames.empty()) MSG_ERR("No data set chosen yet. Plot shouldn't run into this condition."); else { GUIStateParams *guiParams = dynamic_cast(_paramsMgr->GetParams(GUIStateParams::GetClassType())); currentDatasetName = guiParams->GetPlotDatasetName(); if (currentDatasetName == "" || currentDatasetName == "NULL") // not initialized yet { currentDatasetName = dmNames[0]; guiParams->SetPlotDatasetName(currentDatasetName); } } // Do some static QT stuff setupUi(this); setWindowTitle("Plot Utility"); myFidelityWidget->Reinit((VariableFlags)AUXILIARY); spaceTimeTab->setCurrentIndex(0); // default to load space tab timeTabSinglePoint->SetMainLabel(QString("Select one data point in space:")); timeTabTimeRange->SetMainLabel(QString("Select the minimum and maximum time steps:")); timeTabTimeRange->SetIntType(true); spaceTabP1->SetMainLabel(QString("Select spatial location of Point 1")); spaceTabP2->SetMainLabel(QString("Select spatial location of Point 2")); spaceTabTimeSelector->SetLabel(QString("T")); spaceTabTimeSelector->SetIntType(true); // set widget extents _setInitialExtents(); _validator = new QIntValidator(numOfSamplesLineEdit); numOfSamplesLineEdit->setValidator(_validator); // Connect signals with slots connect(newVarCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_newVarChanged(int))); connect(removeVarCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_removeVarChanged(int))); connect(dataMgrCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_dataSourceChanged(int))); connect(timeTabSinglePoint, SIGNAL(pointUpdated()), this, SLOT(_timeModePointChanged())); connect(timeTabTimeRange, SIGNAL(rangeChanged()), this, SLOT(_timeModeT1T2Changed())); connect(spaceTabTimeSelector, SIGNAL(valueChanged(int)), this, SLOT(_spaceModeTimeChanged(int))); connect(spaceTabP1, SIGNAL(pointUpdated()), this, SLOT(_spaceModeP1Changed())); connect(spaceTabP2, SIGNAL(pointUpdated()), this, SLOT(_spaceModeP2Changed())); connect(spaceTabPlotButton, SIGNAL(clicked()), this, SLOT(_spaceTabPlotClicked())); connect(timeTabPlotButton, SIGNAL(clicked()), this, SLOT(_timeTabPlotClicked())); connect(numOfSamplesLineEdit, SIGNAL(editingFinished()), this, SLOT(_numberOfSamplesChanged())); connect(xlock, SIGNAL(stateChanged(int)), this, SLOT(_axisLocksChanged(int))); connect(ylock, SIGNAL(stateChanged(int)), this, SLOT(_axisLocksChanged(int))); connect(zlock, SIGNAL(stateChanged(int)), this, SLOT(_axisLocksChanged(int))); // Create widgets for the plot window _plotDialog = new QDialog(this); _plotLabel = new QLabel(this); _plotLabel->setText(QString(" Plot is on disk: ")); _plotPathEdit = new QLineEdit(this); _plotPathEdit->setReadOnly(true); _plotPathEdit->setTextMargins(6, 0, 6, 0); _plotImageLabel = new QLabel(this); _plotLayout = new QVBoxLayout(); _plotDialog->setLayout(_plotLayout); _plotLayout->addWidget(_plotLabel); _plotLayout->addWidget(_plotPathEdit); _plotLayout->addWidget(_plotImageLabel); VPushButton *close = new VPushButton("Close Window"); connect(close, &VPushButton::ButtonClicked, this, &QDialog::accept); layout()->addWidget(close); // Put the current window on top show(); raise(); activateWindow(); } // Destructor Plot::~Plot() { _dataStatus = NULL; _paramsMgr = NULL; } void Plot::Update() { // Doesn't do anything if the current window isn't visible. if (!(this->isVisible())) return; // Initialize pointers std::vector dmNames = _dataStatus->GetDataMgrNames(); if (dmNames.empty()) { this->close(); return; } GUIStateParams *guiParams = dynamic_cast(_paramsMgr->GetParams(GUIStateParams::GetClassType())); std::string currentDatasetName = guiParams->GetPlotDatasetName(); VAssert(currentDatasetName != "" && currentDatasetName != "NULL"); int currentIdx = -1; for (int i = 0; i < dmNames.size(); i++) if (currentDatasetName == dmNames[i]) { currentIdx = i; break; } if (currentIdx == -1) // currentDatasetName is closed!!! { currentDatasetName = dmNames[0]; currentIdx = 0; guiParams->SetPlotDatasetName(currentDatasetName); _setInitialExtents(); } VAPoR::DataMgr * currentDmgr = _dataStatus->GetDataMgr(currentDatasetName); VAPoR::PlotParams * plotParams = dynamic_cast(_paramsMgr->GetAppRenderParams(currentDatasetName, VAPoR::PlotParams::GetClassType())); std::vector enabledVars = plotParams->GetAuxVariableNames(); // Update DataMgrCombo dataMgrCombo->blockSignals(true); dataMgrCombo->clear(); for (int i = 0; i < dmNames.size(); i++) dataMgrCombo->addItem(QString::fromStdString(dmNames[i])); dataMgrCombo->setCurrentIndex(currentIdx); dataMgrCombo->blockSignals(false); // Update "Add a Variable" std::vector availVars = currentDmgr->GetDataVarNames(); for (int i = 0; i < enabledVars.size(); i++) for (int rmIdx = 0; rmIdx < availVars.size(); rmIdx++) if (availVars[rmIdx] == enabledVars[i]) { availVars.erase(availVars.begin() + rmIdx); break; } std::sort(availVars.begin(), availVars.end()); newVarCombo->blockSignals(true); newVarCombo->clear(); newVarCombo->blockSignals(false); newVarCombo->addItem(QString("Add a Variable")); for (std::vector::iterator it = availVars.begin(); it != availVars.end(); ++it) newVarCombo->addItem(QString::fromStdString(*it)); newVarCombo->setCurrentIndex(0); // Update "Remove a Variable" std::sort(enabledVars.begin(), enabledVars.end()); removeVarCombo->blockSignals(true); removeVarCombo->clear(); removeVarCombo->blockSignals(false); removeVarCombo->addItem(QString("Remove a Variable")); for (int i = 0; i < enabledVars.size(); i++) removeVarCombo->addItem(QString::fromStdString(enabledVars[i])); removeVarCombo->setCurrentIndex(0); // Update "Variable Table" variablesTable->clear(); // This also deletes the items properly. QStringList header; // Start from the header header << "Enabled Variables"; variablesTable->setColumnCount(header.size()); variablesTable->setHorizontalHeaderLabels(header); variablesTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); variablesTable->horizontalHeader()->setFixedHeight(30); variablesTable->verticalHeader()->setFixedWidth(30); variablesTable->setRowCount(enabledVars.size()); // Then work on the cells for (int row = 0; row < enabledVars.size(); row++) { QTableWidgetItem *item = new QTableWidgetItem(QString::fromStdString(enabledVars[row])); item->setFlags(Qt::NoItemFlags); item->setTextAlignment(Qt::AlignCenter); variablesTable->setItem(row, 0, item); } variablesTable->update(); variablesTable->repaint(); variablesTable->viewport()->update(); // If there are variables selected, update the extents based on the selected variables. if (enabledVars.size() > 0) { std::vector min, max; std::vector axes; // First update the space tab min = plotParams->GetMinExtents(); max = plotParams->GetMaxExtents(); size_t dimensionality = min.size(); spaceTabP1->SetDimensionality(dimensionality); spaceTabP2->SetDimensionality(dimensionality); spaceTabP1->SetExtents(min, max); spaceTabP2->SetExtents(min, max); std::vector pt = plotParams->GetPoint1(); if (pt.size() == 0) // 1st time open Plot pt = min; else if (pt.size() == 2 && dimensionality == 3) pt.push_back(min.at(2)); else if (pt.size() == 3 && dimensionality == 2) pt.pop_back(); spaceTabP1->SetValue(pt); plotParams->SetPoint1(pt); pt = plotParams->GetPoint2(); if (pt.size() == 0) pt = max; else if (pt.size() == 2 && dimensionality == 3) pt.push_back(max.at(2)); else if (pt.size() == 3 && dimensionality == 2) pt.pop_back(); spaceTabP2->SetValue(pt); plotParams->SetPoint2(pt); // Second update the time tab timeTabSinglePoint->SetDimensionality(dimensionality); timeTabSinglePoint->SetExtents(min, max); pt = plotParams->GetSinglePoint(); if (pt.size() == 0) { for (size_t i = 0; i < min.size(); i++) pt.push_back(min.at(i) + 0.5 * (max.at(i) - min.at(i))); } else if (pt.size() == 2 && dimensionality == 3) pt.push_back(min.at(2) + 0.5 * (max.at(2) - min.at(2))); else if (pt.size() == 3 && dimensionality == 2) pt.pop_back(); timeTabSinglePoint->SetValue(pt); plotParams->SetSinglePoint(pt); } // Update LOD, Refinement myFidelityWidget->Update(currentDmgr, _paramsMgr, plotParams); // Update time dimension spaceTabTimeSelector->SetValue(plotParams->GetCurrentTimestep()); std::vector range = plotParams->GetMinMaxTS(); VAssert(range.size() > 0); timeTabTimeRange->SetValue((double)range[0], (double)range[1]); // Update number of samples numOfSamplesLineEdit->setText(QString::number(plotParams->GetNumOfSamples(), 10)); // Update axis locks std::vector locks = plotParams->GetAxisLocks(); xlock->setChecked(locks[0]); ylock->setChecked(locks[1]); zlock->setChecked(locks[2]); if (spaceTabP1->GetDimensionality() == 3) zlock->setVisible(true); else zlock->setVisible(false); _spaceModeP1Changed(); // if any axis is locked, this function syncs them } void Plot::_newVarChanged(int index) { if (index == 0) // not selecting any variable return; std::string varName = newVarCombo->itemText(index).toStdString(); VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams(); VAPoR::DataMgr * dataMgr = this->_getCurrentDataMgr(); int refinementLevel = plotParams->GetRefinementLevel(); int compressLevel = plotParams->GetCompressionLevel(); int currentTS = (int)plotParams->GetCurrentTimestep(); // Test if the selected variable available at the specific time step, // compression level, etc. if (!dataMgr->VariableExists(currentTS, varName, refinementLevel, compressLevel)) { MSG_WARN("Selected variable not available at this settings!"); newVarCombo->setCurrentIndex(0); return; } else // Add this variable to parameter { std::vector vars = plotParams->GetAuxVariableNames(); vars.push_back(varName); plotParams->SetAuxVariableNames(vars); _updateExtents(); } } void Plot::_removeVarChanged(int index) { if (index == 0) return; std::string varName = removeVarCombo->itemText(index).toStdString(); VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams(); // Remove this variable from parameter std::vector vars = plotParams->GetAuxVariableNames(); int rmIdx = -1; for (int i = 0; i < vars.size(); i++) if (vars[i] == varName) { rmIdx = i; break; } VAssert(rmIdx != -1); vars.erase(vars.begin() + rmIdx); plotParams->SetAuxVariableNames(vars); } void Plot::_spaceModeP1Changed() { std::vector pt, pt2; spaceTabP1->GetCurrentPoint(pt); VAssert(pt.size() == 2 || pt.size() == 3); VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams(); plotParams->SetPoint1(pt); spaceTabP2->GetCurrentPoint(pt2); std::vector locks = plotParams->GetAxisLocks(); bool lockFlag = false; if (locks[0]) { pt2[0] = pt[0]; lockFlag = true; } if (locks[1]) { pt2[1] = pt[1]; lockFlag = true; } if (spaceTabP1->GetDimensionality() == 3 && locks[2]) { pt2[2] = pt[2]; lockFlag = true; } if (lockFlag) { spaceTabP2->SetValue(pt2); plotParams->SetPoint2(pt2); } } void Plot::_spaceModeP2Changed() { std::vector pt, pt1; spaceTabP2->GetCurrentPoint(pt); VAssert(pt.size() == 2 || pt.size() == 3); VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams(); plotParams->SetPoint2(pt); spaceTabP1->GetCurrentPoint(pt1); std::vector locks = plotParams->GetAxisLocks(); bool lockFlag = false; if (locks[0]) { pt1[0] = pt[0]; lockFlag = true; } if (locks[1]) { pt1[1] = pt[1]; lockFlag = true; } if (spaceTabP2->GetDimensionality() == 3 && locks[2]) { pt1[2] = pt[2]; lockFlag = true; } if (lockFlag) { spaceTabP1->SetValue(pt1); plotParams->SetPoint1(pt1); } } void Plot::_spaceModeTimeChanged(int val) { VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams(); plotParams->SetCurrentTimestep(val); std::string emptyStr; _updateExtents(); } void Plot::_timeModePointChanged() { VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams(); std::vector currentPoint; timeTabSinglePoint->GetCurrentPoint(currentPoint); VAssert(currentPoint.size() == 2 || currentPoint.size() == 3); plotParams->SetSinglePoint(currentPoint); } void Plot::_timeModeT1T2Changed() { VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams(); double smallVal, bigVal; timeTabTimeRange->GetValue(smallVal, bigVal); std::vector rangeInt; rangeInt.push_back((long int)smallVal); rangeInt.push_back((long int)bigVal); plotParams->SetMinMaxTS(rangeInt); std::string emptyStr; _updateExtents(); } void Plot::_dataSourceChanged(int index) { std::string newDataSourceName = dataMgrCombo->itemText(index).toStdString(); // Inform GUIStateParams the change of data source. GUIStateParams *guiParams = dynamic_cast(_paramsMgr->GetParams(GUIStateParams::GetClassType())); guiParams->SetPlotDatasetName(newDataSourceName); _setInitialExtents(); } VAPoR::PlotParams *Plot::_getCurrentPlotParams() const { GUIStateParams *guiParams = dynamic_cast(_paramsMgr->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetPlotDatasetName(); return (dynamic_cast(_paramsMgr->GetAppRenderParams(dsName, VAPoR::PlotParams::GetClassType()))); } VAPoR::DataMgr *Plot::_getCurrentDataMgr() const { GUIStateParams *guiParams = dynamic_cast(_paramsMgr->GetParams(GUIStateParams::GetClassType())); std::string currentDatasetName = guiParams->GetPlotDatasetName(); VAssert(currentDatasetName != "" && currentDatasetName != "NULL"); return (_dataStatus->GetDataMgr(currentDatasetName)); } void Plot::_setInitialExtents() { // Set spatial extents VAPoR::CoordType minExt, maxExt; _dataStatus->GetActiveExtents(_paramsMgr, 0, minExt, maxExt); std::vector minActiveExtents = {minExt[0], minExt[1], minExt[2]}; std::vector maxActiveExtents = {maxExt[0], maxExt[1], maxExt[2]}; int dimensionality = 3; _getCurrentPlotParams()->SetMinExtents(minActiveExtents); _getCurrentPlotParams()->SetMaxExtents(maxActiveExtents); int numOfTimeSteps = this->_getCurrentDataMgr()->GetNumTimeSteps(); std::vector rangeInt; rangeInt.push_back((long int)0); rangeInt.push_back((long int)(numOfTimeSteps - 1)); _getCurrentPlotParams()->SetMinMaxTS(rangeInt); // Set space tab extents spaceTabP1->SetDimensionality(dimensionality); spaceTabP2->SetDimensionality(dimensionality); spaceTabP1->SetExtents(minActiveExtents, maxActiveExtents); spaceTabP2->SetExtents(minActiveExtents, maxActiveExtents); spaceTabP1->SetValue(minActiveExtents); spaceTabP2->SetValue(maxActiveExtents); spaceTabTimeSelector->SetExtents(0.0, (double)(numOfTimeSteps - 1)); spaceTabTimeSelector->SetValue(0.0); // Set time tab extents timeTabSinglePoint->SetDimensionality(dimensionality); timeTabSinglePoint->SetExtents(minActiveExtents, maxActiveExtents); timeTabSinglePoint->SetValue(minActiveExtents); timeTabTimeRange->SetExtents(0.0, (double)(numOfTimeSteps - 1)); } void Plot::_spaceTabPlotClicked() { VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams(); VAPoR::DataMgr * dataMgr = this->_getCurrentDataMgr(); int refinementLevel = plotParams->GetRefinementLevel(); int compressLevel = plotParams->GetCompressionLevel(); int currentTS = (int)plotParams->GetCurrentTimestep(); std::vector point1 = plotParams->GetPoint1(); std::vector point2 = plotParams->GetPoint2(); std::vector enabledVars = plotParams->GetAuxVariableNames(); int numOfSamples = plotParams->GetNumOfSamples(); // Do nothing if no variable is enabled if (enabledVars.size() == 0) return; std::vector p1p2span; for (int i = 0; i < point1.size(); i++) p1p2span.push_back(point2[i] - point1[i]); std::vector> sequences; for (int v = 0; v < enabledVars.size(); v++) { std::vector seq(numOfSamples, 0.0); VAPoR::Grid * grid = dataMgr->GetVariable(currentTS, enabledVars[v], refinementLevel, compressLevel); if (grid) { float missingVal = grid->GetMissingValue(); for (int i = 0; i < numOfSamples; i++) { std::vector sample; if (i == 0) sample = point1; else if (i == numOfSamples - 1) sample = point2; else { for (int j = 0; j < point1.size(); j++) sample.push_back((double)i / (double)(numOfSamples - 1) * p1p2span[j] + point1[j]); } float fieldVal = grid->GetValue(sample); if (fieldVal == missingVal) seq[i] = std::nanf("1"); else seq[i] = fieldVal; } sequences.push_back(seq); } delete grid; } // Decide X label and values std::string xLabel = _getXLabel(); std::vector xValues; if (!xLabel.empty()) // If xLabel isn't empty, we calculate the actual distances { float dist = 0.0f; for (int i = 0; i < p1p2span.size(); i++) dist += p1p2span[i] * p1p2span[i]; dist = std::sqrt(dist); float stepsize = dist / (float)(numOfSamples - 1); for (int i = 0; i < numOfSamples; i++) xValues.push_back((float)i * stepsize); } else { for (int i = 0; i < numOfSamples; i++) xValues.push_back((float)i); } // Decide Y label and values std::string yLabel = _getYLabel(); // Call python routines. QTemporaryFile file; if (file.open()) { QString filename = file.fileName() + QString(".png"); _invokePython(filename, enabledVars, sequences, xValues, xLabel, yLabel); QImage plot(filename); _plotPathEdit->setText(filename); _plotImageLabel->setPixmap(QPixmap::fromImage(plot)); _plotDialog->show(); _plotDialog->raise(); _plotDialog->activateWindow(); file.close(); } else MSG_ERR("QT temporary file not able to open"); } void Plot::_timeTabPlotClicked() { VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams(); VAPoR::DataMgr * dataMgr = this->_getCurrentDataMgr(); int refinementLevel = plotParams->GetRefinementLevel(); int compressLevel = plotParams->GetCompressionLevel(); std::vector singlePt = plotParams->GetSinglePoint(); std::vector minMaxTS = plotParams->GetMinMaxTS(); std::vector enabledVars = plotParams->GetAuxVariableNames(); // Do nothing if no variable is enabled if (enabledVars.size() == 0) return; std::vector> sequences; for (int v = 0; v < enabledVars.size(); v++) { std::vector seq; for (int t = minMaxTS[0]; t <= minMaxTS[1]; t++) { VAPoR::Grid *grid = dataMgr->GetVariable(t, enabledVars[v], refinementLevel, compressLevel); if (grid) { float fieldVal = grid->GetValue(singlePt); if (fieldVal != grid->GetMissingValue()) seq.push_back(fieldVal); else seq.push_back(std::nanf("1")); } delete grid; } sequences.push_back(seq); } std::vector xValues; if (minMaxTS.size() > 0) for (int i = minMaxTS[0]; i <= minMaxTS[1]; i++) xValues.push_back((float)i); // Decide Y label and values std::string yLabel = _getYLabel(); // Call python routines. QTemporaryFile file; if (file.open()) { QString filename = file.fileName() + QString(".png"); const std::string xLabel = "Time Steps"; _invokePython(filename, enabledVars, sequences, xValues, xLabel, yLabel); QImage plot(filename); _plotPathEdit->setText(filename); _plotImageLabel->setPixmap(QPixmap::fromImage(plot)); _plotDialog->show(); _plotDialog->raise(); _plotDialog->activateWindow(); file.close(); } else MSG_ERR("QT temporary file not able to open"); } void Plot::_invokePython(const QString &outFile, const std::vector &enabledVars, const std::vector> &sequences, const std::vector &xValues, const std::string &xLabel, const std::string &yLabel) { /* Adopted from documentation: https://docs.python.org/2/extending/embedding.html */ PyObject *pName = NULL; PyObject *pModule = NULL; PyObject *pFunc = NULL; PyObject *pArgs = NULL; PyObject *pValue = NULL; Wasp::MyPython::Instance()->Initialize(); VAssert(Py_IsInitialized()); pName = PyUnicode_FromString("plot"); pModule = PyImport_Import(pName); if (pModule == NULL) { MSG_ERR("pModule NULL!!"); PyErr_Print(); return; } pFunc = PyObject_GetAttrString(pModule, "plotSequences"); if (pFunc && PyCallable_Check(pFunc)) { pArgs = PyTuple_New(6); // Set the 1st argument: output file name pValue = PyUnicode_FromString(outFile.toLocal8Bit()); PyTuple_SetItem(pArgs, 0, pValue); // pValue is stolen! // Set the 2nd argument: variable names PyObject *pListOfStrings = PyList_New(enabledVars.size()); VAssert(pListOfStrings); for (int i = 0; i < enabledVars.size(); i++) { pValue = PyUnicode_FromString(enabledVars[i].c_str()); int rt = PyList_SetItem(pListOfStrings, i, pValue); // pValue is stolen! VAssert(rt == 0); } PyTuple_SetItem(pArgs, 1, pListOfStrings); // pListOfStrings is stolen! // Set the 3rd argument: sequence values (Y axis) PyObject *pListOfLists = PyList_New(sequences.size()); VAssert(pListOfLists); for (int i = 0; i < sequences.size(); i++) // for each sequence { PyObject *pList = PyList_New(sequences[i].size()); VAssert(pList); for (int j = 0; j < sequences[i].size(); j++) { int rt = PyList_SetItem(pList, j, PyFloat_FromDouble(sequences[i][j])); VAssert(rt == 0); } PyList_SetItem(pListOfLists, i, pList); } PyTuple_SetItem(pArgs, 2, pListOfLists); // Set the 4th argument: X axis values PyObject *pListOfFloats = PyList_New(xValues.size()); VAssert(pListOfFloats); for (int i = 0; i < xValues.size(); i++) { int rt = PyList_SetItem(pListOfFloats, i, PyFloat_FromDouble(xValues[i])); VAssert(rt == 0); } PyTuple_SetItem(pArgs, 3, pListOfFloats); // Set the 5th argument: X axis label pValue = PyUnicode_FromString(xLabel.c_str()); PyTuple_SetItem(pArgs, 4, pValue); // Set the 6th argument: Y axis label pValue = PyUnicode_FromString(yLabel.c_str()); PyTuple_SetItem(pArgs, 5, pValue); pValue = PyObject_CallObject(pFunc, pArgs); if (pValue == NULL) { MSG_ERR("pFunc failed to execute"); PyErr_Print(); } } else { MSG_ERR("pFunc NULL"); PyErr_Print(); } Py_XDECREF(pName); Py_XDECREF(pArgs); Py_XDECREF(pValue); Py_XDECREF(pFunc); Py_XDECREF(pModule); } void Plot::_numberOfSamplesChanged() { long val = numOfSamplesLineEdit->text().toLong(); long minSamples = 50; if (val < minSamples) { val = minSamples; numOfSamplesLineEdit->setText(QString::number(val, 10)); } VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams(); plotParams->SetNumOfSamples(val); } std::string Plot::_getXLabel() { VAPoR::PlotParams * plotParams = this->_getCurrentPlotParams(); VAPoR::DataMgr * dataMgr = this->_getCurrentDataMgr(); std::vector enabledVars = plotParams->GetAuxVariableNames(); std::vector units; for (int i = 0; i < enabledVars.size(); i++) { VAPoR::DC::DataVar dataVar; dataMgr->GetDataVarInfo(enabledVars[i], dataVar); std::string meshName = dataVar.GetMeshName(); VAPoR::DC::Mesh mesh; dataMgr->GetMesh(meshName, mesh); std::vector coordVarNames = mesh.GetCoordVars(); for (int j = 0; j < coordVarNames.size(); j++) { VAPoR::DC::CoordVar coordVar; dataMgr->GetCoordVarInfo(coordVarNames[j], coordVar); units.push_back(coordVar.GetUnits()); } } std::string empty; if (units.size() == 0) return empty; else { std::string label = units[0]; for (int i = 1; i < units.size(); i++) if (units[i] != label) return empty; return label; } } std::string Plot::_getYLabel() { VAPoR::PlotParams * plotParams = this->_getCurrentPlotParams(); VAPoR::DataMgr * dataMgr = this->_getCurrentDataMgr(); std::vector enabledVars = plotParams->GetAuxVariableNames(); std::vector units; for (int i = 0; i < enabledVars.size(); i++) { VAPoR::DC::DataVar dataVar; dataMgr->GetDataVarInfo(enabledVars[i], dataVar); units.push_back(dataVar.GetUnits()); } std::string empty; if (units.size() == 0) return empty; else { std::string label = units[0]; for (int i = 1; i < units.size(); i++) if (units[i] != label) return empty; return label; } } void Plot::_axisLocksChanged(int val) { std::vector locks(3, false); locks[0] = (bool)xlock->isChecked(); locks[1] = (bool)ylock->isChecked(); locks[2] = (bool)zlock->isChecked(); VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams(); plotParams->SetAxisLocks(locks); _spaceModeP1Changed(); } void Plot::_updateExtents() { VAPoR::DataMgr * currentDmgr = this->_getCurrentDataMgr(); VAPoR::PlotParams * plotParams = this->_getCurrentPlotParams(); int refinementLevel = plotParams->GetRefinementLevel(); int compressLevel = plotParams->GetCompressionLevel(); std::vector enabledVars = plotParams->GetAuxVariableNames(); // Retrieve extents of all variables at 3 different time steps. VAPoR::CoordType min, max, minT1, maxT1, minT2, maxT2; std::vector axes; std::vector TSToExamine; TSToExamine.push_back(plotParams->GetCurrentTimestep()); TSToExamine.push_back(plotParams->GetMinMaxTS().at(0)); TSToExamine.push_back(plotParams->GetMinMaxTS().at(1)); // TSToExamine[0] definitely needs to be evaluated. VAPoR::DataMgrUtils::GetExtents(currentDmgr, TSToExamine[0], enabledVars, refinementLevel, compressLevel, min, max, axes); // TSToExamine[1] and TSToExamine[2] are evaluated only when not duplicate if (TSToExamine[1] != TSToExamine[0]) { VAPoR::DataMgrUtils::GetExtents(currentDmgr, TSToExamine[1], enabledVars, refinementLevel, compressLevel, minT1, maxT1, axes); } else { minT1 = min; maxT1 = max; } if ((TSToExamine[2] != TSToExamine[1]) && (TSToExamine[2] != TSToExamine[0])) { VAPoR::DataMgrUtils::GetExtents(currentDmgr, TSToExamine[2], enabledVars, refinementLevel, compressLevel, minT2, maxT2, axes); } else { minT2 = min; maxT2 = max; } // Find the union of the 3 extents for (int i = 0; i < min.size(); i++) { if (minT1[i] < min[i]) min[i] = minT1[i]; if (maxT1[i] > max[i]) max[i] = maxT1[i]; if (minT2[i] < min[i]) min[i] = minT2[i]; if (maxT2[i] > max[i]) max[i] = maxT2[i]; } vector minVec = {min[0], min[1], min[2]}; vector maxVec = {max[0], max[1], max[2]}; plotParams->SetMinExtents(minVec); plotParams->SetMaxExtents(maxVec); } ================================================ FILE: apps/vaporgui/Plot.h ================================================ //************************************************************************ // * // Copyright (C) 2016 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // Author: Samuel Li // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: January 2018 // #ifndef PLOT_H #define PLOT_H #include #include #include "ui_plotWindow.h" #include #include #include "PlotParams.h" #include "Updatable.h" class Plot : public QDialog, public Ui_PlotWindow, public Updatable { Q_OBJECT public: Plot(VAPoR::DataStatus *status, VAPoR::ParamsMgr *manager, QWidget *parent = 0); ~Plot(); /// This is called whenever there's a change to the parameters. void Update(); private slots: /// Update list of enabled variables upon add/remove events void _newVarChanged(int); void _removeVarChanged(int); /// Clean up everything when data source is changed void _dataSourceChanged(int); /// Clean up data points for plotting when the following events happen void _spaceModeP1Changed(); void _spaceModeP2Changed(); void _spaceModeTimeChanged(int); void _timeModePointChanged(); void _timeModeT1T2Changed(); void _numberOfSamplesChanged(); void _axisLocksChanged(int); /// Plot when the plot button is clicked void _spaceTabPlotClicked(); void _timeTabPlotClicked(); private: VAPoR::DataStatus *_dataStatus; VAPoR::ParamsMgr * _paramsMgr; QDialog * _plotDialog; QLabel * _plotLabel; QLineEdit * _plotPathEdit; QLabel * _plotImageLabel; QVBoxLayout * _plotLayout; QIntValidator * _validator; /// Access functions to other pointers VAPoR::PlotParams *_getCurrentPlotParams() const; VAPoR::DataMgr * _getCurrentDataMgr() const; void _setInitialExtents(); /// All the python stuff happens here; no python outside this method void _invokePython(const QString &, const std::vector &, const std::vector> &, const std::vector &, const std::string &, const std::string &); // Returns a string with the proper X label if all variables share the same coordinate unit. // Otherwise returns an empty string. // std::string _getXLabel(); // Returns a string with the proper Y label if all variables share the same unit. // Otherwise returns an empty string. // std::string _getYLabel(); // Update the min and max extents based on all enabled variables. // void _updateExtents(); }; #endif // PLOT_H ================================================ FILE: apps/vaporgui/PlotParams.cpp ================================================ //************************************************************************ // * // Copyright (C) 2014 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: PlotParams.cpp // // Author: Samuel Li // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: January 2018 // // Description: Implements the PlotParams class. // #include #include #include #include "vapor/VAssert.h" #include "PlotParams.h" using namespace VAPoR; const string PlotParams::_minMaxTSTag = "MinMaxTS"; const string PlotParams::_p1Tag = "Point2"; const string PlotParams::_p2Tag = "Point1"; const string PlotParams::_numSamplesTag = "NumberOfSamplesTag"; const string PlotParams::_singlePtTag = "SinglePoint"; const string PlotParams::_lockAxisTag = "LockAxis"; const string PlotParams::_minExtentTag = "MinExtentTag"; const string PlotParams::_maxExtentTag = "MaxExtentTag"; // // Register class with object factory!!! // static RenParamsRegistrar registrar(PlotParams::GetClassType()); PlotParams::PlotParams(DataMgr *dmgr, ParamsBase::StateSave *ssave) : RenderParams(dmgr, ssave, PlotParams::GetClassType()) {} PlotParams::PlotParams(DataMgr *dmgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dmgr, ssave, node) { // If node isn't tagged correctly we correct the tag and reinitialize from scratch; // if (node->GetTag() != PlotParams::GetClassType()) node->SetTag(PlotParams::GetClassType()); } PlotParams::~PlotParams() { MyBase::SetDiagMsg("PlotParams::~PlotParams() this=%p", this); } std::vector PlotParams::GetMinMaxTS() const { return GetValueLongVec(_minMaxTSTag); } void PlotParams::SetMinMaxTS(const std::vector &minmax) { SetValueLongVec(_minMaxTSTag, "Time range in the Time mode", minmax); } std::vector PlotParams::GetSinglePoint() const { return GetValueDoubleVec(_singlePtTag); } void PlotParams::SetSinglePoint(const std::vector &point) { SetValueDoubleVec(_singlePtTag, "Single point in the time mode", point); } std::vector PlotParams::GetPoint1() const { return GetValueDoubleVec(_p1Tag); } void PlotParams::SetPoint1(const std::vector &point) { SetValueDoubleVec(_p1Tag, "Point 1 in the space mode", point); } std::vector PlotParams::GetPoint2() const { return GetValueDoubleVec(_p2Tag); } void PlotParams::SetPoint2(const std::vector &point) { SetValueDoubleVec(_p2Tag, "Point 2 in the space mode", point); } void PlotParams::SetNumOfSamples(long val) { SetValueLong(_numSamplesTag, "Set number of samples", (long)val); } long PlotParams::GetNumOfSamples() const { return GetValueLong(_numSamplesTag, 100); } void PlotParams::SetAxisLocks(const std::vector &locks) { std::vector locksL(3, 0); for (int i = 0; i < 3; i++) locksL[i] = (long int)locks[i]; SetValueLongVec(_lockAxisTag, "Lock values along x, y, or z axes", locksL); } std::vector PlotParams::GetAxisLocks() { std::vector defaultVal(3, 0); std::vector locksL = GetValueLongVec(_lockAxisTag, defaultVal); std::vector locks(3, false); for (int i = 0; i < 3; i++) locks[i] = (bool)locksL[i]; return locks; } std::vector PlotParams::GetMinExtents() const { return GetValueDoubleVec(_minExtentTag); } void PlotParams::SetMinExtents(const std::vector &point) { SetValueDoubleVec(_minExtentTag, "Minimal extent", point); } std::vector PlotParams::GetMaxExtents() const { return GetValueDoubleVec(_maxExtentTag); } void PlotParams::SetMaxExtents(const std::vector &point) { SetValueDoubleVec(_maxExtentTag, "Maximal Extent", point); } ================================================ FILE: apps/vaporgui/PlotParams.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************ // // File: PlotParams.h // // Author: Samuel Li // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: December 2017 // // Description: Defines the PlotParams class. // #ifndef PLOTPARAMS_H #define PLOTPARAMS_H #include namespace VAPoR { /// PlotParams inherits RenderParams. class PlotParams : public RenderParams { public: /// Constructor 1 PlotParams(DataMgr *dmgr, ParamsBase::StateSave *ssave); /// Constructor 2 PlotParams(DataMgr *dmgr, ParamsBase::StateSave *ssave, XmlNode *node); /// Destructor ~PlotParams(); /// In ``time mode,'' these 2 methods get/set the time range. std::vector GetMinMaxTS() const; void SetMinMaxTS(const std::vector &); /// In ``time mode,'' these 2 methods get/set the single point position std::vector GetSinglePoint() const; void SetSinglePoint(const std::vector &point); /// In ``space mode,'' these 4 methods get/set the point 1 and point 2 positions std::vector GetPoint1() const; std::vector GetPoint2() const; void SetPoint1(const std::vector &point); void SetPoint2(const std::vector &point); /// These 4 methods get/set the up-to-date extents. std::vector GetMinExtents() const; std::vector GetMaxExtents() const; void SetMinExtents(const std::vector &point); void SetMaxExtents(const std::vector &point); long GetNumOfSamples() const; void SetNumOfSamples(long); void SetAxisLocks(const std::vector &locks); std::vector GetAxisLocks(); static string GetClassType() { return ("PlotParams"); } virtual size_t GetRenderDim() const override { return (0); } virtual string GetActualColorMapVariableName() const override { return ""; } private: static const string _minMaxTSTag; static const string _p1Tag; // point1 in space mode static const string _p2Tag; // point2 in space mode static const string _numSamplesTag; // number of samples in space mode static const string _singlePtTag; // a single point in time mode static const string _lockAxisTag; // if we lock x, y, or z axis static const string _minExtentTag; // minimal extent we've seen so far static const string _maxExtentTag; // maximal extent we've seen so far }; }; // End namespace VAPoR #endif ================================================ FILE: apps/vaporgui/ProgressStatusBar.h ================================================ #pragma once #include #include #include #include #include class ProgressStatusBar : public QWidget { QLabel * _titleLabel = new QLabel; QProgressBar *_progressBar = new QProgressBar; QToolButton * _cancelButton = new QToolButton; bool _canceled = false; public: ProgressStatusBar() { QHBoxLayout *layout = new QHBoxLayout; layout->setMargin(4); setLayout(layout); _cancelButton->setIcon(_cancelButton->style()->standardIcon(QStyle::StandardPixmap::SP_DialogCancelButton)); QObject::connect(_cancelButton, &QAbstractButton::clicked, this, [this]() { _canceled = true; Finish(); SetTitle("Cancelled."); }); QSizePolicy sp = _cancelButton->sizePolicy(); sp.setRetainSizeWhenHidden(true); _cancelButton->setSizePolicy(sp); _cancelButton->setIconSize(_cancelButton->iconSize() * 0.7); _cancelButton->setToolTip("Cancel"); layout->addWidget(_titleLabel); layout->addWidget(_progressBar); layout->addWidget(_cancelButton); Finish(); } void SetTitle(const string &title) { _titleLabel->setText(QString::fromStdString(title)); } void SetTotal(long total) { _progressBar->setRange(0, total); } void SetCancelable(bool b) { _cancelButton->setEnabled(b); } void SetDone(long done) { _progressBar->setValue(done); } bool Cancelled() { return _canceled; } void StartTask(const string &title, long total, bool cancelable) { Reset(); SetTitle(title); SetTotal(total); SetCancelable(cancelable); _progressBar->show(); _cancelButton->show(); } void Finish() { _progressBar->hide(); _cancelButton->hide(); SetTitle(""); } void Reset() { _canceled = false; _progressBar->reset(); } const QObject *GetCancelButtonObject() const { return _cancelButton; } }; ================================================ FILE: apps/vaporgui/PythonVariables.cpp ================================================ #include "PythonVariables.h" #include "ui_PythonVariablesGUI.h" #include #include #include #include #include #include #include #include #include #include "vapor/ResourcePath.h" #include "ErrorReporter.h" #include "FileOperationChecker.h" #define READ true #define WRITE false #define TWOD 2 #define THREED 3 using namespace VAPoR; template static void printVector(std::vector v) { for (int i = 0; i < v.size(); i++) cout << v[i] << " "; cout << endl; } using namespace PythonVariables_; PythonVariables::PythonVariables(QWidget *parent) : QDialog(parent), Ui_PythonVariablesGUI() { setupUi(this); _importScriptButton->hide(); _exportScriptButton->hide(); setWindowTitle("Derived variables with Python"); _script = ""; _scriptName = ""; _dataMgrName = ""; _newItemDialog = new ::NewItemDialog(this); _openAndDeleteDialog = new ::OpenAndDeleteDialog(this); _justSaved = false; string pythonImagePath = Wasp::GetSharePath(string("images") + string("/PythonLogo.png")); QPixmap thumbnail(pythonImagePath.c_str()); _pythonLabel->setPixmap(thumbnail); _includeCoordVars = false; _variableTabs->removeTab(0); ; _coordInputVarTable = new VaporTable(_coordVarTable, false, true); bool checkboxesEnabled = false; _coordInputVarTable->EnableDisableCheckboxes(checkboxesEnabled); _coordInputVarTable->Reinit((VaporTable::ValidatorFlags)(0), (VaporTable::MutabilityFlags)(VaporTable::IMMUTABLE), (VaporTable::HighlightFlags)(0)); _2DInputVarTable = new VaporTable(_2DVarTable, false, true); _2DInputVarTable->Reinit((VaporTable::ValidatorFlags)(0), (VaporTable::MutabilityFlags)(VaporTable::IMMUTABLE), (VaporTable::HighlightFlags)(0)); _3DInputVarTable = new VaporTable(_3DVarTable, false, true); _3DInputVarTable->Reinit((VaporTable::ValidatorFlags)(0), (VaporTable::MutabilityFlags)(VaporTable::IMMUTABLE), (VaporTable::HighlightFlags)(0)); _summaryTable = new VaporTable(_varSummaryTable); _summaryTable->Reinit((VaporTable::ValidatorFlags)(0), (VaporTable::MutabilityFlags)(VaporTable::IMMUTABLE), (VaporTable::HighlightFlags)(0)); _outputVarTable = new VaporTable(_outputVariablesTable); _outputVarTable->Reinit((VaporTable::ValidatorFlags)(0), (VaporTable::MutabilityFlags)(VaporTable::IMMUTABLE), (VaporTable::HighlightFlags)(VaporTable::ROWS)); _connectWidgets(); setModal(true); } PythonVariables::~PythonVariables() { if (_coordInputVarTable) { delete _coordInputVarTable; _coordInputVarTable = nullptr; } if (_2DInputVarTable) { delete _2DInputVarTable; _2DInputVarTable = nullptr; } if (_3DInputVarTable) { delete _3DInputVarTable; _3DInputVarTable = nullptr; } if (_varSummaryTable) { delete _varSummaryTable; _varSummaryTable = nullptr; } if (_outputVariablesTable) { delete _outputVariablesTable; _outputVariablesTable = nullptr; } } void PythonVariables::Update() { VAPoR::DataStatus * dataStatus = _controlExec->GetDataStatus(); std::vector dataMgrNames = dataStatus->GetDataMgrNames(); if ((_scriptName == "") || (_dataMgrName == "") || ((std::find(dataMgrNames.begin(), dataMgrNames.end(), _dataMgrName) == dataMgrNames.end()))) { _reset(); _setGUIEnabled(false); } else { _setGUIEnabled(true); if (_includeCoordVars) { _coordVarsEnabled.clear(); _coordVarsEnabled.resize(_coordVars.size(), false); _findEnabledCoordinateVariables(_2DVars, _2DVarsEnabled); _findEnabledCoordinateVariables(_3DVars, _3DVarsEnabled); } } _scriptNameLabel->setText(QString::fromStdString(_scriptName)); _dataMgrNameLabel->setText(QString::fromStdString(_dataMgrName)); _scriptEdit->setText(QString::fromStdString(_script)); int numRows; int numCols = 2; std::vector tableValuesCoords, tableValues2D; std::vector tableValues3D, summaryValues; _makeInputTableValues(tableValuesCoords, tableValues2D, tableValues3D, summaryValues); _coordInputVarTable->blockSignals(true); _2DInputVarTable->blockSignals(true); _3DInputVarTable->blockSignals(true); _summaryTable->blockSignals(true); _outputVarTable->blockSignals(true); numRows = _coordVars.size(); _coordInputVarTable->Update(numRows, numCols, tableValuesCoords); numRows = _2DVars.size(); _2DInputVarTable->Update(numRows, numCols, tableValues2D); numRows = _3DVars.size(); _3DInputVarTable->Update(numRows, numCols, tableValues3D); numRows = summaryValues.size() / 2; _summaryTable->Update(numRows, numCols, summaryValues); std::vector outputValues; _makeOutputTableValues(outputValues); numRows = outputValues.size() / 2; _outputVarTable->Update(numRows, numCols, outputValues); _outputVarTable->StretchToColumn(1); _coordInputVarTable->blockSignals(false); _2DInputVarTable->blockSignals(false); _3DInputVarTable->blockSignals(false); _summaryTable->blockSignals(false); _outputVarTable->blockSignals(false); } void PythonVariables::_connectWidgets() { connect(_newScriptButton, SIGNAL(clicked()), this, SLOT(_newScript())); connect(_openScriptButton, SIGNAL(clicked()), this, SLOT(_openScript())); connect(_deleteScriptButton, SIGNAL(clicked()), this, SLOT(_deleteScript())); connect(_importScriptButton, SIGNAL(clicked()), this, SLOT(_importScript())); connect(_exportScriptButton, SIGNAL(clicked()), this, SLOT(_exportScript())); connect(_testScriptButton, SIGNAL(clicked()), this, SLOT(_testScript())); connect(_saveScriptButton, SIGNAL(clicked()), this, SLOT(_saveScript())); connect(_closeButton, SIGNAL(clicked()), this, SLOT(_closeScript())); connect(_coordInputVarTable, SIGNAL(valueChanged(int, int)), this, SLOT(_coordInputVarChanged(int, int))); connect(_2DInputVarTable, SIGNAL(valueChanged(int, int)), this, SLOT(_2DInputVarChanged(int, int))); connect(_3DInputVarTable, SIGNAL(valueChanged(int, int)), this, SLOT(_3DInputVarChanged(int, int))); connect(_coordinatesCheckbox, SIGNAL(stateChanged(int)), this, SLOT(_coordinatesCheckboxClicked(int))); connect(_scriptEdit, SIGNAL(textChanged()), this, SLOT(_scriptChanged())); connect(_newOutVarButton, SIGNAL(clicked()), this, SLOT(_createNewVariable())); connect(_deleteOutVarButton, SIGNAL(clicked()), this, SLOT(_deleteVariable())); } void PythonVariables::_setGUIEnabled(bool enabled) { _variableSelectionFrame->setEnabled(enabled); _scriptEdit->setEnabled(enabled); _testScriptButton->setEnabled(enabled); _saveScriptButton->setEnabled(enabled); _exportScriptButton->setEnabled(enabled); _importScriptButton->setEnabled(enabled); _exportScriptButton->setEnabled(enabled); } void PythonVariables::_updateNewItemDialog() { VAPoR::DataStatus * dataStatus = _controlExec->GetDataStatus(); std::vector dataMgrNames = dataStatus->GetDataMgrNames(); _newItemDialog->Update(::NewItemDialog::SCRIPT, dataMgrNames); } void PythonVariables::_newScript() { VAPoR::DataStatus * dataStatus = _controlExec->GetDataStatus(); std::vector dataMgrNames = dataStatus->GetDataMgrNames(); _newItemDialog->Update(::NewItemDialog::SCRIPT, dataMgrNames); _newItemDialog->exec(); int rc = _newItemDialog->result(); if (rc > 0) { string scriptName = _newItemDialog->GetItemName(); if (scriptName == "") return; scriptName = _controlExec->MakeStringConformant(scriptName); _reset(); _scriptName = scriptName; _dataMgrName = _newItemDialog->GetOptionName(); _scriptNameLabel->setText(QString::fromStdString(_scriptName)); _dataMgrNameLabel->setText(QString::fromStdString(_dataMgrName)); VAPoR::DataMgr *dataMgr = dataStatus->GetDataMgr(_dataMgrName); _coordVars = dataMgr->GetCoordVarNames(); _coordVarsEnabled.resize(_coordVars.size()); std::fill(_coordVarsEnabled.begin(), _coordVarsEnabled.end(), false); _2DVars = dataMgr->GetDataVarNames(TWOD); _2DVarsEnabled.resize(_2DVars.size()); std::fill(_2DVarsEnabled.begin(), _2DVarsEnabled.end(), false); _3DVars = dataMgr->GetDataVarNames(THREED); _3DVarsEnabled.resize(_3DVars.size()); std::fill(_3DVarsEnabled.begin(), _3DVarsEnabled.end(), false); Update(); } } void PythonVariables::_reset() { _script = ""; _scriptName = ""; _dataMgrName = ""; _justSaved = false; _coordVars.clear(); _coordVarsEnabled.clear(); _2DVars.clear(); _2DVarsEnabled.clear(); _3DVars.clear(); _3DVarsEnabled.clear(); _outputVars.clear(); _outputGrids.clear(); _inputGrids.clear(); _otherGrids.clear(); } void PythonVariables::_openScript() { int rc = _openAndDeleteDialog->Update(OpenAndDeleteDialog::_OPEN, _controlExec); if (rc < 0) return; _openAndDeleteDialog->exec(); rc = _openAndDeleteDialog->result(); if (rc > 0) { _reset(); string scriptName = _openAndDeleteDialog->GetScriptName(); string dataMgrName = _openAndDeleteDialog->GetDataMgrName(); std::vector inputVars; bool coordFlag; // TODO: add support for coordinate flag bool rc2 = _controlExec->GetFunction(_scriptType, dataMgrName, scriptName, _script, inputVars, _outputVars, _outputGrids, coordFlag); if (rc2 == false) { MSG_ERR("Invalid script: " + scriptName); return; } _dataMgrName = dataMgrName; _scriptName = scriptName; VAPoR::DataStatus *dataStatus = _controlExec->GetDataStatus(); VAPoR::DataMgr * dataMgr = dataStatus->GetDataMgr(_dataMgrName); _coordVars = dataMgr->GetCoordVarNames(); _coordVarsEnabled.resize(_coordVars.size(), false); _2DVars = dataMgr->GetDataVarNames(TWOD); _2DVarsEnabled.resize(_2DVars.size(), false); _3DVars = dataMgr->GetDataVarNames(THREED); _3DVarsEnabled.resize(_3DVars.size(), false); std::vector::iterator it; for (int i = 0; i < inputVars.size(); i++) { string inVar = inputVars[i]; it = std::find(_coordVars.begin(), _coordVars.end(), inVar); if (it != _coordVars.end()) { int index = it - _coordVars.begin(); _coordVarsEnabled[index] = true; } it = std::find(_2DVars.begin(), _2DVars.end(), inVar); if (it != _2DVars.end()) { int index = it - _2DVars.begin(); _2DVarsEnabled[index] = true; } it = std::find(_3DVars.begin(), _3DVars.end(), inVar); if (it != _3DVars.end()) { int index = it - _3DVars.begin(); _3DVarsEnabled[index] = true; } } _inputGrids.clear(); _otherGrids.clear(); Update(); } } void PythonVariables::_deleteScript() { int rc = _openAndDeleteDialog->Update(OpenAndDeleteDialog::_DELETE, _controlExec); if (rc < 0) return; _openAndDeleteDialog->exec(); rc = _openAndDeleteDialog->result(); if (rc < 1) return; string scriptName = _openAndDeleteDialog->GetScriptName(); string dataMgrName = _openAndDeleteDialog->GetDataMgrName(); _controlExec->RemoveFunction(_scriptType, dataMgrName, scriptName); if (scriptName == _scriptName) _reset(); Update(); } bool PythonVariables::_getFilePath(QString &filePath, bool operation) { QFileDialog::AcceptMode acceptMode = QFileDialog::AcceptOpen; QFileDialog::FileMode fileMode = QFileDialog::ExistingFile; QString title = "Import Python script from file"; if (operation == WRITE) { acceptMode = QFileDialog::AcceptSave; fileMode = QFileDialog::AnyFile; title = "Export your Python script to a file"; } string pythonPath = Wasp::GetSharePath("python"); QFileDialog fileDialog(this, "Import Python script from file", QString::fromStdString(pythonPath), QString("Python file (*.py)")); fileDialog.setAcceptMode(acceptMode); fileDialog.setDefaultSuffix(QString("py")); fileDialog.setFileMode(fileMode); if (fileDialog.exec() != QDialog::Accepted) return false; QStringList files = fileDialog.selectedFiles(); if (files.size() != 1) return false; filePath = files[0]; bool operable; if (operation == READ) operable = FileOperationChecker::FileGoodToRead(filePath); else operable = FileOperationChecker::FileGoodToWrite(filePath); if (!operable) { MSG_ERR(FileOperationChecker::GetLastErrorMessage().toStdString()); return false; } return true; } void PythonVariables::_importScript() { QString filePath; if (!_getFilePath(filePath, READ)) return; _script.clear(); std::ifstream file; file.open(filePath.toStdString()); if (file.is_open()) { std::string line; while (getline(file, line)) { _script += line; _script += "\n"; } } Update(); } void PythonVariables::_exportScript() { QString filePath; if (!_getFilePath(filePath, WRITE)) return; qDebug() << filePath; std::ofstream file; file.open(filePath.toStdString()); file << _script; file.close(); } void PythonVariables::_testScript() { string script = _scriptEdit->toPlainText().toStdString(); std::vector inputVars = _buildInputVars(); if (inputVars.empty() || _outputVars.empty()) { MSG_ERR("At least one Input Variable and one " "Output Variable must be defined"); return; } int rc = _controlExec->AddFunction(_scriptType, _dataMgrName, _scriptName, script, inputVars, _outputVars, _outputGrids, _includeCoordVars); if (rc < 0) { MSG_ERR("Failed to add script"); return; } DataMgr *dataMgr = _controlExec->GetDataStatus()->GetDataMgr(_dataMgrName); string varname = _outputVars[0]; Grid * g = dataMgr->GetVariable(0, varname, 0, 0); if (!g) { MSG_ERR("Failed to calculate variable " + varname); return; } // // Get any output from script // string s = _controlExec->GetFunctionStdout(_scriptType, _dataMgrName, _scriptName); QMessageBox msgBox; if (!s.empty()) { msgBox.setText("Script output:"); msgBox.setInformativeText(s.c_str()); msgBox.exec(); } msgBox.setText("Test passed."); msgBox.exec(); } void PythonVariables::_saveScript() { string script = _scriptEdit->toPlainText().toStdString(); std::vector inputVars = _buildInputVars(); int rc = _controlExec->AddFunction(_scriptType, _dataMgrName, _scriptName, script, inputVars, _outputVars, _outputGrids, _includeCoordVars); if (rc < 0) { MSG_ERR("Invalid syntax"); return; } QMessageBox msgBox; msgBox.setText("Script saved to session."); msgBox.exec(); } std::vector PythonVariables::_buildInputVars() const { std::vector inputVars; for (int i = 0; i < _2DVars.size(); i++) { if (_2DVarsEnabled[i] == true) inputVars.push_back(_2DVars[i]); } for (int i = 0; i < _3DVars.size(); i++) { if (_3DVarsEnabled[i] == true) inputVars.push_back(_3DVars[i]); } return inputVars; } void PythonVariables::_closeScript() { close(); } void PythonVariables::_coordInputVarChanged(int row, int col) { if (col == 0) return; string value = _coordInputVarTable->GetValue(row, col); if (value == "1") _coordVarsEnabled[row] = true; else _coordVarsEnabled[row] = false; Update(); } void PythonVariables::_2DInputVarChanged(int row, int col) { if (col == 0) return; string value = _2DInputVarTable->GetValue(row, col); if (value == "1") _2DVarsEnabled[row] = true; else _2DVarsEnabled[row] = false; Update(); } void PythonVariables::_3DInputVarChanged(int row, int col) { if (col == 0) return; string value = _3DInputVarTable->GetValue(row, col); if (value == "1") _3DVarsEnabled[row] = true; else _3DVarsEnabled[row] = false; Update(); } void PythonVariables::_coordinatesCheckboxClicked(int state) { if (state == Qt::Unchecked) { _includeCoordVars = false; _variableTabs->removeTab(0); _coordVarsEnabled.resize(_coordVars.size()); std::fill(_coordVarsEnabled.begin(), _coordVarsEnabled.end(), false); } else { _includeCoordVars = true; _variableTabs->insertTab(0, _coordTab, "Coordinates"); } Update(); } void PythonVariables::_findEnabledCoordinateVariables(const std::vector vars, const std::vector varsEnabled) { VAPoR::DataStatus *dataStatus = _controlExec->GetDataStatus(); VAPoR::DataMgr * dataMgr = dataStatus->GetDataMgr(_dataMgrName); if (dataMgr == NULL) { MSG_ERR("Invalid DataMgr " + _dataMgrName); } std::vector enabledCoordVarNames; std::vector tmpCoordVarNames; VAPoR::DC::DataVar dataVar; VAPoR::DC::Mesh mesh; // Gather the currently used coord variables for (int i = 0; i < vars.size(); i++) { if (varsEnabled[i] == false) continue; string varName = vars[i]; dataMgr->GetDataVarInfo(varName, dataVar); string meshName = dataVar.GetMeshName(); dataMgr->GetMesh(meshName, mesh); tmpCoordVarNames = mesh.GetCoordVars(); std::move(tmpCoordVarNames.begin(), tmpCoordVarNames.end(), std::back_inserter(enabledCoordVarNames)); } // Set current coord variables to be enabled for (int i = 0; i < _coordVars.size(); i++) { for (int j = 0; j < enabledCoordVarNames.size(); j++) { if (_coordVars[i] == enabledCoordVarNames[j]) { _coordVarsEnabled[i] = true; } } } } void PythonVariables::_createNewVariable() { VAPoR::DataStatus *dataStatus = _controlExec->GetDataStatus(); VAPoR::DataMgr * dataMgr = dataStatus->GetDataMgr(_dataMgrName); if (dataMgr == NULL) MSG_ERR("Invalid DataMgr " + _dataMgrName); std::vector grids = dataMgr->GetMeshNames(); std::vector options = _makeDialogOptions(grids); std::vector cateogryIndices; cateogryIndices.push_back(0); cateogryIndices.push_back(_inputGrids.size() + 1); _newItemDialog->Update(::NewItemDialog::OUTVAR, options, cateogryIndices); _newItemDialog->exec(); int rc = _newItemDialog->result(); if (rc < 1) return; string outputVar = _newItemDialog->GetItemName(); if (outputVar == "") return; rc = _checkForDuplicateNames(_outputVars, outputVar); if (rc < 1) return; _outputVars.push_back(outputVar); string outputGrid = _newItemDialog->GetOptionName(); _outputGrids.push_back(outputGrid); Update(); } std::vector PythonVariables::_makeDialogOptions(std::vector grids) { std::vector options; string inputVarGrid; bool gridSelected; _inputGrids.clear(); _otherGrids.clear(); for (int i = 0; i < grids.size(); i++) { string grid = grids[i]; gridSelected = _isGridSelected(grid, _2DVars, _2DVarsEnabled); if (gridSelected) { _inputGrids.push_back(grid); continue; } gridSelected = _isGridSelected(grid, _3DVars, _3DVarsEnabled); if (gridSelected) { _inputGrids.push_back(grid); continue; } _otherGrids.push_back(grids[i]); } options.push_back("Input variable grids:"); for (int i = 0; i < _inputGrids.size(); i++) { options.push_back(_inputGrids[i]); } options.push_back("Other grids:"); for (int i = 0; i < _otherGrids.size(); i++) { options.push_back(_otherGrids[i]); } return options; } bool PythonVariables::_isGridSelected(string grid, std::vector variables, std::vector varEnabled) const { VAPoR::DC::DataVar dataVar; string inputVarGrid; bool isInputGrid = false; for (int j = 0; j < variables.size(); j++) { if (varEnabled[j] == false) { continue; } VAPoR::DataStatus *dataStatus = _controlExec->GetDataStatus(); VAPoR::DataMgr * dataMgr = dataStatus->GetDataMgr(_dataMgrName); int rc = dataMgr->GetDataVarInfo(variables[j], dataVar); if (!rc) { continue; } inputVarGrid = dataVar.GetMeshName(); if (grid == inputVarGrid) { isInputGrid = true; break; } } return isInputGrid; } void PythonVariables::_deleteVariable() { int activeRow = _outputVarTable->GetActiveRow(); if (activeRow < 0) return; string varName = _outputVarTable->GetValue(activeRow, 0); auto it = std::find(_outputVars.begin(), _outputVars.end(), varName); int index = std::distance(_outputVars.begin(), it); _outputVars.erase(_outputVars.begin() + index); _outputGrids.erase(_outputGrids.begin() + index); Update(); } void PythonVariables::_scriptChanged() { _script = _scriptEdit->toPlainText().toStdString(); } void PythonVariables::_makeInputTableValues(std::vector &tableValuesCoords, std::vector &tableValues2D, std::vector &tableValues3D, std::vector &summaryValues) const { string onOff; for (int i = 0; i < _2DVars.size(); i++) { tableValues2D.push_back(_2DVars[i]); onOff = "0"; if (_2DVarsEnabled[i]) { onOff = "1"; summaryValues.push_back(_2DVars[i]); summaryValues.push_back("2D"); } tableValues2D.push_back(onOff); } for (int i = 0; i < _3DVars.size(); i++) { tableValues3D.push_back(_3DVars[i]); onOff = "0"; if (_3DVarsEnabled[i]) { onOff = "1"; summaryValues.push_back(_3DVars[i]); summaryValues.push_back("3D"); } tableValues3D.push_back(onOff); } for (int i = 0; i < _coordVars.size(); i++) { tableValuesCoords.push_back(_coordVars[i]); onOff = "0"; if (_coordVarsEnabled[i]) { onOff = "1"; summaryValues.push_back(_coordVars[i]); summaryValues.push_back("Coordinate"); } tableValuesCoords.push_back(onOff); } } void PythonVariables::_makeOutputTableValues(std::vector &outputValues) const { for (int i = 0; i < _outputVars.size(); i++) { outputValues.push_back(_outputVars[i]); outputValues.push_back(_outputGrids[i]); } } int PythonVariables::_checkForDuplicateNames(std::vector names, string name) { std::vector::iterator it; it = std::find(names.begin(), names.end(), name); if (it == names.end()) return 1; else { MSG_ERR("Names must be unique"); return 0; } } void PythonVariables::InitControlExec(VAPoR::ControlExec *ce) { VAssert(ce); _controlExec = ce; } void PythonVariables::ShowMe() { Update(); open(); } NewItemDialog::NewItemDialog(QWidget *parent) : QDialog(parent) { setModal(true); _itemNameLabel = new QLabel(tr("Script name:")); _itemNameEdit = new QLineEdit(); _optionNameLabel = new QLabel(tr("Data Set:")); _optionNameCombo = new QComboBox(); _okButton = new QPushButton(tr("Ok")); _cancelButton = new QPushButton(tr("Cancel")); _okButton->setAutoDefault(true); _cancelButton->setAutoDefault(false); _setupGUI(); _connectWidgets(); _itemNameEdit->setFocus(); } void NewItemDialog::_connectWidgets() { connect(_okButton, SIGNAL(clicked()), this, SLOT(_okClicked())); connect(_cancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void NewItemDialog::_setupGUI() { QVBoxLayout *topLeftLayout = new QVBoxLayout; QVBoxLayout *topRightLayout = new QVBoxLayout; QHBoxLayout *topLayout = new QHBoxLayout; QHBoxLayout *bottomLayout = new QHBoxLayout; QVBoxLayout *mainLayout = new QVBoxLayout; topLeftLayout->addWidget(_itemNameLabel); topLeftLayout->addWidget(_optionNameLabel); topRightLayout->addWidget(_itemNameEdit); topRightLayout->addWidget(_optionNameCombo); topLayout->addLayout(topLeftLayout); topLayout->addLayout(topRightLayout); bottomLayout->addWidget(_cancelButton); bottomLayout->addWidget(_okButton); mainLayout->addLayout(topLayout); mainLayout->addLayout(bottomLayout); setLayout(mainLayout); } void NewItemDialog::Update(int type, std::vector optionNames, std::vector categoryIndices) { _adjustToType(type); _itemName = ""; _optionName = ""; _itemNameEdit->clear(); _optionNameCombo->clear(); for (int i = 0; i < optionNames.size(); i++) { QString qName = QString::fromStdString(optionNames[i]); _optionNameCombo->addItem(qName); } bool nextIndexIsInvalid = true; int size = categoryIndices.size(); for (int i = 0; i < size; i++) { _disableComboItem(categoryIndices[i]); if (nextIndexIsInvalid && categoryIndices[i] + 1 != categoryIndices[i + 1] && i != size) { nextIndexIsInvalid = false; _optionNameCombo->setCurrentIndex(categoryIndices[i] + 1); } } } void NewItemDialog::_disableComboItem(int index) { QStandardItemModel *model = qobject_cast(_optionNameCombo->model()); bool disabled = true; QStandardItem * item = model->item(index); item->setFlags(disabled ? item->flags() & ~Qt::ItemIsEnabled : item->flags() | Qt::ItemIsEnabled); } void NewItemDialog::_adjustToType(int type) { if (type == SCRIPT) { setWindowTitle("Create new script"); _itemNameLabel->setText("Script name:"); _optionNameLabel->setText("Data Set:"); } else if (type == OUTVAR) { setWindowTitle("Create new variable"); _itemNameLabel->setText("Variable name:"); _optionNameLabel->setText("Output Grid:"); } } void ::NewItemDialog::_okClicked() { _itemName = _itemNameEdit->text().toStdString(); _optionName = _optionNameCombo->currentText().toStdString(); _itemNameEdit->clear(); accept(); } string NewItemDialog::GetItemName() const { return _itemName; } string NewItemDialog::GetOptionName() const { return _optionName; } OpenAndDeleteDialog::OpenAndDeleteDialog(QWidget *parent) { setModal(true); _dataMgrNameLabel = new QLabel(tr("Data Set name:")); _dataMgrNameCombo = new QComboBox(); _scriptNameLabel = new QLabel(tr("Script:")); _scriptNameCombo = new QComboBox(); _okButton = new QPushButton(tr("Ok")); _cancelButton = new QPushButton(tr("Cancel")); _okButton->setAutoDefault(true); _cancelButton->setAutoDefault(false); _setupGUI(); _dataMgrNameCombo->setFocus(); connect(_okButton, SIGNAL(clicked()), this, SLOT(_okClicked())); connect(_cancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(_dataMgrNameCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_updateOptions(int))); } void OpenAndDeleteDialog::_updateOptions(int index) { string dataSetName = _dataMgrNameCombo->itemText(index).toStdString(); std::vector functionNames; functionNames = _controlExec->GetFunctionNames(_scriptType, dataSetName); _scriptNameCombo->clear(); for (int i = 0; i < functionNames.size(); i++) { QString qName = QString::fromStdString(functionNames[i]); _scriptNameCombo->addItem(qName); } } void OpenAndDeleteDialog::_setupGUI() { QVBoxLayout *topLeftLayout = new QVBoxLayout; QVBoxLayout *topRightLayout = new QVBoxLayout; QHBoxLayout *topLayout = new QHBoxLayout; QHBoxLayout *bottomLayout = new QHBoxLayout; QVBoxLayout *mainLayout = new QVBoxLayout; topLeftLayout->addWidget(_dataMgrNameLabel); topLeftLayout->addWidget(_scriptNameLabel); topRightLayout->addWidget(_dataMgrNameCombo); topRightLayout->addWidget(_scriptNameCombo); topLayout->addLayout(topLeftLayout); topLayout->addLayout(topRightLayout); bottomLayout->addWidget(_cancelButton); bottomLayout->addWidget(_okButton); mainLayout->addLayout(topLayout); mainLayout->addLayout(bottomLayout); setLayout(mainLayout); } int OpenAndDeleteDialog::Update(int type, VAPoR::ControlExec *controlExec) { _controlExec = controlExec; string errMsg; if (type == _OPEN) { setWindowTitle("Open saved script"); errMsg = "There are no scripts to open in this session"; } else if (type == _DELETE) { setWindowTitle("Delete saved script"); errMsg = "There are no scripts to delete in this session"; } _dataMgrNameCombo->clear(); _scriptNameCombo->clear(); VAPoR::DataStatus * dataStatus = _controlExec->GetDataStatus(); std::vector dataMgrNames = dataStatus->GetDataMgrNames(); std::vector scriptNames; for (int i = 0; i < dataMgrNames.size(); i++) { QString qName = QString::fromStdString(dataMgrNames[i]); _dataMgrNameCombo->addItem(qName); if (scriptNames.empty()) { scriptNames = controlExec->GetFunctionNames(_scriptType, dataMgrNames[i]); _dataMgrNameCombo->setCurrentIndex(i); _dataMgrName = dataMgrNames[i]; } } if (scriptNames.empty()) { MSG_ERR(errMsg); return -1; } _scriptName = _scriptNameCombo->currentText().toStdString(); return 0; } void OpenAndDeleteDialog::_okClicked() { _dataMgrName = _dataMgrNameCombo->currentText().toStdString(); _scriptName = _scriptNameCombo->currentText().toStdString(); accept(); } string OpenAndDeleteDialog::GetDataMgrName() const { return _dataMgrName; } string OpenAndDeleteDialog::GetScriptName() const { return _scriptName; } ================================================ FILE: apps/vaporgui/PythonVariables.h ================================================ #ifndef PYTHOVARIABLES_H #define PYTHOVARIABLES_H #include #include "ui_PythonVariablesGUI.h" #include "PythonVariablesParams.h" #include "VaporTable.h" #include "Updatable.h" #include #include #include #include #include // // QObjects do not support nested classes, so use a namespace // namespace PythonVariables_ { class NewItemDialog; class OpenAndDeleteDialog; static const string _scriptType = "Python"; } // namespace PythonVariables_ class PythonVariables : public QDialog, public Updatable, Ui_PythonVariablesGUI { Q_OBJECT public: PythonVariables(QWidget *parent); ~PythonVariables(); void Update(); void InitControlExec(VAPoR::ControlExec *ce); void ShowMe(); private slots: void _newScript(); void _openScript(); void _deleteScript(); void _importScript(); void _exportScript(); bool _getFilePath(QString &filePath, bool operation = true); void _testScript(); void _saveScript(); void _closeScript(); void _createNewVariable(); void _deleteVariable(); void _scriptChanged(); void _coordInputVarChanged(int row, int col); void _2DInputVarChanged(int row, int col); void _3DInputVarChanged(int row, int col); void _findEnabledCoordinateVariables(const std::vector variables, const std::vector variablesEnabled); void _coordinatesCheckboxClicked(int state); private: const QColor *_background; VAPoR::ControlExec *_controlExec; PythonVariables_::NewItemDialog * _newItemDialog; PythonVariables_::OpenAndDeleteDialog *_openAndDeleteDialog; VaporTable *_coordInputVarTable; VaporTable *_2DInputVarTable; VaporTable *_3DInputVarTable; VaporTable *_summaryTable; VaporTable *_outputVarTable; string _script; string _scriptName; string _dataMgrName; bool _justSaved; bool _includeCoordVars; std::vector _coordVars; std::vector _coordVarsEnabled; std::vector _2DVars; std::vector _2DVarsEnabled; std::vector _3DVars; std::vector _3DVarsEnabled; std::vector _outputVars; std::vector _outputGrids; std::vector _inputGrids; std::vector _otherGrids; void _connectWidgets(); void _setGUIEnabled(bool enabled); void _makeInputTableValues(std::vector &tableValuesCoords, std::vector &tableValues2D, std::vector &tableValues3D, std::vector &summaryValues) const; void _makeOutputTableValues(std::vector &outputValues) const; std::vector _makeDialogOptions(std::vector grids); std::vector _buildInputVars() const; int _checkForDuplicateNames(std::vector names, string name); bool _isGridSelected(string grid, std::vector selectedVars, std::vector varEnabled) const; void _saveToSession(); void _updateNewItemDialog(); void _updateLabelColor(int r, int g, int b, QLabel *label); void _reset(); }; namespace PythonVariables_ { class NewItemDialog : public QDialog { Q_OBJECT public: enum { SCRIPT = 0, OUTVAR = 1 }; NewItemDialog(QWidget *parent = 0); ~NewItemDialog(){}; void Update(int type, std::vector optionNames, std::vector categoryItems = std::vector()); string GetItemName() const; string GetOptionName() const; private: void _connectWidgets(); void _setupGUI(); void _adjustToType(int type); void _disableComboItem(int index); string _itemName; string _optionName; QLabel * _itemNameLabel; QLineEdit * _itemNameEdit; QLabel * _optionNameLabel; QComboBox * _optionNameCombo; QPushButton *_okButton; QPushButton *_cancelButton; private slots: void _okClicked(); }; class OpenAndDeleteDialog : public QDialog { Q_OBJECT public: enum { _OPEN = 0, _DELETE = 1 // DELETE is a reserved keyword on Windows }; OpenAndDeleteDialog(QWidget *parent = 0); ~OpenAndDeleteDialog(){}; int Update(int type, VAPoR::ControlExec *controlExec); string GetDataMgrName() const; string GetScriptName() const; private: void _setupGUI(); string _dataMgrName; string _scriptName; QLabel * _dataMgrNameLabel; QComboBox * _dataMgrNameCombo; QLabel * _scriptNameLabel; QComboBox * _scriptNameCombo; QPushButton *_okButton; QPushButton *_cancelButton; VAPoR::ControlExec *_controlExec; private slots: void _okClicked(); void _updateOptions(int index); }; } // namespace PythonVariables_ #endif // PYTHOVARIABLES_H ================================================ FILE: apps/vaporgui/PythonVariablesGUI.ui ================================================ PythonVariablesGUI 0 0 591 685 Dialog -1 0 0 QFrame::NoFrame QFrame::Raised -1 0 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Qt::Vertical QSizePolicy::Maximum 20 40 0 0 PythonImage Qt::Vertical QSizePolicy::Maximum 20 40 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 QFrame::NoFrame QFrame::Raised Qt::Vertical QSizePolicy::Maximum 20 40 0 0 Script Name: 0 0 Data Set: Qt::Vertical QSizePolicy::Maximum 20 40 0 0 QFrame::NoFrame QFrame::Raised Qt::Vertical QSizePolicy::Maximum 20 40 0 0 Script Name 0 0 DataMgr Name Qt::Vertical QSizePolicy::Maximum 20 40 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 5 6 0 0 100 0 New true 0 0 Open from Session false 0 0 Delete false false false Qt::Vertical QSizePolicy::Maximum 20 40 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 QFrame::NoFrame QFrame::Raised -1 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 5 Qt::Horizontal 40 0 0 0 Input Variables Qt::Horizontal 40 0 0 Coordinates 0 0 0 0 0 2D 0 0 0 0 0 3D 0 0 0 0 0 Summary 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Include Coordinate Variables Qt::Horizontal QSizePolicy::Expanding 40 20 0 20 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Qt::Horizontal 40 0 0 0 Output Variables Qt::Horizontal 40 0 0 0 QFrame::NoFrame QFrame::Raised -1 0 0 0 0 New false false Delete false QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Qt::Horizontal 278 20 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 Script Editor Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 0 0 QTextEdit::NoWrap 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 QFrame::NoFrame QFrame::Raised -1 0 0 0 0 Import file false Export file QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Qt::Horizontal 40 20 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Test false QFrame::NoFrame QFrame::Raised 0 0 0 0 0 QFrame::NoFrame QFrame::Raised -1 0 0 0 0 Save Close ================================================ FILE: apps/vaporgui/PythonVariablesParams.cpp ================================================ #include "PythonVariablesParams.h" const string PythonVariablesParams::_pythonScriptsTag = "PythonScripts"; const string PythonScript::_pythonScriptTag = "PythonScript"; const string PythonScript::_scritpNameTag = "PythonScriptName"; const string PythonScript::_dataMgrNameTag = "DataMgrName"; const string PythonScript::_dataMgrGridsTag = "DataMgrGrids"; const string PythonScript::_inputVarsTag = "InputVars"; const string PythonScript::_outputVarsTag = "OutputVars"; const string PythonScript::_outputVarGridsTag = "OutputVarGrids"; const string PythonScript::_dataMgrNameTag = "DataMgrName"; static ParamsRegistrar registrar(PythonVariablesParams::GetClassType()); static ParamsRegistrar registrar_ps(PythonScript::GetClassType()); PythonVariablesParams::PythonVariablesParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : ParamsBase(ssave, GetClassType()) { _pythonScripts = new ParamsContainer(ssave, _pythonScriptsTag); _pythonScripts->SetParent(this); } PythonVariablesParams::PythonVariablesParams(DataMgr *dataMgr, XmlNode *node) : ParamsBase(ssave, node) { if (node->HasChild(_pythonScriptsTag)) { _pythonScripts = new ParamsContainer(ssave, node->GetChild(_pythonScriptsTag)); } else { _pythonScripts = new ParamsContainer(ssave, _pythonScriptsTag); } } PythonScript::PythonScript(VAPoR::ParamsBase::StateSave *ssave) : ParamsBase(ssave, PythonScript::GetClassType()) {} PythonScript::PythonScript(VAPOR::ParamsBase::StateSave *ssave, VAPOR::XmlNode *node) : ParamsBase(ssave, node){}; string PythonScript::GetScript() const { string defaultScript = ""; script = GetValueString(_pythonScriptTag, defaultScript); } void PythonScript::SetScript(string script) { SetValueString(_pythonScriptTag, "Set Python Script", script); } string PythonScript::GetScriptName() const { string defaultName = "default.py"; GetValueString(_pythonScriptName, defaultName); } void PythonScript::SetScriptName(string scriptName) { SetValueString(_pythonScriptName, "Set Python Script Name", scriptName); } std::vector PythonScript::GetOutputVars() const { return GetValueStringVec(_outputVarsTag); } void PythonScript::SetOutputVars(std::vector vars) { SetValueStringVec(_outputVarsTag, "Set Python output variables", vars); } std::vector PythonScript::GetOutputVars() const { return GetValueStringVec(_outputVarsTag); } void PythonScript::SetOutputGrids(std::vector grids) { SetValueStringVec(_outputGridsTag, "Set Python output grids", grids); } std::vector PythonScript::GetOutputGrids() const { return GetValueStringVec(_outputGridsTag); } void PythonScript::SetInputVars(std::vector vars) { SetValueStringVec(_inputVarsTag, "Set Python input variables", vars); } std::vector PythonScript::GetInputVars() const { return GetValueStringVec(_inputVarsTag); } void PythonScript::SetInputGrids(std::vector grids) { SetValueStringVec(_inputGridsTag, "Set Python input grids", grids); } std::vector PythonScript::GetInputGrids() const { return GetValueStringVec(_inputGridsTag); } string GetDataMgr() const { return GetValueString(_dataMgrNameTag, ""); } void PythonScript::SetDataMgr(string dataMgrName) { SetValueString(_dataMgrNameTag, "Set DataMgr name for Python script", dataMgrName); } ================================================ FILE: apps/vaporgui/PythonVariablesParams.h ================================================ #ifndef PYTHONVARIABLESPARAMS_H #define PYTHONVARIABLESPARAMS_H #include namespace VAPoR { class PythonScript; class PythonVariablesParams : public ParamsBase { public: PythonVariablesParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave); PythonVariablesParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node); ~PythonVariablesParams() {} static string GetClassType() { return ("PythonVariablesParams"); } std::vector GetPythonScripts() const; std::vector GetPythonScriptNames(); void AddPythonScript(string scriptName); void RemovePythonScript(string scriptName); private: VAPoR::ParamsContainer *_pythonScripts; static const string _pythonScriptsTag; }; class PythonScript : public ParamsBase { public: PythonScript(VAPoR::ParamsBase::StateSave *ssave); PythonScript(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node); ~PythonScript() {} static string GetClassType() { return ("PythonScript"); } string GetScript() const; void SetScript(string script); string GetScriptName() const; void SetScriptName(string scriptName); std::vector GetOutputVars() const; void SetOutputVars(std::vector outputVars); std::vector GetOutputGrids() const; void SetOutputGrids(std::vector grids); std::vector GetInputVars() const; void SetInputVars(std::vector inputVars); std::vector GetInputGrids() const; void SetInputGrids(std::vector inputGrids); string GetDataMgr() const; void SetDataMgr(string dataMgrName); private: // string _pythonScript; // string _scriptName; // string _dataMgrName; DataMgr * _dataMgr; std::vector _grids; std::vector _inputVars; std::vector _outputVars; std::vector _outputVarGrids; static const string _pythonScriptTag; static const string _scriptNameTag; static const string _dataMgrNameTag; static const string _dataMgrGridsTag; static const string _inputVarsTag; static const string _outputVarsTag; static const string _outputVarGridsTag; }; }; // namespace VAPoR #endif ================================================ FILE: apps/vaporgui/QColorWidget.cpp ================================================ #include "QColorWidget.h" #include #include QColorWidget::QColorWidget() { setColor(Qt::blue); setReadOnly(true); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setFixedSize(minimumSizeHint()); } QSize QColorWidget::minimumSizeHint() const { // How Qt buttons determine size // QSize fontSize = fontMetrics().size(Qt::TextShowMnemonic, QString("XXXX")); float height = QLineEdit::minimumSizeHint().height(); return QSize(height * 1.618, height); } void QColorWidget::setColor(const QColor &color) { _color = color; QPalette pal = palette(); // pal.setColor(QPalette::Background, color); pal.setColor(QPalette::Base, color); pal.setColor(QPalette::Disabled, QPalette::Base, Qt::white); setAutoFillBackground(true); setPalette(pal); } QColor QColorWidget::getColor() const { return _color; } void QColorWidget::mouseReleaseEvent(QMouseEvent *event) { QColorDialog::ColorDialogOptions options = QColorDialog::ColorDialogOptions(); if (ShowAlpha) options |= QColorDialog::ShowAlphaChannel; QColor newColor = QColorDialog::getColor(_color, nullptr, "", options); QApplication::restoreOverrideCursor(); if (newColor.isValid() && newColor != _color) { setColor(newColor); emit colorChanged(newColor); } } void QColorWidget::enterEvent(QEvent *event) { if (isEnabled()) { QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor)); setToolTip(_color.name()); } else { setToolTip(""); } } void QColorWidget::leaveEvent(QEvent *event) { QApplication::restoreOverrideCursor(); } ================================================ FILE: apps/vaporgui/QColorWidget.h ================================================ #pragma once #include #include class QStylePainter; //! \class QColorWidget //! //! Displays a color and allows the user to modify said color class QColorWidget : public QLineEdit { Q_OBJECT QColor _color; public: bool ShowAlpha = false; QColorWidget(); QSize minimumSizeHint() const; void setColor(const QColor &color); QColor getColor() const; signals: void colorChanged(QColor color); protected: void mouseReleaseEvent(QMouseEvent *event); void enterEvent(QEvent *event); void leaveEvent(QEvent *event); }; ================================================ FILE: apps/vaporgui/QCustomIconSizeProxyStyle.h ================================================ #pragma once #include class QCustomIconSizeProxyStyle : public QProxyStyle { const int _size; public: QCustomIconSizeProxyStyle(int size) : _size(size) {} virtual int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const override { if (metric == PM_SmallIconSize) return _size; else return QCommonStyle::pixelMetric(metric, option, widget); } }; ================================================ FILE: apps/vaporgui/QEnableable.h ================================================ #pragma once class QEnableableI { public: // virtual bool isEnabled() const = 0; virtual void setEnabled(bool enabled) = 0; virtual ~QEnableableI() {} }; template class QEnableable : public QEnableableI { public: QEnableable(T *o) : _o(o) {} // bool isEnabled() const override { return _o->isEnabled(); } void setEnabled(bool enabled) override { _o->setEnabled(enabled); } private: T* const _o; }; ================================================ FILE: apps/vaporgui/QIntValidatorWithFixup.cpp ================================================ #include "QIntValidatorWithFixup.h" void QIntValidatorWithFixup::fixup(QString &input) const { QIntValidator::fixup(input); // make sure the locale is correct int val = input.toInt(); if (val > top()) { val = top(); input = QString::number(val); } else if (val < bottom()) { val = bottom(); input = QString::number(val); } } ================================================ FILE: apps/vaporgui/QIntValidatorWithFixup.h ================================================ #ifndef QINTVALIDATORWITHFIXUP_H #define QINTVALIDATORWITHFIXUP_H // // This is a derived QIntValidator that implements the fixup function. // #include class QIntValidatorWithFixup : public QIntValidator { public: explicit QIntValidatorWithFixup(QObject *parent = 0) : QIntValidator(parent = 0) {} explicit QIntValidatorWithFixup(int bottom, int top, QObject *parent = 0) : QIntValidator(bottom, top, parent = 0) {} // // overload fixup() from QIntValidator // virtual void fixup(QString &input) const override; }; #endif ================================================ FILE: apps/vaporgui/QMontereySlider.h ================================================ #pragma once #include #include #include #include #include #include "math.h" class QMontereySlider : public QSlider { public: explicit QMontereySlider(Qt::Orientation orientation, QWidget *parent = nullptr) : QSlider(orientation, parent){}; explicit QMontereySlider(QWidget *parent = nullptr) : QSlider(parent) { this->setStyleSheet("\ QSlider::groove:horizontal {\ height: 8px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */ \ background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4);\ margin: 2px 0;\ }\ \ QSlider::handle:horizontal {\ background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);\ border: 1px solid #5c5c5c;\ width: 18px;\ margin: -2px 0; /* handle is placed by default on the contents rect of the groove. Expand outside the groove */ \ border-radius: 3px;\ }"); }; }; ================================================ FILE: apps/vaporgui/QPaintUtils.cpp ================================================ #include "QPaintUtils.h" #include #include #include #include QT_BEGIN_NAMESPACE extern void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0); QT_END_NAMESPACE void QPaintUtils::DropShadow(QPainter &p, QPicture &picture, float radius, QColor color) { // Why is this code so weird? // Turns out this part of Qt's API is broken (in 4.8 at least) float opacity = color.alphaF(); color.setAlphaF(1.0); QRect pictureBB = picture.boundingRect(); QRect pixmapBB = pictureBB.adjusted(-radius, -radius, radius, radius); QPixmap pixmap(pixmapBB.size()); pixmap.fill(Qt::transparent); QPainter pixmapPainter(&pixmap); pixmapPainter.setRenderHint(QPainter::Antialiasing); pixmapPainter.drawPicture(-pixmapBB.topLeft(), picture); QPixmap shadowLayer(pixmapBB.size()); shadowLayer.fill(color); shadowLayer.setMask(pixmap.mask()); QImage shadowImage = shadowLayer.toImage(); pixmap.fill(Qt::transparent); pixmapPainter.setRenderHints((QPainter::Antialiasing | QPainter::SmoothPixmapTransform)); //? qt_blurImage(&pixmapPainter, shadowImage, radius, false, false); p.setOpacity(opacity); p.drawPixmap(pixmapBB.topLeft(), pixmap); p.setOpacity(1.0); } void QPaintUtils::InnerShadow(QPainter &p, QPicture &picture, float radius, QColor color) { // Why is this code so weird? // Turns out this part of Qt's API is broken (in 4.8 at least) float opacity = color.alphaF(); color.setAlphaF(1.0); QRect pictureBB = picture.boundingRect(); QRect pixmapBB = pictureBB.adjusted(-radius, -radius, radius, radius); QPixmap pixmap(pixmapBB.size()); pixmap.fill(Qt::transparent); QPainter pixmapPainter(&pixmap); pixmapPainter.setRenderHint(QPainter::Antialiasing); pixmapPainter.drawPicture(-pixmapBB.topLeft(), picture); QPixmap shadowLayer(pixmapBB.size()); shadowLayer.fill(color); QBitmap mask = pixmap.mask(); shadowLayer.setMask(pixmap.createMaskFromColor(Qt::transparent, Qt::MaskOutColor)); QImage shadowImage = shadowLayer.toImage(); pixmap.fill(Qt::transparent); qt_blurImage(&pixmapPainter, shadowImage, radius, false, false); QPainter sp(&shadowLayer); sp.setCompositionMode(QPainter::CompositionMode_SourceOut); sp.drawPixmap(0, 0, pixmap); p.setBrush(Qt::NoBrush); p.setPen(Qt::NoPen); p.setOpacity(opacity); p.drawPixmap(pixmapBB.topLeft(), shadowLayer); p.setOpacity(1.0); } void QPaintUtils::BoxDropShadow(QPainter &p, QRect box, float radius, QColor color) { QPicture picture; QPainter pp(&picture); pp.fillRect(box, QBrush(Qt::black)); pp.end(); DropShadow(p, picture, radius, color); } void QPaintUtils::BoxInnerShadow(QPainter &p, QRect box, float radius, QColor color) { QPicture picture; QPainter pp(&picture); pp.fillRect(box, QBrush(Qt::black)); pp.end(); InnerShadow(p, picture, radius, color); } ================================================ FILE: apps/vaporgui/QPaintUtils.h ================================================ #pragma once #include class QPicture; class QPainter; class QRect; //! \namespace QPaintUtils //! Provides functionality to be used when painting a QWidget that behaves the same //! as CSS's drop-shadow and inner-shadow namespace QPaintUtils { void DropShadow(QPainter &p, QPicture &picture, float radius, QColor color = Qt::black); void InnerShadow(QPainter &p, QPicture &picture, float radius, QColor color = Qt::black); void BoxDropShadow(QPainter &p, QRect box, float radius, QColor color = Qt::black); void BoxInnerShadow(QPainter &p, QRect box, float radius, QColor color = Qt::black); } // namespace QPaintUtils ================================================ FILE: apps/vaporgui/QPushButtonWithDoubleClick.h ================================================ #pragma once class QPushButtonWithDoubleClick : public QPushButton { Q_OBJECT using QPushButton::QPushButton; void mouseDoubleClickEvent(QMouseEvent *e) { emit doubleClicked(); } signals: void doubleClicked(); }; ================================================ FILE: apps/vaporgui/QRange.cpp ================================================ #include "QRange.h" #include "ui_QRange.h" QRange::QRange(QWidget *parent) : QWidget(parent), _ui(new Ui::QRange) { _ui->setupUi(this); _ui->minSliderEdit->SetLabel(QString("Min:")); _ui->maxSliderEdit->SetLabel(QString("Max:")); connect(_ui->minSliderEdit, SIGNAL(valueChanged(double)), this, SLOT(_minChanged(double))); connect(_ui->maxSliderEdit, SIGNAL(valueChanged(double)), this, SLOT(_maxChanged(double))); connect(_ui->minSliderEdit, SIGNAL(valueChanged(int)), this, SLOT(_minChanged(int))); connect(_ui->maxSliderEdit, SIGNAL(valueChanged(int)), this, SLOT(_maxChanged(int))); } QRange::~QRange() { delete _ui; } void QRange::SetExtents(double min, double max) { _ui->minSliderEdit->SetExtents(min, max); _ui->maxSliderEdit->SetExtents(min, max); _ui->minSliderEdit->SetValue(min); _ui->maxSliderEdit->SetValue(max); } void QRange::GetValue(double &min, double &max) { min = _ui->minSliderEdit->GetCurrentValue(); max = _ui->maxSliderEdit->GetCurrentValue(); } void QRange::_minChanged(double value) { if (value > _ui->maxSliderEdit->GetCurrentValue()) _ui->maxSliderEdit->SetValue(value); emit rangeChanged(); } void QRange::_maxChanged(double value) { if (value < _ui->minSliderEdit->GetCurrentValue()) _ui->minSliderEdit->SetValue(value); emit rangeChanged(); } void QRange::_minChanged(int value) { if ((double)value > _ui->maxSliderEdit->GetCurrentValue()) _ui->maxSliderEdit->SetValue((double)value); emit rangeChanged(); } void QRange::_maxChanged(int value) { if ((double)value < _ui->minSliderEdit->GetCurrentValue()) _ui->minSliderEdit->SetValue((double)value); emit rangeChanged(); } void QRange::SetMainLabel(const QString &label) { _ui->mainLabel->setText(label); } void QRange::SetDecimals(int dec) { _ui->minSliderEdit->SetDecimals(dec); _ui->maxSliderEdit->SetDecimals(dec); } void QRange::SetIntType(bool val) { _ui->minSliderEdit->SetIntType(val); _ui->maxSliderEdit->SetIntType(val); } void QRange::SetValue(double smallVal, double bigVal) { _ui->minSliderEdit->SetValue(smallVal); _ui->maxSliderEdit->SetValue(bigVal); } ================================================ FILE: apps/vaporgui/QRange.h ================================================ #ifndef QRANGE_H #define QRANGE_H #include namespace Ui { class QRange; } // Note: // One might think it's a good idea for this QRange class to use a RangeCombo. // But it violates the principles of object oriented programming. // That's because a RangeCombo requires two Combos to keep them in sync. // However, as a private member, Combo is hidden by QSliderEdit, and // QRange simply cannot access Combos. class QRange : public QWidget { Q_OBJECT public: explicit QRange(QWidget *parent = 0); ~QRange(); void SetExtents(double min, double max); void GetValue(double &smallVal, double &bigVal); void SetValue(double smallVal, double bigVal); void SetMainLabel(const QString &); void SetDecimals(int dec); // how many digits after the decimal point void SetIntType(bool); // how many digits after the decimal point signals: void rangeChanged(); private slots: void _minChanged(double); void _maxChanged(double); void _minChanged(int); void _maxChanged(int); private: Ui::QRange *_ui; }; #endif // QRANGE_H ================================================ FILE: apps/vaporgui/QRange.ui ================================================ QRange 0 0 527 126 Form QFrame::StyledPanel QFrame::Raised A Range QSliderEdit QWidget

QSliderEdit.h
1 ================================================ FILE: apps/vaporgui/QRangeSlider.cpp ================================================ #include "QRangeSlider.h" #include #include #include #include #include // An arbitrary large number as the number of stops for a continuous qslider #define QT_STOPS 1000000000 // Dragging the selected region currently requires AbsoluteSetButtons to be enabled // For some OS styles, such as linux, this is disabled by default so we need to manually enable it class QForceAbsoluteSetButtonsEnabledStyle : public QProxyStyle { public: using QProxyStyle::QProxyStyle; int styleHint(QStyle::StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const { if (hint == QStyle::SH_Slider_AbsoluteSetButtons) return Qt::LeftButton; return QProxyStyle::styleHint(hint, option, widget, returnData); } }; QRangeSlider::QRangeSlider() : QRangeSlider(Qt::Orientation::Horizontal) {} QRangeSlider::QRangeSlider(Qt::Orientation orientation) : QSlider(orientation) { _position[0] = 0; _value[0] = 0; _position[1] = QT_STOPS - 1; _value[1] = QT_STOPS - 1; this->setRange(0, QT_STOPS); this->setTracking(true); this->QSlider::setStyle(new QForceAbsoluteSetButtonsEnabledStyle(style())); // Fix for Qt bug https://bugreports.qt.io/browse/QTBUG-98093 // Apply a style sheet to QSlider to make it work on OSX Monterey // Note: Inheriting from QMontereySlider does not work, so we manually apply the styleSheet #ifdef Darwin this->setStyleSheet("\ QSlider::groove:horizontal {\ background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4);\ height: 8px; \ margin: 2px 0;\ }\ QSlider::handle:horizontal {\ background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);\ border: 1px solid #5c5c5c;\ width: 18px;\ margin: -2px 0; \ border-radius: 3px;\ }"); #endif } QSize QRangeSlider::minimumSizeHint() const { return QSlider::minimumSizeHint(); } void QRangeSlider::SetValue(float min, float max) { _isOutOfBounds[0] = false; _isOutOfBounds[1] = false; if (min < 0 || min > 1) { _isOutOfBounds[0] = true; _outOfBoundValue[0] = min; min = 0; } if (max < 0 || max > 1) { _isOutOfBounds[1] = true; _outOfBoundValue[1] = max; max = 1; } _position[0] = min * (QT_STOPS - 1); _value[0] = min * (QT_STOPS - 1); _position[1] = max * (QT_STOPS - 1); _value[1] = max * (QT_STOPS - 1); update(); } void QRangeSlider::paintEvent(QPaintEvent *event) { QStylePainter p(this); paintTrack(p); int drawId = (_lastSelectedControl + 1) % 2; paintHandle(p, drawId); drawId = (drawId + 1) % 2; paintHandle(p, drawId); } void QRangeSlider::paintHandle(QStylePainter &p, int i) { QStyleOptionSlider option; this->initStyleOption(&option); option.subControls = QStyle::SC_SliderHandle; option.sliderValue = _value[i]; option.sliderPosition = _position[i]; if (_isOutOfBounds[i]) { option.state &= ~QStyle::State_Enabled; } if (isSliderDown(i)) { option.activeSubControls = QStyle::SC_SliderHandle; option.state |= QStyle::State_Sunken; } p.drawComplexControl(QStyle::CC_Slider, option); } void QRangeSlider::paintTrack(QStylePainter &p) { QStyleOptionSlider option; this->initStyleOption(&option); option.sliderPosition = 0; option.subControls = QStyle::SC_SliderGroove; p.drawComplexControl(QStyle::CC_Slider, option); QRect groove = this->style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderGroove, this); groove.adjust(0, 0, -1, 0); QPixmap pixmap(width(), height()); pixmap.fill(Qt::transparent); QStylePainter pixStylePainter(&pixmap, this); pixStylePainter.drawComplexControl(QStyle::CC_Slider, option); option.sliderPosition = _position[0]; const QRect left = style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, this); option.sliderPosition = _position[1]; const QRect right = style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, this); QRect highlight(0, 0, width(), height()); if (option.orientation == Qt::Horizontal) { highlight.setLeft(left.center().x()); highlight.setRight(right.center().x()); } else { highlight.setBottom(left.center().y()); highlight.setTop(right.center().y()); } p.setClipRegion(QRegion(pixmap.mask())); p.fillRect(highlight, QPalette::Highlight); p.setClipRegion(QRegion(), Qt::NoClip); } void QRangeSlider::mousePressEvent(QMouseEvent *event) { for (int i = 0, id = _lastSelectedControl; i < 2; i++, id = (id + 1) % 2) { if (doesHandleContainPixel(id, event->pos())) { _grabbedControl = id; _lastSelectedControl = id; _isOutOfBounds[id] = false; setValue(_value[id]); QSlider::mousePressEvent(event); emit ValueChangedBegin(); return; } } if (doesGrooveContainPixel(event->pos())) { setValue(-QT_STOPS); QSlider::mousePressEvent(event); int selectedPosition = sliderPosition(); if (selectedPosition > _position[0] && selectedPosition < _position[1]) { _grabbedBar = true; _grabbedBarStartPosition = selectedPosition; _grabbedBarPosition = selectedPosition; _grabbedBarControlStartPositions[0] = _position[0]; _grabbedBarControlStartPositions[1] = _position[1]; _isOutOfBounds[0] = _isOutOfBounds[1] = false; emit ValueChangedBegin(); } } } void QRangeSlider::mouseReleaseEvent(QMouseEvent *event) { QSlider::mouseReleaseEvent(event); if (_grabbedControl >= 0 || _grabbedBar) emitValueChanged(); _grabbedControl = -1; _grabbedBar = false; } void QRangeSlider::mouseMoveEvent(QMouseEvent *event) { if (_grabbedControl >= 0) { setValue(_value[_grabbedControl]); QSlider::mouseMoveEvent(event); if (_grabbedControl == 0) if (sliderPosition() > _position[1]) swapSliders(); if (_grabbedControl == 1) if (sliderPosition() < _position[0]) swapSliders(); _value[_grabbedControl] = value(); _position[_grabbedControl] = sliderPosition(); _isOutOfBounds[_grabbedControl] = false; if (hasTracking()) emitValueChanged(true); } if (_grabbedBar) { setValue(_grabbedBarPosition); QSlider::mouseMoveEvent(event); _grabbedBarPosition = sliderPosition(); int diff = _grabbedBarPosition - _grabbedBarStartPosition; for (int i = 0; i < 2; i++) { _position[i] = _grabbedBarControlStartPositions[i] + diff; _position[i] = _position[i] < 0 ? 0 : _position[i]; _position[i] = _position[i] > QT_STOPS - 1 ? QT_STOPS - 1 : _position[i]; _isOutOfBounds[i] = false; if (hasTracking()) _value[i] = _position[i]; } if (hasTracking()) emitValueChanged(true); } } bool QRangeSlider::doesHandleContainPixel(int handle, const QPoint &pixel) const { QStyleOptionSlider option; initStyleOption(&option); option.sliderValue = _value[handle]; option.sliderPosition = _position[handle]; QStyle::SubControl selected = style()->hitTestComplexControl(QStyle::CC_Slider, &option, pixel, this); return selected == QStyle::SC_SliderHandle; } bool QRangeSlider::doesGrooveContainPixel(const QPoint &pixel) const { QStyleOptionSlider option; initStyleOption(&option); option.sliderValue = _value[0]; option.sliderPosition = _position[0]; QStyle::SubControl selected = style()->hitTestComplexControl(QStyle::CC_Slider, &option, pixel, this); return selected == QStyle::SC_SliderGroove; } bool QRangeSlider::isSliderDown(int i) const { return _grabbedControl == i; } void QRangeSlider::swapSliders() { std::swap(_value[0], _value[1]); std::swap(_position[0], _position[1]); std::swap(_isOutOfBounds[0], _isOutOfBounds[1]); std::swap(_outOfBoundValue[0], _outOfBoundValue[1]); _lastSelectedControl = (_lastSelectedControl + 1) % 2; switch (_grabbedControl) { case 0: _grabbedControl = 1; break; case 1: _grabbedControl = 0; break; case -1: break; } } void QRangeSlider::emitValueChanged(bool intermediate) { float left = _isOutOfBounds[0] ? _outOfBoundValue[0] : _value[0] / (float)QT_STOPS; float right = _isOutOfBounds[1] ? _outOfBoundValue[1] : _value[1] / (float)QT_STOPS; if (intermediate) emit ValueChangedIntermediate(left, right); else emit ValueChanged(left, right); } ================================================ FILE: apps/vaporgui/QRangeSlider.h ================================================ #pragma once #include class QStylePainter; //! \class QRangeSlider //! It is the same as a QSlider except it has two independent slider controls class QRangeSlider : public QSlider { Q_OBJECT public: QRangeSlider(); QRangeSlider(Qt::Orientation orientation); QSize minimumSizeHint() const; void SetValue(float min, float max); void setStyle(QStyle *style) = delete; signals: //! User began to change the value. void ValueChangedBegin(); //! User changed the value but they have not finalized it. void ValueChangedIntermediate(float min, float max); //! User finalized changing the value. void ValueChanged(float min, float max); protected: void paintEvent(QPaintEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); // void mouseDoubleClickEvent(QMouseEvent *event); private: int _position[2]; int _value[2]; bool _isOutOfBounds[2] = {false}; float _outOfBoundValue[2]; int _grabbedControl = -1; int _lastSelectedControl = 0; bool _grabbedBar = false; int _grabbedBarPosition; int _grabbedBarStartPosition; int _grabbedBarControlStartPositions[2]; void paintHandle(QStylePainter &p, int i); void paintTrack(QStylePainter &p); bool doesHandleContainPixel(int handle, const QPoint &pixel) const; bool doesGrooveContainPixel(const QPoint &pixel) const; bool isSliderDown(int i) const; void swapSliders(); void emitValueChanged(bool intermediate = false); }; ================================================ FILE: apps/vaporgui/QRangeSliderTextCombo.cpp ================================================ #include "QRangeSliderTextCombo.h" #include #include "VDoubleValidator.h" #include #include #include #include #include "VDoubleLineEdit.h" #include "VDoubleRangeMenu.h" QRangeSliderTextCombo::QRangeSliderTextCombo() { QBoxLayout *layout = new QHBoxLayout; layout->setMargin(0); layout->setSpacing(0); setLayout(layout); layout->addWidget(_leftText = new VDoubleLineEdit, 20); layout->addWidget(_slider = new QRangeSlider, 60); layout->addWidget(_rightText = new VDoubleLineEdit, 20); _min = 0; _max = 1; SetValue(0, 1); connect(_slider, SIGNAL(ValueChanged(float, float)), this, SLOT(sliderChanged(float, float))); connect(_slider, SIGNAL(ValueChangedIntermediate(float, float)), this, SLOT(sliderChangedIntermediate(float, float))); connect(_slider, SIGNAL(ValueChangedBegin()), this, SIGNAL(ValueChangedBegin())); connect(_leftText, SIGNAL(ValueChanged(double)), this, SLOT(leftTextChanged(double))); connect(_rightText, SIGNAL(ValueChanged(double)), this, SLOT(rightTextChanged(double))); _leftText->RemoveContextMenu(); _rightText->RemoveContextMenu(); _leftText->SetAutoTooltip(false); _rightText->SetAutoTooltip(false); _menu = new VDoubleRangeMenu(this, _leftText->GetSciNotation(), _leftText->GetNumDigits(), _min, _max, _allowCustomRange); connect(_menu, &VDoubleRangeMenu::MinChanged, this, &QRangeSliderTextCombo::minChanged); connect(_menu, &VDoubleRangeMenu::MaxChanged, this, &QRangeSliderTextCombo::maxChanged); connect(_menu, &VDoubleRangeMenu::SciNotationChanged, _leftText, &VDoubleLineEdit::SetSciNotation); connect(_menu, &VDoubleRangeMenu::SciNotationChanged, _rightText, &VDoubleLineEdit::SetSciNotation); connect(_menu, &VDoubleRangeMenu::DecimalDigitsChanged, _leftText, &VDoubleLineEdit::SetNumDigits); connect(_menu, &VDoubleRangeMenu::DecimalDigitsChanged, _rightText, &VDoubleLineEdit::SetNumDigits); setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showContextMenu(const QPoint &))); } void QRangeSliderTextCombo::SetRange(float min, float max) { if (min <= max) { _min = min; _max = max; } SetValue(_left, _right); _menu->SetMinimum(_min); _menu->SetMaximum(_max); setToolTip(QString::fromStdString("Min: " + std::to_string(_min) + "\n" + "Max: " + std::to_string(_max))); } void QRangeSliderTextCombo::SetValue(float left, float right) { if (left > right) std::swap(left, right); if (!_allowCustomRange) { left = std::max(_min, left); right = std::min(_max, right); } _left = left; _right = right; setTextboxes(left, right); if (std::abs(_max - _min) < FLT_EPSILON) _slider->SetValue(0, 1); else _slider->SetValue((left - _min) / (_max - _min), (right - _min) / (_max - _min)); } void QRangeSliderTextCombo::SetNumDigits(int digits) { _leftText->SetNumDigits(digits); _rightText->SetNumDigits(digits); } void QRangeSliderTextCombo::AllowCustomRange() { if (_allowCustomRange) return; _allowCustomRange = true; _menu->AllowUserRange(); } void QRangeSliderTextCombo::setTextboxes(float left, float right) { _leftText->SetValueDouble(left); _rightText->SetValueDouble(right); } float QRangeSliderTextCombo::getRange() const { float range = _max - _min; if (range < FLT_EPSILON) return 1; else return range; } void QRangeSliderTextCombo::sliderChangedIntermediate(float leftNorm, float rightNorm) { float left = (_max - _min) * leftNorm + _min; float right = (_max - _min) * rightNorm + _min; setTextboxes(left, right); emit ValueChangedIntermediate(left, right); } void QRangeSliderTextCombo::sliderChanged(float leftNorm, float rightNorm) { float left = (_max - _min) * leftNorm + _min; float right = (_max - _min) * rightNorm + _min; SetValue(left, right); emit ValueChanged(_left, _right); } void QRangeSliderTextCombo::leftTextChanged(double left) { SetValue(left, _right); emit ValueChanged(_left, _right); } void QRangeSliderTextCombo::rightTextChanged(double right) { SetValue(_left, right); emit ValueChanged(_left, _right); } void QRangeSliderTextCombo::minChanged(double min) { SetRange(min, _max); emit RangeChanged(_min, _max); } void QRangeSliderTextCombo::maxChanged(double max) { SetRange(_min, max); emit RangeChanged(_min, _max); } void QRangeSliderTextCombo::showContextMenu(const QPoint &pos) { QPoint globalPos = mapToGlobal(pos); _menu->exec(globalPos); } ================================================ FILE: apps/vaporgui/QRangeSliderTextCombo.h ================================================ #pragma once #include "QRangeSlider.h" #include #include class VDoubleLineEdit; class VDoubleRangeMenu; //! \class QRangeSliderTextCombo //! Combines a QRangeSlider with two text inputs that represent the values of //! the min/max sliders. The two are automatically synced. class QRangeSliderTextCombo : public QWidget { Q_OBJECT QRangeSlider * _slider; VDoubleLineEdit * _leftText; VDoubleLineEdit * _rightText; VDoubleRangeMenu *_menu; float _min, _max; float _left, _right; bool _allowCustomRange = false; public: QRangeSliderTextCombo(); void SetRange(float min, float max); void SetValue(float left, float right); //! Allows the user to input values outside of the range and allows them to change the range. void AllowCustomRange(); void SetNumDigits(int digits); private: void setTextboxes(float left, float right); float getRange() const; private slots: void sliderChangedIntermediate(float min, float max); void sliderChanged(float min, float max); void leftTextChanged(double left); void rightTextChanged(double right); void minChanged(double min); void maxChanged(double max); void showContextMenu(const QPoint &pos); signals: //! User began to change the value. void ValueChangedBegin(); //! User finalized changing the value. void ValueChanged(float min, float max); //! User changed the value but they have not finalized it. void ValueChangedIntermediate(float min, float max); void RangeChanged(float min, float max); void RangeDefaultRequested(); }; ================================================ FILE: apps/vaporgui/QSinglePoint.cpp ================================================ #include "QSinglePoint.h" #include "ui_QSinglePoint.h" // for debug #include #include "vapor/VAssert.h" QSinglePoint::QSinglePoint(QWidget *parent) : QWidget(parent), _ui(new Ui::QSinglePoint) { _ui->setupUi(this); SetDimensionality(3); // default to have 3 dimensions _ui->xSliderEdit->SetLabel(QString("X")); _ui->ySliderEdit->SetLabel(QString("Y")); _ui->zSliderEdit->SetLabel(QString("Z")); _ui->tSliderEdit->SetLabel(QString("T")); // Connect signals and slots connect(_ui->xSliderEdit, SIGNAL(valueChanged(double)), this, SLOT(_coordinateChanged(double))); connect(_ui->ySliderEdit, SIGNAL(valueChanged(double)), this, SLOT(_coordinateChanged(double))); connect(_ui->zSliderEdit, SIGNAL(valueChanged(double)), this, SLOT(_coordinateChanged(double))); connect(_ui->tSliderEdit, SIGNAL(valueChanged(double)), this, SLOT(_coordinateChanged(double))); } QSinglePoint::~QSinglePoint() { delete _ui; } void QSinglePoint::_coordinateChanged(double value) // value isn't used though { emit pointUpdated(); } void QSinglePoint::SetDimensionality(int dim) { VAssert(dim >= 2 && dim <= 4); _dimensionality = dim; _ui->xSliderEdit->setVisible(true); _ui->ySliderEdit->setVisible(true); _ui->zSliderEdit->setVisible(false); _ui->tSliderEdit->setVisible(false); if (dim >= 3) _ui->zSliderEdit->setVisible(true); if (dim == 4) _ui->tSliderEdit->setVisible(true); } int QSinglePoint::GetDimensionality() { return _dimensionality; } void QSinglePoint::GetCurrentPoint(std::vector &point) { point.clear(); point.push_back(_ui->xSliderEdit->GetCurrentValue()); point.push_back(_ui->ySliderEdit->GetCurrentValue()); if (_dimensionality >= 3) point.push_back(_ui->zSliderEdit->GetCurrentValue()); if (_dimensionality >= 4) point.push_back(_ui->tSliderEdit->GetCurrentValue()); } void QSinglePoint::SetExtents(const std::vector &min, const std::vector &max) { _ui->xSliderEdit->SetExtents(min[0], max[0]); _ui->ySliderEdit->SetExtents(min[1], max[1]); if (_dimensionality >= 3) _ui->zSliderEdit->SetExtents(min[2], max[2]); if (_dimensionality >= 4) _ui->tSliderEdit->SetExtents(min[3], max[3]); } void QSinglePoint::SetMainLabel(const QString &label) { _ui->mainLabel->setText(label); } void QSinglePoint::SetDecimals(int dec) { _ui->xSliderEdit->SetDecimals(dec); _ui->ySliderEdit->SetDecimals(dec); _ui->zSliderEdit->SetDecimals(dec); _ui->tSliderEdit->SetDecimals(dec); } void QSinglePoint::SetValue(const std::vector &point) { _ui->xSliderEdit->SetValue(point[0]); _ui->ySliderEdit->SetValue(point[1]); if (_dimensionality >= 3) _ui->zSliderEdit->SetValue(point[2]); if (_dimensionality >= 4) _ui->tSliderEdit->SetValue(point[3]); } ================================================ FILE: apps/vaporgui/QSinglePoint.h ================================================ #ifndef QSINGLEPOINT_H #define QSINGLEPOINT_H #include namespace Ui { class QSinglePoint; } class QSinglePoint : public QWidget { Q_OBJECT public: explicit QSinglePoint(QWidget *parent = 0); ~QSinglePoint(); void SetExtents(const std::vector &min, const std::vector &max); void SetDimensionality(int); int GetDimensionality(); void GetCurrentPoint(std::vector &); void SetMainLabel(const QString &); void SetDecimals(int dec); // how many digits after the decimal point void SetValue(const std::vector &); signals: void pointUpdated(); private slots: void _coordinateChanged(double); private: Ui::QSinglePoint *_ui; int _dimensionality; }; #endif // QSINGLEPOINT_H ================================================ FILE: apps/vaporgui/QSinglePoint.ui ================================================ QSinglePoint 0 0 400 300 Form QFrame::StyledPanel QFrame::Raised 16777215 35 Single Point QSliderEdit QWidget
QSliderEdit.h
1
================================================ FILE: apps/vaporgui/QSliderEdit.cpp ================================================ #include "QSliderEdit.h" #include "ui_QSliderEdit.h" #include #include #include "vapor/VAssert.h" QSliderEdit::QSliderEdit(QWidget *parent) : QWidget(parent), _ui(new Ui::QSliderEdit) { _ui->setupUi(this); _combo = new Combo(_ui->myLineEdit, _ui->mySlider); _combo->SetPrecision(5); connect(_combo, SIGNAL(valueChanged(double)), this, SLOT(_comboValueChanged(double))); connect(_combo, SIGNAL(valueChanged(int)), this, SLOT(_comboValueChanged(int))); } QSliderEdit::~QSliderEdit() { delete _combo; delete _ui; } void QSliderEdit::SetLabel(const QString &text) { _ui->myLabel->setText(text); } void QSliderEdit::SetExtents(double min, double max) { double value = GetCurrentValue(); _combo->Update(min, max, value); } void QSliderEdit::SetDecimals(int dec) { _combo->SetPrecision(dec); } double QSliderEdit::GetCurrentValue() { return _combo->GetValue(); } void QSliderEdit::SetValue(double value) { _combo->SetSliderLineEdit(value); } void QSliderEdit::_comboValueChanged(double val) { emit valueChanged(val); } void QSliderEdit::_comboValueChanged(int val) { emit valueChanged(val); } void QSliderEdit::SetIntType(bool val) { _combo->SetIntType(val); } ================================================ FILE: apps/vaporgui/QSliderEdit.h ================================================ #ifndef QSLIDEREDIT_H #define QSLIDEREDIT_H #include #include #include "Combo.h" namespace Ui { class QSliderEdit; } class QSliderEdit : public QWidget { Q_OBJECT public: explicit QSliderEdit(QWidget *parent = 0); ~QSliderEdit(); void SetLabel(const QString &text); void SetDecimals(int dec); // how many digits after the decimal point void SetExtents(double min, double max); double GetCurrentValue(); void SetValue(double); void SetIntType(bool); // default is false, which means double type signals: // This is the signal a QSliderEdit emits. void valueChanged(double); void valueChanged(int); private slots: void _comboValueChanged(double); void _comboValueChanged(int); private: Ui::QSliderEdit *_ui; Combo * _combo; // keeps the slider and lineEdit in sync }; #endif // QSLIDEREDIT_H ================================================ FILE: apps/vaporgui/QSliderEdit.ui ================================================ QSliderEdit 0 0 373 25 0 0 Form -1 0 0 0 0 0 0 TextLabel Qt::Horizontal 40 20 0 0 0 0 100 16777215 Qt::Horizontal 0 0 0 0 100 16777215 QMontereySlider QSlider
QMontereySlider.h
valueChanged(double)
================================================ FILE: apps/vaporgui/QtVizWinGLContextManager.cpp ================================================ #include "QtVizWinGLContextManager.h" #include "VizWinMgr.h" #include "VizWin.h" void QtVizWinGLContextManager::Activate(const string &visualizerName) { _vizWinMgr->Get(visualizerName)->makeCurrent(); } ================================================ FILE: apps/vaporgui/QtVizWinGLContextManager.h ================================================ #pragma once #include class VizWinMgr; class VizWin; class QtVizWinGLContextManager : public VAPoR::VisualizerGLContextManager { VizWinMgr *_vizWinMgr; public: QtVizWinGLContextManager(VizWinMgr *vizWinMgr) : _vizWinMgr(vizWinMgr) {} void Activate(const string &visualizerName) override; }; ================================================ FILE: apps/vaporgui/RangeCombos.cpp ================================================ #include #include #include "vapor/VAssert.h" using namespace std; #include "RangeCombos.h" ////////////////////////////////////////////////////// // // RangeCombo // ////////////////////////////////////////////////////// RangeCombo::RangeCombo(Combo *minWidget, Combo *maxWidget) { _minWidget = minWidget; _maxWidget = maxWidget; connect(_minWidget, SIGNAL(valueChanged(double)), this, SLOT(setValueMin(double))); connect(_maxWidget, SIGNAL(valueChanged(double)), this, SLOT(setValueMax(double))); } void RangeCombo::Update(double minValid, double maxValid, double minValue, double maxValue) { _minWidget->Update(minValid, maxValid, minValue); _maxWidget->Update(minValid, maxValid, maxValue); } void RangeCombo::setValueMin(double minValue) { double maxValue = _maxWidget->GetValue(); // If minValue is greater than maxValue we change the maxValue to // minValue // if (minValue > maxValue) { maxValue = minValue; _maxWidget->SetSliderLineEdit(maxValue); } emit valueChanged(minValue, maxValue); } void RangeCombo::setValueMax(double maxValue) { double minValue = _minWidget->GetValue(); if (maxValue < minValue) { minValue = maxValue; _minWidget->SetSliderLineEdit(minValue); } emit valueChanged(minValue, maxValue); } ================================================ FILE: apps/vaporgui/RangeCombos.h ================================================ #ifdef WIN32 #pragma warning(disable : 4100) #endif #ifndef RANGECOMBOS_H #define RANGECOMBOS_H #include #include "Combo.h" // Fix for Qt bug https://bugreports.qt.io/browse/QTBUG-98093 // Apply a style sheet to QSlider to make it work on OSX Monterey #ifdef Darwin #include "QMontereySlider.h" #define QSlider QMontereySlider #endif QT_BEGIN_NAMESPACE class QComboBox; class QGroupBox; class QLineEdit; class QSlider; class QValidator; QT_END_NAMESPACE // // class RangeCombo // // This class manages a pair of Combo objects, one for // a minimum value and one for a maximum value. The class ensures that // the minimum is always less than or equal to the maximum by making // adjustments as necessary. // class RangeCombo : public QWidget { Q_OBJECT public: RangeCombo(Combo *minWidget, Combo *maxWidget); // This method must be called whenever the minimax or maximum allowable // valid value changes, or the current minimum or maximum value // is changed externally. I.e. Update() provides a means to change // the internal state of the class. If minValid > maxValid, maxValid // will be set to minValid. If minValue or maxValid is outside of // minValid and maxValid it will be set to minValid. if minValue is // greater than maxValue, maxValue will be set to minValue // void Update(double minValid, double maxValid, double minValue, double maxValue); QSlider * GetSliderMin() const { return (_minWidget->GetSlider()); }; QLineEdit *GetLineEditMin() const { return (_minWidget->GetLineEdit()); }; QSlider * GetSliderMax() const { return (_maxWidget->GetSlider()); }; QLineEdit *GetLineEditMax() const { return (_maxWidget->GetLineEdit()); }; public slots: void setValueMin(double); void setValueMax(double); signals: void valueChanged(double minValue, double maxValue); private: Combo *_minWidget; Combo *_maxWidget; }; #endif ================================================ FILE: apps/vaporgui/RenderEventRouter.cpp ================================================ #include #include #include #include "RenderEventRouter.h" #include #include #include #include using namespace VAPoR; RenderParams *RenderEventRouter::GetActiveParams() const { VAssert(!_instName.empty()); ParamsMgr *paramsMgr = _controlExec->GetParamsMgr(); string winName, dataSetName, paramsType; bool status = paramsMgr->RenderParamsLookup(_instName, winName, dataSetName, paramsType); if (!status) return nullptr; string renderType = RendererFactory::Instance()->GetRenderClassFromParamsClass(paramsType); return (_controlExec->GetRenderParams(winName, dataSetName, renderType, _instName)); } DataMgr *RenderEventRouter::GetActiveDataMgr() const { VAssert(!_instName.empty()); ParamsMgr *paramsMgr = _controlExec->GetParamsMgr(); string winName, dataSetName, paramsType; bool status = paramsMgr->RenderParamsLookup(_instName, winName, dataSetName, paramsType); VAssert(status); DataStatus *dataStatus = _controlExec->GetDataStatus(); DataMgr * dataMgr = dataStatus->GetDataMgr(dataSetName); VAssert(dataMgr); return (dataMgr); } string RenderEventRouter::GetSmallIconImagePath() const { string imageName = _getSmallIconImagePath(); if (imageName.empty()) return (imageName); return (GetSharePath("images/" + imageName)); } string RenderEventRouter::GetIconImagePath() const { string imageName = _getIconImagePath(); if (imageName.empty()) return (imageName); return (GetSharePath("images/" + imageName)); } ////////////////////////////////////////////////////////////////////////// // // RenderEventRouterFactory Class // ///////////////////////////////////////////////////////////////////////// RenderEventRouter *RenderEventRouterFactory::CreateInstance(string className, QWidget *parent, VAPoR::ControlExec *ce) { RenderEventRouter *instance = NULL; auto it = _factoryFunctionRegistry.find(className); if (it != _factoryFunctionRegistry.end()) instance = it->second(parent, ce); return instance; } vector RenderEventRouterFactory::GetFactoryNames() const { vector names; map>::const_iterator itr; for (itr = _factoryFunctionRegistry.begin(); itr != _factoryFunctionRegistry.end(); ++itr) { names.push_back(itr->first); } return (names); } ================================================ FILE: apps/vaporgui/RenderEventRouter.h ================================================ #pragma once #include "VaporFwd.h" #include "Updatable.h" #include #include #include using std::vector; using std::string; using std::function; class RenderEventRouter : public Updatable { public: RenderEventRouter(ControlExec *ce) : _controlExec(ce) {} virtual ~RenderEventRouter() {} void SetActive(string instName) { _instName = instName; } virtual string GetType() const = 0; virtual bool Supports2DVariables() const = 0; virtual bool Supports3DVariables() const = 0; virtual bool SupportsParticleVariables() const { return false; } VAPoR::RenderParams *GetActiveParams() const; VAPoR::DataMgr *GetActiveDataMgr() const; string GetDescription() const { return _getDescription(); } string GetSmallIconImagePath() const; string GetIconImagePath() const; protected: ControlExec *_controlExec; virtual string _getDescription() const = 0; virtual string _getSmallIconImagePath() const = 0; virtual string _getIconImagePath() const = 0; private: string _instName; }; ////////////////////////////////////////////////////////////////////////// // // RenderEventRouterFactory Class // ///////////////////////////////////////////////////////////////////////// class RenderEventRouterFactory { public: static RenderEventRouterFactory *Instance() { static RenderEventRouterFactory instance; return &instance; } void RegisterFactoryFunction(string name, function classFactoryFunction) { _factoryFunctionRegistry[name] = classFactoryFunction; } RenderEventRouter *CreateInstance(string classType, QWidget *, VAPoR::ControlExec *); vector GetFactoryNames() const; private: std::map> _factoryFunctionRegistry; }; ////////////////////////////////////////////////////////////////////////// // // Register RenderEventRouter derived class with: // // static RenderEventRouterRegistrar registrar("myclassname"); // // where 'RERClass' is a class derived from 'RenderEventRouter', and // "myclassname" is the name of the class // ///////////////////////////////////////////////////////////////////////// template class RenderEventRouterRegistrar { public: RenderEventRouterRegistrar(string classType) { RenderEventRouterFactory::Instance()->RegisterFactoryFunction(classType, [](QWidget *parent, VAPoR::ControlExec *ce) -> RenderEventRouter * { return new T(parent, ce); }); } }; ================================================ FILE: apps/vaporgui/RenderEventRouterGUI.cpp ================================================ #include "RenderEventRouterGUI.h" #include "UWidget.h" #include #include "VContainer.h" #include const std::string RenderEventRouterGUI::VariablesTabName = "Variables"; const std::string RenderEventRouterGUI::AppearanceTabName = "Appearance"; const std::string RenderEventRouterGUI::GeometryTabName = "Geometry"; const std::string RenderEventRouterGUI::ColorbarTabName = "Colorbar"; RenderEventRouterGUI::RenderEventRouterGUI(VAPoR::ControlExec *ce, string paramsType) : RenderEventRouter(ce) { connect(this, &QTabWidget::currentChanged, this, &RenderEventRouterGUI::tabChanged); } QWidget *RenderEventRouterGUI::AddSubtab(string title, UWidget *subtab) { VContainer *container = new VContainer(subtab); container->AddBottomStretch(); container->SetPadding(0, 6, 0, 0); QScrollArea *scrollArea = new QScrollArea; scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); scrollArea->setWidget(container); scrollArea->setWidgetResizable(true); addTab(scrollArea, QString::fromStdString(title)); _subtabs.push_back(subtab); return scrollArea; } void RenderEventRouterGUI::Update() { auto *params = GetActiveParams(); auto *paramsMgr = _controlExec->GetParamsMgr(); auto *dataMgr = GetActiveDataMgr(); if (!(params && paramsMgr && dataMgr)) return; auto gp = getGUIStateParams(); bool hasTab = false; const auto activeTab = QString::fromStdString(gp->ActiveTab()); for (int i = 0; i <= count(); i++) { if (activeTab == tabText(i)) { hasTab = true; setTab(i); break; } } if (!hasTab) { setTab(0); } for (ParamsUpdatable *subtab : _subtabs) subtab->Update(params, paramsMgr, dataMgr); } void RenderEventRouterGUI::setTab(int i) { blockSignals(true); setCurrentIndex(i); blockSignals(false); } void RenderEventRouterGUI::tabChanged(int i) { getGUIStateParams()->SetActiveTab(tabText(i).toStdString()); } GUIStateParams *RenderEventRouterGUI::getGUIStateParams() const { return (GUIStateParams *)_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()); } ================================================ FILE: apps/vaporgui/RenderEventRouterGUI.h ================================================ #pragma once #include "RenderEventRouter.h" #include #include class ParamsUpdatable; class UWidget; //! \class RenderEventRouterGUI //! \ingroup Public_GUI //! \brief Tab manager for renderer subtabs //! \author Stas Jaroszynski class RenderEventRouterGUI : public QTabWidget, public RenderEventRouter { Q_OBJECT vector _subtabs; public: static const std::string VariablesTabName; static const std::string AppearanceTabName; static const std::string GeometryTabName; static const std::string ColorbarTabName; RenderEventRouterGUI(VAPoR::ControlExec *ce, string paramsType); QWidget *AddSubtab(string title, UWidget *subtab); QWidget *AddVariablesSubtab(UWidget *subtab) { return AddSubtab(VariablesTabName, subtab); } QWidget *AddAppearanceSubtab(UWidget *subtab) { return AddSubtab(AppearanceTabName, subtab); } QWidget *AddGeometrySubtab(UWidget *subtab) { return AddSubtab(GeometryTabName, subtab); } QWidget *AddColorbarSubtab(UWidget *subtab) { return AddSubtab(ColorbarTabName, subtab); } protected: void Update() override; private: void setTab(int i); void tabChanged(int i); GUIStateParams *getGUIStateParams() const; }; ================================================ FILE: apps/vaporgui/RenderHolder.cpp ================================================ // * // Copyright (C) 2014 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: RenderHolder.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: October 2014 // // Description: Implements the RenderHolder class #include "vapor/VAssert.h" #include #include #include #include #include #include #include #include #include #include "qdialog.h" #include "ui_NewRendererDialog.h" #include "ErrorReporter.h" #include "RenderHolder.h" #include "QPushButtonWithDoubleClick.h" #include #include #include #include using namespace VAPoR; namespace { const string DuplicateInStr = "Duplicate in:"; }; CBWidget::CBWidget(QWidget *parent, QString text) : QWidget(parent), QTableWidgetItem(text){}; NewRendererDialog::NewRendererDialog(QWidget *parent, std::vector rendererNames, std::vector descriptions, std::vector iconPaths, std::vector smallIconPaths, std::vector dim2DSupport, std::vector dim3DSupport, vector particleSupport) : QDialog(parent), Ui_NewRendererDialog() { setupUi(this); _rendererNames = rendererNames; _descriptions = descriptions; _iconPaths = iconPaths; _smallIconPaths = smallIconPaths; _dim2DSupport = dim2DSupport; _dim3DSupport = dim3DSupport; _particleSupport = particleSupport; rendererNameEdit->setValidator(new QRegExpValidator(QRegExp("[a-zA-Z0-9_]{1,64}"))); dataMgrCombo->clear(); _createButtons(); connect(dataMgrCombo, SIGNAL(activated(int)), this, SLOT(_showRelevantRenderers())); }; void NewRendererDialog::_createButtons() { int size = _rendererNames.size(); _buttons.clear(); for (int i = 0; i < size; i++) { QString iconPath = QString::fromStdString(_smallIconPaths[i]); QIcon icon(iconPath); QString name = QString::fromStdString(_rendererNames[i]); QPushButton *button = _createButton(icon, name, i); buttonHolderGridLayout->addWidget(button, i, 0); _buttons.push_back(button); QPixmap thumbnail(_smallIconPaths[i].c_str()); QLabel *label = new QLabel(); label->setPixmap(thumbnail); label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); buttonHolderGridLayout->addWidget(label, i, 1); if (i == 0) button->setChecked(true); } } QPushButton *NewRendererDialog::_createButton(QIcon icon, QString name, int index) { QPushButton *button = new QPushButtonWithDoubleClick(name, this); button->setIconSize(QSize(50, 50)); button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); button->setLayoutDirection(Qt::RightToLeft); button->setCheckable(true); button->setProperty("index", index); connect(button, SIGNAL(toggled(bool)), this, SLOT(_buttonChecked())); connect(button, SIGNAL(doubleClicked()), this, SLOT(_buttonDoubleClicked())); return button; } void NewRendererDialog::InitializeDataSources(VAPoR::ControlExec *ce) { VAPoR::DataStatus *dataStatus = ce->GetDataStatus(); _dataStatus = dataStatus; const vector datasets = dataStatus->GetDataMgrNames(); const auto gsp = ce->GetParams(); string activeDataset = gsp->GetActiveDataset(); if (activeDataset.empty()) { string _1, _2; ce->RenderLookup(gsp->GetActiveRendererInst(), _1, activeDataset, _2); } dataMgrCombo->blockSignals(true); dataMgrCombo->clear(); for (int i = 0; i < datasets.size(); i++) { dataMgrCombo->addItem(QString::fromStdString(datasets[i])); } dataMgrCombo->setCurrentText(QString::fromStdString(activeDataset)); dataMgrCombo->blockSignals(false); _showRelevantRenderers(); } void NewRendererDialog::_showRelevantRenderers() { const string datasetName = dataMgrCombo->currentText().toStdString(); DataMgr * dm = _dataStatus->GetDataMgr(datasetName); VAssert(dm); bool has2D = dm->GetDataVarNames(2, DataMgr::VarType::Scalar).size(); bool has3D = dm->GetDataVarNames(3, DataMgr::VarType::Scalar).size(); bool hasParticle = dm->GetDataVarNames(3, DataMgr::VarType::Particle).size(); for (int i = 0; i < _buttons.size(); i++) { if ((has2D && _dim2DSupport[i]) || (has3D && _dim3DSupport[i]) || (hasParticle && _particleSupport[i])) { _buttons[i]->setEnabled(true); _buttons[i]->setToolTip(""); } else { _buttons[i]->setEnabled(false); _buttons[i]->setToolTip(QString::fromStdString("Dataset \"" + datasetName + "\" does not have data supported by this renderer")); } } _selectFirstValidRenderer(); } void NewRendererDialog::_selectFirstValidRenderer() { for (int i = 0; i < _buttons.size(); i++) { if (_buttons[i]->isEnabled()) { _buttons[i]->click(); return; } } } void NewRendererDialog::_setUpImage(std::string imageName, QLabel *label) { QPixmap thumbnail(imageName.c_str()); label->setPixmap(thumbnail); } void NewRendererDialog::_buttonChecked() { QPushButton *button = (QPushButton *)sender(); int index = button->property("index").toInt(); _uncheckAllButtons(); button->blockSignals(true); button->setChecked(true); button->blockSignals(false); string icon = _iconPaths[index]; _setUpImage(icon, bigDisplay); QString title = "\n" + QString::fromStdString(_rendererNames[index]) + " Renderer"; titleLabel->setText(title); QString description = QString::fromStdString(_descriptions[index]); descriptionLabel->setText(description); _selectedRenderer = _rendererNames[index]; } void NewRendererDialog::_buttonDoubleClicked() { _buttonChecked(); this->accept(); } void NewRendererDialog::_uncheckAllButtons() { int count = buttonHolderGridLayout->count() / 2; for (int i = 0; i < count; i++) { QPushButton *button; button = (QPushButton *)buttonHolderGridLayout->itemAt(i * 2)->widget(); button->blockSignals(true); button->setChecked(false); button->blockSignals(false); } } void RenderHolder::_showIntelDriverWarning(ControlExec *_controlExec, const string &rendererType) { if (_controlExec->GetGPUVendor() != GLManager::Vendor::Intel) return; if (rendererType != VolumeRenderer::GetClassType() && rendererType != VolumeIsoRenderer::GetClassType()) return; ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); SettingsParams *sp = (SettingsParams *)paramsMgr->GetParams(SettingsParams::GetClassType()); if (sp->GetDontShowIntelDriverWarning()) return; // Qt will automatically delete this for us apparently QCheckBox *dontShowAgain = new QCheckBox("Don't show again"); dontShowAgain->blockSignals(true); QMessageBox warning; warning.setIcon(QMessageBox::Warning); warning.setText("Warning"); warning.setInformativeText("Regular grid renderer is used by default. " "If your data is non-regular, it can result in an image that misrepresents your data. " "\n\n" "To get correct results for non-regular data, select the curvilinear grid rendering algorithm. " "This can be changed under the renderer's Apperance tab under the transfer function editor. " "\n\n" "Your computer uses an Intel GPU which has poor support for the curvilinear renderer. " "It could potentially result in Vapor hanging or crashing. " "In this case, we recommend you use a computer with an AMD or Nvidia GPU. "); warning.addButton(dontShowAgain, QMessageBox::ActionRole); warning.addButton(QMessageBox::Ok); warning.exec(); if (dontShowAgain->checkState() == Qt::Checked) sp->SetDontShowIntelDriverWarning(true); } void RenderHolder::_newRendererDialogAccepted(ControlExec *_controlExec, NewRendererDialog *_newRendererDialog) { ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); vector dataSetNames = _controlExec->GetDataStatus()->GetDataMgrNames(); string rendererType = _newRendererDialog->GetSelectedRenderer(); _showIntelDriverWarning(_controlExec, rendererType); int selection = _newRendererDialog->dataMgrCombo->currentIndex(); string dataSetName = dataSetNames[selection]; GUIStateParams *p = (GUIStateParams *)_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()); string activeViz = p->GetActiveVizName(); // figure out the name // QString qname = _newRendererDialog->rendererNameEdit->text(); string rendererName = qname.toStdString(); // Check that it's not all blanks: // if (rendererName.find_first_not_of(' ') == string::npos) { rendererName = rendererType; } rendererName = _controlExec->MakeRendererNameUnique(rendererName); qname = QString(rendererName.c_str()); paramsMgr->BeginSaveStateGroup("Activate Renderer"); int rc = _controlExec->ActivateRender(activeViz, dataSetName, rendererType, rendererName, false); if (rc < 0) { MSG_ERR("Can't create renderer"); paramsMgr->EndSaveStateGroup(); return; } // Save current instance to state // p->SetActiveRenderer(activeViz, rendererType, rendererName); // Update(); // emit newRendererSignal(activeViz, rendererType, rendererName); paramsMgr->EndSaveStateGroup(); } ================================================ FILE: apps/vaporgui/RenderHolder.h ================================================ #ifndef RENDERHOLDER_H #define RENDERHOLDER_H #include #include #include #include #include #include #include #include "ui_NewRendererDialog.h" #include "VaporTable.h" #include QT_USE_NAMESPACE class RendererList; namespace VAPoR { class ControlExec; class ParamsMgr; class DataStatus; class RenderParams; } // namespace VAPoR class NewRendererDialog : public QDialog, public Ui_NewRendererDialog { Q_OBJECT public: NewRendererDialog(QWidget *parent, std::vector rendererNames, std::vector descriptions, std::vector iconPaths, std::vector smallIconPaths, std::vector dim2DSupport, std::vector dim3DSupport, vector particleSupport); std::string GetSelectedRenderer() { return _selectedRenderer; } void InitializeDataSources(VAPoR::ControlExec *ce); private slots: void _buttonChecked(); void _buttonDoubleClicked(); void _showRelevantRenderers(); private: void _createButtons(); void _setUpImage(std::string imageName, QLabel *label); void _uncheckAllButtons(); void _selectFirstValidRenderer(); QPushButton *_createButton(QIcon icon, QString name, int index); std::vector _rendererNames; std::vector _descriptions; std::vector _iconPaths; std::vector _smallIconPaths; std::vector _dim2DSupport; std::vector _dim3DSupport; std::vector _particleSupport; std::vector _buttons; VAPoR::DataStatus *_dataStatus; std::string _selectedRenderer; QMessageBox *_msgBox; }; class CBWidget : public QWidget, public QTableWidgetItem { public: CBWidget(QWidget *parent, QString type); }; //! \class RenderHolder //! \ingroup Public_GUI //! \brief A class that manages the display of Renderer parameters //! \author Alan Norton //! \version 3.0 //! \date April 2015 //! This is class manages a QTableWidget that indicates the currently //! available Renderers, and a //! QStackedWidget that displays the various parameters associated //! with the selected renderer. //! class RenderHolder { public: static void _showIntelDriverWarning(VAPoR::ControlExec *_controlExec, const string &rendererType); static void _newRendererDialogAccepted(VAPoR::ControlExec *_controlExec, NewRendererDialog *_newRendererDialog); }; #endif // RENDERHOLDER_H ================================================ FILE: apps/vaporgui/RendererInspector.cpp ================================================ #include "RendererInspector.h" #include "RenderEventRouter.h" #include #include #include using namespace VAPoR; using std::vector; using std::string; #include "QTabWidget" RendererInspector::RendererInspector(VAPoR::ControlExec *ce) : _ce(ce) { vector rendererNames = RenderEventRouterFactory::Instance()->GetFactoryNames(); for (auto name : rendererNames) { RenderEventRouter *re = RenderEventRouterFactory::Instance()->CreateInstance(name, NULL, _ce); QWidget *w = dynamic_cast(re); VAssert(w); VRouter::Add(w); _classToInspectorMap[name] = std::pair(re, w); } } void RendererInspector::Update() { ParamsMgr *paramsMgr = _ce->GetParamsMgr(); GUIStateParams *guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType()); string currentViz = guiParams->GetActiveVizName(); string renClass, renInst, _; guiParams->GetActiveRenderer(currentViz, renClass, renInst); if (renInst.empty() || _classToInspectorMap.count(renClass) == 0 || !paramsMgr->RenderParamsLookup(renInst, _, _, _)) { Show(nullptr); return; } Show(_classToInspectorMap[renClass].second); _classToInspectorMap[renClass].first->SetActive(renInst); _classToInspectorMap[renClass].first->Update(); } std::vector RendererInspector::GetRenderEventRouters() const { vector v; for (auto it = _classToInspectorMap.begin(); it != _classToInspectorMap.end(); ++it) v.push_back(it->second.first); return v; } ================================================ FILE: apps/vaporgui/RendererInspector.h ================================================ #pragma once #include "VRouter.h" namespace VAPoR { class ControlExec; } class RenderEventRouter; class RendererInspector : public VRouter { VAPoR::ControlExec *_ce; std::map> _classToInspectorMap; public: RendererInspector(VAPoR::ControlExec *ce); void Update(); // Addresses legacy deps std::vector GetRenderEventRouters() const; }; ================================================ FILE: apps/vaporgui/RendererList.cpp ================================================ #include "RendererList.h" #include #include #include #include #include #include #include #include #include "VGroup.h" #include "VVisibilityCheckbox.h" #include "RenderEventRouter.h" #include "NewRendererDialogManager.h" std::map RendererList::_rendererMetadata; bool RendererList::AllowInspectDataset = true; // Fixes a bug in Qt. class DisableDatasetClickEventFilter: public QObject { QListWidget *_w; public: DisableDatasetClickEventFilter(QListWidget *w) : _w(w) {} protected: bool eventFilter(QObject* object, QEvent* event) { if(event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) { auto pos = _w->mapFromGlobal(QCursor::pos()); auto *item = _w->itemAt(pos); if (item) { if (item->type() == RendererList::DatasetType) { return true; } } } return QObject::eventFilter(object, event); } }; class DisableDragFilter: public QObject { // QListWidget *_w; public: DisableDragFilter(QListWidget *w) // : _w(w) {} protected: bool eventFilter(QObject* object, QEvent* event) { // This event filter is ignored by disabled items. // if (event->type() == QEvent::MouseButtonPress) { // auto pos = _w->mapFromGlobal(QCursor::pos()); // auto *item = _w->itemAt(pos); // if (item && !(item->flags() & Qt::ItemIsEnabled)) // return true; // } if(event->type() == QEvent::MouseMove) return true; return QObject::eventFilter(object, event); } }; RendererList::RendererList(ControlExec *ce) : VContainer(_lw = new QListWidget), _ce(ce) { installEventFilter(new DisableDragFilter(_lw)); // itemSelectionChanged signal specifically needs to be used. currentItemChanged is slightly different from selectedItem. connect(_lw, &QListWidget::itemSelectionChanged, this, &RendererList::itemSelectionChanged); _lw->setContextMenuPolicy(Qt::CustomContextMenu); connect(_lw, &QListWidget::customContextMenuRequested, this, &RendererList::showContextMenu); if (_rendererMetadata.empty()) { auto eventRouterNames = RenderEventRouterFactory::Instance()->GetFactoryNames(); for (auto &rendererType : eventRouterNames) { auto router = std::unique_ptr(RenderEventRouterFactory::Instance()->CreateInstance(rendererType, nullptr, _ce)); _rendererMetadata[rendererType] = { router->Supports2DVariables(), router->Supports3DVariables(), router->SupportsParticleVariables(), router->GetDescription(), router->GetSmallIconImagePath(), router->GetIconImagePath() }; } } if (!AllowInspectDataset) _lw->viewport()->installEventFilter(new DisableDatasetClickEventFilter(_lw)); _toolbar = new VHGroup; _toolbar->layout()->setSpacing(0); _toolbar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); _toolbar->setParent(this); _toolbar->show(); QToolButton *tb = new QToolButton; _deleteToolButton = tb; _toolbar->Add(tb); tb->setText("-"); tb->setStyleSheet("QToolButton{font-size: 15pt;font-weight:bold; } QToolButton:enabled{color:#bf0206;}"); connect(tb, &QToolButton::clicked, this, [=](){ auto item = _lw->currentItem(); if (item && item->type() == RendererType) { RendererItem *rItem = dynamic_cast(item); deleteRenderer(rItem->Id); } }); _nrd = new NewRendererDialogManager(ce, this); tb = new QToolButton; _toolbar->Add(tb); tb->setText("+"); connect(tb, &QToolButton::clicked, _nrd, &NewRendererDialogManager::Show); tb->setStyleSheet("QToolButton{font-size: 15pt;font-weight:bold;} QToolButton:enabled{color:#2b822b;}"); } void RendererList::Update() { auto paramsMgr = _ce->GetParamsMgr(); GUIStateParams *guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType()); string currentViz = guiParams->GetActiveVizName(); string activeRenderClass, activeRenderInst; guiParams->GetActiveRenderer(currentViz, activeRenderClass, activeRenderInst); string activeDataset = guiParams->GetActiveDataset(); const auto allViz = paramsMgr->GetVisualizerNames(); _lw->blockSignals(true); int scrollY = _lw->verticalScrollBar()->value(); _lw->clear(); auto datasets = guiParams->GetOpenDataSetNames(); for (int i = 0; i < datasets.size(); i++) { auto dataset = datasets[i]; if (i != 0) { QListWidgetItem *spacerItem = new QListWidgetItem(); // These flags only sortof work spacerItem->setFlags(spacerItem->flags() & ~Qt::ItemIsEnabled & ~Qt::ItemIsSelectable & ~Qt::ItemIsDragEnabled); _lw->addItem(spacerItem); } QListWidgetItem *datasetItem = new DatasetItem(dataset); datasetItem->setFlags(datasetItem->flags() & ~Qt::ItemIsDragEnabled); QLabel *datasetLabel = new QLabel(QString::fromStdString(dataset)); datasetLabel->setStyleSheet("QLabel { font-weight: 500; }"); if (!AllowInspectDataset) datasetItem->setFlags(datasetItem->flags() & ~Qt::ItemIsEnabled); _lw->addItem(datasetItem); _lw->setItemWidget(datasetItem, datasetLabel); if (AllowInspectDataset && dataset == activeDataset) _lw->setCurrentRow(_lw->count()-1); vector rendererNames; paramsMgr->GetRenderParamNames(currentViz, dataset, rendererNames); for (auto rName : rendererNames) { const auto className = getClassName(rName); RenderParams *rp = _ce->GetRenderParams(currentViz, dataset, className, rName); VHGroup *line = new VHGroup; auto vc = new VVisibilityCheckbox; line->Add(vc); const auto vars = getHintVariables(rp); line->Add(new QLabel(QString::fromStdString(rp->GetValueString(rp->UserNameTag, rName) + (vars.empty() ? "" : " (" + STLUtils::Join(vars, ", ") + ")")))); vc->SetValue(rp->IsEnabled()); connect(vc, &VVisibilityCheckbox::ValueChanged, this, [=](bool on){ RenderParams *rp = _ce->GetRenderParams(currentViz, dataset, className, rName); if (rp) { rp->SetEnabled(on); } }); QListWidgetItem *item = new RendererItem(rName, className, dataset); item->setFlags(item->flags() & ~Qt::ItemIsDragEnabled); _lw->addItem(item); _lw->setItemWidget(item, line); if (rName == activeRenderInst) { _lw->setCurrentRow(_lw->count()-1); } } } // _lw->scroll scrolls container, not the actual scroll area _lw->verticalScrollBar()->setValue(scrollY); _lw->blockSignals(false); _deleteToolButton->setEnabled(!activeRenderInst.empty()); } string RendererList::getCurrentViz() { GUIStateParams *guiParams = (GUIStateParams *)_ce->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()); return guiParams->GetActiveVizName(); } string RendererList::getClassName(string instName) { auto classes = _ce->GetRenderClassNames(getCurrentViz()); for (auto c : classes) { if (STLUtils::Contains(_ce->GetRenderInstances(getCurrentViz(), c), instName)) { return c; } } return ""; } void RendererList::itemSelectionChanged() { if (_lw->selectedItems().empty()) // This will trigger with nothing semi-randomly if return Update(); // empty space between multiple loaded datasets clicked QListWidgetItem *item = _lw->selectedItems()[0]; if (item->type() == RendererType) { RendererItem *rItem = dynamic_cast(item); inspectRenderer(rItem); } else if (item->type() == DatasetType) { DatasetItem *dItem = dynamic_cast(item); inspectDataset(dItem); } } void RendererList::inspectRenderer(RendererItem *rItem) { GUIStateParams *guiParams = (GUIStateParams *)_ce->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()); guiParams->SetActiveRenderer(guiParams->GetActiveVizName(), rItem->Class, rItem->Id); } void RendererList::inspectDataset(DatasetItem *item) { GUIStateParams *guiParams = (GUIStateParams *)_ce->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()); guiParams->SetActiveDataset(item->Id); } void RendererList::showContextMenu(const QPoint& localPos) { auto currentViz = getCurrentViz(); QMenu _menu; QMenu *menu = &_menu; QListWidgetItem *item = _lw->itemAt(localPos); if (item && item->type() == RendererType) { string id, dataset, Class; { // Cannot capture rItem since after update caused by click may be recreated RendererItem *rItem = dynamic_cast(item); id = rItem->Id, dataset = rItem->Dataset, Class = rItem->Class; } RenderParams *rp = _ce->GetRenderParams(currentViz, dataset, Class, id); menu->addAction(rp->IsEnabled() ? "Hide" : "Show", [=](){rp->SetEnabled(!rp->IsEnabled());}); menu->addAction("Delete", [=](){deleteRenderer(id);}); menu->addAction("Rename", [=](){renameRenderer(id);}); QMenu *duplicateMenu = menu->addMenu("Duplicate in"); for (auto viz : _ce->GetVisualizerNames()) { duplicateMenu->addAction(QString::fromStdString(viz), [=](){ auto newName = _ce->MakeRendererNameUnique(id); _ce->GetParamsMgr()->BeginSaveStateGroup("Duplicate Ren"); auto newParams = _ce->GetRenderParams(currentViz, dataset, Class, id); _ce->GetParamsMgr()->CreateRenderParamsInstance(viz, dataset, newName, newParams); _ce->ActivateRender(viz, dataset, Class, newName, false); auto p = _ce->GetRenderParams(viz, dataset, Class, newName); if (!p->GetValueString(p->UserNameTag, "").empty()) p->SetValueString(p->UserNameTag, "", p->GetValueString(p->UserNameTag, "") + " (copy)"); _ce->GetParamsMgr()->EndSaveStateGroup(); }); } } auto eventRouterNames = RenderEventRouterFactory::Instance()->GetFactoryNames(); auto datasets = _ce->GetParamsMgr()->GetDataMgrNames(); QMenu *newRendererMenu = menu->addMenu("New Renderer"); for (const auto &dataset : datasets) { DataMgr *dm = _ce->GetDataStatus()->GetDataMgr(dataset); bool has2D = dm->GetDataVarNames(2, DataMgr::VarType::Scalar).size(); bool has3D = dm->GetDataVarNames(3, DataMgr::VarType::Scalar).size(); bool hasParticle = dm->GetDataVarNames(3, DataMgr::VarType::Particle).size(); QMenu *datasetMenu = newRendererMenu; if (datasets.size() > 1) datasetMenu = newRendererMenu->addMenu(QString::fromStdString(dataset)); for (const auto &rendererType : eventRouterNames) { QAction *action = datasetMenu->addAction(QString::fromStdString(rendererType), [=](){ _ce->ActivateRender(currentViz, dataset, rendererType, _ce->MakeRendererNameUnique(rendererType), false); // TODO renderer creation using params // _ce->GetParamsMgr()->CreateRenderParamsInstance(currentViz, dataset, RendererFactory::Instance()->GetParamsClassFromRenderClass(rendererType), _ce->MakeRendererNameUnique(rendererType)); }); const auto &meta = _rendererMetadata[rendererType]; if (!((has2D && meta.supports2D) || (has3D && meta.supports3D) || (hasParticle && meta.supportsParticle))) { action->setEnabled(false); action->setToolTip(QString::fromStdString("Dataset \"" + dataset + "\" does not have data supported by this renderer")); } } } menu->exec(_lw->viewport()->mapToGlobal(localPos)); } void RendererList::deleteRenderer(std::string id) { string rWin, rDataset, rClass; _ce->RenderLookup(id, rWin, rDataset, rClass); ParamsMgr *paramsMgr = _ce->GetParamsMgr(); GUIStateParams *guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType()); paramsMgr->BeginSaveStateGroup("Remove Renderer"); _ce->RemoveRenderer(rWin, rDataset, rClass, id, false); guiParams->SetActiveRenderer(getCurrentViz(), "", ""); vector otherInsts; paramsMgr->GetRenderParamNames(rWin, otherInsts); // Need to set any other renderer otherwise other GUI code will break. for (auto &other : otherInsts) { if (other == id) continue; _ce->RenderLookup(other, rWin, rDataset, rClass); guiParams->SetActiveRenderer(guiParams->GetActiveVizName(), rClass, other); break; } paramsMgr->EndSaveStateGroup(); } #include #include #include #include #include std::vector RendererList::getHintVariables(VAPoR::RenderParams *rp) { auto helper = [](RenderParams *rp) -> vector { if (dynamic_cast(rp) || dynamic_cast(rp) || dynamic_cast(rp)) return rp->GetFieldVariableNames(); if (dynamic_cast(rp)) return {rp->GetHeightVariableName()}; if (dynamic_cast(rp)) return {}; return {rp->GetFirstVariableName()}; }; return STLUtils::Filter(helper(rp), [](const string &v){return !v.empty();}); } void RendererList::renameRenderer(std::string id) { string rWin, rDataset, rClass; _ce->RenderLookup(id, rWin, rDataset, rClass); RenderParams *rp = _ce->GetRenderParams(rWin, rDataset, rClass, id); bool ok; string newName = QInputDialog::getText(this, "Rename Renderer", "", QLineEdit::Normal, QString::fromStdString(rp->GetValueString(rp->UserNameTag, id)), &ok).toStdString(); if (ok) rp->SetValueString(rp->UserNameTag, "", newName); } void RendererList::resizeEvent(QResizeEvent *event) { _toolbar->setFixedSize(_toolbar->sizeHint()); auto p = size() - _toolbar->size(); _toolbar->move(p.width(), p.height()); } ================================================ FILE: apps/vaporgui/RendererList.h ================================================ #pragma once #include "VContainer.h" #include namespace VAPoR{ class ControlExec; class RenderParams; } using namespace VAPoR; using std::string; class DisableDatasetClickEventFilter; class NewRendererDialogManager; class VHGroup; class QToolButton; class RendererList : public VContainer { Q_OBJECT QListWidget *_lw; QToolButton *_deleteToolButton; ControlExec *_ce; NewRendererDialogManager *_nrd; struct RendererMetadata { bool supports2D, supports3D, supportsParticle; string description; string iconPath; string imagePath; }; static bool AllowInspectDataset; static std::map _rendererMetadata; static const int DatasetType = QListWidgetItem::UserType; static const int RendererType = QListWidgetItem::UserType+1; class RendererItem : public QListWidgetItem { public: const std::string Id; const std::string Class; const std::string Dataset; RendererItem(const std::string &instName, const std::string &className, const std::string &datasetName) : QListWidgetItem(nullptr, RendererType), Id(instName), Class(className), Dataset(datasetName) {} }; class DatasetItem : public QListWidgetItem { public: const std::string Id; DatasetItem(const std::string &name) : QListWidgetItem(nullptr, DatasetType), Id(name) {} }; public: RendererList(ControlExec *ce); void Update(); string getCurrentViz(); string getClassName(string instName); void itemSelectionChanged(); void inspectRenderer(RendererItem *item); void inspectDataset(DatasetItem *item); void showContextMenu(const QPoint& localPos); void deleteRenderer(string id); static std::vector getHintVariables(RenderParams *rp); void renameRenderer(string inst); protected: VHGroup *_toolbar; void resizeEvent(QResizeEvent *event); friend class DisableDatasetClickEventFilter; }; ================================================ FILE: apps/vaporgui/RenderersPanel.cpp ================================================ #include "RenderersPanel.h" #include #include #include #include "RendererList.h" #include "RendererInspector.h" #include "DatasetInspector.h" #include "VRouter.h" using namespace VAPoR; RenderersPanel::RenderersPanel(VAPoR::ControlExec *ce) : VContainer(_splitter = new QSplitter(Qt::Orientation::Vertical)), _ce(ce) { _splitter->addWidget(_renList = new RendererList(_ce)); _splitter->addWidget(_inspectorRouter = new VRouter); _splitter->setChildrenCollapsible(false); _inspectorRouter->Add(_renInspector = new RendererInspector(_ce)); _inspectorRouter->Add(_dataInspector = new DatasetInspector(_ce)); } void RenderersPanel::Update() { GUIStateParams *guiParams = (GUIStateParams *)_ce->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()); _renList->Update(); if (!guiParams->GetActiveDataset().empty() && guiParams->GetActiveRendererInst().empty()) { _inspectorRouter->Show(_dataInspector); _dataInspector->Update(); } else { _inspectorRouter->Show(_renInspector); _renInspector->Update(); } } ================================================ FILE: apps/vaporgui/RenderersPanel.h ================================================ #pragma once #include "VContainer.h" #include "Updatable.h" #include "VaporFwd.h" class RendererList; class RendererInspector; class DatasetInspector; class VRouter; class QSplitter; class RenderersPanel : public VContainer, public Updatable { Q_OBJECT QSplitter *_splitter; VAPoR::ControlExec *_ce; RendererList *_renList; VRouter *_inspectorRouter; RendererInspector *_renInspector; DatasetInspector *_dataInspector; public: RenderersPanel(VAPoR::ControlExec *ce); void Update(); }; ================================================ FILE: apps/vaporgui/SliceEventRouter.cpp ================================================ #include "SliceEventRouter.h" #include #include "PWidgets.h" #include "PSliceController.h" #include "PMetadataClasses.h" using namespace VAPoR; static RenderEventRouterRegistrar registrar(SliceEventRouter::GetClassType()); SliceEventRouter::SliceEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, SliceParams::GetClassType()) { // clang-format off AddVariablesSubtab(new PGroup({ new PSection("Variable Selection", { new PScalarVariableSelector }), new PFidelitySection, new POpenVariableMetadataWidget })); AddAppearanceSubtab(new PGroup({ new PTFEditor, new PSection("Slice", { (new PDoubleSliderEdit(RenderParams::SampleRateTag, "N Samples"))->SetRange(32, 2000) }) })); AddGeometrySubtab(new PGroup({ new PSliceController, new PGeometrySubtab, })); AddColorbarSubtab(new PAnnotationColorbarWidget); // clang-format on } string SliceEventRouter::_getDescription() const { return ("Displays a slice or cutting plane through" "a 3D variable. Slices are sampled along the plane's axes according" " to a sampling rate define by the user.\n\n"); } ================================================ FILE: apps/vaporgui/SliceEventRouter.h ================================================ #pragma once #include "RenderEventRouterGUI.h" #include //! //! \class SliceEventRouter //! \ingroup Public_GUI //! \brief Defines the Slice Renderer GUI //! \author Stas Jaroszynski class SliceEventRouter : public RenderEventRouterGUI { public: SliceEventRouter(QWidget *parent, VAPoR::ControlExec *ce); static string GetClassType() { return VAPoR::SliceRenderer::GetClassType(); } string GetType() const { return GetClassType(); } bool Supports2DVariables() const { return false; } bool Supports3DVariables() const { return true; } protected: string _getDescription() const; string _getSmallIconImagePath() const { return "Slice_small.png"; } string _getIconImagePath() const { return "Slice.png"; } }; ================================================ FILE: apps/vaporgui/Statistics.cpp ================================================ //************************************************************************ // * // Copyright (C) 2016 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************ // // File: Statistics.cpp // // Author: Samuel Li // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: November 2017 // // Description: Implements the Statistics class. // #ifdef WIN32 #pragma warning(disable : 4100) #endif #include "Statistics.h" #include #include "ErrorReporter.h" #include "Flags.h" #include #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include "PWidgets.h" #include "VPushButton.h" using namespace Wasp; using namespace VAPoR; using namespace std; // Class Statistics // Statistics::Statistics(QWidget *parent) : QDialog(parent), Ui_StatsWindow() { _controlExec = NULL; setupUi(this); setWindowTitle("Statistics"); MyFidelityWidget->Reinit((VariableFlags)AUXILIARY); Connect(); auto rs = new PRegionSelector; verticalLayout_2->insertWidget(0, rs); _pw.push_back(rs); auto cr = new PCopyRegionWidget; verticalLayout_2->insertWidget(1, cr); _pw.push_back(cr); VPushButton *close = new VPushButton("Close Window"); connect(close, &VPushButton::ButtonClicked, this, &QDialog::accept); layout()->addWidget(close); } Statistics::~Statistics() { } void Statistics::Update() { // Initialize pointers VAPoR::DataStatus * dataStatus = _controlExec->GetDataStatus(); std::vector dmNames = dataStatus->GetDataMgrNames(); if (dmNames.empty()) { this->close(); return; } GUIStateParams *guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string currentDatasetName = guiParams->GetStatsDatasetName(); if (currentDatasetName == "" || currentDatasetName == "NULL") { this->close(); return; } int currentIdx = -1; for (int i = 0; i < dmNames.size(); i++) if (currentDatasetName == dmNames[i]) { currentIdx = i; break; } if (currentIdx == -1) // currentDatasetName is closed!!! { currentDatasetName = dmNames[0]; currentIdx = 0; guiParams->SetStatsDatasetName(currentDatasetName); _validStats.Clear(); // since the old dataset is closed, we clear all stats. _validStats.currentDataSourceName = currentDatasetName; } VAPoR::DataMgr * currentDmgr = dataStatus->GetDataMgr(currentDatasetName); StatisticsParams * statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(currentDatasetName, StatisticsParams::GetClassType())); std::vector enabledVars = statsParams->GetAuxVariableNames(); if (_validStats.GetVariableCount() == 0) // likely because the current data set is switched { for (int i = 0; i < enabledVars.size(); i++) _validStats.AddVariable(enabledVars[i]); } // detect params changed by undo/redo if (_validStats.currentDataSourceName != currentDatasetName || !_validStats.HaveSameParams(statsParams)) { _validStats.currentDataSourceName = currentDatasetName; _validStats.UpdateMyParams(statsParams); } // Update DataMgrCombo DataMgrCombo->blockSignals(true); DataMgrCombo->clear(); for (int i = 0; i < dmNames.size(); i++) DataMgrCombo->addItem(QString::fromStdString(dmNames[i])); DataMgrCombo->setCurrentIndex(currentIdx); DataMgrCombo->blockSignals(false); // Update auto-update checkbox bool autoUpdate = statsParams->GetAutoUpdateEnabled(); UpdateCheckbox->blockSignals(true); if (autoUpdate) UpdateCheckbox->setCheckState(Qt::Checked); else UpdateCheckbox->setCheckState(Qt::Unchecked); UpdateCheckbox->blockSignals(false); // Update "Add a Variable" std::vector availVars = currentDmgr->GetDataVarNames(); for (int i = 0; i < enabledVars.size(); i++) for (int rmIdx = 0; rmIdx < availVars.size(); rmIdx++) if (availVars[rmIdx] == enabledVars[i]) { availVars.erase(availVars.begin() + rmIdx); break; } std::sort(availVars.begin(), availVars.end()); NewVarCombo->blockSignals(true); NewVarCombo->clear(); NewVarCombo->blockSignals(false); NewVarCombo->addItem(QString("Add a Variable")); for (std::vector::iterator it = availVars.begin(); it != availVars.end(); ++it) { NewVarCombo->addItem(QString::fromStdString(*it)); } NewVarCombo->setCurrentIndex(0); // Update "Remove a Variable" VAssert(enabledVars.size() == _validStats.GetVariableCount()); std::sort(enabledVars.begin(), enabledVars.end()); RemoveVarCombo->blockSignals(true); RemoveVarCombo->clear(); RemoveVarCombo->addItem(QString("Remove a Variable")); for (int i = 0; i < enabledVars.size(); i++) { RemoveVarCombo->addItem(QString::fromStdString(enabledVars[i])); } RemoveVarCombo->setCurrentIndex(0); RemoveVarCombo->blockSignals(false); // Update Statistics table: header this->_updateStatsTable(); // Update calculations NewCalcCombo->blockSignals(true); RemoveCalcCombo->blockSignals(true); NewCalcCombo->clear(); RemoveCalcCombo->clear(); NewCalcCombo->addItem(QString("Add a Calculation")); RemoveCalcCombo->addItem(QString("Remove a Calculation")); if (statsParams->GetMinEnabled()) RemoveCalcCombo->addItem(QString("Min")); else NewCalcCombo->addItem(QString("Min")); if (statsParams->GetMaxEnabled()) RemoveCalcCombo->addItem(QString("Max")); else NewCalcCombo->addItem(QString("Max")); if (statsParams->GetMeanEnabled()) RemoveCalcCombo->addItem(QString("Mean")); else NewCalcCombo->addItem(QString("Mean")); if (statsParams->GetMedianEnabled()) RemoveCalcCombo->addItem(QString("Median")); else NewCalcCombo->addItem(QString("Median")); if (statsParams->GetStdDevEnabled()) RemoveCalcCombo->addItem(QString("StdDev")); else NewCalcCombo->addItem(QString("StdDev")); NewCalcCombo->setCurrentIndex(0); RemoveCalcCombo->setCurrentIndex(0); NewCalcCombo->blockSignals(false); RemoveCalcCombo->blockSignals(false); // Update LOD, Refinement MyFidelityWidget->Update(currentDmgr, _controlExec->GetParamsMgr(), statsParams); // Update timesteps MinTimestepSpinbox->blockSignals(true); MinTimestepSpinbox->setMinimum(0); MinTimestepSpinbox->setMaximum(currentDmgr->GetNumTimeSteps() - 1); MinTimestepSpinbox->setValue(statsParams->GetCurrentTimestep()); MinTimestepSpinbox->blockSignals(false); MaxTimestepSpinbox->blockSignals(true); MaxTimestepSpinbox->setMinimum(0); MaxTimestepSpinbox->setMaximum(currentDmgr->GetNumTimeSteps() - 1); MaxTimestepSpinbox->setValue(statsParams->GetCurrentMaxTS()); MaxTimestepSpinbox->blockSignals(false); bool has3DVar = false; for (const auto &var : enabledVars) has3DVar |= 3 == currentDmgr->GetNumDimensions(var); _controlExec->GetParamsMgr()->BeginSaveStateGroup("Update Box Dims"); if (has3DVar) { statsParams->GetBox()->SetPlanar(false); statsParams->GetBox()->SetOrientation(Box::XYZ); } else { statsParams->GetBox()->SetPlanar(true); statsParams->GetBox()->SetOrientation(Box::XY); } _controlExec->GetParamsMgr()->EndSaveStateGroup(); for (auto p : _pw) p->Update(statsParams, _controlExec->GetParamsMgr(), currentDmgr); } void Statistics::_updateStatsTable() { // Initialize pointers GUIStateParams *guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string currentDatasetName = guiParams->GetStatsDatasetName(); VAssert(currentDatasetName != ""); StatisticsParams *statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(currentDatasetName, StatisticsParams::GetClassType())); // Update Statistics Table: header VariablesTable->clear(); // this also deletes the items properly. QStringList header; header << "Variable" << "No. of Samples"; if (statsParams->GetMinEnabled()) header << "Min"; if (statsParams->GetMaxEnabled()) header << "Max"; if (statsParams->GetMeanEnabled()) header << "Mean"; if (statsParams->GetMedianEnabled()) header << "Median"; if (statsParams->GetStdDevEnabled()) header << "StdDev"; VariablesTable->setColumnCount(header.size()); VariablesTable->setHorizontalHeaderLabels(header); VariablesTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); // Update Statistics Table: cells QBrush brush(QColor(255, 0, 0)); std::vector enabledVars = statsParams->GetAuxVariableNames(); VAssert(enabledVars.size() == _validStats.GetVariableCount()); VariablesTable->setRowCount(enabledVars.size()); int numberOfDigits = 3; for (int row = 0; row < enabledVars.size(); row++) { float m3[3]{0.0f, 0.0f, 0.0f}, median = 0.0f, stddev = 0.0f; long count = 0; _validStats.GetCount(enabledVars[row], &count); _validStats.Get3MStats(enabledVars[row], m3); _validStats.GetMedian(enabledVars[row], &median); _validStats.GetStddev(enabledVars[row], &stddev); VariablesTable->setItem(row, 0, new QTableWidgetItem(QString::fromStdString(enabledVars[row]))); if (count == -1) { VariablesTable->setItem(row, 1, new QTableWidgetItem(QString("??"))); VariablesTable->item(row, 1)->setForeground(brush); } else VariablesTable->setItem(row, 1, new QTableWidgetItem(QString::number(count))); int column = 2; if (statsParams->GetMinEnabled()) { if (!std::isnan(m3[0])) { VariablesTable->setItem(row, column, new QTableWidgetItem(QString::number(m3[0], 'g', numberOfDigits))); } else { VariablesTable->setItem(row, column, new QTableWidgetItem(QString("??"))); VariablesTable->item(row, column)->setForeground(brush); } column++; } if (statsParams->GetMaxEnabled()) { if (!std::isnan(m3[1])) VariablesTable->setItem(row, column, new QTableWidgetItem(QString::number(m3[1], 'g', numberOfDigits))); else { VariablesTable->setItem(row, column, new QTableWidgetItem(QString("??"))); VariablesTable->item(row, column)->setForeground(brush); } column++; } if (statsParams->GetMeanEnabled()) { if (!std::isnan(m3[2])) VariablesTable->setItem(row, column, new QTableWidgetItem(QString::number(m3[2], 'g', numberOfDigits))); else { VariablesTable->setItem(row, column, new QTableWidgetItem(QString("??"))); VariablesTable->item(row, column)->setForeground(brush); } column++; } if (statsParams->GetMedianEnabled()) { if (!std::isnan(median)) VariablesTable->setItem(row, column, new QTableWidgetItem(QString::number(median, 'g', numberOfDigits))); else { VariablesTable->setItem(row, column, new QTableWidgetItem(QString("??"))); VariablesTable->item(row, column)->setForeground(brush); } column++; } if (statsParams->GetStdDevEnabled()) { if (!std::isnan(stddev)) VariablesTable->setItem(row, column, new QTableWidgetItem(QString::number(stddev, 'g', numberOfDigits))); else { VariablesTable->setItem(row, column, new QTableWidgetItem(QString("??"))); VariablesTable->item(row, column)->setForeground(brush); } column++; } } for (int r = 0; r < VariablesTable->rowCount(); r++) for (int c = 0; c < VariablesTable->columnCount(); c++) { QTableWidgetItem *item = VariablesTable->item(r, c); item->setFlags(Qt::NoItemFlags); } VariablesTable->update(); VariablesTable->repaint(); VariablesTable->viewport()->update(); } void Statistics::showMe() { open(); Update(); } int Statistics::initControlExec(ControlExec *ce) { if (ce != NULL) _controlExec = ce; else return -1; // Store the active dataset name std::vector dmNames = _controlExec->GetDataStatus()->GetDataMgrNames(); if (dmNames.empty()) return -1; else { GUIStateParams *guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetStatsDatasetName(); if (dsName == "" || dsName == "NULL") // not initialized yet guiParams->SetStatsDatasetName(dmNames[0]); } return 0; } bool Statistics::Connect() { connect(NewVarCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_newVarChanged(int))); connect(RemoveVarCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_removeVarChanged(int))); connect(NewCalcCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_newCalcChanged(int))); connect(RemoveCalcCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_removeCalcChanged(int))); connect(MinTimestepSpinbox, SIGNAL(valueChanged(int)), this, SLOT(_minTSChanged(int))); connect(MaxTimestepSpinbox, SIGNAL(valueChanged(int)), this, SLOT(_maxTSChanged(int))); connect(UpdateButton, SIGNAL(clicked()), this, SLOT(_updateButtonClicked())); connect(DataMgrCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_dataSourceChanged(int))); connect(UpdateCheckbox, SIGNAL(stateChanged(int)), this, SLOT(_autoUpdateClicked(int))); connect(ExportButton, SIGNAL(clicked()), this, SLOT(_exportTextClicked())); return true; } void Statistics::_autoUpdateClicked(int state) { // Initialize pointers GUIStateParams * guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetStatsDatasetName(); StatisticsParams *statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType())); if (state == 0) // unchecked statsParams->SetAutoUpdateEnabled(false); else if (state == 2) // checked { statsParams->SetAutoUpdateEnabled(true); _updateButtonClicked(); } else { std::cerr << "Dont know what this state is!!!" << std::endl; // REPORT ERROR!!! } } void Statistics::_dataSourceChanged(int index) { std::string newDataSourceName = DataMgrCombo->itemText(index).toStdString(); // Initialize pointers GUIStateParams * guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); StatisticsParams *statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(newDataSourceName, StatisticsParams::GetClassType())); guiParams->SetStatsDatasetName(newDataSourceName); _validStats.currentDataSourceName = newDataSourceName; // add variables to _validStats if there are any _validStats.Clear(); std::vector enabledVars = statsParams->GetAuxVariableNames(); for (int i = 0; i < enabledVars.size(); i++) _validStats.AddVariable(enabledVars[i]); } void Statistics::_geometryValueChanged() { // Initialize pointers GUIStateParams * guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetStatsDatasetName(); StatisticsParams *statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType())); _validStats.InvalidAll(); std::vector myMin, myMax; statsParams->GetBox()->GetExtents(myMin, myMax); _validStats.SetCurrentExtents(myMin, myMax); // Auto-update if enabled if (statsParams->GetAutoUpdateEnabled()) _updateButtonClicked(); } void Statistics::_updateButtonClicked() { // Initialize pointers GUIStateParams * guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetStatsDatasetName(); StatisticsParams *statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType())); for (int i = 0; i < _validStats.GetVariableCount(); i++) { std::string varname = _validStats.GetVariableName(i); long count = 0; _validStats.GetCount(varname, &count); if (count == -1) { _calc3M(varname); _updateStatsTable(); } float m3[3]{0.0f, 0.0f, 0.0f}, median = 0.0f, stddev = 0.0f; _validStats.Get3MStats(varname, m3); _validStats.GetMedian(varname, &median); _validStats.GetStddev(varname, &stddev); if ((statsParams->GetMinEnabled() || statsParams->GetMaxEnabled() || statsParams->GetMeanEnabled()) && std::isnan(m3[2])) { _calc3M(varname); _updateStatsTable(); } if (statsParams->GetMedianEnabled() && std::isnan(median)) { _calcMedian(varname); _updateStatsTable(); } if (statsParams->GetStdDevEnabled() && std::isnan(stddev)) { _calcStddev(varname); _updateStatsTable(); } } } void Statistics::_minTSChanged(int val) { VAssert(val >= 0); // Initialize pointers GUIStateParams * guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetStatsDatasetName(); StatisticsParams *statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType())); _validStats.currentTimeStep[0] = val; // Add this minTS to parameter if different if (val != statsParams->GetCurrentTimestep()) { statsParams->SetCurrentTimestep(val); _validStats.InvalidAll(); if (val > statsParams->GetCurrentMaxTS()) { _validStats.currentTimeStep[1] = val; statsParams->SetCurrentMaxTS(val); MaxTimestepSpinbox->setValue(val); } } // Auto-update if enabled if (statsParams->GetAutoUpdateEnabled()) _updateButtonClicked(); } void Statistics::_maxTSChanged(int val) { VAssert(val >= 0); // Initialize pointers GUIStateParams * guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetStatsDatasetName(); StatisticsParams *statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType())); _validStats.currentTimeStep[1] = val; // Add this maxTS to parameter if different if (val != statsParams->GetCurrentMaxTS()) { statsParams->SetCurrentMaxTS(val); _validStats.InvalidAll(); if (val < statsParams->GetCurrentTimestep()) { _validStats.currentTimeStep[0] = val; statsParams->SetCurrentTimestep(val); MinTimestepSpinbox->setValue(val); } } // Auto-update if enabled if (statsParams->GetAutoUpdateEnabled()) _updateButtonClicked(); } void Statistics::_newCalcChanged(int index) { VAssert(index > 0); // Initialize pointers GUIStateParams * guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetStatsDatasetName(); StatisticsParams *statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType())); std::string calcName = NewCalcCombo->itemText(index).toStdString(); // Add this calculation to parameter if (calcName == "Min") statsParams->SetMinEnabled(true); else if (calcName == "Max") statsParams->SetMaxEnabled(true); else if (calcName == "Mean") statsParams->SetMeanEnabled(true); else if (calcName == "Median") statsParams->SetMedianEnabled(true); else if (calcName == "StdDev") statsParams->SetStdDevEnabled(true); else { // REPORT ERROR!! } // Auto-update if enabled if (statsParams->GetAutoUpdateEnabled()) _updateButtonClicked(); } void Statistics::_removeCalcChanged(int index) { VAssert(index > 0); // Initialize pointers GUIStateParams * guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetStatsDatasetName(); StatisticsParams *statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType())); std::string calcName = RemoveCalcCombo->itemText(index).toStdString(); // Remove this calculation from parameter if (calcName == "Min") statsParams->SetMinEnabled(false); else if (calcName == "Max") statsParams->SetMaxEnabled(false); else if (calcName == "Mean") statsParams->SetMeanEnabled(false); else if (calcName == "Median") statsParams->SetMedianEnabled(false); else if (calcName == "StdDev") statsParams->SetStdDevEnabled(false); else { // REPORT ERROR!! } } void Statistics::_newVarChanged(int index) { if (index <= 0) return; // Initialize pointers GUIStateParams * guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetStatsDatasetName(); StatisticsParams *statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType())); VAPoR::DataMgr * currentDmgr = _controlExec->GetDataStatus()->GetDataMgr(dsName); std::string varName = NewVarCombo->itemText(index).toStdString(); // Test if the selected variable available at the specific time step, // compression level, etc. if (!currentDmgr->VariableExists(statsParams->GetCurrentTimestep(), varName, statsParams->GetRefinementLevel(), statsParams->GetCompressionLevel())) { MSG_WARN("Selected variable not available at this settings!"); NewVarCombo->setCurrentIndex(0); return; } else { // Add this variable to parameter std::vector vars = statsParams->GetAuxVariableNames(); vars.push_back(varName); statsParams->SetAuxVariableNames(vars); // Add this variable to _validStats _validStats.AddVariable(varName); // Auto-update if enabled if (statsParams->GetAutoUpdateEnabled()) _updateButtonClicked(); } } void Statistics::_removeVarChanged(int index) { VAssert(index > 0); // Initialize pointers GUIStateParams * guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetStatsDatasetName(); StatisticsParams *statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType())); std::string varName = RemoveVarCombo->itemText(index).toStdString(); // Remove this variable from parameter std::vector vars = statsParams->GetAuxVariableNames(); int rmIdx = -1; for (int i = 0; i < vars.size(); i++) if (vars[i] == varName) { rmIdx = i; break; } VAssert(rmIdx != -1); vars.erase(vars.begin() + rmIdx); statsParams->SetAuxVariableNames(vars); // Remove this variable from _validStats _validStats.RemoveVariable(varName); } bool Statistics::_calc3M(std::string varname) { // Initialize pointers GUIStateParams * guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetStatsDatasetName(); StatisticsParams *statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType())); VAPoR::DataMgr * currentDmgr = _controlExec->GetDataStatus()->GetDataMgr(dsName); int minTS = statsParams->GetCurrentTimestep(); int maxTS = statsParams->GetCurrentMaxTS(); if (!currentDmgr->IsTimeVarying(varname)) maxTS = minTS; CoordType minExtent = {0.0, 0.0, 0.0}; CoordType maxExtent = {0.0, 0.0, 0.0}; statsParams->GetBox()->GetExtents(minExtent, maxExtent); float c = 0.0; float sum = 0.0; float min = std::numeric_limits::max(); float max = -min; long count = 0; for (int ts = minTS; ts <= maxTS; ts++) { VAPoR::Grid *grid = currentDmgr->GetVariable(ts, varname, statsParams->GetRefinementLevel(), statsParams->GetCompressionLevel(), minExtent, maxExtent); if (grid) { Grid::ConstIterator endItr = grid->cend(); float missingVal = grid->GetMissingValue(); for (Grid::ConstIterator it = grid->cbegin(minExtent, maxExtent); it != endItr; ++it) { if (*it != missingVal) { float val = *it; min = min < val ? min : val; max = max > val ? max : val; float y = val - c; float t = sum + y; c = t - sum - y; sum = t; count++; } } delete grid; // delete the grid after using it! } } if (count > 0) { float m3[3] = {min, max, sum / (float)count}; _validStats.Add3MStats(varname, m3); } else // count == 0 { // std::cerr << "Error: Zero value got selected!!" << std::endl; } _validStats.AddCount(varname, count); return true; } bool Statistics::_calcMedian(std::string varname) { // Initialize pointers GUIStateParams * guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetStatsDatasetName(); StatisticsParams *statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType())); VAPoR::DataMgr * currentDmgr = _controlExec->GetDataStatus()->GetDataMgr(dsName); int minTS = statsParams->GetCurrentTimestep(); int maxTS = statsParams->GetCurrentMaxTS(); if (!currentDmgr->IsTimeVarying(varname)) maxTS = minTS; CoordType minExtent = {0.0, 0.0, 0.0}; CoordType maxExtent = {0.0, 0.0, 0.0}; statsParams->GetBox()->GetExtents(minExtent, maxExtent); std::vector buffer; for (int ts = minTS; ts <= maxTS; ts++) { VAPoR::Grid *grid = currentDmgr->GetVariable(ts, varname, statsParams->GetRefinementLevel(), statsParams->GetCompressionLevel(), minExtent, maxExtent); if (grid) { Grid::ConstIterator endItr = grid->cend(); float missingVal = grid->GetMissingValue(); for (Grid::ConstIterator it = grid->cbegin(minExtent, maxExtent); it != endItr; ++it) { if (*it != missingVal) buffer.push_back(*it); } } } if (buffer.size() > 0) { std::sort(buffer.begin(), buffer.end()); float median = buffer.at(buffer.size() / 2); _validStats.AddMedian(varname, median); } else { // std::cerr << "Error: Zero value got selected!!" << std::endl; } _validStats.AddCount(varname, buffer.size()); return true; } bool Statistics::_calcStddev(std::string varname) { // Initialize pointers GUIStateParams * guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetStatsDatasetName(); StatisticsParams *statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType())); VAPoR::DataMgr * currentDmgr = _controlExec->GetDataStatus()->GetDataMgr(dsName); int minTS = statsParams->GetCurrentTimestep(); int maxTS = statsParams->GetCurrentMaxTS(); if (!currentDmgr->IsTimeVarying(varname)) maxTS = minTS; CoordType minExtent = {0.0, 0.0, 0.0}; CoordType maxExtent = {0.0, 0.0, 0.0}; statsParams->GetBox()->GetExtents(minExtent, maxExtent); float c = 0.0; float sum = 0.0; long count = 0; float m3[3]; _validStats.Get3MStats(varname, m3); if (std::isnan(m3[2])) { this->_calc3M(varname); _validStats.Get3MStats(varname, m3); } for (int ts = minTS; ts <= maxTS; ts++) { VAPoR::Grid *grid = currentDmgr->GetVariable(ts, varname, statsParams->GetRefinementLevel(), statsParams->GetCompressionLevel(), minExtent, maxExtent); if (grid) { Grid::ConstIterator endItr = grid->cend(); float missingVal = grid->GetMissingValue(); for (Grid::ConstIterator it = grid->cbegin(minExtent, maxExtent); it != endItr; ++it) { if (*it != missingVal) { float val = *it; float y = (val - m3[2]) * (val - m3[2]) - c; float t = sum + y; c = t - sum - y; sum = t; count++; } } } } if (count > 0) { _validStats.AddStddev(varname, std::sqrt(sum / (float)count)); } else { // std::cerr << "Error: Zero value got selected!!" << std::endl; } _validStats.AddCount(varname, count); return true; } // ValidStats class // int Statistics::ValidStats::_getVarIdx(std::string &varName) { int idx = -1; for (int i = 0; i < _variables.size(); i++) { if (_variables[i] == varName) { idx = i; break; } } return idx; } bool Statistics::ValidStats::AddVariable(std::string &newVar) { if (newVar == "") return false; if (_getVarIdx(newVar) != -1) // this variable already exists. return false; _variables.push_back(newVar); for (int i = 0; i < 5; i++) { _values[i].push_back(std::nan("1")); VAssert(_values[i].size() == _variables.size()); } _count.push_back(-1); if (_count.size() != _variables.size()) std::cerr << "_count.size() = " << _count.size() << ", _variables.size() = " << _variables.size() << std::endl; VAssert(_count.size() == _variables.size()); return true; } bool Statistics::ValidStats::RemoveVariable(std::string &varname) { int rmIdx = _getVarIdx(varname); if (rmIdx == -1) // this variable doesn't exist. return false; _variables.erase(_variables.begin() + rmIdx); for (int i = 0; i < 5; i++) { _values[i].erase(_values[i].begin() + rmIdx); VAssert(_values[i].size() == _variables.size()); } _count.erase(_count.begin() + rmIdx); VAssert(_count.size() == _variables.size()); return true; } bool Statistics::ValidStats::Add3MStats(std::string &varName, const float *input3M) { int idx = _getVarIdx(varName); if (idx == -1) // This variable doesn't exist return false; for (int i = 0; i < 3; i++) { _values[i][idx] = input3M[i]; } return true; } bool Statistics::ValidStats::AddMedian(std::string &varName, float inputMedian) { int idx = _getVarIdx(varName); if (idx == -1) // This variable doesn't exist return false; _values[3][idx] = inputMedian; return true; } bool Statistics::ValidStats::AddStddev(std::string &varName, float inputStddev) { int idx = _getVarIdx(varName); if (idx == -1) // This variable doesn't exist return false; _values[4][idx] = inputStddev; return true; } bool Statistics::ValidStats::AddCount(std::string &varName, long inputCount) { int idx = _getVarIdx(varName); if (idx == -1) // This variable doesn't exist return false; _count[idx] = inputCount; return true; } bool Statistics::ValidStats::Get3MStats(std::string &varName, float *output3M) { int idx = _getVarIdx(varName); if (idx == -1) // This variable doesn't exist return false; for (int i = 0; i < 3; i++) { output3M[i] = _values[i][idx]; } return true; } bool Statistics::ValidStats::GetMedian(std::string &varName, float *outputMedian) { int idx = _getVarIdx(varName); if (idx == -1) // This variable doesn't exist return false; *outputMedian = _values[3][idx]; return true; } bool Statistics::ValidStats::GetStddev(std::string &varName, float *outputStddev) { int idx = _getVarIdx(varName); if (idx == -1) // This variable doesn't exist return false; *outputStddev = _values[4][idx]; return true; } bool Statistics::ValidStats::GetCount(std::string &varName, long *outputCount) { int idx = _getVarIdx(varName); if (idx == -1) // This variable doesn't exist return false; *outputCount = _count[idx]; return true; } bool Statistics::ValidStats::InvalidAll() { for (int i = 0; i < 5; i++) for (int j = 0; j < _values[i].size(); j++) _values[i][j] = std::nan("1"); for (int i = 0; i < _count.size(); i++) _count[i] = -1; return true; } bool Statistics::ValidStats::Clear() { _variables.clear(); for (int i = 0; i < 5; i++) _values[i].clear(); _count.clear(); return true; } size_t Statistics::ValidStats::GetVariableCount() { return _variables.size(); } std::string Statistics::ValidStats::GetVariableName(int i) { if (i < _variables.size()) return _variables.at(i); else return std::string(""); } bool Statistics::ValidStats::HaveSameParams(const VAPoR::StatisticsParams *rhs) const { std::vector myMin, myMax; rhs->GetBox()->GetExtents(myMin, myMax); std::vector paramsMin, paramsMax; for (int i = 0; i < myMin.size(); i++) { paramsMin.push_back((float)myMin[i]); paramsMax.push_back((float)myMax[i]); } return (_variables == rhs->GetAuxVariableNames() && currentExtentMin == paramsMin && currentExtentMax == paramsMax && currentTimeStep[0] == rhs->GetCurrentTimestep() && currentTimeStep[1] == rhs->GetCurrentMaxTS() && currentLOD == rhs->GetCompressionLevel() && currentRefLev == rhs->GetRefinementLevel()); } bool Statistics::ValidStats::UpdateMyParams(const VAPoR::StatisticsParams *rhs) { this->Clear(); std::vector enabledVars = rhs->GetAuxVariableNames(); for (int i = 0; i < enabledVars.size(); i++) this->AddVariable(enabledVars[i]); std::vector myMin, myMax; rhs->GetBox()->GetExtents(myMin, myMax); this->SetCurrentExtents(myMin, myMax); currentTimeStep[0] = rhs->GetCurrentTimestep(); currentTimeStep[1] = rhs->GetCurrentMaxTS(); currentLOD = rhs->GetCompressionLevel(); currentRefLev = rhs->GetRefinementLevel(); return true; } bool Statistics::ValidStats::SetCurrentExtents(const std::vector &min, const std::vector &max) { currentExtentMin.clear(); currentExtentMax.clear(); if (min.size() != max.size()) { // REPORT ERROR!! return false; } for (int i = 0; i < min.size(); i++) { currentExtentMin.push_back(min[i]); currentExtentMax.push_back(max[i]); } return true; } bool Statistics::ValidStats::SetCurrentExtents(const std::vector &min, const std::vector &max) { std::vector minf, maxf; for (int i = 0; i < min.size(); i++) { minf.push_back((float)min[i]); maxf.push_back((float)max[i]); } return (this->SetCurrentExtents(minf, maxf)); } void Statistics::_exportTextClicked() { QString homePath = QDir::homePath(); homePath.append("/Variable_Statistics.txt"); QString path = QDir::toNativeSeparators(homePath); QString fName = QFileDialog::getSaveFileName(this, "Select file to save statistics:", path, "Comma-separated values (*.txt)"); if (!fName.isEmpty()) { ofstream file; file.open(fName.toStdString().c_str()); if (file.fail()) { std::ostringstream ss; ss << "Failed to open file "; ss << fName.toStdString(); ss << " for writing."; return; } // Initialize pointers GUIStateParams * guiParams = dynamic_cast(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); std::string dsName = guiParams->GetStatsDatasetName(); StatisticsParams * statsParams = dynamic_cast(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType())); VAPoR::DataMgr * currentDmgr = _controlExec->GetDataStatus()->GetDataMgr(dsName); std::vector availVars3D = currentDmgr->GetDataVarNames(3); availVars3D.clear(); // This is a temporary change to hide all 3D variables. // Removing this line could expose 3D variables again. file << "Data Source = " << guiParams->GetStatsDatasetName() << endl << endl; file << "#Variable Statistics:" << endl; file << "Variable_Name, No_of_Samples"; if (statsParams->GetMinEnabled()) file << ", Min"; if (statsParams->GetMaxEnabled()) file << ", Max"; if (statsParams->GetMeanEnabled()) file << ", Mean"; if (statsParams->GetMedianEnabled()) file << ", Median"; if (statsParams->GetStdDevEnabled()) file << ", Stddev"; file << endl; bool has3DVar = false; for (int i = 0; i < _validStats.GetVariableCount(); i++) { std::string varname = _validStats.GetVariableName(i); float m3[3], median, stddev; long count; _validStats.Get3MStats(varname, m3); _validStats.GetMedian(varname, &median); _validStats.GetStddev(varname, &stddev); _validStats.GetCount(varname, &count); file << varname << ", " << count; if (statsParams->GetMinEnabled()) file << ", " << m3[0]; if (statsParams->GetMaxEnabled()) file << ", " << m3[1]; if (statsParams->GetMeanEnabled()) file << ", " << m3[2]; if (statsParams->GetMedianEnabled()) file << ", " << median; if (statsParams->GetStdDevEnabled()) file << ", " << stddev; file << endl; for (int j = 0; j < availVars3D.size(); j++) if (availVars3D[j] == varname) { has3DVar = true; break; } } file << endl; std::vector myMin, myMax; statsParams->GetBox()->GetExtents(myMin, myMax); file << "#Spatial Extents:" << endl; file << "X min = " << myMin[0] << endl; file << "X max = " << myMax[0] << endl; file << "Y min = " << myMin[1] << endl; file << "Y max = " << myMax[1] << endl; if (has3DVar) { file << "Z min = " << myMin[2] << endl; file << "Z max = " << myMax[2] << endl; } file << endl; file << "#Temporal Extents:" << endl; file << "Minimum Timestep = " << statsParams->GetCurrentTimestep() << endl; file << "Maximum Timestep = " << statsParams->GetCurrentMaxTS() << endl; file << endl; file << "#Compression Parameters:" << endl; file << "Level of Detail = " << MyFidelityWidget->GetCurrentLodString() << endl; file << "Refinement Level = " << MyFidelityWidget->GetCurrentMultiresString() << endl; file.close(); } } ================================================ FILE: apps/vaporgui/Statistics.h ================================================ //************************************************************************ // * // Copyright (C) 2016 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: Statistics.h // // Author: Samuel Li // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: November 2017 // // Description: Implements the Statistics class. // #ifdef WIN32 #pragma warning(disable : 4100) #endif #ifndef STATISTICS_H #define STATISTICS_H #include #include #include #include #include #include "ui_statsWindow.h" #include #include #include "PWidgets.h" #include "Updatable.h" namespace VAPoR { class ParamsMgr; class DataMgr; } // namespace VAPoR class Statistics : public QDialog, public Ui_StatsWindow, public Updatable { Q_OBJECT public: Statistics(QWidget *parent); ~Statistics(); int initControlExec(VAPoR::ControlExec *ce); void showMe(); void Update(); protected: // Keeps the current variables shown and their statistical values. // Invalid values are stored as std::nan("1"); // class ValidStats { public: bool AddVariable(std::string &); bool RemoveVariable(std::string &); size_t GetVariableCount(); std::string GetVariableName(int i); bool Add3MStats(std::string &, const float *); // Min, Max, Mean bool AddMedian(std::string &, float); bool AddStddev(std::string &, float); bool AddCount(std::string &, long); // invalid values are represented as nan. bool Get3MStats(std::string &, float *); bool GetMedian(std::string &, float *); bool GetStddev(std::string &, float *); bool GetCount(std::string &, long *); bool InvalidAll(); // keep existing variables, but set values to nan bool Clear(); // clear all variables and values. // keeps the current parameters, and make them public. std::string currentDataSourceName; std::vector currentExtentMin, currentExtentMax; int currentTimeStep[2], currentLOD, currentRefLev; bool HaveSameParams(const VAPoR::StatisticsParams *rhs) const; bool UpdateMyParams(const VAPoR::StatisticsParams *rhs); bool SetCurrentExtents(const std::vector &min, const std::vector &max); bool SetCurrentExtents(const std::vector &min, const std::vector &max); private: std::vector _variables; std::vector _values[5]; // 0: min // 1: max // 2: mean // 3: median // 4: stddev std::vector _count; // number of samples int _getVarIdx(std::string &); // -1: not exist // >=0: a valid index }; // finish class ValidStats bool Connect(); // connect slots private slots: void _newVarChanged(int); void _removeVarChanged(int); void _newCalcChanged(int); void _removeCalcChanged(int); void _minTSChanged(int); void _maxTSChanged(int); void _updateButtonClicked(); void _geometryValueChanged(); void _dataSourceChanged(int); void _autoUpdateClicked(int); void _exportTextClicked(); private: ValidStats _validStats; VAPoR::ControlExec * _controlExec; std::vector _pw; void _updateStatsTable(); // calculations should put results in _validStats directly. bool _calc3M(std::string); // min, max, mean bool _calcMedian(std::string); bool _calcStddev(std::string); }; #endif ================================================ FILE: apps/vaporgui/StatisticsParams.cpp ================================================ //************************************************************************ // * // Copyright (C) 2014 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: StatisticsParams.cpp // // Author: Samuel Li // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: November 2017 // // Description: Implements the StatisticsParams class. // #include #include #include #include #include #include "vapor/VAssert.h" #include using namespace VAPoR; const string StatisticsParams::_maxTSTag = "MaxTS"; const string StatisticsParams::_autoUpdateTag = "AutoUpdate"; const string StatisticsParams::_minEnabledTag = "MinEnabled"; const string StatisticsParams::_maxEnabledTag = "MaxEnabled"; const string StatisticsParams::_meanEnabledTag = "MeanEnabled"; const string StatisticsParams::_medianEnabledTag = "MedianEnabled"; const string StatisticsParams::_stdDevEnabledTag = "StdDevEnabled"; // // Register class with object factory!!! // static RenParamsRegistrar registrar(StatisticsParams::GetClassType()); StatisticsParams::StatisticsParams(DataMgr *dmgr, ParamsBase::StateSave *ssave) : RenderParams(dmgr, ssave, StatisticsParams::GetClassType()) {} StatisticsParams::StatisticsParams(DataMgr *dmgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dmgr, ssave, node) { // If node isn't tagged correctly we correct the tag and reinitialize from scratch; // if (node->GetTag() != StatisticsParams::GetClassType()) { node->SetTag(StatisticsParams::GetClassType()); } } StatisticsParams::~StatisticsParams() { MyBase::SetDiagMsg("StatisticsParams::~StatisticsParams() this=%p", this); } bool StatisticsParams::GetAutoUpdateEnabled() { return (GetValueLong(_autoUpdateTag, (long)false)); } void StatisticsParams::SetAutoUpdateEnabled(bool val) { SetValueLong(_autoUpdateTag, "if we want stats auto-update", (long)val); } int StatisticsParams::GetCurrentMaxTS() const { return (int)(GetValueDouble(_maxTSTag, 0.0)); } void StatisticsParams::SetCurrentMaxTS(int ts) { SetValueDouble(_maxTSTag, "Maximum selected timestep for statistics", (double)ts); } bool StatisticsParams::GetMinEnabled() { return GetValueLong(_minEnabledTag, (long)true); } void StatisticsParams::SetMinEnabled(bool state) { SetValueLong(_minEnabledTag, "Minimum statistic calculation", (long)state); } bool StatisticsParams::GetMaxEnabled() { return GetValueLong(_maxEnabledTag, (long)true); } void StatisticsParams::SetMaxEnabled(bool state) { SetValueLong(_maxEnabledTag, "Maximum statistic calculation", (long)state); } bool StatisticsParams::GetMeanEnabled() { return GetValueLong(_meanEnabledTag, (long)true); } void StatisticsParams::SetMeanEnabled(bool state) { SetValueLong(_meanEnabledTag, "Mean statistic calculation", (long)state); } bool StatisticsParams::GetMedianEnabled() { return GetValueLong(_medianEnabledTag, (long)false); } void StatisticsParams::SetMedianEnabled(bool state) { SetValueLong(_medianEnabledTag, "Median statistic calculation", (long)state); } bool StatisticsParams::GetStdDevEnabled() { return GetValueLong(_stdDevEnabledTag, (long)false); } void StatisticsParams::SetStdDevEnabled(bool state) { SetValueLong(_stdDevEnabledTag, "Standard deviation statistic calculation", (long)state); } ================================================ FILE: apps/vaporgui/StatisticsParams.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************ // // File: StatisticsParams.h // // Author: Samuel Li // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: November 2017 // // Description: Defines the StatisticsParams class. // #ifndef STATISTICSPARAMS_H #define STATISTICSPARAMS_H #include namespace VAPoR { class StatisticsParams : public RenderParams { public: StatisticsParams(DataMgr *dmgr, ParamsBase::StateSave *ssave); StatisticsParams(DataMgr *dmgr, ParamsBase::StateSave *ssave, XmlNode *node); ~StatisticsParams(); bool GetAutoUpdateEnabled(); void SetAutoUpdateEnabled(bool state); // Note: we'll use the Get/SetCurrentTimestep() from RendererParams to // represent the min timestep, MinTS, so we only need to keep track of MaxTS. int GetCurrentMaxTS() const; void SetCurrentMaxTS(int ts); bool GetMinEnabled(); void SetMinEnabled(bool state); bool GetMaxEnabled(); void SetMaxEnabled(bool state); bool GetMeanEnabled(); void SetMeanEnabled(bool state); bool GetMedianEnabled(); void SetMedianEnabled(bool state); bool GetStdDevEnabled(); void SetStdDevEnabled(bool state); static string GetClassType() { return ("StatisticsParams"); } virtual size_t GetRenderDim() const override { return (0); } virtual string GetActualColorMapVariableName() const override { return ""; } private: static const string _maxTSTag; static const string _autoUpdateTag; static const string _minEnabledTag; static const string _maxEnabledTag; static const string _meanEnabledTag; static const string _medianEnabledTag; static const string _stdDevEnabledTag; }; }; // End namespace VAPoR #endif ================================================ FILE: apps/vaporgui/TFColorInfoWidget.cpp ================================================ #include "TFColorInfoWidget.h" #include #include #include #include #include #include "VLineItem.h" TFColorInfoWidget::TFColorInfoWidget(const std::string &variableNameTag) : TFInfoWidget(variableNameTag) { ((QBoxLayout *)layout())->addWidget(new VLineItem("Color", _colorEdit = new QColorWidget)); connect(_colorEdit, SIGNAL(colorChanged(QColor)), this, SLOT(colorEditChanged())); } void TFColorInfoWidget::DeselectControlPoint() { TFInfoWidget::DeselectControlPoint(); _colorEdit->setColor(Qt::gray); } void TFColorInfoWidget::SetColor(const QColor &color) { _colorEdit->setColor(color); } void TFColorInfoWidget::SetControlPoint(float value, const QColor &color) { this->setEnabled(true); SetNormalizedValue(value); SetColor(color); } void TFColorInfoWidget::controlPointChanged() { emit ControlPointChanged(_value, _colorEdit->getColor()); } void TFColorInfoWidget::colorEditChanged() { controlPointChanged(); } ================================================ FILE: apps/vaporgui/TFColorInfoWidget.h ================================================ #pragma once #include "TFInfoWidget.h" #include #include "QColorWidget.h" namespace VAPoR { class RenderParams; } class TFColorInfoWidget : public TFInfoWidget { Q_OBJECT public: TFColorInfoWidget(const std::string &variableNameTag); void SetColor(const QColor &color); protected: void controlPointChanged(); private: QColorWidget *_colorEdit; signals: void ControlPointChanged(float value, QColor color); public slots: void SetControlPoint(float value, const QColor &color); void DeselectControlPoint(); private slots: void colorEditChanged(); }; ================================================ FILE: apps/vaporgui/TFColorWidget.cpp ================================================ #include "TFColorWidget.h" #include #include #include #include #include #include #include "TFColorInfoWidget.h" #include "TFUtils.h" #include "QPaintUtils.h" #include "ParamsMenuItems.h" using namespace VAPoR; using glm::vec2; using std::vector; static vec2 qvec2(const QPoint &qp) { return vec2(qp.x(), qp.y()); } TFColorMap::TFColorMap(const std::string &variableNameTag, TFMapWidget *parent) : TFMap(variableNameTag, parent) { _colorInterpolationMenu = new ParamsDropdownMenuItem( this, VAPoR::ColorMap::_interpTypeTag, {"Linear HSV", "Linear RGB", "Linear LAB", "Linear LCH", "Discrete", "Diverging"}, {TFInterpolator::linear, TFInterpolator::linearRGB, TFInterpolator::linearLAB, TFInterpolator::linearLCH, TFInterpolator::discrete, TFInterpolator::diverging}, "Color Interpolation"); _colorInterpolationWhitepointAction = new ParamsCheckboxMenuItem(this, ColorMap::_useWhitespaceTag, "Add Whitespace"); _colorInterpolationMenu->menu()->addAction(_colorInterpolationWhitepointAction); } QSize TFColorMap::minimumSizeHint() const { return QSize(100, 30); } QSizePolicy TFColorMap::GetSizePolicy() const { return QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); } void TFColorMap::LostFocus() { DeselectControlPoint(); } #define PROPERTY_INDEX ("index") #define PROPERTY_VALUE ("value") void TFColorMap::PopulateContextMenu(QMenu *menu, const glm::vec2 &p) { int selected = findSelectedControlPoint(p); if (selected != -1) menu->addAction("Delete control point", this, SLOT(menuDeleteSelectedControlPoint()))->setProperty(PROPERTY_INDEX, selected); else menu->addAction("Add control point", this, SLOT(menuAddControlPoint()))->setProperty(PROPERTY_VALUE, QVariant(valueForControlX(p.x))); } void TFColorMap::PopulateSettingsMenu(QMenu *menu) const { menu->addAction(_colorInterpolationMenu); menu->addAction("Reverse Colormap", this, SLOT(menuReverse())); menu->addSeparator(); menu->addAction("Save Colormap", this, SLOT(menuSave())); menu->addAction("Load Colormap", this, SLOT(menuLoad())); QMenu *builtinColormapMenu = menu->addMenu("Load Built-In Colormap"); string builtinPath = GetSharePath("palettes"); populateBuiltinColormapMenu(builtinColormapMenu, builtinPath); } void TFColorMap::populateBuiltinColormapMenu(QMenu *menu, const std::string &builtinPath) const { auto fileNames = FileUtils::ListFiles(builtinPath); std::sort(fileNames.begin(), fileNames.end()); for (int i = 0; i < fileNames.size(); i++) { string path = FileUtils::JoinPaths({builtinPath, fileNames[i]}); if (FileUtils::IsDirectory(path)) populateBuiltinColormapMenu(menu->addMenu(QString::fromStdString(fileNames[i])), path); } for (int i = 0; i < fileNames.size(); i++) { string path = FileUtils::JoinPaths({builtinPath, fileNames[i]}); if (FileUtils::Extension(path) != "tf3") continue; QAction *item = new ColorMapMenuItem(path); connect(item, SIGNAL(triggered(std::string)), this, SLOT(menuLoadBuiltin(std::string))); menu->addAction(item); } } void TFColorMap::paramsUpdate() { const auto cm = getColormap(); _colorInterpolationMenu->Update(cm); _colorInterpolationWhitepointAction->Update(cm); _colorInterpolationWhitepointAction->setEnabled(cm->GetInterpType() == TFInterpolator::diverging); updateImage(); _paramsNormalizedControlPoints.resize(cm->numControlPoints()); for (int i = 0; i < _paramsNormalizedControlPoints.size(); i++) _paramsNormalizedControlPoints[i] = cm->controlPointValueNormalized(i); update(); if (_selectedId > -1) UpdateInfo(getColormap()->controlPointValueNormalized(_selectedId), VColorToQColor(getColormap()->controlPointColor(_selectedId))); } void TFColorMap::updateImage() { if (width() <= 0) return; ColorMap *cm = getRenderParams()->GetMapperFunc(getVariableName())->GetColorMap(); QMargins padding = GetPadding(); int nSamples = width() - (padding.left() + padding.right()); nSamples = std::max(nSamples, 256); _imageData.resize(nSamples * 3); float rgb[3]; for (int i = 0; i < nSamples; i++) { cm->colorNormalized(i / (float)nSamples).toRGB(rgb); _imageData[i * 3 + 0] = rgb[0] * 255; _imageData[i * 3 + 1] = rgb[1] * 255; _imageData[i * 3 + 2] = rgb[2] * 255; } _image = QImage(_imageData.data(), nSamples, 1, QImage::Format::Format_RGB888); } TFInfoWidget *TFColorMap::createInfoWidget() { TFColorInfoWidget *info = new TFColorInfoWidget(getVariableNameTag()); connect(this, SIGNAL(ControlPointDeselected()), info, SLOT(DeselectControlPoint())); connect(this, SIGNAL(UpdateInfo(float, QColor)), info, SLOT(SetControlPoint(float, QColor))); connect(info, SIGNAL(ControlPointChanged(float, QColor)), this, SLOT(UpdateFromInfo(float, QColor))); return info; } #define CONTROL_POINT_RADIUS (4.0f) #define PADDING (CONTROL_POINT_RADIUS + 1.0f) void TFColorMap::_paintEvent(QPainter &p) { // 243 245 249 p.fillRect(rect(), Qt::lightGray); QPaintUtils::BoxDropShadow(p, paddedRect(), 10, QColor(0, 0, 0, 120)); p.drawImage(paddedRect(), _image); for (int i = 0; i < _paramsNormalizedControlPoints.size(); i++) { drawControl(p, controlQPositionForValue(_paramsNormalizedControlPoints[i]), i == _selectedId); } } void TFColorMap::mousePressEvent(QMouseEvent *event) { emit Activated(this); ColorMap *cm = getColormap(); vec2 mouse(event->pos().x(), event->pos().y()); for (int i = 0; i < cm->numControlPoints(); i++) { float value = cm->controlPointValueNormalized(i); if (controlPointContainsPixel(value, mouse)) { _isDraggingControl = true; _draggingControlID = i; selectControlPoint(i); update(); _dragOffset = controlPositionForValue(value) - mouse; BeginSaveStateGroup(getParamsMgr(), "Colormap modification"); return; } } DeselectControlPoint(); event->ignore(); update(); } void TFColorMap::mouseReleaseEvent(QMouseEvent *event) { if (_isDraggingControl) EndSaveStateGroup(getParamsMgr()); else event->ignore(); _isDraggingControl = false; } void TFColorMap::mouseMoveEvent(QMouseEvent *event) { vec2 mouse = qvec2(event->pos()); if (_isDraggingControl) { float newVal = glm::clamp(valueForControlX(mouse.x + _dragOffset.x), 0.f, 1.f); moveControlPoint(&_draggingControlID, newVal); selectControlPoint(_draggingControlID); updateImage(); paramsUpdate(); getParamsMgr()->IntermediateChange(); } else { event->ignore(); } } void TFColorMap::mouseDoubleClickEvent(QMouseEvent *event) { vec2 mouse = qvec2(event->pos()); int selectedId = findSelectedControlPoint(mouse); if (selectedId >= 0) { deleteControlPoint(selectedId); return; } float newVal = valueForControlX(mouse.x); if (newVal >= 0 && newVal <= 1) addControlPoint(newVal); } void TFColorMap::moveControlPoint(int *index, float value, const VAPoR::ColorMap::Color &c) { ColorMap *cm = getColormap(); cm->deleteControlPoint(*index); *index = cm->addNormControlPoint(value, c); } void TFColorMap::moveControlPoint(int *index, float value) { ColorMap * cm = getColormap(); ColorMap::Color c = cm->controlPointColor(_draggingControlID); moveControlPoint(index, value, c); } void TFColorMap::deleteControlPoint(int index) { ColorMap *cm = getColormap(); if (cm->numControlPoints() == 1) return; if (index == _selectedId) DeselectControlPoint(); else if (index < _selectedId) _selectedId--; cm->deleteControlPoint(index); update(); } void TFColorMap::addControlPoint(float value) { selectControlPoint(getColormap()->addNormControlPointAt(value)); update(); } ColorMap *TFColorMap::getColormap() const { return getRenderParams()->GetMapperFunc(getVariableName())->GetColorMap(); } void TFColorMap::selectControlPoint(int index) { _selectedId = index; ColorMap *cm = getColormap(); float value = cm->controlPointValueNormalized(index); ColorMap::Color vColor = cm->controlPointColor(index); UpdateInfo(value, VColorToQColor(vColor)); } void TFColorMap::DeselectControlPoint() { _selectedId = -1; emit ControlPointDeselected(); update(); } void TFColorMap::UpdateFromInfo(float value, QColor color) { moveControlPoint(&_selectedId, value, QColorToVColor(color)); } void TFColorMap::menuDeleteSelectedControlPoint() { emit Activated(this); const ColorMap *cm = getColormap(); QVariant valueVariant = sender()->property(PROPERTY_INDEX); if (valueVariant.isValid()) { int index = valueVariant.toInt(); if (index >= 0 && index < cm->numControlPoints()) deleteControlPoint(index); } } void TFColorMap::menuAddControlPoint() { emit Activated(this); QVariant value = sender()->property(PROPERTY_VALUE); if (value.isValid()) addControlPoint(value.toFloat()); } void TFColorMap::menuLoad() { RenderParams *rp = getRenderParams(); if (!rp) return; TFUtils::LoadColormap(getParamsMgr(), rp->GetMapperFunc(getVariableName())); } void TFColorMap::menuSave() { RenderParams *rp = getRenderParams(); if (!rp) return; TFUtils::SaveTransferFunction(getParamsMgr(), rp->GetMapperFunc(getVariableName())); } void TFColorMap::menuLoadBuiltin(std::string path) { RenderParams *rp = getRenderParams(); if (!rp) return; TFUtils::LoadColormap(rp->GetMapperFunc(getVariableName()), path); } void TFColorMap::menuReverse() { RenderParams *rp = getRenderParams(); if (!rp) return; MapperFunction *tf = rp->GetMapperFunc(getVariableName()); ColorMap * cm = tf->GetColorMap(); cm->Reverse(); } int TFColorMap::findSelectedControlPoint(const glm::vec2 &mouse) const { const ColorMap *cm = getColormap(); const int n = cm->numControlPoints(); for (int i = 0; i < n; i++) if (controlPointContainsPixel(cm->controlPointValueNormalized(i), mouse)) return i; return -1; } bool TFColorMap::controlPointContainsPixel(float cp, const vec2 &pixel) const { return glm::distance(pixel, controlPositionForValue(cp)) <= GetControlPointRadius(); } QPointF TFColorMap::controlQPositionForValue(float value) const { const vec2 v = controlPositionForValue(value); return QPointF(v.x, v.y); } glm::vec2 TFColorMap::controlPositionForValue(float value) const { return vec2(controlXForValue(value), height() / 2.f); } float TFColorMap::controlXForValue(float value) const { return NDCToPixel(vec2(value, 0.f)).x; } float TFColorMap::valueForControlX(float position) const { return PixelToNDC(vec2(position, 0.f)).x; } QColor TFColorMap::VColorToQColor(const ColorMap::Color &c) { float rgb[3]; c.toRGB(rgb); return QColor(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255); } ColorMap::Color TFColorMap::QColorToVColor(const QColor &c) { double h, s, v; c.getHsvF(&h, &s, &v); return ColorMap::Color(h, s, v); } #include #include std::map ColorMapMenuItem::icons; QIcon ColorMapMenuItem::getCachedIcon(const std::string &path) { auto it = icons.find(path); if (it != icons.end()) return it->second; ParamsBase::StateSave stateSave; MapperFunction mf(&stateSave); mf.LoadColormapFromFile(path); ColorMap *cm = mf.GetColorMap(); QSize size = getIconSize(); int nSamples = size.width(); unsigned char *buf = new unsigned char[nSamples * 3]; float rgb[3]; for (int i = 0; i < nSamples; i++) { cm->colorNormalized(i / (float)nSamples).toRGB(rgb); buf[i * 3 + 0] = rgb[0] * 255; buf[i * 3 + 1] = rgb[1] * 255; buf[i * 3 + 2] = rgb[2] * 255; } QImage image(buf, nSamples, 1, QImage::Format::Format_RGB888); icons[path] = QIcon(QPixmap::fromImage(image).scaled(size.width(), size.height())); delete[] buf; return icons[path]; } QSize ColorMapMenuItem::getIconSize() { return QSize(50, 15); } QSize ColorMapMenuItem::getIconPadding() { return QSize(10, 10); } ColorMapMenuItem::ColorMapMenuItem(const std::string &path) : QWidgetAction(nullptr), _path(path) { QPushButton *button = new QPushButton; setDefaultWidget(button); button->setIcon(getCachedIcon(path)); button->setFixedSize(getIconSize() + getIconPadding()); button->installEventFilter(this); string name = STLUtils::Split(FileUtils::Basename(path), ".")[0]; button->setToolTip(QString::fromStdString(name)); button->setStyleSheet(R"( QPushButton { icon-size: 50px 15px; padding: 0px; margin: 0px; background: none; border: none; } QPushButton::hover { background: #aaa; } )"); } // Manually riggering an action does not close the menu so it has to be done manually. void ColorMapMenuItem::CloseMenu(QAction *action) { if (!action) return; QList menus = action->associatedWidgets(); for (QWidget *widget : menus) { QMenu *menu = dynamic_cast(widget); if (!menu) continue; if (menu->isHidden()) continue; menu->hide(); CloseMenu(menu->menuAction()); } } bool ColorMapMenuItem::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::MouseButtonRelease) { trigger(); emit triggered(_path); CloseMenu(this); return true; } return QObject::eventFilter(obj, event); } ================================================ FILE: apps/vaporgui/TFColorWidget.h ================================================ #pragma once #include "TFMapWidget.h" #include #include #include #include class TFColorInfoWidget; class ParamsDropdownMenuItem; class ParamsCheckboxMenuItem; class TFColorMap : public TFMap { Q_OBJECT public: TFColorMap(const std::string &variableNameTag, TFMapWidget *parent = nullptr); QSize minimumSizeHint() const override; QSizePolicy GetSizePolicy() const override; void LostFocus() override; void PopulateContextMenu(QMenu *menu, const glm::vec2 &p) override; void PopulateSettingsMenu(QMenu *menu) const override; private: void populateBuiltinColormapMenu(QMenu *menu, const std::string &builtinPath) const; protected: void paramsUpdate() override; TFInfoWidget *createInfoWidget() override; void _paintEvent(QPainter &p) override; void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseDoubleClickEvent(QMouseEvent *event) override; private: ParamsDropdownMenuItem *_colorInterpolationMenu; ParamsCheckboxMenuItem *_colorInterpolationWhitepointAction; bool _isDraggingControl = false; int _draggingControlID; int _selectedId = -1; glm::vec2 _dragOffset; glm::vec2 m; QImage _image; vector _imageData; std::vector _paramsNormalizedControlPoints; void updateImage(); bool controlPointContainsPixel(const glm::vec2 &cp, const glm::vec2 &pixel) const; void moveControlPoint(int *index, float value, const VAPoR::ColorMap::Color &c); void moveControlPoint(int *index, float value); void deleteControlPoint(int index); void addControlPoint(float value); VAPoR::ColorMap *getColormap() const; void selectControlPoint(int index); int findSelectedControlPoint(const glm::vec2 &mouse) const; bool controlPointContainsPixel(float cp, const glm::vec2 &pixel) const; QPointF controlQPositionForValue(float value) const; glm::vec2 controlPositionForValue(float value) const; float controlXForValue(float value) const; float valueForControlX(float position) const; static QColor VColorToQColor(const VAPoR::ColorMap::Color &c); static VAPoR::ColorMap::Color QColorToVColor(const QColor &c); signals: void ControlPointDeselected(); void UpdateInfo(float value, QColor color); public slots: void DeselectControlPoint(); void UpdateFromInfo(float value, QColor color); private slots: void menuDeleteSelectedControlPoint(); void menuAddControlPoint(); void menuLoad(); void menuSave(); void menuLoadBuiltin(std::string path); void menuReverse(); }; class TFColorWidget : public TFMapWidget { Q_OBJECT public: TFColorWidget(const std::string &variableNameTag) : TFMapWidget(new TFColorMap(variableNameTag, this)) {} }; #include class ColorMapMenuItem : public QWidgetAction { Q_OBJECT static std::map icons; static QIcon getCachedIcon(const std::string &path); static QSize getIconSize(); static QSize getIconPadding(); const std::string _path; public: ColorMapMenuItem(const std::string &path); static void CloseMenu(QAction *action); protected: bool eventFilter(QObject *obj, QEvent *event); signals: void triggered(std::string colormapPath); }; ================================================ FILE: apps/vaporgui/TFHistogramInfoWidget.cpp ================================================ #include "TFHistogramInfoWidget.h" #include #include #include TFHistogramInfoWidget::TFHistogramInfoWidget(const std::string &variableNameTag) : TFInfoWidget(variableNameTag) { _valueEdit->SetReadOnly(true); } void TFHistogramInfoWidget::SetControlPoint(float value) { this->setEnabled(true); SetNormalizedValue(value); } void TFHistogramInfoWidget::Deselect() { this->setEnabled(false); _valueEdit->Clear(); } ================================================ FILE: apps/vaporgui/TFHistogramInfoWidget.h ================================================ #pragma once #include "TFInfoWidget.h" #include namespace VAPoR { class RenderParams; } class TFHistogramInfoWidget : public TFInfoWidget { Q_OBJECT using TFInfoWidget::TFInfoWidget; public: TFHistogramInfoWidget(const std::string &variableNameTag); public slots: void SetControlPoint(float value); void Deselect(); }; ================================================ FILE: apps/vaporgui/TFHistogramWidget.cpp ================================================ #include "TFHistogramWidget.h" #include "TFHistogramInfoWidget.h" #include #include #include #include #include #include #include "ErrorReporter.h" #include #include #include #include "QPaintUtils.h" #include "ParamsMenuItems.h" using namespace VAPoR; using glm::clamp; using glm::vec2; using std::vector; #define SCALING_TAG "HistogramScalingTag" TFHistogramMap::TFHistogramMap(const std::string &variableNameTag, TFMapWidget *parent) : TFMap(variableNameTag, parent) { _scalingMenu = new ParamsDropdownMenuItem(this, SCALING_TAG, {"Linear", "Logarithmic", "Boolean"}, {}, "Histogram Scaling"); } QSize TFHistogramMap::minimumSizeHint() const { // return QSize(100, 40); return QSize(100, 75); } void TFHistogramMap::PopulateSettingsMenu(QMenu *menu) const { menu->addAction(_scalingMenu); QAction *histogramDynamicScalingAction = menu->addAction("Histogram Dynamic Scaling", this, SLOT(_menuDynamicScalingToggled(bool))); histogramDynamicScalingAction->setCheckable(true); histogramDynamicScalingAction->setChecked(_dynamicScaling); } void TFHistogramMap::paramsUpdate() { RenderParams *rp = getRenderParams(); if (rp->GetValueDoubleVec(RenderParams::CustomHistogramRangeTag).size()) { auto range = rp->GetValueDoubleVec(RenderParams::CustomHistogramRangeTag); auto bins = rp->GetValueLongVec(RenderParams::CustomHistogramDataTag); int numBins = bins.size(); _histo.reset(numBins, range[0], range[1]); _histo.setBins(bins); } else { int numBins = width() ? width() : 256; if (_histo.getNumBins() != numBins) _histo.reset(numBins); // This can be called before it is resized if (_histo.PopulateIfNeeded(getVariableName(), getDataMgr(), getRenderParams()) < 0) MSG_ERR("Failed to populate histogram"); } _scalingMenu->Update(getRenderParams()); _mapRange = getRenderParams()->GetMapperFunc(getVariableName())->getMinMaxMapValue(); update(); } TFInfoWidget *TFHistogramMap::createInfoWidget() { TFHistogramInfoWidget *info = new TFHistogramInfoWidget(getVariableNameTag()); connect(this, SIGNAL(UpdateInfo(float)), info, SLOT(SetControlPoint(float))); connect(this, SIGNAL(InfoDeselected()), info, SLOT(Deselect())); return info; } void TFHistogramMap::_paintEvent(QPainter &p) { if (width() == 0) return; p.fillRect(rect(), Qt::lightGray); QPolygonF graph; graph.push_back(NDCToQPixel(0, 0)); int startBin = _histo.getBinIndexForValue(_mapRange[0]); int endBin = _histo.getBinIndexForValue(_mapRange[1]); int stride = 1; QMargins padding = GetPadding(); while ((endBin - startBin) / stride >= 2 * (width() - (padding.left() + padding.right()))) stride *= 2; startBin -= startBin % stride; // Prevents an edge case where the current range is very far from the computed one if (_histo.getRange() < FLT_EPSILON || (_mapRange[1] - _mapRange[0]) / _histo.getRange() > 10000) return; float maxBin; if (_dynamicScaling) maxBin = _histo.getMaxBinSizeBetweenIndices(startBin, endBin); else maxBin = _histo.getMaxBinSize(); const float logMaxBin = maxBin == 1 ? 1 : logf(maxBin); ScalingType scaling = _getScalingType(); for (int i = startBin; i < endBin; i += stride) { float bin = _histo.getBinSize(i, stride); switch (scaling) { default: case ScalingType::Linear: bin /= maxBin; break; case ScalingType::Logarithmic: bin = bin == 0 ? 0 : logf(bin) / logMaxBin; break; case ScalingType::Boolean: bin = bin > 0 ? 1 : 0; break; } graph.push_back(NDCToQPixel((i - startBin) / (float)(endBin - startBin), bin)); } graph.push_back(NDCToQPixel(1, 0)); QPicture picture; QPainter pp(&picture); pp.setRenderHint(QPainter::Antialiasing); pp.setPen(Qt::NoPen); pp.setBrush(QBrush(QColor(56, 128, 255))); pp.drawPolygon(graph); pp.end(); QPaintUtils::DropShadow(p, picture, 10, QColor(56, 128, 255, 150)); p.drawPicture(0, 0, picture); QPaintUtils::InnerShadow(p, picture, 10, QColor(0, 0, 0, 100)); } void TFHistogramMap::mousePressEvent(QMouseEvent *event) { emit Activated(this); emit UpdateInfo(PixelToNDC(event->pos()).x); } void TFHistogramMap::mouseReleaseEvent(QMouseEvent *event) { emit InfoDeselected(); } void TFHistogramMap::mouseMoveEvent(QMouseEvent *event) { emit UpdateInfo(PixelToNDC(event->pos()).x); } // void TFHistogramWidget::mouseDoubleClickEvent(QMouseEvent *event) TFHistogramMap::ScalingType TFHistogramMap::_getScalingType() const { if (!getRenderParams()) return ScalingType::Linear; ScalingType type = (ScalingType)getRenderParams()->GetValueLong(SCALING_TAG, (int)ScalingType::Linear); if (type >= ScalingTypeCount || type < 0) type = Linear; return type; } void TFHistogramMap::_menuDynamicScalingToggled(bool on) { _dynamicScaling = on; } ================================================ FILE: apps/vaporgui/TFHistogramWidget.h ================================================ #pragma once #include #include #include #include #include "TFMapWidget.h" class ParamsDropdownMenuItem; class TFHistogramMap : public TFMap { Q_OBJECT enum ScalingType { Linear = 0, Logarithmic, Boolean, ScalingTypeCount }; public: TFHistogramMap(const std::string &variableNameTag, TFMapWidget *parent = nullptr); QSize minimumSizeHint() const; void LostFocus() {} void PopulateSettingsMenu(QMenu *menu) const; protected: void paramsUpdate(); TFInfoWidget *createInfoWidget(); void _paintEvent(QPainter &p); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); // void mouseDoubleClickEvent(QMouseEvent *event); private: Histo _histo; ParamsDropdownMenuItem *_scalingMenu; bool _dynamicScaling = true; vector _mapRange; ScalingType _getScalingType() const; private slots: void _menuDynamicScalingToggled(bool on); signals: void InfoDeselected(); void UpdateInfo(float value); }; class TFHistogramWidget : public TFMapWidget { Q_OBJECT public: TFHistogramWidget(const std::string &variableNameTag) : TFMapWidget(new TFHistogramMap(variableNameTag, this)) {} }; ================================================ FILE: apps/vaporgui/TFInfoWidget.cpp ================================================ #include "TFInfoWidget.h" #include #include #include #include #include #ifndef __FLT_MIN__ #define __FLT_MIN__ FLT_MIN #define __FLT_MAX__ FLT_MAX #endif TFInfoWidget::TFInfoWidget(const std::string &variableNameTag) : _variableNameTag(variableNameTag) { QBoxLayout *layout = new QVBoxLayout; layout->setSpacing(12); layout->setMargin(0); this->setLayout(layout); layout->addWidget(new VLineItem("Data Value", _valueEdit = new VDoubleLineEdit)); _valueEditType = new QComboBox; _valueEditType->blockSignals(true); _valueEditType->setMinimumSize(30, 10); _valueEditType->setSizeAdjustPolicy(QComboBox::AdjustToContents); _valueEditType->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); _valueEditType->addItem("data"); _valueEditType->addItem("%"); _valueEditType->blockSignals(false); connect(_valueEditType, SIGNAL(currentIndexChanged(int)), this, SLOT(valueEditTypeChanged(int))); connect(_valueEdit, &VDoubleLineEdit::ValueChanged, this, &TFInfoWidget::valueEditChanged); this->setDisabled(true); } void TFInfoWidget::Update(VAPoR::RenderParams *rParams) { if (!rParams) return; string variableName = rParams->GetValueString(_variableNameTag, ""); _min = rParams->GetMapperFunc(variableName)->getMinMapValue(); _max = rParams->GetMapperFunc(variableName)->getMaxMapValue(); updateValueEditValidator(); } void TFInfoWidget::DeselectControlPoint() { this->setDisabled(true); _valueEdit->Clear(); } void TFInfoWidget::SetNormalizedValue(float value) { value = value < 0 ? 0 : value > 1 ? 1 : value; _value = value; updateValue(); } void TFInfoWidget::paintEvent(QPaintEvent *event) { QStyleOption opt; opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); QWidget::paintEvent(event); } void TFInfoWidget::updateValue() { if (!isEnabled()) return; float value = _value; if (isUsingMappedValue()) value = toMappedValue(value); else value *= 100; _valueEdit->SetValueDouble(value); } void TFInfoWidget::updateValueEditValidator() { if (isUsingMappedValue()) _valueEdit->SetRange(_min, _max); else _valueEdit->SetRange(0, 100); } bool TFInfoWidget::isUsingNormalizedValue() const { return _valueEditType->currentIndex() == ValueFormat::Percent; } bool TFInfoWidget::isUsingMappedValue() const { return _valueEditType->currentIndex() == ValueFormat::Mapped; } float TFInfoWidget::toMappedValue(float normalized) const { return normalized * (_max - _min) + _min; } float TFInfoWidget::toNormalizedValue(float mapped) const { if (_max == _min) return 0; return (mapped - _min) / (_max - _min); } float TFInfoWidget::getValueFromEdit() const { float value = _valueEdit->GetValueDouble(); if (isUsingMappedValue()) return toNormalizedValue(value); else return value / 100.f; } void TFInfoWidget::valueEditTypeChanged(int) { updateValue(); updateValueEditValidator(); } void TFInfoWidget::valueEditChanged() { _value = getValueFromEdit(); controlPointChanged(); } ================================================ FILE: apps/vaporgui/TFInfoWidget.h ================================================ #pragma once #include #include #include #include namespace VAPoR { class RenderParams; } //! \class TFInfoWidget //! The TFInfoWidget displays details and allow users to manually edit values for the control //! points used by the TFMapWidget class TFInfoWidget : public QWidget { Q_OBJECT public: enum ValueFormat { Mapped = 0, Percent = 1 }; TFInfoWidget(const std::string &variableNameTag); void Update(VAPoR::RenderParams *rParams); void DeselectControlPoint(); void SetNormalizedValue(float value); protected: void paintEvent(QPaintEvent *event); void updateValue(); void updateValueEditValidator(); bool isUsingNormalizedValue() const; bool isUsingMappedValue() const; float toMappedValue(float normalized) const; float toNormalizedValue(float mapped) const; float getValueFromEdit() const; virtual void controlPointChanged(){}; protected: VDoubleLineEdit *_valueEdit; QComboBox * _valueEditType; float _min = 0; float _max = 1; protected: float _value; const std::string _variableNameTag; private slots: void valueEditTypeChanged(int); void valueEditChanged(); }; ================================================ FILE: apps/vaporgui/TFIsoValueInfoWidget.cpp ================================================ #include "TFIsoValueInfoWidget.h" #include #include #include void TFIsoValueInfoWidget::controlPointChanged() { emit ControlPointChanged(this->getValueFromEdit()); } void TFIsoValueInfoWidget::SetControlPoint(float value) { this->setEnabled(true); SetNormalizedValue(value); } void TFIsoValueInfoWidget::Deselect() { this->setEnabled(false); _valueEdit->Clear(); } ================================================ FILE: apps/vaporgui/TFIsoValueInfoWidget.h ================================================ #pragma once #include "TFInfoWidget.h" #include namespace VAPoR { class RenderParams; } class TFIsoValueInfoWidget : public TFInfoWidget { Q_OBJECT using TFInfoWidget::TFInfoWidget; protected: void controlPointChanged(); signals: void ControlPointChanged(float value); public slots: void SetControlPoint(float value); void Deselect(); }; ================================================ FILE: apps/vaporgui/TFIsoValueWidget.cpp ================================================ #include "TFIsoValueWidget.h" #include #include #include #include #include "QPaintUtils.h" #include "TFIsoValueInfoWidget.h" using namespace VAPoR; using glm::vec2; using std::vector; static vec2 qvec2(const QPoint &qp) { return vec2(qp.x(), qp.y()); } TFIsoValueMap::TFIsoValueMap(const std::string &variableNameTag, TFMapWidget *parent) : TFMap(variableNameTag, parent) {} void TFIsoValueMap::paramsUpdate() { if (!getRenderParams()->HasIsoValues()) { hide(); return; } loadFromParams(getRenderParams()); update(); if (_selectedId > -1) UpdateInfo(_isoValues[_selectedId]); } QSizePolicy TFIsoValueMap::GetSizePolicy() const { return QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); } #define PROPERTY_INDEX ("index") #define PROPERTY_VALUE ("value") void TFIsoValueMap::PopulateContextMenu(QMenu *menu, const glm::vec2 &p) { if (_equidistantIsoValues) return; int selectedId = findSelectedControlPoint(p); if (selectedId != -1) menu->addAction("Delete control point", this, SLOT(menuDeleteControlPoint()))->setProperty(PROPERTY_INDEX, selectedId); else { QAction *action = menu->addAction("Add control point", this, SLOT(menuAddControlPoint())); action->setProperty(PROPERTY_VALUE, QVariant(valueForControlX(p.x))); if (_isoValues.size() >= 4) action->setDisabled(true); } } QSize TFIsoValueMap::minimumSizeHint() const { QSize s = GetControlPointArea(QPoint(0, 0)).size(); if (BottomPadding) s.setHeight(s.height() + GetControlPointRadius()); return s; } void TFIsoValueMap::LostFocus() { DeselectControlPoint(); } TFInfoWidget *TFIsoValueMap::createInfoWidget() { TFIsoValueInfoWidget *info = new TFIsoValueInfoWidget(getVariableNameTag()); connect(this, SIGNAL(ControlPointDeselected()), info, SLOT(Deselect())); connect(this, SIGNAL(UpdateInfo(float)), info, SLOT(SetControlPoint(float))); connect(info, SIGNAL(ControlPointChanged(float)), this, SLOT(UpdateFromInfo(float))); return info; } void TFIsoValueMap::_paintEvent(QPainter &p) { p.fillRect(rect(), Qt::lightGray); for (int i = 0; i < _isoValues.size(); i++) { float v = _isoValues[i]; bool invalid = false; if (v < 0 || v > 1) { v = glm::clamp(v, 0.f, 1.f); invalid = true; } drawControl(p, controlQPositionForValue(v), i == _selectedId, invalid); } if (_isoValues.size() == 0) { QFont font = getFont(); font.setPixelSize(rect().height()); p.setFont(font); p.drawText(rect(), Qt::AlignCenter, "doubleclick to add isovalues"); } } void TFIsoValueMap::drawControl(QPainter &p, const QPointF &pos, bool selected, bool invalid) const { float r = GetControlPointRadius(); float t = GetControlPointTriangleHeight(); float s = GetControlPointSquareHeight(); QPen pen(Qt::darkGray, 0.5); QBrush brush(QColor(0xfa, 0xfa, 0xfa)); p.setBrush(brush); p.setPen(pen); if (invalid) p.setBrush(QBrush(QColor(0xfa, 0x8a, 0x8a))); QPolygonF graph; graph.push_back(pos + QPointF(0, 0)); graph.push_back(pos + QPointF(-r, t)); graph.push_back(pos + QPointF(-r, t + s)); graph.push_back(pos + QPointF(r, t + s)); graph.push_back(pos + QPointF(r, t)); p.drawPolygon(graph); if (selected) { if (selected) { p.setPen(Qt::NoPen); p.setBrush(QBrush(Qt::black)); r *= 0.38; p.drawEllipse(pos + QPointF(0, t + (s / 3)), r, r); } } } float TFIsoValueMap::GetControlPointTriangleHeight() const { return GetControlPointRadius() * 2 * 0.618; } float TFIsoValueMap::GetControlPointSquareHeight() const { return GetControlPointRadius() * 1.618; } QRect TFIsoValueMap::GetControlPointArea(const QPoint &p) const { float h = GetControlPointSquareHeight() + GetControlPointTriangleHeight(); float r = GetControlPointRadius(); return QRect(p - QPoint(r, 0), p + QPoint(r, h)); } void TFIsoValueMap::mousePressEvent(QMouseEvent *event) { emit Activated(this); vec2 mouse(event->pos().x(), event->pos().y()); int selectedId = findSelectedControlPoint(mouse); if (selectedId >= 0) { _isDraggingControl = true; _draggingControlID = selectedId; selectControlPoint(selectedId); update(); _dragOffset = controlPositionForValue(glm::clamp(_isoValues[selectedId], 0.f, 1.f)) - mouse; getParamsMgr()->BeginSaveStateGroup("IsoValue modification"); return; } DeselectControlPoint(); event->ignore(); update(); } void TFIsoValueMap::mouseReleaseEvent(QMouseEvent *event) { if (_isDraggingControl) getParamsMgr()->EndSaveStateGroup(); else event->ignore(); _isDraggingControl = false; } void TFIsoValueMap::mouseMoveEvent(QMouseEvent *event) { vec2 mouse = qvec2(event->pos()); if (_isDraggingControl) { float newVal = glm::clamp(valueForControlX(mouse.x + _dragOffset.x), 0.f, 1.f); moveControlPoint(&_draggingControlID, newVal); selectControlPoint(_draggingControlID); saveToParams(getRenderParams()); update(); getParamsMgr()->IntermediateChange(); } else { event->ignore(); } } void TFIsoValueMap::mouseDoubleClickEvent(QMouseEvent *event) { if (_equidistantIsoValues) return; vec2 mouse = qvec2(event->pos()); int selectedId = findSelectedControlPoint(mouse); if (selectedId >= 0) { deleteControlPoint(selectedId); return; } if (_isoValues.size() < 4) { float newVal = valueForControlX(mouse.x); if (newVal >= 0 && newVal <= 1) { addControlPoint(newVal); } return; } } QMargins TFIsoValueMap::GetPadding() const { QMargins m = TFMap::GetPadding(); m.setTop(0); return m; } void TFIsoValueMap::saveToParams(VAPoR::RenderParams *rp) const { if (!rp) return; if (!rp->HasIsoValues()) return; assert(rp->HasIsoValues()); const float min = getMapRangeMin(); const float max = getMapRangeMax(); vector values(_isoValues.size()); for (int i = 0; i < values.size(); i++) values[i] = _isoValues[i] * (max - min) + min; rp->SetIsoValues(values); } void TFIsoValueMap::loadFromParams(VAPoR::RenderParams *rp) { if (!rp) return; if (!rp->HasIsoValues()) return; assert(rp->HasIsoValues()); const float min = getMapRangeMin(); const float max = getMapRangeMax(); vector newValues = rp->GetIsoValues(); if (newValues.size() != _isoValues.size()) { DeselectControlPoint(); _isoValues.resize(newValues.size()); } for (int i = 0; i < newValues.size(); i++) _isoValues[i] = (newValues[i] - min) / (max - min); // if (!_equidistantIsoValues) // clampIsoValuesToMappingRange(); } // void TFIsoValueMap::clampIsoValuesToMappingRange() //{ // / for (int i = 0; i < _isoValues.size(); i++) // _isoValues[i] = glm::clamp(_isoValues[i], 0.f, 1.f); //} int TFIsoValueMap::addControlPoint(float value) { int index = -1; for (int i = 0; i < _isoValues.size(); i++) { if (value < _isoValues[i]) { _isoValues.insert(_isoValues.begin() + i, value); index = i; break; } } if (index == -1) { _isoValues.push_back(value); index = _isoValues.size() - 1; } saveToParams(getRenderParams()); selectControlPoint(index); update(); return index; } void TFIsoValueMap::deleteControlPoint(int i) { if (i == _selectedId) DeselectControlPoint(); _isoValues.erase(_isoValues.begin() + i); update(); saveToParams(getRenderParams()); } void TFIsoValueMap::moveControlPoint(int *index, float value) { if (_equidistantIsoValues) { if (*index == 0) { const float initialValue = _isoValues[0]; const float diff = value - initialValue; for (float &v : _isoValues) v += diff; } else { const float baseValue = _isoValues[0]; float spacing = (value - baseValue) / (float)(*index); spacing = std::max(spacing, 0.f); for (int i = 1; i < _isoValues.size(); i++) _isoValues[i] = baseValue + spacing * i; } } else { deleteControlPoint(*index); *index = addControlPoint(value); } } void TFIsoValueMap::selectControlPoint(int index) { _selectedId = index; float value = _isoValues[index]; emit UpdateInfo(value); } void TFIsoValueMap::DeselectControlPoint() { _selectedId = -1; emit ControlPointDeselected(); update(); } void TFIsoValueMap::UpdateFromInfo(float value) { if (_selectedId >= 0 && _selectedId < _isoValues.size()) { moveControlPoint(&_selectedId, value); update(); saveToParams(getRenderParams()); } } int TFIsoValueMap::findSelectedControlPoint(const glm::vec2 &mouse) const { for (int i = _isoValues.size() - 1; i >= 0; i--) if (controlPointContainsPixel(glm::clamp(_isoValues[i], 0.f, 1.f), mouse)) return i; return -1; } bool TFIsoValueMap::controlPointContainsPixel(float cp, const vec2 &p) const { QRect rect = GetControlPointArea(controlQPositionForValue(cp)); return rect.contains(QPoint(p.x, p.y)); } QPoint TFIsoValueMap::controlQPositionForValue(float value) const { const vec2 v = controlPositionForValue(value); return QPoint(v.x, v.y); } glm::vec2 TFIsoValueMap::controlPositionForValue(float value) const { return vec2(controlXForValue(value), 0); } float TFIsoValueMap::controlXForValue(float value) const { return NDCToPixel(vec2(value, 0.f)).x; } float TFIsoValueMap::valueForControlX(float position) const { return PixelToNDC(vec2(position, 0.f)).x; } float TFIsoValueMap::getMapRangeMin() const { if (!getRenderParams()) return 0; return getRenderParams()->GetMapperFunc(getRenderParams()->GetVariableName())->getMinMapValue(); } float TFIsoValueMap::getMapRangeMax() const { if (!getRenderParams()) return 1; return getRenderParams()->GetMapperFunc(getRenderParams()->GetVariableName())->getMaxMapValue(); } void TFIsoValueMap::menuDeleteControlPoint() { emit Activated(this); QVariant valueVariant = sender()->property(PROPERTY_INDEX); if (valueVariant.isValid()) { int index = valueVariant.toInt(); if (index >= 0 && index < _isoValues.size()) deleteControlPoint(index); } } void TFIsoValueMap::menuAddControlPoint() { emit Activated(this); QVariant value = sender()->property(PROPERTY_VALUE); if (value.isValid()) addControlPoint(value.toFloat()); } ================================================ FILE: apps/vaporgui/TFIsoValueWidget.h ================================================ #pragma once #include "TFMapWidget.h" #include #include #include #include // class TFIsoValueInfoWidget; class TFIsoValueMap : public TFMap { Q_OBJECT public: bool BottomPadding = false; TFIsoValueMap(const std::string &variableNameTag, TFMapWidget *parent = nullptr); void PopulateContextMenu(QMenu *menu, const glm::vec2 &p) override; QSize minimumSizeHint() const override; QSizePolicy GetSizePolicy() const override; void LostFocus() override; TFIsoValueMap *SetEquidistantIsoValues(bool b) { _equidistantIsoValues = b; return this; } protected: void paramsUpdate() override; TFInfoWidget *createInfoWidget() override; void _paintEvent(QPainter &p) override; void drawControl(QPainter &p, const QPointF &pos, bool selected = false, bool invalid = false) const; float GetControlPointTriangleHeight() const; float GetControlPointSquareHeight() const; QRect GetControlPointArea(const QPoint &p) const; void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseDoubleClickEvent(QMouseEvent *event) override; QMargins GetPadding() const override; private: bool _isDraggingControl = false; int _draggingControlID; int _selectedId = -1; glm::vec2 _dragOffset; glm::vec2 m; std::vector _isoValues; std::vector _isoValuesInBounds; bool _equidistantIsoValues = true; bool controlPointContainsPixel(const glm::vec2 &cp, const glm::vec2 &pixel) const; void saveToParams(VAPoR::RenderParams *rp) const; void loadFromParams(VAPoR::RenderParams *rp); void clampIsoValuesToMappingRange(); int addControlPoint(float value); void deleteControlPoint(int i); void moveControlPoint(int *index, float value); void selectControlPoint(int index); int findSelectedControlPoint(const glm::vec2 &mouse) const; bool controlPointContainsPixel(float cp, const glm::vec2 &pixel) const; QPoint controlQPositionForValue(float value) const; glm::vec2 controlPositionForValue(float value) const; float controlXForValue(float value) const; float valueForControlX(float position) const; float getMapRangeMin() const; float getMapRangeMax() const; signals: void ControlPointDeselected(); void UpdateInfo(float value); public slots: void DeselectControlPoint(); void UpdateFromInfo(float value); private slots: void menuDeleteControlPoint(); void menuAddControlPoint(); }; class TFIsoValueWidget : public TFMapWidget { public: TFIsoValueWidget(const std::string &variableNameTag) : TFMapWidget(new TFIsoValueMap(variableNameTag, this)) {} }; ================================================ FILE: apps/vaporgui/TFMapGroupWidget.cpp ================================================ #include "TFMapGroupWidget.h" #include "TFMapWidget.h" #include "TFInfoWidget.h" #include TFMapGroupWidget::TFMapGroupWidget() { QVBoxLayout *layout = new QVBoxLayout; layout->setSpacing(0); layout->setMargin(0); setLayout(layout); } void TFMapGroupWidget::Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams) { for (auto map : _maps) map->Update(dataMgr, paramsMgr, rParams); } TFMapInfoGroupWidget *TFMapGroupWidget::CreateInfoGroup() { TFMapInfoGroupWidget *infos = new TFMapInfoGroupWidget; for (auto map : _maps) { infos->add(map); } return infos; } void TFMapGroupWidget::Add(TFMapWidget *mapWidget) { _maps.push_back(mapWidget); layout()->addWidget(mapWidget); connect(mapWidget, SIGNAL(Activated(TFMapWidget *)), this, SLOT(mapActivated(TFMapWidget *))); } void TFMapGroupWidget::Add(TFMap *map) { Add(new TFMapWidget(map)); } void TFMapGroupWidget::Add(const std::initializer_list &layeredMaps) { assert(layeredMaps.size() > 0); if (layeredMaps.size() == 0) return; TFMapWidget *mapWidget = new TFMapWidget(*layeredMaps.begin()); for (auto it = layeredMaps.begin() + 1; it != layeredMaps.end(); ++it) mapWidget->AddMap(*it); Add(mapWidget); } void TFMapGroupWidget::mapActivated(TFMapWidget *activatedMap) { for (auto map : _maps) if (map != activatedMap) map->Deactivate(); } void TFMapInfoGroupWidget::Update(VAPoR::RenderParams *rParams) { for (auto info : _infos) info->Update(rParams); } void TFMapInfoGroupWidget::add(TFMapWidget *mapWidget) { for (TFMap *map : mapWidget->GetMaps()) { TFInfoWidget *info = map->GetInfoWidget(); if (!info) continue; _infos.push_back(info); // Qt::StackedLayout does not support alignment so we need to wrap // the info widget in another widget with a box layout. QWidget * box = new QWidget; QVBoxLayout *layout = new QVBoxLayout; layout->setMargin(0); layout->setAlignment(Qt::AlignTop); layout->addWidget(info); box->setLayout(layout); addWidget(box); connect(map, SIGNAL(Activated(TFMap *)), this, SLOT(mapActivated(TFMap *))); } } void TFMapInfoGroupWidget::mapActivated(TFMap *activatedMap) { setCurrentWidget((QWidget *)(activatedMap->GetInfoWidget()->parent())); } ================================================ FILE: apps/vaporgui/TFMapGroupWidget.h ================================================ #pragma once #include #include #include class TFInfoWidget; class TFMapWidget; class TFMap; class TFMapInfoGroupWidget; namespace VAPoR { class DataMgr; class ParamsMgr; class RenderParams; } // namespace VAPoR //! \class TFMapGroupWidget //! Manages a vertical stack of TFMap without any spacing between them //! to create the illusion of a continuous widget class TFMapGroupWidget : public QWidget { Q_OBJECT std::vector _maps; public: TFMapGroupWidget(); void Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams); TFMapInfoGroupWidget *CreateInfoGroup(); void Add(TFMapWidget *mapWidget); void Add(TFMap *map); void Add(const std::initializer_list &layeredMaps); private slots: void mapActivated(TFMapWidget *map); }; //! \class TFMapInfoGroupWidget //! Holds a group of TFMapInfo and only displays the relevant one. class TFMapInfoGroupWidget : public QStackedWidget { Q_OBJECT std::vector _infos; public: void Update(VAPoR::RenderParams *rParams); friend class TFMapGroupWidget; private: void add(TFMapWidget *map); private slots: void mapActivated(TFMap *map); }; ================================================ FILE: apps/vaporgui/TFMapWidget.cpp ================================================ #include "TFMapWidget.h" #include "TFColorWidget.h" #include "TFIsoValueWidget.h" #include #include #include #include #include using glm::vec2; #define CONTROL_POINT_RADIUS (4.0f) #define PADDING (CONTROL_POINT_RADIUS + 1.0f) TFMap::TFMap(const std::string &variableNameTag, TFMapWidget *parent) : _variableNameTag(variableNameTag), _parent(parent) {} TFInfoWidget *TFMap::GetInfoWidget() { if (!_infoWidget) _infoWidget = createInfoWidget(); return _infoWidget; } void TFMap::Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams) { assert(_parent); if (_renderParams != rParams) LostFocus(); _dataMgr = dataMgr; _paramsMgr = paramsMgr; _renderParams = rParams; _variableName = _renderParams->GetValueString(_variableNameTag, ""); if (!_dataMgr->VariableExists(_renderParams->GetCurrentTimestep(), getVariableName())) _renderParams = nullptr; if (HasValidParams()) paramsUpdate(); } bool TFMap::HasValidParams() const { return _dataMgr && _paramsMgr && _renderParams; } bool TFMap::IsShown() const { return !_hidden; } void TFMap::resize(int width, int height) { _width = width; _height = height; } bool TFMap::isLargeEnoughToPaint() const { QMargins p = GetPadding(); if (_width - (p.left() + p.right()) <= 0) return false; if (_height - (p.top() + p.bottom()) <= 0) return false; return true; } void TFMap::paintEvent(QPainter &p) { // _renderParams can be invalid during a paintEvent if params are changed and then Qt refreshes the GUI // prior to the change event being handled. const auto savedParams = _renderParams; _renderParams = nullptr; _paintEvent(p); _renderParams = savedParams; } void TFMap::mousePressEvent(QMouseEvent *event) { event->ignore(); } void TFMap::mouseReleaseEvent(QMouseEvent *event) { event->ignore(); } void TFMap::mouseMoveEvent(QMouseEvent *event) { event->ignore(); } void TFMap::mouseDoubleClickEvent(QMouseEvent *event) { event->ignore(); } void TFMap::update() { if (_parent) _parent->update(); } void TFMap::show() { _hidden = false; if (_parent) _parent->showMap(this); } void TFMap::hide() { _hidden = true; if (_parent) _parent->hideMap(this); } VAPoR::MapperFunction *TFMap::getMapperFunction() const { return _renderParams->GetMapperFunc(getVariableName()); } QSizePolicy TFMap::GetSizePolicy() const { return QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); } std::string TFMap::getVariableName() const { return _variableName; } const std::string &TFMap::getVariableNameTag() const { return _variableNameTag; } void TFMap::drawControl(QPainter &p, const QPointF &pos, bool selected) const { float radius = CONTROL_POINT_RADIUS; if (selected) { QRadialGradient gradient(0.5, 0.5, 0.4); gradient.setCoordinateMode(QGradient::ObjectBoundingMode); gradient.setColorAt(0, QColor(0, 0, 0, 100)); gradient.setColorAt(1, Qt::transparent); QBrush shadowBrush(gradient); p.setPen(Qt::NoPen); p.setBrush(shadowBrush); p.drawEllipse(pos, radius * 2, radius * 2); } QPen pen(Qt::darkGray, 0.5); QBrush brush(QColor(0xfa, 0xfa, 0xfa)); // if (selected) { // pen.setColor(Qt::black); // pen.setWidth(1.5); // // brush.setColor(Qt::white); // } p.setBrush(brush); p.setPen(pen); p.drawEllipse(pos, radius, radius); if (selected) { p.setPen(Qt::NoPen); p.setBrush(QBrush(Qt::black)); radius *= 0.38; p.drawEllipse(pos, radius, radius); } } QRect TFMap::paddedRect() const { const QMargins p = GetPadding(); return QRect(p.left(), p.top(), width() - (p.left() + p.right()), height() - (p.top() + p.bottom())); } QRect TFMap::rect() const { return QRect(0, 0, width(), height()); } const QFont TFMap::getFont() const { if (_parent) return _parent->font(); return QFont(); } glm::vec2 TFMap::NDCToPixel(const glm::vec2 &v) const { const QRect p = paddedRect(); return vec2(p.x() + v.x * p.width(), p.y() + (1.0f - v.y) * p.height()); } QPointF TFMap::NDCToQPixel(const glm::vec2 &v) const { const vec2 p = NDCToPixel(v); return QPointF(p.x, p.y); } QPointF TFMap::NDCToQPixel(float x, float y) const { return NDCToQPixel(vec2(x, y)); } glm::vec2 TFMap::PixelToNDC(const glm::vec2 &p) const { float width = TFMap::width(); float height = TFMap::height(); if (width == 0 || height == 0) return vec2(0); return vec2((p.x - PADDING) / (width - 2 * PADDING), 1.0f - (p.y - PADDING) / (height - 2 * PADDING)); } glm::vec2 TFMap::PixelToNDC(const QPointF &p) const { return PixelToNDC(vec2(p.x(), p.y())); } QMargins TFMap::GetPadding() const { return QMargins(PADDING, PADDING, PADDING, PADDING); } int TFMap::GetControlPointRadius() const { return CONTROL_POINT_RADIUS; } void TFMap::BeginSaveStateGroup(VAPoR::ParamsMgr *paramsMgr, const std::string &description) { assert(!_insideSaveStateGroup); paramsMgr->BeginSaveStateGroup(description); _insideSaveStateGroup = true; } void TFMap::EndSaveStateGroup(VAPoR::ParamsMgr *paramsMgr) { assert(_insideSaveStateGroup); paramsMgr->EndSaveStateGroup(); _insideSaveStateGroup = false; } void TFMap::CancelSaveStateGroup(VAPoR::ParamsMgr *paramsMgr) { if (_insideSaveStateGroup) paramsMgr->EndSaveStateGroup(); _insideSaveStateGroup = false; } TFMapWidget::TFMapWidget(TFMap *map) { AddMap(map); setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(_showContextMenu(const QPoint &))); setSizePolicy(map->GetSizePolicy()); } TFMapWidget::~TFMapWidget() { for (TFMap *map : _maps) { delete map; } } void TFMapWidget::AddMap(TFMap *map) { if (std::find(_maps.begin(), _maps.end(), map) == _maps.end()) { map->_parent = this; _maps.push_back(map); connect(map, SIGNAL(Activated(TFMap *)), this, SLOT(_mapActivated(TFMap *))); } } std::vector TFMapWidget::GetMaps() const { return _maps; } TFInfoWidget *TFMapWidget::GetInfoWidget() { assert(_maps.size() == 1); if (_maps.size()) return _maps[0]->GetInfoWidget(); return nullptr; } void TFMapWidget::Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams) { for (auto map : _maps) map->Update(dataMgr, paramsMgr, rParams); } void TFMapWidget::Deactivate() { for (auto map : _maps) map->LostFocus(); } QSize TFMapWidget::minimumSizeHint() const { QSize max(0, 0); for (auto map : _maps) { QSize s = map->minimumSizeHint(); max.setWidth(std::max(max.width(), s.width())); max.setHeight(std::max(max.height(), s.height())); } return max; } void TFMapWidget::showMap(TFMap *map) { map->_hidden = false; show(); } void TFMapWidget::hideMap(TFMap *map) { map->_hidden = true; int nHidden = 0; for (TFMap *m : _maps) if (m->_hidden) nHidden++; if (nHidden == _maps.size()) hide(); } void TFMapWidget::_mapActivated(TFMap *who) { for (auto map : _maps) if (map != who) map->LostFocus(); emit Activated(this); } void TFMapWidget::_showContextMenu(const QPoint &qp) { vec2 p(qp.x(), qp.y()); QMenu menu("Context Menu", this); for (auto map : _maps) { if (map->HasValidParams() && map->rect().contains(qp)) { map->PopulateContextMenu(&menu, p); menu.addSeparator(); map->PopulateSettingsMenu(&menu); menu.addSeparator(); } } menu.exec(mapToGlobal(qp)); } //#include void TFMapWidget::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); QPainter p(this); p.setRenderHint(QPainter::Antialiasing); // void *s = VAPoR::GLManager::BeginTimer(); for (int i = _maps.size() - 1; i >= 0; i--) { if (!_maps[i]->HasValidParams() || !_maps[i]->isLargeEnoughToPaint() || _maps[i]->_hidden) continue; p.save(); _maps[i]->paintEvent(p); p.restore(); } // printf("Paint took %fs\n", VAPoR::GLManager::EndTimer(s)); } void TFMapWidget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::RightButton) return; // Reserved for context menu for (auto map : _maps) { if (!map->HasValidParams() || map->_hidden) continue; event->accept(); map->mousePressEvent(event); if (event->isAccepted()) break; } } void TFMapWidget::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::RightButton) return; // Reserved for context menu for (auto map : _maps) { if (!map->HasValidParams() || map->_hidden) continue; event->accept(); map->mouseReleaseEvent(event); if (event->isAccepted()) break; } } void TFMapWidget::mouseMoveEvent(QMouseEvent *event) { if (event->button() == Qt::RightButton) return; // Reserved for context menu for (auto map : _maps) { if (!map->HasValidParams() || map->_hidden) continue; event->accept(); map->mouseMoveEvent(event); if (event->isAccepted()) break; } } void TFMapWidget::mouseDoubleClickEvent(QMouseEvent *event) { if (event->button() == Qt::RightButton) return; // Reserved for context menu for (auto map : _maps) { if (!map->HasValidParams() || map->_hidden) continue; event->accept(); map->mouseDoubleClickEvent(event); if (event->isAccepted()) break; } } void TFMapWidget::resizeEvent(QResizeEvent *event) { for (auto map : _maps) { map->resize(event->size().width(), event->size().height()); } } ================================================ FILE: apps/vaporgui/TFMapWidget.h ================================================ #pragma once #include #include #include #include #include #include namespace VAPoR { class DataMgr; class ParamsMgr; class RenderParams; class MapperFunction; } // namespace VAPoR class TFInfoWidget; class TFMapWidget; //! \class TFMap //! A widget for editing a transfer function mapped value, for example opacity or color. //! They are not QWidgets because of limitations in Qt which do not allow widgets to be //! stacked on top of another with passthrough mouse events. Because of this, TFMapWidget //! manually holds TFMaps and manages such events. class TFMap : public QObject { Q_OBJECT const std::string _variableNameTag; TFMapWidget * _parent = nullptr; TFInfoWidget * _infoWidget = nullptr; int _width = 0; int _height = 0; bool _insideSaveStateGroup = false; bool _hidden = false; std::string _variableName; VAPoR::DataMgr * _dataMgr = nullptr; VAPoR::ParamsMgr * _paramsMgr = nullptr; VAPoR::RenderParams *_renderParams = nullptr; public: TFMap(const std::string &variableNameTag, TFMapWidget *parent = nullptr); TFInfoWidget *GetInfoWidget(); void Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams); bool HasValidParams() const; bool IsShown() const; virtual void LostFocus() = 0; virtual QSize minimumSizeHint() const = 0; virtual QSizePolicy GetSizePolicy() const; //! (Right-click menu) virtual void PopulateContextMenu(QMenu *menu, const glm::vec2 &p) {} virtual void PopulateSettingsMenu(QMenu *menu) const {} int width() const { return _width; } int height() const { return _height; } void resize(int width, int height); //! Sometimes Qt tries painting a 0 sized widget bool isLargeEnoughToPaint() const; //! Returns the rect of the internal padded area QRect paddedRect() const; QRect rect() const; const QFont getFont() const; //! These map to the QWidget counterparts void paintEvent(QPainter &p); virtual void mousePressEvent(QMouseEvent *event); virtual void mouseReleaseEvent(QMouseEvent *event); virtual void mouseMoveEvent(QMouseEvent *event); virtual void mouseDoubleClickEvent(QMouseEvent *event); friend class TFMapWidget; public slots: //! These map to the QWidget counterparts void update(); void show(); void hide(); protected: virtual void _paintEvent(QPainter &p) = 0; virtual void paramsUpdate() = 0; VAPoR::DataMgr * getDataMgr() const { return _dataMgr; } VAPoR::ParamsMgr * getParamsMgr() const { return _paramsMgr; } VAPoR::RenderParams * getRenderParams() const { return _renderParams; } VAPoR::MapperFunction *getMapperFunction() const; std::string getVariableName() const; const std::string & getVariableNameTag() const; void drawControl(QPainter &p, const QPointF &pos, bool selected = false) const; virtual TFInfoWidget *createInfoWidget() = 0; glm::vec2 NDCToPixel(const glm::vec2 &v) const; QPointF NDCToQPixel(const glm::vec2 &v) const; QPointF NDCToQPixel(float x, float y) const; glm::vec2 PixelToNDC(const QPointF &p) const; glm::vec2 PixelToNDC(const glm::vec2 &p) const; virtual QMargins GetPadding() const; int GetControlPointRadius() const; void BeginSaveStateGroup(VAPoR::ParamsMgr *paramsMgr, const std::string &description = ""); void EndSaveStateGroup(VAPoR::ParamsMgr *paramsMgr); void CancelSaveStateGroup(VAPoR::ParamsMgr *paramsMgr); signals: //! Emittend when focus was gained void Activated(TFMap *who); }; //! \class TFMapWidget //! Wrap a TFMap(s) in a QWidget class TFMapWidget : public QWidget { Q_OBJECT std::vector _maps; public: TFMapWidget(TFMap *map); ~TFMapWidget(); void AddMap(TFMap *map); std::vector GetMaps() const; TFInfoWidget * GetInfoWidget(); void Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams); void Deactivate(); QSize minimumSizeHint() const override; void showMap(TFMap *map); void hideMap(TFMap *map); signals: void Activated(TFMapWidget *who); private slots: void _mapActivated(TFMap *who); void _showContextMenu(const QPoint &); protected: void paintEvent(QPaintEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseDoubleClickEvent(QMouseEvent *event) override; void resizeEvent(QResizeEvent *event) override; }; ================================================ FILE: apps/vaporgui/TFMappingRangeSelector.cpp ================================================ #include "TFMappingRangeSelector.h" #include #include #include using VAPoR::RenderParams; TFMappingRangeSelector::TFMappingRangeSelector(const std::string &variableNameTag) : _variableNameTag(variableNameTag) { AllowCustomRange(); connect(this, SIGNAL(ValueChanged(float, float)), this, SLOT(_rangeChanged(float, float))); connect(this, SIGNAL(ValueChangedBegin()), this, SLOT(_rangeChangedBegin())); connect(this, SIGNAL(ValueChangedIntermediate(float, float)), this, SLOT(_rangeChangedIntermediate(float, float))); connect(this, SIGNAL(RangeChanged(float, float)), this, SLOT(_sliderRangeChanged(float, float))); connect(this, SIGNAL(RangeDefaultRequested()), this, SLOT(_sliderRangeResetToDefaultRequested())); } void TFMappingRangeSelector::Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams) { _rParams = rParams; _paramsMgr = paramsMgr; if (!rParams || !paramsMgr || !dataMgr) return; if (!dataMgr->VariableExists(rParams->GetCurrentTimestep(), _getVariableName())) return; float min, max; if (_getTF()->IsUsingCustomMappingSliderRange()) { auto range = _getTF()->GetCustomMappingSliderRange(); min = range[0]; max = range[1]; } else { _getDefaultRange(dataMgr, rParams, &min, &max); } SetRange(min, max); vector mapperRange = rParams->GetMapperFunc(_getVariableName())->getMinMaxMapValue(); SetValue(mapperRange[0], mapperRange[1]); } void TFMappingRangeSelector::_getDefaultRange(VAPoR::DataMgr *d, VAPoR::RenderParams *r, float *min, float *max) const { if (r->GetValueDoubleVec(RenderParams::CustomHistogramRangeTag).size() == 2) { auto range = r->GetValueDoubleVec(RenderParams::CustomHistogramRangeTag); *min = range[0]; *max = range[1]; } else { _getDataRange(d, r, min, max); } } void TFMappingRangeSelector::_getDataRange(VAPoR::DataMgr *d, VAPoR::RenderParams *r, float *min, float *max) const { VAPoR::CoordType minExt, maxExt; r->GetBox()->GetExtents(minExt, maxExt); std::vector range; d->GetDataRange(r->GetCurrentTimestep(), _getVariableName(), r->GetRefinementLevel(), r->GetCompressionLevel(), minExt, maxExt, range); *min = range[0]; *max = range[1]; } std::string TFMappingRangeSelector::_getVariableName() const { return _rParams->GetValueString(_variableNameTag, ""); } VAPoR::MapperFunction *TFMappingRangeSelector::_getTF() const { return _rParams->GetMapperFunc(_getVariableName()); } void TFMappingRangeSelector::_rangeChangedBegin() { if (!_rParams || !_paramsMgr) return; _paramsMgr->BeginSaveStateGroup("Change tf mapping range"); _insideIntermediateChangeGroup = true; } void TFMappingRangeSelector::_rangeChangedIntermediate(float left, float right) { if (!_rParams || !_paramsMgr) return; _rParams->GetMapperFunc(_getVariableName())->setMinMaxMapValue(left, right); // _maps->histo->update(); _paramsMgr->IntermediateChange(); } void TFMappingRangeSelector::_rangeChanged(float left, float right) { if (!_rParams || !_paramsMgr) return; _rParams->GetMapperFunc(_getVariableName())->setMinMaxMapValue(left, right); if (_insideIntermediateChangeGroup) _paramsMgr->EndSaveStateGroup(); _insideIntermediateChangeGroup = false; } void TFMappingRangeSelector::_sliderRangeChanged(float left, float right) { _paramsMgr->BeginSaveStateGroup("Enable custom tf slider range"); _getTF()->SetUsingCustomMappingSliderRange(true); _getTF()->SetCustomMappingSliderRange({left, right}); _paramsMgr->EndSaveStateGroup(); } void TFMappingRangeSelector::_sliderRangeResetToDefaultRequested() { _getTF()->SetUsingCustomMappingSliderRange(false); } ================================================ FILE: apps/vaporgui/TFMappingRangeSelector.h ================================================ #pragma once #include "QRangeSliderTextCombo.h" #include namespace VAPoR { class DataMgr; class ParamsMgr; class RenderParams; class MapperFunction; } // namespace VAPoR class TFMappingRangeSelector : public QRangeSliderTextCombo { Q_OBJECT public: TFMappingRangeSelector(const std::string &variableNameTag); void Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams); private: VAPoR::RenderParams *_rParams = nullptr; VAPoR::ParamsMgr * _paramsMgr = nullptr; const std::string & _variableNameTag; bool _insideIntermediateChangeGroup = false; void _getDefaultRange(VAPoR::DataMgr *dataMgr, VAPoR::RenderParams *rParams, float *min, float *max) const; void _getDataRange(VAPoR::DataMgr *dataMgr, VAPoR::RenderParams *rParams, float *min, float *max) const; std::string _getVariableName() const; VAPoR::MapperFunction *_getTF() const; private slots: void _rangeChangedBegin(); void _rangeChangedIntermediate(float left, float right); void _rangeChanged(float left, float right); void _sliderRangeChanged(float left, float right); void _sliderRangeResetToDefaultRequested(); }; ================================================ FILE: apps/vaporgui/TFOpacityInfoWidget.cpp ================================================ #include "TFOpacityInfoWidget.h" #include #include #include #include #include #include "VLineItem.h" TFOpacityInfoWidget::TFOpacityInfoWidget(const std::string &variableNameTag) : TFInfoWidget(variableNameTag) { ((QBoxLayout *)layout())->addWidget(new VLineItem("Opacity", _opacityEdit = new VDoubleLineEdit)); _opacityEdit->SetRange(0, 1); connect(_opacityEdit, &VDoubleLineEdit::ValueChanged, this, &TFOpacityInfoWidget::opacityEditChanged); } void TFOpacityInfoWidget::DeselectControlPoint() { TFInfoWidget::DeselectControlPoint(); _opacityEdit->Clear(); } void TFOpacityInfoWidget::SetOpacity(float opacity) { _opacity = opacity; updateOpacity(); } void TFOpacityInfoWidget::SetControlPoint(float value, float opacity) { this->setEnabled(true); SetNormalizedValue(value); SetOpacity(opacity); } void TFOpacityInfoWidget::updateOpacity() { if (!isEnabled()) return; _opacityEdit->SetValueDouble(_opacity); } float TFOpacityInfoWidget::getOpacityFromEdit() const { return _opacityEdit->GetValueDouble(); } void TFOpacityInfoWidget::controlPointChanged() { emit ControlPointChanged(_value, _opacity); } void TFOpacityInfoWidget::opacityEditChanged() { _opacity = getOpacityFromEdit(); controlPointChanged(); } ================================================ FILE: apps/vaporgui/TFOpacityInfoWidget.h ================================================ #pragma once #include "TFInfoWidget.h" #include namespace VAPoR { class RenderParams; } class TFOpacityInfoWidget : public TFInfoWidget { Q_OBJECT public: TFOpacityInfoWidget(const std::string &variableNameTag); public: void SetOpacity(float opacity); protected: void updateOpacity(); float getOpacityFromEdit() const; void controlPointChanged(); private: VDoubleLineEdit *_opacityEdit; float _opacity; signals: void ControlPointChanged(float value, float opacity); public slots: void SetControlPoint(float value, float opacity); void DeselectControlPoint(); private slots: void opacityEditChanged(); }; ================================================ FILE: apps/vaporgui/TFOpacityWidget.cpp ================================================ #include "TFOpacityWidget.h" #include #include #include #include #include #include #include "TFOpacityInfoWidget.h" #include "TFUtils.h" using namespace VAPoR; using glm::clamp; using glm::vec2; using std::vector; static vec2 qvec2(const QPoint &qp) { return vec2(qp.x(), qp.y()); } static vec2 qvec2(const QPointF &qp) { return vec2(qp.x(), qp.y()); } static QPointF qvec2(const vec2 &v) { return QPointF(v.x, v.y); } static vec2 Project(vec2 a, vec2 b, vec2 p) { vec2 n = glm::normalize(b - a); float t = glm::dot(n, p - a); return n * t + a; } static float DistanceToLine(vec2 a, vec2 b, vec2 p) { vec2 n = glm::normalize(b - a); float t = glm::dot(n, p - a); if (t < 0) return glm::distance(a, p); if (t > glm::distance(a, b)) return glm::distance(b, p); vec2 projection = n * t + a; return glm::distance(projection, p); } #define CONTROL_POINT_RADIUS (4.0f) #define PADDING (CONTROL_POINT_RADIUS + 1.0f) TFOpacityMap::TFOpacityMap(const std::string &variableNameTag, TFMapWidget *parent) : TFMap(variableNameTag, parent) {} QSize TFOpacityMap::minimumSizeHint() const { return QSize(100, 75); } void TFOpacityMap::LostFocus() { DeselectControlPoint(); } #define PROPERTY_INDEX ("index") #define PROPERTY_LOCATION ("location") void TFOpacityMap::PopulateContextMenu(QMenu *menu, const glm::vec2 &p) { auto selected = findSelectedControlPoint(p); if (selected != _controlPoints.EndPoints()) menu->addAction("Delete control point", this, SLOT(menuDeleteSelectedControlPoint()))->setProperty(PROPERTY_INDEX, QVariant(selected.Index())); else menu->addAction("Add control point", this, SLOT(menuAddControlPoint()))->setProperty(PROPERTY_LOCATION, QVariant(qvec2(PixelToNDC(p)))); } void TFOpacityMap::PopulateSettingsMenu(QMenu *menu) const { menu->addAction("Save Transfer Function", this, SLOT(menuSave())); menu->addAction("Load Transfer Function", this, SLOT(menuLoad())); } void TFOpacityMap::paramsUpdate() { MapperFunction *mf = getRenderParams()->GetMapperFunc(getVariableName()); // TODO Multiple opacity maps? // int n = mf->getNumOpacityMaps(); // printf("# opacity maps = %i\n", n); OpacityMap *om = mf->GetOpacityMap(0); vector cp = om->GetControlPoints(); _controlPoints.Resize(cp.size() / 2); for (int i = 0; i < cp.size(); i += 2) { _controlPoints[i / 2].y = cp[i]; _controlPoints[i / 2].x = cp[i + 1]; } update(); if (_selectedControl > -1) UpdateInfo(_controlPoints[_selectedControl].x, _controlPoints[_selectedControl].y); } TFInfoWidget *TFOpacityMap::createInfoWidget() { TFOpacityInfoWidget *info = new TFOpacityInfoWidget(getVariableNameTag()); connect(info, SIGNAL(ControlPointChanged(float, float)), this, SLOT(UpdateFromInfo(float, float))); connect(this, SIGNAL(UpdateInfo(float, float)), info, SLOT(SetControlPoint(float, float))); connect(this, SIGNAL(ControlPointDeselected()), info, SLOT(DeselectControlPoint())); return info; } void TFOpacityMap::_paintEvent(QPainter &p) { // p.setViewport(10, 10, 30, 30); // p.setWindow(10, 10, 30, 30); // p.fillRect(event->rect(), QBrush(QColor(64, 32, 64))); if (_controlPoints.Size()) { ControlPointList &cp = _controlPoints; for (auto it = cp.BeginLines(); it != cp.EndLines(); ++it) { p.drawLine(NDCToQPixel(it.a()), NDCToQPixel(it.b())); // p.drawEllipse(qvec2(Project(NDCToPixel(it.a()), NDCToPixel(it.b()), m)), 2, 2); } for (auto it = --cp.EndPoints(); it != --cp.BeginPoints(); --it) drawControl(p, NDCToQPixel(*it), it.Index() == _selectedControl); } } void TFOpacityMap::mousePressEvent(QMouseEvent *event) { emit Activated(this); vec2 mouse = qvec2(event->localPos()); auto it = findSelectedControlPoint(mouse); auto lineIt = findSelectedControlLine(mouse); if (it != _controlPoints.EndPoints()) { _draggedControl = it; _dragOffset = NDCToPixel(*it) - mouse; _isDraggingControl = true; selectControlPoint(it); getParamsMgr()->BeginSaveStateGroup("Move opacity control point"); } else if (lineIt != _controlPoints.EndLines()) { _draggedLine = lineIt; _dragOffset = NDCToPixel(lineIt.a()) - mouse; _dragOffsetB = NDCToPixel(lineIt.b()) - mouse; _isDraggingLine = true; getParamsMgr()->BeginSaveStateGroup("Move opacity control line"); } else { DeselectControlPoint(); event->ignore(); } } void TFOpacityMap::mouseReleaseEvent(QMouseEvent *event) { if (_isDraggingControl || _isDraggingLine) { opacityChanged(); getParamsMgr()->EndSaveStateGroup(); } else event->ignore(); _isDraggingControl = false; _isDraggingLine = false; } void TFOpacityMap::mouseMoveEvent(QMouseEvent *event) { vec2 mouse = qvec2(event->pos()); m = mouse; // const int i = _draggedID; // ControlPointList &cp = _controlPoints; // const int N = cp.Size(); if (_isDraggingControl) { const auto &it = _draggedControl; vec2 newVal = glm::clamp(PixelToNDC(mouse + _dragOffset), vec2(it.IsFirst() ? 0 : (*(it - 1)).x, 0), vec2(it.IsLast() ? 1 : (*(it + 1)).x, 1)); *_draggedControl = newVal; emit UpdateInfo(newVal.x, newVal.y); update(); opacityChanged(); getParamsMgr()->IntermediateChange(); } else if (_isDraggingLine) { auto &it = _draggedLine; it.setA(glm::clamp(PixelToNDC(mouse + _dragOffset), vec2(it.IsFirst() ? 0 : (it - 1).a().x, 0), vec2(it.IsLast() ? 1 : (it + 1).b().x, 1))); it.setB(glm::clamp(PixelToNDC(mouse + _dragOffsetB), vec2(it.IsFirst() ? 0 : (it - 1).a().x, 0), vec2(it.IsLast() ? 1 : (it + 1).b().x, 1))); update(); opacityChanged(); getParamsMgr()->IntermediateChange(); } else { event->ignore(); } } void TFOpacityMap::mouseDoubleClickEvent(QMouseEvent *event) { vec2 mouse = qvec2(event->pos()); ControlPointList &cp = _controlPoints; auto controlPointIt = findSelectedControlPoint(mouse); if (controlPointIt != cp.EndPoints()) { deleteControlPoint(controlPointIt); return; } auto controlLineIt = findSelectedControlLine(mouse); if (controlLineIt != cp.EndLines()) { const vec2 a = NDCToPixel(controlLineIt.a()); const vec2 b = NDCToPixel(controlLineIt.b()); addControlPoint(PixelToNDC(Project(a, b, mouse))); return; } event->ignore(); } void TFOpacityMap::opacityChanged() { if (!getRenderParams()) return; MapperFunction *mf = getRenderParams()->GetMapperFunc(getVariableName()); OpacityMap *om = mf->GetOpacityMap(0); vector cp(_controlPoints.Size() * 2); for (int i = 0; i < _controlPoints.Size(); i++) { cp[i * 2] = _controlPoints[i].y; cp[i * 2 + 1] = _controlPoints[i].x; } om->SetControlPoints(cp); } bool TFOpacityMap::controlPointContainsPixel(const vec2 &cp, const vec2 &pixel) const { return glm::distance(pixel, NDCToPixel(cp)) <= GetControlPointRadius(); } ControlPointList::PointIterator TFOpacityMap::findSelectedControlPoint(const glm::vec2 &mouse) { const auto end = _controlPoints.EndPoints(); for (auto it = _controlPoints.BeginPoints(); it != end; ++it) if (controlPointContainsPixel(*it, mouse)) return it; return end; } ControlPointList::LineIterator TFOpacityMap::findSelectedControlLine(const glm::vec2 &mouse) { ControlPointList &cp = _controlPoints; const float radius = GetControlPointRadius(); for (auto it = cp.BeginLines(); it != cp.EndLines(); ++it) { const vec2 a = NDCToPixel(it.a()); const vec2 b = NDCToPixel(it.b()); if (DistanceToLine(a, b, mouse) <= radius) return it; } return cp.EndLines(); } void TFOpacityMap::selectControlPoint(ControlPointList::PointIterator it) { _selectedControl = it.Index(); update(); emit UpdateInfo((*it).x, (*it).y); } void TFOpacityMap::deleteControlPoint(ControlPointList::PointIterator it) { if (_isDraggingControl || _isDraggingLine) { getParamsMgr()->EndSaveStateGroup(); _isDraggingControl = false; _isDraggingLine = false; } if (_selectedControl == it.Index()) DeselectControlPoint(); else if (_selectedControl > it.Index()) _selectedControl--; _controlPoints.Remove(it); update(); opacityChanged(); } void TFOpacityMap::addControlPoint(const glm::vec2 &ndc) { ControlPointList &cp = _controlPoints; int index = cp.Add(ndc); selectControlPoint(cp.BeginPoints() + index); update(); opacityChanged(); } void TFOpacityMap::menuDeleteSelectedControlPoint() { emit Activated(this); QVariant indexVariant = sender()->property(PROPERTY_INDEX); if (indexVariant.isValid()) { int index = indexVariant.toInt(); if (index >= 0 && index < _controlPoints.Size()) deleteControlPoint(_controlPoints.BeginPoints() + index); } } void TFOpacityMap::menuAddControlPoint() { emit Activated(this); QVariant location = sender()->property(PROPERTY_LOCATION); if (location.isValid()) addControlPoint(qvec2(location.toPointF())); } void TFOpacityMap::menuLoad() { RenderParams *rp = getRenderParams(); if (!rp) return; TFUtils::LoadTransferFunction(getParamsMgr(), rp->GetMapperFunc(getVariableName())); } void TFOpacityMap::menuSave() { RenderParams *rp = getRenderParams(); if (!rp) return; TFUtils::SaveTransferFunction(getParamsMgr(), rp->GetMapperFunc(getVariableName())); } void TFOpacityMap::DeselectControlPoint() { _selectedControl = -1; update(); emit ControlPointDeselected(); } void TFOpacityMap::UpdateFromInfo(float value, float opacity) { assert(_selectedControl >= 0); assert(value >= 0 && value <= 1); assert(opacity >= 0 && opacity <= 1); _controlPoints.Remove(_controlPoints.BeginPoints() + _selectedControl); _selectedControl = _controlPoints.Add(vec2(value, opacity)); opacityChanged(); } TFOpacityWidget::TFOpacityWidget(const std::string &variableNameTag) : TFMapWidget(new TFOpacityMap(variableNameTag, this)) { this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding); // this->setFrameStyle(QFrame::Box); } ================================================ FILE: apps/vaporgui/TFOpacityWidget.h ================================================ #pragma once #include "TFMapWidget.h" #include #include class ControlPointList { public: class PointIterator { ControlPointList *list; int i; PointIterator(ControlPointList *list, int i) : list(list), i(i) {} public: PointIterator() {} PointIterator &operator++() { ++i; return *this; } PointIterator &operator--() { --i; return *this; } PointIterator operator+(int x) const { return PointIterator(list, i + x); } PointIterator operator-(int x) const { return PointIterator(list, i - x); } glm::vec2 & operator*() { return (*list)[i]; } bool operator!=(const PointIterator &other) { return !(*this == other); } bool operator==(const PointIterator &other) { return other.list == this->list && other.i == this->i; } bool IsFirst() const { return i == 0; } bool IsLast() const { return i == list->Size() - 1; } int Index() const { return i; } friend class ControlPointList; }; class LineIterator : public PointIterator { using PointIterator::PointIterator; public: glm::vec2 &operator*() = delete; // bool IsFirst() const = delete; // bool IsLast() const = delete; bool IsLast() const { return i == list->Size(); } LineIterator operator+(int x) const { return LineIterator(list, i + x); } LineIterator operator-(int x) const { return LineIterator(list, i - x); } const glm::vec2 a() { if (i == 0) return glm::vec2(0, (*list)[0].y); return (*list)[i - 1]; } const glm::vec2 b() { if (i == list->SizeLines() - 1) return glm::vec2(1, (*list)[list->Size() - 1].y); return (*list)[i]; } void setA(const glm::vec2 &v) { if (i != 0) (*list)[i - 1] = v; } void setB(const glm::vec2 &v) { if (i != list->SizeLines() - 1) (*list)[i] = v; } friend class ControlPointList; }; std::vector _points; public: glm::vec2 &operator[](const int i) { VAssert(i >= 0 && i < _points.size()); return _points[i]; } int Add(const glm::vec2 &v) { for (int i = 0; i < _points.size(); i++) if (_points[i].x > v.x) return Add(v, i); return Add(v, Size()); } int Add(const glm::vec2 &v, const int i) { VAssert(i >= 0 && i <= _points.size()); glm::vec2 vClamped = glm::clamp(v, glm::vec2(0, 0), glm::vec2(1, 1)); _points.insert(_points.begin() + i, vClamped); return i; } int Add(const glm::vec2 &v, const LineIterator &line) { VAssert(line.i >= 0 && line.i <= _points.size()); _points.insert(_points.begin() + line.i, v); return line.i; } void Remove(const PointIterator &point) { VAssert(point.i >= 0 && point.i < _points.size()); if (Size() > 1) _points.erase(_points.begin() + point.i); } int Size() const { return _points.size(); } int SizeLines() const { return Size() + 1; } void Resize(int n) { _points.resize(n); } PointIterator BeginPoints() { return PointIterator(this, 0); } PointIterator EndPoints() { return PointIterator(this, Size()); } LineIterator BeginLines() { return LineIterator(this, 0); } LineIterator EndLines() { return LineIterator(this, SizeLines()); } }; class TFOpacityMap : public TFMap { Q_OBJECT public: TFOpacityMap(const std::string &variableNameTag, TFMapWidget *parent = nullptr); QSize minimumSizeHint() const override; void LostFocus() override; void PopulateContextMenu(QMenu *menu, const glm::vec2 &p) override; void PopulateSettingsMenu(QMenu *menu) const override; protected: void paramsUpdate() override; TFInfoWidget *createInfoWidget() override; void _paintEvent(QPainter &p) override; void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseDoubleClickEvent(QMouseEvent *event) override; private: ControlPointList _controlPoints; bool _isDraggingControl = false; bool _isDraggingLine = false; ControlPointList::PointIterator _draggedControl; ControlPointList::LineIterator _draggedLine; glm::vec2 _dragOffset; glm::vec2 _dragOffsetB; glm::vec2 m; int _selectedControl = -1; void opacityChanged(); bool controlPointContainsPixel(const glm::vec2 &cp, const glm::vec2 &pixel) const; ControlPointList::PointIterator findSelectedControlPoint(const glm::vec2 &mouse); ControlPointList::LineIterator findSelectedControlLine(const glm::vec2 &mouse); void selectControlPoint(ControlPointList::PointIterator it); void deleteControlPoint(ControlPointList::PointIterator it); void addControlPoint(const glm::vec2 &ndc); signals: void ControlPointDeselected(); void UpdateInfo(float value, float opacity); public slots: void DeselectControlPoint(); void UpdateFromInfo(float value, float opacity); private slots: void menuDeleteSelectedControlPoint(); void menuAddControlPoint(); void menuLoad(); void menuSave(); }; class TFOpacityWidget : public TFMapWidget { Q_OBJECT public: TFOpacityWidget(const std::string &variableNameTag); }; ================================================ FILE: apps/vaporgui/TFUtils.cpp ================================================ #include "TFUtils.h" #include #include #include #include #include "ErrorReporter.h" #include #include void TFUtils::LoadColormap(VAPoR::MapperFunction *tf, const std::string &path) { int rc = tf->LoadColormapFromFile(path); if (rc < 0) MSG_ERR("Failed to load transfer function"); } void TFUtils::LoadColormap(VAPoR::ParamsMgr *paramsMgr, VAPoR::MapperFunction *tf) { assert(paramsMgr); SettingsParams *sp = (SettingsParams *)paramsMgr->GetParams(SettingsParams::GetClassType()); QString qDefaultDirectory = QString::fromStdString(sp->GetSessionDir()); QString qSelectedPath = QFileDialog::getOpenFileName(nullptr, "Select a .tf3 file", qDefaultDirectory, "Vapor Transfer Function (*.tf3)"); if (qSelectedPath.isNull()) return; string selectedPath = qSelectedPath.toStdString(); sp->SetSessionDir(Wasp::FileUtils::Dirname(selectedPath)); LoadColormap(tf, selectedPath); } void TFUtils::LoadTransferFunction(VAPoR::ParamsMgr *paramsMgr, VAPoR::MapperFunction *tf) { SettingsParams *sp = (SettingsParams *)paramsMgr->GetParams(SettingsParams::GetClassType()); QString qDefaultDirectory = QString::fromStdString(sp->GetSessionDir()); QString qSelectedPath = QFileDialog::getOpenFileName(nullptr, "Select a .tf3 file", qDefaultDirectory, "Vapor Transfer Function (*.tf3)"); if (qSelectedPath.isNull()) return; string selectedPath = qSelectedPath.toStdString(); sp->SetSessionDir(FileUtils::Dirname(selectedPath)); int rc = tf->LoadFromFile(selectedPath); if (rc < 0) MSG_ERR("Failed to load transfer function"); } void TFUtils::SaveTransferFunction(VAPoR::ParamsMgr *paramsMgr, VAPoR::MapperFunction *tf) { SettingsParams *sp = (SettingsParams *)paramsMgr->GetParams(SettingsParams::GetClassType()); QString qDefaultDirectory = QString::fromStdString(sp->GetSessionDir()); QString qSelectedPath = QFileDialog::getSaveFileName(nullptr, "Select a .tf3 file", qDefaultDirectory, "Vapor Transfer Function (*.tf3)", 0); if (qSelectedPath.isNull()) return; string selectedPath = qSelectedPath.toStdString(); if (FileUtils::Extension(selectedPath) != "tf3") selectedPath += ".tf3"; sp->SetSessionDir(FileUtils::Dirname(selectedPath)); int rc = tf->SaveToFile(selectedPath); if (rc < 0) MSG_ERR("Failed to save transfer function"); } ================================================ FILE: apps/vaporgui/TFUtils.h ================================================ #pragma once #include namespace VAPoR { class MapperFunction; class ParamsMgr; } // namespace VAPoR namespace TFUtils { void LoadColormap(VAPoR::MapperFunction *tf, const std::string &path); void LoadColormap(VAPoR::ParamsMgr *paramsMgr, VAPoR::MapperFunction *tf); void LoadTransferFunction(VAPoR::ParamsMgr *paramsMgr, VAPoR::MapperFunction *tf); void SaveTransferFunction(VAPoR::ParamsMgr *paramsMgr, VAPoR::MapperFunction *tf); } // namespace TFUtils ================================================ FILE: apps/vaporgui/TwoDDataEventRouter.cpp ================================================ #include "TwoDDataEventRouter.h" #include "vapor/TwoDDataParams.h" #include "PWidgets.h" #include "PMetadataClasses.h" using namespace VAPoR; static RenderEventRouterRegistrar registrar(TwoDDataEventRouter::GetClassType()); TwoDDataEventRouter::TwoDDataEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, TwoDDataParams::GetClassType()) { // clang-format off AddVariablesSubtab(new PGroup({ new PSection("Variable Selection", { new PScalarVariableSelector, new PHeightVariableSelector }), new PFidelitySection, new POpenVariableMetadataWidget })); AddAppearanceSubtab(new PGroup({ new PTFEditor, new PCheckbox(RenderParams::DrawInFrontTag, "Draw renderer in front") })); AddGeometrySubtab(new PGeometrySubtab); AddColorbarSubtab(new PAnnotationColorbarWidget); // clang-format on } string TwoDDataEventRouter::_getDescription() const { return ("Displays " "the user's 2D data variables along the plane described by the source data " "file.\n\nThese 2D variables may be offset by a height variable.\n\n"); } ================================================ FILE: apps/vaporgui/TwoDDataEventRouter.h ================================================ #pragma once #include "RenderEventRouterGUI.h" #include "vapor/TwoDDataRenderer.h" //! \class TwoDDataEventRouter //! \ingroup Public_GUI //! \brief TwoDData Renderer GUI //! \author Stas Jaroszynski class TwoDDataEventRouter : public RenderEventRouterGUI { public: TwoDDataEventRouter(QWidget *parent, VAPoR::ControlExec *ce); static string GetClassType() { return VAPoR::TwoDDataRenderer::GetClassType(); } string GetType() const { return GetClassType(); } bool Supports2DVariables() const { return true; } bool Supports3DVariables() const { return false; } protected: string _getDescription() const; string _getSmallIconImagePath() const { return "TwoDData_small.png"; } string _getIconImagePath() const { return "TwoDData.png"; } }; ================================================ FILE: apps/vaporgui/UCloseVDCMenu.cpp ================================================ #include "UCloseVDCMenu.h" #include #include UCloseVDCMenu::UCloseVDCMenu(QMenu *parent, ControlExec *ce) : QMenu("Close Dataset", parent), _ce(ce) { parent->addMenu(this); } void UCloseVDCMenu::Update() { this->clear(); vector dataSetNames = _ce->GetParams()->GetOpenDataSetNames(); if (dataSetNames.empty()) { this->setEnabled(false); // This doesn't really work on macOS (qt bug) } else { this->setEnabled(true); for (const auto &name : dataSetNames) this->addAction(QString::fromStdString(name), [this, name](){ _ce->CloseData(name); }); } } ================================================ FILE: apps/vaporgui/UCloseVDCMenu.h ================================================ #pragma once #include #include "Updatable.h" #include class UCloseVDCMenu : public QMenu, public Updatable{ Q_OBJECT ControlExec * const _ce; public: UCloseVDCMenu(QMenu *parent, ControlExec *ce); void Update() override; }; ================================================ FILE: apps/vaporgui/UWidget.cpp ================================================ #include "UWidget.h" ================================================ FILE: apps/vaporgui/UWidget.h ================================================ #pragma once #include "VContainer.h" #include "ParamsUpdatable.h" //! \class UWidget //! \brief A widget that standardizes support for params updates. //! \author Stas Jaroszynski class UWidget : public VContainer, public ParamsUpdatable { public: using VContainer::VContainer; }; ================================================ FILE: apps/vaporgui/Updatable.h ================================================ #pragma once #include class Updatable { public: virtual void Update() = 0; }; ================================================ FILE: apps/vaporgui/V3DInput.cpp ================================================ #include "V3DInput.h" #include #include #include "VDoubleLineEdit.h" #include V3DInput::V3DInput() { QHBoxLayout *layout = new QHBoxLayout; layout->setMargin(0); setLayout(layout); layout->addWidget(new QLabel("X")); layout->addWidget(_x = new VDoubleLineEdit); layout->addWidget(new QLabel("Y")); layout->addWidget(_y = new VDoubleLineEdit); layout->addWidget(new QLabel("Z")); layout->addWidget(_z = new VDoubleLineEdit); for (auto input : {_x, _y, _z}) QObject::connect(input, &VDoubleLineEdit::ValueChanged, this, &V3DInput::axisValueChanged); } void V3DInput::SetValue(double x, double y, double z) { _x->SetValueDouble(x); _y->SetValueDouble(y); _z->SetValueDouble(z); } void V3DInput::SetValue(const std::vector &xyz) { VAssert(xyz.size() == 3); SetValue(xyz[0], xyz[1], xyz[2]); } void V3DInput::SetValue(const double xyz[3]) { SetValue(xyz[0], xyz[1], xyz[2]); } void V3DInput::GetValue(double xyz[3]) const { xyz[0] = _x->GetValueDouble(); xyz[1] = _y->GetValueDouble(); xyz[2] = _z->GetValueDouble(); } std::vector V3DInput::GetValue() const { std::vector v(3); GetValue(v.data()); return v; } void V3DInput::axisValueChanged(double) { double x = _x->GetValueDouble(); double y = _y->GetValueDouble(); double z = _z->GetValueDouble(); emit ValueChanged(x, y, z); emit ValueChangedVec(std::vector{x, y, z}); } ================================================ FILE: apps/vaporgui/V3DInput.h ================================================ #pragma once #include #include class VDoubleLineEdit; //! \class V3DInput //! \brief Widget that allows the user to specify a 3D point. //! \author Stas Jaroszynski class V3DInput : public QWidget { Q_OBJECT VDoubleLineEdit *_x, *_y, *_z; public: V3DInput(); void SetValue(double x, double y, double z); void SetValue(const std::vector &xyz); void SetValue(const double xyz[3]); void GetValue(double xyz[3]) const; std::vector GetValue() const; signals: void ValueChanged(double x, double y, double z); void ValueChangedVec(const std::vector &xyz); private slots: void axisValueChanged(double); }; ================================================ FILE: apps/vaporgui/V3DIntInput.cpp ================================================ #include "V3DIntInput.h" #include #include #include "VIntLineEdit.h" #include V3DIntInput::V3DIntInput() { QHBoxLayout *layout = new QHBoxLayout; layout->setMargin(0); setLayout(layout); layout->addWidget(new QLabel("X")); layout->addWidget(_x = new VIntLineEdit); layout->addWidget(new QLabel("Y")); layout->addWidget(_y = new VIntLineEdit); layout->addWidget(new QLabel("Z")); layout->addWidget(_z = new VIntLineEdit); for (auto input : {_x, _y, _z}) QObject::connect(input, &VIntLineEdit::ValueChanged, this, &V3DIntInput::axisValueChanged); } void V3DIntInput::SetValue(int x, int y, int z) { _x->SetValueInt(x); _y->SetValueInt(y); _z->SetValueInt(z); } void V3DIntInput::SetValue(const std::vector &xyz) { VAssert(xyz.size() == 3); SetValue(xyz[0], xyz[1], xyz[2]); } void V3DIntInput::axisValueChanged(int) { int x = _x->GetValueInt(); int y = _y->GetValueInt(); int z = _z->GetValueInt(); emit ValueChanged(x, y, z); emit ValueChangedVec(std::vector{x, y, z}); } ================================================ FILE: apps/vaporgui/V3DIntInput.h ================================================ #pragma once #include #include class VIntLineEdit; //! \class V3DIntInput //! \brief Widget that allows the user to specify a 3D integer vector //! \author Scott Pearse class V3DIntInput : public QWidget { Q_OBJECT VIntLineEdit *_x, *_y, *_z; public: V3DIntInput(); void SetValue(int x, int y, int z); void SetValue(const std::vector &xyz); signals: void ValueChanged(int x, int y, int z); void ValueChangedVec(const std::vector &xyz); private slots: void axisValueChanged(int); }; ================================================ FILE: apps/vaporgui/VActions.cpp ================================================ #include #include "VActions.h" #include "VIntSpinBox.h" #include "VCheckBox.h" #include "VStringLineEdit.h" #include "VIntLineEdit.h" #include "VDoubleLineEdit.h" VLineAction::VLineAction(const std::string &title, VHBoxWidget *container) : QWidgetAction(NULL) { VLineItem *vli = new VLineItem(title, container); vli->setContentsMargins(5, 0, 5, 0); setDefaultWidget(vli); } VSpinBoxAction::VSpinBoxAction(const std::string &title, int value) : VLineAction(title, _spinBox = new VIntSpinBox(1, 10)) { _spinBox->SetValue(value); connect(_spinBox, SIGNAL(ValueChanged(int)), this, SLOT(_spinBoxChanged(int))); } void VSpinBoxAction::SetValue(int value) { _spinBox->SetValue(value); } void VSpinBoxAction::_spinBoxChanged(int value) { emit editingFinished(value); } VCheckBoxAction::VCheckBoxAction(const std::string &title, bool value) : VLineAction(title, _checkBox = new VCheckBox(value)) { connect(_checkBox, &VCheckBox::ValueChanged, this, &VCheckBoxAction::_checkBoxChanged); } void VCheckBoxAction::SetValue(bool value) { _checkBox->SetValue(value); } void VCheckBoxAction::_checkBoxChanged(bool value) { emit clicked(value); } VStringLineEditAction::VStringLineEditAction(const std::string &title, std::string value) : VLineAction(title, _lineEdit = new VStringLineEdit(value)) { connect(_lineEdit, SIGNAL(ValueChanged(int)), this, SLOT(_lineEditChanged(int))); } void VStringLineEditAction::SetValue(const std::string &value) { _lineEdit->SetValueString(value); } void VStringLineEditAction::_lineEditChanged(int value) { emit ValueChanged(value); } VIntLineEditAction::VIntLineEditAction(const std::string &title, int value) : VLineAction(title, _lineEdit = new VIntLineEdit(value)) { connect(_lineEdit, SIGNAL(ValueChanged(int)), this, SLOT(_lineEditChanged(int))); } void VIntLineEditAction::SetValue(int value) { _lineEdit->SetValueInt(value); } void VIntLineEditAction::_lineEditChanged(int value) { emit ValueChanged(value); } VDoubleLineEditAction::VDoubleLineEditAction(const std::string &title, double value) : VLineAction(title, _lineEdit = new VDoubleLineEdit(value)) { connect(_lineEdit, SIGNAL(ValueChanged(double)), this, SLOT(_lineEditChanged(double))); } void VDoubleLineEditAction::SetValue(double value) { _lineEdit->SetValueDouble(value); } void VDoubleLineEditAction::_lineEditChanged(double value) { emit ValueChanged(value); } ================================================ FILE: apps/vaporgui/VActions.h ================================================ #pragma once #include #include class VIntSpinBox; class VCheckBox; class VStringLineEdit; class VIntLineEdit; class VDoubleLineEdit; #include "VHBoxWidget.h" class VLineAction : public QWidgetAction { Q_OBJECT public: VLineAction(const std::string &title, VHBoxWidget *container); }; //! //! \class VSpinBoxAction //! \ingroup Public_GUI //! \brief A menu item represented by a VLabel and VSpinBox, wrapped in a VLineItem //! selection tab in any renderer EventRouter class //! A QWidgetAction that represents itself as a VLineItem, which contains //! a VLabel and a VSpinBox. VWidget's standard SetValue() //! function can be used to retrieve and update the current value. Used //! within QMenu classes. class VSpinBoxAction : public VLineAction { Q_OBJECT public: VSpinBoxAction(const std::string &title, int value); //! Set the current integer value held by the VSpinBox void SetValue(int value); private: VIntSpinBox *_spinBox; private slots: //! Respond to a change in the VSpinBox void _spinBoxChanged(int value); signals: void editingFinished(int); }; //! //! \class VCheckBoxAction //! \ingroup Public_GUI //! \brief A menu item represented by a VLabel and VCheckBox, wrapped in a VLineItem //! A QWidgetAction that represents itself as a VLineItem, which contains //! a VLabel and a VCheckBox. VWidget's standard SetValue() //! function can be used to retrieve and update the current value. Used //! within QMenu classes. class VCheckBoxAction : public VLineAction { Q_OBJECT public: VCheckBoxAction(const std::string &title, bool value); //! Set the checkstate of the VCheckBox (0=unchecked, 1=checked) void SetValue(bool value); private: VCheckBox *_checkBox; private slots: //! Respond to a change in the checkstate of the VCheckBox void _checkBoxChanged(bool value); signals: void clicked(bool); }; //! //! \class VStringLineEditAction //! \ingroup Public_GUI //! \brief A menu item represented by a VLabel and VStringLineEdit, wrapped in a VLineItem //! A QWidgetAction that represents itself as a VLineItem, which contains //! a VLabel and a VStringLineEditAction. VWidget's standard SetValue() //! function can be used to retrieve and update the current value. Used //! within QMenu classes. class VStringLineEditAction : public VLineAction { Q_OBJECT public: VStringLineEditAction(const std::string &title, std::string value); //! Set the string value held by the VStringLineEdit void SetValue(const std::string &value); private: VStringLineEdit *_lineEdit; private slots: //! Respond to a change made (editingFinished, or returnPressed) in the V*LineEdit void _lineEditChanged(int value); signals: void ValueChanged(int); }; //! //! \class VIntLineEditAction //! \ingroup Public_GUI //! \brief A menu item represented by a VLabel and VIntLineEdit, wrapped in a VLineItem //! A QWidgetAction that represents itself as a VLineItem, which contains //! a VLabel and a VIntLineEditAction. VWidget's standard SetValue() //! function can be used to retrieve and update the current value. Used //! within QMenu classes. class VIntLineEditAction : public VLineAction { Q_OBJECT public: VIntLineEditAction(const std::string &title, int value); //! Set the numeric value held by the VIntLineEdit void SetValue(int value); private: VIntLineEdit *_lineEdit; private slots: //! @copydoc VStringLineEditAction::SetValue() void _lineEditChanged(int value); signals: void ValueChanged(int); }; //! //! \class VIntLineEditAction //! \ingroup Public_GUI //! \brief A menu item represented by a VLabel and VIntLineEdit, wrapped in a VLineItem //! A QWidgetAction that represents itself as a VLineItem, which contains //! a VLabel and a VDoubleLineEditAction. VWidget's standard SetValue() //! function can be used to retrieve and update the current value. Used //! within QMenu classes. class VDoubleLineEditAction : public VLineAction { Q_OBJECT public: VDoubleLineEditAction(const std::string &title, double value); //! @copydoc VIntLineEditAction::SetValue() void SetValue(double value); private: VDoubleLineEdit *_lineEdit; private slots: //! @copydoc VIntLineEditAction::_lineEditChanged() void _lineEditChanged(double value); signals: void ValueChanged(double); }; ================================================ FILE: apps/vaporgui/VCheckBox.cpp ================================================ #include "VCheckBox.h" VCheckBox::VCheckBox(bool checked) : VHBoxWidget() { _checkBox = new QCheckBox; SetValue(checked); layout()->addWidget(_checkBox); connect(_checkBox, &QCheckBox::clicked, this, &VCheckBox::emitCheckBoxChanged); } // Stas thinks that we should have setValues and setValue instead of Update // void VCheckBox::SetValue(bool checked) { _checkBox->blockSignals(true); _checkBox->setChecked(checked); _checkBox->blockSignals(false); } bool VCheckBox::GetValue() const { return _checkBox->isChecked(); } void VCheckBox::emitCheckBoxChanged(bool checked) { emit ValueChanged(checked); } ================================================ FILE: apps/vaporgui/VCheckBox.h ================================================ #pragma once #include #include #include #include "VHBoxWidget.h" //! class VCheckBox //! //! Wraps a QCheckBox and provides vaporgui's standard setter/getter functions //! and signals. class VCheckBox : public VHBoxWidget { Q_OBJECT public: VCheckBox(bool value = false); void SetValue(bool value); bool GetValue() const; private: QCheckBox *_checkBox; public slots: void emitCheckBoxChanged(bool checked); signals: void ValueChanged(bool checked); }; ================================================ FILE: apps/vaporgui/VComboBox.cpp ================================================ #include "VComboBox.h" #include #include #include #include "VHBoxWidget.h" VComboBox::VComboBox(const std::vector &values) : VContainer(_combo = new QComboBox) { _combo->setSizeAdjustPolicy(QComboBox::AdjustToContents); // Disable scroll wheel // _combo->setFocusPolicy(Qt::StrongFocus); _combo->installEventFilter(new MouseWheelWidgetAdjustmentGuard(_combo)); SetOptions(values); // We are forced to used SIGNAL/SLOT macros here because there are two // signatures for QComboBox::currentIndexChanged connect(_combo, SIGNAL(currentIndexChanged(QString)), this, SLOT(emitComboChanged(QString))); } // Stas thinks that we should have setValues and setValue instead of Update // void VComboBox::SetOptions(const std::vector &values) { _options = values; _combo->blockSignals(true); _combo->clear(); for (auto i : values) { _combo->addItem(QString::fromStdString(i)); } _combo->blockSignals(false); } void VComboBox::SetIndex(int index) { if (index >= _combo->count()) return; _combo->blockSignals(true); _combo->setCurrentIndex(index); _combo->blockSignals(false); } void VComboBox::SetValue(const std::string &value) { if (!STLUtils::Contains(_options, value)) { _options.push_back(value); SetOptions(_options); } QString qValue = QString::fromStdString(value); int index = _combo->findText(qValue); if (index >= 0) SetIndex(index); } void VComboBox::SetItemEnabled(int index, bool enabled) { QStandardItemModel *model = dynamic_cast(_combo->model()); assert(model); if (!model) return; model->item(index)->setEnabled(enabled); } int VComboBox::GetCurrentIndex() const { return _combo->currentIndex(); } std::string VComboBox::GetValue() const { return _combo->currentText().toStdString(); } int VComboBox::GetCount() const { return _combo->count(); } void VComboBox::emitComboChanged(const QString &value) { emit ValueChanged(value.toStdString()); emit IndexChanged(_combo->currentIndex()); } ================================================ FILE: apps/vaporgui/VComboBox.h ================================================ #pragma once #include #include #include "VContainer.h" //! class VComboBox //! //! Wraps a QComboBox and provides vaporgui's standard setter/getter functions //! and signals. class VComboBox : public VContainer { Q_OBJECT public: VComboBox(const std::vector &values = {}); void SetOptions(const std::vector &values); void SetIndex(int index); void SetValue(const std::string &value); void SetItemEnabled(int index, bool enabled); std::string GetValue() const; int GetCurrentIndex() const; int GetCount() const; private: QComboBox *_combo; std::vector _options; public slots: void emitComboChanged(const QString &value); signals: void ValueChanged(std::string value); void IndexChanged(int index); }; ================================================ FILE: apps/vaporgui/VContainer.cpp ================================================ #include "VContainer.h" #include #include VContainer::VContainer(QWidget *w) { QLayout *layout = new QVBoxLayout; layout->setMargin(0); layout->setSpacing(0); layout->addWidget(w); QWidget::setLayout(layout); } void VContainer::AddBottomStretch() { QVBoxLayout *layout = dynamic_cast(QWidget::layout()); assert(layout); assert(layout->count() == 1); layout->addStretch(); } void VContainer::SetPadding(int left, int top, int right, int bottom) { QVBoxLayout *layout = dynamic_cast(QWidget::layout()); assert(layout); layout->setContentsMargins(left, top, right, bottom); } ================================================ FILE: apps/vaporgui/VContainer.h ================================================ #pragma once #include class VContainer : public QWidget { public: VContainer(QWidget *w); void AddBottomStretch(); void SetPadding(int left, int top, int right, int bottom); QLayout *layout() const = delete; void setLayout(QLayout *) = delete; }; ================================================ FILE: apps/vaporgui/VDoubleLineEdit.cpp ================================================ #include #include #include #include #include "VDoubleLineEdit.h" VDoubleLineEdit::VDoubleLineEdit(double value) : VNumericLineEdit(), _value(value) { std::string formattedNumber = _formatValue(_value); SetValueString(formattedNumber); } void VDoubleLineEdit::SetValueDouble(double value) { _value = value; std::string formattedNumber = _formatValue(value); SetValueString(formattedNumber); } double VDoubleLineEdit::GetValueDouble() const { return _value; } void VDoubleLineEdit::SetRange(double min, double max) { _min = min; _max = max; } void VDoubleLineEdit::_valueChanged() { std::string str = _getText(); double value; try { value = std::stod(str); value = std::min(_max, std::max(_min, value)); // If value changed, update and emit, otherwiese revert to old value if (value != _value) { SetValueDouble(value); emit ValueChanged(_value); } else { SetValueDouble(_value); } } catch (const std::invalid_argument &) { SetValueDouble(_value); } catch (const std::out_of_range &) { SetValueDouble(_value); } } std::string VDoubleLineEdit::_formatValue(double value) { std::stringstream stream; stream << std::fixed << std::setprecision(_decimalDigits); if (_sciNotation) { stream << std::scientific; stream << value; } else { stream << value; } return stream.str(); } ================================================ FILE: apps/vaporgui/VDoubleLineEdit.h ================================================ #pragma once #include #include #include #include #include #include "VNumericLineEdit.h" //! \class VDoubleLineEdit //! \ingroup Public_GUI //! \brief A wrapper for a QLineEdit that handles user input of type double, //! and provides Vapor's standard setters, getters, and signals class VDoubleLineEdit : public VNumericLineEdit { Q_OBJECT public: VDoubleLineEdit(double value = 0.0); //! Set the current double value in the line edit void SetValueDouble(double value); //! Get the current double value in the line edit double GetValueDouble() const; void SetRange(double min, double max); protected: std::string _formatValue(double value); double _value; double _min = -std::numeric_limits::max(); double _max = std::numeric_limits::max(); protected slots: void _valueChanged() override; signals: void ValueChanged(double value); }; ================================================ FILE: apps/vaporgui/VDoubleRangeMenu.cpp ================================================ #include "VDoubleRangeMenu.h" #include "VActions.h" VDoubleRangeMenu::VDoubleRangeMenu(QWidget *parent, bool sciNotation, double decimalDigits, double min, double max, bool rangeChangable) : VNumericFormatMenu(parent, sciNotation, decimalDigits), _minRangeAction(new VDoubleLineEditAction("Minimum value", min)), _maxRangeAction(new VDoubleLineEditAction("Maximum value", max)) { connect(_minRangeAction, &VDoubleLineEditAction::ValueChanged, this, &VDoubleRangeMenu::_minChanged); addAction(_minRangeAction); connect(_maxRangeAction, &VDoubleLineEditAction::ValueChanged, this, &VDoubleRangeMenu::_maxChanged); addAction(_maxRangeAction); if (!rangeChangable) { _minRangeAction->setEnabled(false); _maxRangeAction->setEnabled(false); } } void VDoubleRangeMenu::AllowUserRange(bool allowed) { _minRangeAction->setEnabled(allowed); _maxRangeAction->setEnabled(allowed); } void VDoubleRangeMenu::SetMinimum(double min) { _minRangeAction->SetValue(min); } void VDoubleRangeMenu::SetMaximum(double max) { _maxRangeAction->SetValue(max); } void VDoubleRangeMenu::_minChanged(double min) { emit MinChanged(min); } void VDoubleRangeMenu::_maxChanged(double max) { emit MaxChanged(max); } ================================================ FILE: apps/vaporgui/VDoubleRangeMenu.h ================================================ #pragma once #include "VNumericFormatMenu.h" class VDoubleLineEditAction; //! \class VDoubleRangeMenu //! \ingroup Public_GUI //! \brief A menu that allows the user to control the range of double values //! that can be set by a widget. Also allows for setting the numeric format //! that the number is displayed with. class VDoubleRangeMenu : public VNumericFormatMenu { Q_OBJECT public: explicit VDoubleRangeMenu(QWidget *parent, bool sciNotation, double decimalDigits, double min, double max, bool rangeChangable); void AllowUserRange(bool allowed = true); protected: VDoubleLineEditAction *_minRangeAction; VDoubleLineEditAction *_maxRangeAction; public slots: //! Set the minimum value that the current widget can use void SetMinimum(double min); //! Set the maximum value that the current widget can use void SetMaximum(double max); private slots: void _minChanged(double min); void _maxChanged(double max); signals: void MinChanged(double min); void MaxChanged(double max); }; ================================================ FILE: apps/vaporgui/VDoubleSliderEdit.cpp ================================================ #include #include #include #include "vapor/VAssert.h" #include "VDoubleSliderEdit.h" #include "VDoubleLineEdit.h" #include "VDoubleSliderEditMenu.h" #include "VSlider.h" VDoubleSliderEdit::VDoubleSliderEdit(double min, double max, double value, bool rangeChangable) : VSliderEditInterface(), _value(value), _rangeChangable(rangeChangable) { _slider->SetRange(min, max); _slider->SetValue(value); connect(_slider, &VSlider::ValueChanged, this, &VDoubleSliderEdit::SetValue); connect(_slider, &VSlider::ValueChangedIntermediate, this, &VDoubleSliderEdit::_sliderChangedIntermediate); _lineEdit = new VDoubleLineEdit(value); _lineEdit->RemoveContextMenu(); layout()->addWidget(_lineEdit); connect(_lineEdit, SIGNAL(ValueChanged(double)), this, SLOT(SetValue(double))); _makeContextMenu(); } void VDoubleSliderEdit::AllowUserRange(bool allowed) { _rangeChangable = allowed; _menu->AllowUserRange(allowed); } void VDoubleSliderEdit::_makeContextMenu() { _menu = new VDoubleSliderEditMenu(this); connect(_menu, &VNumericFormatMenu::DecimalDigitsChanged, this, &VDoubleSliderEdit::SetNumDigits); connect(_menu, &VNumericFormatMenu::SciNotationChanged, this, &VDoubleSliderEdit::SetSciNotation); connect(_menu, &VDoubleRangeMenu::MinChanged, this, &VDoubleSliderEdit::SetMinimum); connect(_menu, &VDoubleRangeMenu::MaxChanged, this, &VDoubleSliderEdit::SetMaximum); connect(_menu, &VDoubleSliderEditMenu::DynamicUpdateChanged, this, &VDoubleSliderEdit::SetDynamicUpdate); } void VDoubleSliderEdit::AllowDynamicUpdate() const { _menu->AllowDynamicUpdate(); } void VDoubleSliderEdit::SetDynamicUpdate(bool enabled) { emit DynamicUpdateChanged(enabled); } bool VDoubleSliderEdit::GetSciNotation() const { return _lineEdit->GetSciNotation(); } void VDoubleSliderEdit::SetSciNotation(bool value) { if (value == _lineEdit->GetSciNotation()) { return; } _lineEdit->SetSciNotation(value); emit FormatChanged(); } int VDoubleSliderEdit::GetNumDigits() const { return _lineEdit->GetNumDigits(); } void VDoubleSliderEdit::SetNumDigits(int digits) { if (digits == _lineEdit->GetNumDigits()) { return; } _lineEdit->SetNumDigits(digits); emit FormatChanged(); } double VDoubleSliderEdit::GetValue() const { return _value; } void VDoubleSliderEdit::SetValue(double value) { // If the new value is illegal, reset _lineEdit's text and return if (value < _slider->GetMinimum() || value > _slider->GetMaximum()) { _lineEdit->SetValueDouble(_value); return; } _value = value; _lineEdit->SetValueDouble(_value); _slider->SetValue(_value); if (QObject::sender() != nullptr && QObject::sender() != this) { emit ValueChanged(_value); } } double VDoubleSliderEdit::GetMinimum() const { return _slider->GetMinimum(); ; } void VDoubleSliderEdit::SetMinimum(double min) { // If the new value is unchanged, or illegal, reset the menu and return if (min == _slider->GetMinimum() || min > _slider->GetMaximum()) { if (min > _value) { _value = min; SetValue(_value); } _menu->SetMinimum(_slider->GetMinimum()); return; } _slider->SetMinimum(min); _menu->SetMinimum(min); // If sender() is a nullptr, then this fuction is being called from Update(). // Don't emit anythong. Otherwise, emit our signal. if (QObject::sender() != nullptr) { emit MinimumChanged(min); } } double VDoubleSliderEdit::GetMaximum() const { return _slider->GetMaximum(); } void VDoubleSliderEdit::SetMaximum(double max) { // If the new value is unchanged, or illegal, reset the menu and retur if (max == _slider->GetMaximum() || max < _slider->GetMinimum()) { if (max < _value) { _value = max; SetValue(_value); } _menu->SetMaximum(_slider->GetMaximum()); return; } _slider->SetMaximum(max); _menu->SetMaximum(max); // If sender() is a nullptr, then this fuction is being called from Update(). // Don't emit anythong. Otherwise, emit our signal. if (QObject::sender() != nullptr) { emit MaximumChanged(max); } } void VDoubleSliderEdit::ShowContextMenu(const QPoint &pos) { QPoint globalPos = mapToGlobal(pos); _menu->exec(globalPos); } void VDoubleSliderEdit::_sliderChangedIntermediate(double value) { dynamic_cast(_lineEdit)->SetValueDouble(value); emit ValueChangedIntermediate(value); } ================================================ FILE: apps/vaporgui/VDoubleSliderEdit.h ================================================ #pragma once #include #include "VHBoxWidget.h" #include "VSliderEditInterface.h" class QMenu; class VDoubleLineEdit; class VDoubleSliderEditMenu; //! \class VDoubleSliderEdit //! \ingroup Public_GUI //! \brief A wrapper for a VSlider and a VDoubleLineEdit, that //! provides synchronization between the two widgets, and support //! for a menu that allows setting and getting the VSlider range, //! and the numeric representation of the VDoubleLineEdit class VDoubleSliderEdit : public VSliderEditInterface { Q_OBJECT public: VDoubleSliderEdit(double min = 0, double max = 10, double value = 3, bool rangeChangable = false); //! Set the minimum allowable value for the VSlider and VDoubleLineEdit void SetMinimum(double min); //! Set the maximum allowable value for the VSlider and VDoubleLineEdit void SetMaximum(double max); void AllowUserRange(bool allowed = true); void AllowDynamicUpdate() const; //! Get the value associated with the VSlider and VDoubleLineEdit double GetValue() const; //! Get the minimum allowable value for the VSlider and VDoubleLineEdit double GetMinimum() const; //! Get the maximum allowable value for the VSlider and VDoubleLineEdit double GetMaximum() const; //! Get the number of digits displayed by the VDoubleLineEdit virtual int GetNumDigits() const; //! Get whether the VDoubleLineEdit is being displayed with scientific notation virtual bool GetSciNotation() const; public slots: //! Set the current value displayed by the slider and line edit void SetValue(double value); //! Set the number of digits displayed by the VDoubleLineEdit virtual void SetNumDigits(int numDigits); //! Set whether the VDoubleLineEdit is being displayed with scientific notation virtual void SetSciNotation(bool sciNotation); //! Set the dynamic update menu item's toggle state virtual void SetDynamicUpdate(bool enabled); //! Show the context menu options for the entire widget, triggered on right-click virtual void ShowContextMenu(const QPoint &pos); protected: virtual void _makeContextMenu(); void _sliderChanged(double value); void _sliderChangedIntermediate(double value); double _value; bool _rangeChangable; VDoubleLineEdit * _lineEdit; VDoubleSliderEditMenu *_menu; signals: void ValueChanged(double value); void ValueChangedIntermediate(double value); void MinimumChanged(double min); void MaximumChanged(double max); void DynamicUpdateChanged(bool enabled); }; ================================================ FILE: apps/vaporgui/VDoubleSliderEditMenu.cpp ================================================ #include #include "VActions.h" #include "VDoubleSliderEditMenu.h" // clang-format off VDoubleSliderEditMenu::VDoubleSliderEditMenu(QWidget *parent) : VDoubleRangeMenu( parent, false, 2, 0., 10., false) { _dynamicUpdateAction = new VCheckBoxAction("Dynamic update enabled", false); connect(_dynamicUpdateAction, &VCheckBoxAction::clicked, this, &VDoubleSliderEditMenu::_dynamicUpdateChanged); addAction(_dynamicUpdateAction); _dynamicUpdateAction->setEnabled(false); } void VDoubleSliderEditMenu::AllowDynamicUpdate() const { _dynamicUpdateAction->setEnabled(true); } void VDoubleSliderEditMenu::SetDynamicUpdate(bool dynamicUpdateEnabled) { _dynamicUpdateAction->SetValue(dynamicUpdateEnabled); } void VDoubleSliderEditMenu::_dynamicUpdateChanged(bool dynamicUpdateEnabled) { emit DynamicUpdateChanged(dynamicUpdateEnabled); } // clang-format on ================================================ FILE: apps/vaporgui/VDoubleSliderEditMenu.h ================================================ #pragma once #include #include "VDoubleRangeMenu.h" class VCheckBoxAction; //! \class VDoubleSliderEditMenu //! \ingroup Public_GUI //! \brief A menu for VDoubleSliderEdit that allows for setting //! a min/max range, numeric formatting controls, and dynamic update controls //! in regard to how many digits are displayed, and whether scientific notation is used. // clang-format off class VDoubleSliderEditMenu : public VDoubleRangeMenu { Q_OBJECT public: explicit VDoubleSliderEditMenu(QWidget *parent); //! Allow the toggling of the dynamic update checkbox in the right-click menu void AllowDynamicUpdate() const; protected: VCheckBoxAction *_dynamicUpdateAction; public slots: //! Check/Uncheck the dynamic update checkbox void SetDynamicUpdate(bool enabled); private slots: void _dynamicUpdateChanged(bool dynamicUpdateEnabled); signals: void DynamicUpdateChanged(bool dynamicUpdateEnabled); }; // clang-format on ================================================ FILE: apps/vaporgui/VDoubleValidator.cpp ================================================ #include "VDoubleValidator.h" void VDoubleValidator::fixup(QString &input) const { bool ok; double v = locale().toDouble(input, &ok); if (ok) { if (v > top()) input.setNum(top()); if (v < bottom()) input.setNum(bottom()); } } QValidator::State VDoubleValidator::validate(QString &input, int &pos) const { State s = QDoubleValidator::validate(input, pos); if (s == State::Intermediate) { bool ok; double v = locale().toDouble(input, &ok); if (ok) if (v > top() || v < bottom()) s = State::Invalid; } return s; } ================================================ FILE: apps/vaporgui/VDoubleValidator.h ================================================ #pragma once #include //! \class VDoubleValidator //! Use as a direct replacement of QDoubleValidator. //! They behave the same except QDoubleValidator does not accept values outside //! the range while VDoubleValidator does not allow the user to input //! values outside of the range. This solves some quirks with QLineEdit //! With QDoubleValidator, the user can type a value outside the range in the text //! box but the text box will say the value is invalid and it will stop working //! VDoubleValidator, will not allow the user to type in a value outside the range //! omitting the above problem. class VDoubleValidator : public QDoubleValidator { public: using QDoubleValidator::QDoubleValidator; virtual void fixup(QString &input) const override; virtual QValidator::State validate(QString &input, int &pos) const override; }; ================================================ FILE: apps/vaporgui/VFileSelector.cpp ================================================ #include "VFileSelector.h" #include #include "FileOperationChecker.h" #include "ErrorReporter.h" #include "VPushButton.h" #include "VLineEdit_Deprecated.h" VFileSelector::VFileSelector(const std::string &buttonText, const std::string &defaultPath, const std::string &filter = "") : VHBoxWidget(), _filePath(defaultPath), _filter(filter) { _pushButton = new VPushButton(buttonText); _lineEdit = new VLineEdit_Deprecated(defaultPath); layout()->addWidget(_pushButton); layout()->addWidget(_lineEdit); if (_filePath.empty()) _filePath = QDir::homePath().toStdString(); connect(_pushButton, &VPushButton::ButtonClicked, this, &VFileSelector::OpenFileDialog); connect(_lineEdit, SIGNAL(ValueChanged(std::string)), this, SLOT(SetPathFromLineEdit(std::string))); } std::string VFileSelector::GetValue() const { return _filePath; } bool VFileSelector::SetValue(const std::string &file) { bool success = false; if (file == _filePath) // Do nothing, if nothing is changed return success; if (_isFileOperable(file)) { _filePath = file; success = true; } else { MSG_ERR(FileOperationChecker::GetLastErrorMessage().toStdString()); } _lineEdit->SetValue(_filePath); _lineEdit->setToolTip(QString::fromStdString(_filePath)); return success; } void VFileSelector::OpenFileDialog() { std::string file = _launchFileDialog(); if (SetValue(file)) { emit ValueChanged(_filePath); } } void VFileSelector::SetPathFromLineEdit(const std::string &file) { if (SetValue(file)) emit ValueChanged(_filePath); } void VFileSelector::HideLineEdit(bool hide) { if (hide) _lineEdit->hide(); else _lineEdit->show(); } // // // VFileReader::VFileReader(const std::string &buttonText, const std::string &defaultPath, const std::string &filter) : VFileSelector(buttonText, defaultPath, filter) {} std::string VFileReader::_launchFileDialog() { QString fileName = QFileDialog::getOpenFileName(this, "Select Directory/File", QString::fromStdString(_filePath), QString::fromStdString(_filter)); return fileName.toStdString(); } bool VFileReader::_isFileOperable(const std::string &filePath) const { bool operable = false; operable = FileOperationChecker::FileGoodToRead(QString::fromStdString(filePath)); return operable; } // // // VFileWriter::VFileWriter(const std::string &buttonText, const std::string &defaultPath, const std::string &filter) : VFileSelector(buttonText, defaultPath, filter) {} bool VFileWriter::_isFileOperable(const std::string &filePath) const { bool operable = false; operable = FileOperationChecker::FileGoodToWrite(QString::fromStdString(filePath)); return operable; } std::string VFileWriter::_launchFileDialog() { QString fileName = QFileDialog::getSaveFileName(this, "Select Directory/File", QString::fromStdString(_filePath), QString::fromStdString(_filter)); return fileName.toStdString(); } VDirSelector::VDirSelector(const std::string &buttonText, const std::string &defaultPath) : VFileSelector(buttonText, defaultPath) {} std::string VDirSelector::_launchFileDialog() { QString fileName = QFileDialog::getExistingDirectory(this, "Select Directory/File", QString::fromStdString(_filePath)); return fileName.toStdString(); } bool VDirSelector::_isFileOperable(const std::string &filePath) const { bool operable = false; operable = FileOperationChecker::DirectoryGoodToRead(QString::fromStdString(filePath)); return operable; } ================================================ FILE: apps/vaporgui/VFileSelector.h ================================================ #pragma once #include #include #include #include "VHBoxWidget.h" class VPushButton; class VLineEdit_Deprecated; //! class VFileSelector //! //! An abstract class for reading and writing files, or selecting //! directory paths. This class wraps a VLineEdit_Deprecated to display the current //! selection, and a VPushButton to open file dialogs. It also provides //! vaporgui's standard setter/getter functions and signals. class VFileSelector : public VHBoxWidget { Q_OBJECT public: std::string GetValue() const; bool SetValue(const std::string &file); void HideLineEdit(bool hide); protected: VFileSelector(const std::string &buttonText, const std::string &defaultPath, const std::string &filter); VLineEdit_Deprecated *_lineEdit; VPushButton * _pushButton; std::string _filePath; std::string _filter; private: virtual std::string _launchFileDialog() = 0; virtual bool _isFileOperable(const std::string &file) const = 0; public slots: void OpenFileDialog(); void SetPathFromLineEdit(const std::string &value); signals: void ValueChanged(const std::string &path); }; //! class VFileReader //! //! A class for opening a file-dialog and selecting a file for reading. //! This class provides vaporgui's standard setter/getter functions, and signals. class VFileReader : public VFileSelector { Q_OBJECT public: VFileReader(const std::string &buttonText = "Select", const std::string &defaultPath = QDir::homePath().toStdString(), const std::string &filter = ""); private: virtual std::string _launchFileDialog(); virtual bool _isFileOperable(const std::string &file) const; }; //! class VFileWriter //! //! A class for opening a file-dialog and selecting a file for writing. //! This class provides vaporgui's standard setter/getter functions, and signals. class VFileWriter : public VFileSelector { Q_OBJECT public: VFileWriter(const std::string &buttonText = "Select", const std::string &defaultPath = QDir::homePath().toStdString(), const std::string &filter = ""); private: virtual std::string _launchFileDialog(); virtual bool _isFileOperable(const std::string &file) const; }; //! class VFileSelector //! //! A class for opening a file-dialog and selecting a directory. //! This class provides vaporgui's standard setter/getter functions, and signals. class VDirSelector : public VFileSelector { Q_OBJECT public: VDirSelector(const std::string &buttonText = "Select", const std::string &defaultPath = QDir::homePath().toStdString()); private: virtual std::string _launchFileDialog(); virtual bool _isFileOperable(const std::string &file) const; }; ================================================ FILE: apps/vaporgui/VFrame.cpp ================================================ #include "VFrame.h" #include VFrame::VFrame() { setLayout(new QVBoxLayout); layout()->setContentsMargins(0, 0, 0, 0); layout()->setSpacing(12); setFrameStyle(QFrame::NoFrame); } void VFrame::addWidget(QWidget *widget) { layout()->addWidget(widget); _child_widgets.push_front(widget); _num_of_children++; } int VFrame::getNumOfChildWidgets() const { return _num_of_children; } int VFrame::hideChildAtIdx(int idx) { if (_child_widgets.empty()) return 1; else if (idx < 0 || idx >= _num_of_children) return 1; else { auto itr = _child_widgets.before_begin(); for (int i = 0; i < _num_of_children - idx; i++) ++itr; (*itr)->hide(); return 0; } } int VFrame::showChildAtIdx(int idx) { if (_child_widgets.empty()) return 1; else if (idx < 0 || idx >= _num_of_children) return 1; else { auto itr = _child_widgets.before_begin(); for (int i = 0; i < _num_of_children - idx; i++) ++itr; (*itr)->show(); return 0; } } ================================================ FILE: apps/vaporgui/VFrame.h ================================================ #pragma once #include #include #include //! \class VFrame //! //! A simple class that sets a layout, spacing, and margin //! policy onto a QFrame for consistency throughout the application. class VFrame : public QFrame { Q_OBJECT public: VFrame(); void addWidget(QWidget *widget); int getNumOfChildWidgets() const; // The following two methods control if a child is shown or hidden. // If a child widget is the ith added to this VFrame, then idx should be i-1. // It returns 0 upon success, and 1 upon failure (e.g. invalid index). int hideChildAtIdx(int idx); int showChildAtIdx(int idx); private: std::forward_list _child_widgets; int _num_of_children = 0; }; ================================================ FILE: apps/vaporgui/VGroup.cpp ================================================ #include "VGroup.h" #include VGroup::VGroup(List children) : VGroup(new QVBoxLayout, children) {} VGroup::VGroup(QBoxLayout *layout, List children) { layout->setMargin(0); layout->setSpacing(4); setLayout(layout); AddM(children); } VGroup *VGroup::Add(QWidget *w) { layout()->addWidget(w); return this; } VSubGroup::VSubGroup(List children) { layout()->setContentsMargins(12, 0, 0, 0); AddM(children); } VHGroup::VHGroup() : VGroup(new QHBoxLayout, {}) {} ================================================ FILE: apps/vaporgui/VGroup.h ================================================ #pragma once #include #include "AbstractWidgetGroup.h" class QBoxLayout; //! \class VGroup //! Creates a group for parameter controls in the sidebar class VGroup : public QWidget, public AbstractWidgetGroup { Q_OBJECT public: VGroup(List children = {}); VGroup *Add(QWidget *w); protected: VGroup(QBoxLayout *layout, List children); }; class VHGroup : public VGroup { Q_OBJECT public: VHGroup(); }; //! \class VSubGroup //! Creates a subgroup for parameter controls in the sidebar class VSubGroup : public VGroup { Q_OBJECT public: VSubGroup(List children = {}); }; ================================================ FILE: apps/vaporgui/VHBoxWidget.cpp ================================================ #include #include #include #include "VHBoxWidget.h" const int VHBoxWidget::_LEFT_MARGIN = 0; const int VHBoxWidget::_TOP_MARGIN = 0; const int VHBoxWidget::_RIGHT_MARGIN = 0; const int VHBoxWidget::_BOTTOM_MARGIN = 0; VHBoxWidget::VHBoxWidget() : QFrame() { QHBoxLayout *layout = new QHBoxLayout; layout->setContentsMargins(_LEFT_MARGIN, _TOP_MARGIN, _RIGHT_MARGIN, _BOTTOM_MARGIN); setLayout(layout); setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); } MouseWheelWidgetAdjustmentGuard::MouseWheelWidgetAdjustmentGuard(QObject *parent) : QObject(parent) {} bool MouseWheelWidgetAdjustmentGuard::eventFilter(QObject *o, QEvent *e) { const QWidget *widget = dynamic_cast(o); if (e->type() == QEvent::Wheel && widget && !widget->hasFocus()) { e->ignore(); return true; } return QObject::eventFilter(o, e); } // QSize VContainer::sizeHint() const { // QWidget* parent = this->parentWidget(); // if ( layout()->count() > 1 ) { // return QSize( parent->width() / 2., 20 ); // } // else { // return QSize( parent->width() / 3. , 20 ); // } //} ================================================ FILE: apps/vaporgui/VHBoxWidget.h ================================================ #pragma once #include #include #include #include "VLineItem.h" //! \class VContainer //! //! A simple wrapper class for one or more VWidgets. //! Sets a standard layout and margin policy, and protects //! against unwanted mouse scroll whell events. class VHBoxWidget : public QFrame { Q_OBJECT public: // virtual QSize sizeHint() const; VHBoxWidget(); private: static const int _LEFT_MARGIN; static const int _TOP_MARGIN; static const int _RIGHT_MARGIN; static const int _BOTTOM_MARGIN; }; // Helper object for disabling the mouse scroll-wheel on a given widget. // #include class MouseWheelWidgetAdjustmentGuard : public QObject { public: explicit MouseWheelWidgetAdjustmentGuard(QObject *parent); protected: bool eventFilter(QObject *o, QEvent *e) override; }; ================================================ FILE: apps/vaporgui/VHyperlink.cpp ================================================ #include "VHyperlink.h" #include VHyperlink::VHyperlink(const std::string &text, const std::string &url, bool bullet) : VLabel() { std::string link = "" + text + ""; if (bullet == true) link.insert(0, "• "); _ql->setText(QString::fromStdString(link)); _ql->setTextFormat(Qt::RichText); _ql->setTextInteractionFlags(Qt::TextBrowserInteraction); _ql->setOpenExternalLinks(true); } ================================================ FILE: apps/vaporgui/VHyperlink.h ================================================ #pragma once #include "VLabel.h" //! \class VHyperlink //! A VLabel that contains a hyperlink and optional bulletpoint class VHyperlink : public VLabel { public: VHyperlink(const std::string &text = "", const std::string &url = "", bool bullet=false); }; ================================================ FILE: apps/vaporgui/VIntLineEdit.cpp ================================================ #include #include #include #include #include #include "VIntLineEdit.h" VIntLineEdit::VIntLineEdit(int value) : VNumericLineEdit(), _value(value) { std::string formattedNumber = _formatValue(_value); SetValueString(formattedNumber); } void VIntLineEdit::SetValueInt(int value) { std::string formattedNumber = _formatValue(value); try { _value = (int)std::stod(formattedNumber); } catch (const std::invalid_argument &) { return; } catch (const std::out_of_range &) { return; } SetValueString(formattedNumber); } int VIntLineEdit::GetValueInt() const { return _value; } void VIntLineEdit::_valueChanged() { std::string str = _getText(); int value; try { double dValue = std::stod(str); if (_checkOverflow(dValue)) { SetValueInt(_value); return; } value = (int)std::stod(str); // If value changed, update and emit, otherwiese revert to old value if (value != _value) { SetValueInt(value); emit ValueChanged(_value); } else { SetValueInt(_value); } } catch (const std::invalid_argument &) { SetValueInt(_value); } catch (const std::out_of_range &) { SetValueInt(_value); } } std::string VIntLineEdit::_formatValue(int value) { std::stringstream stream; stream << std::fixed << std::setprecision(_decimalDigits); if (_sciNotation) { stream << std::scientific; stream << (double)value; } else { stream << value; } return stream.str(); } bool VIntLineEdit::_checkOverflow(double value) { std::stringstream svalue; svalue << std::fixed << std::setprecision(0) << value; std::string error = "Value " + svalue.str() + " exceeds "; if (value < INT_MIN) { error += " minimum integer limit (" + std::to_string(INT_MIN) + ")."; MSG_ERR(error); return true; } if (value > INT_MAX) { error += " maximum integer limit (" + std::to_string(INT_MAX) + ")."; MSG_ERR(error); return true; } return false; } ================================================ FILE: apps/vaporgui/VIntLineEdit.h ================================================ #pragma once #include #include #include #include #include #include "VNumericLineEdit.h" //! \class VIntLineEdit //! \ingroup Public_GUI //! \brief A wrapper for a QLineEdit that handles user input of type int, //! and provides Vapor's standard setters, getters, and signals class VIntLineEdit : public VNumericLineEdit { Q_OBJECT public: VIntLineEdit(int value = 0); //! Set the current int value in the line edit void SetValueInt(int value); //! Get the current int value in the line iedit int GetValueInt() const; protected: virtual void _valueChanged(); std::string _formatValue(int value); bool _checkOverflow(double value); int _value; signals: void ValueChanged(int value); }; ================================================ FILE: apps/vaporgui/VIntRangeMenu.cpp ================================================ #include "VIntRangeMenu.h" #include "VActions.h" VIntRangeMenu::VIntRangeMenu(QWidget *parent, bool sciNotation, int decimalDigits, int min, int max, bool rangeChangable) : VNumericFormatMenu(parent, sciNotation, decimalDigits), _minRangeAction(new VIntLineEditAction("Minimum value", min)), _maxRangeAction(new VIntLineEditAction("Maximum value", max)) { connect(_minRangeAction, &VIntLineEditAction::ValueChanged, this, &VIntRangeMenu::_minChanged); addAction(_minRangeAction); connect(_maxRangeAction, &VIntLineEditAction::ValueChanged, this, &VIntRangeMenu::_maxChanged); addAction(_maxRangeAction); if (!rangeChangable) { _minRangeAction->setEnabled(false); _maxRangeAction->setEnabled(false); } } void VIntRangeMenu::AllowUserRange(bool allowed) { _minRangeAction->setEnabled(allowed); _maxRangeAction->setEnabled(allowed); } void VIntRangeMenu::SetMinimum(int min) { _minRangeAction->SetValue(min); } void VIntRangeMenu::SetMaximum(int max) { _maxRangeAction->SetValue(max); } void VIntRangeMenu::_minChanged(int min) { emit MinChanged(min); } void VIntRangeMenu::_maxChanged(int max) { emit MaxChanged(max); } ================================================ FILE: apps/vaporgui/VIntRangeMenu.h ================================================ #pragma once #include "VNumericFormatMenu.h" class VIntLineEditAction; //! \class VIntRangeMenu //! \ingroup Public_GUI //! \brief A menu that allows the user to control the range of integer values //! that can be set by a widget. Also allows for setting the numeric format //! that the number is displayed with. class VIntRangeMenu : public VNumericFormatMenu { Q_OBJECT public: explicit VIntRangeMenu(QWidget *parent, bool sciNotation, int decimalDigits, int min, int max, bool rangeChangable = false); void AllowUserRange(bool allowed = true); protected: VIntLineEditAction *_minRangeAction; VIntLineEditAction *_maxRangeAction; public: //! Set the minimum value that the current widget can use void SetMinimum(int min); //! Set the maximum value that the current widget can use void SetMaximum(int max); private slots: void _minChanged(int min); void _maxChanged(int max); signals: void MinChanged(int min); void MaxChanged(int max); }; ================================================ FILE: apps/vaporgui/VIntSliderEdit.cpp ================================================ #include #include #include "vapor/VAssert.h" #include "VIntSliderEdit.h" #include "VIntLineEdit.h" #include "VIntSliderEditMenu.h" #include "VSlider.h" VIntSliderEdit::VIntSliderEdit(int min, int max, int value, bool rangeChangable) : VSliderEditInterface(), _value(value), _rangeChangable(rangeChangable) { _slider->SetRange(min, max); _slider->SetValue(value); connect(_slider, &VSlider::ValueChanged, this, &VIntSliderEdit::SetValue); connect(_slider, &VSlider::ValueChangedIntermediate, this, &VIntSliderEdit::_sliderChangedIntermediate); _lineEdit = new VIntLineEdit(value); _lineEdit->RemoveContextMenu(); layout()->addWidget(_lineEdit); connect(_lineEdit, SIGNAL(ValueChanged(int)), this, SLOT(SetValue(int))); _makeContextMenu(); } void VIntSliderEdit::AllowUserRange(bool allowed) { _rangeChangable = allowed; _menu->AllowUserRange(allowed); } void VIntSliderEdit::_makeContextMenu() { _menu = new VIntSliderEditMenu(this); connect(_menu, &VNumericFormatMenu::DecimalDigitsChanged, this, &VIntSliderEdit::SetNumDigits); connect(_menu, &VNumericFormatMenu::SciNotationChanged, this, &VIntSliderEdit::SetSciNotation); connect(_menu, &VIntRangeMenu::MinChanged, this, &VIntSliderEdit::SetMinimum); connect(_menu, &VIntRangeMenu::MaxChanged, this, &VIntSliderEdit::SetMaximum); connect(_menu, &VIntSliderEditMenu::DynamicUpdateChanged, this, &VIntSliderEdit::SetDynamicUpdate); } void VIntSliderEdit::AllowDynamicUpdate() const { _menu->AllowDynamicUpdate(); } void VIntSliderEdit::SetDynamicUpdate(bool enabled) { emit DynamicUpdateChanged(enabled); } bool VIntSliderEdit::GetSciNotation() const { return _lineEdit->GetSciNotation(); } void VIntSliderEdit::SetSciNotation(bool value) { if (value == _lineEdit->GetSciNotation()) { return; } _lineEdit->SetSciNotation(value); emit FormatChanged(); } int VIntSliderEdit::GetNumDigits() const { return _lineEdit->GetNumDigits(); } void VIntSliderEdit::SetNumDigits(int digits) { if (digits == _lineEdit->GetNumDigits()) { return; } _lineEdit->SetNumDigits(digits); emit FormatChanged(); } int VIntSliderEdit::GetValue() const { return _value; } void VIntSliderEdit::SetValue(int value) { // If the new value is unchanged or illegal, reset _lineEdit and return if (value == _value || value < _slider->GetMinimum() || value > _slider->GetMaximum()) { _lineEdit->SetValueInt(_value); return; } _value = value; _lineEdit->SetValueInt(_value); _slider->SetValue(_value); if (QObject::sender() != nullptr && QObject::sender() != this) { emit ValueChanged(_value); } } int VIntSliderEdit::GetMinimum() const { return _slider->GetMinimum(); ; } void VIntSliderEdit::SetMinimum(int min) { // If the new value is unchanged, or illegal, reset the menu and retur if (min == _slider->GetMinimum() || min > _slider->GetMaximum()) { if (min > _value) { _value = min; SetValue(_value); } _menu->SetMinimum(_slider->GetMinimum()); return; } _slider->SetMinimum(min); _menu->SetMinimum(min); // If sender() is a nullptr, then this fuction is being called from Update(). // Don't emit anythong. Otherwise, emit our signal. if (QObject::sender() != nullptr) { emit MinimumChanged(min); } } int VIntSliderEdit::GetMaximum() const { return _slider->GetMaximum(); } void VIntSliderEdit::SetMaximum(int max) { // If the new value is unchanged, or illegal, reset the menu and return if (max == _slider->GetMaximum() || max < _slider->GetMinimum()) { if (max < _value) { _value = max; SetValue(_value); } _menu->SetMaximum(_slider->GetMaximum()); return; } _slider->SetMaximum(max); _menu->SetMaximum(max); // If sender() is a nullptr, then this fuction is being called from Update(). // Don't emit anythong. Otherwise, emit our signal. if (QObject::sender() != nullptr) { emit MaximumChanged(max); } } void VIntSliderEdit::ShowContextMenu(const QPoint &pos) { QPoint globalPos = mapToGlobal(pos); _menu->exec(globalPos); } void VIntSliderEdit::_sliderChangedIntermediate(int value) { dynamic_cast(_lineEdit)->SetValueInt(value); emit ValueChangedIntermediate(value); } ================================================ FILE: apps/vaporgui/VIntSliderEdit.h ================================================ #pragma once #include #include "VHBoxWidget.h" #include "VSliderEditInterface.h" class VIntSliderEditMenu; class VIntLineEdit; //! \class VIntSliderEdit //! \ingroup Public_GUI //! \brief A wrapper for a VSlider and a VIntLineEdit, that //! provides synchronization between the two widgets, and support //! for a menu that allows setting and getting the VSlider range, //! and the numeric representation of the VIntLineEdit class VIntSliderEdit : public VSliderEditInterface { Q_OBJECT public: VIntSliderEdit(int min = 0, int max = 10, int value = 3, bool rangeChangable = false); //! Set the dynamic update menu item's toggle state virtual void SetDynamicUpdate(bool enabled); //! Set the minimum allowable value for the VSlider and VIntLineEdit void SetMinimum(int min); //! Set the maximum allowable value for the VSlider and VIntLineEdit void SetMaximum(int max); void AllowUserRange(bool allowed = true); //! Allow the toggling of dynamic updating widgets void AllowDynamicUpdate() const; //! Get the value associated with the VSlider and VIntLineEdit int GetValue() const; //! Get the minimum allowable value for the VSlider and VIntLineEdit int GetMinimum() const; //! Get the maximum allowable value for the VSlider and VIntLineEdit int GetMaximum() const; //! Get the number of digits displayed by the VIntLineEdit virtual int GetNumDigits() const; //! Set the number of digits displayed by the VIntLineEdit virtual void SetNumDigits(int numDigits); //! Get whether the VIntLineEdit is being displayed with scientific notation virtual bool GetSciNotation() const; //! Set whether the VIntLineEdit is being displayed with scientific notation virtual void SetSciNotation(bool sciNotation); //! Show the context menu options for the entire widget, triggered on right-click virtual void ShowContextMenu(const QPoint &pos); public slots: //! Set the current value displayed by the slider and line edit void SetValue(int value); protected: virtual void _makeContextMenu(); void _sliderChanged(int value); void _sliderChangedIntermediate(int value); int _value; bool _rangeChangable; VIntSliderEditMenu *_menu; VIntLineEdit * _lineEdit; signals: void ValueChanged(int value); void ValueChangedIntermediate(int value); void MinimumChanged(int min); void MaximumChanged(int max); void DynamicUpdateChanged(bool enabled); }; ================================================ FILE: apps/vaporgui/VIntSliderEditMenu.cpp ================================================ #include #include "VActions.h" #include "VIntSliderEditMenu.h" // clang-format off VIntSliderEditMenu::VIntSliderEditMenu( QWidget *parent ) : VIntRangeMenu( parent, false, 2, 0., 10., false ) { _dynamicUpdateAction = new VCheckBoxAction("Dynamic update enabled", false); connect(_dynamicUpdateAction, &VCheckBoxAction::clicked, this, &VIntSliderEditMenu::_dynamicUpdateChanged); addAction(_dynamicUpdateAction); _dynamicUpdateAction->setEnabled(false); } void VIntSliderEditMenu::AllowDynamicUpdate() const { _dynamicUpdateAction->setEnabled(true); } void VIntSliderEditMenu::SetDynamicUpdate(bool dynamicUpdateEnabled) { _dynamicUpdateAction->SetValue(dynamicUpdateEnabled); } void VIntSliderEditMenu::_dynamicUpdateChanged(bool dynamicUpdateEnabled) { emit DynamicUpdateChanged(dynamicUpdateEnabled); } // clang-format on ================================================ FILE: apps/vaporgui/VIntSliderEditMenu.h ================================================ #pragma once #include #include "VIntRangeMenu.h" class VCheckBoxAction; //! \class VIntSliderEditMenu //! \ingroup Public_GUI //! \brief A menu for VIntSliderEdit that allows for setting //! a min/max range, numeric formatting controls, and dynamic update controls //! in regard to how many digits are displayed, and whether scientific notation is used. // clang-format off class VIntSliderEditMenu : public VIntRangeMenu { Q_OBJECT public: explicit VIntSliderEditMenu( QWidget *parent ); //! Allow the toggling of the dynamic update checkbox in the right-click menu void AllowDynamicUpdate() const; protected: VCheckBoxAction *_dynamicUpdateAction; public slots: //! Check/Uncheck the dynamic update checkbox void SetDynamicUpdate(bool enabled); private slots: void _dynamicUpdateChanged(bool dynamicUpdateEnabled); signals: void DynamicUpdateChanged(bool dynamicUpdateEnabled); }; // clang-format on ================================================ FILE: apps/vaporgui/VIntSpinBox.cpp ================================================ #include #include "VIntSpinBox.h" #include VIntSpinBox::VIntSpinBox(int min, int max) : VHBoxWidget(), _value(min) { _spinBox = new QSpinBox; SetRange(min, max); SetValue(min); layout()->addWidget(_spinBox); _spinBox->setKeyboardTracking(false); // Emit when the spinbox loses focus, or when return is pressed // Note: when opening a context menu with right click, a QSpinBox will emit the editingFinished signal, // due to the QLineEdit receiving focus upon click, and losing focus upon opening the menu. // In the VIntSpinBox's slot, we must therefore check if the currently held value has changed before emitting. connect(_spinBox, &QSpinBox::editingFinished, this, &VIntSpinBox::emitValueChanged); // QSpinBox overloads valueChanged. This makes the function pointer // based syntax for signal and slot connection ugly, so defer to // SIGNAL/SLOT connections with data type specificaiton. // // More info here: https://doc.qt.io/qt-5/qspinbox.html#valueChanged connect(_spinBox, SIGNAL(valueChanged(int)), this, SLOT(emitValueChangedIntermediate(int))); } void VIntSpinBox::SetValue(int value) { _value = value; _spinBox->blockSignals(true); _spinBox->setValue(_value); _spinBox->blockSignals(false); } void VIntSpinBox::SetRange(int min, int max) { blockSignals(true); _spinBox->setRange(min, max); blockSignals(false); } int VIntSpinBox::GetValue() const { return _spinBox->value(); } void VIntSpinBox::emitValueChanged() { int value = GetValue(); if (value != _value) { _value = value; emit ValueChanged(_value); } } void VIntSpinBox::emitValueChangedIntermediate(int value) { emit ValueChangedIntermediate(value); } ================================================ FILE: apps/vaporgui/VIntSpinBox.h ================================================ #pragma once #include #include #include #include "VHBoxWidget.h" //! class VIntSpinBox //! //! Wraps a QSpinBox and provides vaporgui's standard setter/getter functions //! and signals. class VIntSpinBox : public VHBoxWidget { Q_OBJECT public: VIntSpinBox(int min, int max); void SetValue(int value); void SetRange(int min, int max); int GetValue() const; private: QSpinBox *_spinBox; int _value; public slots: void emitValueChanged(); void emitValueChangedIntermediate(int value); signals: void ValueChanged(int value); void ValueChangedIntermediate(int value); }; ================================================ FILE: apps/vaporgui/VLabel.cpp ================================================ #include "VLabel.h" #include VLabel::VLabel(const std::string &text) : VContainer(_ql = new QLabel) { _ql->setWordWrap(true); SetText(text); } void VLabel::SetText(const std::string &text) { _ql->setText(QString::fromStdString(text)); } void VLabel::MakeSelectable() { _ql->setTextInteractionFlags(_ql->textInteractionFlags() | Qt::TextSelectableByMouse); } ================================================ FILE: apps/vaporgui/VLabel.h ================================================ #pragma once #include "VContainer.h" #include class QLabel; class VLabel : public VContainer { protected: QLabel *_ql; public: VLabel(const std::string &text = ""); void SetText(const std::string &text); void MakeSelectable(); }; ================================================ FILE: apps/vaporgui/VLabelPair.cpp ================================================ #include "VLabelPair.h" #include VLabelPair::VLabelPair() : VHBoxWidget() { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); _leftLabel = new QLabel(); _rightLabel = new QLabel(); _rightLabel->setAlignment(Qt::AlignRight); layout()->addWidget(_leftLabel); layout()->addWidget(_rightLabel); } void VLabelPair::SetLeftText(const std::string &text) const { _leftLabel->setText(QString::fromStdString(text)); } void VLabelPair::SetRightText(const std::string &text) const { _rightLabel->setText(QString::fromStdString(text)); } ================================================ FILE: apps/vaporgui/VLabelPair.h ================================================ #include "VHBoxWidget.h" class QLabel; //! \class VLabelPair //! \brief A VHBoxWidget that contains a pair of labels that can be set independently class VLabelPair : public VHBoxWidget { Q_OBJECT QLabel *_leftLabel; QLabel *_rightLabel; public: VLabelPair(); void SetLeftText(const std::string &text) const; void SetRightText(const std::string &text) const; }; ================================================ FILE: apps/vaporgui/VLineEdit_Deprecated.cpp ================================================ #include #include #include #include #include #include "VLineEdit_Deprecated.h" #include "ErrorReporter.h" VLineEdit_Deprecated::VLineEdit_Deprecated(const std::string &value) : VHBoxWidget(), _value(value), _isDouble(false), _scientific(false), _menuEnabled(false), _decDigits(10) { _lineEdit = new QLineEdit; SetValue(_value); layout()->addWidget(_lineEdit); connect(_lineEdit, &QLineEdit::editingFinished, this, &VLineEdit_Deprecated::emitLineEditChanged); } void VLineEdit_Deprecated::UseDoubleMenu() { _menuEnabled = true; _lineEdit->setContextMenuPolicy(Qt::CustomContextMenu); connect(_lineEdit, &QLineEdit::customContextMenuRequested, this, &VLineEdit_Deprecated::ShowContextMenu); } void VLineEdit_Deprecated::SetValue(double value) { VAssert(_isDouble); std::stringstream stream; if (_menuEnabled) { stream << std::fixed << std::setprecision(_decDigits); if (_scientific) stream << std::scientific; } stream << value << std::endl; _value = stream.str(); _lineEdit->blockSignals(true); _lineEdit->setText(QString::fromStdString(_value)); _lineEdit->blockSignals(false); } void VLineEdit_Deprecated::SetValue(const std::string &value) { _value = value; _lineEdit->blockSignals(true); _lineEdit->setText(QString::fromStdString(_value)); _lineEdit->blockSignals(false); } std::string VLineEdit_Deprecated::GetValue() const { return _value; } void VLineEdit_Deprecated::SetIsDouble(bool isDouble) { _isDouble = isDouble; } void VLineEdit_Deprecated::SetReadOnly(bool b) { _lineEdit->setReadOnly(b); } void VLineEdit_Deprecated::emitLineEditChanged() { std::string value = _lineEdit->text().toStdString(); SetValue(value); emit ValueChanged(_value); } void VLineEdit_Deprecated::ShowContextMenu(const QPoint &pos) { if (!_menuEnabled) return; QMenu menu; SpinBoxAction *decimalAction = new SpinBoxAction(tr("Decimal digits"), _decDigits); connect(decimalAction, &SpinBoxAction::editingFinished, this, &VLineEdit_Deprecated::_decimalDigitsChanged); menu.addAction(decimalAction); CheckBoxAction *checkBoxAction = new CheckBoxAction(tr("Scientific"), _scientific); connect(checkBoxAction, &CheckBoxAction::clicked, this, &VLineEdit_Deprecated::_scientificClicked); menu.addAction(checkBoxAction); QPoint globalPos = _lineEdit->mapToGlobal(pos); menu.exec(globalPos); } void VLineEdit_Deprecated::_decimalDigitsChanged(int value) { _decDigits = value; SetValue(_value); } void VLineEdit_Deprecated::_scientificClicked(bool value) { _scientific = value; SetValue(_value); } ================================================ FILE: apps/vaporgui/VLineEdit_Deprecated.h ================================================ #pragma once #include #include #include #include #include #include #include #include "VHBoxWidget.h" //! \class VLineEdit_Deprecated //! //! Wraps a QLineEdit with vaporgui's standard setter/getter functions. //! Handles string and double types, as well as precision and display of //! double values. class VLineEdit_Deprecated : public VHBoxWidget { Q_OBJECT public: VLineEdit_Deprecated(const std::string &value = ""); void SetValue(double value); void SetValue(const std::string &value); std::string GetValue() const; // Note: VLineEdit_Deprecated does NOT support an integer type at this point. // When isDouble == false, it represents a string. void SetIsDouble(bool isDouble); //! Sets the line edit to read-only based on the value of b void SetReadOnly(bool b); void UseDoubleMenu(); private: QLineEdit *_lineEdit; std::string _value; bool _isDouble; bool _scientific; bool _menuEnabled; int _decDigits; public slots: void emitLineEditChanged(); void ShowContextMenu(const QPoint &); private slots: void _decimalDigitsChanged(int value); void _scientificClicked(bool value); signals: void ValueChanged(const std::string &value); }; class SpinBoxAction : public QWidgetAction { Q_OBJECT public: SpinBoxAction(const QString &title, int value) : QWidgetAction(NULL) { QWidget * widget = new QWidget(NULL); QHBoxLayout *layout = new QHBoxLayout(); QLabel * label = new QLabel(title); // bug fixed here, pointer was missing _spinBox = new QSpinBox(NULL); _spinBox->setValue(value); layout->setContentsMargins(-1, 0, -1, 0); layout->addWidget(label); layout->addWidget(_spinBox); widget->setLayout(layout); // We need to use SIGNAL/SLOT macros here because the arguments // of the signal and slot do not match connect(_spinBox, SIGNAL(valueChanged(int)), this, SLOT(spinBoxChanged())); setDefaultWidget(widget); } private: QSpinBox *_spinBox; private slots: void spinBoxChanged() { int value = _spinBox->value(); emit editingFinished(value); } signals: void editingFinished(int); }; class CheckBoxAction : public QWidgetAction { Q_OBJECT public: CheckBoxAction(const QString &title, bool value) : QWidgetAction(NULL) { QWidget * widget = new QWidget(NULL); QHBoxLayout *layout = new QHBoxLayout(); QLabel * label = new QLabel(title); _checkBox = new QCheckBox(NULL); _checkBox->setChecked(value); layout->setContentsMargins(-1, 0, 20, 0); layout->addWidget(label); layout->addStretch(); layout->addWidget(_checkBox); widget->setLayout(layout); connect(_checkBox, &QCheckBox::clicked, this, &CheckBoxAction::checkBoxChanged); setDefaultWidget(widget); } private: QCheckBox *_checkBox; private slots: void checkBoxChanged(bool value) { emit clicked(value); } signals: void clicked(bool); }; ================================================ FILE: apps/vaporgui/VLineItem.cpp ================================================ #include #include "VLineItem.h" #include #include const int VLineItem::_LEFT_MARGIN = 0; const int VLineItem::_TOP_MARGIN = 0; const int VLineItem::_RIGHT_MARGIN = 0; const int VLineItem::_BOTTOM_MARGIN = 0; VLineItem::VLineItem(const std::string &label, QLayoutItem *centerItem, QWidget *rightWidget) : VLineItem(label) { layout()->addItem(centerItem); layout()->addWidget(rightWidget); } VLineItem::VLineItem(const std::string &label, QWidget *centerWidget, QWidget *rightWidget) : VLineItem(label) { layout()->addWidget(centerWidget); layout()->addWidget(rightWidget); } VLineItem::VLineItem(const std::string &label, QWidget *rightWidget) : VLineItem(label, (QLayoutItem *)new QSpacerItem(0, 20, QSizePolicy::Maximum, QSizePolicy::Minimum), rightWidget) {} VLineItem::VLineItem(const std::string &label) { setLayout(new QHBoxLayout); layout()->setContentsMargins(_LEFT_MARGIN, _TOP_MARGIN, _RIGHT_MARGIN, _BOTTOM_MARGIN); QLabel *qLabel = new QLabel(label.c_str()); layout()->addWidget(qLabel); } ================================================ FILE: apps/vaporgui/VLineItem.h ================================================ #pragma once #include #include #include //! \class VLineItem //! A widget that creates a label - input pair separated by a spacer //! as is used throughout vapor class VLineItem : public QWidget { Q_OBJECT public: VLineItem(const std::string &label, QLayoutItem *centerItem, QWidget *rightWidget); VLineItem(const std::string &label, QWidget *centerWidget, QWidget *rightWidget); VLineItem(const std::string &label, QWidget *rightWidget); private: static const int _LEFT_MARGIN; static const int _TOP_MARGIN; static const int _BOTTOM_MARGIN; static const int _RIGHT_MARGIN; VLineItem(const std::string &label); }; ================================================ FILE: apps/vaporgui/VNumericFormatMenu.cpp ================================================ #include #include #include #include #include "VActions.h" #include "VNumericFormatMenu.h" VNumericFormatMenu::VNumericFormatMenu(QWidget *parent, bool sciNotation, int decimalDigits) : QMenu(parent), _sciNotationAction(new VCheckBoxAction("Scientific notation", sciNotation)), _decimalAction(new VSpinBoxAction("Decimal digits", decimalDigits)) { connect(_sciNotationAction, &VCheckBoxAction::clicked, this, &VNumericFormatMenu::_sciNotationChanged); addAction(_sciNotationAction); connect(_decimalAction, &VSpinBoxAction::editingFinished, this, &VNumericFormatMenu::_decimalDigitsChanged); addAction(_decimalAction); } void VNumericFormatMenu::SetDecimalDigits(int digits) { _decimalAction->SetValue(digits); } void VNumericFormatMenu::SetSciNotation(bool sciNotation) { _sciNotationAction->SetValue(sciNotation); } void VNumericFormatMenu::_decimalDigitsChanged(int digits) { emit DecimalDigitsChanged(digits); } void VNumericFormatMenu::_sciNotationChanged(bool sciNotation) { emit SciNotationChanged(sciNotation); } ================================================ FILE: apps/vaporgui/VNumericFormatMenu.h ================================================ #pragma once #include class VCheckBoxAction; class VSpinBoxAction; //! \class VNumericFormatMenu //! \ingroup Public_GUI //! \brief A menu that allows users to specify how a number is displayed in a line edit, //! in regard to how many digits are displayed, and whether scientific notation is used. class VNumericFormatMenu : public QMenu { Q_OBJECT public: explicit VNumericFormatMenu(QWidget *parent, bool sciNotation, int decimalDigits); //! Set the number of decimal digits used by the clicked line-edit void SetDecimalDigits(int digits); //! Set whether the current line-edit is using scientific notation void SetSciNotation(bool sciNotation); protected: VCheckBoxAction *_sciNotationAction; VSpinBoxAction * _decimalAction; private slots: void _decimalDigitsChanged(int digits); void _sciNotationChanged(bool sciNotation); signals: void DecimalDigitsChanged(int decimalDigits); void SciNotationChanged(bool sciNotation); }; ================================================ FILE: apps/vaporgui/VNumericLineEdit.cpp ================================================ #include #include "VNumericFormatMenu.h" #include "VNumericLineEdit.h" VNumericLineEdit::VNumericLineEdit(int decimals) : VStringLineEdit(), _sciNotation(false), _decimalDigits(decimals) { _menu = new VNumericFormatMenu(this, _sciNotation, _decimalDigits); connect(_menu, &VNumericFormatMenu::SciNotationChanged, this, &VNumericLineEdit::SetSciNotation); connect(_menu, &VNumericFormatMenu::DecimalDigitsChanged, this, &VNumericLineEdit::SetNumDigits); SetCustomContextMenu(); } int VNumericLineEdit::GetNumDigits() const { return _decimalDigits; } void VNumericLineEdit::SetNumDigits(int digits) { _decimalDigits = digits; _valueChanged(); emit DecimalDigitsChanged(_decimalDigits); } bool VNumericLineEdit::GetSciNotation() const { return _sciNotation; } void VNumericLineEdit::SetSciNotation(bool sciNotation) { _sciNotation = sciNotation; _valueChanged(); emit SciNotationChanged(_sciNotation); } void VNumericLineEdit::_showMenu(const QPoint &pos) { QPoint globalPos = mapToGlobal(pos); _menu->exec(globalPos); }; ================================================ FILE: apps/vaporgui/VNumericLineEdit.h ================================================ #pragma once #include #include "vapor/VAssert.h" #include "VHBoxWidget.h" #include "VStringLineEdit.h" class VNumericFormatMenu; class VCheckBoxAction; class VSpinBoxAction; //! \class VNumericSliderEdit //! \ingroup Public_GUI //! \brief An abstract class defining functions used by different //! V*LineEdits (VDoubleLineEdit, VIntLineEdit, and VStringLineEdit). //! Supports menus that allow different functionalities, depending //! on the data type being used by the line edit. class VNumericLineEdit : public VStringLineEdit { Q_OBJECT protected: explicit VNumericLineEdit(int decimals = 5); public: //! If the line edit is numeric, get the number of digits of the number being displayed int GetNumDigits() const; //! If the line edit is numeric, set the number of digits of the number being displayed void SetNumDigits(int digits); //! If the line edit is numeric, get whether the display is in scientific notation bool GetSciNotation() const; //! If the line edit is numeric, set whether the display is in scientific notation void SetSciNotation(bool sciNotation); protected slots: //! Called whenever the line edit's value is changed. Must be reimplemented by derived classes //! to handle correct formatting virtual void _valueChanged() = 0; //! Show a custom context menu virtual void _showMenu(const QPoint &pos); protected: VNumericFormatMenu *_menu; bool _sciNotation; int _decimalDigits; signals: // Required to propogate changes from the menus // up to Params, via PWidgets void DecimalDigitsChanged(int decimalDigits); void SciNotationChanged(bool sciNotation); }; ================================================ FILE: apps/vaporgui/VProjectionStringFrame.cpp ================================================ #include #include "VProjectionStringFrame.h" #include "PProjectionStringWidget.h" VProjectionStringFrame::VProjectionStringFrame(PProjectionStringWidget *section) : VFrame(), _section(section) { layout()->addWidget(_section); show(); } void VProjectionStringFrame::Update(ParamsBase *p, ParamsMgr *pm, DataMgr* dm) { _section->Update(p, pm); } void VProjectionStringFrame::closeEvent(QCloseEvent *event) { emit closed(); QWidget::closeEvent(event); } ================================================ FILE: apps/vaporgui/VProjectionStringFrame.h ================================================ #pragma once #include "VFrame.h" #include "ParamsUpdatable.h" class PProjectionStringWidget; class VProjectionStringFrame : public VFrame , public ParamsUpdatable { Q_OBJECT PProjectionStringWidget *_section; public: VProjectionStringFrame(PProjectionStringWidget *psection); void Update(VAPoR::ParamsBase *p, VAPoR::ParamsMgr *pm = nullptr, VAPoR::DataMgr *dm = nullptr) override; protected: void closeEvent(QCloseEvent *event) override; signals: void closed(); }; ================================================ FILE: apps/vaporgui/VPushButton.cpp ================================================ #include "VPushButton.h" VPushButton::VPushButton(const std::string &buttonText) : VHBoxWidget() { _pushButton = new QPushButton(QString::fromStdString(buttonText)); _pushButton->setFocusPolicy(Qt::NoFocus); layout()->addWidget(_pushButton); // We need to use SIGNAL/SLOT macros here because the arguments // of the signal and slot do not match connect(_pushButton, SIGNAL(clicked(bool)), this, SLOT(emitButtonClicked())); } void VPushButton::emitButtonClicked() { emit ButtonClicked(); } ================================================ FILE: apps/vaporgui/VPushButton.h ================================================ #pragma once #include #include #include #include "VHBoxWidget.h" //! \class VPushButton //! //! Wraps a QPushButton with vaporgui's VContainer, so that //! the QPushButton follows correct size policy class VPushButton : public VHBoxWidget { Q_OBJECT public: VPushButton(const std::string &buttonText = "Select"); private: QPushButton *_pushButton; public slots: void emitButtonClicked(); signals: void ButtonClicked(); }; ================================================ FILE: apps/vaporgui/VRadioButton.cpp ================================================ #include "VRadioButton.h" #include VRadioButton::VRadioButton(const std::string &label, bool checked) : VHBoxWidget() { _radioButton = new QRadioButton(QString::fromStdString(label), nullptr); SetValue(checked); layout()->addWidget(_radioButton); connect(_radioButton, &QRadioButton::toggled, this, &VRadioButton::emitRadioButtonChanged); } void VRadioButton::SetValue(bool checked) { _radioButton->blockSignals(true); _radioButton->setChecked(checked); _radioButton->blockSignals(false); } bool VRadioButton::GetValue() const { return _radioButton->isChecked(); } std::string VRadioButton::GetText() const { return _radioButton->text().toStdString(); } void VRadioButton::emitRadioButtonChanged(bool checked) { emit ValueChanged(checked); } ================================================ FILE: apps/vaporgui/VRadioButton.h ================================================ #pragma once #include #include #include "VHBoxWidget.h" class QRadioButton; //! class VRadioButton //! //! Wraps a QRadioButton and provides vaporgui's standard setter/getter functions //! and signals. class VRadioButton : public VHBoxWidget { Q_OBJECT public: VRadioButton(const std::string &label, bool value = false); void SetValue(bool value); bool GetValue() const; std::string GetText() const; private: QRadioButton *_radioButton; public slots: void emitRadioButtonChanged(bool checked); signals: void ValueChanged(bool checked); }; ================================================ FILE: apps/vaporgui/VRouter.cpp ================================================ #include "VRouter.h" #include "vapor/STLUtils.h" VRouter::VRouter() : VContainer(_stack = new QStackedWidget) { } VRouter::VRouter(AbstractWidgetGroup::List children) : VContainer(_stack = new QStackedWidget) { AddM(children); } VRouter *VRouter::Add(QWidget *w) { AbstractWidgetGroup::Add(w); _stack->addWidget(w); return this; } void VRouter::Show(QWidget *w) { if (w == nullptr) return Show(emptyWidget()); if (!STLUtils::Contains(_children, w)) Add(w); _stack->setCurrentWidget(w); } QWidget *VRouter::emptyWidget() { if (_emptyWidget == nullptr) _emptyWidget = new QWidget; return _emptyWidget; } ================================================ FILE: apps/vaporgui/VRouter.h ================================================ #pragma once #include "VContainer.h" #include "AbstractWidgetGroup.h" #include class VRouter : public VContainer, public AbstractWidgetGroup { Q_OBJECT QStackedWidget *_stack; QWidget *_emptyWidget = nullptr; public: VRouter(); VRouter(List children); VRouter *Add(QWidget *w) override; void Show(QWidget *w); private: QWidget *emptyWidget(); }; ================================================ FILE: apps/vaporgui/VScrollArea.cpp ================================================ #include "VScrollArea.h" VScrollArea::VScrollArea(QWidget *w) { QScrollArea::setWidget(w); QScrollArea::setWidgetResizable(true); sizePolicy().setVerticalStretch(1); // setSizePolicy(QSizePolicy::Ignored,QSizePolicy::Ignored); } ================================================ FILE: apps/vaporgui/VScrollArea.h ================================================ #pragma once #include class VScrollArea : public QScrollArea { Q_OBJECT public: VScrollArea(QWidget *w); }; ================================================ FILE: apps/vaporgui/VScrollGroup.h ================================================ #pragma once #include "VScrollArea.h" #include "VGroup.h" #include "VContainer.h" class VScrollGroup : public VScrollArea, public WidgetGroupWrapper { Q_OBJECT VContainer *_container; VGroup *_group; public: VScrollGroup(List children = {}) : VScrollArea(_container = new VContainer(_group = new VGroup())), WidgetGroupWrapper(_group) { _container->AddBottomStretch(); _group->AddM(children);// } }; ================================================ FILE: apps/vaporgui/VSection.cpp ================================================ #include "VSection.h" #include #include #include VSection::VSection(const std::string &title) { QTabWidget::addTab(new QWidget, QString::fromStdString(title)); _tab()->setLayout(new QVBoxLayout); layout()->setMargin(12); setStyleSheet(_createStylesheet()); } QVBoxLayout *VSection::layout() const { return (QVBoxLayout *)_tab()->layout(); } void VSection::setMenu(QMenu *menu) { SettingsMenuButton *menuButton = (SettingsMenuButton *)QTabWidget::cornerWidget(); if (!menuButton) { menuButton = new SettingsMenuButton; QTabWidget::setCornerWidget(menuButton); } menuButton->setMenu(menu); } void VSection::enableExpandedSection() { ExpandSectionButton *expandSectionButton = (ExpandSectionButton *)QTabWidget::cornerWidget(); if (!expandSectionButton) { expandSectionButton = new ExpandSectionButton; QTabWidget::setCornerWidget(expandSectionButton, Qt::TopLeftCorner); } connect(expandSectionButton, &QToolButton::clicked, this, [this](){ emit this->expandButtonClicked(); }); } std::string VSection::getTitle() const { return QTabWidget::tabText(0).toStdString(); } QWidget *VSection::_tab() const { return QTabWidget::widget(0); } QString VSection::_createStylesheet() const { std::string stylesheet; #if defined(Darwin) stylesheet += R"( QTabWidget::right-corner { top: 24px; right: 3px; } )"; stylesheet += R"( QTabWidget::left-corner { top: 24px; left: 3px; } )"; #else stylesheet += R"( QTabWidget::right-corner { top: -3px; right: 5px; } )"; stylesheet += R"( QTabWidget::left-corner { top: -3px; right: 5px; } )"; #endif return QString::fromStdString(stylesheet); } VSection::SettingsMenuButton::SettingsMenuButton() : AbstractButton() { setIcon(QIcon(QString::fromStdString(Wasp::GetSharePath("images/gear-dropdown1.png")))); configureButton(); } void VSection::SettingsMenuButton::setIconDark(bool darkMode) { if (darkMode) setIcon(QIcon(QString::fromStdString(Wasp::GetSharePath("images/gear-dropdown1_darkMode.png")))); else setIcon(QIcon(QString::fromStdString(Wasp::GetSharePath("images/gear-dropdown1.png")))); } void VSection::AbstractButton::setDarkOrLight() { QColor textColor = this->palette().color(QPalette::WindowText); if (textColor.lightness() > 128) setIconDark(); else setIconDark(false); } void VSection::AbstractButton::paintEvent(QPaintEvent *event) { // This function is overridden to prevent Qt from drawing its own dropdown arrow QStylePainter p(this); setDarkOrLight(); QStyleOptionToolButton option; initStyleOption(&option); option.subControls = QStyle::SC_ToolButton; option.features = QStyleOptionToolButton::None; p.drawComplexControl(QStyle::CC_ToolButton, option); } void VSection::AbstractButton::configureButton() { setIconSize(QSize(18, 18)); setCursor(QCursor(Qt::PointingHandCursor)); setPopupMode(QToolButton::InstantPopup); setStyleSheet("border: none;" "background-color: none;" "padding: 0px;"); } VSection::ExpandSectionButton::ExpandSectionButton() : AbstractButton() { setIcon(QIcon(QString::fromStdString(Wasp::GetSharePath("images/expandSection.png")))); configureButton(); } void VSection::ExpandSectionButton::setIconDark(bool darkMode) { if (darkMode) setIcon(QIcon(QString::fromStdString(Wasp::GetSharePath("images/expandSection_darkMode.png")))); else setIcon(QIcon(QString::fromStdString(Wasp::GetSharePath("images/expandSection.png")))); } ================================================ FILE: apps/vaporgui/VSection.h ================================================ #pragma once #include #include #include #include #include //! \class VSection //! Represents a section/group to be used in the sidebar. //! Provides a consistent layout which is not supposed to be changed //! Provides a settings menu that is intended to provide extra options for the parameters that are //! shown within this section, for example resetting to default values. //! //! Prefer the use of VSectionGroup when possible. class VSection : public QTabWidget { Q_OBJECT class SettingsMenuButton; class ExpandSectionButton; class AbstractButton; public: VSection(const std::string &title); QVBoxLayout *layout() const; void setMenu(QMenu *menu); void enableExpandedSection(); std::string getTitle() const; void setLayout(QLayout *layout) = delete; int addTab(QWidget *page, const QString &label) = delete; QWidget *widget(int index) const = delete; void setCornerWidget(QWidget *widget, Qt::Corner corner) = delete; QWidget *cornerWidget() const = delete; private: QWidget *_tab() const; QString _createStylesheet() const; signals: void expandButtonClicked(); }; #include "AbstractWidgetGroup.h" #include "VGroup.h" //! \class VSectionGroup //! \brief VSection that implements the standardized widget group interface. Use this one when possible. //! \author Stas Jaroszynski class VSectionGroup : public VSection, public WidgetGroupWrapper { public: VSectionGroup(const std::string &title, List children = {}) : VSection(title), WidgetGroupWrapper(new VGroup()) { layout()->addWidget(_group); _group->AddM(children); } }; class VSection::AbstractButton : public QToolButton { Q_OBJECT protected: AbstractButton() {}; void paintEvent(QPaintEvent *event); void configureButton(); void setDarkOrLight(); virtual void setIconDark(bool darkMode = true) = 0; }; class VSection::SettingsMenuButton : public AbstractButton { Q_OBJECT void setIconDark(bool darkMode) override; public: SettingsMenuButton(); }; class VSection::ExpandSectionButton: public AbstractButton { Q_OBJECT void setIconDark(bool darkMode) override; public: ExpandSectionButton(); }; ================================================ FILE: apps/vaporgui/VSlider.cpp ================================================ #include #include #include #include #include "VSlider.h" #define NUM_STEPS 100 VSlider::VSlider(double min, double max) : VHBoxWidget(), _min(0.0), _max(0.0), _stepSize(1.0) { _slider = new QSlider; _slider->setOrientation(Qt::Horizontal); _slider->setMinimum(0); _slider->setMaximum(NUM_STEPS); SetRange(min, max); SetValue((max - min) / 2); layout()->addWidget(_slider); connect(_slider, &QSlider::sliderMoved, this, &VSlider::_sliderChangedIntermediate); connect(_slider, &QSlider::sliderReleased, this, &VSlider::_sliderChanged); _slider->installEventFilter(new ScrollWheelEater); } void VSlider::SetValue(double value) { if (_stepSize <= 0) return; if (value > _max) value = _max; if (value < _min) value = _min; value = (value - _min) / _stepSize; _slider->blockSignals(true); _slider->setValue(value); _slider->blockSignals(false); } double VSlider::GetMinimum() const { return _min; } void VSlider::SetMinimum(double min) { if (min > _max) _max = min; SetRange(min, _max); } double VSlider::GetMaximum() const { return _max; } void VSlider::SetMaximum(double max) { if (max < _min) _min = max; SetRange(_min, max); } void VSlider::SetRange(double min, double max) { // VAssert( min <= max ); double previousValue = GetValue(); _min = min; _max = max; _stepSize = (_max - _min) / NUM_STEPS; if (previousValue < min) previousValue = min; if (previousValue > max) previousValue = max; SetValue(previousValue); } double VSlider::GetValue() const { int sliderVal = _slider->value(); // Return min/max values if the slider is at the end. // note - Qt does not move the sliders to positions 0, 1, 99, or 100 until // the mouse is released. if (sliderVal <= 2) // positions 0, 1 and 2 return _min; if (sliderVal >= NUM_STEPS - 2) // positions 98, 99, and 100 return _max; double value = _stepSize * _slider->value() + _min; return value; } void VSlider::_sliderChanged() { double value = GetValue(); emit ValueChanged(value); } void VSlider::_sliderChangedIntermediate(int position) { double value = GetValue(); emit ValueChangedIntermediate(value); } bool ScrollWheelEater::eventFilter(QObject *object, QEvent *event) { if (event->type() == QEvent::Wheel) { return true; } else { return QObject::eventFilter(object, event); } } ================================================ FILE: apps/vaporgui/VSlider.h ================================================ #pragma once #include #include #include #include "VHBoxWidget.h" // Fix for Qt bug https://bugreports.qt.io/browse/QTBUG-98093 // Apply a style sheet to QSlider to make it work on OSX Monterey #ifdef Darwin #include "QMontereySlider.h" #define QSlider QMontereySlider #endif //! class VSlider //! //! Wraps a QSlider and provides vaporgui's standard setter/getter fucntions //! and signals. This class also provides range setting for the slider values. class VSlider : public VHBoxWidget { Q_OBJECT public: VSlider(double min = 0, double max = 1); double GetValue() const; void SetValue(double value); double GetMinimum() const; void SetMinimum(double min); double GetMaximum() const; void SetMaximum(double max); void SetRange(double min, double max); private: QSlider *_slider; double _min; double _max; double _stepSize; private slots: void _sliderChanged(); void _sliderChangedIntermediate(int position); signals: void ValueChanged(double value); void ValueChangedIntermediate(double value); }; class ScrollWheelEater : public QObject { Q_OBJECT protected: bool eventFilter(QObject *obj, QEvent *event) override; }; ================================================ FILE: apps/vaporgui/VSliderEdit.cpp ================================================ #include #include #include "vapor/VAssert.h" #include "VSliderEdit.h" #include "VSlider.h" #include "VLineEdit_Deprecated.h" VSliderEdit::VSliderEdit(double min, double max, double value) : VHBoxWidget(), _minValid(min), _maxValid(max), _value(value), _isIntType(false) { _lineEdit = new VLineEdit_Deprecated(); _slider = new VSlider(); SetRange(min, max); SetValue(value); layout()->addWidget(_slider); layout()->addWidget(_lineEdit); connect(_lineEdit, SIGNAL(ValueChanged(const std::string &)), this, SLOT(_lineEditChanged(const std::string &))); connect(_slider, &VSlider::ValueChanged, this, &VSliderEdit::_sliderChanged); connect(_slider, &VSlider::ValueChangedIntermediate, this, &VSliderEdit::_sliderChangedIntermediate); } double VSliderEdit::GetValue() const { return _value; } void VSliderEdit::SetValue(double value) { if (_isIntType) value = std::round(value); if (value < _minValid) value = _minValid; if (value > _maxValid) value = _maxValid; if (_isIntType) _lineEdit->SetValue(std::to_string((int)value)); else _lineEdit->SetValue(std::to_string(value)); _slider->SetValue(value); _value = value; } void VSliderEdit::SetRange(double min, double max) { if (_isIntType) { min = round(min); max = round(max); } VAssert(min <= max); if (_value < min) _value = min; if (_value > max) _value = max; _slider->SetRange(min, max); _minValid = min; _maxValid = max; } void VSliderEdit::SetIntType(bool type) { _isIntType = type; SetValue(_value); } void VSliderEdit::_lineEditChanged(const std::string &value) { try { double newValue = std::stod(value); SetValue(newValue); if (_isIntType) emit ValueChangedInt((int)_value); else emit ValueChanged(_value); } // If we can't convert the _lineEdit text to a double, // then revert to the previous value. catch (...) { SetValue(_value); } } void VSliderEdit::_sliderChanged(double value) { SetValue(value); if (_isIntType) { emit ValueChangedInt((int)_value); } else emit ValueChanged(_value); } void VSliderEdit::_sliderChangedIntermediate(double value) { if (_isIntType) { _lineEdit->SetValue(std::to_string((int)value)); emit ValueChangedIntIntermediate((int)value); } else { _lineEdit->SetValue(std::to_string(value)); emit ValueChangedIntermediate(value); } } ================================================ FILE: apps/vaporgui/VSliderEdit.h ================================================ #pragma once #include #include "VHBoxWidget.h" class VSlider; class VLineEdit_Deprecated; //! class VSliderEdit //! //! Wraps a VSlider and a VLineEdit_Deprecated for selecting a numeric value within a //! defined range. Allows for integer and double value types. This class //! also provides vaporgui's standard setter/getter functions and signals. class VSliderEdit : public VHBoxWidget { Q_OBJECT public: VSliderEdit(double min = 0., double max = 1., double value = 0.); void SetIntType(bool type); void SetValue(double value); void SetRange(double min, double max); double GetValue() const; private: VLineEdit_Deprecated *_lineEdit; VSlider * _slider; double _minValid; double _maxValid; double _value; bool _isIntType; private slots: void _lineEditChanged(const std::string &value); void _sliderChanged(double value); void _sliderChangedIntermediate(double value); signals: void ValueChanged(double value); void ValueChangedInt(int value); void ValueChangedIntermediate(double value); void ValueChangedIntIntermediate(int value); }; ================================================ FILE: apps/vaporgui/VSliderEditInterface.cpp ================================================ #include #include #include #include "vapor/VAssert.h" #include "VSliderEditInterface.h" #include "VSlider.h" #include "VActions.h" VSliderEditInterface::VSliderEditInterface() : VHBoxWidget() { _slider = new VSlider(); _slider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); layout()->addWidget(_slider); setContextMenuPolicy(Qt::CustomContextMenu); connect(this, &VSliderEditInterface::customContextMenuRequested, this, &VSliderEditInterface::ShowContextMenu); } QSize VSliderEditInterface::sizeHint() const { QWidget *parent = this->parentWidget(); return QSize(parent->width() * 3 / 5., 20); } ================================================ FILE: apps/vaporgui/VSliderEditInterface.h ================================================ #pragma once #include #include "VHBoxWidget.h" class VSlider; class VCheckBoxAction; class VSpinBoxAction; //! \class VSliderEditInterface //! \ingroup Public_GUI //! \brief An interface class that needs to be reimplemented to support the //! synchronization of a VSlider and a numeric V*LineEdit, and their menus. class VSliderEditInterface : public VHBoxWidget { Q_OBJECT public slots: //! Emit signal when dynamic update checkbox is toggled virtual void SetDynamicUpdate(bool enabled) = 0; //! Set use of scientific notation on the current type of line edit virtual void SetSciNotation(bool sci) = 0; //! Set the number of digits shown on the current line edit virtual void SetNumDigits(int digits) = 0; //! Show the context menu for the slider-edit, triggered on right-click virtual void ShowContextMenu(const QPoint &) = 0; public: //! Retrieve whether dynamic updates are toggled virtual void AllowDynamicUpdate() const = 0; //! Retrieve whether the currnet line edit is using scientific notation virtual bool GetSciNotation() const = 0; //! Get the number of digits in use by the current line edit virtual int GetNumDigits() const = 0; //! Return the size-hint for the current slider-edit virtual QSize sizeHint() const; protected: VSliderEditInterface(); virtual void _makeContextMenu() = 0; VSlider * _slider; signals: void FormatChanged(); }; ================================================ FILE: apps/vaporgui/VStringLineEdit.cpp ================================================ #include #include #include #include #include #include VStringLineEdit::VStringLineEdit(std::string value) : VHBoxWidget(), _lineEdit(new QLineEdit), _strValue(value) { layout()->addWidget(_lineEdit); _lineEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); connect(_lineEdit, SIGNAL(editingFinished()), this, SLOT(_valueChanged())); _lineEdit->setContextMenuPolicy(Qt::DefaultContextMenu); _lineEdit->setText(QString::fromStdString(value)); _lineEdit->setToolTip(QString::fromStdString(value)); } void VStringLineEdit::SetValueString(std::string value) { _strValue = value; _lineEdit->setText(QString::fromStdString(_strValue)); if (_autoTooltip) _lineEdit->setToolTip(QString::fromStdString(_strValue)); _lineEdit->setCursorPosition(0); } std::string VStringLineEdit::GetValueString() const { return _strValue; } void VStringLineEdit::RemoveContextMenu() { _lineEdit->setContextMenuPolicy(Qt::NoContextMenu); setContextMenuPolicy(Qt::NoContextMenu); } void VStringLineEdit::SetCustomContextMenu() { _lineEdit->setContextMenuPolicy(Qt::CustomContextMenu); setContextMenuPolicy(Qt::CustomContextMenu); connect(_lineEdit, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(_showMenu(const QPoint &))); } void VStringLineEdit::SetAutoTooltip(bool on) { _autoTooltip = on; if (on) _lineEdit->setToolTip(_lineEdit->text()); else _lineEdit->setToolTip(""); } void VStringLineEdit::_valueChanged() { std::string value = _lineEdit->text().toStdString(); if (value != _strValue) { _strValue = value; emit ValueChanged(_strValue); } } std::string VStringLineEdit::_getText() const { std::string value = _lineEdit->text().toStdString(); return value; } ================================================ FILE: apps/vaporgui/VStringLineEdit.h ================================================ #pragma once #include #include #include #include #include #include "VHBoxWidget.h" class QStringLineEdit; //! \class VStringLineEdit //! \ingroup Public_GUI //! \brief A wrapper for a QLineEdit that handles user input of type string, //! and provides Vapor's standard setters, getters, and signals class VStringLineEdit : public VHBoxWidget { Q_OBJECT public: VStringLineEdit(std::string value = ""); //! Set the current string value in the line edit void SetValueString(std::string value); //! Get the current value in the line edit std::string GetValueString() const; //! Remove the current context menu void RemoveContextMenu(); //! Create a custom context menu for the QLineEdit void SetCustomContextMenu(); void SetReadOnly(bool b) { _lineEdit->setReadOnly(b); } void Clear() { SetValueString(""); } void SetAutoTooltip(bool on); private: QLineEdit * _lineEdit; std::string _strValue; bool _autoTooltip = true; protected: std::string _getText() const; protected slots: virtual void _valueChanged(); signals: void ValueChanged(const std::string &value); }; ================================================ FILE: apps/vaporgui/VVisibilityCheckbox.cpp ================================================ #include "VVisibilityCheckbox.h" #include #include #include "mac_helpers.h" VVisibilityCheckbox::VVisibilityCheckbox() { _isWhite = true; setBlack(); } void VVisibilityCheckbox::paintEvent(QPaintEvent *e) { #ifdef __APPLE__ if (MacIsDarkMode()) setWhite(); else setBlack(); #endif VCheckBox::paintEvent(e); } void VVisibilityCheckbox::setColor(std::string color) { string eye = Wasp::GetSharePath("images/eye"); if (eye.empty()) return; setStyleSheet(QString( R"VV( QCheckBox::indicator:checked { image: url(%1); } QCheckBox::indicator:unchecked { image: url(%2); } )VV") .arg(QString::fromStdString(eye + "/eye_on_" + color + ".png")) .arg(QString::fromStdString(eye + "/eye_off_" + color + ".png")) ); } void VVisibilityCheckbox::setBlack() { if (_isWhite) { _isWhite = false; setColor("black"); } } void VVisibilityCheckbox::setWhite() { if (!_isWhite) { _isWhite = true; setColor("white"); } } ================================================ FILE: apps/vaporgui/VVisibilityCheckbox.h ================================================ #pragma once #include "VCheckBox.h" class VVisibilityCheckbox : public VCheckBox { bool _isWhite; public: VVisibilityCheckbox(); protected: void paintEvent(QPaintEvent *e) override; private: void setColor(std::string color); void setBlack(); void setWhite(); }; ================================================ FILE: apps/vaporgui/VaporFwd.h ================================================ #pragma once namespace VAPoR { class ParamsMgr; class DataMgr; class ControlExec; class ParamsBase; class RenderParams; class ViewpointParams; } using namespace VAPoR; class GUIStateParams; class AnimationParams; ================================================ FILE: apps/vaporgui/VaporTable.cpp ================================================ //************************************************************************* // * // Copyright (C) 2017 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: VaporTable.cpp // // Author: Scott Pearse // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: December 2017 // #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include "VaporTable.h" namespace { QString selectionColor = "{color: white; background-color: blue}"; QString normalColor = "{ color: black; background: white; }"; } // namespace VaporTable::VaporTable(QTableWidget *table, bool lastRowIsCheckboxes, bool lastColIsCheckboxes) { _table = table; _lastRowIsCheckboxes = lastRowIsCheckboxes; _lastColIsCheckboxes = lastColIsCheckboxes; _checkboxesEnabled = true; _activeRow = -1; _stretchColumn = -1; _hideColumn = -1; _autoResizeHeight = false; _showToolTips = false; SetVerticalHeaderWidth(100); _table->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); connect(_table, &QTableWidget::cellClicked, this, &VaporTable::emitCellClicked); connect(_table, &QTableWidget::cellChanged, this, &VaporTable::emitValueChanged); } // Clear current table, then generate table of rows x columns // Determine if checkboxes are needed // Convert values, rowHeaders, and colHeaders to QStrings, then populate void VaporTable::Update(int rows, int cols, std::vector values, std::vector rowHeaders, std::vector colHeaders) { std::vector sValues = convertToString(values); Update(rows, cols, sValues, rowHeaders, colHeaders); resizeTableHeight(); } void VaporTable::Update(int rows, int cols, std::vector values, std::vector rowHeaders, std::vector colHeaders) { std::vector sValues = convertToString(values); Update(rows, cols, sValues, rowHeaders, colHeaders); resizeTableHeight(); } void VaporTable::Update(int rows, int cols, std::vector values, std::vector rowHeaders, std::vector colHeaders) { _table->blockSignals(true); _table->clearContents(); _table->setRowCount(rows); _table->setColumnCount(cols); setTableCells(values); setVerticalHeader(rowHeaders); setHorizontalHeader(colHeaders); addCheckboxes(values); if ((rows < 1) || (cols < 1)) { _activeRow = -1; } if (_activeRow >= rows) { _activeRow = rows - 1; } if (_highlightFlags & ROWS) highlightActiveRow(_activeRow); resizeTableHeight(); if (_mutabilityFlags & IMMUTABLE) { _correctImmutableCellText(); } _table->blockSignals(false); } void VaporTable::SetVerticalHeaderWidth(int width) { _table->verticalHeader()->setMaximumWidth(width); } void VaporTable::SetAutoResizeHeight(bool val) { _autoResizeHeight = val; } bool VaporTable::GetAutoResizeHeight() const { return _autoResizeHeight; } void VaporTable::StretchToColumn(int column) { _stretchColumn = column; } void VaporTable::HideColumn(int column) { _hideColumn = column; } void VaporTable::ShowToolTips(bool showOrHide) { _showToolTips = showOrHide; } bool VaporTable::GetShowToolTips() const { return _showToolTips; } void VaporTable::resizeTableHeight() { if (!_autoResizeHeight) return; int height = _table->horizontalHeader()->height(); int rows = _table->rowCount(); _table->setMaximumHeight(height * rows * 3); } void VaporTable::Reinit(VaporTable::ValidatorFlags vFlags, VaporTable::MutabilityFlags mFlags, VaporTable::HighlightFlags hFlags) { _validatorFlags = vFlags; _mutabilityFlags = mFlags; _highlightFlags = hFlags; } std::vector VaporTable::convertToString(std::vector values) { std::vector sValues; int size = values.size(); for (int i = 0; i < size; i++) { std::stringstream ss; ss << values[i]; std::string s = ss.str(); sValues.push_back(s); } return sValues; } std::vector VaporTable::convertToString(std::vector values) { std::vector sValues; int size = values.size(); for (int i = 0; i < size; i++) { std::stringstream ss; ss << values[i]; std::string s = ss.str(); sValues.push_back(s); } return sValues; } void VaporTable::setTableCells(std::vector values) { int cols = _table->columnCount(); int rows = _table->rowCount(); for (int i = 0; i < cols; i++) { for (int j = 0; j < rows; j++) { int index = i + (cols)*j; std::string value = values[index]; QString qVal = QString::fromStdString(value); // If the cell has a checkbox, // don't write the string value into the cell if (_lastColIsCheckboxes && i == _table->columnCount() - 1) { qVal = ""; } QTableWidgetItem *item = new QTableWidgetItem(qVal); if (_mutabilityFlags & IMMUTABLE) { item->setFlags(Qt::ItemIsEditable); // turns off user-editability } if (_showToolTips) item->setToolTip(qVal); _table->setItem(j, i, item); } } } void VaporTable::addCheckboxes(std::vector values) { int cols = _table->columnCount(); int rows = _table->rowCount(); if (_lastColIsCheckboxes) { for (int j = 0; j < rows; j++) { int index = j * cols + (cols - 1); bool checked = isValueChecked(values, index); addCheckbox(j, cols - 1, checked); } } if (_lastRowIsCheckboxes) { for (int i = 0; i < cols; i++) { int index = (rows - 1) * (cols - 1) + i; bool checked = isValueChecked(values, index); addCheckbox(rows - 1, i, checked); } } } bool VaporTable::isValueChecked(std::vector values, int index) { std::string value = values[index]; std::stringstream ss; ss << value; bool checked = false; if (atoi(ss.str().c_str())) checked = true; return checked; } void VaporTable::addCheckbox(int row, int column, bool checked) { _table->removeCellWidget(row, column); QWidget * cbWidget = new QWidget(); QCheckBox * checkBox = new QCheckBox(); QHBoxLayout *cbLayout = new QHBoxLayout(cbWidget); cbLayout->addWidget(checkBox); cbLayout->setAlignment(Qt::AlignCenter); cbLayout->setContentsMargins(0, 0, 0, 0); cbWidget->setLayout(cbLayout); _table->setCellWidget(row, column, cbWidget); if (checked) { checkBox->setCheckState(Qt::Checked); } else { checkBox->setCheckState(Qt::Unchecked); } // The chekbox and the widget can both be clicked, // so I've given both objects row and column // properties to relay if needed checkBox->setProperty("row", row); checkBox->setProperty("col", column); cbWidget->setProperty("row", row); cbWidget->setProperty("col", column); checkBox->setEnabled(_checkboxesEnabled); connect(checkBox, SIGNAL(stateChanged(int)), this, SLOT(emitValueChanged())); } void VaporTable::emitValueChanged(int row, int col) { QCheckBox *item = qobject_cast(QObject::sender()); if (item != nullptr) { row = item->property("row").toInt(); col = item->property("col").toInt(); } _activeRow = row; if (_highlightFlags & ROWS) highlightActiveRow(_activeRow); emit valueChanged(row, col); } void VaporTable::emitReturnPressed() { emit returnPressed(); } void VaporTable::emitCellClicked(int row, int col) { _activeRow = row; if (_highlightFlags & ROWS) { highlightActiveRow(_activeRow); } emit cellClicked(row, col); } void VaporTable::setValidator(QLineEdit *edit) { if (_validatorFlags & INT) { edit->setValidator(new QIntValidator(edit)); } if (_validatorFlags & DOUBLE) { edit->setValidator(new QDoubleValidator(edit)); } if (_validatorFlags & STRING) { QRegExpValidator *validator; validator = new QRegExpValidator(QRegExp(".{1,64}")); edit->setValidator(validator); } } void VaporTable::setHorizontalHeader(std::vector header) { QHeaderView *headerView = _table->horizontalHeader(); if (_stretchColumn != -1) { _table->horizontalScrollBar()->setEnabled(false); _table->resizeColumnsToContents(); headerView->setSectionResizeMode(_stretchColumn, QHeaderView::Stretch); } else { headerView->setSectionResizeMode(1, QHeaderView::Stretch); } if (_hideColumn != -1) _table->hideColumn(_hideColumn); int size = header.size(); if (size < 1) { _table->horizontalHeader()->hide(); return; } QStringList list; for (int i = 0; i < size; i++) { list << QString::fromStdString(header[i]); } _table->setHorizontalHeaderLabels(list); QTableWidgetItem *headerItem; for (int i = 0; i < size; i++) { headerItem = _table->horizontalHeaderItem(i); if (headerItem) headerItem->setToolTip(list[i]); } } std::string VaporTable::GetHorizontalHeaderItem(int index) { QString str = _table->horizontalHeaderItem(index)->text(); return str.toStdString(); } void VaporTable::setVerticalHeader(std::vector header) { int size = header.size(); if (size < 1) { _table->verticalHeader()->hide(); return; } else if (_table->verticalHeader()->isHidden()) { _table->verticalHeader()->show(); } QStringList list; for (int i = 0; i < size; i++) { list << QString::fromStdString(header[i]); } _table->setVerticalHeaderLabels(list); _table->resizeRowsToContents(); _table->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); QTableWidgetItem *headerItem; for (int i = 0; i < size; i++) { headerItem = _table->verticalHeaderItem(i); if (headerItem) headerItem->setToolTip(list[i]); } } std::string VaporTable::GetVerticalHeaderItem(int index) { QString str = _table->verticalHeaderItem(index)->text(); return str.toStdString(); } void VaporTable::SetCheckboxesInFinalRow(bool enabled) { _lastRowIsCheckboxes = enabled; } void VaporTable::SetCheckboxesInFinalColumn(bool enabled) { _lastColIsCheckboxes = enabled; } void VaporTable::EnableDisableCheckboxes(bool enabled) { if (!_lastRowIsCheckboxes && !_lastColIsCheckboxes) { return; } _checkboxesEnabled = enabled; } Value VaporTable::GetValue(int row, int col) { std::string value; int nRows = _table->rowCount(); int nCols = _table->columnCount(); QWidget *widget = _table->cellWidget(row, col); if ((col == nCols - 1 && _lastColIsCheckboxes) || (row == nRows - 1 && _lastRowIsCheckboxes)) { QCheckBox *checkBox = widget->findChild(); if (checkBox->isChecked()) value = "1"; else value = "0"; } else { QString qvalue = _table->item(row, col)->text(); value = qvalue.toStdString(); } return {value}; } std::string VaporTable::GetStringValue(int row, int col) { std::string value; int nRows = _table->rowCount(); int nCols = _table->columnCount(); if (row >= nRows || col >= nCols) return ""; if ((col == nCols - 1 && _lastColIsCheckboxes) || (row == nRows - 1 && _lastRowIsCheckboxes)) { QCheckBox *checkBox = _table->cellWidget(row, col)->findChild(); if (checkBox->isChecked()) value = "1"; else value = "0"; } else { QString qvalue = _table->item(row, col)->text(); value = qvalue.toStdString(); } return value; } void VaporTable::GetValues(std::vector &vec) { vec.clear(); int nRows = _table->rowCount(); int nCols = _table->columnCount(); for (int i = 0; i < nRows; i++) { for (int j = 0; j < nCols; j++) { std::string cellVal = GetValue(i, j); vec.push_back(cellVal); } } } void VaporTable::GetValues(std::vector &vec) { vec.clear(); int nRows = _table->rowCount(); int nCols = _table->columnCount(); for (int i = 0; i < nRows; i++) { for (int j = 0; j < nCols; j++) { int cellVal = GetValue(i, j); vec.push_back(cellVal); } } } void VaporTable::GetValues(std::vector &vec) { vec.clear(); int nRows = _table->rowCount(); int nCols = _table->columnCount(); for (int i = 0; i < nRows; i++) { for (int j = 0; j < nCols; j++) { double cellVal = GetValue(i, j); vec.push_back(cellVal); } } } void VaporTable::_correctImmutableCellText() { _table->blockSignals(true); for (int i = 0; i < _table->rowCount(); i++) { if ((i == _activeRow) && (_highlightFlags == ROWS)) { continue; } for (int j = 0; j < _table->columnCount(); j++) { QBrush b(QColor("black")); QBrush w(QColor("white")); _table->item(i, j)->setForeground(b); _table->item(i, j)->setBackground(w); } } _table->blockSignals(false); } void VaporTable::highlightActiveRow(int row) { if (row < 0) return; _table->blockSignals(true); for (int i = 0; i < _table->rowCount(); i++) { for (int j = 0; j < _table->columnCount(); j++) { if (i == row) { QBrush b(QColor("blue")); QBrush w(QColor("white")); _table->item(i, j)->setForeground(w); _table->item(i, j)->setBackground(b); } else { QBrush b(QColor("black")); QBrush w(QColor("white")); _table->item(i, j)->setForeground(b); _table->item(i, j)->setBackground(w); } } } _table->blockSignals(false); } int VaporTable::GetActiveRow() const { return _activeRow; } void VaporTable::SetActiveRow(int row) { _activeRow = row; } ================================================ FILE: apps/vaporgui/VaporTable.h ================================================ #ifndef VAPORTABLE_H #define VAPORTABLE_H #include #include #include #include struct Value; // class VaporTable // class VaporTable : public QWidget { Q_OBJECT public: enum HighlightFlags { ROWS = (1u << 0), COLS = (1u << 1), }; enum MutabilityFlags { MUTABLE = (1u << 0), IMMUTABLE = (1u << 1), }; // The ValidatorTypeFlag will be used to apply validators // to the cells that are regenerated on each Update call. // // Can this be replaced with the template info in Update? // enum ValidatorFlags { INT = (1u << 0), DOUBLE = (1u << 1), STRING = (1u << 2), }; VaporTable(QTableWidget *table, bool lastRowIsCheckboxes = false, bool lastColIsCheckboxes = false); void Update(int rows, int columns, std::vector values, std::vector rowHeaders = std::vector(), std::vector colHeaders = std::vector()); void Update(int rows, int columns, std::vector values, std::vector rowHeaders = std::vector(), std::vector colHeaders = std::vector()); void Update(int rows, int columns, std::vector values, std::vector rowHeaders = std::vector(), std::vector colHeaders = std::vector()); void Reinit(ValidatorFlags vFlags, MutabilityFlags mFlags, HighlightFlags hFlags); Value GetValue(int row, int col); std::string GetStringValue(int row, int col); // Dump all values in the table back to the user void GetValues(std::vector &vec); void GetValues(std::vector &vec); void GetValues(std::vector &vec); std::string GetVerticalHeaderItem(int index); std::string GetHorizontalHeaderItem(int index); void SetCheckboxesInFinalColumn(bool enabled); void SetCheckboxesInFinalRow(bool enabled); void EnableDisableCheckboxes(bool enabled); // I think we may need something like this. TBD... void SetCellMutability(int row, int col); int RowCount() const { return _table->rowCount(); } int ColumnCount() const { return _table->columnCount(); } QWidget *CellWidget(int row, int col) { return _table->cellWidget(row, col); } int GetActiveRow() const; void SetActiveRow(int row); void SetAutoResizeHeight(bool val); bool GetAutoResizeHeight() const; void StretchToColumn(int column); void HideColumn(int column); void ShowToolTips(bool showOrHide); bool GetShowToolTips() const; void SetVerticalHeaderWidth(int width); public slots: void emitCellClicked(int, int); void emitValueChanged(int row = 0, int col = 0); void emitReturnPressed(); signals: void valueChanged(int row, int col); void cellClicked(int row, int col); void returnPressed(); private: std::vector convertToString(std::vector values); std::vector convertToString(std::vector values); void setHorizontalHeader(std::vector header); void setVerticalHeader(std::vector header); void setValidator(QLineEdit *edit); void setTableCells(std::vector values); void addCheckboxes(std::vector values); void addCheckbox(int row, int column, bool checked = false); bool isValueChecked(std::vector values, int index); void highlightActiveRow(int row); void resizeTableHeight(); void _correctImmutableCellText(); int _activeRow; int _stretchColumn; int _hideColumn; bool _lastRowIsCheckboxes; bool _lastColIsCheckboxes; bool _checkboxesEnabled; bool _autoResizeHeight; bool _showToolTips; QTableWidget *_table; MutabilityFlags _mutabilityFlags; ValidatorFlags _validatorFlags; HighlightFlags _highlightFlags; }; // A way to return a generic built-in type, so that the user can do: // int myVal = vaporTable->GetValue(0,0); // double myVal = vaporTable->GetValue(0,0); // std::string myVal = vaporTable->GetValue(0,0); struct Value { std::string _value; template operator T() const // implicitly convert into T { std::stringstream ss(_value); T convertedValue; if (ss >> convertedValue) return convertedValue; else throw std::runtime_error("conversion failed"); } }; #endif ================================================ FILE: apps/vaporgui/VaporTableGUI.ui ================================================ VaporTableGUI 0 0 410 100 0 0 0 100 16777215 113 Form 0 QLayout::SetDefaultConstraint 0 0 0 0 ================================================ FILE: apps/vaporgui/VaporWidgetsFwd.h ================================================ #pragma once class QDoubleValidator; class QComboBox; class QLineEdit; typedef QLineEdit VDoubleInput; typedef QLineEdit VIntegerInput; // Needs to allow changing contents without having to worry about blocking signals typedef QComboBox VDropdown; ================================================ FILE: apps/vaporgui/ViewpointToolbar.cpp ================================================ #include "ViewpointToolbar.h" #include #include "VizWinMgr.h" #include "PVisualizerSelector.h" #include #include #include "images/tiles.xpm" #include "images/home.xpm" #include "images/sethome.xpm" #include "images/eye.xpm" ViewpointToolbar::ViewpointToolbar(QWidget *parent, VAPoR::ControlExec *ce, VizWinMgr *vwm) : QToolBar(parent), _ce(ce), _vizWinMgr(vwm) { _visualizerSelector = new PVisualizerSelector(); addWidget(_visualizerSelector); addAction(QPixmap(tiles), "Tile Windows", [this](){_vizWinMgr->FitSpace();}); addAction(QPixmap(home), "Go to Home View", [this](){NavigationUtils::UseHomeViewpoint(_ce);}); addAction(QPixmap(sethome), "Set Home View", [this](){NavigationUtils::SetHomeViewpoint(_ce);}); addAction(QPixmap(eye), "View All", [this](){NavigationUtils::ViewAll(_ce);}); auto alignViewCombo = new QComboBox(this); alignViewCombo->addItems({"Align View", "Nearest axis", "+ X", "+ Y", "+ Z", "- X", "- Y", "- Z (Default)"}); alignViewCombo->setToolTip("Rotate view to an axis-aligned viewpoint, centered on current rotation center."); QObject::connect(alignViewCombo, QOverload::of(&QComboBox::activated), this, [this](int i){ NavigationUtils::AlignView(_ce, i); sender()->blockSignals(true); ((QComboBox *)sender())->setCurrentIndex(0); sender()->blockSignals(false); }); addWidget(alignViewCombo); } void ViewpointToolbar::Update() { _visualizerSelector->Update(_ce->GetParams(), _ce->GetParamsMgr()); } ================================================ FILE: apps/vaporgui/ViewpointToolbar.h ================================================ #pragma once #include #include #include "Updatable.h" class VizWinMgr; class PVisualizerSelector; class ViewpointToolbar : public QToolBar, public Updatable { Q_OBJECT ControlExec * const _ce; VizWinMgr * const _vizWinMgr; PVisualizerSelector *_visualizerSelector; public: ViewpointToolbar(QWidget *parent, ControlExec *ce, VizWinMgr *vwm); void Update() override; }; ================================================ FILE: apps/vaporgui/VizWin.cpp ================================================ //************************************************************************ // * // Copyright (C) 2013 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // File: VizWin.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: October 2013 // // Description: Implements the VizWin class // This is the QGLWidget that performs OpenGL rendering (using associated // Visualizer). // // Supports mouse event reporting. // #include // Must be included first!!! #include "vapor/VAssert.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "qdatetime.h" #include "ErrorReporter.h" #include "RenderEventRouterGUI.h" #include "FlowEventRouter.h" #include "images/vapor-icon-32.xpm" #include "VizWin.h" #include "Core3_2_context.h" #include #include "vapor/GLManager.h" #include "vapor/LegacyGL.h" #include "vapor/FontManager.h" #include "vapor/FileUtils.h" #include "vapor/Visualizer.h" #include #include #include #define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH #include #include "hide_std_error_util.h" using namespace VAPoR; #define ORIGIN_TIC_WIDTH .03 /* * Constructs a VizWindow as a child of 'parent', with the * name 'name' and widget flags set to 'f'. * */ VizWin::VizWin(const QGLFormat &format, QWidget *parent, const QString &name, string winName, ControlExec *ce, Trackball *trackBall) : QGLWidget(new Core3_2_context(format), parent) { _trackBall = trackBall; setAttribute(Qt::WA_DeleteOnClose); _winName = winName; setWindowIcon(QPixmap(vapor_icon___)); _controlExec = ce; _glManager = nullptr; _manip = nullptr; setAutoBufferSwap(false); _mouseClicked = false; _buttonNum = 0; _navigateFlag = false; _manipFlag = false; _openGLInitFlag = false; setMouseTracking(false); // Only track mouse when button clicked/held } VizWin::~VizWin() { // Sometimes when closing the application this will crash as the OpenGL context is // destroyed prior to the destructor being called. // Qt specifically states you are supposed to call ::makeCurrent() in the destructor. // https://doc.qt.io/qt-6/qopenglwidget.html#resource-initialization-and-cleanup // TODO Migrate to QOpenGLWidget this->makeCurrent(); delete _glManager; } // First project all 8 box corners to the center line of the camera // view, finding the furthest and nearest projection in front of the // camera. The furthest distance is used as the far distance. // If some point projects behind the camera, then either the // camera is inside the box, or a corner of the // box is behind the camera. This calculation is always performed in // local coordinates since a translation won't affect // the result // void VizWin::_getNearFarDist(const double posVec[3], const double dirVec[3], double &boxNear, double &boxFar) const { // First check full box double wrk[3], cor[3], boxcor[3]; double camPosBox[3], dvdir[3]; #ifdef WIN32 double maxProj = -DBL_MAX; double minProj = DBL_MAX; #else double maxProj = -std::numeric_limits::max(); double minProj = std::numeric_limits::max(); #endif DataStatus *dataStatus = _controlExec->GetDataStatus(); ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); AnimationParams *p = (AnimationParams *)paramsMgr->GetParams(AnimationParams::GetClassType()); size_t ts = p->GetCurrentTimestep(); VAPoR::CoordType minExts, maxExts; dataStatus->GetActiveExtents(paramsMgr, _winName, ts, minExts, maxExts); for (int i = 0; i < 3; i++) camPosBox[i] = posVec[i]; for (int i = 0; i < 3; i++) dvdir[i] = dirVec[i]; vnormal(dvdir); // For each box corner, // convert to box coords, then project to line of view for (int i = 0; i < 8; i++) { for (int j = 0; j < 3; j++) { cor[j] = ((i >> j) & 1) ? maxExts[j] : minExts[j]; } for (int k = 0; k < 3; k++) boxcor[k] = cor[k]; vsub(boxcor, camPosBox, wrk); float mdist = abs(vdot(wrk, dvdir)); if (minProj > mdist) { minProj = mdist; } if (maxProj < mdist) { maxProj = mdist; } } if (maxProj < 1.e-10) maxProj = 1.e-10; if (minProj > 0.03 * maxProj) minProj = 0.03 * maxProj; // minProj will be < 0 if either the camera is in the box, or // if some of the region is behind the camera plane. In that case, just // set the nearDist a reasonable multiple of the fardist // if (minProj <= 0.0) minProj = 0.0002 * maxProj; boxFar = (float)maxProj; boxNear = (float)minProj; return; } void VizWin::_setUpProjMatrix() { ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName); MatrixManager * mm = _glManager->matrixManager; double m[16]; vParams->GetModelViewMatrix(m); double posvec[3], upvec[3], dirvec[3]; bool status = vParams->ReconstructCamera(m, posvec, upvec, dirvec); if (!status) { MSG_ERR("Failed to get camera parameters"); return; } double nearDist, farDist; _getNearFarDist(posvec, dirvec, nearDist, farDist); nearDist *= 0.25; farDist *= 4.0; size_t width, height; vParams->GetWindowSize(width, height); width *= this->devicePixelRatioF(); height *= this->devicePixelRatioF(); int wWidth = width; int wHeight = height; if (vParams->GetValueLong(ViewpointParams::UseCustomFramebufferTag, 0)) { width = vParams->GetValueLong(ViewpointParams::CustomFramebufferWidthTag, 0); height = vParams->GetValueLong(ViewpointParams::CustomFramebufferHeightTag, 0); if (width == 0) width = 1; if (height == 0) height = 1; int maxSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize); if (width > maxSize) { width = maxSize; vParams->SetValueLong(ViewpointParams::CustomFramebufferWidthTag, ViewpointParams::CustomFramebufferWidthTag, width); MSG_ERR("Selected width is larger than your OpenGL implementation supports"); } if (height > maxSize) { height = maxSize; vParams->SetValueLong(ViewpointParams::CustomFramebufferHeightTag, ViewpointParams::CustomFramebufferHeightTag, height); MSG_ERR("Selected height is larger than your OpenGL implementation supports"); } float fa = width / (float)height; float wa = wWidth / (float)wHeight; if (fa >= wa) { int x = 0; int y = (wHeight / 2) - (wHeight / fa * wa / 2); int w = wWidth; int h = wHeight / fa * wa; glViewport(x, y, w, h); } else { int x = (wWidth / 2) - (wWidth * fa / wa / 2); int y = 0; int w = wWidth * fa / wa; int h = wHeight; glViewport(x, y, w, h); } } else { glViewport(0, 0, width, height); } mm->MatrixModeProjection(); mm->LoadIdentity(); GLfloat w = (float)width / (float)height; if (vParams->GetProjectionType() == ViewpointParams::MapOrthographic) { float s = _trackBall->GetOrthoSize(); mm->Ortho(-s * w, s * w, -s, s, nearDist, farDist); } else { double fov = vParams->GetFOV(); mm->Perspective(glm::radians(fov), w, nearDist, farDist); } double pMatrix[16]; mm->GetDoublev(MatrixManager::Mode::Projection, pMatrix); bool enabled = _controlExec->GetSaveStateEnabled(); _controlExec->SetSaveStateEnabled(false); vParams->SetProjectionMatrix(pMatrix); if (vParams->GetProjectionType() == ViewpointParams::MapOrthographic) vParams->SetOrthoProjectionSize(_trackBall->GetOrthoSize()); _controlExec->SetSaveStateEnabled(enabled); mm->MatrixModeModelView(); } void VizWin::_setUpModelViewMatrix() { makeCurrent(); // necessary? ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName); double m[16]; vParams->GetModelViewMatrix(m); _glManager->matrixManager->LoadMatrixd(m); } // React to a user-change in window size/position (or possibly max/min) // Either the window is minimized, maximized, restored, or just resized. // void VizWin::resizeGL(int width, int height) { _resizeGL(width, height); if (paintOnResize) Render(true); } void VizWin::_resizeGL(int width, int height) { if (!_openGLInitFlag || !FrameBufferReady()) { return; } int rc = CheckGLErrorMsg("GLVizWindowResizeEvent"); if (rc < 0) { MSG_ERR("OpenGL error"); } rc = _controlExec->ResizeViz(_winName, width, height); if (rc < 0) { MSG_ERR("OpenGL error"); } glViewport(0, 0, (GLint)width, (GLint)height); ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName); // Window size can't be undone, so disable state saving // bool enabled = _controlExec->GetSaveStateEnabled(); _controlExec->SetSaveStateEnabled(false); vParams->SetWindowSize(width, height); _controlExec->SetSaveStateEnabled(enabled); } void VizWin::initializeGL() { bool ok = gladLoaderLoadGL(); VAssert(GLManager::CheckError()); if (!ok) { MyBase::SetErrMsg("Error: Unable to initialize GLAD"); MSG_ERR("OpenGL Error"); } _glManager = new GLManager; _manip = new TranslateStretchManip(_glManager); bool initialize = true; updateManip(initialize); CheckGLErrorMsg("GLVizWindowInitializeEvent"); int rc = _controlExec->InitializeViz(_winName, _glManager); if (rc < 0) { MSG_FATAL("Failure to initialize Visualizer"); return; } _glManager->legacy->Initialize(); CheckGLErrorMsg("GLVizWindowInitializeEvent"); ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName); if (vParams != NULL) { bool enabled = _controlExec->GetSaveStateEnabled(); _controlExec->SetSaveStateEnabled(false); vParams->SetWindowSize(width(), height()); _controlExec->SetSaveStateEnabled(enabled); } _openGLInitFlag = true; } void VizWin::paintGL() { if (_swapBufferQueued) { swapBuffers(); _swapBufferQueued = false; } } void VizWin::safeSwapBuffers() { if (windowHandle()->isExposed()) swapBuffers(); else _swapBufferQueued = true; } void VizWin::_mousePressEventManip(QMouseEvent *e) { makeCurrent(); std::vector screenCoords = _getScreenCoords(e); screenCoords[0] *= this->devicePixelRatioF(); screenCoords[1] *= this->devicePixelRatioF(); _manipFlag = _manip->MouseEvent(_buttonNum, screenCoords, _strHandleMid); } void VizWin::_mousePressEventNavigate(QMouseEvent *e) { _navigateFlag = true; ParamsMgr *paramsMgr = _controlExec->GetParamsMgr(); double m[16]; ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName); vParams->GetModelViewMatrix(m); double center[3]; vParams->GetRotationCenter(center); double posvec[3], upvec[3], dirvec[3]; bool status = vParams->ReconstructCamera(m, posvec, upvec, dirvec); VAssert(status); _trackBall->setFromFrame(posvec, dirvec, upvec, center, true); int trackballButtonNumber = _buttonNum; if (vParams->GetProjectionType() == ViewpointParams::MapOrthographic && _buttonNum == 1) trackballButtonNumber = 2; _trackBall->MouseOnTrackball(0, trackballButtonNumber, e->x(), e->y(), width(), height()); _navigationPendingChanges = false; } void VizWin::mousePressEvent(QMouseEvent *e) { if (_mouseClicked) return; _buttonNum = 0; _mouseClicked = true; if ((e->buttons() & Qt::LeftButton) && (e->buttons() & Qt::RightButton)) ; // do nothing else if (e->button() == Qt::LeftButton) _buttonNum = 1; else if (e->button() == Qt::RightButton) _buttonNum = 3; else if (e->button() == Qt::MiddleButton) _buttonNum = 2; // ControlModifier means [command], not [control] apparently if (e->button() == Qt::LeftButton && (e->modifiers() & Qt::ShiftModifier)) { _buttonNum = 2; } if (_buttonNum == 0) { _mouseClicked = true; // mouse button is held return; } string modeName = _getCurrentMouseMode(); if (modeName == MouseModeParams::GetRegionModeName()) { _mousePressEventManip(e); // Only manipulating if user managed to grab manipulator handle. // Otherwise we navigate // if (_manipFlag) { return; } } _mousePressEventNavigate(e); } void VizWin::_mouseReleaseEventManip(QMouseEvent *e) { if (!_manipFlag) return; std::vector screenCoords = _getScreenCoords(e); screenCoords[0] *= this->devicePixelRatioF(); screenCoords[1] *= this->devicePixelRatioF(); (void)_manip->MouseEvent(_buttonNum, screenCoords, _strHandleMid, true); _setNewExtents(); _manipFlag = false; } void VizWin::_mouseReleaseEventNavigate(QMouseEvent *e) { if (!_navigateFlag) return; _trackBall->MouseOnTrackball(2, _buttonNum, e->x(), e->y(), width(), height()); _trackBall->TrackballSetMatrix(); const double *m = _trackBall->GetModelViewMatrix(); ParamsMgr *paramsMgr = _controlExec->GetParamsMgr(); ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName); if (_navigationPendingChanges) { vParams->SetModelViewMatrix(m); paramsMgr->EndSaveStateGroup(); emit EndNavigation(_winName); } _navigationPendingChanges = false; _navigateFlag = false; } /* * If the user releases the mouse or moves it (with the left mouse down) * then we note the displacement */ void VizWin::mouseReleaseEvent(QMouseEvent *e) { if (_buttonNum == 0) { _mouseClicked = false; return; } _mouseClicked = false; if (_manipFlag) { _mouseReleaseEventManip(e); } else if (_navigateFlag) { _mouseReleaseEventNavigate(e); } _buttonNum = 0; } void VizWin::_mouseMoveEventManip(QMouseEvent *e) { if (!_manipFlag) return; std::vector screenCoords = _getScreenCoords(e); screenCoords[0] *= this->devicePixelRatioF(); screenCoords[1] *= this->devicePixelRatioF(); (void)_manip->MouseEvent(_buttonNum, screenCoords, _strHandleMid); _controlExec->GetParamsMgr()->IntermediateChange(); } void VizWin::_mouseMoveEventNavigate(QMouseEvent *e) { if (!_navigateFlag) return; // if (_getCurrentMouseMode() == MouseModeParams::GetGeoRefModeName() && _buttonNum == 1) // return; // _buttonNum is ignored in MouseOnTrackball here _trackBall->MouseOnTrackball(1, _buttonNum, e->x(), e->y(), width(), height()); _trackBall->TrackballSetMatrix(); const double *m = _trackBall->GetModelViewMatrix(); ParamsMgr *paramsMgr = _controlExec->GetParamsMgr(); // Set modelview matrix in ViewpointParams // ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName); if (!_navigationPendingChanges) paramsMgr->BeginSaveStateGroup("Navigate"); _navigationPendingChanges = true; vParams->SetModelViewMatrix(m); paramsMgr->IntermediateChange(); } std::vector VizWin::_getScreenCoords(QMouseEvent *e) const { std::vector screenCoords; screenCoords.push_back((double)e->x()); screenCoords.push_back((double)(height() - e->y())); return screenCoords; } string VizWin::_getCurrentMouseMode() const { ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); GUIStateParams *guiP = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType()); string activeTab = guiP->ActiveTab(); if (activeTab == RenderEventRouterGUI::GeometryTabName || activeTab == FlowEventRouter::SeedingTabName || activeTab == FlowEventRouter::IntegrationTabName) return MouseModeParams::GetRegionModeName(); else return MouseModeParams::GetNavigateModeName(); } void VizWin::_setNewExtents() { std::vector llc, urc; _manip->GetBox(llc, urc); VAPoR::RenderParams *rParams = _getRenderParams(); if (rParams == NULL) return; VAPoR::Box * box = rParams->GetBox(); std::vector pllc, purc; box->GetExtents(pllc, purc); if (_manipFlowSeedFlag) { FlowParams *fp = dynamic_cast(rParams); if (fp) { // Sam's box format: xmin, xmax, ymin, ymax, zmin, zmax int dims = fp->GetRenderDim(); if (dims == 3) { // 3D flow renderer vector b(6); b[0] = llc[0]; b[2] = llc[1]; b[4] = llc[2]; b[1] = urc[0]; b[3] = urc[1]; b[5] = urc[2]; fp->SetRake(b); } else if (dims == 2) { // 2D flow renderer vector b(4); b[0] = llc[0]; b[2] = llc[1]; b[1] = urc[0]; b[3] = urc[1]; fp->SetRake(b); } } } else if (_manipFlowIntegrationFlag) { FlowParams *fp = dynamic_cast(rParams); VAssert(fp); fp->GetIntegrationBox()->SetExtents(llc, urc); } else { box->SetExtents(llc, urc); } } /* * When the mouse is moved, it can affect navigation, * region position, light position, or probe position, depending * on current mode. The values associated with the window are * changed whether or not the tabbed panel is visible. * It's important that coordinate changes eventually get recorded in the * viewpoint params panel. This requires some work every time there is * mouse navigation. Changes in the viewpoint params panel will notify * the viztab if it is active and change the values there. * Conversely, when values are changed in the viztab, the viewpoint * values are set in the VizWin class, provided they did not originally * come from the mouse navigation. Such a change forces a reinitialization * of the trackball and the new values will be used at the next rendering. * */ void VizWin::mouseMoveEvent(QMouseEvent *e) { if (_buttonNum == 0) return; if (_manipFlag) { _mouseMoveEventManip(e); } else if (_navigateFlag) { _mouseMoveEventNavigate(e); } return; } void VizWin::setFocus() { QWidget::setFocus(); } void VizWin::Render(bool fast) { // Failsafe to prevent VizWin::Render from being called recursively. if (_insideRender) return; _insideRender = true; _renderHelper(fast); _insideRender = false; HideSTDERR(); safeSwapBuffers(); RestoreSTDERR(); } void VizWin::_renderHelper(bool fast) { // Need to call since we're not overriding QGLWidget::paintGL() // makeCurrent(); if (!_openGLInitFlag || !FrameBufferReady()) { return; } glClearColor(0.3, 0.3, 0.3, 1); glClear(GL_COLOR_BUFFER_BIT); ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName); bool enabled = _controlExec->GetSaveStateEnabled(); _controlExec->SetSaveStateEnabled(false); vParams->SetWindowSize(width(), height()); _controlExec->SetSaveStateEnabled(enabled); DataStatus *dataStatus = _controlExec->GetDataStatus(); if (!dataStatus->GetDataMgrNames().size()) return; _preRender(); int rc = _controlExec->Paint(_winName, fast); if (rc < 0) { MSG_ERR("Paint failed"); } if (_getCurrentMouseMode() == MouseModeParams::GetRegionModeName()) { updateManip(); if (_getRenderParams() && _getRenderParams()->GetOrientable()) { _updateOriginGlyph(); _drawContourSliceQuad(); } } else if (vParams->GetProjectionType() == ViewpointParams::MapOrthographic) { #ifndef WIN32 _glManager->PixelCoordinateSystemPush(); _glManager->matrixManager->Translate(10, 10, 0); glDisable(GL_DEPTH_TEST); _glManager->fontManager->GetFont("arimo", 22)->DrawText("Geo Referenced Mode"); _glManager->PixelCoordinateSystemPop(); #endif } rc = CheckGLErrorMsg("VizWindowPaintGL"); if (rc < 0) { MSG_ERR("OpenGL error"); } _postRender(); } void VizWin::_preRender() { _glManager->matrixManager->MatrixModeProjection(); _glManager->matrixManager->PushMatrix(); _setUpProjMatrix(); _glManager->matrixManager->MatrixModeModelView(); _glManager->matrixManager->PushMatrix(); _setUpModelViewMatrix(); } void VizWin::_postRender() { _glManager->matrixManager->MatrixModeProjection(); _glManager->matrixManager->PopMatrix(); _glManager->matrixManager->MatrixModeModelView(); _glManager->matrixManager->PopMatrix(); } VAPoR::RenderParams *VizWin::_getRenderParams() { string className; return _getRenderParams(className); } VAPoR::RenderParams *VizWin::_getRenderParams(string &className) { ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); GUIStateParams *guiP = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType()); string inst, winName, dataSetName; guiP->GetActiveRenderer(_winName, className, inst); bool exists = paramsMgr->RenderParamsLookup(inst, winName, dataSetName, className); if (!exists) return NULL; // VAPoR::RenderParams* rParams = _controlExec->GetRenderParams( // _winName, dataSetName, className, inst // ); VAPoR::RenderParams *rParams = paramsMgr->GetRenderParams(_winName, dataSetName, className, inst); return rParams; } string VizWin::_getCurrentDataMgrName() const { ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); GUIStateParams *guiP = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType()); string inst, winName, className, dataSetName; guiP->GetActiveRenderer(_winName, className, inst); bool exists = paramsMgr->RenderParamsLookup(inst, winName, dataSetName, className); if (!exists) return ""; return dataSetName; } void VizWin::_getUnionOfFieldVarExtents(RenderParams *rParams, DataMgr *dataMgr, int timeStep, int refLevel, int lod, CoordType &minExts, CoordType &maxExts) { vector fieldVars = rParams->GetFieldVariableNames(); vector axes; bool ok = DataMgrUtils::GetExtents(dataMgr, timeStep, fieldVars, refLevel, lod, minExts, maxExts, axes); VAssert(ok); } void VizWin::_getActiveExtents(CoordType &minExts, CoordType &maxExts) { VAPoR::RenderParams *rParams = _getRenderParams(); if (rParams == NULL) return; int refLevel = rParams->GetRefinementLevel(); int lod = rParams->GetCompressionLevel(); string varName = rParams->GetVariableName(); vector fieldVars = rParams->GetFieldVariableNames(); ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); AnimationParams *aParams = (AnimationParams *)paramsMgr->GetParams(AnimationParams::GetClassType()); int timeStep = aParams->GetCurrentTimestep(); DataStatus *dataStatus = _controlExec->GetDataStatus(); string dataMgrName = _getCurrentDataMgrName(); DataMgr * dataMgr = dataStatus->GetDataMgr(dataMgrName); if (fieldVars[0] == "" && fieldVars[1] == "" && fieldVars[2] == "") { dataMgr->GetVariableExtents(timeStep, varName, refLevel, lod, minExts, maxExts); } else { _getUnionOfFieldVarExtents(rParams, dataMgr, timeStep, refLevel, lod, minExts, maxExts); } } VAPoR::Transform *VizWin::_getDataMgrTransform() const { string dataMgrName = _getCurrentDataMgrName(); if (dataMgrName.empty()) return NULL; ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); ViewpointParams * vpParams = paramsMgr->GetViewpointParams(_winName); vector names = paramsMgr->GetDataMgrNames(); VAPoR::Transform *t = vpParams->GetTransform(dataMgrName); return t; } void VizWin::updateManip(bool initialize) { CoordType minExts = {0.0, 0.0, 0.0}; CoordType maxExts = {0.0, 0.0, 0.0}; _getActiveExtents(minExts, maxExts); CoordType llc, urc; string classType; VAPoR::RenderParams *rParams = _getRenderParams(classType); if (initialize || rParams == NULL) { llc = minExts; urc = maxExts; } else { _manipFlowSeedFlag = false; _manipFlowIntegrationFlag = false; GUIStateParams *gp = (GUIStateParams *)_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()); if (rParams->GetName() == FlowParams::GetClassType()) { if (gp->ActiveTab() == FlowEventRouter::SeedingTabName) _manipFlowSeedFlag = true; if (gp->ActiveTab() == FlowEventRouter::IntegrationTabName) _manipFlowIntegrationFlag = true; } if (_manipFlowSeedFlag) { FlowParams *fp = dynamic_cast(rParams); VAssert(fp); // Sam's box format: xmin, xmax, ymin, ymax, zmin, zmax // Why doesn't Sam's code use the standard box class? vector b = fp->GetRake(); // If the flow renderer is 2d, add z extents or the Manip will break if (b.size() == 4) { b.push_back(0); b.push_back(0); } llc[0] = b[0]; urc[0] = b[1]; llc[1] = b[2]; urc[1] = b[3]; llc[2] = b[4]; urc[2] = b[5]; } else if (_manipFlowIntegrationFlag) { FlowParams *fp = dynamic_cast(rParams); VAssert(fp); fp->GetIntegrationBox()->GetExtents(llc, urc); } else { VAPoR::Box *box = rParams->GetBox(); box->GetExtents(llc, urc); } } bool constrain = true; if (classType == ImageParams::GetClassType()) constrain = false; VAPoR::Transform *dmTransform = _getDataMgrTransform(); VAPoR::Transform *rpTransform = NULL; if (rParams != NULL) rpTransform = rParams->GetTransform(); vector llcVec = {llc[0], llc[1], llc[2]}; vector urcVec = {urc[0], urc[1], urc[2]}; vector minExtsVec = {minExts[0], minExts[1], minExts[2]}; vector maxExtsVec = {maxExts[0], maxExts[1], maxExts[2]}; if (rParams && rParams->GetRenderDim() == 2) { double defaultZ = DataMgrUtils::Get2DRendererDefaultZ(_controlExec->GetDataStatus()->GetDataMgr(_getCurrentDataMgrName()), rParams->GetCurrentTimestep(), rParams->GetRefinementLevel(), rParams->GetCompressionLevel()); llcVec[2] = defaultZ; urcVec[2] = defaultZ; minExtsVec[2] = defaultZ; maxExtsVec[2] = defaultZ; } _manip->Update(llcVec, urcVec, minExtsVec, maxExtsVec, rpTransform, dmTransform, constrain); if (!initialize) _manip->Render(); GL_ERR_BREAK(); } void VizWin::_updateOriginGlyph() { _glManager->matrixManager->PushMatrix(); Renderer::ApplyDatasetTransform(_glManager, _getDataMgrTransform()); Renderer::ApplyTransform(_glManager->matrixManager, _getDataMgrTransform(), _getRenderParams()->GetTransform()); VAPoR::RenderParams *rp = _getRenderParams(); double xOrigin = rp->GetValueDouble(RenderParams::XSlicePlaneOriginTag, 0.); double yOrigin = rp->GetValueDouble(RenderParams::YSlicePlaneOriginTag, 0.); double zOrigin = rp->GetValueDouble(RenderParams::ZSlicePlaneOriginTag, 0.); std::vector scales = _getDataMgrTransform()->GetScales(); std::vector scales2 = rp->GetTransform()->GetScales(); scales[0] *= scales2[0]; scales[1] *= scales2[1]; scales[2] *= scales2[2]; int refLevel = rp->GetRefinementLevel(); int lod = rp->GetCompressionLevel(); string varName = rp->GetVariableName(); vector fieldVars = rp->GetFieldVariableNames(); int timeStep = rp->GetCurrentTimestep(); DataStatus *dataStatus = _controlExec->GetDataStatus(); string dataMgrName = _getCurrentDataMgrName(); DataMgr * dataMgr = dataStatus->GetDataMgr(dataMgrName); CoordType min, max; dataMgr->GetVariableExtents(timeStep, varName, refLevel, lod, min, max); // Find the average magnitude of the X and Y axes. 3% of that magnitude will be the size of the // origin marker's crosshairs. double p = .03 * ((max[0] - min[0]) + (max[1] - min[1])) / 2; std::vector width = {p / scales[0], p / scales[1], p / scales[2]}; int depthFunc; glGetIntegerv(GL_DEPTH_FUNC, &depthFunc); glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); LegacyGL *lgl = _glManager->legacy; lgl->Color4f(1., 1., 0., 1.); lgl->Begin(GL_LINES); lgl->Vertex3f(xOrigin, yOrigin, zOrigin - width[2]); lgl->Vertex3f(xOrigin, yOrigin, zOrigin + width[2]); lgl->End(); lgl->Begin(GL_LINES); lgl->Vertex3f(xOrigin - width[0], yOrigin, zOrigin); lgl->Vertex3f(xOrigin + width[0], yOrigin, zOrigin); lgl->End(); lgl->Begin(GL_LINES); lgl->Vertex3f(xOrigin, yOrigin - width[1], zOrigin); lgl->Vertex3f(xOrigin, yOrigin + width[1], zOrigin); lgl->End(); glDepthFunc(depthFunc); _glManager->matrixManager->PopMatrix(); } void VizWin::_drawContourSliceQuad() { _glManager->matrixManager->PushMatrix(); Renderer::ApplyDatasetTransform(_glManager, _getDataMgrTransform()); Renderer::ApplyTransform(_glManager->matrixManager, _getDataMgrTransform(), _getRenderParams()->GetTransform()); auto quad = _getRenderParams()->GetSlicePlaneQuad(); LegacyGL *lgl = _glManager->legacy; lgl->Color3f(0, 1, 0); lgl->Begin(GL_LINE_STRIP); for (auto v : quad) lgl->Vertex3dv(v.data()); if (quad.size()) lgl->Vertex3dv(quad[0].data()); lgl->End(); _glManager->matrixManager->PopMatrix(); } ================================================ FILE: apps/vaporgui/VizWin.h ================================================ //************************************************************************ // * // Copyright (C) 2013 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: VizWin.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: October 2013 // // #ifndef VIZWIN_H #define VIZWIN_H #include #include #include "vapor/Transform.h" #include "Manip.h" #include class QCloseEvent; class QRect; class QMouseEvent; class QFocusEvent; class Visualizer; class Viewpoint; class Trackball; namespace VAPoR { class ControlExec; class Visualizer; struct GLManager; }; // namespace VAPoR //! \class VizWin //! \ingroup Public_GUI /*! \brief A QGLWidget that supports display based on GL methods invoked in a * Visualizer */ //! \author Alan Norton //! \version 3.0 //! \date October 2013 //! The VizWin class is a QGLWidget that supports the rendering by the VAPOR //! Visualizer class. //! The standard rendering methods (resize, initialize, paint) are passed to the //! Visualizer. //! In addition this is the class that responds to mouse events, resulting in //! scene navigation //! or manipulator changes. //! class VizWin : public QGLWidget { Q_OBJECT public: VizWin(const QGLFormat &format, QWidget *parent, const QString &name, string winName, VAPoR::ControlExec *ce, Trackball *trackBall); ~VizWin(); //! Identify the visualizer index //! \retval visualizer index. string getWindowName() { return _winName; } // Render the scene // // If \p fast is true try to render the scene quickly // void Render(bool fast); bool paintOnResize = true; signals: void EndNavigation(const string &winName); public slots: virtual void setFocus(); private: void _renderHelper(bool fast); void _preRender(); void _postRender(); void updateManip(bool initialize = false); void _updateOriginGlyph(); void _drawContourSliceQuad(); // Event handling // Virtual overrides: virtual void wheelEvent(QWheelEvent *e) { e->accept(); } // QWidget reimplementations virtual void mousePressEvent(QMouseEvent *); virtual void mouseReleaseEvent(QMouseEvent *); virtual void mouseMoveEvent(QMouseEvent *); virtual void _mousePressEventNavigate(QMouseEvent *); virtual void _mouseReleaseEventNavigate(QMouseEvent *); virtual void _mouseMoveEventNavigate(QMouseEvent *); virtual void _mousePressEventManip(QMouseEvent *); virtual void _mouseReleaseEventManip(QMouseEvent *); virtual void _mouseMoveEventManip(QMouseEvent *); // QGLWidget reimplementations virtual void resizeGL(int width, int height); void _resizeGL(int width, int height); virtual void initializeGL(); virtual void paintGL(); void safeSwapBuffers(); string _winName; VAPoR::ControlExec *_controlExec; VAPoR::GLManager * _glManager; double _strHandleMid[3]; bool _insideRender = false; bool _mouseClicked; // Indicates mouse has been clicked but not move int _buttonNum; // currently pressed button (0=none, 1=left,2=mid, 3=right) bool _navigateFlag; bool _manipFlag; bool _manipFlowSeedFlag = false; bool _manipFlowIntegrationFlag = false; Trackball *_trackBall; bool _navigationPendingChanges; std::vector _getScreenCoords(QMouseEvent *e) const; string _getCurrentMouseMode() const; void _setNewExtents(); void _getActiveExtents(VAPoR::CoordType &minExts, VAPoR::CoordType &maxExts); void _getUnionOfFieldVarExtents(VAPoR::RenderParams *rParams, VAPoR::DataMgr *dataMgr, int timestep, int refLevel, int lod, VAPoR::CoordType &minExts, VAPoR::CoordType &maxExts); string _getCurrentDataMgrName() const; VAPoR::Transform *_getDataMgrTransform() const; void _getNearFarDist(const double posVec[3], const double dirVec[3], double &boxNear, double &boxFar) const; VAPoR::RenderParams *_getRenderParams(); VAPoR::RenderParams *_getRenderParams(string &classType); void _setUpProjMatrix(); void _setUpModelViewMatrix(); VAPoR::TranslateStretchManip *_manip; bool _openGLInitFlag; bool _swapBufferQueued = false; friend class VizWinMgr; }; #endif // VIZWIN_H ================================================ FILE: apps/vaporgui/VizWinMgr.cpp ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: VizWinMgr.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: Sept 2004 // // Description: Implementation of VizWinMgr class // This class manages the VizWin visualizers // Its main function is to catch events from the visualizers and // to route them to the appropriate params class, and in reverse, // to route events from tab panels to the appropriate visualizer. // #ifdef WIN32 #pragma warning(disable : 4251 4100) #endif #include // Must be included first!!! #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include #include #include "QtVizWinGLContextManager.h" #include #include #include #include #include #include "VizWin.h" #include "VizWinMgr.h" #include "ErrorReporter.h" #include using namespace VAPoR; VizWinMgr::VizWinMgr(ControlExec *ce) : _controlExec(ce), visualizerGLContextManager(new QtVizWinGLContextManager(this)) { _mdiArea = this; _mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); _mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); _trackBall = new Trackball(); _initialized = false; } VizWinMgr::~VizWinMgr() { if (_trackBall) delete _trackBall; } class DisableFocusFilter: public QObject { protected: bool eventFilter(QObject* object, QEvent* event) { if(event->type() == QEvent::FocusIn) return true; return QObject::eventFilter(object, event); } }; // All other tested methods for user-interaction window activation also fire from programmatic events // - The original focus method had no way of truly distinguishing user actions. // Even when wrapping the operations in _safeMDIChange which disables focus signals, for some actions such as adding subwindows Qt will ignore this. // - MDI active signals are also indistinguishable and unblockable for certain operations. // Also, while QMDISubWindow and QMDIArea both have a "window activated" signal, they behave a little differently, both have the same issues though. // A potential solution would be to not have the active visualizer be a core part of the application state but this is currently deeply ingrained in the app. class UserFocusEventFilter: public QObject { function _callback; static QWidget *_focusedWidget; public: UserFocusEventFilter(const function &callback): _callback(callback) {} protected: bool eventFilter(QObject* object, QEvent* event) { if(event->type() == QEvent::FocusIn && ((QFocusEvent*)event)->reason() == Qt::MouseFocusReason) _callback(); return QObject::eventFilter(object, event); } }; void OnMDISubwindowUserFocus(QMdiSubWindow *w, const function &callback) { w->widget()->setFocusPolicy(Qt::ClickFocus); w->widget()->installEventFilter(new UserFocusEventFilter(callback)); w->installEventFilter(new UserFocusEventFilter(callback)); } class CancelCloseEventFilter: public QObject { function _callback; public: CancelCloseEventFilter(const function &callback): _callback(callback) {} protected: bool eventFilter(QObject* object, QEvent* event) { if(event->type() == QEvent::Close) { _callback(); event->ignore(); return true; } return QObject::eventFilter(object, event); } }; void VizWinMgr::_attachVisualizer(string vizName) { if (_vizWindow.find(vizName) != _vizWindow.end()) return; QString qvizname = QString::fromStdString(vizName); QGLFormat glFormat; glFormat.setVersion(4, 1); glFormat.setProfile(QGLFormat::CoreProfile); _vizWindow[vizName] = new VizWin(glFormat, this, qvizname, vizName, _controlExec, _trackBall); _vizWindow[vizName]->setWindowTitle(qvizname); // _vizWindow[vizName]->setAttribute(Qt::WA_ShowWithoutActivating); // Not honored in MDI view // Closing window will be handled by syncing with params _vizWindow[vizName]->installEventFilter(new CancelCloseEventFilter([this, vizName](){ if (_controlExec->GetNumVisualizers() == 1) return; _controlExec->GetParamsMgr()->RemoveVisualizer(vizName); })); connect(_vizWindow[vizName], SIGNAL(EndNavigation(const string &)), this, SLOT(_syncViewpoints(const string &))); _vizMdiWin[vizName] = _mdiArea->addSubWindow(_vizWindow[vizName]); OnMDISubwindowUserFocus(_vizMdiWin[vizName], [this, vizName](){ _setActiveViz(vizName); }); GUIStateParams *p = _controlExec->GetParams(); string prevActiveVizName = p->GetActiveVizName(); _safeMDIChange([&](){ _vizWindow[vizName]->showMaximized(); }); int numWins = _controlExec->GetNumVisualizers(); // Tile if more than one visualizer: if (numWins > 1) FitSpace(); // When we go from 1 to 2 windows, need to enable multiple // viz panels and signals. // if (numWins > 1) { emit enableMultiViz(true); _syncViewpoints(prevActiveVizName); } } void VizWinMgr::FitSpace() { _safeMDIChange([this](){ _mdiArea->tileSubWindows(); }); } void VizWinMgr::_setActiveViz(string vizName) { GUIStateParams *p = _controlExec->GetParams(); string currentVizName = p->GetActiveVizName(); if (currentVizName != vizName) { p->SetActiveVizName(vizName); emit(activateViz(QString::fromStdString(vizName))); if (vizName.empty()) return; // Need to cause a redraw in all windows if we are not in navigate mode, // So that the manips will change where they are drawn: if (p->GetMouseModeParams()->GetCurrentMouseMode() != MouseModeParams::GetNavigateModeName()) { map::iterator it; for (it = _vizWindow.begin(); it != _vizWindow.end(); it++) { (it->second)->Render(false); } } } } void VizWinMgr::_syncViewpoints(string vizName) { if (vizName.empty()) return; ParamsMgr *paramsMgr = _controlExec->GetParamsMgr(); bool enabled = paramsMgr->GetSaveStateEnabled(); paramsMgr->SetSaveStateEnabled(false); ViewpointParams *currentVP = _controlExec->GetParamsMgr()->GetViewpointParams(vizName); vector winNames = _getVisualizerNames(); for (int i = 0; i < winNames.size(); i++) { if (winNames[i] != vizName) { ViewpointParams *vpParams = _controlExec->GetParamsMgr()->GetViewpointParams(winNames[i]); vpParams->SetModelViewMatrix(currentVP->GetModelViewMatrix()); vpParams->SetRotationCenter(currentVP->GetRotationCenter()); } } paramsMgr->SetSaveStateEnabled(enabled); } vector VizWinMgr::_getVisualizerNames() const { vector names; std::map::const_iterator itr = _vizWindow.begin(); for (; itr != _vizWindow.end(); ++itr) { names.push_back(itr->first); } return (names); } void VizWinMgr::_killViz(string vizName) { VAssert(_vizWindow.find(vizName) != _vizWindow.end()); _mdiArea->removeSubWindow(_vizMdiWin[vizName]); // This will trigger a closeEvent on VizWin, which will in turn // call vizAboutToDisappear // _vizWindow[vizName]->setEnabled(false); _vizWindow[vizName]->close(); } void VizWinMgr::_removeVisualizer(const string &name) { auto win = _vizWindow[name]; win->makeCurrent(); _controlExec->CleanupVisualizer(name, true); // disconnect all signals from window disconnect(win, 0, this, 0); // Remove the vizwin and the vizmdiwin _safeMDIChange([&](){ _mdiArea->removeSubWindow(_vizMdiWin[name]); }); delete _vizWindow[name]; _vizMdiWin.erase(name); _vizWindow.erase(name); } void VizWinMgr::_safeMDIChange(function f) { // QMdiArea ignores attributes that disable focus signals launching by showing. // These conflict with active visualizer selection based on viz win selection. auto e = new DisableFocusFilter; for (auto &w : _vizWindow) { w.second->installEventFilter(e); w.second->paintOnResize = false; } f(); for (auto &w : _vizWindow) { w.second->removeEventFilter(e); w.second->paintOnResize = true; } } void VizWinMgr::syncWithParams() { vector vizNames = _controlExec->GetParamsMgr()->GetVisualizerNames(); vector toRemove; for (auto it = _vizWindow.cbegin(); it != _vizWindow.cend(); ++it) if (!STLUtils::Contains(vizNames, it->first)) toRemove.push_back(it->first); for (const auto &name : toRemove) _removeVisualizer(name); if (!toRemove.empty()) FitSpace(); for (int i = 0; i < vizNames.size(); i++) { if (_vizWindow.find(vizNames[i]) != _vizWindow.end()) continue; blockSignals(true); _attachVisualizer(vizNames[i]); blockSignals(false); } if (_controlExec->WasDataCacheDirty()) setTrackballScale(); } void VizWinMgr::Update(bool fast) { // Certain actions queue multiple renders within Qt's event queue (e.g. changing the // renderer variable dimension). Normally, Qt will then process each of these events // sequentially and render multiple times. While not ideal, this just results in extra // renders and computation time. When using the progress bar, however, it sometimes // requests a redraw of the entire GUI at which point Qt processes queued events. // When you have pending render events, it will now try to initiate a new render // before the first has finished. This prevents that but it does not fix the // underlying issue. if (_insideRender) return; _insideRender = true; this->syncWithParams(); map::const_iterator it; for (it = _vizWindow.begin(); it != _vizWindow.end(); it++) { (it->second)->Render(fast); } _insideRender = false; } int VizWinMgr::EnableImageCapture(string filename, string winName) { _vizWindow[winName]->makeCurrent(); _vizWindow[winName]->_preRender(); return _controlExec->EnableImageCapture(filename, winName); _vizWindow[winName]->_postRender(); } void VizWinMgr::setTrackballScale() { if (_controlExec->GetDataNames().size() == 0) return; DataStatus *dataStatus = _controlExec->GetDataStatus(); ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); size_t ts = _controlExec->GetParams()->GetCurrentTimestep(); VAPoR::CoordType minExts, maxExts; dataStatus->GetActiveExtents(paramsMgr, ts, minExts, maxExts); double scale[3]; scale[0] = scale[1] = scale[2] = max(maxExts[0] - minExts[0], (maxExts[1] - minExts[1])); _trackBall->SetScale(scale); } ================================================ FILE: apps/vaporgui/VizWinMgr.h ================================================ #pragma once #include #include #include #include #include "VaporFwd.h" class VizWin; class Trackball; class QtVizWinGLContextManager; class VizWinMgr : public QMdiArea { Q_OBJECT VAPoR::ControlExec *_controlExec; public: VizWinMgr(VAPoR::ControlExec *ce); ~VizWinMgr(); void Update(bool fast); void SetTrackBall(const double posvec[3], const double dirvec[3], const double upvec[3], const double centerRot[3], bool perspective); int EnableImageCapture(string filename, string winName); VizWin *Get(const std::string &name) { return _vizWindow[name]; } QtVizWinGLContextManager * const visualizerGLContextManager; public slots: void FitSpace(); private slots: void _setActiveViz(string winName); void _syncViewpoints(string winName); signals: void enableMultiViz(bool onOff); void activateViz(const QString &); private: std::map _vizWindow; std::map _vizMdiWin; QMdiArea *_mdiArea; Trackball * _trackBall; bool _initialized; bool _insideRender = false; void syncWithParams(); void _attachVisualizer(string vizName); void _removeVisualizer(const string &name); void _safeMDIChange(function f); vector _getVisualizerNames() const; void _killViz(string vizName); void setTrackballScale(); }; ================================================ FILE: apps/vaporgui/VolumeEventRouter.cpp ================================================ #include "VolumeEventRouter.h" #include "vapor/VolumeParams.h" #include #include "PWidgets.h" #include "PStringDropdownHLI.h" #include "PMetadataClasses.h" using namespace VAPoR; typedef VolumeParams VP; static RenderEventRouterRegistrar registrar(VolumeEventRouter::GetClassType()); VolumeEventRouter::VolumeEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, VolumeParams::GetClassType()) { // clang-format off AddVariablesSubtab(new PGroup({ new PSection("Variable Selection", { new PScalarVariableSelector, new PColorMapVariableSelector }), new PFidelitySection, new POpenVariableMetadataWidget })); AddAppearanceSubtab(new PGroup({ (new PTFEditor)->ShowColormapBasedOnParam(VP::UseColormapVariableTag, false), new PSection("Rendering Method", { new PStringDropdownHLI("Raytracing Algorithm", VP::GetAlgorithmNames(VP::Type::DVR), &VP::GetAlgorithm, &VP::SetAlgorithmByUser), }), (new PShowIf(VP::_algorithmTag))->Equals(VolumeOSPRay::GetName())->Then({ new PSection("OSPRay Parameters", { (new PDoubleSliderEdit(VolumeParams::OSPDensity, "Density"))->SetRange(0, 3)->EnableDynamicUpdate()->SetTooltip("Volume density (aka opacity)."), (new PIntegerSliderEdit("osp_spp", "Samples Per Pixel"))->SetRange(1, 10)->SetTooltip("Number of render passes. Increases fidelity but may significantly reduce performance."), (new PDoubleInput(VolumeParams::OSPSampleRateScalar, "Volume Sample Rate Scalar"))->EnableBasedOnParam("osp_usePT", false)->SetTooltip("Scales the sampling rate along the ray throughout the volume. Increasing may significantly reduce performance."), }) })->Else({ new PSection("Ray Tracing", { new PEnumDropdown(VP::SamplingRateMultiplierTag, {"1x", "2x", "4x", "8x", "16x"}, {1, 2, 4, 8, 16}, "Sampling Rate Multiplier"), (new PDoubleSliderEdit(VP::VolumeDensityTag, "Volume Density"))->EnableDynamicUpdate()->SetTooltip("Changes the overall density or 'opacity' of the volume allowing for finer tuning of the transfer function."), new PCheckbox(VP::UseColormapVariableTag, "Color by other variable"), }), (new PColormapTFEditor)->ShowBasedOnParam(VolumeParams::UseColormapVariableTag), new PSection("Lighting", { new PCheckbox(VolumeParams::LightingEnabledTag, "Enabled"), (new PDoubleSliderEdit(VP::PhongAmbientTag, "Ambient" ))->EnableDynamicUpdate(), (new PDoubleSliderEdit(VP::PhongDiffuseTag, "Diffuse" ))->EnableDynamicUpdate(), (new PDoubleSliderEdit(VP::PhongSpecularTag, "Specular" ))->EnableDynamicUpdate(), (new PDoubleSliderEdit(VP::PhongShininessTag, "Shininess"))->EnableDynamicUpdate() }) }) })); AddGeometrySubtab(new PGeometrySubtab); AddColorbarSubtab(new PAnnotationColorbarWidget); // clang-format on } string VolumeEventRouter::_getDescription() const { return ("Displays " "the user's 3D data variables within a volume described by the source data " "file, according to color and opacity settings defined by the user.\n\n" "These 3D variables may be offset by a height variable.\n\n"); } ================================================ FILE: apps/vaporgui/VolumeEventRouter.h ================================================ #pragma once #include "vapor/VolumeRenderer.h" #include "RenderEventRouterGUI.h" //! \class VolumeEventRouter //! \ingroup Public_GUI //! \brief Volume renderer GUI //! \author Stas Jaroszynski class VolumeEventRouter : public RenderEventRouterGUI { public: VolumeEventRouter(QWidget *parent, VAPoR::ControlExec *ce); static string GetClassType() { return VAPoR::VolumeRenderer::GetClassType(); } string GetType() const { return GetClassType(); } bool Supports2DVariables() const { return false; } bool Supports3DVariables() const { return true; } protected: string _getDescription() const; string _getSmallIconImagePath() const { return "DVR_small.png"; } string _getIconImagePath() const { return "DVR.png"; } }; ================================================ FILE: apps/vaporgui/VolumeIsoEventRouter.cpp ================================================ #include "VolumeIsoEventRouter.h" #include #include #include "PWidgets.h" #include "PStringDropdownHLI.h" #include "PMetadataClasses.h" using namespace VAPoR; typedef VolumeIsoParams VIP; static RenderEventRouterRegistrar registrar(VolumeIsoEventRouter::GetClassType()); VolumeIsoEventRouter::VolumeIsoEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, VolumeIsoParams::GetClassType()) { // clang-format off AddVariablesSubtab(new PGroup({ new PSection("Variable Selection", { new PScalarVariableSelector, new PColorMapVariableSelector }), new PFidelitySection, new POpenVariableMetadataWidget })); AddAppearanceSubtab(new PGroup({ new PTFEditor(RenderParams::_variableNameTag, {PTFEditor::Histogram, PTFEditor::Opacity, PTFEditor::IsoValues}), new PSection("Rendering Method", { new PStringDropdownHLI("Raytracing Algorithm", VIP::GetAlgorithmNames(VIP::Type::Iso), &VIP::GetAlgorithm, &VIP::SetAlgorithmByUser), }), (new PShowIf(VIP::_algorithmTag))->Equals(VolumeOSPRayIso::GetName())->Then({ new PSection("OSPRay Parameters", { (new PIntegerSliderEdit("osp_spp", "Samples Per Pixel"))->SetRange(1, 10)->SetTooltip("Number of render passes. Increases fidelity but may significantly reduce performance."), (new PDoubleSliderEdit(VIP::OSPAmbientLightIntensity, "Ambient Light"))->EnableDynamicUpdate(), (new PDoubleSliderEdit(VIP::OSPDirectionalLightIntensity, "Diffuse Light"))->SetRange(0, 3)->EnableDynamicUpdate(), }) })->Else({ new PSection("Ray Tracing", { new PEnumDropdown(VIP::SamplingRateMultiplierTag, {"1x", "2x", "4x", "8x", "16x"}, {1, 2, 4, 8, 16}, "Sampling Rate Multiplier"), new PCheckbox(VIP::UseColormapVariableTag, "Color by other variable"), (new PColorSelector(RenderParams::_constantColorTag, "Color"))->ShowBasedOnParam(VIP::UseColormapVariableTag, false), (new PVariableSelector3D(RenderParams::_colorMapVariableNameTag))->ShowBasedOnParam(VIP::UseColormapVariableTag) }), (new PColormapTFEditor)->ShowBasedOnParam(VIP::UseColormapVariableTag), new PSection("Lighting", { new PCheckbox(VIP::LightingEnabledTag, "Enabled"), (new PDoubleSliderEdit(VIP::PhongAmbientTag, "Ambient" ))->EnableDynamicUpdate(), (new PDoubleSliderEdit(VIP::PhongDiffuseTag, "Diffuse" ))->EnableDynamicUpdate(), (new PDoubleSliderEdit(VIP::PhongSpecularTag, "Specular"))->EnableDynamicUpdate(), (new PDoubleSliderEdit(VIP::PhongShininessTag, "Shininess"))->SetRange(1, 100)->EnableDynamicUpdate() }) }) })); AddGeometrySubtab(new PGeometrySubtab); AddColorbarSubtab(new PAnnotationColorbarWidget); // clang-format on } string VolumeIsoEventRouter::_getDescription() const { return ("Displays " "the user's 3D data variables within a volume described by the source data " "file, according to color and opacity settings defined by the user.\n\n" "These 3D variables may be offset by a height variable.\n\n"); } ================================================ FILE: apps/vaporgui/VolumeIsoEventRouter.h ================================================ #pragma once #include "RenderEventRouterGUI.h" #include "vapor/VolumeIsoRenderer.h" //! \class VolumeIsoEventRouter //! \ingroup Public_GUI //! \brief Isosurface renderer GUI //! \author Stas Jaroszynski class VolumeIsoEventRouter : public RenderEventRouterGUI { public: VolumeIsoEventRouter(QWidget *parent, VAPoR::ControlExec *ce); static string GetClassType() { return VAPoR::VolumeIsoRenderer::GetClassType(); } string GetType() const { return GetClassType(); } bool Supports2DVariables() const { return false; } bool Supports3DVariables() const { return true; } protected: string _getDescription() const; string _getSmallIconImagePath() const { return "IsoSurface_small.png"; } string _getIconImagePath() const { return "IsoSurface.png"; } }; ================================================ FILE: apps/vaporgui/WireFrameEventRouter.cpp ================================================ #include "WireFrameEventRouter.h" #include "vapor/WireFrameParams.h" #include "PWidgets.h" #include "PConstantColorWidget.h" #include "PMetadataClasses.h" using namespace VAPoR; static RenderEventRouterRegistrar registrar(WireFrameEventRouter::GetClassType()); WireFrameEventRouter::WireFrameEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, WireFrameParams::GetClassType()) { // clang-format off AddVariablesSubtab(new PGroup({ new PSection("Variable Selection", { new PDimensionSelector, new PScalarVariableSelector, new PHeightVariableSelector }), new PFidelitySection, new POpenVariableMetadataWidget })); AddAppearanceSubtab(new PGroup({ (new PTFEditor)->ShowOpacityBasedOnParam("NULL", 1), new PSection("Appearance", { new PConstantColorWidget }) })); AddGeometrySubtab(new PGeometrySubtab); AddColorbarSubtab(new PAnnotationColorbarWidget); // clang-format on } string WireFrameEventRouter::_getDescription() const { return ("Displays a wireframe of the mesh for the selected variable"); } ================================================ FILE: apps/vaporgui/WireFrameEventRouter.h ================================================ #pragma once #include "RenderEventRouterGUI.h" #include "vapor/WireFrameRenderer.h" //! \class WireFrameEventRouter //! \ingroup Public_GUI //! \brief WireFrame Renderer GUI //! \author Stas Jaroszynski class WireFrameEventRouter : public RenderEventRouterGUI { public: WireFrameEventRouter(QWidget *parent, VAPoR::ControlExec *ce); static string GetClassType() { return VAPoR::WireFrameRenderer::GetClassType(); } string GetType() const { return GetClassType(); } bool Supports2DVariables() const { return true; } bool Supports3DVariables() const { return true; } protected: string _getDescription() const; string _getSmallIconImagePath() const { return "WireFrame_small.png"; } string _getIconImagePath() const { return "WireFrame.png"; } }; ================================================ FILE: apps/vaporgui/common.cpp ================================================ #include ================================================ FILE: apps/vaporgui/common.h ================================================ #pragma once #include #include #include "PWidgetsFwd.h" namespace VAPoR { class ParamsBase; class ParamsMgr; class DataMgr; class ControlExec; } using namespace VAPoR; class SettingsParams; class GUIStateParams; class PDynamicMixin; template class PWidgetHLIBase; ================================================ FILE: apps/vaporgui/core_profile_attributes.mm ================================================ #include #if QT_VERSION < 0x050000 // if less than 5.0.0 void* select_3_2_mac_visual(GDHandle handle, int depthBufferSize) { static const int Max = 40; NSOpenGLPixelFormatAttribute attribs[Max]; int cnt = 0; attribs[cnt++] = NSOpenGLPFAOpenGLProfile; attribs[cnt++] = NSOpenGLProfileVersion3_2Core; attribs[cnt++] = NSOpenGLPFADoubleBuffer; attribs[cnt++] = NSOpenGLPFADepthSize; attribs[cnt++] = (NSOpenGLPixelFormatAttribute)(depthBufferSize==-1)?32:depthBufferSize; attribs[cnt] = 0; Q_ASSERT(cnt < Max); return [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; } #endif ================================================ FILE: apps/vaporgui/hide_std_error_util.cpp ================================================ #include "hide_std_error_util.h" #ifndef WIN32 #include #include #endif static int _savedSTDERR; void HideSTDERR() { #ifndef WIN32 _savedSTDERR = -1; if (fflush(stderr) != 0) return; int rc = dup(STDERR_FILENO); if (rc < 0) return; else _savedSTDERR = rc; auto *tmp = freopen("/dev/null", "w", stderr); (void)tmp; #endif } void RestoreSTDERR() { #ifndef WIN32 if (_savedSTDERR == -1) return; fflush(stderr); dup2(_savedSTDERR, STDERR_FILENO); close(_savedSTDERR); clearerr(stderr); #endif } ================================================ FILE: apps/vaporgui/hide_std_error_util.h ================================================ #pragma once void HideSTDERR(); void RestoreSTDERR(); ================================================ FILE: apps/vaporgui/images/arrowrake.xpm ================================================ /* XPM */ const static char *arrowrake[] = { /* columns rows colors chars-per-pixel */ "26 23 82 1", " c #040404", ". c #040308", "X c #090A05", "o c #0A0B0A", "O c #100F14", "+ c #131314", "@ c #16151A", "# c gray11", "$ c #232323", "% c #2B2C29", "& c #2C2B31", "* c #343434", "= c #393A36", "- c #3D3D3C", "; c #494949", ": c #51524A", "> c #505050", ", c #5F5F5F", "< c #626262", "1 c #6C6C6C", "2 c #737373", "3 c #7A7A7A", "4 c #848483", "5 c #878880", "6 c #8A8B84", "7 c #8B8B89", "8 c #91928B", "9 c #9A9C8F", "0 c #959595", "q c #9A9B94", "w c #9C9C9A", "e c #9C9BA0", "r c #9FA194", "t c #A1A29C", "y c #ABAD9F", "u c #A4A4A2", "i c #ABACA3", "p c #ABABAB", "a c #A7A5B2", "s c #ADABB6", "d c #B2B5A4", "f c #B3B5A9", "g c #B7B9AE", "h c #B2B2B2", "j c #B7B8B0", "k c #B8B7BC", "l c #B9B9B4", "z c #BABABB", "x c #BEBDC3", "c c #BFC1B3", "v c #C2C3BC", "b c #C7C9BC", "n c #CACDBD", "m c #C1C1C3", "M c #C7C8C3", "N c #C8C7CC", "B c #CACCC3", "V c #CBCBCA", "C c #D0CFD4", "Z c #D0D2C7", "A c #D7D9CB", "S c #DADDCC", "D c #D7D7D5", "F c #DCDCDA", "G c #DEE1CC", "H c #DEE0D4", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", /* pixels */ "PYYKPYUJUPURYU!IUUUUUUUUUU", "YUY/TKURURPKTYITUUUUUUUUUU", "YPPPIIYYUKTRJPYPUUUUUUYUUU", "YPTYcqfYTRUURUGTUUUUUUUUUU", "YPPYYFj6fK!KU~YPUUIUUUUUUU", "PY~Fi8iVuwlIYKTYUUUUUUUUUU", "UPIIIEVwphuwrB^KUUUUUUUUUU", "PUUbq8pNxpp0=:ZWUUUUUUUUUU", "UP!KEYDhuppw*>17HWWLIYYPUU", "UPGy88wwhpp4$23-%6H^IY!TTI", "PPTLQQFNhpp4&33;@o-qVcpiq7", "!KBrrrupppp2$21,&O.o XooO ", "KY~IQEVxzhk3$73;@.$<678685", "TIAiruhxhpp2$3,;=2MQYI!!YI", "IY~EEFmeppu2%230AY!IHYTJUU", "YIFfqumNhpp1#sQE!IIYTYJUYY", "UUUHECsazpuiyIUUUUUUUUUUUU", "TJIBtlVkivIYGYPUUUUUUUUUUU", "JY~~YgrVUY!TUTUPUUUUUUUUUU", "~K!Adn!KUUJKUYYYUUUUUUUUUU", "ILYYYUGTUYTUUUUYUUUUUUUUUU", "IW!II!UYYYYUKUYUUUUUUUUUUU", "IY!II!YEEW!!K/YUUUUUUUUUUU" }; ================================================ FILE: apps/vaporgui/images/back.xpm ================================================ /* XPM */ /* Drawn by Mark Donohoe for the K Desktop Environment */ /* See http://www.kde.org */ const static char*back[]={ "16 16 5 1", "# c #000000", "a c #ffffff", "c c #808080", "b c #c0c0c0", ". c None", "................", ".......#........", "......##........", ".....#a#........", "....#aa########.", "...#aabaaaaaaa#.", "..#aabbbbbbbbb#.", "...#abbbbbbbbb#.", "...c#ab########.", "....c#a#ccccccc.", ".....c##c.......", "......c#c.......", ".......cc.......", "........c.......", "................", "......................"}; ================================================ FILE: apps/vaporgui/images/capture-off.xpm ================================================ /* XPM */ const static char *capture-off[] = { /* columns rows colors chars-per-pixel */ "24 21 236 2", " c black", ". c #000100", "X c #010100", "o c #010101", "O c #000002", "+ c #010103", "@ c #010200", "# c #020200", "$ c #020300", "% c #030301", "& c #020202", "* c gray1", "= c #000004", "- c #000005", "; c #010005", ": c #010006", "> c #020106", ", c #020107", "< c #020204", "1 c #030305", "2 c #030207", "3 c #040500", "4 c #040402", "5 c #040404", "6 c gray2", "7 c #040406", "8 c #050507", "9 c #060606", "0 c #070707", "q c #03020A", "w c #040308", "e c #040309", "r c #050409", "t c #070709", "y c #080903", "u c #080806", "i c #090A04", "p c #0A0B05", "a c #0B0C06", "s c #0B0C07", "d c #0D0F04", "f c #090909", "g c gray4", "h c #0C0C0A", "j c #0D0E08", "k c gray5", "l c #11110F", "z c #13140C", "x c #14150D", "c c #111113", "v c #131313", "b c #151513", "n c #151611", "m c #161712", "M c gray8", "N c #151515", "B c #151517", "V c #161616", "C c gray9", "Z c #161618", "A c #171719", "S c #171812", "D c #1A1B15", "F c #1A1B16", "G c #1C1E11", "H c #1C1D17", "J c #191919", "K c #1B1B19", "L c #1D1E18", "P c #1E1E1E", "I c #1E2015", "U c #1F2018", "Y c #1F201B", "T c #22231D", "R c #24261B", "E c #232323", "W c #252523", "Q c #252620", "! c #262721", "~ c gray14", "^ c #252525", "/ c #252527", "( c #272729", ") c #272823", "_ c #2A2B26", "` c #2A2A28", "' c #2A2A2A", "] c gray17", "[ c #303129", "{ c #32332E", "} c #303032", "| c #333331", " . c gray20", ".. c #343530", "X. c #353535", "o. c #343436", "O. c #353537", "+. c #393937", "@. c #3A3B35", "#. c #3C3D35", "$. c gray22", "%. c #38383A", "&. c #3A3A38", "*. c #3C3C3A", "=. c #41423C", "-. c #43443C", ";. c gray25", ":. c #424240", ">. c #434341", ",. c #454641", "<. c #444444", "1. c #454547", "2. c gray28", "3. c #454449", "4. c #474749", "5. c #474840", "6. c #4A4B45", "7. c #484848", "8. c #494949", "9. c #4D4E48", "0. c #50504E", "q. c #53544C", "w. c #595B4E", "e. c #56555A", "r. c #5F605A", "t. c #606257", "y. c #6A6B63", "u. c #7A7A7C", "i. c #7D7D7F", "p. c #82837E", "a. c #85877C", "s. c #878785", "d. c #878789", "f. c #888886", "g. c #8E8F87", "h. c #898989", "j. c #88888A", "k. c #8B8B89", "l. c gray54", "z. c #8B8B8D", "x. c #8C8C8E", "c. c #97998B", "v. c #9C9E91", "b. c gray61", "n. c #9C9C9E", "m. c #A8AA9F", "M. c #A9AAA5", "N. c #AAABA5", "B. c #ABADA0", "V. c #ACADA5", "C. c #ACADA7", "Z. c #AEAEAE", "A. c #AFAFB1", "S. c #BBBCB4", "D. c #BFC1B4", "F. c #C3C5BA", "G. c #C6C8BD", "H. c #C8CABD", "J. c #CBCDC0", "K. c #CDCFC4", "L. c #CFD2C1", "P. c #CFD1C6", "I. c #D1D3C5", "U. c #D2D4C7", "Y. c #D3D5CA", "T. c #D8D9D1", "R. c #D8D8D6", "E. c #DBDDD0", "W. c #DEDFD7", "Q. c #DDDDDB", "!. c #DDDED8", "~. c #E6EACF", "^. c #E2E4D6", "/. c #E4E7D2", "(. c #E4E7D4", "). c #E4E7D6", "_. c #E2E4D9", "`. c #E4E6D8", "'. c #E5E7D9", "]. c #E5E8D3", "[. c #E6EAD3", "{. c #E7EBD2", "}. c #E5E8D7", "|. c #E6E9D4", " X c #E6E9D6", ".X c #E7EAD5", "XX c #E7EBD4", "oX c #E7EAD7", "OX c #E6E9D8", "+X c #E6E8DA", "@X c #E6E8DB", "#X c #E7E9DB", "$X c #E7EAD9", "%X c #E6E8DD", "&X c #E7E9DE", "*X c #E8EBD6", "=X c #E8ECD3", "-X c #E9EED0", ";X c #E8ECD5", ":X c #E9ECD7", ">X c #E9EDD6", ",X c #EAEED5", " c #F81D23", ", c #FF1D28", "< c #F62217", "1 c #F9221F", "2 c #F42E23", "3 c #F52A2E", "4 c #FE2B26", "5 c #FF2B2A", "6 c #F72234", "7 c #F72F32", "8 c #FD2431", "9 c #FD2B32", "0 c #F33326", "q c #FF3228", "w c #FF3B2C", "e c #F63D3A", "r c #FD3434", "t c #FD353C", "y c #FD3B34", "u c #FD3B3C", "i c #FE3641", "p c #FD3A44", "a c #FC3C49", "s c #F74237", "d c #F7443D", "f c #F94137", "g c #FC403D", "h c #FF4444", "j c #FF4048", "k c #FF4D44", "l c #FD4B4A", "z c #FF4755", "x c #FC4D54", "c c #F95345", "v c #FF5155", "b c #FF605A", "n c #F86C5F", "m c #F76C6F", "M c #FF6567", "N c #FE6C63", "B c #FA6B68", "V c #FF6D73", "C c #FB716D", "Z c #FC7D6A", "A c #FA7274", "S c #FA7D7B", "D c #FC827C", "F c #FD8184", "G c #FF848A", "H c #FF8F83", "J c #FF8F8E", "K c #FF8B93", "L c #F2998B", "P c #F89083", "I c #FF938E", "U c #F59599", "Y c #FD9494", "T c #FF939D", "R c #FF8EA0", "E c #FFA199", "W c #FFAB9C", "Q c #FBBDA8", "! c #FCB2B3", "~ c #F2CDBA", "^ c #FDC0BB", "/ c #DEECD2", "( c #DBEEDA", ") c #DEF3DC", "_ c #DEF0E0", "` c #F9D5C5", "' c #FFDBD1", "] c #E5E6C7", "[ c #E4ECCD", "{ c #E9EBCD", "} c #E5E7D9", "| c #E5ECD4", " . c #E4ECDB", ".. c #EDE7D4", "X. c #EBE6DB", "o. c #EAEBD4", "O. c #EAEBDA", "+. c #E3F0CC", "@. c #E4F0D4", "#. c #E4F0DC", "$. c #EDF2D4", "%. c #ECF1DB", "&. c #F7E7CD", "*. c #F0E9CD", "=. c #F4E7D3", "-. c #F1E6D9", ";. c #F3EBD3", ":. c #F1E9DA", ">. c #FFE2DF", ",. c #F0F1CF", "<. c #F2F1DD", "1. c #F6FCD8", "2. c #E4EDE4", "3. c #E9E7EA", "4. c #EAEBE2", "5. c #E4F3E3", "6. c #ECF4E5", "7. c #E6FAF8", "8. c #F5ECE2", "9. c #F6ECEB", "0. c #FEE5E1", "q. c #FCE9E4", "w. c #FBEBEC", "e. c #F0EEF1", "r. c #F3F3E3", "t. c #F6FDF5", "y. c #FBF4F2", /* pixels */ "| .. .o.[ | O.| O.4.+...O.o. ...O.| .O.O.#.| $.", "O.o.O.| ) O.-.o...O.;.O./ ;.o.#.o...O.o.2.{ O.X.", "2.:...:.8.| W : b @. .#.} #.4.L ; X I O.&. .:.", "O.O.} o.%.v O o O o O ' O.;.o.& o o + o # 6._ | ", "O.[ 5.$.~ y y t p t ; ] %.t g p t f a O u O.%.", "O. . .=.7 * p R >.Y e O O.O.o y I q.J f t o r. .", "| 4.$. .O y u 9.v 9.y o 2.| . j w., ' a w t.{ ", "[ O.X.8.3 + w Y q.U u o o.o.o t Y q.T y 4 o e.#.", "o.O.{ O.` O y a u u g ; O.:.j g y t d t O a ;. .", "O.[ .#.%.S o + O 1.2./ 5.4 O o o o ; $.{ 4.", "O.#.:.| 3.O.Z o o < ! :.6.y.7.y.9 o l %.%...} ", "O.:.a Q r.;.Y O o o # o 9 5 0 k x l 9 e .[ 4.) ", "O.o.N O O t 2 o o o r E h l v c l Y k =.o.O. .", "O.[ m o o o O o O y H > r 7 9 6 K x 4.{ | o.", "o.O.A O o O 8 r 4 1 % B M B N n V x t O.o.X.o.", "o.O.B o o o O B C B V o o o O o o o o q 5.2.$.} ", "o.O.@ @.$. .z o @ O - o o O o o o 9 O.O.@.O.", "o.} O.4.} O.O.r.O.P O O o o o F 8.r. .o.@.} ", "O.o.} o. ...O.O. .O.^ G D G G D D o.O.;.{ o.o.O.", "@.O.o. .o.o.o.| o...@.o.o.o.| o.| O.O. .4.o.o.4.", "@.O.o. .O.o.o.@. .O.o.o.o.| | o. .o.O. .4...@.4." }; ================================================ FILE: apps/vaporgui/images/cascade.xpm ================================================ /* XPM */ const static char *cascade[] = { /* columns rows colors chars-per-pixel */ "24 21 202 2", " c #000100", ". c #020300", "X c #030301", "o c gray1", "O c #050503", "+ c #060606", "@ c #070707", "# c #090A02", "$ c #0D0E06", "% c gray3", "& c #08080A", "* c #0B0B09", "= c gray4", "- c #0B0B0B", "; c #0C0C0A", ": c #0C0C0C", "> c gray5", ", c #0F0F0D", "< c gray6", "1 c #0E0E10", "2 c #0F1103", "3 c #0F100B", "4 c #101207", "5 c #10100E", "6 c #11110F", "7 c #12130D", "8 c #12130E", "9 c #14150D", "0 c #101010", "q c #111111", "w c #131311", "e c gray7", "r c #131313", "t c #131315", "y c #141510", "u c #151513", "i c #151610", "p c #151611", "a c #161711", "s c #161712", "d c gray8", "f c #161614", "g c gray9", "h c #181914", "j c #191A15", "k c #1A1A18", "l c #1D1D1B", "z c #1D1D1D", "x c #1D1D1F", "c c #1E1E1E", "v c #1D1C21", "b c #20201E", "n c #212123", "m c #232323", "M c #242520", "N c #252525", "B c #252527", "V c #272727", "C c #242328", "Z c gray16", "A c #2A2A2A", "S c #2C2C2E", "D c #302F34", "F c gray21", "G c #70706E", "H c #71716F", "J c #73746F", "K c gray44", "L c #717171", "P c #717173", "I c #727270", "U c #737371", "Y c #727272", "T c gray45", "R c #727177", "E c #727274", "W c #737375", "Q c #737277", "! c #747472", "~ c #747474", "^ c gray46", "/ c #747476", "( c #767676", ") c #747378", "_ c gray48", "` c #A5A6A1", "' c gray65", "] c #A7A7A7", "[ c #A6A6A8", "{ c #A9A9A7", "} c #A9AAA5", "| c #AAABA6", " . c #ABACA7", ".. c gray66", "X. c #A9A9A9", "o. c #A9A9AB", "O. c #AAAAA8", "+. c #ABABA9", "@. c #AAAAAA", "#. c gray67", "$. c #AAA9AF", "%. c #AAAAAC", "&. c #ABABAD", "*. c #ACADA8", "=. c #ACACAA", "-. c #ADADAB", ";. c #ADAEA9", ":. c #ACACAC", ">. c gray68", ",. c #ADADAF", "<. c #AEAEAE", "1. c #AFAFAF", "2. c #AAA9B1", "3. c #AEAEB0", "4. c #B0B1AC", "5. c #B0B0B2", "6. c #DCDDD7", "7. c gray85", "8. c #DADADC", "9. c #DCDCDA", "0. c #DDDED9", "q. c #DCDCDE", "w. c #DDDDDF", "e. c #DEDEDC", "r. c gray87", "t. c #DFDFDF", "y. c #DBDAE0", "u. c #DEDEE0", "i. c #DFDFE1", "p. c none", "a. c none", "s. c none", "d. c none", "f. c none", "g. c none", "h. c none", "j. c none", "k. c none", "l. c none", "z. c none", "x. c none", "c. c none", "v. c none", "b. c none", "n. c none", "m. c none", "M. c none", "N. c none", "B. c none", "V. c none", "C. c none", "Z. c none", "A. c none", "S. c none", "D. c none", "F. c none", "G. c none", "H. c none", "J. c none", "K. c none", "L. c none", "P. c none", "I. c none", "U. c none", "Y. c none", "T. c none", "R. c none", "E. c none", "W. c none", "Q. c none", "!. c none", "~. c none", "^. c none", "/. c none", "(. c none", "). c none", "_. c none", "`. c none", "'. c none", "]. c none", "[. c none", "{. c none", "}. c none", "|. c none", " X c none", ".X c none", "XX c none", "oX c none", "OX c none", "+X c none", "@X c none", "#X c none", "$X c none", "%X c none", "&X c none", "*X c none", "=X c none", "-X c none", ";X c none", ":X c none", ">X c none", ",X c none", /* pixels */ "/.x.K.x.K./.s.K./.N.N.K.H.H.:Xj.H.K.N.Z.N.c./.Z.", "Z.N././.E.&X].E.&Xj.].E.].H.N.K.E.N.K.].].c.K.:X", "].;XN.W. = a a a l j 8 $ 2 s.P.].N.K.H.H.K.N.j.", "].N.].E.a q.u.w.i.7.u.%Xw.$ E.K.&XN./.].Z./.K.Z.", "N.K.N.Z.j u.8.%X0.e.@Xq.$X= 6.&Xh. Xs./.E./.a.].", "N.K. Xd.a u.B A b b C v C x x 0 N.K.s.:XZ. Xx.", "/.K.s.,Xa t.S T ( ( G _ T H / P g N.K./.E.].N.M.", "Z././.j., i.D T / / T H G T T T = ].x./.j.E./.N.", "N./.H.H.s @XV H 0 @ = 0 o = @ : t a q O /./.Z./.", "/.N.H.H.3 %XF G @ X.1.@.<.' 1.#.,.O.[ r N.N.].K.", "N./.].:X9 e.n / @ @.#.X.#.#.#.#.o.| -.: /./.].N.", "/.N.H.j.9 q.Z / g #.@.#.#.#.X.#.#.4.[ , Z.M.]./.", "/.b.E.].4 a m Q : #.#.#.@.#.#.<.-.| 3.: N.N.j.K.", "H./.H.H.E.:Xa / x @.#.X.X.<.X.#.5.` -.3 ]./.].K.", "x. Xj.H.H.E.8 / : @.#.#.1.X.@.#.[ +.#., N.K.W./.", "P.s.E.].H.H. & b #.#.@.@.X.<.#.#.+.O.= /.N.j.K.", "K.H.H.E./.H.H.H.1 o.,.o.o.o.,.o.+.+.| # H./.N.N.", "H.H.H.H.H.H.H.H., +.O.-.-.O.-.O.2.2.2.8 W.H./.K.", "H.H.H./.H./.H.H.+ & e = e g r 0 t e + Z./.N.N.", "H.H.H.E.H.E.H.H.Z././.Z.H.]./.H.K./.].Z./.x.].H.", "H.H.H.H.H.E.K.H.N././.Z.Z.].].Z./.Z.H././.s./.E." }; ================================================ FILE: apps/vaporgui/images/cube.xpm ================================================ /* XPM */ const static char *cube[] = { /* columns rows colors chars-per-pixel */ "24 21 121 2", " c black", ". c black", "X c black", "o c black", "O c black", "+ c black", "@ c black", "# c black", "$ c black", "% c black", "& c black", "* c black", "= c black", "- c black", "; c black", ": c black", "> c black", ", c black", "< c black", "1 c black", "2 c black", "3 c black", "4 c black", "5 c black", "6 c black", "7 c black", "8 c black", "9 c black", "0 c black", "q c black", "w c black", "e c black", "r c black", "t c black", "y c black", "u c black", "i c black", "p c black", "a c black", "s c black", "d c black", "f c black", "g c black", "h c black", "j c black", "k c black", "l c black", "z c black", "x c black", "c c black", "v c black", "b c black", "n c black", "m c black", "M c black", "N c black", "B c black", "V c black", "C c none", "Z c none", "A c none", "S c none", "D c none", "F c none", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", "| c none", " . c none", ".. c none", "X. c none", "o. c none", "O. c none", "+. c none", "@. c none", "#. c none", "$. c none", "%. c none", "&. c none", "*. c none", "=. c none", "-. c none", ";. c none", ":. c none", ">. c none", ",. c none", "<. c none", "1. c none", "2. c none", "3. c none", "4. c none", "5. c none", "6. c none", "7. c none", "8. c none", "9. c none", "0. c none", /* pixels */ ") I +.+.I +.) L I 5.I +.+.T 4.I +.T ) ) L ) I { ", "I 4.I +.+.+.I +.{ W +.+.+.{ +.{ +.{ +.) L ) 5.W ", "{ ~ ) A +.+.| 6.5.) L ) ) ) I #.*.{ { W 5.+.I +.", "~ +.K 5.) W 9.5 V t w q b n q % + g . +.I I +.) ", "*.+.+.K ~ { x *.{ W { { { *.| 0.+ o { I 5.) +.", "{ ~ +.~ { : - 5 5 2 e - 2 5 2 5 5 6.$ +.~ K T ) ", "{ +.I { | z | | +.+.I W +.+.{ +.$ *.g 4.W +.) ) ", "+.+.:.| | , { *.+.I +.+.I +.I #.- ! ; W +.R +.+.", "T [ W +.>.a #.W ~ +.{ +.+.+.~ { 1 4.1 #.I +.[ T ", "T +.+.+.) a +.I +.~ { ~ +.~ +.{ 4 T 4 W ) I 4.) ", "I { =.+.J r I +.~ +.+.+.{ { +.+.5 I e W 5.+.W T ", ") =.{ +.L u I +.{ { +.~ +.~ +.~ 5 ) x +.Z 5.+.T ", "+.) I +.>.a 5.+.~ +.{ { +.+.~ { 2 +.4 +.+.Z { T ", ") +.W +.) i I ) +.+.+.~ +.~ +.{ 4 #.1 +.) 5.{ #.", "I +.{ =.K 4 I +.~ { ~ +.{ { +.+.1 ) p S 5.Z [ T ", "+.+.[ +.) i ) { +.{ +.+.+.~ +.~ 4 B e +.) I =.) ", ") +.+.W 3.l ! { +.W [ { { { +.[ 1 X ! +.L #.T +.", "J >.K #.W k N 5 # h N + q n 5 h b *.! 4.+.I +.+.", "W { W +.+.+.I ) +.+.I +.4.+.{ +.{ [ #.S =.I +.+.", ") >.) +.I +.=.{ ) ) +.T I +.) +.) ) +.+.{ { I +.", ") ) I +.[ +.+.+.) T +.) T ) ) ) L T ) +.{ =.+.+." }; ================================================ FILE: apps/vaporgui/images/eye.xpm ================================================ /* XPM */ const static char *eye[] = { /* columns rows colors chars-per-pixel */ "24 21 73 1", " c #060606", ". c #0C0C0C", "X c #131313", "o c #1B1B1B", "O c gray14", "+ c #2D2D2D", "@ c #343530", "# c #3C3C3C", "$ c #444444", "% c #4B4B4C", "& c #4F4E53", "* c #51514F", "= c #535351", "- c #585954", "; c #5B5B5B", ": c #60605E", "> c #626163", ", c #6A6B66", "< c #6B6B6B", "1 c #727271", "2 c #747378", "3 c #7C7C7C", "4 c #7F7F81", "5 c #807F84", "6 c #838483", "7 c #858489", "8 c #898987", "9 c #8B8B8B", "0 c #8E8E90", "q c #91928C", "w c #939494", "e c #969699", "r c #9B9B9B", "t c #A0A09E", "y c #A3A3A3", "u c #A7A7A9", "i c #A8A8A6", "p c #ACACAB", "a c #AEADB2", "s c #B0B0AE", "d c #B4B4B4", "f c #B6B6B8", "g c #B8B9B5", "h c #BBBBBB", "j c #C3C4BF", "k c #C4C4C4", "l c #C6C6C8", "z c #CBCCC7", "x c #CBCBCB", "c c #CCCBD0", "v c #D0D1CD", "b c #D3D3D3", "n c #D5D4D9", "m c #D9DAD6", "M c #DCDCDB", "N c #DFDFE1", "B c none", "V c none", "C c none", "Z c none", "A c none", "S c none", "D c none", "F c none", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c #F2F4E7", "U c #F0F1E9", "Y c #F1F1F1", /* pixels */ "AAAAASSLKKKKKKYGKSASAAAS", "SSAASSJKKGVMMMNGHPJSAACS", "AZASLKJGFMblhhhkbNJSSSSS", "SAAJJKGGKGFbhutyajbJSSSA", "ASJKKKGKYYYGbhy90tgJCICS", "CJKKGFFGYYYKNxpw68rjSSSS", "SJJGFNMmbnlfie96430iNZUS", "SJJFnkuq3<%@$%$%;<3rhMJJ", "KVbge6<&#O#%oo$$*;19anKJ", "Kmp3,-#&:X6rX #1=*,9pcVI", "Kz7>*@*i1XXX .+w8::4ycNK", "Gg2>:;9h-XX.Xo+9t415elFJ", "Kj94tsis>ooooO$ee88rplHS", "Lmkapjvlp<+oo@ c #424100", ", c #424500", "< c #4A4900", "1 c #4A4D00", "2 c #525100", "3 c #525500", "4 c #5A5D00", "5 c #636100", "6 c #636500", "7 c #6B6900", "8 c #6B6D00", "9 c #737100", "0 c #737500", "q c #7B7900", "w c #424142", "e c #424542", "r c gray38", "t c #C6C342", "y c #D6D74A", "u c #E7E74A", "i c #E7E752", "p c #C6C763", "a c #D6D36B", "s c #EFEB73", "d c #F7F37B", "f c #F7F77B", "g c #F7F784", "h c #F7F78C", "j c #F7F794", "k c #F7F79C", "l c #D6D3CE", "z c #E6E4E1", "x c #EFEEEC", "c c #F5F5F3", /* pixels */ "xzzzzzzzzzzzzzzzzzzzzzzx", "zllllllllllllllllllllllz", "zllllllllllllllO. lllllz", "zlllllllllllll l llllz", "zllllllllllll lll ll z", "zllllllllllllllllllll z", "zlll:*Xlllllllllllll z", "zllekhg lllllllllll z", "zlwkjgf XO&**+X lllllllz", "zl;jhgffgghhhgfa llllllz", "zl-hggfffgggggsp llllllz", "zl=hgffiiiiiiuyt llllllz", "zl=hgffuu .o r", "zl=hgfuu qqqqq00000841 z", "zl=hgfu qqqqqqq00962> lz", "zl*hgi qqqqqqqq0851$ llz", "zl+gi 00000000974<# lllz", "zlod 66666666653,# llllz", "zl 31<<<<<<<<,%@ lllllz", "zll llllllz", "zllllllllllllllllllllllz", "zllllllllllllllllllllllz", "cxxxxxxxxxxxxxxxxxxxxxxc" }; ================================================ FILE: apps/vaporgui/images/forward.xpm ================================================ /* XPM */ /* Drawn by Mark Donohoe for the K Desktop Environment */ /* See http://www.kde.org */ const static char*forward[]={ "16 16 5 1", "# c #000000", "a c #ffffff", "c c #808080", "b c #c0c0c0", ". c None", "................", "................", ".........#......", ".........##.....", ".........#a#....", "..########aa#...", "..#aaaaaaabaa#..", "..#bbbbbbbbbaa#.", "..#bbbbbbbbba#..", "..########ba#c..", "..ccccccc#a#c...", "........c##c....", "........c#c.....", "........cc......", "........c.......", "................", "................"}; ================================================ FILE: apps/vaporgui/images/home.xpm ================================================ /* XPM */ const static char *home[] = { /* columns rows colors chars-per-pixel */ "24 21 163 2", " c black", ". c #000100", "X c #010100", "o c #010101", "O c #000002", "+ c #000200", "@ c #010200", "# c #010300", "$ c #020300", "% c #000004", "& c #020106", "* c #030207", "= c #030400", "- c #050601", "; c #6B6A70", ": c #92938B", "> c #92938D", ", c #96978F", "< c #96988D", "1 c #989A8F", "2 c #9A9C8E", "3 c #939393", "4 c #959690", "5 c #969791", "6 c #969792", "7 c #959595", "8 c #959597", "9 c #969694", "0 c #979795", "q c #949399", "w c #97969C", "e c #979892", "r c #979893", "t c #989896", "y c #9A9B96", "u c #9B9C96", "i c #989898", "p c gray", "a c #BEBEC0", "s c #C0C1B9", "d c #C1C1BF", "f c #C4C6B8", "g c #C1C1C1", "h c #C2C2C0", "j c #C3C3C3", "k c #C2C2C4", "l c #C5C5C5", "z c #C7C7C5", "x c none", "c c none", "v c none", "b c none", "n c none", "m c none", "M c none", "N c none", "B c none", "V c none", "C c none", "Z c none", "A c none", "S c none", "D c none", "F c none", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", "| c none", " . c none", ".. c none", "X. c none", "o. c none", "O. c none", "+. c none", "@. c none", "#. c none", "$. c none", "%. c none", "&. c none", "*. c none", "=. c none", "-. c none", ";. c none", ":. c none", ">. c none", ",. c none", "<. c none", "1. c none", "2. c none", "3. c none", "4. c none", "5. c none", "6. c none", "7. c none", "8. c none", "9. c none", "0. c none", "q. c none", "w. c none", "e. c none", "r. c none", "t. c none", "y. c none", "u. c none", "i. c none", "p. c none", "a. c none", "s. c none", "d. c none", "f. c none", "g. c #F0EFF4", "h. c #F0F3E2", "j. c #F3F6E3", "k. c #F0F1EB", "l. c #F1F1EF", "z. c #F1F2ED", "x. c #F2F3EE", "c. c #F3F4EF", "v. c #F0F0F2", "b. c #F1F1F3", "n. c #F3F3F3", "m. c #F2F1F6", "M. c #F3F3F5", "N. c #F4F4F2", "B. c #F4F4F4", "V. c #F4F4F6", "C. c #F4F3F8", "Z. c #F6F6F8", "A. c #FBFBFB", "S. c #FCFBFF", "D. c #FCFCFA", "F. c #FDFDFB", "G. c #FDFEF9", "H. c #FFFFF8", "J. c #FFFFFB", "K. c #FEFEFC", "L. c #FFFFFD", "P. c #FFFEFF", "I. c gray100", /* pixels */ "+.G E *.G +.D ~ &.~ ~ ) ~ >.D ! E D D D ~ _ G +.", "G *.~ E D +.G +.E +.,.G +.G +.I } *.S ~ +.&.+.,.", "E ~ c ~ +.~ E G G ~ B &.~ :.:.V t._ +.+.G +.+.G ", "+.E ~ +.+.G +.&.x y.y.< # ~ n y 7 # _ _ I I +.~ ", "D G *.E G +.+.G +._ q l.&.# &.8 4.- } +.+.+.G ! ", "+.+.+.G +.I I &._ t l.# # T # 4 9.# %.I ~ .~ ~ ", "D E G +._ I h.v 4 l.* p z # T # 9.# } D ! +.G +.", "~ ~ E +._ &.v 2 n.# d P.S.g # } # # I +.+.G +.~ ", "G ~ D +._ T t m.# k P.G.c.n.p * t.# t.~ &.I ~ ~ ", "+.+.G E &.< n.# l A.P.V.n.n.4.g # a.# ~ +.G <.G ", "+.G +.D &., # k S.P.V.f.C.4.d.m f # # D I &.~ G ", "+.~ D ~ _ } < P.P.n.3 7 i # 4.6.I # y.) +.+.D +.", "+.c +.G E } 4 P.P.d.u G.e.# w.9.+.# T D +.I :.G ", "+.c ~ ,.~ t.4 P.C.a.: t.s # 6.9.I # %.~ +.I D +.", "b j.D G E %.: G.B m 6 g 7 # B } &.# &.S +.I +.G ", "&.c +.~ &.&.4 u._ } 7 w ; # } _ G # I ) c +.D +.", "+.G :.! +.I # # # # # # # # # # # # I ~ D ) E &.", "I &.G :.G &.} } ! .I _ E I I G } } &.E +.G +.+.", "G :.G G +.+.G &. . . . ._ +._ +._ G +.+.+.G ~ G ", ") G &.+.G ~ ! ! ! ) ! ! +.~ ~ ~ E E _ _ +.+.G ~ ", "~ G +.+.I ~ ~ W ~ Q ! ) ~ ) ~ ~ W ~ ~ I +.+.D ! " }; ================================================ FILE: apps/vaporgui/images/home2.xpm ================================================ /* XPM */ /* Drawn by Mark Donohoe for the K Desktop Environment */ /* See http://www.kde.org */ const static char*home2[]={ "16 16 4 1", "# c #000000", "a c #ffffff", "b c #c0c0c0", ". c None", "........... ....", " ....##.......", "..#...####......", "..#..#aabb#.....", "..#.#aaaabb#....", "..##aaaaaabb#...", "..#aaaaaaaabb#..", ".#aaaaaaaaabbb#.", "###aaaaaaaabb###", "..#aaaaaaaabb#..", "..#aaa###aabb#..", "..#aaa#.#aabb#..", "..#aaa#.#aabb#..", "..#aaa#.#aabb#..", "..#aaa#.#aabb#..", "..#####.######..", "................"}; ================================================ FILE: apps/vaporgui/images/isoline.xpm ================================================ /* XPM */ static const char *isoline[] = { /* columns rows colors chars-per-pixel */ "24 21 20 1 ", " c black", ". c #E4E8CF", "X c #E3E6D1", "o c #E5E8D5", "O c #E7EBD4", "+ c #E7EAD5", "@ c #E9EDD4", "# c #E4E6D8", "$ c #E6E8DA", "% c #E8EBDA", "& c #E9ECD9", "* c #E9ECDB", "= c #ECEFDA", "- c #E8EADC", "; c #EAECDE", ": c #ECEFDC", "> c #ECF0D9", ", c #EEF1DE", "< c #EFF2DF", "1 c #E5E6E0", /* pixels */ "&&&&&&&&@@&&&:&&%&.>+*&&", "&&&&&&&&&&&&&&--*+@@&*%+", "&&&&&& >-:+@&#+@", "&&&&& &&&&&&& &&@&%<+", "&&&& &&&&&&&&&&& &+,o,", "&&&& &&&&&&&&&&&&& %:+", "&&& &&&&&&&&&&&&&&& &@", "&&& &&&&& &&&&&&& +", "&& &&&& &&& &&&&&& ", ",& &&&&& &&&&&& &&X&@:", "&* +&&& &&&&&&&& %&&&&", "%+ &&&& &&&&&&&&&& +&&:&", "%% &&&& &&&&&&&& :&%+&", "+% ,&&&& &&&&&&& &&@%<&", "&& &&&&& %@%,@+", "&&& &&&&&&#&&%&&+&%%+&&", "&&&@ &&1&&@&+&&&&&&& ", "&+&%%% &&&&&>@&&& &", "&&&+&%&& &&&&& &&&&", "@@%:*:+&&+ &&&&&&&", "@+&:%&+&*+%%-**@&&&&&&&&" }; ================================================ FILE: apps/vaporgui/images/lightbulb.xpm ================================================ /* XPM */ const static char *lightbulb[] = { /* columns rows colors chars-per-pixel */ "24 21 137 2", " c #000100", ". c #010200", "X c #020200", "o c #020300", "O c #030301", "+ c #030305", "@ c #030400", "# c #040500", "$ c #040402", "% c #040600", "& c #050600", "* c #050601", "= c #060700", "- c #060701", "; c #060702", ": c #040406", "> c #070707", ", c #050409", "< c #070709", "1 c #070800", "2 c #08070C", "3 c #080903", "4 c #090B00", "5 c #0A0B03", "6 c #090A05", "7 c #0A0B06", "8 c gray3", "9 c #0B0B09", "0 c #0B0B0B", "q c #0D0E08", "w c #0C0C0C", "e c #0F0F0D", "r c #0F100B", "t c #101109", "y c #10110B", "u c #11110F", "i c #13140C", "p c #121210", "a c gray7", "s c #141510", "d c #161712", "f c #151515", "g c #161616", "h c #21221C", "j c #21221D", "k c #2D2E28", "l c #2F302B", "z c #DDDCE2", "x c #E2E5D2", "c c #E3E7D0", "v c #E2E5D4", "b c #E3E5D7", "n c #E4E7D4", "m c #E4E6D8", "M c #E4E8D1", "N c #E5E8D3", "B c #E6EAD1", "V c #E6EAD3", "C c #E5E8D5", "Z c #E5E8D7", "A c #E6E9D4", "S c #E6E9D6", "D c #E7EAD5", "F c #E7EBD4", "G c #E7EAD7", "H c #E6E9D8", "J c #E6E8DA", "K c #E7E9DB", "L c #E7EAD9", "P c #E7E9DC", "I c #E7E9DE", "U c #E8EBD6", "Y c #E8ECD3", "T c #E8ECD5", "R c #E9ECD7", "E c #E9EDD6", "W c #EAEED7", "Q c #E8EBD8", "! c #E8EBDA", "~ c #E8EADC", "^ c #E8EADD", "/ c #E9EBDD", "( c #E9EBDE", ") c #E9ECD9", "_ c #E9ECDB", "` c #EAEDD8", "' c #EAEDDA", "] c #EBEED9", "[ c #EBEFD8", "{ c #EBEEDB", "} c #EAEDDC", "| c #EAECDE", " . c #EAECDF", ".. c #EBEEDD", "X. c #ECEFDA", "o. c #ECEFDC", "O. c #ECEFDE", "+. c #ECF0D7", "@. c #ECF0D9", "#. c #EDF0DB", "$. c #EDF1DA", "%. c #EDF0DD", "&. c #EEF1DC", "*. c #EEF1DE", "=. c #E1E0E5", "-. c #E1E0E6", ";. c #E5E4E9", ":. c #E8E9E1", ">. c #EBEDE2", ",. c #EBECE4", "<. c #ECEEE0", "1. c #EDEFE1", "2. c #EDEEE6", "3. c #F0F3E0", "4. c #F1F1F1", "5. c #F3F3F3", "6. c #F4F4F6", "7. c #F6F6F8", "8. c #F7F6FC", "9. c #FBFBF9", "0. c gray98", "q. c #FBFBFD", "w. c #FBFAFF", "e. c #FDFEF9", "r. c #FFFFFB", "t. c gray99", "y. c #FDFDFD", "u. c #FCFCFE", "i. c #FDFCFF", "p. c #FDFDFF", "a. c #FEFDFF", "s. c #FEFEFC", "d. c #FFFFFD", "f. c #FEFEFE", "g. c #FEFEFF", "h. c #FFFEFF", "j. c gray100", /* pixels */ "U ` D ! ! L ` ` ! L ` ` D D ! ! ` X.D ! ! ` ` ` ", "` D ` ! ` ` R D R o.X.D ` ` ` R [ n *.` ` ! +.U ", "! D ` X.F ` D ` R ! ! <.P L ! U R R n U ` ` x ..", "! ` D U Y R R R ! ! 1 j ; i ! ! R U U +.D ` ` ! ", "` ` R +.n W o.L o q g g.g.a j o ! ` o.n U U X.! ", "` ! R n +.` P % 9 g.g.g.8.g.g.e 5 m ` U X.U D ` ", "D D ` R ! b ,.q g.g.g.g.g.g.q.g.k 2.P ` X.n U ! ", "! ` n X.L <.; e g.g.r.r.r.9.g.g.# ; P ! D +.U ` ", "X.U X.n X.P 6 g.r.9.g.g.g.g.r.r.g.6 ! ` ! U ! U ", "U o.v o.U P q q.r.g.g.g.0.g.g.0.q.o 1.D ` ` X.U ", "U U ` U U ..; g g.g.g.g.g.g.g.g.a ; ! D X.U D R ", "X.! X.! U ! >.o g.g.g.r.r.g.g.g.; P ..D ! ..! ! ", "U U ! U +.U P o < g.g.g.g.r.g.+ % P D +.! D X.U ", "n o.! ..Y R ` 1.a o 8 w 9 > o u 1.U X.c ..P X.! ", "X.D ! X.R B o.v :.3 5.7.5.5.i ,.! U [ U U ..U U ", "X.U ! ! +.Y U ! ! 5 o 2 , o i I X.R Y X.` ! ` ! ", "! ! ! ` ! ` ! ` P # ;.z -.-.i P X.! ! ` ! ` ! ` ", "! ! ` ! ` ! ` ! R l + d o 8 o ! ` ! ` ! ` ! ` ! ", "R ` ! ` ! ` ! ` P X.D ; ; ! B ..! ` ! ` ! ` ! ` ", "` ! ` ! ` ! ` ! U R ` P ! ! +.U ` ! ` ! ` ! ` ! ", "` ! ` ! ! ` ! ` U R R ..! U X.U ` ! ` ! ! ` ! ` " }; ================================================ FILE: apps/vaporgui/images/magnify.xpm ================================================ /* XPM */ const static char *magnify[] = { /* columns rows colors chars-per-pixel */ "24 21 165 2", " c black", ". c #000100", "X c #010103", "o c #020200", "O c #010005", "+ c #020106", "@ c #0C0D07", "# c #0E0E0E", "$ c #0C0B10", "% c #0F1008", "& c #13140C", "* c #1A1B13", "= c #33342F", "- c #353439", "; c #38373D", ": c #3C3D37", "> c #3D3E36", ", c #3C3D38", "< c #3D3D3B", "1 c #3E3F39", "2 c #3D3C41", "3 c #565752", "4 c #595A54", "5 c #5B5C57", "6 c #676862", "7 c #6A6B63", "8 c #696A65", "9 c #6A6B65", "0 c gray46", "q c #747476", "w c #7E7F77", "e c #78787A", "r c #7C7D78", "t c #7E8073", "y c #808179", "u c #81817F", "i c #838383", "p c #8D8F82", "a c #898989", "s c #8A8A88", "d c #8A8A8C", "f c #8B8B8D", "g c #989A8F", "h c #9B9E8D", "j c #9A9B93", "k c #989896", "l c #999997", "z c #9C9E91", "x c #9D9E99", "c c #AAABA3", "v c #ABABA9", "b c #ABABAD", "n c #AEAEB0", "m c #B4B6AB", "M c #B6B8AD", "N c #B1B1B3", "B c #B2B2B4", "V c #B3B3B5", "C c #B6B6B6", "Z c #BCBEB1", "A c #BABAB8", "S c gray73", "D c #BABABC", "F c #BBBBBD", "G c #BFBFBD", "H c #C2C2C0", "J c gray76", "K c #C2C2C4", "L c #C3C2C7", "P c #C4C4C2", "I c #C7C7C9", "U c #CECFC7", "Y c #CBCBCB", "T c #CACACC", "R c #CBCBCD", "E c gray80", "W c #CCCCCE", "Q c #CDCDCF", "! c #CECED0", "~ c #CFD0CB", "^ c #D1D3C6", "/ c #D0D1C9", "( c #D2D3CD", ") c #DADCCE", "_ c #D0D0D2", "` c #D2D1D6", "' c #D5D5D5", "] c #D7D7D7", "[ c #D6D6D8", "{ c #DDDFD2", "} c #D8D8DA", "| c #DADADC", " . c #DCDCDA", ".. c #DDDDDD", "X. c gray87", "o. c #DFE1D3", "O. c none", "+. c none", "@. c none", "#. c none", "$. c none", "%. c none", "&. c none", "*. c none", "=. c none", "-. c none", ";. c none", ":. c none", ">. c none", ",. c none", "<. c none", "1. c none", "2. c none", "3. c none", "4. c none", "5. c none", "6. c none", "7. c none", "8. c none", "9. c none", "0. c none", "q. c none", "w. c none", "e. c none", "r. c none", "t. c none", "y. c none", "u. c none", "i. c none", "p. c none", "a. c none", "s. c none", "d. c none", "f. c none", "g. c none", "h. c none", "j. c none", "k. c none", "l. c none", "z. c none", "x. c none", "c. c none", "v. c none", "b. c none", "n. c none", "m. c none", "M. c none", "N. c none", "B. c none", "V. c none", "C. c none", "Z. c none", "A. c none", "S. c none", "D. c none", "F. c none", "G. c none", "H. c none", "J. c none", "K. c none", "L. c none", "P. c none", "I. c none", "U. c none", "Y. c none", /* pixels */ "s.3.k.V.q.k.q.k.V.q.=.V.t.=.k.k.k.k.k.k.k.k.k.k.", "C.k.3.t.q.k.k.C.3.q.V.3.t.V.3.V.k.k.k.k.k.k.k.k.", "q.t.k.t.q.3.n.s.I.f.$.n.4.k.k.q.k.k.k.k.k.k.k.k.", "V.=.t.t.C.s.o.z r 4 6 / 4.s.s.q.k.k.k.k.k.k.k.k.", "k.t.s.k.#.^ @.U ' ] v 9 r U.k.V.k.k.k.k.k.k.k.k.", "3.D.3.s.{ J.K. .| T Q C 5 M s.q.k.k.k.k.k.k.k.k.", "k.3.n.n.g ~ X.[ _ W F F u > C.s.k.k.k.k.k.k.k.k.", "q.k.n.f.r .} ` Y T B b k % f.s.k.k.k.k.k.k.k.k.", "w.t.C.f.3 [ ! Q P A P W d # Y.s.s.q.k.k.3.k.3.q.", "t.q.k.f.7 v K L A J ..I q = f.t.V.q.3.k.3.C.D.q.", "k.k.3.s.Z 9 G B b ..B f # c *.O.=.k.t.t.t.3.k.k.", "n.3.p.t.3.w 4 i l s 0 $ + I.w.D.t.w.t.t.t.q.3.", "f.k.k.=.V.f.m > & @ 1 e ; + f.4.H.3.D.t.t.k.3.", "4.q.t.V.t.s.s.I.I.f.o./ s - f.n.k.3.w.k.k.k.", "k.k.3.q.k.#.C.q.4.H.t.3.J.x < Y.4.H.t.t.t.k.", "q.k.k.k.3.H.=.t.n.3.=.A.s.L.j 1 f.4.D.=.k.k.", "k.k.k.k.k.k.k.k.t.w.q.k.t.k.n.h 2 * n.3.t.t.k.", "k.k.k.k.k.k.k.k.t.t.t.3.H.4.k.k.x > p n.k.t.3.k.", "k.k.k.k.k.k.k.k.q.s.H.k.3.k.k.k.f.) k.k.t.t.k.t.", "k.k.k.k.k.k.k.k.k.k.s.k.t.t.t.k.t.t.k.n.4.k.t.t.", "k.k.k.k.k.k.k.k.k.k.q.V.t.t.k.k.2.t.k.n.k.k.t.t." }; ================================================ FILE: apps/vaporgui/images/pauseA.xpm ================================================ /* XPM */ static const char *pause_[] = { /* columns rows colors chars-per-pixel */ "24 17 38 1", " c black", ". c #000002", "X c #010103", "o c #000004", "O c #000005", "+ c #010005", "@ c #010006", "# c #000106", "$ c #000008", "% c #010008", "& c #02000D", "* c #00000E", "= c none", "- c none", "; c none", ": c none", "> c none", ", c none", "< c none", "1 c none", "2 c none", "3 c none", "4 c none", "5 c none", "6 c none", "7 c none", "8 c none", "9 c none", "0 c none", "q c none", "w c none", "e c none", "r c none", "t c none", "y c none", "u c none", "i c none", "p c none", /* pixels */ "qqqqqqqq=iq-;i3=qqqqqqqq", "qqqqqqqq3u8ru8q3qqqqqqqq", "qqqqqqqqi8u;;u8iqqqqqqqq", "qqqqqqqq8u8ii8pwqqqqqqqq", "qqqqqqqq+*+w8+*+qqqqqqqq", "qqqqqqqq$*+wq+*$qqqqqqqq", "qqqqqqqq+++qq$++qqqqqqqq", "qqqqqqqq+++-q+++qqqqqqqq", "qqqqqqqqXXX33XXXqqqqqqqq", "qqqqqqqqXXX:-XXXqqqqqqqq", "qqqqqqqqXXX-:XXXqqqqqqqq", "qqqqqqqqXXX3:XXXqqqqqqqq", "qqqqqqqqXX+q3+XXqqqqqqqq", "qqqqqqq0XX+q-+XXqqqqqqqq", "qqqqqqqqqqqqqqqqqqqqqqqq", "qqqqqqqqqqqqqqqqqqqqqqqq", "qqqqqqqqqqqqqqqqqqqqqqqq", }; ================================================ FILE: apps/vaporgui/images/pauseimage.xpm ================================================ /* XPM */ const static char *pauseimage[] = { /* columns rows colors chars-per-pixel */ "24 21 38 1", " c black", ". c black", "X c black", "o c black", "O c black", "+ c black", "@ c black", "# c black", "$ c black", "% c black", "& c black", "* c black", "= c none", "- c none", "; c none", ": c none", "> c none", ", c none", "< c none", "1 c none", "2 c none", "3 c none", "4 c none", "5 c none", "6 c none", "7 c none", "8 c none", "9 c none", "0 c none", "q c none", "w c none", "e c none", "r c none", "t c none", "y c none", "u c none", "i c none", "p c none", /* pixels */ "qqqqqqqq03:33:31qqqqqqqq", "qqqqqqqqu88uu88uqqqqqqqq", "qqqqqqqq=iq-;i3=qqqqqqqq", "qqqqqqqq3u8ru8q3qqqqqqqq", "qqqqqqqqi8u;;u8iqqqqqqqq", "qqqqqqqq8u8ii8pwqqqqqqqq", "qqqqqqqq+*+w8+*+qqqqqqqq", "qqqqqqqq$*+wq+*$qqqqqqqq", "qqqqqqqq+++qq$++qqqqqqqq", "qqqqqqqq+++-q+++qqqqqqqq", "qqqqqqqqXXX33XXXqqqqqqqq", "qqqqqqqqXXX:-XXXqqqqqqqq", "qqqqqqqqXXX-:XXXqqqqqqqq", "qqqqqqqqXXX3:XXXqqqqqqqq", "qqqqqqqqXX+q3+XXqqqqqqqq", "qqqqqqq0XX+q-+XXqqqqqqqq", "qqqqqqqqqqqqqqqqqqqqqqqq", "qqqqqqqqqqqqqqqqqqqqqqqq", "qqqqqqqqqqqqqqqqqqqqqqqq", "qqqqqqqqqqqqqqqqqqqqqqqq", "qqqqqqqqqqqqqqqqqqqqqqqq" }; ================================================ FILE: apps/vaporgui/images/planes.xpm ================================================ /* XPM */ const static char *planes[] = { /* columns rows colors chars-per-pixel */ "24 21 175 2", " c #292A22", ". c #282826", "X c #2C2E20", "o c #2C2E23", "O c gray16", "+ c #2F3028", "@ c #313325", "# c #30312B", "$ c #33342C", "% c #383A2F", "& c #3A3B35", "* c #3D3F32", "= c #42433B", "- c #41413F", "; c #42433E", ": c #43443C", "> c gray25", ", c #414141", "< c #434247", "1 c #454543", "2 c #454640", "3 c #494A44", "4 c #4B4D42", "5 c #4B4C46", "6 c #4B4C47", "7 c #4C4D45", "8 c #4D4F44", "9 c #4D4E46", "0 c #4E4F47", "q c #4D4E49", "w c #4E4F49", "e c #4E4F4A", "r c #4F4F4D", "t c gray31", "y c #4F5143", "u c #4F5048", "i c #4F504A", "p c #4F504B", "a c #505245", "s c #505247", "d c #515346", "f c #50514B", "g c #51524A", "h c #52534B", "j c #50514C", "k c #50504E", "l c #52534D", "z c #53544C", "x c #56584D", "c c #595B4D", "v c #585A4F", "b c #5A5C4F", "n c #505050", "m c #575852", "M c #585951", "N c #595A52", "B c #5A5B53", "V c #595A54", "C c #595A55", "Z c #5A5B56", "A c #5B5D50", "S c #5B5D52", "D c #5B5C54", "F c #5B5C56", "G c #5C5D55", "H c #5C5D57", "J c #5A5A5C", "K c #5C5D58", "L c #5E5F5A", "P c #5E5E5C", "I c #5E6053", "U c #6F6F6F", "Y c gray44", "T c #717171", "R c #707072", "E c #727270", "W c #727272", "Q c gray45", "! c #727274", "~ c #737375", "^ c #737277", "/ c #747570", "( c #767772", ") c #747474", "_ c #747476", "` c #757577", "' c #737278", "] c #8B8B89", "[ c #8C8C8A", "{ c #8D8D8B", "} c #8D8E88", "| c #8D8D8D", " . c #8D8D8F", ".. c #8E8E8C", "X. c #8F8F8D", "o. c #8E8E90", "O. c #8F8F91", "+. c #90908E", "@. c #91918F", "#. c #929290", "$. c #919096", "%. c #929294", "&. c #B8BAAD", "*. c #B9BBAD", "=. c #B8BAAF", "-. c #B9BCAB", ";. c #BABCAE", ":. c #B6B7B1", ">. c #B7B8B0", ",. c #B8B9B3", "<. c #B9BBB0", "1. c #B9BAB2", "2. c #BABBB3", "3. c #B9BAB4", "4. c #BABCB1", "5. c #BBBCB6", "6. c #E4E7D4", "7. c #E4E6D9", "8. c #E5E7D9", "9. c #E5E9D2", "0. c #E7EBD0", "q. c #E6EAD3", "w. c #E7EBD2", "e. c #E5E8D5", "r. c #E5E8D7", "t. c #E6E9D4", "y. c #E6E9D6", "u. c #E7EAD5", "i. c #E7EBD4", "p. c #E7EAD7", "a. c #E6E9D8", "s. c #E6E8DA", "d. c #E7EAD9", "f. c #E7E9DC", "g. c #E7E9DE", "h. c #E8EBD6", "j. c #E8ECD3", "k. c #E8ECD5", "l. c #E9EDD4", "z. c #E9ECD7", "x. c #E9EDD6", "c. c #EAEED5", "v. c #EBEFD4", "b. c #EAEED7", "n. c #EBEFD6", "m. c #E8EBD8", "M. c #E8EBDA", "N. c #E8EADC", "B. c #E9EBDD", "V. c #E9EBDE", "C. c #E9ECD9", "Z. c #E9ECDB", "A. c #EAEDD8", "S. c #EAEDDA", "D. c #EBEED9", "F. c #EBEFD8", "G. c #EBEEDB", "H. c #EAEDDC", "J. c #EAECDE", "K. c #EAECDF", "L. c #EBEEDD", "P. c #ECEFDA", "I. c #ECEFDC", "U. c #ECEFDE", "Y. c #ECF0D5", "T. c #ECF0D7", "R. c #ECF0D9", "E. c #EDF0DB", "W. c #EFF3DC", "Q. c #E9EBE0", "!. c #E9EAE2", "~. c #EBEDE0", "^. c #ECEEE0", "/. c #EEF1E0", "(. c #EFF2E1", /* pixels */ "G.x.x.h.h.h.P.h.h.x.!.P.0.U.h.M.p.G.h.G.x.9.x.h.", "p.G.G.h.x.6.h.m.G.p.m.9.9.U.P.M.G.6.U.p.x.P.9.G.", "h.9.h.h.p.U.G.M.% n.P.h.U.& p.m.m.U.* !.x.p.W.p.", "G.G.G.h.p.G.g.B 1 9.G.m.m - x.m.g.x = U.G.9.9.G.", "G.6.p.P.P.G.7 ( - n.p.a #., h.M.g 4.: 7.P.P.x.p.", "p.m.P.p.7.4 ( E r x.y } o.e P.7 >.>.h G.G.x.h.p.", "U.p.p.P.m.z E ' P 9.g .%.B x.k ;.*.x !.p.x.G.G.", "m.G.h.h.M.F Y ' C P.C $.o.b x.J -.*.b G.G.9.G.m.", "G.p.G.9.G.F ! ( H G.C +.} K m.H *.2.C m.x.m.m.m.", "9.G.G.x.p.k Y Q 7 G.k #. .e h.g *.:.k p.x.G.G.p.", "9.G.m.G.m.e ! ' 7 G.e ] #.e m.a *.2.e m.x.G.m.x.", "x.G.m.x.P.m ) ! 7 P.K +.+.5 G.H *.5.6 G.p.h.G.p.", "x.G.G.p.G.B ! ! - G.C X.X.- G.B *.2.2 p.h.G.M.h.", "x.p.G.p.m.H ! E 7 G.C X.#.e G.B *.2.5 m.h.G.G.h.", "G.p.p.9.G.C ) Q g G.K X.} e p.B ;.5.e G.h.p.m.G.", "x.G.G.x.m.e E Q 7 G.e #.X.e G.7 ;.>.e p.x.G.U.m.", "p.G.9.x.m.n ' Q I p.e O. .K h.e >.4.x G.G.p.x.x.", "p.G.G.x.G.- U h p.G.< O.8 G.P., 4.d M.p.p.h.G.h.", "m.G.p.9.G. $ p.G.p.O + G.x.x.O @ p.G.G.x.G.p.m.", "G.e.Z.G.G.o U.x.p.x.o p.G.p.q.+ G.G.p.x.h.p.m.h.", "9.(.m.h.U.Q.g.q.g.Y.p.(.6.G.x.!.m.m.x.h.x.h.m.m." }; ================================================ FILE: apps/vaporgui/images/playforward.xpm ================================================ /* XPM */ const static char *playforward[] = { /* columns rows colors chars-per-pixel */ "24 21 95 2", " c black", ". c black", "X c black", "o c black", "O c black", "+ c black", "@ c black", "# c black", "$ c black", "% c black", "& c black", "* c black", "= c black", "- c black", "; c black", ": c black", "> c black", ", c black", "< c black", "1 c black", "2 c none", "3 c none", "4 c none", "5 c none", "6 c none", "7 c none", "8 c none", "9 c none", "0 c none", "q c none", "w c none", "e c none", "r c none", "t c none", "y c none", "u c none", "i c none", "p c none", "a c none", "s c none", "d c none", "f c none", "g c none", "h c none", "j c none", "k c none", "l c none", "z c none", "x c none", "c c none", "v c none", "b c none", "n c none", "m c none", "M c none", "N c none", "B c none", "V c none", "C c none", "Z c none", "A c none", "S c none", "D c none", "F c none", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", "| c none", " . c none", ".. c none", "X. c none", /* pixels */ "L L L L L L L L L L n [ L A n A L L L L L L L L ", "L L L L L L L L J L ) M M L ' l L L L L L L L L ", "L L L L L L L L L l L L .J ) Q L L L L L L L L ", "L L L L L L L L A A A l L J ) Q L L L L L L L L ", "L L L L L L L L n I z Z A l n L L L L L L L L L ", "L L L L L L L L Q / L n A L I A L L L L L L L L ", "L L L L L L L L e y .. .J M A n L L L L L L L L ", "L L L L L L L L , % 7 p Q / J J L L L L L L L L ", "L L L L L L L L % , , , w t .n L l N N M A M / ", "L L L L L L L L o O % % 1 6 u Q ) ) M M M l M ", "L L L L L L L L O % = r h S Q L L A A ", "L L L L L L L L % % % 4 q d S X./ n M A M ", "L L L L L L L L % : 2 q i g J ) F l A A L L ", "L L L L L L L L : 3 9 a f } H A z A A L n L L ", "L L L L L L J J 6 9 s j | F [ z n A A M z L L / ", "L L L L L L L F d } / n ' n L / / L L A A L F L ", "L L L L L L L L L L L L L L L L L L L L L L L L ", "L L L L L L L L L L L L L L L L L L L L L L L L ", "L L L L L L L L L L L L L L L L L L L L L L L L ", "L L L L L L L L L L L L L L L L L L L L L L L L ", "L L L L L L L L L L L L L L L L L L L L L L L L " }; ================================================ FILE: apps/vaporgui/images/playforwardA.xpm ================================================ /* XPM */ const static char *playforward[] = { /* columns rows colors chars-per-pixel */ "24 17 95 2", " c black", ". c #000002", "X c gray1", "o c #040500", "O c #040402", "+ c #000004", "@ c #000005", "# c #010005", "$ c #020204", "% c #010006", "& c #000007", "* c #010008", "= c #000009", "- c #00000B", "; c #02000B", ": c #040309", "> c #04030B", ", c #00000C", "< c #00000E", "1 c #08070D", "2 c #43414C", "3 c #46454D", "4 c #4D4C51", "5 c #605F67", "6 c #67666B", "7 c #767676", "8 c #76757B", "9 c #75747C", "0 c #78777F", "q c #7B7A80", "w c #7B7984", "e c #878789", "r c #8A8A88", "t c #9F9F9F", "y c #A7A7A5", "u c #A4A4A6", "i c #A7A6AB", "p c #B2B3AB", "a c #ABAAB0", "s c #B2B2B4", "d c #BBBCB7", "f c #BCBCBA", "g c #BABABC", "h c #C0C1BC", "j c #C2C3BE", "k c none", "l c none", "z c none", "x c none", "c c none", "v c none", "b c none", "n c none", "m c none", "M c none", "N c none", "B c none", "V c none", "C c none", "Z c none", "A c none", "S c none", "D c none", "F c none", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", "| c none", " . c none", ".. c none", "X. c #F2F4E9", /* pixels */ "L L L L L L L L L l L L .J ) Q L L L L L L L L ", "L L L L L L L L A A A l L J ) Q L L L L L L L L ", "L L L L L L L L n I z Z A l n L L L L L L L L L ", "L L L L L L L L Q / L n A L I A L L L L L L L L ", "L L L L L L L L e y .. .J M A n L L L L L L L L ", "L L L L L L L L , % 7 p Q / J J L L L L L L L L ", "L L L L L L L L % , , , w t .n L l N N M A M / ", "L L L L L L L L o O % % 1 6 u Q ) ) M M M l M ", "L L L L L L L L O % = r h S Q L L A A ", "L L L L L L L L % % % 4 q d S X./ n M A M ", "L L L L L L L L % : 2 q i g J ) F l A A L L ", "L L L L L L L L : 3 9 a f } H A z A A L n L L ", "L L L L L L J J 6 9 s j | F [ z n A A M z L L / ", "L L L L L L L F d } / n ' n L / / L L A A L F L ", "L L L L L L L L L L L L L L L L L L L L L L L L ", "L L L L L L L L L L L L L L L L L L L L L L L L ", "L L L L L L L L L L L L L L L L L L L L L L L L ", }; ================================================ FILE: apps/vaporgui/images/playreverse.xpm ================================================ /* XPM */ const static char *playreverse[] = { /* columns rows colors chars-per-pixel */ "24 21 95 2", " c black", ". c black", "X c black", "o c black", "O c black", "+ c black", "@ c black", "# c black", "$ c black", "% c black", "& c black", "* c black", "= c black", "- c black", "; c black", ": c black", "> c black", ", c black", "< c black", "1 c black", "2 c none", "3 c none", "4 c none", "5 c none", "6 c none", "7 c none", "8 c none", "9 c none", "0 c none", "q c none", "w c none", "e c none", "r c none", "t c none", "y c none", "u c none", "i c none", "p c none", "a c none", "s c none", "d c none", "f c none", "g c none", "h c none", "j c none", "k c none", "l c none", "z c none", "x c none", "c c none", "v c none", "b c none", "n c none", "m c none", "M c none", "N c none", "B c none", "V c none", "C c none", "Z c none", "A c none", "S c none", "D c none", "F c none", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", "| c none", " . c none", ".. c none", "X. c none", /* pixels */ "L L L L L L L L Z Z Z M _ b L L K P K P K P K P ", "L L L L L L L L b L L F M _ K L P K P K P K P K ", "L L L L L L L L W ( K _ L L l I K P K P K P K P ", "L L L L L L L L W _ K Z b M M Z P K P K P K P K ", "L L L L L L L L L b l Z ` b I b K P K P K P K P ", "L L L L L L L L L I L b M Z ( W P K P K P K P K ", "L L L L L L L L M Z b Z _ ..y e K P K P K P K P ", "L L L L L L L L W F ( W p 7 = = P K P K P K P K ", "W M Z M c c l Z M .t w < = > & K P K P K P K P ", "I b M K M ( _ K y 6 1 . & . . o P K P K P K P K ", "Z M Z L W S j r = & . . . o . . K P K P K P K P ", "M M M M W X.S d q 4 & . . . & . P K P K P K P K ", "K I M I c M _ L g i 0 2 > & . . K P K P K P K P ", "K K M I P c c P W | f a 8 3 : . P K P K P K P K ", "K K K c M I K M c ] b | j s 8 5 K P K P K P K P ", "I M P M M I K W ( K M P M _ | f P K P K P K P K ", "K T K P K P K P K P K P K P K P K P K P K P K P ", "T K P K P K P K P K P K P K P K P K P K P K P K ", "K P K P K P K P K P K P K P K P K P K P K P K P ", "P K P K P K P K P K P K P K P K P K P K P K P K ", "P K P K K P K P K P K P P K P K P K P K K P K P " }; ================================================ FILE: apps/vaporgui/images/playreverseA.xpm ================================================ /* XPM */ const static char *playreverse[] = { /* columns rows colors chars-per-pixel */ "24 17 95 2", " c black", ". c #000002", "X c gray1", "o c #040500", "O c #040402", "+ c #000004", "@ c #000005", "# c #010005", "$ c #020204", "% c #010006", "& c #000007", "* c #010008", "= c #000009", "- c #00000B", "; c #02000B", ": c #040309", "> c #04030B", ", c #00000C", "< c #00000E", "1 c #08070D", "2 c #43414C", "3 c #46454D", "4 c #4D4C51", "5 c #605F67", "6 c #67666B", "7 c #767676", "8 c #76757B", "9 c #75747C", "0 c #78777F", "q c #7B7A80", "w c #7B7984", "e c #878789", "r c #8A8A88", "t c #9F9F9F", "y c #A7A7A5", "u c #A4A4A6", "i c #A7A6AB", "p c #B2B3AB", "a c #ABAAB0", "s c #B2B2B4", "d c #BBBCB7", "f c #BCBCBA", "g c #BABABC", "h c #C0C1BC", "j c #C2C3BE", "k c none", "l c none", "z c none", "x c none", "c c none", "v c none", "b c none", "n c none", "m c none", "M c none", "N c none", "B c none", "V c none", "C c none", "Z c none", "A c none", "S c none", "D c none", "F c none", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", "| c none", " . c none", ".. c none", "X. c #F2F4E9", /* pixels */ "L L L L L L L L W ( K _ L L l I K P K P K P K P ", "L L L L L L L L W _ K Z b M M Z P K P K P K P K ", "L L L L L L L L L b l Z ` b I b K P K P K P K P ", "L L L L L L L L L I L b M Z ( W P K P K P K P K ", "L L L L L L L L M Z b Z _ ..y e K P K P K P K P ", "L L L L L L L L W F ( W p 7 = = P K P K P K P K ", "W M Z M c c l Z M .t w < = > & K P K P K P K P ", "I b M K M ( _ K y 6 1 . & . . o P K P K P K P K ", "Z M Z L W S j r = & . . . o . . K P K P K P K P ", "M M M M W X.S d q 4 & . . . & . P K P K P K P K ", "K I M I c M _ L g i 0 2 > & . . K P K P K P K P ", "K K M I P c c P W | f a 8 3 : . P K P K P K P K ", "K K K c M I K M c ] b | j s 8 5 K P K P K P K P ", "I M P M M I K W ( K M P M _ | f P K P K P K P K ", "K T K P K P K P K P K P K P K P K P K P K P K P ", "T K P K P K P K P K P K P K P K P K P K P K P K ", "K P K P K P K P K P K P K P K P K P K P K P K P ", }; ================================================ FILE: apps/vaporgui/images/probe.xpm ================================================ /* XPM */ const static char *probe[] = { /* columns rows colors chars-per-pixel */ "24 21 128 2", " c black", ". c black", "X c black", "o c black", "O c black", "+ c black", "@ c black", "# c black", "$ c black", "% c black", "& c black", "* c black", "= c black", "- c black", "; c black", ": c black", "> c black", ", c black", "< c black", "1 c black", "2 c black", "3 c black", "4 c black", "5 c black", "6 c black", "7 c black", "8 c black", "9 c black", "0 c black", "q c black", "w c black", "e c black", "r c black", "t c black", "y c black", "u c black", "i c black", "p c black", "a c black", "s c black", "d c black", "f c black", "g c black", "h c black", "j c black", "k c black", "l c black", "z c black", "x c black", "c c none", "v c none", "b c none", "n c none", "m c none", "M c none", "N c none", "B c none", "V c none", "C c none", "Z c none", "A c none", "S c none", "D c none", "F c none", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", "| c none", " . c none", ".. c none", "X. c none", "o. c none", "O. c none", "+. c none", "@. c none", "#. c none", "$. c none", "%. c none", "&. c none", "*. c none", "=. c none", "-. c none", ";. c none", ":. c none", ">. c none", ",. c none", "<. c none", "1. c none", "2. c none", "3. c none", "4. c none", "5. c none", "6. c none", "7. c none", "8. c none", "9. c none", "0. c none", "q. c none", "w. c none", "e. c none", "r. c none", "t. c none", "y. c none", "u. c none", /* pixels */ "X.X.X.X.X.X.X.X.( ( ( #.X.=.X.X.( #.m #.U ..X.( ", "X.X.X.X.X.X.X.X... .=.B =.P . ...P ] ( X.$.X.P ", "X.X.X.X.X.X.X.X.U X.X.X.( ] ^ ,. .1.( ( P X./ <.", "X.X.X.X.X.X.X.X.#.( P X.P X.P P y.N X.X.X.N u.m ", "X.X.X.X.X.X.X.X.B u.% % 3 l > s % e N ( P #.P 5.", "X.X.X.X.X.X.X.X.6.B D % > > 8 > t < =.X.U =.X.P ", "X.X.X.X.X.X.X.X.n / ..e.% 5 % < > t U X.P X.U X.", "X.X.X.X.X.X.X.X.X.e.v % r % % % > % >.P #.X.X.( ", "P X.X...P X.( ( w.C % % % % y > % % S N 6./ P X.", "1.P ( ..X.P 1.N q.g 5 5 > x % % % % e.1.m X.( =.", "N 1.X.( X.1.A e.% % % y % % i w.% % ..=.X.X.P X.", "..P ( #.X.N c % % x % > p % ..X.q.< ..P ( ( X.#.", "X.1.( X.P e.q > t % k % % D X.#.....X.X.X.X.P X.", "P N X.1.D % g > % % % < e.D X.( X.X.X.X.U P 1.X.", "<.X.B u.% 5 > > s % i D ..X.( X.( X.( P X.1.P ( ", "^ / 1.D q % > : : % q.N X.X.U X.X.P X.X...P X.X.", "X.X.( ( ..< % % 6 S ..( X.X.( X.X.X.X.X.X.X.X.X.", "X./ X.X.N ..i % S >.( P ( X.#.X.X.X.X.X.X.X.X.X.", "( X.X.P .. .e. ...X.( #.U X.P <.X.X.X.X.X.X.X.X.", "X.( U =.X.X.P ( X./ X.X.D e.X.( X.X.X.X.X.X.X.X.", "X.( X...X.X.P ( X.( X.X.N e.X.( X.X.X.X.X.X.X.X." }; ================================================ FILE: apps/vaporgui/images/rake.xpm ================================================ /* XPM */ const static char *rake[] = { /* columns rows colors chars-per-pixel */ "26 23 82 1", " c #040404", ". c #040308", "X c #090A05", "o c #0A0B0A", "O c #100F14", "+ c #131314", "@ c #16151A", "# c gray11", "$ c #232323", "% c #2B2C29", "& c #2C2B31", "* c #343434", "= c #393A36", "- c #3D3D3C", "; c #494949", ": c #51524A", "> c #505050", ", c #5F5F5F", "< c #626262", "1 c #6C6C6C", "2 c #737373", "3 c #7A7A7A", "4 c #848483", "5 c #878880", "6 c #8A8B84", "7 c #8B8B89", "8 c #91928B", "9 c #9A9C8F", "0 c #959595", "q c #9A9B94", "w c #9C9C9A", "e c #9C9BA0", "r c #9FA194", "t c #A1A29C", "y c #ABAD9F", "u c #A4A4A2", "i c #ABACA3", "p c #ABABAB", "a c #A7A5B2", "s c #ADABB6", "d c #B2B5A4", "f c #B3B5A9", "g c #B7B9AE", "h c #B2B2B2", "j c #B7B8B0", "k c #B8B7BC", "l c #B9B9B4", "z c #BABABB", "x c #BEBDC3", "c c #BFC1B3", "v c #C2C3BC", "b c #C7C9BC", "n c #CACDBD", "m c #C1C1C3", "M c #C7C8C3", "N c #C8C7CC", "B c #CACCC3", "V c #CBCBCA", "C c #D0CFD4", "Z c #D0D2C7", "A c #D7D9CB", "S c #DADDCC", "D c #D7D7D5", "F c #DCDCDA", "G c #DEE1CC", "H c #DEE0D4", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", /* pixels */ "PYYKPYUJUPURYU!IUUUUUUUUUU", "YUY/TKURURPKTYITUUUUUUUUUU", "YPPPIIYYUKTRJPYPUUUUUUYUUU", "YPTYcqfYTRUURUGTUUUUUUUUUU", "YPPYYFj6fK!KU~YPUUIUUUUUUU", "PY~Fi8iVuwlIYKTYUUUUUUUUUU", "UPIIIEVwphuwrB^KUUUUUUUUUU", "PUUbq8pNxpp0=:ZWUUUUUUUUUU", "UP!KEYDhuppw*>17HWWLIYYPUU", "UPGy88wwhpp4$23-%6H^IY!TTI", "PPTLQQFNhpp4&33;@o-qVcpiq7", "!KBrrrupppp2$21,&O.o XooO ", "KY~IQEVxzhk3$73;@.$<678685", "TIAiruhxhpp2$3,;=2MQYI!!YI", "IY~EEFmeppu2%230AY!IHYTJUU", "YIFfqumNhpp1#sQE!IIYTYJUYY", "UUUHECsazpuiyIUUUUUUUUUUUU", "TJIBtlVkivIYGYPUUUUUUUUUUU", "JY~~YgrVUY!TUTUPUUUUUUUUUU", "~K!Adn!KUUJKUYYYUUUUUUUUUU", "ILYYYUGTUYTUUUUYUUUUUUUUUU", "IW!II!UYYYYUKUYUUUUUUUUUUU", "IY!II!YEEW!!K/YUUUUUUUUUUU" }; ================================================ FILE: apps/vaporgui/images/replayA.xpm ================================================ /* XPM */ static const char *replay_[] = { /* columns rows colors chars-per-pixel */ "24 17 196 2", " c black", ". c #000002", "X c #020202", "o c #000004", "O c #010204", "+ c #000007", "@ c #020106", "# c #030207", "$ c #060606", "% c #000009", "& c #020109", "* c #030208", "= c #020308", "- c #00000A", "; c #01010B", ": c #040509", "> c #00000C", ", c #01000D", "< c #02000D", "1 c #00000E", "2 c #01000E", "3 c #01000F", "4 c #050311", "5 c #121214", "6 c #141517", "7 c #151517", "8 c #15141A", "9 c #18181A", "0 c #20201E", "q c #171427", "w c #1F1E23", "e c #201F24", "r c #27262B", "t c #2C2D28", "y c #29282D", "u c #29282E", "i c #2A292E", "p c #2D2D2F", "a c #2B2936", "s c #2C2A37", "d c #303133", "f c #333237", "g c #363837", "h c #393B38", "j c gray24", "k c #3F403B", "l c #41423D", "z c #343146", "x c #383641", "c c #403F45", "v c #444540", "b c #444446", "n c #464648", "m c #48474C", "M c #51524D", "N c #52554E", "B c #444250", "V c #494850", "C c #4C4B51", "Z c #505251", "A c #505052", "S c #525254", "D c #595957", "F c #55545A", "G c #56555B", "H c #5B5B59", "J c #5F6064", "K c #656563", "L c #616065", "P c #656764", "I c #676475", "U c #6A6873", "Y c #706E79", "T c #757573", "R c #7B7C74", "E c #7C7D78", "W c #777580", "Q c #787684", "! c #7D7B88", "~ c #7F7D88", "^ c #848388", "/ c #89888E", "( c #90908E", ") c #8B8A92", "_ c #908E99", "` c #949398", "' c #9D9E99", "] c #A2A1A9", "[ c #A4A3A8", "{ c #B0AFB7", "} c #B9B8BE", "| c #C1C1BF", " . c #BEBFC3", ".. c none", "X. c none", "o. c none", "O. c none", "+. c none", "@. c none", "#. c none", "$. c none", "%. c none", "&. c none", "*. c none", "=. c none", "-. c none", ";. c none", ":. c none", ">. c none", ",. c none", "<. c none", "1. c none", "2. c none", "3. c none", "4. c none", "5. c none", "6. c none", "7. c none", "8. c none", "9. c none", "0. c none", "q. c none", "w. c none", "e. c none", "r. c none", "t. c none", "y. c none", "u. c none", "i. c none", "p. c none", "a. c none", "s. c none", "d. c none", "f. c none", "g. c none", "h. c none", "j. c none", "k. c none", "l. c none", "z. c none", "x. c none", "c. c none", "v. c none", "b. c none", "n. c none", "m. c none", "M. c none", "N. c none", "B. c none", "V. c none", "C. c none", "Z. c none", "A. c none", "S. c none", "D. c none", "F. c none", "G. c none", "H. c none", "J. c none", "K. c none", "L. c none", "P. c none", "I. c none", "U. c none", "Y. c none", "T. c none", "R. c none", "E. c none", "W. c none", "Q. c none", "!. c none", "~. c none", "^. c none", "/. c none", "(. c none", "). c none", "_. c none", "`. c none", "'. c none", "]. c none", "[. c none", "{. c none", "}. c none", "|. c none", " X c none", ".X c none", "XX c none", "oX c none", "OX c none", "+X c none", "@X c none", "#X c none", "$X c none", "%X c none", "&X c none", "*X c none", /* pixels */ ";.`.Z.v.].z.j.+X+Xz.z.m.m.F.u.%._.y.y.m.v.T.;.v.", "Z.y.y.;.;.I.].p.z.T.T.z.m.m.m./.6.y.Z.;.Z.`.y.v.", "Z.;.y.v._._.+.`.y.6.(.y.y.Z.m.m.Z.;.;.{.;.;.;.0.", "m.m.Z.v.+.v.].m.Z.j.{.;.T.d.' j j.@X{.;.Z.0.0.Z.", "m.'.+.`.v.I.}.( C b b n m V a 4 t Xz.;._.Z.Z.Z.", "y.6.y.Z.+X| G - < - - . . : + < . k T._.6.y.F.m.", "6.;.y.6.+XU < 6 I Q Y E ! ! B 4 d |.+Xz.Z.T.%.6.", "/.I.Z.v.T.p + N (.X.6...m.@XR v z.T w P j.y.T.j.", "u.0.Z.y.j.6 - Z z.T.T.Z.%.;.@XL.T.H + 9 j.6.;.%X", "%._.%.F.T.l 5 J } A E +XZ.Z.Z.;.z.M $ 0 T.y._.y.", "/.L.@./.j.].z.+Xx + F ` ^ / ) _ P 8 - Z m.6.%.F.", "m.0.F.m.Z.%.+Xh . . . . $ + + < + < z ] j.6.Z.z.", "1._.%.m.Z.y.T. .q < a i r i i w g L [ }.{.%.m.+X", "L.0.0.E.y.o.Z.$X{ f H *Xj.F.;.Z.+Xm.y.X.6.y.;.y.", "m.Z.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.", "y.m.Z.y.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.", "Z.Z.m.j.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.", }; ================================================ FILE: apps/vaporgui/images/sethome.xpm ================================================ /* XPM */ const static char *sethome[] = { /* columns rows colors chars-per-pixel */ "24 21 157 2", " c black", ". c #000100", "X c #010100", "o c #010101", "O c #000002", "+ c #010103", "@ c #000200", "# c #010200", "$ c #010300", "% c #020200", "& c #020300", "* c #020202", "= c #000004", "- c #000005", "; c #010005", ": c #020204", "> c #030305", ", c #030400", "< c #040500", "1 c #050503", "2 c #050601", "3 c gray2", "4 c #040406", "5 c #050507", "6 c #000009", "7 c #040308", "8 c #91928C", "9 c #91928D", "0 c #93948F", "q c #94968B", "w c #95978C", "e c #96978F", "r c #9A9C8E", "t c #919193", "y c #949492", "u c #969791", "i c #969792", "p c #949496", "a c #969694", "s c #979795", "d c #979893", "f c #9A9B93", "g c #989994", "h c #999997", "j c #9A9B95", "k c gray60", "l c #9A9A9A", "z c #C0C2B7", "x c #C1C1C1", "c c #C2C2C0", "v c #C3C3C1", "b c #C3C3C5", "n c #C5C5C5", "m c none", "M c none", "N c none", "B c none", "V c none", "C c none", "Z c none", "A c none", "S c none", "D c none", "F c none", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", "| c none", " . c none", ".. c none", "X. c none", "o. c none", "O. c none", "+. c none", "@. c none", "#. c none", "$. c none", "%. c none", "&. c none", "*. c none", "=. c none", "-. c none", ";. c none", ":. c none", ">. c none", ",. c none", "<. c none", "1. c none", "2. c none", "3. c none", "4. c none", "5. c none", "6. c none", "7. c none", "8. c none", "9. c none", "0. c none", "q. c none", "w. c none", "e. c none", "r. c none", "t. c none", "y. c none", "u. c none", "i. c none", "p. c none", "a. c none", "s. c none", "d. c none", "f. c none", "g. c none", "h. c none", "j. c none", "k. c none", "l. c none", "z. c none", "x. c #F0F3E2", "c. c #F0F1E9", "v. c #F2F3EE", "b. c #F6F7EF", "n. c #F0F0F2", "m. c #F3F3F3", "M. c #F5F5F3", "N. c gray96", "B. c gray97", "V. c #F5F4FA", "C. c #F7F8F3", "Z. c #FBFBF9", "A. c #FDFDFD", "S. c #FDFDFF", "D. c #FEFEFE", "F. c #FFFEFF", "G. c gray100", /* pixels */ "&.G W >.S >.S ) ) ) P i.+.) ^ &.&.S ^ ^ W Y G ) ", "G >.) W W ) G &.) ) &.o o ) G &.+.&.S S &.&.&.&.", "W ) m ) 2.&.W G 2.^ s.o o E ) s.s.P &.) G k.&.G ", "&.W ) &.Y G &.&.S P &.o * G +.w y o &.&.G P G &.", "S W >.W G +.&.Y k.W p o o o G k 7.* P &.&.&.L L ", ">.) &.G &.Y P &.P j z.: : +.o d r.o k.G &.L L ) ", "S S W &.Y P x.N y b.7 : 5 o Y * r.o +.S L 2.G &.", ") &.G >.) &.N r b.o b 6 o z * s.o o P &.&.G &.G ", "&.G ) ) ) &.9 V.o x A.o 7 j.n o s.* +.Q &.L ^ &.", ") 2.R +.E e N.o x Z.A.B.j.N.5.x * q.* &.u.&.&.P ", "Q P * o o 3 o o o 3 v.j.C.5.o o o * o o o * &.s.", "[ G o o o o o o : o p f y h o o o o o o * o S +.", "L +.E R +.g.y A.A.n.k A.h.k 7.6.+.* Y k.R k.^ L ", "&.&.S 2.S G 8 A.N.w.p o o y q.w.G * +.L s.m [ L ", "S &.) ) S &.j A.B y.y o : d 5.R P * M ^ 4.L ^ L ", ") G &.) &.&.w y.+.E d o o d E +.+.o &.[ L &.L &.", "&.G [ L [ P * o o o o : : o o o o o G &.Q [ L &.", "&.&.L &.L &.+.Y ) ) &.o o +.) ) R +.&.L &.G &.} ", "G &.G G &.&.} &.+.G +.o o E S &.&.L &.&.G Q &.S ", ") G &.&.L [ L L +.) &.o o &.) +.) L ) L +.&.L ) ", "[ L &.&.L L Q L Y &.L +.+.L ) } ^ L ) } &.+.L [ " }; ================================================ FILE: apps/vaporgui/images/sphere.xpm ================================================ /* XPM */ const static char *sphere[] = { /* columns rows colors chars-per-pixel */ "20 20 42 1", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c gray3", "$ c #090909", "% c gray4", "& c #0C0C0C", "* c gray5", "= c #0E0E0E", "- c #101010", "; c #131313", ": c gray9", "> c #1B1B1B", ", c #E6E6E6", "< c #E7E7E7", "1 c #E9E9E9", "2 c #EAEAEA", "3 c gray92", "4 c #ECECEC", "5 c gray93", "6 c #EEEEEE", "7 c #EFEFEF", "8 c gray94", "9 c #F1F1F1", "0 c gray95", "q c #F3F3F3", "w c #F4F4F4", "e c gray96", "r c #F6F6F6", "t c gray97", "y c #F8F8F8", "u c #F9F9F9", "i c gray98", "p c #FBFBFB", "a c gray99", "s c #FDFDFD", "d c #FEFEFE", "f c gray100", /* pixels */ "dddrdddddtddddddttdd", "rd00d6tdd6dtdddrdddr", "dddd0dd00dddrddd2ddd", "drdddr<>.%..;rdtdd6d", "tdd6d%..d.d.d.&dddd2", "dddt+d;d.t&d.dr.dttd", "dtd;0.6d%d.td.dd.tdd", "dd.td.d.dtd%r+rdd%td", "td&td.d.ddd.d.ddd.dt", "d.0d.dt%tdd.dd%ddt.t", "t.dd%dd.d2d+dd.ddd.t", "d%dd.dd%rtd.6d.d0d.d", "d2.d0+t%dd0+d.d0d.t6", "td.dd.d.ddr.0&2dd.dd", "d0d.r&0d.d&dd.dd.ddd", "drdd+t.d%r.d.rd.dddt", "dtddt+.+d-t.d..ddddd", "d6dd0dd......trddddd", "ddtddddddddddtd6dddd", "ddr0ddrdtdt c #16000A", ", c #170E00", "< c #1C0000", "1 c #1F000C", "2 c #110012", "3 c #19031A", "4 c #131300", "5 c #000221", "6 c #00002E", "7 c #080020", "8 c #000930", "9 c #0B0930", "0 c #001623", "q c #00152C", "w c #001D33", "e c #180026", "r c #002716", "t c #00241A", "y c #022123", "u c #002820", "i c #00263D", "p c #240000", "a c #230009", "s c #2B0002", "d c #201B18", "f c #320100", "g c #31000C", "h c #3D0000", "j c #310810", "k c #24192A", "l c #000443", "z c #000B40", "x c #145B4D", "c c #13695E", "v c #0C6D66", "b c #176963", "n c #116F6E", "m c #1A6D65", "M c #156677", "N c #106579", "B c #156A73", "V c #1F6376", "C c #1B7C74", "Z c #1D7F7E", "A c #205C5D", "S c #2C676B", "D c #2B7167", "F c #297569", "G c #2C797F", "H c #336A65", "J c #3C626D", "K c #3D6C76", "L c #327D74", "P c #307A7B", "I c #3C7972", "U c #460906", "Y c #630000", "T c #6E0000", "R c #762218", "E c #693935", "W c #7F2A41", "Q c #574E2F", "! c #446061", "~ c #614544", "^ c #3C7588", "/ c #427684", "( c #2C8073", ") c #36879A", "_ c #7987A1", "` c #6EA3B5", "' c #5B83CB", "] c #56BFC5", "[ c #6992D4", "{ c #7F9BE5", "} c #65CAB8", "| c #69D0BB", " . c #5FC3C5", ".. c #62C5C4", "X. c #68CFD4", "o. c #65D1C1", "O. c #63D9DD", "+. c #79D3C7", "@. c #72DED1", "#. c #77E7CF", "$. c #77E0DB", "%. c #70E7ED", "&. c #8E2D2B", "*. c #842932", "=. c #933E3B", "-. c #AD160F", ";. c #B10A02", ":. c #B4120D", ">. c #A61E20", ",. c #A3271D", "<. c #B12116", "1. c #9B2B44", "2. c #D8231C", "3. c #C42A20", "4. c #ED6F3D", "5. c #D27F5D", "6. c #C07764", "7. c #DB7863", "8. c #E17E45", "9. c #F66F52", "0. c #8277BC", "q. c #8D7CB2", "w. c #9077B8", "e. c #CE7D84", "r. c #BD8F5E", "t. c #BF8E6E", "y. c #C1925E", "u. c #DF8B66", "i. c #DB886A", "p. c #D38B7D", "a. c #FB9C5C", "s. c #E88A7E", "d. c #E29166", "f. c #E9976F", "g. c #FF8C69", "h. c #86858D", "j. c #8784BD", "k. c #8D90B9", "l. c #9182B9", "z. c #9895B4", "x. c #B58E87", "c. c #A5BDA7", "v. c #AEB3AD", "b. c #8D89C4", "n. c #8F8DCE", "m. c #968CC0", "M. c #9E8ACF", "N. c #9598C1", "B. c #96D1B1", "V. c #87D2D8", "C. c #93D5D4", "Z. c #CA9B89", "A. c #CA96A2", "S. c #E4948B", "D. c #FF8D80", "F. c #F0A387", "G. c #DCDADB", "H. c #DCE1E1", "J. c #D2FDF9", "K. c #D9F7F9", "L. c #DDFFFC", "P. c #E8DDE3", "I. c #F6E3DF", "U. c #FFF8DB", "Y. c #E5E3E8", "T. c #E5ECEC", "R. c #EBE3EB", "E. c #E9EAEF", "W. c #E6E8F5", "Q. c #E7F0EF", "!. c #E8F2EA", "~. c #ECFFEE", "^. c #E6F0F1", "/. c #E0FBFD", "(. c #ECF3F3", "). c #EBF4FE", "_. c #EDFAF3", "`. c #ECFEFE", "'. c #F6EEEC", "]. c #FDE5E3", "[. c #FFEEEA", "{. c #F6E4F4", "}. c #F3EEF4", "|. c #FDE5FC", " X c #FBECF2", ".X c #FFEBFB", "XX c #F5F3E5", "oX c #F1F2ED", "OX c #F5F8E5", "+X c #FEFCEA", "@X c #F2F4F3", "#X c #F4F6FF", "$X c #F5FFF4", "%X c #F4FDFD", "&X c #FCF2F3", "*X c #FDF3FD", "=X c #FEFBF5", "-X c #FCFDFE", /* pixels */ "+X+X+XXX-X%X).-X-X=X~.$X=X X&X=X&X=X@X-X", "OXOXOX=XG.*X-X*X}.'.%X_.@X-X-XoX*X-X=X-X", "-X=X%X-X=X].|.|.*X*X.X-X%X%XY.-XP.*X-X-X", "}.%X`.!.+X+X{.k O 7 5 = J.%X-X-X-XP.-X", "-X%X-X@XU., o & B.X k.6 J : o L.W.-X-XP.", "#X-XR.I.f Q r | % c.9 b.# K S : %X-XY.-X", "-X*X*XU R < } #.4 Z.2 q.m.6 ^ c o %X%X-X", "*X*Xf &.=.O #.* t.7.A.e w.8 B C I X `.`.", "*X.XT ,.E o ..; 5.g.p.> M.l M C F & J./.", "|.f :.<.O C.X.& f.4.i.p 0.{ w v ( x t /.", "-Xf 2.3.X ..O.* y.a.d.p n.' q C c ( & J.", "&Xf ;.-.O V.%.* r.8.u.p b.[ i B m D : L.", "-X[.Y >.W 7 .t F.9.s.g l.z N Z P H J.K.", "=X].h &.1.1 .r 6.g.e.> N.8 ) B A = `.%X", "-X X].p *.g $.o.1 S.a z.` 0 V ^ - `.#XW.", " X=X-X&Xs ~ : +.+ x.3 _ = G / # `.).-X-X", "-X%X%X-X&X o ; v.d h.. ! y . %X%X-X-X-X", "%XE.-X`.W.%X%X . & W.-X%X-X-X-X-X", "-X-X_.-X-X%X-X%X-X(.%X%X%XQ.-X_.-X-X-X-X", "%X-X(.T.%X-X(.-XT.-X-XH.-X%XT.-X-X-X-X-X" }; ================================================ FILE: apps/vaporgui/images/step-back-off.xpm ================================================ /* XPM */ const static char *step-back-off[] = { /* columns rows colors chars-per-pixel */ "24 21 75 1", " c #B3B6A3", ". c #B6B9A6", "X c #B7BAA7", "o c #B7B9AB", "O c #B7BAA9", "+ c #B8BBA8", "@ c #B8BBAA", "# c #B9BBAD", "$ c #B9BCA9", "% c #B9BCAB", "& c #BABDAA", "* c #BBBEAB", "= c #BBBDAF", "- c #BBBEAD", "; c #BCBFAC", ": c #BCBFAE", "> c #BCBEB0", ", c #BDBFB1", "< c #BDC0AD", "1 c #BDC0AF", "2 c #BEC1AE", "3 c #BEC0B2", "4 c #BFC1B3", "5 c #C0C2B4", "6 c #C1C3B5", "7 c #C1C4B3", "8 c #C3C6B5", "9 c #C6C9B8", "0 c #C8CBBA", "q c #CFD1C3", "w c #CFD2C1", "e c #D2D5C4", "r c #DADDCA", "t c #DBDECD", "y c #DDE0CF", "u c #DFE2D1", "i c #E0E3D2", "p c #E2E5D2", "a c #E3E6D3", "s c #E4E7D4", "d c #E4E7D6", "f c #E5E8D3", "g c #E5E8D5", "h c #E6E9D4", "j c #E6E9D6", "k c #E7EAD5", "l c #E7EBD4", "z c #E7EAD7", "x c #E6E9D8", "c c #E7EAD9", "v c #E8EBD6", "b c #E8ECD5", "n c #E9ECD7", "m c #E9EDD6", "M c #EAEED7", "N c #E8EBD8", "B c #E8EBDA", "V c #E8EADC", "C c #E9EBDD", "Z c #E9ECD9", "A c #E9ECDB", "S c #EAEDD8", "D c #EAEDDA", "F c #EBEED9", "G c #EBEEDB", "H c #EAEDDC", "J c #EBEEDD", "K c #ECEFDA", "L c #ECEFDC", "P c #EDF0DB", "I c #EDF0DD", "U c #EEF1DC", "Y c #EEF1DE", "T c #EFF2DD", "R c #EFF2DF", /* pixels */ "knvSSSkSSkSnnSnnGzzzzzSz", "SnKfSkvSnSaYnknSzcGGSGGG", "SkfnScYfSSkkSkYkzGGczcGc", "cGSYkkSSSdYSGkSSSGzzzSzG", "zSzkGJpJGGScdGckGczGSGzG", "SzGJSzYScSSkJSSSSzzIzGzn", "zScGo$X$- --.X-SzSzGacGz", "GGzS-S-zcSSk-c-zzGzfyzGm", "SkSG$$OGvSkGX,XCBct84GGl", "kYcaVy9444czm", "nkGGO$$SSkGcoXX033444IdG", "zccGde444:Gcc", "nSkk$$ c #B8BBAA", ", c #B8BAAC", "< c #B9BBAD", "1 c #B9BCA9", "2 c #B9BCAB", "3 c #BABDAA", "4 c #BBBDAF", "5 c #BCBEB0", "6 c #BDBFB1", "7 c #BEC1B0", "8 c #BEC0B2", "9 c #BFC1B3", "0 c #BFC2B1", "q c #C1C4B3", "w c #C4C7B6", "e c #C5C8B7", "r c #CDD0BF", "t c #CDCFC1", "y c #D0D3C2", "u c #D8DBC8", "i c #DADDCC", "p c #DBDECD", "a c #DDE0CF", "s c #E0E3D2", "d c #E2E5D2", "f c #E3E6D3", "g c #E4E7D4", "h c #E5E8D3", "j c #E5E8D5", "k c #E5E8D7", "l c #E6E9D4", "z c #E6E9D6", "x c #E7EAD5", "c c #E7EAD7", "v c #E6E9D8", "b c #E7E9DB", "n c #E7EAD9", "m c #E8EBD6", "M c #E9ECD7", "N c #E9EDD6", "B c #EAEED7", "V c #E8EBD8", "C c #E8EBDA", "Z c #E9EBDD", "A c #E9ECD9", "S c #E9ECDB", "D c #EAEDD8", "F c #EAEDDA", "G c #EBEED9", "H c #EBEEDB", "J c #EAEDDC", "K c #EBEEDD", "L c #ECEFDA", "P c #ECEFDC", "I c #ECEFDE", "U c #EDF0DD", "Y c #EDF0DF", "T c #EEF1DC", "R c #EEF1DE", "E c #EFF2DF", /* pixels */ "VVFcFcVVmmmchmmmFmcFmNBl", "FFFcFFFFVVcFUcFFFFmmcGhU", "VFFVVFFVcUFFgcFFcnFFhmmB", "FFVFcFFVFccFFFcFFFFcUmxm", "FVcFcVVFFnUcFVFVFcFNcNmm", "cFFFFVVFFcFFmVFcnBcFFNUc", "cFFdUVFcF** :@X:*-*#FFmF", "FFVuVcFVF*F c black", ", c black", "< c black", "1 c black", "2 c black", "3 c black", "4 c black", "5 c black", "6 c black", "7 c black", "8 c black", "9 c black", "0 c black", "q c black", "w c black", "e c black", "r c black", "t c black", "y c black", "u c black", "i c black", "p c black", "a c black", "s c black", "d c black", "f c black", "g c black", "h c black", "j c black", "k c black", "l c black", "z c black", "x c black", "c c black", "v c black", "b c black", "n c black", "m c black", "M c black", "N c black", "B c black", "V c none", "C c none", "Z c none", "A c none", "S c none", "D c none", "F c none", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", "| c none", " . c none", ".. c none", "X. c none", "o. c none", "O. c none", "+. c none", "@. c none", "#. c none", "$. c none", "%. c none", "&. c none", "*. c none", "=. c none", "-. c none", ";. c none", ":. c none", ">. c none", ",. c none", "<. c none", "1. c none", "2. c none", "3. c none", "4. c none", "5. c none", "6. c none", "7. c none", "8. c none", "9. c none", "0. c none", "q. c none", "w. c none", "e. c none", "r. c none", "t. c none", "y. c none", "u. c none", "i. c none", "p. c none", "a. c none", "s. c none", "d. c none", "f. c none", "g. c none", "h. c none", "j. c none", "k. c none", "l. c none", /* pixels */ "[ E ) $.$.$.X.@.O.2.$.E [ 2.$.O.X.$.[ +.$.) ) $.", "$.$.$.$.E E $.$.2.$.[ [ [ / $.t./ E $.w.U $.$.E ", "+.+.X.$.q.$.$.E [ E / [ [ / [ U $.E / U $.) ) +.", "+.8.E $.E E X.$.2.2.f.X.X.2.X.g.E X.2.@.8.+.+.$.", "$.X.$.X.$.+.$.E q./ U [ $./ E $.E 2.@.2.J X.2./ ", "E $.$.X.g.O.s.2.U w.U t.[ / w.E $.@.E E g.@.$.@.", "$.E E g.O - - O , X s 3 3 3 + h.$.X.$.$.U q.@.@.", "[ $.2.X.1 i.X j.$.@.O.f.$ f.$ 2.@.$.@.@.C Y $.@.", "2.E @.e.w - 0 @.@.$.$.E u O 0 *.@.*.Z m c f.E *.", "X.$./ X.w O.q X.( [ / q.+ e.0 @.A n x v x X.q.$.", "$.@.$.X.y - 3 e.O.d.O.l.2 0 p M f d k l f [ ! / ", "@.Y / 2.+ O.q E ' ' [ / 0 *.+ F V x z l g X.[ $.", "@.$.' $.q - q X.E / $.@.+ - q *.i.D B b j *.@.O.", "2.J w.P + f.3 e.@.@.t.@.3 d.3 2.$.E X.S N E t.O.", "*.$.G q.0 1 0 O 4 0 + 0 a O i p./ @.2.O.O.' / f.", "*.$.( ! p.X.k.2./ $./ / f.^ *.H @.$.$.2.@.^ ^ / ", "@.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.", "@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.", "$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.", "@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.", "@.$.@.$.$.@.$.@.$.@.$.@.@.$.@.$.@.$.@.$.$.@.$.@." }; ================================================ FILE: apps/vaporgui/images/stepbackA.xpm ================================================ /* XPM */ const static char *stepback[] = { /* columns rows colors chars-per-pixel */ "24 17 139 2", " c #1D1F12", ". c #1E1F19", "X c #1D1D1B", "o c gray12", "O c #1F2018", "+ c #1F201A", "@ c #212413", "# c #202214", "$ c #212316", "% c #222514", "& c #222417", "* c #212318", "= c #20211B", "- c #252719", "; c #20211C", ": c #21211F", "> c #23241C", ", c #23241F", "< c #25271C", "1 c #26281A", "2 c #201E29", "3 c #202020", "4 c gray13", "5 c #222220", "6 c #232321", "7 c #232323", "8 c #242520", "9 c #252621", "0 c #242422", "q c #232325", "w c #222126", "e c #232227", "r c gray14", "t c #252525", "y c #252527", "u c gray15", "i c #212028", "p c #23212C", "a c #22202D", "s c #282828", "d c #30302E", "f c gray21", "g c #393A35", "h c #383836", "j c #3A3B36", "k c #363638", "l c #36353B", "z c #3A3A3C", "x c #3F3F3D", "c c #40403E", "v c #424146", "b c #444444", "n c #53544C", "m c #4E4E50", "M c #555553", "N c #797A72", "B c #7B7C76", "V c #898989", "C c #A0A390", "Z c #ABACA6", "A c #B3B4AC", "S c #CACBC5", "D c #CED0C5", "F c #DFE1D3", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", "| c none", " . c none", ".. c none", "X. c none", "o. c none", "O. c none", "+. c none", "@. c none", "#. c none", "$. c none", "%. c none", "&. c none", "*. c none", "=. c none", "-. c none", ";. c none", ":. c none", ">. c none", ",. c none", "<. c none", "1. c none", "2. c none", "3. c none", "4. c none", "5. c none", "6. c none", "7. c none", "8. c none", "9. c none", "0. c none", "q. c none", "w. c none", "e. c none", "r. c none", "t. c none", "y. c none", "u. c none", "i. c none", "p. c none", "a. c none", "s. c none", "d. c none", "f. c none", "g. c none", "h. c none", "j. c none", "k. c none", "l. c none", /* pixels */ "+.+.X.$.q.$.$.E [ E / [ [ / [ U $.E / U $.) ) +.", "+.8.E $.E E X.$.2.2.f.X.X.2.X.g.E X.2.@.8.+.+.$.", "$.X.$.X.$.+.$.E q./ U [ $./ E $.E 2.@.2.J X.2./ ", "E $.$.X.g.O.s.2.U w.U t.[ / w.E $.@.E E g.@.$.@.", "$.E E g.O - - O , X s 3 3 3 + h.$.X.$.$.U q.@.@.", "[ $.2.X.1 i.X j.$.@.O.f.$ f.$ 2.@.$.@.@.C Y $.@.", "2.E @.e.w - 0 @.@.$.$.E u O 0 *.@.*.Z m c f.E *.", "X.$./ X.w O.q X.( [ / q.+ e.0 @.A n x v x X.q.$.", "$.@.$.X.y - 3 e.O.d.O.l.2 0 p M f d k l f [ ! / ", "@.Y / 2.+ O.q E ' ' [ / 0 *.+ F V x z l g X.[ $.", "@.$.' $.q - q X.E / $.@.+ - q *.i.D B b j *.@.O.", "2.J w.P + f.3 e.@.@.t.@.3 d.3 2.$.E X.S N E t.O.", "*.$.G q.0 1 0 O 4 0 + 0 a O i p./ @.2.O.O.' / f.", "*.$.( ! p.X.k.2./ $./ / f.^ *.H @.$.$.2.@.^ ^ / ", "@.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.", "@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.", "$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.", }; ================================================ FILE: apps/vaporgui/images/stepfwd.xpm ================================================ /* XPM */ const static char *stepfwd[] = { /* columns rows colors chars-per-pixel */ "24 21 139 2", " c black", ". c black", "X c black", "o c black", "O c black", "+ c black", "@ c black", "# c black", "$ c black", "% c black", "& c black", "* c black", "= c black", "- c black", "; c black", ": c black", "> c black", ", c black", "< c black", "1 c black", "2 c black", "3 c black", "4 c black", "5 c black", "6 c black", "7 c black", "8 c black", "9 c black", "0 c black", "q c black", "w c black", "e c black", "r c black", "t c black", "y c black", "u c black", "i c black", "p c black", "a c black", "s c black", "d c black", "f c black", "g c black", "h c black", "j c black", "k c black", "l c black", "z c black", "x c black", "c c black", "v c black", "b c black", "n c black", "m c black", "M c black", "N c black", "B c black", "V c black", "C c black", "Z c black", "A c none", "S c none", "D c none", "F c none", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", "| c none", " . c none", ".. c none", "X. c none", "o. c none", "O. c none", "+. c none", "@. c none", "#. c none", "$. c none", "%. c none", "&. c none", "*. c none", "=. c none", "-. c none", ";. c none", ":. c none", ">. c none", ",. c none", "<. c none", "1. c none", "2. c none", "3. c none", "4. c none", "5. c none", "6. c none", "7. c none", "8. c none", "9. c none", "0. c none", "q. c none", "w. c none", "e. c none", "r. c none", "t. c none", "y. c none", "u. c none", "i. c none", "p. c none", "a. c none", "s. c none", "d. c none", "f. c none", "g. c none", "h. c none", "j. c none", "k. c none", "l. c none", /* pixels */ ";.Q .;.' ' ;.' 2.;.;.' Q ;.6.$.+.;.6.;.%.;.Q ;.", "Q ;.;.P e.;.Q .6.%.E . .' Q 6.' ;.Q Q ' ;. .;.", ";.Q .;.Q .P ;.Q ;. .{ { . .{ E ;.' t.;.+.+.+.", ";.%.%.q.+.;.+.;.d.+.%.$.+.d.6.$.e.' ' Q Q ;.r.;.", "+.;.Q L 6.;.6.+. .E ' ;.;.E .{ +.6.;.;.&.&.+.;.", "%.;.;.d.+.Q %.;.E e. .Q ;.P e.Q 6.u.+.d.Q &.;.Q ", "%.%.q.L ;.6.+.+.f.0 y y 5 g . r @ # , O d.+.Y ;.", "%.6.Q S +.;.%.;.&.% u.# 6.u.&.6.k.@ u.1 +.e.;.' ", "6.Q 6.b B D 6.&.$.0 O u Q .;.Q ;.y @ s 6.' ' ;.", ";.e.+.b m b N F +.q 6.@ e. .` .&.o d.s +.e.&.&.", "Q ' ;.j c x h j V d 0 3 l.o.u.6.6.5 O p Q Q ;.' ", ";. .+.k c v b A J @ $.0 ' ' { .;.u u.o ;.e.+.6.", "5.;.5.z M Z H u.5.s 2 5 ;.e.&.' +.0 # y Q ` +.+.", "+.r.Q C G $.Q 6.&.@ t.@ +.r.&.' d.o u.0 ' w.&.;.", "6.( .5.$.6. .' f.a @ f , , 0 y & o 2 @ { ' &.&.", "' { ) ' 6.;. .' K 6.{ u.( ' ;.Q +.k.5.k.( U e.&.", "&.;.&.&.;.;.&.&.;.&.' &.;.&.' ;.&.&.;.&.' &.;.&.", "&.&.;.' &.' &.;.&.&.;.&.;.' &.;.&.;.&.&.;.&.;.' ", ";.;.&.&.' &.' ;.' ;.&.;.&.&.' &.' &.;.;.&.;.&.&.", "&.' &.;.;.;.&.&.&.;.&.' &.;.;.&.;.&.&.' &.' &.;.", "&.&.;.' &.&.;.&.&.&.;.&.;.' &.;.&.;.&.&.;.&.' ;." }; ================================================ FILE: apps/vaporgui/images/stepfwdA.xpm ================================================ /* XPM */ const static char *stepfwd[] = { /* columns rows colors chars-per-pixel */ "24 17 139 2", " c #1D1F12", ". c #1E1E1C", "X c #1F1F1D", "o c gray12", "O c #1F2113", "+ c #1F2018", "@ c #1F201A", "# c #212316", "$ c #202217", "% c #222514", "& c #252817", "* c #20211B", "= c #22231B", "- c #242619", "; c #252719", ": c #20211C", "> c #20201E", ", c #22231E", "< c #23241F", "1 c #25271C", "2 c #26281A", "3 c #201E29", "4 c #202020", "5 c gray13", "6 c #222220", "7 c #232321", "8 c #222222", "9 c #232323", "0 c #242520", "q c #252621", "w c #242422", "e c #252523", "r c #262722", "t c #232227", "y c gray14", "u c #252525", "i c #242426", "p c #252527", "a c #222129", "s c #242328", "d c #23212E", "f c #25232E", "g c #282828", "h c #30302E", "j c gray21", "k c #393A35", "l c #383836", "z c #3A3B36", "x c #363638", "c c #36353B", "v c #3A3A3C", "b c #3F3F3D", "n c #40403E", "m c #424146", "M c #444444", "N c #53544C", "B c #4E4E50", "V c #565654", "C c #797A72", "Z c #7B7C76", "A c #898989", "S c #A0A390", "D c #ABACA6", "F c #B3B4AC", "G c #CACBC5", "H c #CED0C5", "J c #DFE1D3", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", "| c none", " . c none", ".. c none", "X. c none", "o. c none", "O. c none", "+. c none", "@. c none", "#. c none", "$. c none", "%. c none", "&. c none", "*. c none", "=. c none", "-. c none", ";. c none", ":. c none", ">. c none", ",. c none", "<. c none", "1. c none", "2. c none", "3. c none", "4. c none", "5. c none", "6. c none", "7. c none", "8. c none", "9. c none", "0. c none", "q. c none", "w. c none", "e. c none", "r. c none", "t. c none", "y. c none", "u. c none", "i. c none", "p. c none", "a. c none", "s. c none", "d. c none", "f. c none", "g. c none", "h. c none", "j. c none", "k. c none", "l. c none", /* pixels */ ";.Q .;.Q .P ;.Q ;. .{ { . .{ E ;.' t.;.+.+.+.", ";.%.%.q.+.;.+.;.d.+.%.$.+.d.6.$.e.' ' Q Q ;.r.;.", "+.;.Q L 6.;.6.+. .E ' ;.;.E .{ +.6.;.;.&.&.+.;.", "%.;.;.d.+.Q %.;.E e. .Q ;.P e.Q 6.u.+.d.Q &.;.Q ", "%.%.q.L ;.6.+.+.f.0 y y 5 g . r @ # , O d.+.Y ;.", "%.6.Q S +.;.%.;.&.% u.# 6.u.&.6.k.@ u.1 +.e.;.' ", "6.Q 6.b B D 6.&.$.0 O u Q .;.Q ;.y @ s 6.' ' ;.", ";.e.+.b m b N F +.q 6.@ e. .` .&.o d.s +.e.&.&.", "Q ' ;.j c x h j V d 0 3 l.o.u.6.6.5 O p Q Q ;.' ", ";. .+.k c v b A J @ $.0 ' ' { .;.u u.o ;.e.+.6.", "5.;.5.z M Z H u.5.s 2 5 ;.e.&.' +.0 # y Q ` +.+.", "+.r.Q C G $.Q 6.&.@ t.@ +.r.&.' d.o u.0 ' w.&.;.", "6.( .5.$.6. .' f.a @ f , , 0 y & o 2 @ { ' &.&.", "' { ) ' 6.;. .' K 6.{ u.( ' ;.Q +.k.5.k.( U e.&.", "&.;.&.&.;.;.&.&.;.&.' &.;.&.' ;.&.&.;.&.' &.;.&.", "&.&.;.' &.' &.;.&.&.;.&.;.' &.;.&.;.&.&.;.&.;.' ", ";.;.&.&.' &.' ;.' ;.&.;.&.&.' &.' &.;.;.&.;.&.&.", }; ================================================ FILE: apps/vaporgui/images/tiles.xpm ================================================ /* XPM */ const static char *tiles[] = { /* columns rows colors chars-per-pixel */ "24 21 142 2", " c black", ". c #000100", "X c #010100", "o c #000002", "O c #010103", "+ c #000200", "@ c #010200", "# c #010300", "$ c #000004", "% c #000005", "& c #010005", "* c #000007", "= c #010006", "- c #020106", "; c #020107", ": c #020204", "> c #020400", ", c #030400", "< c #030500", "1 c #030600", "2 c #040500", "3 c #040600", "4 c #050700", "5 c #060701", "6 c #060702", "7 c #040404", "8 c #050507", "9 c #020109", "0 c #030208", "q c #04020D", "w c #05030E", "e c #05040A", "r c #05040C", "t c #07060C", "y c #08070D", "u c #08070F", "i c #080901", "p c #090B00", "a c #080904", "s c #090907", "d c #0A0B05", "f c #0D0F04", "g c #08080A", "h c #0A0A0C", "j c #050213", "k c #0D0C12", "l c #10100E", "z c #181A0D", "x c gray7", "c c #121116", "v c #151419", "b c #191A14", "n c #1D1D1B", "m c #28282A", "M c none", "N c none", "B c none", "V c none", "C c none", "Z c none", "A c none", "S c none", "D c none", "F c none", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", "| c none", " . c none", ".. c none", "X. c none", "o. c none", "O. c none", "+. c none", "@. c none", "#. c none", "$. c none", "%. c none", "&. c none", "*. c none", "=. c none", "-. c none", ";. c none", ":. c none", ">. c none", ",. c none", "<. c none", "1. c none", "2. c none", "3. c none", "4. c none", "5. c none", "6. c none", "7. c none", "8. c none", "9. c none", "0. c none", "q. c none", "w. c none", "e. c none", "r. c none", "t. c none", "y. c none", "u. c none", "i. c none", "p. c none", "a. c none", "s. c none", "d. c none", "f. c none", "g. c none", "h. c none", "j. c none", "k. c none", "l. c none", "z. c none", "x. c none", "c. c none", /* pixels */ "..^ [ [ Y ;.Y K [ h.;.! [ #.J h.#.[ Y ;.;.Y ....", ";.Y [ ;.;.! #.-.[ R M c.B [ ( ;.R ;.;.J Y ;.Y ;.", ";.Y ;.R h.h.X.#.( #.[ h.[ R ...#.R ..l.Y #.;.[ ", "R Y ;.#.i 2 X X X t X w X = X = z X X ! ! J [ J ", "R #...a.2 x.! X.K R r.X [ V [ ;.R l.b u.r.-.^ ;.", ";.J X.a.X u.l.[ ;.! R X [ #.^ #.;.a.X a.#.M -...", "[ ^ ;...X l.;.J ( ;.X.h Y X.( ;.( ..X a.;. .V [ ", "[ ^ ;.#.5 #.Y 4.[ #.X.n ..h...X.[ ;.X a.;.( [ ;.", "#.Y Y ;.X ;.[ ;.#.Y ;.X [ Y Y #.#.r.= ;.;.J ^ ;.", "Y [ [ J X R ;.#.h.#.R 8 J ;.;.#.#.X.j [ Y q.J Y ", "Y -.J ;.9 < 5 X m X l j X 5 5 X < X e [ ;.J -.[ ", "[ [ ;.r.= h.;.h.c.J ;.X ;.R .#.;...= ^ #.[ Y #.", "#.#.R R 9 ;.[ Y J .;.x K -.J [ ^ #.k ;.;.V ;.^ ", "X.! l.Z = ;.( [ X.#.h.q #.#.R #.^ [ X ^ ..[ ;...", ";.J #.R 9 ;.J ;.r.M ;.X -.J .J -.;.= ( ^ [ J ..", "( [ Y ;.t R ;.R Y ;.#.= ;.;.[ ;.^ ..v ;.^ ^ ;.;.", "[ ;.X.a.< #.[ ( [ [ #.X c.R ;.( #.#.f X.R [ ;...", "[ Y ! S e c = = t X = 9 = = = g h < X d.h.Y [ ..", "[ Y ^ ;.R ;.Y ;.;.Y ;...;.R ;.R N .Y [ [ K ^ ;.", "..;.;.^ [ ;.Y [ ..[ ^ Y J ;.J ;.#...l.R ^ [ [ ..", "R ;.;.Y Y ;.[ [ ;.[ ^ [ J Y ;...#.R l...^ [ [ .." }; ================================================ FILE: apps/vaporgui/images/tobeginA.xpm ================================================ /* XPM */ static const char *toBegin_[] = { /* columns rows colors chars-per-pixel */ "24 17 91 1", " c black", ". c #000100", "X c #010100", "o c #010101", "O c #000200", "+ c #010200", "@ c #030301", "# c #010103", "$ c #000005", "% c #020106", "& c #353535", "* c #363634", "= c #373833", "- c #353439", "; c #363638", ": c #35343A", "> c #393939", ", c #3B3B39", "< c #3E3E3C", "1 c #3E3E3E", "2 c gray25", "3 c #424240", "4 c #424244", "5 c #4B4B4D", "6 c #4E4E4E", "7 c #565656", "8 c #7B7C74", "9 c #7D7D7B", "0 c gray53", "q c #9FA193", "w c #AFAFAD", "e c #B2B3AD", "r c #C9CAC4", "t c #CBCCC4", "y c #D8D9D4", "u c #DDDED9", "i c none", "p c none", "a c none", "s c none", "d c none", "f c none", "g c none", "h c none", "j c none", "k c none", "l c none", "z c none", "x c none", "c c none", "v c none", "b c none", "n c none", "m c none", "M c none", "N c none", "B c none", "V c none", "C c none", "Z c none", "A c none", "S c none", "D c none", "F c none", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", /* pixels */ "GGGGGGGGBkBvvGTGvvMLMfMh", "GGGGGGGGvGgBvvLGLLvAJMMM", "GGGGGGGGLAMMMvLkvGLvkLfk", "GGGGGGGGWGLLvLGLTkTLkMvL", "GGGGGGGGXXAkMfLka[kMLMkv", "GGGGGGGGXXYLMMvLqkTkLvkv", "GGGGGGGGXXLs)'w53GvvvGv]", "GGGGGGGGXX']e6121WvL^vv]", "GGGGGGGGXXy7:;;&&WBGiBLv", "GGGGGGGG$X{u04;>,]vGGvBM", "GGGGGGGG$XWvWr93=GGkWBsG", "GGGGGGGG$XalGGVr8aBvCBBG", "GGGGGGGGXXLBvG^C'Bs^WGBC", "GGGGGGGG`WCGGkvBWlbaWWkW", "GGGGGGGGGGGGGGGGGGGGGGGG", "GGGGGGGGGGGGGGGGGGGGGGGG", "GGGGGGGGGGGGGGGGGGGGGGGG", }; ================================================ FILE: apps/vaporgui/images/toendA.xpm ================================================ /* XPM */ static const char *toEnd_[] = { /* columns rows colors chars-per-pixel */ "24 17 91 1", " c black", ". c #000100", "X c #010100", "o c #010101", "O c #000200", "+ c #010200", "@ c #030301", "# c #010103", "$ c #000005", "% c #020106", "& c #353535", "* c #363634", "= c #373833", "- c #353439", "; c #363638", ": c #35343A", "> c #393939", ", c #3B3B39", "< c #3E3E3C", "1 c #3E3E3E", "2 c gray25", "3 c #424240", "4 c #424244", "5 c #4B4B4D", "6 c #4E4E4E", "7 c #565656", "8 c #7B7C74", "9 c #7D7D7B", "0 c gray53", "q c #9FA193", "w c #AFAFAD", "e c #B2B3AD", "r c #C9CAC4", "t c #CBCCC4", "y c #D8D9D4", "u c #DDDED9", "i c none", "p c none", "a c none", "s c none", "d c none", "f c none", "g c none", "h c none", "j c none", "k c none", "l c none", "z c none", "x c none", "c c none", "v c none", "b c none", "n c none", "m c none", "M c none", "N c none", "B c none", "V c none", "C c none", "Z c none", "A c none", "S c none", "D c none", "F c none", "G c none", "H c none", "J c none", "K c none", "L c none", "P c none", "I c none", "U c none", "Y c none", "T c none", "R c none", "E c none", "W c none", "Q c none", "! c none", "~ c none", "^ c none", "/ c none", "( c none", ") c none", "_ c none", "` c none", "' c none", "] c none", "[ c none", "{ c none", "} c none", /* pixels */ "MLivJGMMMLMhMJfvGGGGGGGG", "vMvJChGLMGMMvMvMGGGGGGGG", "MiLMaJGCMLvvvLMLGGGGGGGG", "JMMMJThQLLJfJLCTGGGGGGGG", "MMhGGC[ahLhLCSooGGGGGGGG", "MMMGGWaqLhvMWCooGGGGGGGG", "TMvCvvL25w`QfJooGGGGGGGG", "WMLWJhW1216e]TooGGGGGGGG", "C_vhLvT**;;:7yooGGGGGGGG", "GvvLLv}>>;40u{ooGGGGGGGG", "LfvQh)h=29tWCWo$GGGGGGGG", "hvLCMvp8rVWvcho$GGGGGGGG", "GLLW_fL'CWLvz)ooGGGGGGGG", "ThLGvvcWvvCCLhTSGGGGGGGG", "GGGGGGGGGGGGGGGGGGGGGGGG", "GGGGGGGGGGGGGGGGGGGGGGGG", "GGGGGGGGGGGGGGGGGGGGGGGG", }; ================================================ FILE: apps/vaporgui/images/twoDData.xpm ================================================ /* XPM */ const static char *twoDData[] = { /* columns rows colors chars-per-pixel */ "24 21 61 1", " c #020201", ". c #070801", "X c #0A0B04", "o c #0C0C0B", "O c #0F100A", "+ c #13140D", "@ c #131313", "# c #191A17", "$ c #1A1A18", "% c #1F201B", "& c gray14", "* c #54564B", "= c #57594E", "- c #5B5C54", "; c #616358", ": c #6C6D66", "> c #73756A", ", c #7A7B73", "< c #80807E", "1 c #878882", "2 c #8E8F89", "3 c #95978C", "4 c #969791", "5 c #9A9C95", "6 c #9C9C9A", "7 c #A6A7A3", "8 c #ADAEA8", "9 c #C0C1BC", "0 c #C6C8BB", "q c #CACDBC", "w c gray76", "e c #CDCFC2", "r c #CFD2C1", "t c #D1D4C5", "y c #D3D5CB", "u c #D7D9CA", "i c #D9DCCD", "p c gray84", "a c #DBDCD3", "s c #DDDDDA", "d c #DFE1D3", "f c none", "g c none", "h c none", "j c none", "k c none", "l c none", "z c none", "x c none", "c c none", "v c none", "b c none", "n c none", "m c none", "M c none", "N c none", "B c none", "V c none", "C c none", "Z c none", "A c none", /* pixels */ "llkggklnfkmmMuuljcjBcZaN", "llkkgklluVjeqZZMjVjlsjev", "lhllllkhllvtZ .NavaxZZbN", "lhzlllkjkfjVZ AcNvjyyjd", "hhhhhzlkvjypN..ZxsvNvCAp", "hhghhllvvvZZA XAAbZAAACA", "hhgghlmMZ, $o oX $8", "hhgfglMC-+ o @@o. .@o s", "gfMgfiZ; .,bA AbACAp$ A", "zlmrlZ*+ 2AwAo AspA7 7v", "ugvgZ=. :A6bA oAxA1Xo4Ax", "mBfn>$ 2A9ApwAAxZ5 o1NCj", "lyA5X jACCCbAAxA8. :ZsyN", "xZ: % @ & .X:AaCyN", "vA o .o # $@. 3ZyZeiZ", "NpAZACCANAACA CZMfZdnZu", "llllclkctVM0ZXXMlllllllc", "lkkllkllMqiMB XVllllllll", "lklkkllkzBBqBVVullllllll", "llllllllVimVfqglllllllll", "llllllllhtdVdlMmllllllll" }; ================================================ FILE: apps/vaporgui/images/twoDImage.xpm ================================================ /* XPM */ const static char *twoDImage[] = { /* columns rows colors chars-per-pixel */ "24 21 256 2", " c #020401", ". c #0A0200", "X c #020B00", "o c #080607", "O c #130003", "+ c #1D0101", "@ c #1B030E", "# c #190906", "$ c #001200", "% c #041604", "& c #191A01", "* c #1B1000", "= c #000216", "- c #0D0013", "; c #0F001B", ": c #140017", "> c #1B0116", ", c #1A0819", "< c #031718", "1 c #121411", "2 c #1B171C", "3 c #230200", "4 c #2C0001", "5 c #20080E", "6 c #260708", "7 c #330000", "8 c #3A0002", "9 c #310F06", "0 c #27001C", "q c #102B00", "w c #073A0F", "e c #1B3F1B", "r c #34220E", "t c #282909", "y c #000324", "u c #02022E", "i c #0D062F", "p c #050931", "a c #160338", "s c #041938", "d c #171624", "f c #240028", "g c #2C0031", "h c #36003E", "j c #330032", "k c #2C1132", "l c #271428", "z c #002928", "x c #152522", "c c #440002", "v c #490000", "b c #4B060B", "n c #482C1E", "m c #3A0041", "M c #28005B", "N c #2C1950", "B c #002F51", "V c #062746", "C c #0F006C", "Z c #1A0A66", "A c #27006B", "S c #2F0076", "D c #410049", "F c #451841", "G c #451852", "H c #54095C", "J c #BD5866", "K c #DB7F66", "L c #CD707A", "P c #D87B7A", "I c #EE736C", "U c #EC7677", "Y c #F07B71", "T c #F17A7C", "R c #BC9279", "E c #D28477", "W c #C8847B", "Q c #E98578", "! c #F2F172", "~ c #F2EB66", "^ c #E279DE", "/ c #F87BE7", "( c #5F98B3", ") c #18C1BC", "_ c #4BCCB6", "` c #6DD4BF", "' c #74C7AB", "] c #64A5CD", "[ c #5FB8E2", "{ c #7CABE9", "} c #6CBAE5", "| c #7CB4E4", " . c #70A3F6", ".. c #6EBAF6", "X. c #7CBEFC", "o. c #79BAF6", "O. c #1DCDCA", "+. c #3ED1CB", "@. c #2CF5EF", "#. c #5DCBCC", "$. c #4CD7CC", "%. c #53D5CD", "&. c #59D7D4", "*. c #6DCCC6", "=. c #7FC0DC", "-. c #6CDDD7", ";. c #52E0D4", ":. c #73E6D6", ">. c #76E6DE", ",. c #6AC1EE", "<. c #72C3F0", "1. c #59EFED", "2. c #43F6F3", "3. c #5EF7F4", "4. c #B48E99", "5. c #B68B85", "6. c #8F9EB5", "7. c #8BBBAF", "8. c #9EAFB9", "9. c #94B0BE", "0. c #9CA3A9", "q. c #DB8F82", "w. c #DF868A", "e. c #DD8491", "r. c #D6869F", "t. c #C68D8E", "y. c #E6878C", "u. c #E1919C", "i. c #FF9393", "p. c #FA858B", "a. c #CE98B0", "s. c #FC9AA7", "d. c #8FD4B5", "f. c #89CDB4", "g. c #DAE182", "h. c #FFFC87", "j. c #FFFE8A", "k. c #F6F58A", "l. c #FFFC95", "z. c #F6F998", "x. c #D9F2BB", "c. c #F5EEA6", "v. c #E6FAA8", "b. c #F9F9A6", "n. c #F5F9AE", "m. c #FAF8A9", "M. c #E6E7B4", "N. c #F2EFBC", "B. c #EFF5BD", "V. c #E9FBB4", "C. c #F4F4B7", "Z. c #80A3C9", "A. c #99B6DE", "S. c #85BCDA", "D. c #8EA7E0", "F. c #9EBAEC", "G. c #80A7F4", "H. c #9BA9FD", "J. c #9DBDF0", "K. c #9095CF", "L. c #CA86C9", "P. c #DA84C1", "I. c #D197CB", "U. c #E393D8", "Y. c #D591FE", "T. c #F88AE7", "R. c #EF8AF2", "E. c #FF8EF0", "W. c #E794FC", "Q. c #FA95F9", "!. c #EB90E6", "~. c #EFAAED", "^. c #FFA7E4", "/. c #8DE4DB", "(. c #86CEF4", "). c #9FC3F7", "_. c #91D2FC", "`. c #89C3EB", "'. c #A8CAE5", "]. c #BBC5FF", "[. c #B7DCFF", "{. c #9FF9F0", "}. c #9DF7EB", "|. c #A1EDEB", " X c none", ".X c none", "XX c none", "oX c none", "OX c none", "+X c none", "@X c none", "#X c none", "$X c none", "%X c none", "&X c none", "*X c none", "=X c none", "-X c none", ";X c none", ":X c none", ">X c none", ",X c none", " F f h G g > BX", "FXJXcXS.,.[ | s = + 4 7 7 4 + O + # 0 > : - O IX", "NXfXvX( (._.p y @ 7 Q Q K 7 7 R t.5.4.> , 2 . 3X", "nXLX9.'.] i u : 4 s.T I Y v c q.E W 3 , 8XrX", "%XfX8.6.= i ; 6 r.J p.I T i.P P P c 6 < z f.#XCX", "PXfX0.d - - : a.t.u.y.y.y.L e.e.8 + o < *./.hX&X", "%X%X2 o o @ O + 3 7 3 4 7 b b 8 O 1 z #.+.%.vXZX", "mX 1 X . . * * . r 3 n 6 9 # x < &.2.@.) xXdX", "6X X % o & . X t & X % -.3.O.2.1.XXbX", "8X5X4XqX>XC.b.l.h.j.k.z.v.q e f.:.;.$.&.>.|.kXPX", "5X5X-X>XB.n.z.j.j.~ ! k.v.% w ' _ $.>.{.xXjXfX6X", "-X-X-XXB.n.b.k.l.k.g.V.$ $ d.` :.}..XbXjXNX8X", "=X=X-X5X-X-XN.C.c.m.b.m.V.$ $ *X X X.XgX%X6X0XSX", "=X=X-XqX8X8X5X:X:XC.M.M.2X1XeX*XjXhXjXZX0X5X3X:X" }; ================================================ FILE: apps/vaporgui/images/vapor-icon-32.xpm ================================================ /* XPM */ const static char *vapor_icon___[] = { /* columns rows colors chars-per-pixel */ "32 32 193 2", " c #337771", ". c #D25F02", "X c #D4670F", "o c #DB7800", "O c #D3710D", "+ c #E76507", "@ c #EE6B07", "# c #E96B0F", "$ c #EF7804", "% c #F17701", "& c #EB6B14", "* c #EA7315", "= c #CE7F24", "- c #DC7228", "; c #D07E36", ": c #D4793E", "> c #E77528", ", c #DD7844", "< c #D57F49", "1 c #3CBF23", "2 c #79CD11", "3 c #AE9C01", "4 c #B2A000", "5 c #A4B703", "6 c #ACB90C", "7 c #BBB703", "8 c #B5A11C", "9 c #95AE2E", "0 c #84B835", "q c #BBAA3F", "w c #A3B83E", "e c #B6B93F", "r c #D98814", "t c #F78D00", "y c #F98B00", "u c #E59300", "i c #E8960B", "p c #F29904", "a c #E18015", "s c #E59417", "d c #F39C19", "f c #C4A300", "g c #C4AF0E", "h c #CCBC00", "j c #DFB60E", "k c #DCBC13", "l c #DDBC1A", "z c #E3A503", "x c #E8A404", "c c #F5A000", "v c #FAA600", "b c #F4AF02", "n c #ECB401", "m c #EEBE04", "M c #F9B700", "N c #F6BD00", "B c #E1A11A", "V c #ECAC19", "C c #F0AC1F", "Z c #F2B417", "A c #C2942E", "S c #DE942F", "D c #C09535", "F c #EB8520", "G c #E98A25", "H c #E39323", "J c #E79F22", "K c #E99926", "L c #E38C33", "P c #E6873B", "I c #E58E3B", "U c #E99133", "Y c #F19F34", "T c #CDB624", "R c #F5A020", "E c #ECBF26", "W c #F2AE33", "Q c #81CA0B", "! c #84CF19", "~ c #92CA12", "^ c #96DE1B", "/ c #A2DF01", "( c #BCDC01", ") c #BCCD14", "_ c #9BE809", "` c #A0E300", "' c #A2EA0C", "] c #93C138", "[ c #BDC03D", "{ c #CFCF01", "} c #D4C302", "| c #CDD303", " . c #C2DB02", ".. c #CBDF02", "X. c #DED100", "o. c #D9DE02", "O. c #DBCC1C", "+. c #C4D712", "@. c #CCD11A", "#. c #E4CF01", "$. c #ECCD04", "%. c #EECB0B", "&. c #F4C30B", "*. c #F6CB08", "=. c #E4D400", "-. c #F0D403", ";. c #E1CB13", ":. c #E7CB18", ">. c #F6C91B", ",. c #C3E103", "<. c #D4E602", "1. c #D9E202", "2. c #DFD12B", "3. c #DDC133", "4. c #F7C527", "5. c #EAD33B", "6. c #F1D33A", "7. c #DF8842", "8. c #D5824D", "9. c #DB804C", "0. c #DE8552", "q. c #DA9D54", "w. c #E3844B", "e. c #E89D46", "r. c #E3885E", "t. c #E59550", "y. c #EA9352", "u. c #EB9E56", "i. c #C6B950", "p. c #C5B55E", "a. c #E2A04B", "s. c #EEB243", "d. c #F5B74F", "f. c #E9AA53", "g. c #EDA25F", "h. c #E2BE54", "j. c #D68A69", "k. c #E99463", "l. c #EA9A66", "z. c #E69770", "x. c #EC9A74", "c. c #E4997C", "v. c #DFA870", "b. c #EBAC6E", "n. c #E4B661", "m. c #F7B06C", "M. c #EDA473", "N. c #F2B473", "B. c #96C540", "V. c #DAC141", "C. c #D5C845", "Z. c #DDC55B", "A. c #F9C54F", "S. c #EDD544", "D. c #FBDB52", "F. c #F7C963", "G. c #18789C", "H. c #2F46AF", "J. c #ECA382", "K. c #F0AB81", "L. c #E8BD80", "P. c #F1B784", "I. c #EBBA94", "U. c #EDBBA4", "Y. c #F3BFAB", "T. c #EBCA95", "R. c #F7C19C", "E. c #DBD1A1", "W. c #EEC8AA", "Q. c #FACAA7", "!. c #F1C0B5", "~. c #F1CFB6", "^. c #FACEB2", "/. c #F5CEB8", "(. c #F8CBBB", "). c #F5C9C0", "_. c #F8CEC7", "`. c #F7D1C5", "'. c #FAD4C4", "]. c #FDD8C6", "[. c #F5D0C9", "{. c #F9D5CC", "}. c #FDDBCD", "|. c #FAD7D1", " X c #F6DAD3", ".X c #FBDCD4", "XX c #FBDED9", "oX c #FDE0D5", "OX c #FDE3DD", "+X c #FDE6E2", "@X c #FEE9E4", "#X c #FEEDE8", "$X c None", /* pixels */ "$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X", "$Xl R $X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$XD f 2 G.$X$X$X", "$Xg b u 7.$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X8 h 5 H.1 $X", "$X$Xk N p s H r t.N.u.l.$X$X$X$X$X$X$X$X$X$X$X$Xp.6 7 3 4 5 $.D.", "$X$X$Xm i U L L a g.P.M.k.9., < $X$X$X$X$X$X$X$XT ,.( { -.4.F.$X", "$X$X$X:.n Y Q._.$XI y.J.$X$X$X$X8.0.c.$X[.OX).q.X.o.=.*.d.$X$X$X", "$X$X$XO.$.W $X]..X{.K.x.$X$X$X$X$X).`.{.$X.X[.e ,...*.d.$X$X$X$X", "$X$X$XC.#.f.oX@XXX$X$X$X$X$X$X$XOXOX.X`.$X{.E.^ ' 1.A.$X$X$X$X$X", "$X$X$X$X=.V R.$X$X+XXXXX.X$X$X$X.X{.{.$X$X(.e _ <.6.$X$X$X$X$X$X", "$X$X$X$X=.V m.].$X$X$X+XOXXX.XXXXXXX+X+X@Xv.| 1.6.$X$X$X$X$X$X$X", "$X$X$X$X;.s ^.^.+X$X$X$X+X@XXX$X$X$X$X$X$Xi.1.2.$X$X$X$X$X$X$X$X", "$X$X$X$X5.z `.oX].OX$X$X$X$X+X+X$X$X$X$X$X@.) $X$X$X$X$X$X$X$X$X", "$X$X$X$XS.n I.OX}.oX@X$X$X$X$X$X$X$X$X$XZ. .w $X$X$X$X$X$X$X$X$X", "$X$X$X$X$X&.a..XOXoXOX@X$X$X$X$X$X$X$XW.| ~ $X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X>.J /.OXOXOX@X@X$X$X$X$X$X Xh.` B.$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X4.b b.@X@X+X@X#X$X$X$X$X$XT.+.! $X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$XM K }.@X@X#X$X$X$X$X$X$XV.` 0 $X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$XZ c M.XX@X$X$X$X$X$X$XL.( Q $X$X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$Xs.v G W.+X$X$X$X$X$X~.3.` ] $X$X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$X$Xd t P _.+X$X$X$X$Xn.| ~ $X$X$X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$X$Xe.y $ z.{.+X$X$XU.j ( 9 $X$X$X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$X$X$XF % & r.!._.U.S =.6 $X$X$X$X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$X$X$X$X* @ & , j.; x } q $X$X$X$X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$X$X$X$X$X> & + X o u D $X$X$X$X$X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$X$X$X$X$X$Xw.- X O = $X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X", "$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X" }; ================================================ FILE: apps/vaporgui/images/wheel.xpm ================================================ /* XPM */ const static char *wheel[] = { /* columns rows colors chars-per-pixel */ "24 21 195 2", " c black", ". c black", "X c black", "o c black", "O c black", "+ c black", "@ c black", "# c black", "$ c black", "% c black", "& c black", "* c black", "= c black", "- c black", "; c black", ": c black", "> c black", ", c black", "< c black", "1 c black", "2 c black", "3 c black", "4 c black", "5 c black", "6 c black", "7 c black", "8 c black", "9 c black", "0 c black", "q c black", "w c black", "e c black", "r c black", "t c black", "y c black", "u c black", "i c black", "p c black", "a c black", "s c black", "d c black", "f c black", "g c black", "h c black", "j c black", "k c black", "l c black", "z c black", "x c black", "c c black", "v c black", "b c black", "n c black", "m c black", "M c black", "N c black", "B c black", "V c black", "C c black", "Z c black", "A c black", "S c black", "D c black", "F c black", "G c black", "H c black", "J c black", "K c black", "L c black", "P c black", "I c black", "U c black", "Y c black", "T c black", "R c black", "E c black", "W c black", "Q c black", "! c black", "~ c black", "^ c black", "/ c black", "( c black", ") c black", "_ c black", "` c black", "' c black", "] c black", "[ c black", "{ c black", "} c black", "| c black", " . c black", ".. c black", "X. c black", "o. c black", "O. c black", "+. c none", "@. c none", "#. c none", "$. c none", "%. c none", "&. c none", "*. c none", "=. c none", "-. c none", ";. c none", ":. c none", ">. c none", ",. c none", "<. c none", "1. c none", "2. c none", "3. c none", "4. c none", "5. c none", "6. c none", "7. c none", "8. c none", "9. c none", "0. c none", "q. c none", "w. c none", "e. c none", "r. c none", "t. c none", "y. c none", "u. c none", "i. c none", "p. c none", "a. c none", "s. c none", "d. c none", "f. c none", "g. c none", "h. c none", "j. c none", "k. c none", "l. c none", "z. c none", "x. c none", "c. c none", "v. c none", "b. c none", "n. c none", "m. c none", "M. c none", "N. c none", "B. c none", "V. c none", "C. c none", "Z. c none", "A. c none", "S. c none", "D. c none", "F. c none", "G. c none", "H. c none", "J. c none", "K. c none", "L. c none", "P. c none", "I. c none", "U. c none", "Y. c none", "T. c none", "R. c none", "E. c none", "W. c none", "Q. c none", "!. c none", "~. c none", "^. c none", "/. c none", "(. c none", "). c none", "_. c none", "`. c none", "'. c none", "]. c none", "[. c none", "{. c none", "}. c none", "|. c none", " X c none", ".X c none", "XX c none", "oX c none", "OX c none", "+X c none", "@X c none", "#X c none", "$X c none", "%X c none", "&X c none", /* pixels */ "H.b.b.u.D.u.c.D.H.5.g.D.u.D.D.f.D.u.g.b.D.u.D.f.", "b.u.U.g.s.s.D.4.g.F.D.4.c.g.g.D.4.D.D.D.u.H.b.g.", "c.D.s.+Xs.b.D.c.D.g.s.i .b.D.c.b.D.D.f.f.s.u.F.", "q.D.s.oXN Q s.D.H.7.%Xg Y B.f.b.D.U.Q l f.D.F.q.", "c.u.U.f.b | oXf.] ) V _ t G T ] +Xs.b | f.s.c.v.", "c.g.D.b.+XB.a k Z X >.r r '.X Z b s oXf.H.D.g.u.", "c.D.D.3.H.oX( : % %.{.X : +.(.% : o.7.Q.3.D.q.b.", "b.b.u.F.H.U J % 2 X *.- X ).7 : 2 r Q b.D.D.D.H.", "c.D.c.D.oXA q '.X : X X : X X ; >.X F f.D.D.g.g.", "4.D.u.f.7.U >.>.-.: X X : X X %.}.%.Q B.H.b.g.D.", "D.c.H.i F ..X % X X : X X 9 X ; % X g b ` s.u.c.", "u.u.H.N b A X % X : 7 7 : e X X 9 7 g b a H.F.c.", "c.F.5.f..Xk `.%.%.: X X X X : `.`.#.] %Xf.b.b.g.", "u.4.Q.u.7.Q X (.: X X 9 7 X X : %.T ^ 2.~.u.g.H.", "f.q.c.F.g.i T % X : #.X X -.9 X X T f.D.q.F.b.H.", "b.D.c.<.F.f.D S 7 `.`.9 9 `.{.X X.g b.v.1.v.D.b.", "c.B.c.q.} T c.b G X `.X X %.X / D c.g / D.c.7.c.", "c.7.D.g.T s F.f.{ Y t G O.C J Z f.D.b T c.c.f.c.", "D.b.q.D.H.7.F.D.c.g.f.N l s.D.g.D.g.6.+Xg.c.D.u.", "g.c.c.g.f.D.u.c.q.~.f.b U +Xb.c.c.c.b.H.g.c.g.c.", "u.c.c.c.D.H.u.q.g.D.6.B.%Xb.u.c.u.D.b.b.g.c.c.c." }; ================================================ FILE: apps/vaporgui/mac_helpers.h ================================================ #pragma once class QWidget; bool MacIsDarkMode(); void DisableMacFullscreen(QWidget *widget); ================================================ FILE: apps/vaporgui/mac_helpers.mm ================================================ #include "mac_helpers.h" #import #import #include bool MacIsDarkMode() { NSString *appearanceName = [[NSAppearance currentAppearance] name]; return [appearanceName containsString:@"Dark"]; } void DisableMacFullscreen(QWidget* widget) { // Ensure native view exists widget->winId(); NSView *nsView = (NSView *)widget->window()->winId(); if (![nsView isKindOfClass:[NSView class]]) return; NSWindow *nsWindow = [nsView window]; if (!nsWindow) return; // Remove fullscreen behavior NSUInteger behavior = [nsWindow collectionBehavior]; behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary; [nsWindow setCollectionBehavior:behavior]; // Keep resizable, but disable fullscreen by overriding standardWindowButton NSButton *zoomButton = [nsWindow standardWindowButton:NSWindowZoomButton]; [zoomButton setTarget:nil]; [zoomButton setAction:nil]; } ================================================ FILE: apps/vaporgui/main.cpp ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: main.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: June 2004 // // Description: Main program for vapor gui #include #include #include #include #include #include "MainForm.h" #include #include #include #include "BannerGUI.h" #include #include #include #include #include #include #include #ifdef WIN32 #include "Windows.h" #endif using namespace std; using namespace VAPoR; using namespace Wasp; void myMessageOutput(QtMsgType type, const char *msg) { switch (type) { case QtDebugMsg: break; case QtWarningMsg: break; case QtFatalMsg: break; default: // ignore QtCriticalMsg and QtSystemMsg break; } } // // Open a file named by the environment variable, path_var. Exit on failure // FILE *OpenLog(string path_var) { FILE * fp = NULL; const char *cstr = getenv(path_var.c_str()); if (!cstr) return (NULL); string s = cstr; if (!s.empty()) { fp = fopen(s.c_str(), "w"); if (!fp) { cerr << "Failed to open " << s << " : " << strerror(errno) << endl; exit(1); } MyBase::SetDiagMsgFilePtr(fp); } return (fp); } struct opt_t { OptionParser::Boolean_T help; OptionParser::Boolean_T render; OptionParser::IntRange_ renderRange; OptionParser::Dimension2D_ resolution; char * outputPath; char * datasetType; } opt; OptionParser::OptDescRec_T set_opts[] = {{"help", 0, "", "Print this message and exit"}, {"render", 0, "", "Render a given session file and exit"}, {"timesteps", 1, "0:0", "Timesteps to render when using -render. Defaults to all timesteps."}, {"resolution", 1, "1920x1080", "Output resolution when using -render"}, {"output", 1, "vapor.tiff", "Output image file when using -render. This will be suffixed with the timestep number. Supports tiff, jpg"}, {"ftype", 1, "auto", "Specify file format of datasets passed in command line. Valid options are: auto vdc wrf mpas dcp ugrid cf bov"}, {NULL}}; OptionParser::Option_T get_options[] = {{"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {"render", Wasp::CvtToBoolean, &opt.render, sizeof(opt.render)}, {"timesteps", Wasp::CvtToIntRange, &opt.renderRange, sizeof(opt.renderRange)}, {"resolution", Wasp::CvtToDimension2D, &opt.resolution, sizeof(opt.resolution)}, {"output", Wasp::CvtToString, &opt.outputPath, sizeof(opt.outputPath)}, {"ftype", Wasp::CvtToString, &opt.datasetType, sizeof(opt.datasetType)}, {NULL}}; const char * ProgName; QApplication *app; int main(int argc, char **argv) { OptionParser op; ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] [session.vs3] [data files...]" << endl; op.PrintOptionHelp(stderr); exit(0); } // Install our own message handler. // Needed for SGI to avoid dithering: // FILE *diagfp = OpenLog("VAPOR_DIAG_LOG"); // FILE *errfp = OpenLog("VAPOR_ERR_LOG"); FILE *diagfp = NULL; FILE *errfp = NULL; if (getenv("VAPOR_DEBUG")) MyBase::SetDiagMsgFilePtr(stderr); #ifdef Darwin if (!getenv("DISPLAY")) setenv("DISPLAY", ":0.0", 0); #endif #ifdef Q_WS_X11 if (!getenv("DISPLAY")) { fprintf(stderr, "Error: X11 DISPLAY variable is not defined. %s \n", "Vapor user interface requires X server to be available."); exit(-1); } #endif #ifdef IRIX QApplication::setColorSpec(QApplication::ManyColor); #endif VOSP::Initialize(&argc, argv); QApplication a(argc, argv, true); // All C programs are run with the locale set to "C" // Initalizing QApplication changes the locale to the system configuration // which can cause problems if it is not supported. // Udunits does not support it and vapor potentially does not either. // // https://www.gnu.org/software/libc/manual/html_node/Setting-the-Locale.html // https://doc.qt.io/qt-5/qcoreapplication.html#locale-settings // setlocale(LC_ALL, "C"); // For Mac and Linux, set the PYTHONHOME in this app #ifndef WIN32 const char *s = getenv("PYTHONHOME"); string phome = s ? s : ""; if (!phome.empty() && !getenv("PYTHONHOME_SET_BY_VAPOR")) { string msg("The PYTHONHOME variable is already specified as: \n"); msg += phome; msg += "\n"; msg += "The VAPOR "; msg += "python" + PYTHON_VERSION; msg += " environment will operate in this path\n"; msg += " This path must be the location of a Python "; msg += "python" + PYTHON_VERSION; msg += " installation\n"; msg += "Unset the PYTHONHOME environment to revert to the installed "; msg += "VAPOR python" + PYTHON_VERSION + " environment."; QMessageBox::warning(0, "PYTHONHOME warning", msg.c_str()); // This does not work on Casper printf("======== PYTHONHOME warning ========\n"); printf("%s\n\n", msg.c_str()); } else { phome = GetPythonDir(); setenv("PYTHONHOME", phome.c_str(), 1); // We shouldnt be setting "PYTHONHOME" here but this is a temporary fix for relaunching vapor without extra warnings setenv("PYTHONHOME_SET_BY_VAPOR", "", 1); } MyBase::SetDiagMsg("PYTHONHOME = %s", phome.c_str()); #endif VAPoR::SetHDF5PluginPath(); app = &a; vector files; for (int i = 1; i < argc; i++) { files.push_back(argv[i]); } MainForm *mw = new MainForm(files, app, !opt.render, opt.datasetType); // StartupParams* sParams = new StartupParams(0); string fontFile = GetSharePath("fonts/arimo.ttf"); QFontDatabase fdb; fdb.addApplicationFont(QString::fromStdString(fontFile)); QStringList fonts = fdb.families(); QFont f = fdb.font("Arimo", "normal", 12); const char *useFont = std::getenv("USE_SYSTEM_FONT"); if (!useFont) { mw->setFont(f); } string title = "VAPOR " + Version::GetVersionString() + " (" + Version::GetBuildHash() + ")"; mw->setWindowTitle(title.c_str()); mw->show(); // Disable banner in debug build #ifdef NDEBUG std::string banner_file_name = "vapor_banner.png"; BannerGUI banner(mw, banner_file_name, 3000); #endif a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit())); int estatus = 0; if (opt.render) { estatus = mw->RenderAndExit(opt.renderRange.min, opt.renderRange.max, opt.outputPath, opt.resolution.nx, opt.resolution.ny); } if (estatus == 0) { estatus = a.exec(); } VOSP::Shutdown(); if (diagfp) fclose(diagfp); if (errfp) fclose(errfp); exit(estatus); } ================================================ FILE: apps/vaporgui/plotWindow.ui ================================================ PlotWindow 0 0 885 651 Form QLayout::SetMinimumSize QLayout::SetMinimumSize 20 0 Data Source: Qt::Horizontal 40 20 150 0 Variables 5 0 Qt::Vertical 0 0 16777215 16777215 0 Space 20 Lock X Lock Y Lock Z QFrame::StyledPanel QFrame::Plain 1 -1 12 12 12 12 Select one time step: QFrame::StyledPanel QFrame::Plain QFrame::NoFrame QFrame::Plain Number of samples between two points: Plot Time Plot QSinglePoint QWidget
QSinglePoint.h
1
FidelityWidget QWidget
FidelityWidget.h
1
QRange QWidget
QRange.h
1
QSliderEdit QWidget
QSliderEdit.h
1
================================================ FILE: apps/vaporgui/statsWindow.ui ================================================ StatsWindow 0 0 1009 441 0 0 Form QLayout::SetDefaultConstraint QLayout::SetDefaultConstraint 0 0 0 0 10 1 1 500 120 true 21 129 false false false 0 10 0 Data Source Qt::Horizontal 40 20 280 0 5 5 5 5 10 0 0 Variable Selection Qt::AlignCenter QComboBox::InsertAlphabetically QComboBox::InsertAlphabetically Qt::Vertical 10 0 0 Statistic Selection Qt::AlignCenter QComboBox::InsertAlphabetically false QComboBox::InsertAlphabetically true Qt::Horizontal 0 0 0 0 Qt::Vertical QSizePolicy::Expanding 20 0 0 0 3 3 Qt::Vertical 0 0 12 3 3 Qt::Horizontal 0 20 10 0 0 Temporal Extents 5 0 Minimum Timestep Qt::Horizontal QSizePolicy::MinimumExpanding 40 20 0 0 Maximum Timestep Qt::Horizontal QSizePolicy::MinimumExpanding 40 20 Qt::Vertical QSizePolicy::Expanding 20 0 3 3 Qt::Horizontal 5 -1 true 150 0 Export Text false false false 150 0 Update Statistics true false Auto-update FidelityWidget QWidget
FidelityWidget.h
1
================================================ FILE: apps/vaporgui/vapor.rc.in ================================================ IDI_ICON1 ICON DISCARDABLE "@WINDOWS_ICON_PATH@" ================================================ FILE: apps/vaporgui/windowsUtils.cpp ================================================ #ifdef WIN32 #include #include #include #include #include #include "windowsUtils.h" LONG Windows_OpenRegistry(HKEY root, std::string keyName, HKEY &key) { return RegOpenKeyEx(root, TEXT(keyName.c_str()), 0, KEY_ALL_ACCESS, &key); } LONG Windows_CloseRegistry(HKEY key) { return RegCloseKey(key); } LONG Windows_GetRegistryString(HKEY hKey, const std::string &strValueName, std::string &strValue, const std::string &strDefaultValue) { strValue = strDefaultValue; CHAR szBuffer[8192]; DWORD dwBufferSize = sizeof(szBuffer); LONG error; error = RegQueryValueEx(hKey, strValueName.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize); if (error == ERROR_SUCCESS) strValue = szBuffer; return error; } LONG Windows_SetRegistryString(HKEY hKey, const std::string &strValueName, const std::string &strValue) { LONG error; error = RegSetValueEx(hKey, strValueName.c_str(), 0, REG_SZ, (LPBYTE)strValue.c_str(), strValue.length()); if (error == ERROR_SUCCESS) { BroadcastSystemMessage(0, 0, WM_SETTINGCHANGE, 0, (LPARAM)TEXT("Environment")); } return error; } std::string Windows_GetErrorString(LONG errorCode) { LPVOID lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL); std::wstringstream wss; wss << (LPCTSTR)lpMsgBuf; std::wstring ws = wss.str(); std::wstring_convert, wchar_t> converter; std::string s = converter.to_bytes(ws); LocalFree(lpMsgBuf); return s; } #endif ================================================ FILE: apps/vaporgui/windowsUtils.h ================================================ #ifndef WINDOWS_UTILS_H #define WINDOWS_UTILS_H #ifdef WIN32 #include #define WIN32_LEAN_AND_MEAN #define WINDOWS_SUCCESS ERROR_SUCCESS #define WINDOWS_ERROR_FILE_NOT_FOUND ERROR_FILE_NOT_FOUND #define WINDOWS_HKEY_CLASSES_ROOT HKEY_CLASSES_ROOT #define WINDOWS_HKEY_CURRENT_CONFIG HKEY_CURRENT_CONFIG #define WINDOWS_HKEY_CURRENT_USER HKEY_CURRENT_USER #define WINDOWS_HKEY_LOCAL_MACHINE HKEY_LOCAL_MACHINE #define WINDOWS_HKEY_USERS HKEY_USERS LONG Windows_OpenRegistry(HKEY root, std::string keyName, HKEY &key); LONG Windows_CloseRegistry(HKEY key); LONG Windows_GetRegistryString(HKEY hKey, const std::string &strValueName, std::string &strValue, const std::string &strDefaultValue); LONG Windows_SetRegistryString(HKEY hKey, const std::string &strValueName, const std::string &strValue); std::string Windows_GetErrorString(LONG errorCode); #endif #endif ================================================ FILE: apps/vaporpychecker/CMakeLists.txt ================================================ add_executable (vaporpychecker vaporpychecker.cpp) target_link_libraries (vaporpychecker common render ${Python_LIBRARIES}) OpenMPInstall ( TARGETS vaporpychecker DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/vaporpychecker/vaporpychecker.cpp ================================================ #include #include #include #include #include #include using namespace Wasp; struct opt_t { OptionParser::Boolean_T quiet; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"quiet", 0, "", "Don't print anything, just exit with status"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; string ProgName; // Fetch an error message genereated by Python API. // string pyErr() { PyObject *pMain = PyImport_AddModule("__main__"); PyObject *catcher = NULL; if (pMain && PyObject_HasAttrString(pMain, "catchErr")) { catcher = PyObject_GetAttrString(pMain, "catchErr"); } // If catcher is NULL the Python message will be written // to stderr. Otherwise it is writter to the catchErr object. // PyErr_Print(); if (!catcher) { cerr << "CATCHER NULL" << endl; return ("No Python error catcher"); } PyObject *output = PyObject_GetAttrString(catcher, "value"); return (PyUnicode_AsUTF8(output)); } int main(int argc, char **argv) { OptionParser op; #ifndef WIN32 std::string phome = GetPythonDir(); setenv("PYTHONHOME", phome.c_str(), 1); #endif MyBase::SetErrMsgFilePtr(stderr); // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { return (1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { return (1); } if (argc != 1 || opt.help) { cerr << "Usage: " << ProgName << endl; op.PrintOptionHelp(stderr, 80, false); return (1); } // Use MyPython singleton class to initialize Python interpeter to // ensure it only gets initialized once. // int rc = MyPython::Instance()->Initialize(); if (rc < 0) { MyBase::SetErrMsg("Failed to initialize python : %s", pyErr().c_str()); printf("Failed to initialize python : %s\n", pyErr().c_str()); return (1); } cout << endl << "System search path: "; std::string printSysPath = "try:\n" " import sys\n" "except: \n" " print >> sys.stderr, \'Failed to import sys\'\n" " raise\n" "print(sys.path)\n"; rc = PyRun_SimpleString(printSysPath.c_str()); if (rc < 0) { MyBase::SetErrMsg("PyRun_SimpleString() : %s", MyPython::Instance()->PyErr().c_str()); return (1); } cout << MyPython::Instance()->PyOut() << endl; cout << "Location of site module: "; std::string printSiteModulePath = "try:\n" " import site\n" "except: \n" " print >> sys.stderr, \'Failed to import site\'\n" " raise\n" "import os\n" "print(os.path.dirname(site.__file__))\n"; rc = PyRun_SimpleString(printSiteModulePath.c_str()); if (rc < 0) { MyBase::SetErrMsg("PyRun_SimpleString() : %s", MyPython::Instance()->PyErr().c_str()); return (1); } cout << MyPython::Instance()->PyOut() << endl; cout << "Location of matplotlib module: "; std::string printMatplotlibModulePath = "try:\n" " import matplotlib\n" "except: \n" " print >> sys.stderr, \'Failed to import matplotlib\'\n" " raise\n" "import os\n" "print(os.path.dirname(matplotlib.__file__))\n"; rc = PyRun_SimpleString(printMatplotlibModulePath.c_str()); if (rc < 0) { MyBase::SetErrMsg("PyRun_SimpleString() : %s", MyPython::Instance()->PyErr().c_str()); return (1); } cout << MyPython::Instance()->PyOut() << endl; return (0); } ================================================ FILE: apps/vaporversion/CMakeLists.txt ================================================ add_executable (vaporversion vaporversion.cpp) target_link_libraries (vaporversion common) OpenMPInstall ( TARGETS vaporversion DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/vaporversion/vaporversion.cpp ================================================ // // $Id$ // //*********************************************************************** // * // Copyright (C) 2005 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //***********************************************************************/ // // File: raw2vdf.cpp // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: Tue Jun 14 15:01:13 MDT 2005 // // Description: Read a file containing a raw data volume. Translate // and append the volume to an existing // Vapor Data Collection // #include #include #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include "windows.h" #endif using namespace Wasp; // // Command line argument stuff // struct opt_t { OptionParser::Boolean_T help; OptionParser::Boolean_T _long; OptionParser::Boolean_T numeric; } opt; OptionParser::OptDescRec_T set_opts[] = {{"help", 0, "", "Print this message and exit"}, {"long", 0, "", "Print long form (version and date)"}, {"numeric", 0, "", "Print numeric form"}, {NULL}}; OptionParser::Option_T get_options[] = { {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {"long", Wasp::CvtToBoolean, &opt._long, sizeof(opt._long)}, {"numeric", Wasp::CvtToBoolean, &opt.numeric, sizeof(opt.numeric)}, {NULL}}; const char *ProgName; int main(int argc, char **argv) { OptionParser op; // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] metafile datafile" << endl; op.PrintOptionHelp(stderr); exit(0); } if (argc != 1) { cerr << "Usage: " << ProgName << " [options] " << endl; op.PrintOptionHelp(stderr); exit(1); } if (opt._long) { cout << "Vapor " << Version::GetBuildType() << " version " << Version::GetFullVersionString() << " (" << Version::GetDateString() << ")" << endl; } else if (opt.numeric) { cout << Version::GetMajor() << "." << Version::GetMinor() << "." << Version::GetMinorMinor() << endl; } else { cout << "vapor-" << Version::GetVersionString() << endl; } } ================================================ FILE: apps/vdc2raw/CMakeLists.txt ================================================ add_executable (vdc2raw vdc2raw.cpp) target_link_libraries (vdc2raw common vdc) OpenMPInstall ( TARGETS vdc2raw DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/vdc2raw/vdc2raw.cpp ================================================ #include #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include using namespace Wasp; using namespace VAPoR; struct opt_t { int ts; string varname; string type; int level; int lod; int nthreads; OptionParser::Boolean_T help; OptionParser::Boolean_T debug; OptionParser::Boolean_T quiet; vector xregion; vector yregion; vector zregion; } opt; OptionParser::OptDescRec_T set_opts[] = {{"ts", 1, "0", "Timestep of data file starting from 0"}, {"varname", 1, "var1", "Name of variable"}, {"type", 1, "float32", "Primitive type of output data"}, {"level", 1, "-1", "Multiresolution refinement level. Zero implies coarsest resolution"}, {"lod", 1, "-1", "Compression level of detail. Zero implies coarsest approximation"}, {"nthreads", 1, "0", "Number of execution threads (0=># processors)"}, {"help", 0, "", "Print this message and exit"}, {"debug", 0, "", "Enable debugging"}, {"quiet", 0, "", "Operate quietly"}, {"xregion", 1, "-1:-1", "X dimension subregion bounds (min:max)"}, {"yregion", 1, "-1:-1", "Y dimension subregion bounds (min:max)"}, {"zregion", 1, "-1:-1", "Z dimension subregion bounds (min:max)"}, {NULL}}; OptionParser::Option_T get_options[] = {{"ts", Wasp::CvtToInt, &opt.ts, sizeof(opt.ts)}, {"varname", Wasp::CvtToCPPStr, &opt.varname, sizeof(opt.varname)}, {"type", Wasp::CvtToCPPStr, &opt.type, sizeof(opt.type)}, {"level", Wasp::CvtToInt, &opt.level, sizeof(opt.level)}, {"lod", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)}, {"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {"xregion", Wasp::CvtToIntVec, &opt.xregion, sizeof(opt.xregion)}, {"yregion", Wasp::CvtToIntVec, &opt.yregion, sizeof(opt.yregion)}, {"zregion", Wasp::CvtToIntVec, &opt.zregion, sizeof(opt.zregion)}, {NULL}}; size_t size_of_type(string type) { if (type.compare("float32") == 0) return (4); if (type.compare("float64") == 0) return (8); if (type.compare("int8") == 0) return (1); return (1); } int write_data(FILE * fp, string type, // element type size_t n, const float *slice) { static SmartBuf smart_buf; size_t element_sz = size_of_type(type); unsigned char *buffer = (unsigned char *)smart_buf.Alloc(n * element_sz); const float *sptr = slice; if (type.compare("float32") == 0) { float *dptr = (float *)buffer; for (size_t i = 0; i < n; i++) { *dptr++ = (float)*sptr++; } } else if (type.compare("float64") == 0) { double *dptr = (double *)buffer; for (size_t i = 0; i < n; i++) { *dptr++ = (double)*sptr++; } } else if (type.compare("int8") == 0) { char *dptr = (char *)buffer; for (size_t i = 0; i < n; i++) { *dptr++ = (char)*sptr++; } } int rc = fwrite(buffer, element_sz, n, fp); if (rc != n) { MyBase::SetErrMsg("Error writing output file : %M"); return (-1); } return (0); } void process_volume(size_t ts, string varname, int level, int lod, VDCNetCDF &vdc, FILE *fp, vector dims, string type) { vector hslice_dims; size_t nslice; int rc = vdc.GetHyperSliceInfo(varname, opt.level, hslice_dims, nslice); if (rc < 0) { MyBase::SetErrMsg("Invalid variable name : %s", varname.c_str()); exit(1); } size_t nelements = 1; for (int i = 0; i < hslice_dims.size(); i++) { nelements *= hslice_dims[i]; } float *buffer = new float[nelements]; size_t ntotal = 1; for (int i = 0; i < dims.size(); i++) { ntotal *= dims[i]; } int fd = vdc.OpenVariableRead(ts, varname, level, lod); if (fd < 0) exit(1); for (size_t i = 0; i < nslice; i++) { rc = vdc.ReadSlice(fd, buffer); if (rc < 0) exit(1); nelements = nelements < ntotal ? nelements : ntotal; rc = write_data(fp, type, nelements, buffer); if (rc < 0) exit(1); ntotal -= nelements; } rc = vdc.CloseVariable(fd); if (rc < 0) exit(1); delete[] buffer; } void process_region(size_t ts, string varname, int level, int lod, VDCNetCDF &vdc, FILE *fp, vector dims, string type, const vector &xregion, const vector &yregion, const vector &zregion) { VAssert(dims.size() >= 1 && dims.size() <= 3); VAssert(xregion.size() == 2); VAssert(yregion.size() == 2); VAssert(zregion.size() == 2); vector min_bound; vector max_bound; min_bound.push_back(xregion[0] < 0 ? 0 : xregion[0]); max_bound.push_back(xregion[1] < 0 ? dims[0] - 1 : xregion[1]); int fd = vdc.OpenVariableRead(ts, varname, level, lod); if (fd < 0) exit(1); if (dims.size() > 1) { min_bound.push_back(yregion[0] < 0 ? 0 : yregion[0]); max_bound.push_back(yregion[1] < 0 ? dims[1] - 1 : yregion[1]); } if (dims.size() > 2) { min_bound.push_back(zregion[0] < 0 ? 0 : zregion[0]); max_bound.push_back(zregion[1] < 0 ? dims[2] - 1 : zregion[1]); } size_t nelements = 1; for (int i = 0; i < dims.size(); i++) { nelements *= max_bound[i] - min_bound[i] + 1; } float *region = new float[nelements]; int rc = vdc.ReadRegion(fd, min_bound, max_bound, region); if (rc < 0) exit(1); rc = write_data(fp, type, nelements, region); if (rc < 0) exit(1); delete[] region; rc = vdc.CloseVariable(fd); if (rc < 0) exit(1); } const char *ProgName; int main(int argc, char **argv) { OptionParser op; ProgName = FileUtils::LegacyBasename(argv[0]); MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] vdcmaster datafile" << endl; op.PrintOptionHelp(stderr); exit(0); } if (opt.xregion.size() != 2 || opt.yregion.size() != 2 || opt.zregion.size() != 2) { cerr << "Usage: " << ProgName << " [options] vdcmaster datafile" << endl; op.PrintOptionHelp(stderr); exit(1); } if (argc != 3) { cerr << "Usage: " << ProgName << " [options] vdcmaster datafile" << endl; op.PrintOptionHelp(stderr); exit(1); } string vdcmaster = argv[1]; string datafile = argv[2]; FILE *fp = fopen(datafile.c_str(), "wb"); if (!fp) { MyBase::SetErrMsg("Could not open file \"%s\" : %M", datafile.c_str()); exit(1); } VDCNetCDF vdc(opt.nthreads); vector bs; int rc = vdc.Initialize(vdcmaster, vector(), VDC::R, bs, 4 * 1024 * 1024); if (rc < 0) exit(1); vector dims; vector dummy; if (vdc.GetDimLensAtLevel(opt.varname, opt.level, dims, dummy) < 0) { exit(1); } if (dims.size() < 1) { MyBase::SetErrMsg("Variable must be 1D, 2D or 3D"); exit(1); } // if (opt.xregion[0] == -1 && opt.xregion[1] == -1 && opt.yregion[0] == -1 && opt.yregion[1] == -1 && opt.zregion[0] == -1 && opt.zregion[1] == -1) { process_volume(opt.ts, opt.varname, opt.level, opt.lod, vdc, fp, dims, opt.type); if (!opt.quiet) { cout << "Wrote "; for (int i = 0; i < dims.size(); i++) { cout << dims[i]; if (i != dims.size() - 1) cout << "x"; } cout << endl; } } else { process_region(opt.ts, opt.varname, opt.level, opt.lod, vdc, fp, dims, opt.type, opt.xregion, opt.yregion, opt.zregion); if (!opt.quiet) { cout << "Wrote "; cout << (opt.xregion[1] - opt.xregion[0] + 1) << "x"; cout << (opt.yregion[1] - opt.yregion[0] + 1) << "x"; cout << (opt.zregion[1] - opt.zregion[0] + 1) << endl; } } fclose(fp); exit(0); } ================================================ FILE: apps/vdccompare/CMakeLists.txt ================================================ add_executable (vdccompare vdccompare.cpp) target_link_libraries (vdccompare common vdc) OpenMPInstall ( TARGETS vdccompare DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/vdccompare/vdccompare.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; struct opt_t { int nthreads; int numts; int memsize; std::vector vars; OptionParser::Boolean_T datamgr; OptionParser::Boolean_T quiet; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"nthreads", 1, "0", "Specify number of execution threads " "0 => use number of cores"}, {"numts", 1, "-1", "Number of timesteps to be included in the VDC. Default (-1) includes all timesteps."}, { "memsize", 1, "2000", "Cache size in MBs (if -datamgr used)", }, {"vars", 1, "", "Colon delimited list of 3D variable names (compressed) " "to be included in " "the VDC"}, {"datamgr", 0, "", "Get data from second data source via DataMgr"}, {"quiet", 0, "", "Don't print individual variable results"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"numts", Wasp::CvtToInt, &opt.numts, sizeof(opt.numts)}, {"memsize", Wasp::CvtToInt, &opt.memsize, sizeof(opt.memsize)}, {"vars", Wasp::CvtToStrVec, &opt.vars, sizeof(opt.vars)}, {"datamgr", Wasp::CvtToBoolean, &opt.datamgr, sizeof(opt.datamgr)}, {"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; string ProgName; DC *DCCreate(string ftype) { if (ftype.compare("vdc") == 0) { return (new VDCNetCDF(opt.nthreads)); } else if (ftype.compare("wrf") == 0) { return (new DCWRF()); } else if (ftype.compare("cf") == 0) { return (new DCCF()); } else if (ftype.compare("mpas") == 0) { return (new DCMPAS()); } else { MyBase::SetErrMsg("Invalid data collection format : %s", ftype.c_str()); return (NULL); } } float *Buffer1; size_t BufSize1 = 0; float *Buffer2; size_t BufSize2 = 0; void computeLMax(const float *buf1, const float *buf2, size_t nelements, double &lmax, double &min, double &max, bool hasMissing, float mv) { lmax = 0.0; min = 0.0; max = 0.0; if (nelements < 1) return; size_t index = 0; while (hasMissing && buf1[index] == mv && index < nelements) index++; if (index >= nelements) return; min = max = buf1[index]; for (; index < nelements; index++) { if (hasMissing && buf1[index] == mv) continue; if (min > buf1[index]) { min = buf1[index]; } if (max < buf1[index]) { max = buf1[index]; } double diff = fabs(buf1[index] - buf2[index]); if (diff > lmax) { lmax = diff; } } } int get_var(DC *dc, size_t ts, string varname, float *Buffer) { return (dc->GetVar(ts, varname, -1, -1, Buffer)); } int get_var(DataMgr *data_mgr, size_t ts, string varname, float *Buffer) { Grid *grid = data_mgr->GetVariable(ts, varname, -1, -1); if (!grid) return (-1); Grid::Iterator itr; Grid::Iterator enditr = grid->end(); for (itr = grid->begin(); itr != enditr; ++itr, ++Buffer) { *Buffer = *itr; } delete grid; return (0); } template bool compare(S *dc1, T *dc2, size_t nts, string varname, double &nlmax_all) { vector dims; int rc = dc1->GetDimLens(varname, dims); if (rc < 0) return (false); vector dims2; rc = dc2->GetDimLens(varname, dims2, -1); if (rc < 0) return (false); VAssert(dims == dims2); size_t nelements = 1; for (int i = 0; i < dims.size(); i++) { nelements *= dims[i]; } if (BufSize1 < nelements) { if (Buffer1) delete[] Buffer1; Buffer1 = new float[nelements]; BufSize1 = nelements; if (Buffer2) delete[] Buffer2; Buffer2 = new float[nelements]; BufSize2 = nelements; } nlmax_all = 0.0; for (int ts = 0; ts < nts; ts++) { rc = get_var(dc1, ts, varname, Buffer1); if (rc < 0) return (false); DC::DataVar datavar; bool ok = dc1->GetDataVarInfo(varname, datavar); VAssert(ok); float mv = 0.0; bool hasMissing = datavar.GetHasMissing(); if (hasMissing) mv = datavar.GetMissingValue(); rc = get_var(dc2, ts, varname, Buffer2); if (rc < 0) return (false); double lmax, min, max; computeLMax(Buffer1, Buffer2, nelements, lmax, min, max, hasMissing, mv); if ((max - min) != 0.0) { lmax /= (max - min); } if (lmax > nlmax_all) { nlmax_all = lmax; } } return (true); } template int process(S *dc1, const vector &files1, T *dc2, const vector &files2) { int rc = dc1->Initialize(files1, vector()); if (rc < 0) return (1); rc = dc2->Initialize(files2, vector()); if (rc < 0) return (1); vector varnames; if (opt.vars.size()) { varnames = opt.vars; } else { varnames = dc1->GetDataVarNames(); } double max_nlmax = 0; bool success = true; for (int i = 0; i < varnames.size(); i++) { int nts = dc1->GetNumTimeSteps(varnames[i]); nts = opt.numts != -1 && nts > opt.numts ? opt.numts : nts; VAssert(nts >= 0); if (!opt.quiet) { cout << "Testing variable " << varnames[i] << endl; } double nlmax; bool ok = compare(dc1, dc2, nts, varnames[i], nlmax); if (!ok) { cout << "failed!" << endl; success = false; break; } if (!opt.quiet) { cout << " NLmax = " << nlmax << endl; } if (nlmax > max_nlmax) { max_nlmax = nlmax; } } cout << "Max NLmax = " << max_nlmax << endl; return success ? 0 : 1; } int main(int argc, char **argv) { OptionParser op; MyBase::SetErrMsgFilePtr(stderr); // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); } if (argc < 6 || opt.help) { cerr << "Usage: " << ProgName << " source_ftype secondary_ftype source_files... -- secondary_files... " << endl; cerr << "Valid file types: vdc, wrf, cf, mpas" << endl; op.PrintOptionHelp(stderr, 80, false); exit(1); } argc--; argv++; string ftype1 = argv[0]; argc--; argv++; string ftype2 = argv[0]; argc--; argv++; vector files1; string sep("--"); while (*argv && string(*argv) != sep) { files1.push_back(*argv); argv++; } if (*argv) argv++; vector files2; while (*argv) { files2.push_back(*argv); argv++; } DC *dc1 = NULL; dc1 = DCCreate(ftype1); if (!dc1) return (1); if (opt.datamgr) { DataMgr *datamgr2 = new DataMgr(ftype2, opt.memsize, opt.nthreads); return (process(dc1, files1, datamgr2, files2)); } else { DC *dc2 = DCCreate(ftype2); if (!dc2) return (1); return (process(dc1, files1, dc2, files2)); } } ================================================ FILE: apps/vdccreate/CMakeLists.txt ================================================ add_executable (vdccreate vdccreate.cpp) target_link_libraries (vdccreate common vdc) OpenMPInstall ( TARGETS vdccreate DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/vdccreate/vdccreate.cpp ================================================ #include #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; struct opt_t { OptionParser::Dimension3D_T dim; std::vector bs; std::vector cratios; string wname; string xtype; string xcoords; string ycoords; string zcoords; string tcoords; int numts; int nthreads; std::vector vars3d; std::vector vars2dxy; std::vector vars2dxz; std::vector vars2dyz; std::vector ncvars3d; std::vector ncvars2dxy; std::vector ncvars2dxz; std::vector ncvars2dyz; std::vector extents; OptionParser::Boolean_T force; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = { {"dimension", 1, "512x512x512", "Data volume dimensions expressed in " "grid points (NXxNYxNZ)"}, {"bs", 1, "64:64:64", "Internal storage blocking factor expressed in grid points (NX:NY:NZ)"}, {"cratios", 1, "500:100:10:1", "Colon delimited list compression ratios. " "The default is 500:100:10:1. The maximum compression ratio " "is wavelet and block size dependent."}, {"wname", 1, "bior4.4", "Wavelet family used for compression " "Valid values are bior1.1, bior1.3, " "bior1.5, bior2.2, bior2.4 ,bior2.6, bior2.8, bior3.1, bior3.3, " "bior3.5, bior3.7, bior3.9, bior4.4"}, {"xtype", 1, "float", "External data type representation. " "Valid values are uint8 int8 int16 int32 int64 float double"}, {"xcoords", 1, "", "Path to a file containing a newline " "delineated list of monotonically increasing X-axis user coordinates. The list may optionally be preceeded by a UDUNITS style units specification (e.g. meters, degrees_east)"}, {"ycoords", 1, "", "Path to a file containing a newline " "delineated list of monotonically increasing Y-axis user coordinates. The list may optionally be preceeded by a UDUNITS style units specification (e.g. meters, degrees_north)"}, {"zcoords", 1, "", "Path to a file containing a newline " "delineated list of monotonically increasing Z-axis user coordinates. The list may optionally be preceeded by a UDUNITS style units specification (e.g. meters)"}, {"tcoords", 1, "", "Path to a file containing a newline " "delineated list of monotonically increasing T-axis (time) user coordinates. The list may optionally be preceeded by a UDUNITS style units specification (e.g. hours since 2004-01-01 00:00:00)"}, {"numts", 1, "1", "Number of timesteps in the data set"}, {"nthreads", 1, "0", "Specify number of execution threads " "0 => use number of cores"}, {"vars3d", 1, "", "Colon delimited list of 3D variable names (compressed) " "to be included in " "the VDC"}, {"vars2dxy", 1, "", "Colon delimited list of 2D XY-plane variable " "names (compressed) " "to be included in the VDC"}, {"vars2dxz", 1, "", "Colon delimited list of 3D XZ-plane variable " "names (compressed) " "to be included in the VDC"}, {"vars2dyz", 1, "", "Colon delimited list of 3D YZ-plane variable " "names (compressed) " "to be included in the VDC"}, {"ncvars3d", 1, "", "Colon delimited list of 3D variable names (not compressed) " "to be included in " "the VDC"}, {"ncvars2dxy", 1, "", "Colon delimited list of 2D XY-plane variable " "names (not compressed) " "to be included in the VDC"}, {"ncvars2dxz", 1, "", "Colon delimited list of 3D XZ-plane variable " "names (not compressed) " "to be included in the VDC"}, {"ncvars2dyz", 1, "", "Colon delimited list of 3D YZ-plane variable " "names (not compressed) " "to be included in the VDC"}, {"extents", 1, "", "Colon delimited 6-element vector " "specifying domain extents in user coordinates (X0:Y0:Z0:X1:Y1:Z1)"}, {"force", 0, "", "Create a new VDC master file even if a VDC data " "directory already exists. Results may be undefined if settings between " "the new master file and old data directory do not match."}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"dimension", Wasp::CvtToDimension3D, &opt.dim, sizeof(opt.dim)}, {"bs", Wasp::CvtToSize_tVec, &opt.bs, sizeof(opt.bs)}, {"cratios", Wasp::CvtToSize_tVec, &opt.cratios, sizeof(opt.cratios)}, {"wname", Wasp::CvtToCPPStr, &opt.wname, sizeof(opt.wname)}, {"xtype", Wasp::CvtToCPPStr, &opt.xtype, sizeof(opt.xtype)}, {"xcoords", Wasp::CvtToCPPStr, &opt.xcoords, sizeof(opt.xcoords)}, {"ycoords", Wasp::CvtToCPPStr, &opt.ycoords, sizeof(opt.ycoords)}, {"zcoords", Wasp::CvtToCPPStr, &opt.zcoords, sizeof(opt.zcoords)}, {"tcoords", Wasp::CvtToCPPStr, &opt.tcoords, sizeof(opt.tcoords)}, {"numts", Wasp::CvtToInt, &opt.numts, sizeof(opt.numts)}, {"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"vars3d", Wasp::CvtToStrVec, &opt.vars3d, sizeof(opt.vars3d)}, {"vars2dxy", Wasp::CvtToStrVec, &opt.vars2dxy, sizeof(opt.vars2dxy)}, {"vars2dxz", Wasp::CvtToStrVec, &opt.vars2dxz, sizeof(opt.vars2dxz)}, {"vars2dyz", Wasp::CvtToStrVec, &opt.vars2dyz, sizeof(opt.vars2dyz)}, {"ncvars3d", Wasp::CvtToStrVec, &opt.ncvars3d, sizeof(opt.ncvars3d)}, {"ncvars2dxy", Wasp::CvtToStrVec, &opt.ncvars2dxy, sizeof(opt.ncvars2dxy)}, {"ncvars2dxz", Wasp::CvtToStrVec, &opt.ncvars2dxz, sizeof(opt.ncvars2dxz)}, {"ncvars2dyz", Wasp::CvtToStrVec, &opt.ncvars2dyz, sizeof(opt.ncvars2dyz)}, {"extents", Wasp::CvtToFloatVec, &opt.extents, sizeof(opt.extents)}, {"force", Wasp::CvtToBoolean, &opt.force, sizeof(opt.force)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; string ProgName; void set_coord_uniform(VDCNetCDF &vdc, string dimname, size_t dimlen, float min, float max) { VAssert(dimlen >= 1); float *buf = new float[dimlen]; float delta = dimlen > 1 ? (max - min) / (float)(dimlen - 1) : 0.0; for (int i = 0; i < dimlen; i++) { buf[i] = min + i * delta; } int rc = vdc.PutVar(0, dimname, -1, buf); if (rc < 0) exit(1); } void set_coord_stretched(VDCNetCDF &vdc, string dimname, const vector &coords) { int rc = vdc.PutVar(0, dimname, -1, coords.data()); if (rc < 0) exit(1); } void set_coords_uniform(VDCNetCDF &vdc, const vector &extents, const vector &dimnames, const vector &dimlens) { if (!extents.size()) return; VAssert(extents.size() == 6); VAssert(dimnames.size() == 4); VAssert(dimlens.size() == 4); set_coord_uniform(vdc, dimnames[0], dimlens[0], extents[0], extents[3]); set_coord_uniform(vdc, dimnames[1], dimlens[1], extents[1], extents[4]); set_coord_uniform(vdc, dimnames[2], dimlens[2], extents[2], extents[5]); } DC::XType parseXType(string xTypeStr) { if (xTypeStr == "uint8") return (DC::XType::UINT8); if (xTypeStr == "int8") return (DC::XType::INT8); // if (xTypeStr == "int16") return (DC::XType::INT16); if (xTypeStr == "int32") return (DC::XType::INT32); if (xTypeStr == "int64") return (DC::XType::INT64); if (xTypeStr == "float") return (DC::XType::FLOAT); if (xTypeStr == "float32") return (DC::XType::FLOAT); if (xTypeStr == "float64") return (DC::XType::DOUBLE); if (xTypeStr == "double") return (DC::XType::DOUBLE); return (DC::XType::INVALID); } bool string_to_float(string s, float &f) { f = 0.0; try { f = std::stof(s); } catch (invalid_argument const&) { return (false); } catch (out_of_range const&) { return (false); } return (true); } int read_float_vec(string path, size_t n, vector &vec, string &unit) { vec.clear(); unit.clear(); ifstream fin(path.c_str()); if (!fin) { MyBase::SetErrMsg("Error opening file %s", path.c_str()); return (-1); } string item; while (getline(fin, item)) { if (item.empty()) continue; float f; bool ok = string_to_float(item, f); if (!ok) { if (vec.empty()) { unit = item; continue; } else { MyBase::SetErrMsg("Invalid float %s", item.c_str()); return -1; } } vec.push_back(f); } if (fin.bad()) { MyBase::SetErrMsg("Error reading file %s", path.c_str()); return (-1); } fin.close(); // Make sure values are monotonic and increasing // bool mono = true; for (int i = 0; i < (int)vec.size() - 1; i++) { if (vec[i] > vec[i + 1]) mono = false; } if (!mono) { MyBase::SetErrMsg("Sequence contained in %s must be monotonic", path.c_str()); return (-1); } if (vec.size() != n) { MyBase::SetErrMsg("Short read file %s", path.c_str()); return (-1); } return (0); } int main(int argc, char **argv) { OptionParser op; MyBase::SetErrMsgFilePtr(stderr); // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); } if (argc != 2) { cerr << "Usage: " << ProgName << " [options] master.vdc" << endl; op.PrintOptionHelp(stderr, 80, false); exit(1); } if (opt.extents.size() && opt.extents.size() != 6) { cerr << "Usage: " << ProgName << " master.vdc" << endl; op.PrintOptionHelp(stderr, 80, false); exit(1); } string master = argv[1]; if (FileUtils::Extension(master) != "vdc") { fprintf(stderr, "Warning: VDC files should the extension .vdc\n"); } if (opt.help) { cerr << "Usage: " << ProgName << " master.vdc" << endl; op.PrintOptionHelp(stderr, 80, false); exit(0); } DC::XType xType = parseXType(opt.xtype); if (xType == DC::XType::INVALID) { MyBase::SetErrMsg("Invalid external data type specifier : %s", opt.xtype.c_str()); exit(1); } VDCNetCDF vdc(opt.nthreads); if (vdc.DataDirExists(master) && !opt.force) { MyBase::SetErrMsg("Data directory exists and -force option not used. " "Remove directory %s or use -force", vdc.GetDataDir(master).c_str()); exit(1); } if (FileUtils::Exists(master) && !opt.force) { MyBase::SetErrMsg("\"%s\" already exists and -force option not used.", master.c_str()); exit(1); } size_t chunksize = 1024 * 1024 * 4; int rc = vdc.Initialize(master, vector(), VDC::W, opt.bs, chunksize); if (rc < 0) exit(1); vector xcoords, ycoords, zcoords, tcoords; string xunit, yunit, zunit, tunit; if (!opt.xcoords.empty()) { rc = read_float_vec(opt.xcoords, opt.dim.nx, xcoords, xunit); if (rc < 0) exit(1); } if (!opt.ycoords.empty()) { rc = read_float_vec(opt.ycoords, opt.dim.ny, ycoords, yunit); if (rc < 0) exit(1); } if (!opt.zcoords.empty()) { rc = read_float_vec(opt.zcoords, opt.dim.nz, zcoords, zunit); if (rc < 0) exit(1); } if (!opt.tcoords.empty()) { rc = read_float_vec(opt.tcoords, opt.numts, tcoords, tunit); if (rc < 0) exit(1); } vector dimnames; dimnames.push_back("Nx"); dimnames.push_back("Ny"); dimnames.push_back("Nz"); dimnames.push_back("Nt"); vector dimlens; dimlens.push_back(opt.dim.nx); dimlens.push_back(opt.dim.ny); dimlens.push_back(opt.dim.nz); dimlens.push_back(opt.numts); vector cratios(1, 1); rc = vdc.SetCompressionBlock("", cratios); rc = vdc.DefineDimension(dimnames[0], dimlens[0], 0); rc = vdc.DefineDimension(dimnames[1], dimlens[1], 1); rc = vdc.DefineDimension(dimnames[2], dimlens[2], 2); rc = vdc.DefineDimension(dimnames[3], dimlens[3], 3); if (rc < 0) exit(1); if (!opt.xcoords.empty()) { rc = vdc.DefineCoordVar(dimnames[0], vector{dimnames[0]}, "", xunit, 0, DC::XType::FLOAT, false); } if (!opt.ycoords.empty()) { rc = vdc.DefineCoordVar(dimnames[1], vector{dimnames[1]}, "", yunit, 1, DC::XType::FLOAT, false); } if (!opt.zcoords.empty()) { rc = vdc.DefineCoordVar(dimnames[2], vector{dimnames[2]}, "", zunit, 2, DC::XType::FLOAT, false); } if (!opt.tcoords.empty()) { rc = vdc.DefineCoordVar(dimnames[3], vector(), dimnames[3], tunit, 3, DC::XType::FLOAT, false); } rc = vdc.SetCompressionBlock(opt.wname, opt.cratios); if (rc < 0) exit(1); for (int i = 0; i < opt.vars3d.size(); i++) { rc = vdc.DefineDataVar(opt.vars3d[i], dimnames, dimnames, "", xType, true); } for (int i = 0; i < opt.ncvars3d.size(); i++) { rc = vdc.DefineDataVar(opt.ncvars3d[i], dimnames, dimnames, "", xType, false); } vector dimnames2dxy; dimnames2dxy.push_back(dimnames[0]); dimnames2dxy.push_back(dimnames[1]); dimnames2dxy.push_back(dimnames[3]); // // Try to compute "reasonable" 2D compression ratios from 3D // compression ratios // vector cratios2D = opt.cratios; for (int i = 0; i < cratios2D.size(); i++) { size_t c = (size_t)pow((double)cratios2D[i], (double)(2.0 / 3.0)); cratios2D[i] = c; } rc = vdc.SetCompressionBlock(opt.wname, cratios2D); if (rc < 0) exit(1); for (int i = 0; i < opt.vars2dxy.size(); i++) { rc = vdc.DefineDataVar(opt.vars2dxy[i], dimnames2dxy, dimnames2dxy, "", xType, true); } for (int i = 0; i < opt.ncvars2dxy.size(); i++) { rc = vdc.DefineDataVar(opt.ncvars2dxy[i], dimnames2dxy, dimnames2dxy, "", xType, false); } vector dimnames2dxz; dimnames2dxz.push_back(dimnames[0]); dimnames2dxz.push_back(dimnames[2]); dimnames2dxz.push_back(dimnames[3]); for (int i = 0; i < opt.vars2dxz.size(); i++) { rc = vdc.DefineDataVar(opt.vars2dxz[i], dimnames2dxz, dimnames2dxz, "", xType, true); } for (int i = 0; i < opt.ncvars2dxz.size(); i++) { rc = vdc.DefineDataVar(opt.ncvars2dxz[i], dimnames2dxz, dimnames2dxz, "", xType, false); } vector dimnames2dyz; dimnames2dyz.push_back(dimnames[1]); dimnames2dyz.push_back(dimnames[2]); dimnames2dyz.push_back(dimnames[3]); for (int i = 0; i < opt.vars2dyz.size(); i++) { rc = vdc.DefineDataVar(opt.vars2dyz[i], dimnames2dyz, dimnames2dyz, "", xType, true); } for (int i = 0; i < opt.ncvars2dyz.size(); i++) { rc = vdc.DefineDataVar(opt.ncvars2dyz[i], dimnames2dyz, dimnames2dyz, "", xType, false); } vdc.EndDefine(); // Set coordinates to be uniform (e.g. a regular grid) // set_coords_uniform(vdc, opt.extents, dimnames, dimlens); // Handle any stretched dimensions // if (xcoords.size()) { set_coord_stretched(vdc, dimnames[0], xcoords); } if (ycoords.size()) { set_coord_stretched(vdc, dimnames[1], ycoords); } if (zcoords.size()) { set_coord_stretched(vdc, dimnames[2], zcoords); } if (tcoords.size()) { set_coord_stretched(vdc, dimnames[3], tcoords); } return (0); } ================================================ FILE: apps/vdcdump/CMakeLists.txt ================================================ add_executable (vdcdump vdcdump.cpp) target_link_libraries (vdcdump common vdc) OpenMPInstall ( TARGETS vdcdump DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/vdcdump/vdcdump.cpp ================================================ #include #include #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; typedef VDCNetCDF::XType XType; typedef DC::Dimension Dimension; typedef unsigned int Verbosity; struct Attribute; struct Variable; struct DataVariable; struct CoordVariable; class OutFormat; //--------------------------------------- // Command Line Options //--------------------------------------- struct opt_t { OptionParser::Boolean_T verbose; OptionParser::Boolean_T ncOrder; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = { {"verbose", 0, "0", "Print additional information"}, {"nc-order", 0, "0", "Reverse dimension order to match NetCDF"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"verbose", Wasp::CvtToBoolean, &opt.verbose, sizeof(opt.verbose)}, {"nc-order", Wasp::CvtToBoolean, &opt.ncOrder, sizeof(opt.ncOrder)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; //--------------------------------------- // Utility Functions and Print Format //--------------------------------------- #define Assert(tst) \ { \ if (!(tst)) { \ cerr << "[" << __LINE__ << ":" << __FILE__ << "] Assert Failed: " << #tst << endl; \ std::raise(SIGINT); \ } \ } class OutFormat { protected: int _depth; public: stringstream _ss; OutFormat() : _depth(0) {} void push() { _depth++; } void pop() { _depth--; Assert(_depth >= 0); } void pre() { for (int i = 0; i < _depth; i++) cout << "\t"; } void post() { cout << _ss.str() << " ;" << endl; _ss.str(""); _ss.clear(); } void header(string name) { cout << "----------------------------------" << endl; cout << name << endl; cout << "----------------------------------" << endl; } void stringProperty(string owner, string name, string value) { pre(); _ss << owner << (owner == "" ? "" : ":") << name << " = \"" << value << "\""; post(); } void boolProperty(string owner, string name, bool value) { pre(); _ss << owner << (owner == "" ? "" : ":") << name << " = " << (value ? "True" : "False"); post(); } void intProperty(string owner, string name, long value) { pre(); _ss << owner << (owner == "" ? "" : ":") << name << " = " << value; post(); } void floatProperty(string owner, string name, double value) { pre(); _ss << owner << (owner == "" ? "" : ":") << name << " = " << value; post(); } void typeProperty(string owner, XType type) { pre(); _ss << owner << (owner == "" ? "" : ":") << "Type = " << GetTypeString(type); post(); } template void vectorProperty(string owner, string name, vector array, bool reversed) { pre(); _ss << owner << (owner == "" ? "" : ":") << name << " = "; if (reversed) for (int i = array.size() - 1; i >= 0; i--) _ss << (T)array[i] << (i == 0 ? "" : ", "); else for (int i = 0; i < array.size(); i++) _ss << (T)array[i] << (i == array.size() - 1 ? "" : ", "); post(); } void category(string name) { pre(); _ss << name; post(); } static string GetAxisString(int axis) { switch (axis) { case 0: return "X"; case 1: return "Y"; case 2: return "Z"; case 3: return "Time"; default: return std::to_string((long long int)axis); } } static string GetTypeString(XType type) { switch (type) { case XType::UINT8: return "uint8"; case XType::INT8: return "int8"; case XType::INT32: return "int32"; case XType::INT64: return "int64"; case XType::FLOAT: return "float"; case XType::DOUBLE: return "double"; case XType::TEXT: return "text"; case XType::INVALID: return "INVALID"; default: return "INVALID"; }; } }; //--------------------------------------- // Classes that load and print vdc data //--------------------------------------- struct Attribute { string _name; XType _type; vector _ivalues; vector _fvalues; string _svalues; Attribute(string name, XType type) : _name(name), _type(type) {} bool isInt() { return _type == XType::INT32 || _type == XType::INT64; } bool isFloat() { return _type == XType::FLOAT || _type == XType::DOUBLE; } bool isText() { return _type == XType::TEXT; } void print(OutFormat *out, string parentName) { if (isText()) out->stringProperty(parentName, _name, _svalues); else if (isInt()) out->vectorProperty(parentName, _name, _ivalues, false); else out->vectorProperty(parentName, _name, _fvalues, false); } }; struct Variable { string _name; DC::BaseVar * _data; vector _attributes; vector _dimnames; Variable(string name, VDCNetCDF &vdc) : _name(name), _data(0) { // // Get Attributes // vector attNames = vdc.GetAttNames(name); for (int i = 0; i < attNames.size(); i++) { _attributes.push_back(Attribute(attNames[i], vdc.GetAttType(name, attNames[i]))); if (_attributes[i].isInt()) vdc.GetAtt(name, attNames[i], _attributes[i]._ivalues); else if (_attributes[i].isFloat()) vdc.GetAtt(name, attNames[i], _attributes[i]._fvalues); else if (_attributes[i].isText()) vdc.GetAtt(name, attNames[i], _attributes[i]._svalues); } vdc.GetVarDimNames(_name, false, _dimnames); } virtual ~Variable() {} void printName(OutFormat *out, Verbosity V, bool reversedCoordOrder) { out->pre(); out->_ss << OutFormat::GetTypeString(_data->GetXType()) << " " << _name << "("; if (reversedCoordOrder) for (int i = _dimnames.size() - 1; i >= 0; i--) out->_ss << _dimnames[i] << (i != 0 ? ", " : ""); else for (int i = 0; i < _dimnames.size(); i++) out->_ss << _dimnames[i] << (i != _dimnames.size() - 1 ? ", " : ""); out->_ss << ")"; out->post(); } virtual void printChild(OutFormat *out, Verbosity V, bool reversedCoordOrder) = 0; virtual void print(OutFormat *out, Verbosity V, bool reversedCoordOrder) { printName(out, V, reversedCoordOrder); out->push(); // Print VDC specific data if verbose if (V >= 1) { out->stringProperty(_name, "Units", _data->GetUnits()); out->stringProperty(_name, "WName", _data->GetWName()); out->vectorProperty(_name, "CRatios", _data->GetCRatios(), false); out->vectorProperty(_name, "Periodic", _data->GetPeriodic(), false); } // Print information specific to Data or Coordinate variable printChild(out, V, reversedCoordOrder); // Print attributes if (_attributes.size()) { out->category("Attributes"); out->push(); for (int i = 0; i < _attributes.size(); i++) _attributes[i].print(out, _name); out->pop(); } out->pop(); } }; struct DataVariable : public Variable { vector _coordvars; DataVariable(string name, VDCNetCDF &vdc) : Variable(name, vdc) { _data = new DC::DataVar(); vdc.GetDataVarInfo(name, *(DC::DataVar *)_data); vdc.GetVarCoordVars(name, false, _coordvars); } ~DataVariable() { if (_data) delete _data; } void printChild(OutFormat *out, Verbosity V, bool reversedCoordOrder) { out->vectorProperty(_name, "Coord Vars", _coordvars, reversedCoordOrder); // Print VDC specific data if verbose if (V >= 1) { out->stringProperty(_name, "Mask Var", ((DC::DataVar *)_data)->GetMaskvar()); out->boolProperty(_name, "Has Missing", ((DC::DataVar *)_data)->GetHasMissing()); out->boolProperty(_name, "Missing Value", ((DC::DataVar *)_data)->GetMissingValue()); } } }; struct CoordVariable : public Variable { CoordVariable(string name, VDCNetCDF &vdc) : Variable(name, vdc) { _data = new DC::CoordVar(); vdc.GetCoordVarInfo(name, *(DC::CoordVar *)_data); } ~CoordVariable() { if (_data) delete _data; } void printChild(OutFormat *out, Verbosity V, bool reversedCoordOrder) { out->stringProperty(_name, "Axis", OutFormat::GetAxisString(((DC::CoordVar *)_data)->GetAxis())); // Print VDC specific data if verbose if (V >= 1) { out->boolProperty(_name, "Uniform", ((DC::CoordVar *)_data)->GetUniform()); } } }; struct GlobalData : public Variable { vector _dimensions; GlobalData(VDCNetCDF &vdc) : Variable("", vdc) { _name = "__GLOBAL__"; vector dimNames = vdc.GetDimensionNames(); _dimensions.resize(dimNames.size()); for (int i = 0; i < dimNames.size(); i++) vdc.GetDimension(dimNames[i], _dimensions[i], -1); } void printChild(OutFormat *out, Verbosity V, bool reversedCoordOrder) {} void print(OutFormat *out, Verbosity V, bool reversedCoordOrder) { out->category("Dimensions"); out->push(); for (int i = 0; i < _dimensions.size(); i++) { out->category(_dimensions[i].GetName()); out->push(); out->intProperty("", "Length", _dimensions[i].GetLength()); out->pop(); } out->pop(); out->category("Attributes"); out->push(); for (int i = 0; i < _attributes.size(); i++) _attributes[i].print(out, ""); out->pop(); } }; //--------------------------------------- // Utility Functions and Print Format //--------------------------------------- int main(int argc, char **argv) { OptionParser op; const char * progName = FileUtils::LegacyBasename(argv[0]); MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << progName << ": " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << progName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << progName << " [options] vdc.vdc" << endl; op.PrintOptionHelp(stderr); exit(0); } if (argc != 2) { cerr << "Usage: " << progName << " vdcmaster.vdc" << endl; exit(1); } VDCNetCDF vdc(1); int rc = vdc.Initialize(string(argv[1]), vector(), VDC::R, vector(), 4 * 1024 * 1024); if (rc < 0) exit(1); // // Allocate VDC data // GlobalData * globalData; vector variables; vector coordinates; // // Load VDC data // globalData = new GlobalData(vdc); vector varNames = vdc.GetDataVarNames(); for (int i = 0; i < varNames.size(); i++) variables.push_back(new DataVariable(varNames[i], vdc)); vector coordNames = vdc.GetCoordVarNames(); for (int i = 0; i < coordNames.size(); i++) coordinates.push_back(new CoordVariable(coordNames[i], vdc)); // // Print VDC data // OutFormat *out = new OutFormat; out->header("Global Data"); globalData->print(out, opt.verbose, opt.ncOrder); out->header("Data Variables"); for (int i = 0; i < variables.size(); i++) variables[i]->print(out, opt.verbose, opt.ncOrder); out->header("Coordinate Variables"); for (int i = 0; i < coordinates.size(); i++) coordinates[i]->print(out, opt.verbose, opt.ncOrder); return 0; } ================================================ FILE: apps/vdcerr/vdcerr.cpp ================================================ #include #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include using namespace Wasp; using namespace VAPoR; struct opt_t { int ts; char * varname; int lod; int nthreads; OptionParser::Boolean_T quiet; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"ts", 1, "0", "Timestep of data file starting from 0"}, {"varname", 1, "var1", "Name of variable"}, {"lod", 1, "-1", "Compression level of detail. Zero implies coarsest approximation"}, {"nthreads", 1, "0", "Number of execution threads (0=># processors)"}, {"quiet", 0, "", "Be less verbose"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"ts", Wasp::CvtToInt, &opt.ts, sizeof(opt.ts)}, {"varname", Wasp::CvtToString, &opt.varname, sizeof(opt.varname)}, {"lod", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)}, {"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; const char *ProgName; float *read_vdc_volume(string metafile, size_t dims[3], bool &has_missing, float &mv) { has_missing = false; mv = 0.0; string varname = opt.varname; WaveCodecIO *wcreader = new WaveCodecIO(metafile, opt.nthreads); if (wcreader->GetErrCode() != 0) { return (NULL); } if (wcreader->OpenVariableRead(opt.ts, varname.c_str(), -1, opt.lod) < 0) { return (NULL); } if (wcreader->GetVMissingValue(opt.ts, varname).size() == 1) { mv = wcreader->GetVMissingValue(0, varname)[0]; has_missing = true; } else if (wcreader->GetTSMissingValue(opt.ts).size() == 1) { mv = wcreader->GetTSMissingValue(opt.ts)[0]; has_missing = true; } else if (wcreader->GetMissingValue().size() == 1) { mv = wcreader->GetMissingValue()[0]; has_missing = true; } Metadata::VarType_T vtype = wcreader->GetVarType(varname); wcreader->GetDim(dims, -1); switch (vtype) { case Metadata::VAR2D_XY: dims[2] = 1; break; case Metadata::VAR2D_XZ: dims[1] = dims[2]; dims[2] = 1; break; case Metadata::VAR2D_YZ: dims[0] = dims[1]; dims[1] = dims[2]; dims[2] = 1; break; case Metadata::VAR3D: break; default: break; } size_t slice_size = dims[0] * dims[1]; float *buf = new float[slice_size * dims[2]]; float *bufptr = buf; VAssert(buf != NULL); for (int z = 0; z < dims[2]; z++) { if (!opt.quiet && z % 10 == 0) { cout << "Reading vdc slice # " << z << endl; } if (wcreader->ReadSlice(bufptr) < 0) { return (NULL); } bufptr += slice_size; } wcreader->CloseVariable(); return (buf); } float *read_raw_volume(string file, const size_t dims[3]) { FILE *fp = FOPEN64(file.c_str(), "r"); if (!fp) { MyBase::SetErrMsg("Could not open file \"%s\" : %M", file.c_str()); return (NULL); } size_t slice_size = dims[0] * dims[1]; float *buf = new float[slice_size * dims[2]]; float *bufptr = buf; VAssert(buf != NULL); for (int z = 0; z < dims[2]; z++) { if (!opt.quiet && z % 10 == 0) { cout << "Reading raw slice # " << z << endl; } int rc = fread(bufptr, sizeof(bufptr[0]), slice_size, fp); if (rc != slice_size) { MyBase::SetErrMsg("Errore reading slice : %M"); return (NULL); } bufptr += slice_size; } fclose(fp); return (buf); } void compute_error(const float *odata, const float *cdata, size_t nelements, bool has_missing, float mv, float &lmax, float &rms, float &min, float &max) { lmax = 0.0; rms = 0.0; min = 0.0; max = 0.0; double delta = 0; double sqrsum = 0; size_t nvalid = 0; bool first = true; for (size_t idx = 0; idx < nelements; idx++) { if (has_missing && cdata[idx] == mv) continue; nvalid++; if (first) { min = max = odata[idx]; first = false; } if (min > odata[idx]) min = odata[idx]; if (max < odata[idx]) max = odata[idx]; delta = fabs(odata[idx] - cdata[idx]); if (delta > lmax) lmax = delta; sqrsum += (odata[idx] - cdata[idx]) * (odata[idx] - cdata[idx]); } rms = (float)sqrt(sqrsum / (double)nvalid); } int main(int argc, char **argv) { OptionParser op; string metafile; string datafile; ProgName = Basename(argv[0]); MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] metafile datafile" << endl; op.PrintOptionHelp(stderr); exit(0); } if (argc != 3) { cerr << "Usage: " << ProgName << " [options] metafile datafile" << endl; op.PrintOptionHelp(stderr); exit(1); } metafile = argv[1]; datafile = argv[2]; size_t dims[3]; bool has_missing; float mv; float *vdcdata = read_vdc_volume(metafile, dims, has_missing, mv); if (!vdcdata) exit(1); float *rawdata = read_raw_volume(datafile, dims); if (!rawdata) exit(1); float lmax, rms, min, max; compute_error(rawdata, vdcdata, dims[0] * dims[1] * dims[2], has_missing, mv, lmax, rms, min, max); float lmaxrel = 0.0; if ((max - min) != 0.0) lmaxrel = lmax / (max - min); float nrms = 0.0; if ((max - min) != 0.0) nrms = rms / (max - min); cout << "Range : " << min << " .. " << max << endl; cout << "Lmax : " << lmax << endl; cout << "Lmax Relative: " << lmaxrel << endl; cout << "RMS : " << rms << endl; cout << "Normalized RMS : " << nrms << endl; exit(0); } ================================================ FILE: apps/wasp2ncdf/CMakeLists.txt ================================================ add_executable (wasp2ncdf wasp2ncdf.cpp) target_link_libraries (wasp2ncdf common wasp) OpenMPInstall ( TARGETS wasp2ncdf DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/wasp2ncdf/wasp2ncdf.cpp ================================================ #include #include #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; // // Command line argument stuff // struct opt_t { string varname; int lod; int nthreads; std::vector xvarnames; OptionParser::Boolean_T debug; OptionParser::Boolean_T quiet; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"varname", 1, "var1", "Name of variable"}, {"lod", 1, "-1", "Compression levels saved. 0 => coarsest, 1 => " "next refinement, etc. -1 => all levels defined by the netcdf file"}, {"nthreads", 1, "0", "Specify number of execution threads " "0 => use number of cores"}, {"xvarnames", 1, "", "Colon delimited list of variable names " "to exclude from compression."}, {"debug", 0, "", "Enable diagnostic"}, {"quiet", 0, "", "Operate quietly"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"varname", Wasp::CvtToCPPStr, &opt.varname, sizeof(opt.varname)}, {"lod", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)}, {"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"xvarnames", Wasp::CvtToStrVec, &opt.xvarnames, sizeof(opt.xvarnames)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; const char *ProgName; // Return true if string 'name' contained in vector of strings, 'names' // bool name_in(string name, const vector &names) { return (find(names.begin(), names.end(), name) != names.end()); } int GetDims(const WASP &wasp, vector &dimnames, vector &dimlens) { dimnames.clear(); dimlens.clear(); vector vars; int rc = wasp.InqVarnames(vars); if (rc < 0) return (-1); // Ugh. No easy way to find all of the implicitly defined WASP // dimensions in a file. So find all explicitly defined // dimensions for each variable, and use that list to build // list of dimensions // vector all_dimnames; for (int i = 0; i < vars.size(); i++) { vector var_dimnames; vector dummy; int rc = wasp.InqVarDims(vars[i], var_dimnames, dummy); if (rc < 0) return (-1); all_dimnames.insert(all_dimnames.begin(), var_dimnames.begin(), var_dimnames.end()); } // // sort and remove duplicates // sort(all_dimnames.begin(), all_dimnames.end()); vector::iterator lasts; lasts = unique(all_dimnames.begin(), all_dimnames.end()); all_dimnames.erase(lasts, all_dimnames.end()); vector my_dimnames; vector my_dimlens; rc = wasp.InqDims(my_dimnames, my_dimlens); if (rc < 0) return (-1); VAssert(my_dimnames.size() == my_dimlens.size()); for (int i = 0; i < my_dimnames.size(); i++) { if (name_in(my_dimnames[i], all_dimnames)) { dimnames.push_back(my_dimnames[i]); dimlens.push_back(my_dimlens[i]); } } return (0); } // // Define the WASP output file using 'ncdf' as a template // int DefFile(const WASP &wasp, NetCDFCpp &ncdf) { vector dimnames; vector dimlens; int rc = GetDims(wasp, dimnames, dimlens); if (rc < 0) return (-1); VAssert(dimnames.size() == dimlens.size()); for (int i = 0; i < dimnames.size(); i++) { rc = ncdf.DefDim(dimnames[i], dimlens[i]); if (rc < 0) return (-1); } vector attnames; rc = wasp.InqAttnames("", attnames); if (rc < 0) return (-1); for (int i = 0; i < attnames.size(); i++) { if (attnames[i].find("WASP") != std::string::npos) continue; rc = wasp.CopyAtt("", attnames[i], ncdf, ""); if (rc < 0) return (-1); } return (0); } // Get all of the variable names, and parse // the names into a vector of // variable names that will be copied verbatim, and a vector of variable // names that will be de-compressed. // int GetVarNames(const WASP &wasp, vector &vars, vector ©_vars, vector &compress_vars) { vars.clear(); copy_vars.clear(); compress_vars.clear(); int rc = wasp.InqVarnames(vars); if (rc < 0) return (-1); for (int i = 0; i < vars.size(); i++) { bool wasp_var; rc = wasp.InqVarWASP(vars[i], wasp_var); if (rc < 0) return (-1); if (wasp_var) { compress_vars.push_back(vars[i]); } else { copy_vars.push_back(vars[i]); } } return (0); } // Copy variables verbatim from 'wasp' to 'ncdf' // int CopyVars(NetCDFCpp &wasp, const vector ©_vars, NetCDFCpp &ncdf) { for (int i = 0; i < copy_vars.size(); i++) { if (!opt.quiet) { cout << "Copying variable " << copy_vars[i] << endl; } int rc = wasp.CopyVar(copy_vars[i], ncdf); if (rc < 0) return (-1); } return (0); } // Define a variable that will not be compressed (i.e copied verbatim) // int DefCopyVar(const WASP &wasp, string varname, NetCDFCpp &ncdf) { vector dimnames; vector dimlens; int rc = wasp.InqVarDims(varname, dimnames, dimlens); if (rc < 0) return (-1); nc_type xtype; rc = wasp.InqVartype(varname, xtype); if (rc < 0) return (-1); rc = ncdf.DefVar(varname, xtype, dimnames); if (rc < 0) return (-1); return (0); } // Define all variables in 'wasp', preserving the variable order // in 'ncdf' // int DefVars(const WASP &wasp, const vector &vars, NetCDFCpp &ncdf) { int rc; for (int i = 0; i < vars.size(); i++) { rc = DefCopyVar(wasp, vars[i], ncdf); if (rc < 0) return (-1); // Now copy variable attributes // vector attnames; rc = wasp.InqAttnames(vars[i], attnames); if (rc < 0) return (-1); for (int j = 0; j < attnames.size(); j++) { if (attnames[j].find("WASP") != std::string::npos) continue; rc = wasp.CopyAtt(vars[i], attnames[j], ncdf, vars[i]); if (rc < 0) return (-1); } } return (0); } // Compress variables // int DeCompressVars(WASP &wasp, const vector ©_vars, NetCDFCpp &ncdf) { for (int i = 0; i < copy_vars.size(); i++) { if (!opt.quiet) { cout << "Decompressing variable " << copy_vars[i] << endl; } int rc = wasp.CopyVarTo(copy_vars[i], ncdf); if (rc < 0) return (-1); } return (0); } void Process(string waspfile, string ncdffile) { NetCDFCpp ncdf; WASP wasp; size_t chunksize = 1024 * 1024 * 4; int rc = wasp.Open(waspfile, NC_NOWRITE); if (rc < 0) { MyBase::SetErrMsg("Error opening %s for reading", waspfile.c_str()); exit(1); } rc = ncdf.Create(ncdffile, NC_64BIT_OFFSET, 0, chunksize); if (rc < 0) { MyBase::SetErrMsg("Error opening %s for writing", ncdffile.c_str()); exit(1); } rc = DefFile(wasp, ncdf); if (rc < 0) exit(1); vector vars, copy_vars, compress_vars; rc = GetVarNames(wasp, vars, copy_vars, compress_vars); if (rc < 0) exit(1); rc = DefVars(wasp, vars, ncdf); if (rc < 0) exit(1); rc = ncdf.EndDef(); if (rc < 0) exit(1); rc = CopyVars(wasp, copy_vars, ncdf); if (rc < 0) exit(1); rc = DeCompressVars(wasp, compress_vars, ncdf); if (rc < 0) exit(1); (void)wasp.Close(); rc = ncdf.Close(); if (rc < 0) exit(1); } int main(int argc, char **argv) { OptionParser op; MyBase::SetErrMsgFilePtr(stderr); // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] waspfile ncdffile" << endl; op.PrintOptionHelp(stderr); exit(0); } if (argc != 3) { cerr << "Usage: " << ProgName << " [options] waspfile ncdffile" << endl; op.PrintOptionHelp(stderr); exit(1); } string waspfile = argv[1]; // Path to wasp file string ncdffile = argv[2]; // Path to a vdf file if (opt.debug) MyBase::SetDiagMsgFilePtr(stderr); Process(waspfile, ncdffile); return (0); } ================================================ FILE: apps/wasp2raw/CMakeLists.txt ================================================ add_executable (wasp2raw wasp2raw.cpp) target_link_libraries (wasp2raw common wasp) OpenMPInstall ( TARGETS wasp2raw DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/wasp2raw/wasp2raw.cpp ================================================ #include #include #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; // // Command line argument stuff // struct opt_t { string varname; string type; int lod; int level; int nthreads; vector start; vector count; OptionParser::Boolean_T debug; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"varname", 1, "var1", "Name of variable"}, {"type", 1, "float32", "Primitive type of output data"}, {"lod", 1, "-1", "Compression levels saved. 0 => coarsest, 1 => " "next refinement, etc. -1 => all levels defined by the netcdf file"}, {"level", 1, "-1", "Multiresolution refinement level. Zero implies coarsest " "resolution"}, {"start", 1, "", "Colon-delimited NetCDF style start coordinate vector"}, {"count", 1, "", "Colon-delimited NetCDF style count coordinate vector"}, {"nthreads", 1, "0", "Number of execution threads. 0 => use number of cores"}, {"debug", 0, "", "Enable diagnostic"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"varname", Wasp::CvtToCPPStr, &opt.varname, sizeof(opt.varname)}, {"type", Wasp::CvtToCPPStr, &opt.type, sizeof(opt.type)}, {"lod", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)}, {"level", Wasp::CvtToInt, &opt.level, sizeof(opt.level)}, {"start", Wasp::CvtToIntVec, &opt.start, sizeof(opt.start)}, {"count", Wasp::CvtToIntVec, &opt.count, sizeof(opt.count)}, {"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; const char *ProgName; template void CopyVar(string ncdffile, string datafile, T dummy) { WASP wasp(opt.nthreads); int rc = wasp.Open(ncdffile, NC_WRITE); vector dims; vector bs; rc = wasp.InqVarDimlens(opt.varname, opt.level, dims, bs); if (rc < 0) exit(1); rc = wasp.OpenVarRead(opt.varname, opt.level, opt.lod); if (rc < 0) exit(1); vector start(dims.size(), 0); if (opt.start.size()) { if (opt.start.size() != dims.size()) { MyBase::SetErrMsg("Invalid start specification"); exit(1); } for (int i = 0; i < opt.start.size(); i++) { start[i] = opt.start[i]; } } vector count = dims; if (opt.count.size()) { if (opt.count.size() != dims.size()) { MyBase::SetErrMsg("Invalid count specification"); exit(1); } for (int i = 0; i < opt.count.size(); i++) { count[i] = opt.count[i]; } } size_t nelements = 1; for (int i = 0; i < count.size(); i++) nelements *= count[i]; T *data = new T[nelements]; rc = wasp.GetVara(start, count, data); if (rc < 0) exit(1); rc = wasp.CloseVar(); if (rc < 0) exit(1); rc = wasp.Close(); if (rc < 0) exit(1); FILE *fp = fopen(datafile.c_str(), "wb"); if (!fp) { MyBase::SetErrMsg("fopen(%s) : %M", datafile.c_str()); exit(1); } rc = fwrite(data, sizeof(*data), nelements, fp); if (rc != nelements) { MyBase::SetErrMsg("fread() : %M"); exit(1); } } int main(int argc, char **argv) { OptionParser op; MyBase::SetErrMsgFilePtr(stderr); // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] netcdffile datafile" << endl; op.PrintOptionHelp(stderr); exit(0); } if (argc != 3) { cerr << "Usage: " << ProgName << " [options] netcdffile datafile" << endl; op.PrintOptionHelp(stderr); exit(1); } string ncdffile = argv[1]; // Path to a vdf file string datafile = argv[2]; // Path to raw data file if (opt.debug) MyBase::SetDiagMsgFilePtr(stderr); if (opt.type == "float32") { float dummy = 0.0; CopyVar(ncdffile, datafile, dummy); } else if (opt.type == "float64") { double dummy = 0.0; CopyVar(ncdffile, datafile, dummy); } else if (opt.type == "int32") { int dummy = 0; CopyVar(ncdffile, datafile, dummy); } else if (opt.type == "int16") { int16_t dummy = 0; CopyVar(ncdffile, datafile, dummy); } else if (opt.type == "uint8") { unsigned char dummy = 0; CopyVar(ncdffile, datafile, dummy); } else { cerr << "Invalid type " << opt.type << endl; } return (0); } ================================================ FILE: apps/waspcreate/CMakeLists.txt ================================================ add_executable (waspcreate waspcreate.cpp) target_link_libraries (waspcreate common wasp) OpenMPInstall ( TARGETS waspcreate DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/waspcreate/waspcreate.cpp ================================================ #include #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; struct opt_t { vector dimnames; vector dimlens; std::vector cratios; string wname; string ofile; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"dimnames", 1, "", "Colon delimited list of dimension names"}, {"dimlens", 1, "", "Colon delimited list of dimension lengths"}, {"wname", 1, "bior4.4", "Wavelet family used for compression " "Valid values are bior1.1, bior1.3, " "bior1.5, bior2.2, bior2.4 ,bior2.6, bior2.8, bior3.1, bior3.3, " "bior3.5, bior3.7, bior3.9, bior4.4 intbior2.2"}, {"cratios", 1, "500:100:10:1", "Colon delimited list compression ratios. " "The default is 500:100:10:1. The maximum compression ratio " "is wavelet and block size dependent."}, {"ofile", 1, "test.nc", "Output file"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"dimnames", Wasp::CvtToStrVec, &opt.dimnames, sizeof(opt.dimnames)}, {"dimlens", Wasp::CvtToIntVec, &opt.dimlens, sizeof(opt.dimlens)}, {"cratios", Wasp::CvtToSize_tVec, &opt.cratios, sizeof(opt.cratios)}, {"wname", Wasp::CvtToCPPStr, &opt.wname, sizeof(opt.wname)}, {"ofile", Wasp::CvtToCPPStr, &opt.ofile, sizeof(opt.ofile)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; string ProgName; vector split(string s, string delim) { size_t pos = 0; vector tokens; while ((pos = s.find(delim)) != std::string::npos) { tokens.push_back(s.substr(0, pos)); s.erase(0, pos + delim.length()); } if (!s.empty()) tokens.push_back(s); return (tokens); } nc_type parsextype(string xtypestr) { if (xtypestr.compare("NC_BYTE") == 0) return (NC_BYTE); if (xtypestr.compare("NC_UBYTE") == 0) return (NC_UBYTE); if (xtypestr.compare("NC_CHAR") == 0) return (NC_CHAR); if (xtypestr.compare("NC_SHORT") == 0) return (NC_SHORT); if (xtypestr.compare("NC_USHORT") == 0) return (NC_USHORT); if (xtypestr.compare("NC_INT") == 0) return (NC_INT); if (xtypestr.compare("NC_UINT") == 0) return (NC_UINT); if (xtypestr.compare("NC_FLOAT") == 0) return (NC_FLOAT); if (xtypestr.compare("NC_INT64") == 0) return (NC_INT64); if (xtypestr.compare("NC_UINT64") == 0) return (NC_UINT64); if (xtypestr.compare("NC_DOUBLE") == 0) return (NC_DOUBLE); return (-1); } int main(int argc, char **argv) { OptionParser op; MyBase::SetErrMsgFilePtr(stderr); // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] [name:type:count[:dimname]+]+" << endl; op.PrintOptionHelp(stderr, 80, false); exit(0); } if (opt.dimnames.size() != opt.dimlens.size()) { MyBase::SetErrMsg("dimension name and dimension length vector size mismatch"); exit(1); } WASP wasp; vector bs; bs.push_back(64); bs.push_back(64); bs.push_back(64); size_t chunksize = 1024 * 1024 * 4; vector cratios3D = opt.cratios; vector cratios2D = cratios3D; vector cratios1D = cratios3D; for (int i = 0; i < cratios2D.size(); i++) { size_t c = (size_t)pow((double)cratios2D[i], (double)(2.0 / 3.0)); cratios2D[i] = c; c = (size_t)pow((double)cratios2D[i], (double)(1.0 / 3.0)); cratios2D[i] = c; } int rc = wasp.Create(opt.ofile, NC_64BIT_OFFSET, 0, chunksize, cratios3D.size()); if (rc < 0) exit(1); int dummy; rc = wasp.SetFill(NC_NOFILL, dummy); if (rc < 0) exit(1); for (int i = 0; i < opt.dimnames.size(); i++) { int rc = wasp.DefDim(opt.dimnames[i], opt.dimlens[i]); if (rc < 0) exit(1); } argc--; argv++; for (int i = 0; i < argc; i++) { string s = argv[i]; vector vardef = split(s, ":"); if (vardef.size() < 4) { MyBase::SetErrMsg("Invalid variable definition : %s", s.c_str()); exit(1); } string name = vardef[0]; vardef.erase(vardef.begin()); string xtypestr = vardef[0]; vardef.erase(vardef.begin()); int xtype = parsextype(xtypestr); size_t ncdims; std::istringstream(vardef[0]) >> ncdims; vardef.erase(vardef.begin()); // Everything else should be dimension name // vector dimnames = vardef; if (ncdims == 0) { vector cratios; int rc = wasp.DefVar(name, xtype, dimnames, "", bs, cratios); if (rc < 0) exit(1); } else { vector cratios; if (ncdims == 3) cratios = cratios3D; if (ncdims == 2) cratios = cratios2D; if (ncdims == 1) cratios = cratios1D; int rc = wasp.DefVar(name, xtype, dimnames, opt.wname, bs, cratios); if (rc < 0) exit(1); } } wasp.EndDef(); wasp.Close(); } ================================================ FILE: apps/wrf2vdc/CMakeLists.txt ================================================ add_executable (wrf2vdc wrf2vdc.cpp) target_link_libraries (wrf2vdc common vdc) OpenMPInstall ( TARGETS wrf2vdc DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/wrf2vdc/wrf2vdc.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; struct opt_t { int nthreads; int numts; std::vector vars; std::vector xvars; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"nthreads", 1, "0", "Specify number of execution threads " "0 => use number of cores"}, {"numts", 1, "-1", "Number of timesteps to be included in the VDC. Default (-1) includes all timesteps."}, {"vars", 1, "", "Colon delimited list of variable names " "to be copied to the VDC"}, {"xvars", 1, "", "Colon delimited list of variable names " "to exclude from copying the VDC"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"numts", Wasp::CvtToInt, &opt.numts, sizeof(opt.numts)}, {"vars", Wasp::CvtToStrVec, &opt.vars, sizeof(opt.vars)}, {"xvars", Wasp::CvtToStrVec, &opt.xvars, sizeof(opt.xvars)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; // Return a new vector containing elements of v1 with any elements from // v2 removed // vector remove_vector(vector v1, vector v2) { vector newvec; for (auto it = v1.begin(); it != v1.end(); ++it) { if (find(v2.begin(), v2.end(), *it) == v2.end()) { newvec.push_back(*it); } } return (newvec); } string ProgName; int main(int argc, char **argv) { VAPoR::SetHDF5PluginPath(); OptionParser op; MyBase::SetErrMsgFilePtr(stderr); // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { return (1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { return (1); } if (argc < 3) { cerr << "Usage: " << ProgName << " wrffiles... master.vdc" << endl; op.PrintOptionHelp(stderr, 80, false); return (1); } if (opt.help) { cerr << "Usage: " << ProgName << " master.vdc" << endl; op.PrintOptionHelp(stderr, 80, false); return (0); } argc--; argv++; vector wrffiles; for (int i = 0; i < argc - 1; i++) wrffiles.push_back(argv[i]); string master = argv[argc - 1]; VDCNetCDF vdc(opt.nthreads); size_t chunksize = 1024 * 1024 * 4; vector bs; int rc = vdc.Initialize(master, vector(), VDC::A, bs, chunksize); if (rc < 0) return (1); DCWRF dcwrf; rc = dcwrf.Initialize(wrffiles, vector()); if (rc < 0) { return (1); } vector varnames = dcwrf.GetCoordVarNames(); for (int i = 0; i < varnames.size(); i++) { int nts = dcwrf.GetNumTimeSteps(varnames[i]); nts = opt.numts != -1 && nts > opt.numts ? opt.numts : nts; VAssert(nts >= 0); cout << "Copying variable " << varnames[i] << endl; for (int ts = 0; ts < nts; ts++) { cout << " Time step " << ts << endl; int rc = vdc.CopyVar(dcwrf, ts, varnames[i], -1, -1); if (rc < 0) { MyBase::SetErrMsg("Failed to copy variable %s", varnames[i].c_str()); return (1); } } } if (opt.vars.size()) { varnames = opt.vars; } else { varnames = dcwrf.GetDataVarNames(); } varnames = remove_vector(varnames, opt.xvars); int estatus = 0; for (int i = 0; i < varnames.size(); i++) { int nts = dcwrf.GetNumTimeSteps(varnames[i]); nts = opt.numts != -1 && nts > opt.numts ? opt.numts : nts; VAssert(nts >= 0); cout << "Copying variable " << varnames[i] << endl; for (int ts = 0; ts < nts; ts++) { cout << " Time step " << ts << endl; int rc = vdc.CopyVar(dcwrf, ts, varnames[i], -1, -1); if (rc < 0) { MyBase::SetErrMsg("Failed to copy variable %s", varnames[i].c_str()); estatus = 1; } } } return estatus; } ================================================ FILE: apps/wrfvdccreate/CMakeLists.txt ================================================ add_executable (wrfvdccreate wrfvdccreate.cpp) target_link_libraries (wrfvdccreate common vdc) OpenMPInstall ( TARGETS wrfvdccreate DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) ================================================ FILE: apps/wrfvdccreate/wrfvdccreate.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; struct opt_t { std::vector bs; std::vector cratios; string wname; int nthreads; std::vector vars; OptionParser::Boolean_T force; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"bs", 1, "64:64:64", "Internal storage blocking factor expressed in grid points (NX:NY:NZ)"}, {"cratios", 1, "1:10:100:500", "Colon delimited list compression ratios. " "for 3D variables. The default is 1:10:100:500. The maximum " "compression ratio is wavelet and block size dependent."}, {"wname", 1, "bior4.4", "Wavelet family used for compression " "Valid values are bior1.1, bior1.3, " "bior1.5, bior2.2, bior2.4 ,bior2.6, bior2.8, bior3.1, bior3.3, " "bior3.5, bior3.7, bior3.9, bior4.4"}, {"nthreads", 1, "0", "Specify number of execution threads " "0 => use number of cores"}, {"vars", 1, "", "Colon delimited list of 3D variable names (compressed) " "to be included in " "the VDC"}, {"force", 0, "", "Create a new VDC master file even if a VDC data " "directory already exists. Results may be undefined if settings between " "the new master file and old data directory do not match."}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"bs", Wasp::CvtToSize_tVec, &opt.bs, sizeof(opt.bs)}, {"cratios", Wasp::CvtToSize_tVec, &opt.cratios, sizeof(opt.cratios)}, {"wname", Wasp::CvtToCPPStr, &opt.wname, sizeof(opt.wname)}, {"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"vars", Wasp::CvtToStrVec, &opt.vars, sizeof(opt.vars)}, {"force", Wasp::CvtToBoolean, &opt.force, sizeof(opt.force)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; string ProgName; void defineMapProjection(const DCWRF &dcwrf, VDCNetCDF &vdc) { vdc.SetMapProjection(dcwrf.GetMapProjection()); } int main(int argc, char **argv) { VAPoR::SetHDF5PluginPath(); OptionParser op; MyBase::SetErrMsgFilePtr(stderr); // // Parse command line arguments // ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); } if (argc < 3) { cerr << "Usage: " << ProgName << " wrf_file1 wrf_file2 ... master.vdc" << endl; op.PrintOptionHelp(stderr, 80, false); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << "wrffiles... master.vdc" << endl; op.PrintOptionHelp(stderr, 80, false); exit(0); } argc--; argv++; vector wrffiles; for (int i = 0; i < argc - 1; i++) wrffiles.push_back(argv[i]); string master = argv[argc - 1]; if (FileUtils::Extension(master) != "vdc") { fprintf(stderr, "Warning: VDC files should the extension .vdc\n"); } VDCNetCDF vdc(opt.nthreads); if (vdc.DataDirExists(master) && !opt.force) { MyBase::SetErrMsg("Data directory exists and -force option not used. " "Remove directory %s or use -force", vdc.GetDataDir(master).c_str()); exit(1); } if (FileUtils::Exists(master) && !opt.force) { MyBase::SetErrMsg("\"%s\" already exists and -force option not used.", master.c_str()); exit(1); } size_t chunksize = 1024 * 1024 * 4; int rc = vdc.Initialize(master, vector(), VDC::W, opt.bs, chunksize); if (rc < 0) exit(1); DCWRF dcwrf; rc = dcwrf.Initialize(wrffiles, vector()); if (rc < 0) { exit(1); } vector dimnames = dcwrf.GetDimensionNames(); for (int i = 0; i < dimnames.size(); i++) { DC::Dimension dim; dcwrf.GetDimension(dimnames[i], dim, -1); rc = vdc.DefineDimension(dim.GetName(), dim.GetLength()); if (rc < 0) { exit(1); } } // // Define coordinate variables // vector coordnames = dcwrf.GetCoordVarNames(); vector cratios(1, 1); for (int i = 0; i < coordnames.size(); i++) { DC::CoordVar cvar; dcwrf.GetCoordVarInfo(coordnames[i], cvar); vector sdimnames; string time_dimname; bool ok = dcwrf.GetVarDimNames(coordnames[i], sdimnames, time_dimname); VAssert(ok); rc = vdc.SetCompressionBlock(opt.wname, cratios); if (rc < 0) exit(1); if (cvar.GetUniform()) { rc = vdc.DefineCoordVarUniform(cvar.GetName(), sdimnames, time_dimname, cvar.GetUnits(), cvar.GetAxis(), cvar.GetXType(), false); } else { rc = vdc.DefineCoordVar(cvar.GetName(), sdimnames, time_dimname, cvar.GetUnits(), cvar.GetAxis(), cvar.GetXType(), false); } if (rc < 0) { exit(1); } rc = vdc.CopyAtt(dcwrf, cvar.GetName()); if (rc < 0) { return (1); } } defineMapProjection(dcwrf, vdc); // // Define data variables // for (int d = 0; d < 4; d++) { vector datanames = dcwrf.DC::GetDataVarNames(d); // // 1D coordinates are not blocked // string mywname; bool compress; if (d < 2) { mywname.clear(); compress = false; } else { mywname = opt.wname; compress = true; } // Try to compute "reasonable" 1D & 2D compression ratios from 3D // compression ratios // vector cratios = opt.cratios; for (int i = 0; i < cratios.size(); i++) { size_t c = (size_t)pow((double)cratios[i], (double)((float)d / 3.0)); cratios[i] = c; } rc = vdc.SetCompressionBlock(mywname, cratios); if (rc < 0) exit(1); for (int i = 0; i < datanames.size(); i++) { DC::DataVar dvar; dcwrf.GetDataVarInfo(datanames[i], dvar); vector dimnames; bool ok = dcwrf.GetVarDimNames(datanames[i], false, dimnames); VAssert(ok); vector coordvars; ok = dcwrf.GetVarCoordVars(datanames[i], false, coordvars); VAssert(ok); rc = vdc.DefineDataVar(dvar.GetName(), dimnames, coordvars, dvar.GetUnits(), dvar.GetXType(), compress); if (rc < 0) { exit(1); } rc = vdc.CopyAtt(dcwrf, dvar.GetName()); if (rc < 0) { return (1); } } } // // Copy global attributes // { vector attnames = dcwrf.GetAttNames(""); for (int j = 0; j < attnames.size(); j++) { vdc.CopyAtt(dcwrf, "", attnames[j]); } } rc = vdc.EndDefine(); if (rc < 0) { MyBase::SetErrMsg("Failed to write VDC master file : %s", master.c_str()); exit(1); } exit(0); } ================================================ FILE: buildutils/AppRun ================================================ #!/bin/bash executables=( "wrf2vdc" "raw2wasp" "wasp2raw" "wrfvdccreate" "raw2vdc" "vdc2raw" "cfvdccreate" "vapor_check_udunits" "vdcdump" "ncdf2wasp" "tiff2geotiff" "wasp2ncdf" "vapor" "vaporversion" "cf2vdc" "vdccreate" "vaporpychecker" "vdccompare" "waspcreate" ) bindir="$(dirname "$0")/bin" if [ "$#" -eq 0 ]; then # No arguments provided # Launch vapor exec "$bindir/vapor" "$@" else # Check if AppImage was given a valid executable for exe in ${executables[@]}; do if [ "$1" = "$exe" ] ; then # An executable was provided # Launch it with given args exec "$bindir/$1" "${@:2}" exit 0 fi done # No executable found echo Invalid argument: $@$'\n' echo If launching vapor with arguments, the vapor executable must be specified echo IE - ./VAPOR-x86_64.Appimage vapor dataFile1 dataFile2 ... echo IE - ./VAPOR-x86_64.Appimage vapor mySession.vs3$'\n' echo Usage: $0 [EXECUTABLE] [ARGS] echo Available executables: printf '\t%s\n' "${executables[@]}" exit 1 fi ================================================ FILE: buildutils/GetGitRevisionDescription.cmake ================================================ # - Returns a version string from Git # # These functions force a re-configure on each git commit so that you can # trust the values of the variables in your build system. # # get_git_head_revision( [ ...]) # # Returns the refspec and sha hash of the current head revision # # git_describe( [ ...]) # # Returns the results of git describe on the source tree, and adjusting # the output so that it tests false if an error occurs. # # git_get_exact_tag( [ ...]) # # Returns the results of git describe --exact-match on the source tree, # and adjusting the output so that it tests false if there was no exact # matching tag. # # git_local_changes() # # Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes. # Uses the return code of "git diff-index --quiet HEAD --". # Does not regard untracked files. # # Requires CMake 2.6 or newer (uses the 'function' command) # # Original Author: # 2009-2010 Ryan Pavlik # http://academic.cleardefinition.com # Iowa State University HCI Graduate Program/VRAC # # Copyright Iowa State University 2009-2010. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) if(__get_git_revision_description) return() endif() set(__get_git_revision_description YES) # We must run the following at "include" time, not at function call time, # to find the path to this module rather than the path to a calling list file get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) function(get_git_head_revision _refspecvar _hashvar) set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set(GIT_DIR "${GIT_PARENT_DIR}/.git") while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) # We have reached the root directory, we are not in git set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) return() endif() set(GIT_DIR "${GIT_PARENT_DIR}/.git") endwhile() # check if this is a submodule if(NOT IS_DIRECTORY ${GIT_DIR}) file(READ ${GIT_DIR} submodule) string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) endif() set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") if(NOT EXISTS "${GIT_DATA}") file(MAKE_DIRECTORY "${GIT_DATA}") endif() if(NOT EXISTS "${GIT_DIR}/HEAD") return() endif() set(HEAD_FILE "${GIT_DATA}/HEAD") configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" "${GIT_DATA}/grabRef.cmake" @ONLY) include("${GIT_DATA}/grabRef.cmake") set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) endfunction() function(git_describe _var) if(NOT GIT_FOUND) find_package(Git QUIET) endif() get_git_head_revision(refspec hash) if(NOT GIT_FOUND) set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) return() endif() if(NOT hash) set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) return() endif() # TODO sanitize #if((${ARGN}" MATCHES "&&") OR # (ARGN MATCHES "||") OR # (ARGN MATCHES "\\;")) # message("Please report the following error to the project!") # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") #endif() #message(STATUS "Arguments to execute_process: ${ARGN}") execute_process(COMMAND "${GIT_EXECUTABLE}" describe ${hash} ${ARGN} WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" RESULT_VARIABLE res OUTPUT_VARIABLE out ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if(NOT res EQUAL 0) set(out "${out}-${res}-NOTFOUND") endif() set(${_var} "${out}" PARENT_SCOPE) endfunction() function(git_get_exact_tag _var) git_describe(out --exact-match ${ARGN}) set(${_var} "${out}" PARENT_SCOPE) endfunction() function(git_local_changes _var) if(NOT GIT_FOUND) find_package(Git QUIET) endif() get_git_head_revision(refspec hash) if(NOT GIT_FOUND) set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) return() endif() if(NOT hash) set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) return() endif() execute_process(COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD -- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" RESULT_VARIABLE res OUTPUT_VARIABLE out ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if(res EQUAL 0) set(${_var} "CLEAN" PARENT_SCOPE) else() set(${_var} "DIRTY" PARENT_SCOPE) endif() endfunction() ================================================ FILE: buildutils/GetGitRevisionDescription.cmake.in ================================================ # # Internal file for GetGitRevisionDescription.cmake # # Requires CMake 2.6 or newer (uses the 'function' command) # # Original Author: # 2009-2010 Ryan Pavlik # http://academic.cleardefinition.com # Iowa State University HCI Graduate Program/VRAC # # Copyright Iowa State University 2009-2010. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) set(HEAD_HASH) file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) if(HEAD_CONTENTS MATCHES "ref") # named branch string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") if(EXISTS "@GIT_DIR@/${HEAD_REF}") configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) else() configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") set(HEAD_HASH "${CMAKE_MATCH_1}") endif() endif() else() # detached HEAD configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) endif() if(NOT HEAD_HASH) file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) string(STRIP "${HEAD_HASH}" HEAD_HASH) endif() ================================================ FILE: buildutils/NSIS.preInstall.ini.in ================================================ ; MessageBox MB_OK "Pre Install Command" ; include for some of the windows messages defines !include "winmessages.nsh" ; HKLM (all users) vs HKCU (current user) defines !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' !define env_hkcu 'HKCU "Environment"' ; set variable for local machine ; WriteRegExpandStr ${env_hklm} "VAPOR3_HOME" $INSTDIR ; and current user ; WriteRegExpandStr ${env_hkcu} "MYVAR" "MYVAL" ; make sure windows knows about the change SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 ================================================ FILE: buildutils/NSIS.preUnInstall.ini.in ================================================ ; MessageBox MB_OK "Pre Un Install Command" ; delete variable DeleteRegValue ${env_hklm} "VAPOR3_HOME" ; DeleteRegValue ${env_hkcu} MYVAR ; make sure windows knows about the change SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 ================================================ FILE: buildutils/NSIS.template.in ================================================ ; CPack install script designed for a nmake build ;-------------------------------- ; You must define these values !define VERSION "@CPACK_PACKAGE_VERSION@" !define PATCH "@CPACK_PACKAGE_VERSION_PATCH@" !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" ;-------------------------------- ;Variables Var MUI_TEMP Var STARTMENU_FOLDER Var SV_ALLUSERS Var START_MENU Var DO_NOT_ADD_TO_PATH Var ADD_TO_PATH_ALL_USERS Var ADD_TO_PATH_CURRENT_USER Var INSTALL_DESKTOP Var IS_DEFAULT_INSTALLDIR ;-------------------------------- ;Include Modern UI !include "MUI.nsh" ;Default installation folder InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" ;-------------------------------- ;General ;Name and file Name "@CPACK_NSIS_PACKAGE_NAME@" OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@" ;Set compression ;SetCompress off SetCompressor @CPACK_NSIS_COMPRESSOR@ ;Require administrator access RequestExecutionLevel admin @CPACK_NSIS_DEFINES@ !include Sections.nsh ;--- Component support macros: --- ; The code for the add/remove functionality is from: ; http://nsis.sourceforge.net/Add/Remove_Functionality ; It has been modified slightly and extended to provide ; inter-component dependencies. Var AR_SecFlags Var AR_RegFlags @CPACK_NSIS_SECTION_SELECTED_VARS@ ; Loads the "selected" flag for the section named SecName into the ; variable VarName. !macro LoadSectionSelectedIntoVar SecName VarName SectionGetFlags ${${SecName}} $${VarName} IntOp $${VarName} $${VarName} & ${SF_SELECTED} ;Turn off all other bits !macroend ; Loads the value of a variable... can we get around this? !macro LoadVar VarName IntOp $R0 0 + $${VarName} !macroend ; Sets the value of a variable !macro StoreVar VarName IntValue IntOp $${VarName} 0 + ${IntValue} !macroend !macro InitSection SecName ; This macro reads component installed flag from the registry and ;changes checked state of the section on the components page. ;Input: section index constant name specified in Section command. ClearErrors ;Reading component status from registry ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" "Installed" IfErrors "default_${SecName}" ;Status will stay default if registry value not found ;(component was never installed) IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading default section flags IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE ;Turn lowest (enabled) bit off IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags ;Change lowest bit ; Note whether this component was installed before !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags IntOp $R0 $AR_RegFlags & $AR_RegFlags ;Writing modified flags SectionSetFlags ${${SecName}} $AR_SecFlags "default_${SecName}:" !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected !macroend !macro FinishSection SecName ; This macro reads section flag set by user and removes the section ;if it is not selected. ;Then it writes component installed flag to registry ;Input: section index constant name specified in Section command. SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading section flags ;Checking lowest bit: IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED} IntCmp $AR_SecFlags 1 "leave_${SecName}" ;Section is not selected: ;Calling Section uninstall macro and writing zero installed flag !insertmacro "Remove_${${SecName}}" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ "Installed" 0 Goto "exit_${SecName}" "leave_${SecName}:" ;Section is selected: WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ "Installed" 1 "exit_${SecName}:" !macroend !macro RemoveSection_CPack SecName ; This macro is used to call section's Remove_... macro ;from the uninstaller. ;Input: section index constant name specified in Section command. !insertmacro "Remove_${${SecName}}" !macroend ; Determine whether the selection of SecName changed !macro MaybeSelectionChanged SecName !insertmacro LoadVar ${SecName}_selected SectionGetFlags ${${SecName}} $R1 IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits ; See if the status has changed: IntCmp $R0 $R1 "${SecName}_unchanged" !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected" !insertmacro "Deselect_required_by_${SecName}" goto "${SecName}_unchanged" "${SecName}_was_selected:" !insertmacro "Select_${SecName}_depends" "${SecName}_unchanged:" !macroend ;--- End of Add/Remove macros --- ;-------------------------------- ;Interface Settings !define MUI_HEADERIMAGE !define MUI_ABORTWARNING ;---------------------------------------- ; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02" ;---------------------------------------- !verbose 3 !include "WinMessages.NSH" !verbose 4 ;==================================================== ; get_NT_environment ; Returns: the selected environment ; Output : head of the stack ;==================================================== !macro select_NT_profile UN Function ${UN}select_NT_profile StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single DetailPrint "Selected environment for all users" Push "all" Return environment_single: DetailPrint "Selected environment for current user only." Push "current" Return FunctionEnd !macroend !insertmacro select_NT_profile "" !insertmacro select_NT_profile "un." ;---------------------------------------------------- !define NT_current_env 'HKCU "Environment"' !define NT_all_env 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' !ifndef WriteEnvStr_RegKey !ifdef ALL_USERS !define WriteEnvStr_RegKey \ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' !else !define WriteEnvStr_RegKey 'HKCU "Environment"' !endif !endif ; AddToPath - Adds the given dir to the search path. ; Input - head of the stack ; Note - Win9x systems requires reboot Function AddToPath Exch $0 Push $1 Push $2 Push $3 # don't add if the path doesn't exist IfFileExists "$0\*.*" "" AddToPath_done ReadEnvStr $1 PATH ; if the path is too long for a NSIS variable NSIS will return a 0 ; length string. If we find that, then warn and skip any path ; modification as it will trash the existing path. StrLen $2 $1 IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done CheckPathLength_ShowPathWarning: Messagebox MB_OK|MB_ICONEXCLAMATION "Warning! PATH too long installer unable to modify PATH!" Goto AddToPath_done CheckPathLength_Done: Push "$1;" Push "$0;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Push "$1;" Push "$0\;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done GetFullPathName /SHORT $3 $0 Push "$1;" Push "$3;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Push "$1;" Push "$3\;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Call IsNT Pop $1 StrCmp $1 1 AddToPath_NT ; Not on NT StrCpy $1 $WINDIR 2 FileOpen $1 "$1\autoexec.bat" a FileSeek $1 -1 END FileReadByte $1 $2 IntCmp $2 26 0 +2 +2 # DOS EOF FileSeek $1 -1 END # write over EOF FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n" FileClose $1 SetRebootFlag true Goto AddToPath_done AddToPath_NT: StrCmp $ADD_TO_PATH_ALL_USERS "1" ReadAllKey ReadRegStr $1 ${NT_current_env} "PATH" Goto DoTrim ReadAllKey: ReadRegStr $1 ${NT_all_env} "PATH" DoTrim: StrCmp $1 "" AddToPath_NTdoIt Push $1 Call Trim Pop $1 StrCpy $0 "$1;$0" AddToPath_NTdoIt: StrCmp $ADD_TO_PATH_ALL_USERS "1" WriteAllKey WriteRegExpandStr ${NT_current_env} "PATH" $0 Goto DoSend WriteAllKey: WriteRegExpandStr ${NT_all_env} "PATH" $0 DoSend: SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 AddToPath_done: Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ; RemoveFromPath - Remove a given dir from the path ; Input: head of the stack Function un.RemoveFromPath Exch $0 Push $1 Push $2 Push $3 Push $4 Push $5 Push $6 IntFmt $6 "%c" 26 # DOS EOF Call un.IsNT Pop $1 StrCmp $1 1 unRemoveFromPath_NT ; Not on NT StrCpy $1 $WINDIR 2 FileOpen $1 "$1\autoexec.bat" r GetTempFileName $4 FileOpen $2 $4 w GetFullPathName /SHORT $0 $0 StrCpy $0 "SET PATH=%PATH%;$0" Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoop: FileRead $1 $3 StrCpy $5 $3 1 -1 # read last char StrCmp $5 $6 0 +2 # if DOS EOF StrCpy $3 $3 -1 # remove DOS EOF so we can compare StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "" unRemoveFromPath_dosLoopEnd FileWrite $2 $3 Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoopRemoveLine: SetRebootFlag true Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoopEnd: FileClose $2 FileClose $1 StrCpy $1 $WINDIR 2 Delete "$1\autoexec.bat" CopyFiles /SILENT $4 "$1\autoexec.bat" Delete $4 Goto unRemoveFromPath_done unRemoveFromPath_NT: StrCmp $ADD_TO_PATH_ALL_USERS "1" unReadAllKey ReadRegStr $1 ${NT_current_env} "PATH" Goto unDoTrim unReadAllKey: ReadRegStr $1 ${NT_all_env} "PATH" unDoTrim: StrCpy $5 $1 1 -1 # copy last char StrCmp $5 ";" +2 # if last char != ; StrCpy $1 "$1;" # append ; Push $1 Push "$0;" Call un.StrStr ; Find `$0;` in $1 Pop $2 ; pos of our dir StrCmp $2 "" unRemoveFromPath_done ; else, it is in path # $0 - path to add # $1 - path var StrLen $3 "$0;" StrLen $4 $2 StrCpy $5 $1 -$4 # $5 is now the part before the path to remove StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove StrCpy $3 $5$6 StrCpy $5 $3 1 -1 # copy last char StrCmp $5 ";" 0 +2 # if last char == ; StrCpy $3 $3 -1 # remove last char StrCmp $ADD_TO_PATH_ALL_USERS "1" unWriteAllKey WriteRegExpandStr ${NT_current_env} "PATH" $3 Goto unDoSend unWriteAllKey: WriteRegExpandStr ${NT_all_env} "PATH" $3 unDoSend: SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 unRemoveFromPath_done: Pop $6 Pop $5 Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Uninstall sutff ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ########################################### # Utility Functions # ########################################### ;==================================================== ; IsNT - Returns 1 if the current system is NT, 0 ; otherwise. ; Output: head of the stack ;==================================================== ; IsNT ; no input ; output, top of the stack = 1 if NT or 0 if not ; ; Usage: ; Call IsNT ; Pop $R0 ; ($R0 at this point is 1 or 0) !macro IsNT un Function ${un}IsNT Push $0 ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion StrCmp $0 "" 0 IsNT_yes ; we are not NT. Pop $0 Push 0 Return IsNT_yes: ; NT!!! Pop $0 Push 1 FunctionEnd !macroend !insertmacro IsNT "" !insertmacro IsNT "un." ; StrStr ; input, top of stack = string to search for ; top of stack-1 = string to search in ; output, top of stack (replaces with the portion of the string remaining) ; modifies no other variables. ; ; Usage: ; Push "this is a long ass string" ; Push "ass" ; Call StrStr ; Pop $R0 ; ($R0 at this point is "ass string") !macro StrStr un Function ${un}StrStr Exch $R1 ; st=haystack,old$R1, $R1=needle Exch ; st=old$R1,haystack Exch $R2 ; st=old$R1,old$R2, $R2=haystack Push $R3 Push $R4 Push $R5 StrLen $R3 $R1 StrCpy $R4 0 ; $R1=needle ; $R2=haystack ; $R3=len(needle) ; $R4=cnt ; $R5=tmp loop: StrCpy $R5 $R2 $R3 $R4 StrCmp $R5 $R1 done StrCmp $R5 "" done IntOp $R4 $R4 + 1 Goto loop done: StrCpy $R1 $R2 "" $R4 Pop $R5 Pop $R4 Pop $R3 Pop $R2 Exch $R1 FunctionEnd !macroend !insertmacro StrStr "" !insertmacro StrStr "un." Function Trim ; Added by Pelaca Exch $R1 Push $R2 Loop: StrCpy $R2 "$R1" 1 -1 StrCmp "$R2" " " RTrim StrCmp "$R2" "$\n" RTrim StrCmp "$R2" "$\r" RTrim StrCmp "$R2" ";" RTrim GoTo Done RTrim: StrCpy $R1 "$R1" -1 Goto Loop Done: Pop $R2 Exch $R1 FunctionEnd Function ConditionalAddToRegisty Pop $0 Pop $1 StrCmp "$0" "" ConditionalAddToRegisty_EmptyString WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" \ "$1" "$0" ;MessageBox MB_OK "Set Registry: '$1' to '$0'" DetailPrint "Set install registry entry: '$1' to '$0'" ConditionalAddToRegisty_EmptyString: FunctionEnd ;-------------------------------- !ifdef CPACK_USES_DOWNLOAD Function DownloadFile IfFileExists $INSTDIR\* +2 CreateDirectory $INSTDIR Pop $0 ; Skip if already downloaded IfFileExists $INSTDIR\$0 0 +2 Return StrCpy $1 "@CPACK_DOWNLOAD_SITE@" try_again: NSISdl::download "$1/$0" "$INSTDIR\$0" Pop $1 StrCmp $1 "success" success StrCmp $1 "Cancelled" cancel MessageBox MB_OK "Download failed: $1" cancel: Return success: FunctionEnd !endif ;-------------------------------- ; Installation types @CPACK_NSIS_INSTALLATION_TYPES@ ;-------------------------------- ; Component sections @CPACK_NSIS_COMPONENT_SECTIONS@ ;-------------------------------- ; Define some macro setting for the gui @CPACK_NSIS_INSTALLER_MUI_ICON_CODE@ @CPACK_NSIS_INSTALLER_ICON_CODE@ @CPACK_NSIS_INSTALLER_MUI_WELCOMEFINISH_CODE@ @CPACK_NSIS_INSTALLER_MUI_UNWELCOMEFINISH_CODE@ @CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@ @CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@ ;-------------------------------- ;Pages !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@" Page custom InstallOptionsPage !insertmacro MUI_PAGE_DIRECTORY ;Start Menu Folder Page Configuration !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX" !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER @CPACK_NSIS_PAGE_COMPONENTS@ !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ;-------------------------------- ;Languages !insertmacro MUI_LANGUAGE "English" ;first language is the default language !insertmacro MUI_LANGUAGE "Albanian" !insertmacro MUI_LANGUAGE "Arabic" !insertmacro MUI_LANGUAGE "Basque" !insertmacro MUI_LANGUAGE "Belarusian" !insertmacro MUI_LANGUAGE "Bosnian" !insertmacro MUI_LANGUAGE "Breton" !insertmacro MUI_LANGUAGE "Bulgarian" !insertmacro MUI_LANGUAGE "Croatian" !insertmacro MUI_LANGUAGE "Czech" !insertmacro MUI_LANGUAGE "Danish" !insertmacro MUI_LANGUAGE "Dutch" !insertmacro MUI_LANGUAGE "Estonian" !insertmacro MUI_LANGUAGE "Farsi" !insertmacro MUI_LANGUAGE "Finnish" !insertmacro MUI_LANGUAGE "French" !insertmacro MUI_LANGUAGE "German" !insertmacro MUI_LANGUAGE "Greek" !insertmacro MUI_LANGUAGE "Hebrew" !insertmacro MUI_LANGUAGE "Hungarian" !insertmacro MUI_LANGUAGE "Icelandic" !insertmacro MUI_LANGUAGE "Indonesian" !insertmacro MUI_LANGUAGE "Irish" !insertmacro MUI_LANGUAGE "Italian" !insertmacro MUI_LANGUAGE "Japanese" !insertmacro MUI_LANGUAGE "Korean" !insertmacro MUI_LANGUAGE "Kurdish" !insertmacro MUI_LANGUAGE "Latvian" !insertmacro MUI_LANGUAGE "Lithuanian" !insertmacro MUI_LANGUAGE "Luxembourgish" !insertmacro MUI_LANGUAGE "Macedonian" !insertmacro MUI_LANGUAGE "Malay" !insertmacro MUI_LANGUAGE "Mongolian" !insertmacro MUI_LANGUAGE "Norwegian" !insertmacro MUI_LANGUAGE "Polish" !insertmacro MUI_LANGUAGE "Portuguese" !insertmacro MUI_LANGUAGE "PortugueseBR" !insertmacro MUI_LANGUAGE "Romanian" !insertmacro MUI_LANGUAGE "Russian" !insertmacro MUI_LANGUAGE "Serbian" !insertmacro MUI_LANGUAGE "SerbianLatin" !insertmacro MUI_LANGUAGE "SimpChinese" !insertmacro MUI_LANGUAGE "Slovak" !insertmacro MUI_LANGUAGE "Slovenian" !insertmacro MUI_LANGUAGE "Spanish" !insertmacro MUI_LANGUAGE "Swedish" !insertmacro MUI_LANGUAGE "Thai" !insertmacro MUI_LANGUAGE "TradChinese" !insertmacro MUI_LANGUAGE "Turkish" !insertmacro MUI_LANGUAGE "Ukrainian" !insertmacro MUI_LANGUAGE "Welsh" ;-------------------------------- ;Reserve Files ;These files should be inserted before other files in the data block ;Keep these lines before any File command ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA) ReserveFile "NSIS.InstallOptions.ini" !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS ;-------------------------------- ;Installer Sections Section "-Core installation" ;Use the entire tree produced by the INSTALL target. Keep the ;list of directories here in sync with the RMDir commands below. SetOutPath "$INSTDIR" !include "@CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@" @CPACK_NSIS_FULL_INSTALL@ ;Store installation folder WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR ;Create uninstaller WriteUninstaller "$INSTDIR\Uninstall.exe" Push "DisplayName" Push "@CPACK_NSIS_DISPLAY_NAME@" Call ConditionalAddToRegisty Push "DisplayVersion" Push "@CPACK_PACKAGE_VERSION@" Call ConditionalAddToRegisty Push "Publisher" Push "@CPACK_PACKAGE_VENDOR@" Call ConditionalAddToRegisty Push "UninstallString" Push "$INSTDIR\Uninstall.exe" Call ConditionalAddToRegisty Push "NoRepair" Push "1" Call ConditionalAddToRegisty !ifdef CPACK_NSIS_ADD_REMOVE ;Create add/remove functionality Push "ModifyPath" Push "$INSTDIR\AddRemove.exe" Call ConditionalAddToRegisty !else Push "NoModify" Push "1" Call ConditionalAddToRegisty !endif ; Optional registration Push "DisplayIcon" Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@" Call ConditionalAddToRegisty Push "HelpLink" Push "@CPACK_NSIS_HELP_LINK@" Call ConditionalAddToRegisty Push "URLInfoAbout" Push "@CPACK_NSIS_URL_INFO_ABOUT@" Call ConditionalAddToRegisty Push "Contact" Push "@CPACK_NSIS_CONTACT@" Call ConditionalAddToRegisty !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State" !insertmacro MUI_STARTMENU_WRITE_BEGIN Application ;Create shortcuts CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" @CPACK_NSIS_CREATE_ICONS@ @CPACK_NSIS_CREATE_ICONS_EXTRA@ CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" ;Read a value from an InstallOptions INI file !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State" !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State" !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State" ; Write special uninstall registry entries Push "StartMenu" Push "$STARTMENU_FOLDER" Call ConditionalAddToRegisty Push "DoNotAddToPath" Push "$DO_NOT_ADD_TO_PATH" Call ConditionalAddToRegisty Push "AddToPathAllUsers" Push "$ADD_TO_PATH_ALL_USERS" Call ConditionalAddToRegisty Push "AddToPathCurrentUser" Push "$ADD_TO_PATH_CURRENT_USER" Call ConditionalAddToRegisty Push "InstallToDesktop" Push "$INSTALL_DESKTOP" Call ConditionalAddToRegisty !insertmacro MUI_STARTMENU_WRITE_END @CPACK_NSIS_EXTRA_INSTALL_COMMANDS@ SectionEnd Section "-Add to path" Push $INSTDIR\bin StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0 Call AddToPath doNotAddToPath: SectionEnd ;-------------------------------- ; Create custom pages Function InstallOptionsPage !insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@" !insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini" FunctionEnd ;-------------------------------- ; determine admin versus local install Function un.onInit ClearErrors UserInfo::GetName IfErrors noLM Pop $0 UserInfo::GetAccountType Pop $1 StrCmp $1 "Admin" 0 +3 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Admin group' Goto done StrCmp $1 "Power" 0 +3 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Power Users group' Goto done noLM: ;Get installation folder from registry if available done: FunctionEnd ;--- Add/Remove callback functions: --- !macro SectionList MacroName ;This macro used to perform operation on multiple sections. ;List all of your components in following manner here. @CPACK_NSIS_COMPONENT_SECTION_LIST@ !macroend Section -FinishComponents ;Removes unselected components and writes component status to registry !insertmacro SectionList "FinishSection" !ifdef CPACK_NSIS_ADD_REMOVE ; Get the name of the installer executable System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1' StrCpy $R3 $R0 ; Strip off the last 13 characters, to see if we have AddRemove.exe StrLen $R1 $R0 IntOp $R1 $R0 - 13 StrCpy $R2 $R0 13 $R1 StrCmp $R2 "AddRemove.exe" addremove_installed ; We're not running AddRemove.exe, so install it CopyFiles $R3 $INSTDIR\AddRemove.exe addremove_installed: !endif SectionEnd ;--- End of Add/Remove callback functions --- ;-------------------------------- ; Component dependencies Function .onSelChange !insertmacro SectionList MaybeSelectionChanged FunctionEnd ;-------------------------------- ;Uninstaller Section Section "Uninstall" ReadRegStr $START_MENU SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu" ;MessageBox MB_OK "Start menu is in: $START_MENU" ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "DoNotAddToPath" ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathAllUsers" ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathCurrentUser" ;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS" ReadRegStr $INSTALL_DESKTOP SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "InstallToDesktop" ;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP " !include "@CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@" ;Remove files we installed. ;Keep the list of directories here in sync with the File commands above. @CPACK_NSIS_DELETE_FILES@ @CPACK_NSIS_DELETE_DIRECTORIES@ !ifdef CPACK_NSIS_ADD_REMOVE ;Remove the add/remove program Delete "$INSTDIR\AddRemove.exe" !endif ;Remove the uninstaller itself. Delete "$INSTDIR\Uninstall.exe" DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" ;Remove the installation directory if it is empty. RMDir "$INSTDIR" ; Remove the registry entries. DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" ; Removes all optional components !insertmacro SectionList "RemoveSection_CPack" !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" @CPACK_NSIS_DELETE_ICONS@ @CPACK_NSIS_DELETE_ICONS_EXTRA@ ;Delete empty start menu parent diretories StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" startMenuDeleteLoop: ClearErrors RMDir $MUI_TEMP GetFullPathName $MUI_TEMP "$MUI_TEMP\.." IfErrors startMenuDeleteLoopDone StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop startMenuDeleteLoopDone: ; If the user changed the shortcut, then untinstall may not work. This should ; try to fix it. StrCpy $MUI_TEMP "$START_MENU" Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" @CPACK_NSIS_DELETE_ICONS_EXTRA@ ;Delete empty start menu parent diretories StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" secondStartMenuDeleteLoop: ClearErrors RMDir $MUI_TEMP GetFullPathName $MUI_TEMP "$MUI_TEMP\.." IfErrors secondStartMenuDeleteLoopDone StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop secondStartMenuDeleteLoopDone: DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" Push $INSTDIR\bin StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0 Call un.RemoveFromPath doNotRemoveFromPath: SectionEnd ;-------------------------------- ; determine admin versus local install ; Is install for "AllUsers" or "JustMe"? ; Default to "JustMe" - set to "AllUsers" if admin or on Win9x ; This function is used for the very first "custom page" of the installer. ; This custom page does not show up visibly, but it executes prior to the ; first visible page and sets up $INSTDIR properly... ; Choose different default installation folder based on SV_ALLUSERS... ; "Program Files" for AllUsers, "My Documents" for JustMe... Function .onInit StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString" StrCmp $0 "" inst MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \ "@CPACK_NSIS_PACKAGE_NAME@ is already installed. $\n$\nDo you want to uninstall the old version before installing the new one?" \ /SD IDYES IDYES uninst IDNO inst Abort ;Run the uninstaller uninst: ClearErrors StrLen $2 "\Uninstall.exe" StrCpy $3 $0 -$2 # remove "\Uninstall.exe" from UninstallString to get path ExecWait '"$0" /S _?=$3' ;Do not copy the uninstaller to a temp file IfErrors uninst_failed inst uninst_failed: MessageBox MB_OK|MB_ICONSTOP "Uninstall failed." Abort inst: ; Reads components status for registry !insertmacro SectionList "InitSection" ; check to see if /D has been used to change ; the install directory by comparing it to the ; install directory that is expected to be the ; default StrCpy $IS_DEFAULT_INSTALLDIR 0 StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2 StrCpy $IS_DEFAULT_INSTALLDIR 1 StrCpy $SV_ALLUSERS "JustMe" ; if default install dir then change the default ; if it is installed for JustMe StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@" ClearErrors UserInfo::GetName IfErrors noLM Pop $0 UserInfo::GetAccountType Pop $1 StrCmp $1 "Admin" 0 +4 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Admin group' StrCpy $SV_ALLUSERS "AllUsers" Goto done StrCmp $1 "Power" 0 +4 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Power Users group' StrCpy $SV_ALLUSERS "AllUsers" Goto done noLM: StrCpy $SV_ALLUSERS "AllUsers" ;Get installation folder from registry if available done: StrCmp $SV_ALLUSERS "AllUsers" 0 +3 StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage !insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini" noOptionsPage: FunctionEnd ================================================ FILE: buildutils/OpenMPInstaller.cmake ================================================ function (OpenMPInstall) set(options ) set(oneValueArgs TARGETS DESTINATION COMPONENT) set(multiValueArgs ) cmake_parse_arguments(VINSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if (USE_OMP AND APPLE) get_target_property(target_type ${VINSTALL_TARGETS} TYPE) get_target_property(target_is_bundle ${VINSTALL_TARGETS} MACOSX_BUNDLE) if (target_type STREQUAL "EXECUTABLE") set (SRC_FILE ${VINSTALL_TARGETS}) set (SRC_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) elseif (target_type STREQUAL "SHARED_LIBRARY") set (SRC_FILE lib${VINSTALL_TARGETS}.dylib) set (SRC_DIR ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) else() message(FATAL_ERROR "Unsupported target type '${target_type}'") endif() if (${target_is_bundle}) set (APP_BIN_DIR "${SRC_FILE}.app/Contents/MacOS") set (SRC_PATH "${SRC_DIR}/${APP_BIN_DIR}/${SRC_FILE}") set (FINAL_DESTINATION "${VINSTALL_DESTINATION}/${APP_BIN_DIR}") set (BUNDLE_MSG "(BUNDLE)") else() set (SRC_PATH "${SRC_DIR}/${SRC_FILE}") set (FINAL_DESTINATION "${VINSTALL_DESTINATION}") set (BUNDLE_MSG "") endif() message("Generate OpenMP install script for ${VINSTALL_TARGETS} (${target_type}) ${BUNDLE_MSG}") # message("\t SRC=\"${SRC_PATH}\"") set (MOD ${CMAKE_CURRENT_BINARY_DIR}/MOD_FOR_INST_${SRC_FILE}) install ( CODE " message(\"Relinking OpenMP: ${VINSTALL_TARGETS}\") configure_file(\"${SRC_PATH}\" \"${MOD}\" COPYONLY) execute_process(COMMAND sh \"${CMAKE_SOURCE_DIR}/buildutils/renameomp.sh\" \"${MOD}\") " COMPONENT ${VINSTALL_COMPONENT} ) if (${target_is_bundle}) # This has to be called first to install cf bundle metadata # since the install PROGRAMS just installs the binary, not the app install ( TARGETS ${VINSTALL_TARGETS} DESTINATION ${VINSTALL_DESTINATION} COMPONENT ${VINSTALL_COMPONENT} ) endif() # install (CODE "message(\"install ( \")") # install (CODE "message(\" PROGRAMS ${MOD} \")") # install (CODE "message(\" DESTINATION ${FINAL_DESTINATION}\")") # install (CODE "message(\" COMPONENT ${VINSTALL_COMPONENT} \")") # install (CODE "message(\" RENAME ${SRC_FILE} \")") # install (CODE "message(\") \")") install ( PROGRAMS ${MOD} DESTINATION ${FINAL_DESTINATION} COMPONENT ${VINSTALL_COMPONENT} RENAME ${SRC_FILE} ) else() install ( TARGETS ${VINSTALL_TARGETS} DESTINATION ${VINSTALL_DESTINATION} COMPONENT ${VINSTALL_COMPONENT} ) endif() endfunction() ================================================ FILE: buildutils/UtilityFunctions.cmake ================================================ FUNCTION(PREPEND var prefix) SET(listVar "") FOREACH(f ${ARGN}) LIST(APPEND listVar "${prefix}${f}") ENDFOREACH(f) SET(${var} "${listVar}" PARENT_SCOPE) ENDFUNCTION(PREPEND) FUNCTION(APPEND var postfix) SET(listVar "") FOREACH(f ${ARGN}) LIST(APPEND listVar "${f}${postfix}") ENDFOREACH(f) SET(${var} "${listVar}" PARENT_SCOPE) ENDFUNCTION(APPEND) ================================================ FILE: buildutils/codesignMacOS.sh ================================================ set +e installDir="/Applications" dmgDir="tmp" xattr -dr com.apple.quarantine $installDir/vapor.app dmgName="VAPOR3-`$installDir/vapor.app/Contents/MacOS/vaporversion -numeric`-" if [[ `file $installDir/vapor.app/Contents/MacOS/vapor` == *arm64* ]]; then dmgName="${dmgName}AppleSilicon.dmg" else dmgName="${dmgName}macOSx86.dmg" fi #for file in ${installDir}/vapor.app/Contents/Frameworks/*; do # codesign --sign "Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)" --force --deep --timestamp --verbose $file #done # Deploy Qt with macdeployqt # N.B. Apple's notorization will give an "bundle format is ambiguous (could be app or framework)" if Qt's frameworks are missing symlinks # So, if copying the third party libraries use 'cp -a /old/libs /new/libs' and not 'cp -r /old/libs /new/libs' (-a and not -r) /usr/local/VAPOR-Deps/current/bin/macdeployqt ${installDir}/vapor.app -timestamp -sign-for-notarization="Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)" # Codesign libraries and frameworks find ${installDir}/vapor.app/Contents/Frameworks -type f -exec file {} + | grep -E 'Mach-O .* shared library' | cut -d: -f1 | while read -r file; do codesign --sign "Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)" --timestamp --force --deep --verbose --options runtime "$file" done # Codesign plugins and python directories=( "${installDir}/vapor.app/Contents/share/plugins/" "${installDir}/vapor.app/Contents/Resources/" "${installDir}/vapor.app/Contents/Resources/python/lib/" "${installDir}/vapor.app/Contents/Resources/python/lib/python3.9/site-packages/numpy/.dylibs" "${installDir}/vapor.app/Contents/Resources/python/lib/python3.9/site-packages/PIL/.dylibs" "${installDir}/vapor.app/Contents/Resources/python/lib/python3.9/site-packages/scipy/.dylibs" ) for dir in "${directories[@]}"; do find "$dir" -type f \( -name "*.so" -o -name "*.dylib" \) | while read -r file; do codesign --sign "Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)" --timestamp --force --deep --verbose $file done done # Codesign additional MacOS plugins codesign --sign "Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)" --force --deep --verbose ${installDir}/vapor.app/Contents/MacOS/platforms/libqcocoa.dylib codesign --sign "Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)" --force --deep --verbose ${installDir}/vapor.app/Contents/MacOS/styles/libqmacstyle.dylib # Codesign all vapor executables with timestamp and hardended runtime for file in ${installDir}/vapor.app/Contents/MacOS/*; do codesign --sign "Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)" --force --deep --timestamp --verbose --options runtime $file done # Create .dmg that contains symlink to /Applications mkdir -p "${dmgDir}" cp -R "${installDir}/vapor.app" "${dmgDir}" ln -s /Applications "${dmgDir}/Applications" hdiutil create -volname "vapor" -srcfolder ${dmgDir} -ov -format UDZO "${installDir}/${dmgName}" rm -rf "${dmgDir}" # Sign and notarize the .dmg codesign --force --verify --verbose --sign "Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)" ${installDir}/${dmgName} xcrun -v notarytool submit ${installDir}/${dmgName} --keychain-profile "VAPOR3" --wait # Staple the notarized .dmg xcrun stapler staple ${installDir}/${dmgName} xcrun stapler validate ${installDir}/${dmgName} # Fetch the notorization log # xcrun notarytool log --keychain-profile "testApp-password" ================================================ FILE: buildutils/copylibdeps.pl ================================================ #!/usr/bin/perl use English; use POSIX; use Cwd; use Cwd 'abs_path'; use File::Basename; use File::Copy; use File::Spec; $0 =~ s/.*\///; $ProgName = $0; $Debug = 0; sub usage { my($msg) = @_; if ($msg) { printf STDERR "$ProgName: $msg\n"; } my($format) = "\t%-12.12s %-12.12s %s\n"; print STDERR "Usage: $ProgName [options] targetlist... libdir"; print STDERR "\nWhere \"options\" are:\n\n"; printf STDERR $format, "Option name", "Default", "Description"; printf STDERR $format, "------ ----", "-------", "-----------"; printf STDERR $format, "-exclude", "expression", "Paths to exclude"; printf STDERR $format, "-include", "expression", "Paths to include (override -exclude)"; printf STDERR $format, "-ldlibpath", "expression", "library search path"; print STDERR "\n"; exit(1) } sub mysystem { my(@cmd) = @_; print "cmd=@cmd\n"; system(@cmd); if ($? != 0) { print STDERR "$ProgName: \"@cmd\" exited with error\n"; exit(1); } } sub copy_dir{ my($srcdir, $destdir) = @_; my($volume, $parentdir, $file) = File::Spec->splitpath($srcdir); $tmpfile = "/tmp/$ProgName.$$.tar"; $cwd = getcwd(); chdir $parentdir or die "$ProgName: Can't cd to $parentdir: $!\n"; @cmd = ("tar", "-cf", $tmpfile, "$file"); mysystem(@cmd); chdir $cwd or die "$ProgName: Can't cd to $cwd: $!\n"; chdir $destdir or die "$ProgName: Can't cd to $destdir: $!\n"; @cmd = ("tar", "-xf", $tmpfile); mysystem(@cmd); chdir $cwd or die "$ProgName: Can't cd to $cwd: $!\n"; unlink $tmpfile; } sub chaselink { my($path) = @_; if (defined($link = readlink($path))) { if (! File::Spec->file_name_is_absolute($link)) { my($name0,$dir0) = fileparse($path); my($name1,$dir1) = fileparse($link); $link = "$dir0" . "$name1"; } return(chaselink($link)); } else { return($path); } } sub get_deps { my($target) = @_; # # ldd generates error message on 32bit version of libQtCore # "Accessing a corrupted shared library" # if (($Arch eq "Linux") && ( ($target =~ /libQtCore/))) { printf STDERR "$ProgName: SKIPPING $target\n"; return(); } my(@Deps) = (); my($target_is_lib) = 1; my(@lddcmd); my($cmd) = "/usr/bin/file $target"; $_ = `$cmd`; if ($?>>8) { printf STDERR "$ProgName: Command \"$cmd\" failed\n"; exit(1); } if ($_ =~ "executable") { $target_is_lib = 0; } if ($Arch eq "Darwin") { # Mac system @lddcmd = ("/usr/bin/otool", "-L"); } else { @lddcmd = ("/usr/bin/ldd"); } my ($cmd) = join(' ', @lddcmd, $target); $_ = `$cmd`; if ($?>>8) { printf STDERR "$ProgName: Command \"$cmd\" failed\n"; exit(1); } my(@lines) = split /\n/, $_; if (($Arch eq "Darwin") || ($Arch eq "AIX")) { shift @lines; # discard first line } # clyne - Fri Feb 5 12:20:50 MST 2016 # # for .so files the second line is *not* the library name # #if (($Arch eq "Darwin") && $target_is_lib) { #shift @lines; # discard second line - the library name #} # Get base name of target without any extensions # my ($tfname, $tdirs, $text) = fileparse($target, qr/\..*/); LINE: foreach $line (@lines) { my($lib); $line =~ s/^\s+//; if ($Arch eq "Darwin") { ($lib) = split(/\s+/, $line); } elsif ($Arch eq "AIX") { ($lib) = split(/\s+/, $line); $lib =~ s/\(.*\)//; next LINE if ($lib eq "/unix"); } else { ($junk1, $junk2, $lib) = split(/\s+/, $line); } next LINE if (! defined($lib)); if ($lib =~ "not found") { printf STDERR "$ProgName: Command \"$cmd\" failed - library $lib not found\n"; exit(1); } next LINE if (($Arch eq "Darwin") && !( ($lib =~ /dylib/) || $lib =~ /framework/) ); next LINE if (($Arch eq "Linux") && !( ($lib =~ /\.so/))); # Handle case where target name appears as its own dependency # my ($fname, $dirs, $ext) = fileparse($lib, qr/\..*/); next LINE if (($Arch eq "Darwin") && ($tfname eq $fname)); my ($toss) = 0; foreach $exclude (@ExcludePaths) { if ($lib =~ m!$exclude!) { $toss = 1; } } if ($toss) { foreach $include (@IncludePaths) { if ($lib =~ m!$include!) { $toss = 0; } } } if (! $toss) { push @Deps, $lib; } } return(@Deps); } @IncludePaths = (); @ExcludePaths = (); while ($ARGV[0] =~ /^-/) { $_ = shift @ARGV; if (/^-exclude$/) { defined($_ = shift @ARGV) || die "Missing argument"; push(@ExcludePaths, $_); } elsif (/^-arch$/) { defined($Arch = shift @ARGV) || die "Missing argument"; } elsif (/^-include$/) { defined($_ = shift @ARGV) || die "Missing argument"; push(@IncludePaths, $_); } elsif (/^-ldlibpath$/) { defined($_ = shift @ARGV) || die "Missing argument"; $LD_LIBRARY_PATH = defined($LD_LIBRARY_PATH) ? "$LD_LIBRARY_PATH:$_" : $_; } else { usage("Invalid option: $_"); } } if (! (defined($Libdir = pop @ARGV))) { usage("Wrong # of arguments"); } $Libdir = abs_path($Libdir); if (! -d $Libdir) { print STDERR "$ProgName: Library directory $Libdir does not exist\n"; exit(1); } @Targets = @ARGV; # # Set LD environment variables for ld search path. # Needed for the ldd command only (Mac 'otool' ignores these) # $ENV{"LD_LIBRARY_PATH"} = $LD_LIBRARY_PATH; $ENV{"LD_LIBRARYN32_PATH"} = $LD_LIBRARY_PATH; $ENV{"LD_LIBRARY64_PATH"} = $LD_LIBRARY_PATH; # # Recursively look for library dependencies # @cpfiles = (); while (defined($target = shift(@Targets))) { if ($Debug) {print "Target = $target\n";} @_ = get_deps($target); foreach $dep (@_) { if ($Debug) {print "Dep = $dep\n";} if (! -f $dep) { printf STDERR "$ProgName: Library dependency $dep not found\n"; exit(1); } $match = 0; foreach $target (@Targets) { $match = 1 if ($dep eq $target); } if ($Arch ne "AIX") { push @Targets, $dep if (! $match); } # # add library dependency to copy list if not already there # $match = 0; foreach $cpfile (@cpfiles) { $match = 1 if ($dep eq $cpfile); } push @cpfiles, $dep if (! $match); } } foreach $_ (@cpfiles) { $dirname = abs_path(dirname($_)); if ($dirname ne $Libdir) { if (! (($Arch eq "Darwin") && $_ =~ /framework/)) { my($volume, $dir, $file) = File::Spec->splitpath($_); my ($target) = File::Spec->catpath("", $Libdir, $file); print "Copying $_ to $target\n"; copy($_,$target) || die "$ProgName: file copy failed - $!\n"; my(@cmd) = ("/bin/chmod", "+x", $target); mysystem(@cmd); my ($baselib) = $target; if ($Arch eq "Darwin") { if ($baselib =~ /(\.[\d+|.]+dylib)/) { $baselib =~ s/$1/.dylib/; } } else { if ($baselib =~ /(\.so\.[\d+|.]+)/) { $baselib =~ s/$1/.so/; } } if (($baselib ne $target) && ! -e $baselib) { my(@cmd) = ("/bin/ln", "-s", "$file", "$baselib"); mysystem(@cmd); } } else { $dirname = $_; $dirname =~ s/(.*framework).*/$1/; copy_dir($dirname, $Libdir); } } } exit 0; ================================================ FILE: buildutils/exports.awk ================================================ { if ((($2 == "T") || ($2 == "D") || ($2 == "B")) \ && ( substr($1,1,1) != ".")) { if (substr ($1, 1, 7) != "__sinit" && substr ($1, 1, 7) != "__sterm") { if (substr ($1, 1, 5) == "__tf1") print (substr ($1, 7)) else if (substr ($1, 1, 5) == "__tf9") print (substr ($1, 15)) else print $1 } } } ================================================ FILE: buildutils/fastdep.pl ================================================ # Copyright (c) 2001, Stanford University # All rights reserved. # # See the file LICENSE.txt for information on redistributing this software sub dir { my ( $file ) = @_; my ( $dir ); if ( $file =~ /\// ) { $file =~ /^(.*)\/([^\/])+$/; $dir = $1; } else { $dir = "."; } $dir .= "/"; } sub includes { my ( $file ) = @_; return @{$inc{$file}} if ( $inc{$file} ); my ( @angles, @quotes ); return () unless open(SCAN, $file); while () { next unless /^\s*\#/; if ( /^\s*\#\s*include\s*([<\"])(.*)[>\"]/ ) { if ( $1 eq "<" ) { push @angles, $2; } else { push @quotes, $2; } } } close(SCAN); my ( $dir ) = dir($file); my ( @files, $f, $name ); while ( $name = pop @quotes ) { $f = $dir . $name; if ( -f $f ) { push @files, $f; } else { push @angles, $name; } } foreach $name ( @angles ) { foreach $dir ( @incpath ) { $f = $dir . $name; if ( -f $f ) { push @files, $f; last; } } } $inc{$file} = \@files; @files; } sub depends { my ( $file ) = @_; my ( @files ) = ( @_ ); my ( %files ); while ( $f = pop @files ) { next if exists $files{$f}; $files{$f} = 1; push @files, includes($f); } keys %files; } $obj_prefix = ""; $obj_suffix = ( $^O eq "MSWin32" ) ? ".obj" : ".o"; @extra_targets = (); foreach $arg ( @ARGV ) { if ( $arg =~ /^-I(.+)\/$/ ) { push @incpath, $1; } elsif ( $arg =~ /^-I(.+)$/ ) { push @incpath, $1 . "/"; } elsif ( $arg =~ /^--obj-prefix=(.*)$/ ) { $obj_prefix = $1; } elsif ( $arg =~ /^--obj-suffix=(.*)$/ ) { $obj_suffix = $1; } elsif ( $arg =~ /^--extra-target=(.*)$/ ) { push @extra_targets, $1; } elsif ( $arg =~ /^-/ ) { # skip it } else { push @files, $arg; } } foreach $file ( @files ) { my ( $obj ); $file =~ /^(.*)\.\w+$/; $obj = $obj_prefix . $1 . $obj_suffix; foreach $t ( @extra_targets ) { $obj .= " " . $t; } foreach $file ( depends($file) ) { print "$obj: $file\n"; } } ================================================ FILE: buildutils/genAppImage.sh ================================================ #! /bin/bash # Exit on error and print commands to stdout set -ex export VERSION=$1 VAPOR="VAPOR3-$VERSION-Linux" SRC_DIR=$2 #### # Install vapor into build dir for modification into an AppImage #### mkdir -p $VAPOR rm -rf $VAPOR/* || true ./$VAPOR.sh --skip-license --prefix=$VAPOR cp ${SRC_DIR}/buildutils/AppRun $VAPOR cp ${SRC_DIR}/buildutils/vapor.desktop $VAPOR cp ${SRC_DIR}/share/images/VAPOR.png $VAPOR cp ${SRC_DIR}/share/images/VAPOR.png . #### # Produces a self-contained AppDir with Qt #### linuxdeployqt=linuxdeployqt-continuous-x86_64.AppImage rm $linuxdeployqt || true wget https://github.com/probonopd/linuxdeployqt/releases/download/continuous/$linuxdeployqt chmod 755 $linuxdeployqt export APPIMAGE_EXTRACT_AND_RUN=1 THIRD_PARTY_DIR=/usr/local/VAPOR-Deps/current;\ Qt5_DIR=$THIRD_PARTY_DIR/lib/cmake/Qt5;\ LD_LIBRARY_PATH=$THIRD_PARTY_DIR/lib:\ /opt/intel/oneapi/mpi/latest/lib:\ $THIRD_PARTY_DIR/lib/python3.9/site-packages/Pillow.libs:\ $THIRD_PARTY_DIR/lib/python3.9/site-packages/scipy.libs:\ $THIRD_PARTY_DIR/lib/python3.9/site-packages/numpy.libs \ ./$linuxdeployqt \ $VAPOR/vapor.desktop \ -qmake=$THIRD_PARTY_DIR/bin/qmake \ -appimage #### # Produces an AppImage from an AppDir #### appimagetool=appimagetool-x86_64.AppImage rm $appimagetool || true wget https://github.com/AppImage/appimagetool/releases/download/continuous/$appimagetool chmod 755 $appimagetool ./$appimagetool $VAPOR ================================================ FILE: buildutils/gen_linux_shared_libs.pl ================================================ #!/usr/bin/env perl use strict; use warnings; use File::Copy qw(copy); my $tmpDir = "/tmp/vapor_install_libs"; if (scalar @ARGV < 1) { print "Usage $0 input_bin [extra_lib [...]]\n"; exit; } if (not -B $ARGV[0]) { print STDERR "Error: File \"$ARGV[0]\" is not a binary file\n"; exit 1; } my @extras; for (my $i = 1; $i < scalar @ARGV; $i++) { push @extras, $ARGV[$i]; } my $ldd = `ldd "$ARGV[0]"`; my @libs; foreach (split(/\n/, $ldd)) { chomp; push @libs, $1 if m/=> (\/glade\S+\.so\S*)/; push @libs, $1 if m/=> (\/usr\/local\/VAPOR-Deps\S+\.so\S*)/; foreach my $e (@extras) { push @libs, $1 if m/.*$e.*=> (\/.+.so\S*)/; } } mkdir $tmpDir if (not -e $tmpDir); foreach my $l (@libs) { my $real = $l; while (-l $real) { $real = readlink $real; } if (not $real =~ /^\//) { $l =~ m/^.*\//; $real = $&.$real; } $l =~ m/[^\/]+$/; my $baseName = $&; copy "$real", "$tmpDir/$baseName"; if ($!) { print STDERR "ERROR Failed to copy '$real' to '$tmpDir/$baseName'\n"; print STDERR "ERROR $!\n"; die(1); } print "$tmpDir/$baseName\n"; } # use Data::Dumper qw(Dumper); # print Dumper \@libs; ================================================ FILE: buildutils/install-sh ================================================ #!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5; it is not part of GNU. # # $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" instcmd="$mvprog" chmodcmd="" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -S) stripcmd="$stripprog $2" shift shift continue;; *) if [ x"$src" = x ] then src=$1 else dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` fi # Make a temp file name in the proper directory. dstdir=`dirname $dst` dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp # and set any options; do chmod last to preserve setuid bits if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi # Now rename the file to the real destination. $doit $rmcmd $dst $doit $mvcmd $dsttmp $dst exit 0 ================================================ FILE: buildutils/install_name.pl ================================================ #!/usr/bin/perl use English; use POSIX; use Cwd; use File::Basename; #use File::Glob; use File::Copy; use File::Spec; use File::Find; $0 =~ s/.*\///; $ProgName = $0; $Debug = 0; sub usage { my($msg) = @_; if ($msg) { printf STDERR "$ProgName: $msg\n"; } my($format) = "\t%-12.12s %-12.12s %s\n"; print STDERR "Usage: $ProgName [options] targetlist... libdir"; print STDERR "\nWhere \"options\" are:\n\n"; printf STDERR $format, "Option name", "Default", "Description"; printf STDERR $format, "------ ----", "-------", "-----------"; printf STDERR $format, "-exec_path", "", "Path to executables"; printf STDERR $format, "-ldlibpath", "", "library search path"; print STDERR "\n"; exit(1) } sub mysystem { my(@cmd) = @_; if ($Debug) {print "cmd=@cmd\n";} system(@cmd); if ($? != 0) { print STDERR "$ProgName: \"@cmd\" exited with error\n"; exit(1); } } sub get_deps { my($target) = @_; # # ldd generates error message on 32bit version of libQtCore # "Accessing a corrupted shared library" # if (($Arch eq "Linux") && ( ($target =~ /libQtCore/))) { printf STDERR "$ProgName: SKIPPING $target\n"; return(); } my(@Deps) = (); my($target_is_lib) = 1; my(@lddcmd); my($cmd) = "/usr/bin/file $target"; $_ = `$cmd`; if ($?>>8) { printf STDERR "$ProgName: Command \"$cmd\" failed\n"; exit(1); } if ($_ =~ "executable") { $target_is_lib = 0; } if ($Arch eq "Darwin") { # Mac system @lddcmd = ("/usr/bin/otool", "-L"); } else { @lddcmd = ("/usr/bin/ldd"); } my ($cmd) = join(' ', @lddcmd, $target); $_ = `$cmd`; if ($?>>8) { printf STDERR "$ProgName: Command \"$cmd\" failed\n"; exit(1); } my(@lines) = split /\n/, $_; if (($Arch eq "Darwin") || ($Arch eq "AIX")) { shift @lines; # discard first line } # clyne - Fri Feb 5 12:20:50 MST 2016 # # for .so files the second line is *not* the library name # #if (($Arch eq "Darwin") && $target_is_lib) { #shift @lines; # discard second line - the library name #} # Get base name of target without any extensions # my ($tfname, $tdirs, $text) = fileparse($target, qr/\..*/); LINE: foreach $line (@lines) { my($lib); $line =~ s/^\s+//; if ($Arch eq "Darwin") { ($lib) = split(/\s+/, $line); } elsif ($Arch eq "AIX") { ($lib) = split(/\s+/, $line); $lib =~ s/\(.*\)//; next LINE if ($lib eq "/unix"); } else { ($junk1, $junk2, $lib) = split(/\s+/, $line); } next LINE if (! defined($lib)); if ($lib =~ "not found") { printf STDERR "$ProgName: Command \"$cmd\" failed - library $lib not found\n"; exit(1); } next LINE if (($Arch eq "Darwin") && !( ($lib =~ /dylib/) || $lib =~ /framework/) ); next LINE if (($Arch eq "Linux") && !( ($lib =~ /\.so/))); # Handle case where target name appears as its own dependency # my ($fname, $dirs, $ext) = fileparse($lib, qr/\..*/); next LINE if (($Arch eq "Darwin") && ($tfname eq $fname)); my ($toss) = 0; foreach $exclude (@ExcludePaths) { if ($lib =~ m!$exclude!) { $toss = 1; } } if ($toss) { foreach $include (@IncludePaths) { if ($lib =~ m!$include!) { $toss = 0; } } } if (! $toss) { push @Deps, $lib; } } return(@Deps); } sub want_libraries { if (-f $File::Find::name) { my ($cmd) = "/usr/bin/file $File::Find::name"; $_ = `$cmd`; if ($?>>8) { #printf STDERR "$ProgName: Command \"$cmd\" failed\n"; #exit(1); return; } if ($_ =~ "Mach-O" && $_ =~ "library") { push (@WantedFiles, $File::Find::name); } } } sub want_executables { if (-f $File::Find::name) { # clyne - Tue Feb 2 20:17:17 MST 2016 # # The /usr/bin/file command returns "Linux/i386 core file". Sigh. # #my ($cmd) = "/usr/bin/file $File::Find::name"; #$_ = `$cmd`; #if ($?>>8) { #printf STDERR "$ProgName: Command \"$cmd\" failed\n"; #exit(1); # return; #} #if ($_ =~ "Mach-O" && $_ =~ "executable") { # push (@WantedFiles, $File::Find::name); #} my ($cmd) = "/usr/bin/otool -h $File::Find::name"; $_ = `$cmd`; if ($?>>8) { #printf STDERR "$ProgName: Command \"$cmd\" failed\n"; #exit(1); return; } if ($_ =~ "Mach header") { push (@WantedFiles, $File::Find::name); } } } sub find_mach_o { my($do_lib, @paths) = @_; @WantedFiles = (); if ($do_lib) { find (\&want_libraries, @paths); } else { find (\&want_executables, @paths); } return(@WantedFiles); } sub get_relpath_to_libname { my($libname, $exec_path, @libs) = @_; foreach $lib (@libs) { my($vol_new, $dir_new, $file_new) = File::Spec->splitpath($lib); if ($libname eq $file_new) { return (File::Spec->abs2rel($lib, $ExecPath)); } } return; } sub get_dep_libname { my($dep) = @_; # # remove Mac OS macros # $dep =~ s/\@executable_path//; $dep =~ s/\@loader_path//; $dep =~ s/\@rpath//; my($vol, $dir, $libname) = File::Spec->splitpath($dep); return ($libname); } # # Install path is hardwired :-( # $InstallExecPath = "/Applications/VAPOR3/VAPOR.app/Contents/MacOS"; $ExecPath = ""; @IncludePaths = (); @ExcludePaths = ("^/System", "^/usr/lib"); # exclude everything by default @ExecutablePaths = (); $Arch = "Darwin"; # only works on Mac OS while ($ARGV[0] =~ /^-/) { $_ = shift @ARGV; if (/^-include$/) { defined($_ = shift @ARGV) || die "Missing argument"; push(@IncludePaths, $_); } elsif (/^-exec_path$/) { defined($_ = shift @ARGV) || die "Missing argument"; push(@ExecutablePaths, $_); } else { usage("Invalid option: $_"); } } if (! (defined($ExecPath = pop @ARGV))) { usage("Wrong # of arguments"); } if (! -d $ExecPath) { print STDERR "$ProgName: Executable path $ExecPath does not exist\n"; exit(1); } push(@ExecutablePaths, $ExecPath); @LibSearchPaths = @ARGV; @Executables = find_mach_o(0, $ExecPath); @Libraries = find_mach_o(1, @LibSearchPaths); push(@IncludePaths, $ExecPath); foreach $target (@Executables) { if ($Debug) {print "Target = $target\n";} my(@Deps) = get_deps($target, @ExecutablePaths); foreach $dep (@Deps) { if ($Debug) {print "dep = $dep\n";} my ($libname) = get_dep_libname($dep); if (! defined($libname)) { print STDERR "$ProgName: Couldn't resolve name for $dep\n"; exit(1); } my($rel_path) = get_relpath_to_libname($libname, $ExecPath, @Libraries); if (! defined($rel_path)) { print STDERR "$ProgName: Dependent library $dep not found\n"; print STDERR "Looked for $libname in:\n"; foreach $lib (@Libraries) { print STDERR " $lib\n"; } exit(1); } # # Wed May 6 12:18:32 MDT 2015 # Hard code name to full application installation path. This makes # it easier for 3rd party applications to link to VAPOR libraries. # my (@cmd) = ( "/usr/bin/install_name_tool", "-change", $dep, "$InstallExecPath/$rel_path", $target ); # my (@cmd) = ( # "/usr/bin/install_name_tool", "-change", $dep, # "\@executable_path/$rel_path", $target # ); mysystem(@cmd); } } foreach $target (@Libraries) { if ($Debug) {print "Target = $target\n";} my($rel_path) = File::Spec->abs2rel($target, $ExecPath); if (! defined($rel_path)) { print STDERR "$ProgName: No path from $target to $ExecPath\n"; exit(1); } # # Mon Nov 26 19:31:36 MST 2012 - clyne # Hard code name to full application installation path. This makes # it easier for 3rd party applications to link to VAPOR libraries. # my($vol, $dir, $libname) = File::Spec->splitpath($target); my (@cmd) = ( "/usr/bin/install_name_tool", "-id", "$InstallExecPath/$rel_path", $target ); # my (@cmd) = ( # "/usr/bin/install_name_tool", "-id", # "\@executable_path/$rel_path", $target # ); mysystem(@cmd); my(@Deps) = get_deps($target, @ExecutablePaths); foreach $dep (@Deps) { if ($Debug) {print "dep = $dep\n";} my ($libname) = get_dep_libname($dep); if (! defined($libname)) { print STDERR "$ProgName: Couldn't resolve name for $dep\n"; exit(1); } my($rel_path) = get_relpath_to_libname($libname, $ExecPath, @Libraries); if (! defined($rel_path)) { print STDERR "$ProgName: Dependent library $dep not found\n"; exit(1); } my (@cmd) = ( "/usr/bin/install_name_tool", "-change", $dep, "$InstallExecPath/$rel_path", $target ); # my (@cmd) = ( # "/usr/bin/install_name_tool", "-change", $dep, # "\@executable_path/$rel_path", $target # ); mysystem(@cmd); } } exit 0; ================================================ FILE: buildutils/mklinks.pl ================================================ #!/usr/bin/perl use English; use POSIX; use Cwd; use File::Basename; #use File::Glob; use File::Copy; use File::Spec; $0 =~ s/.*\///; $ProgName = $0; sub usage { my($msg) = @_; if ($msg) { printf STDERR "$ProgName: $msg\n"; } printf STDERR "Usage: %s libname application_path directory\n", $ProgName; exit(1); } sub chaselink { my($path) = @_; if (defined($link = readlink($path))) { if (! File::Spec->file_name_is_absolute($link)) { my($name0,$dir0) = fileparse($path); my($name1,$dir1) = fileparse($link); $link = "$dir0" . "$name1"; } return(chaselink($link)); } else { return($path); } } if (! (defined($Arch = shift @ARGV))) { usage("Wrong # of arguments"); } if (! (defined($Libname = shift @ARGV))) { usage("Wrong # of arguments"); } if (! (defined($Application = shift @ARGV))) { usage("Wrong # of arguments"); } if (! (defined($TargetDir = shift @ARGV))) { usage("Wrong # of arguments"); } if (defined(shift @ARGV)) { usage("Wrong # of arguments"); } if ($Arch eq "Darwin") { $cmd = "/usr/bin/otool -L $Application"; } else { $cmd = "/usr/bin/ldd $Application"; } $_ = `$cmd`; if ($?>>8) { printf STDERR "$ProgName: Command \"$cmd\" failed\n"; exit(1); } @matchs = (); @lines = split /\n/, $_; foreach $line (@lines) { if ($line =~ $Libname) { push @matchs, $line; } } if (@matchs < 1) { printf STDERR "$ProgName: WARNING : Library $Libname not found in application $Application\n"; exit(0); } if (@matchs > 1) { printf STDERR "$ProgName: Multiple instances of library $Libname found in application $Application\n"; exit(1); } # remove leading white space. Don't know why this is neccessary - split # should take care of it. # $matchs[0] =~ s/^\s+//; @_ = split /\s+/, $matchs[0]; if ($Arch eq "Darwin") { $path = $_[0]; } else { $path = $_[2]; } my($name,$dir,$suffix) = fileparse($path); @libs = glob("$dir" . $Libname . "*"); @cpfiles = (); foreach $lib (@libs) { if (defined(readlink($lib))) { $link = chaselink($lib); my($oldname,$olddir,) = fileparse($link); my($newname,$newdir) = fileparse($lib); if ($oldname ne $newname) { $newname = "$TargetDir" . "/" . $newname; if (! eval { symlink("$oldname","$newname"); 1 }) { printf STDERR "$ProgName: symlink($oldname, $newname) : failed\n"; exit(1); } } else { push @cpfiles, $link } } else { push @cpfiles, $lib } } foreach $lib (@cpfiles) { copy($lib, $TargetDir) or die "Copy failed: $!"; my($name,$dir,) = fileparse($lib); chmod 0755, $TargetDir . "/" . $name; } exit 0; ================================================ FILE: buildutils/patchelf/COPYING ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: buildutils/patchelf/elf.h ================================================ /* This file defines standard ELF types, structures, and macros. Copyright (C) 1995-2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C 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. The GNU C 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 the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifndef _ELF_H #define _ELF_H 1 /* Standard ELF types. */ #include /* Type for a 16-bit quantity. */ typedef uint16_t Elf32_Half; typedef uint16_t Elf64_Half; /* Types for signed and unsigned 32-bit quantities. */ typedef uint32_t Elf32_Word; typedef int32_t Elf32_Sword; typedef uint32_t Elf64_Word; typedef int32_t Elf64_Sword; /* Types for signed and unsigned 64-bit quantities. */ typedef uint64_t Elf32_Xword; typedef int64_t Elf32_Sxword; typedef uint64_t Elf64_Xword; typedef int64_t Elf64_Sxword; /* Type of addresses. */ typedef uint32_t Elf32_Addr; typedef uint64_t Elf64_Addr; /* Type of file offsets. */ typedef uint32_t Elf32_Off; typedef uint64_t Elf64_Off; /* Type for section indices, which are 16-bit quantities. */ typedef uint16_t Elf32_Section; typedef uint16_t Elf64_Section; /* Type for version symbol information. */ typedef Elf32_Half Elf32_Versym; typedef Elf64_Half Elf64_Versym; /* The ELF file header. This appears at the start of every ELF file. */ #define EI_NIDENT (16) typedef struct { unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf32_Half e_type; /* Object file type */ Elf32_Half e_machine; /* Architecture */ Elf32_Word e_version; /* Object file version */ Elf32_Addr e_entry; /* Entry point virtual address */ Elf32_Off e_phoff; /* Program header table file offset */ Elf32_Off e_shoff; /* Section header table file offset */ Elf32_Word e_flags; /* Processor-specific flags */ Elf32_Half e_ehsize; /* ELF header size in bytes */ Elf32_Half e_phentsize; /* Program header table entry size */ Elf32_Half e_phnum; /* Program header table entry count */ Elf32_Half e_shentsize; /* Section header table entry size */ Elf32_Half e_shnum; /* Section header table entry count */ Elf32_Half e_shstrndx; /* Section header string table index */ } Elf32_Ehdr; typedef struct { unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf64_Half e_type; /* Object file type */ Elf64_Half e_machine; /* Architecture */ Elf64_Word e_version; /* Object file version */ Elf64_Addr e_entry; /* Entry point virtual address */ Elf64_Off e_phoff; /* Program header table file offset */ Elf64_Off e_shoff; /* Section header table file offset */ Elf64_Word e_flags; /* Processor-specific flags */ Elf64_Half e_ehsize; /* ELF header size in bytes */ Elf64_Half e_phentsize; /* Program header table entry size */ Elf64_Half e_phnum; /* Program header table entry count */ Elf64_Half e_shentsize; /* Section header table entry size */ Elf64_Half e_shnum; /* Section header table entry count */ Elf64_Half e_shstrndx; /* Section header string table index */ } Elf64_Ehdr; /* Fields in the e_ident array. The EI_* macros are indices into the array. The macros under each EI_* macro are the values the byte may have. */ #define EI_MAG0 0 /* File identification byte 0 index */ #define ELFMAG0 0x7f /* Magic number byte 0 */ #define EI_MAG1 1 /* File identification byte 1 index */ #define ELFMAG1 'E' /* Magic number byte 1 */ #define EI_MAG2 2 /* File identification byte 2 index */ #define ELFMAG2 'L' /* Magic number byte 2 */ #define EI_MAG3 3 /* File identification byte 3 index */ #define ELFMAG3 'F' /* Magic number byte 3 */ /* Conglomeration of the identification bytes, for easy testing as a word. */ #define ELFMAG "\177ELF" #define SELFMAG 4 #define EI_CLASS 4 /* File class byte index */ #define ELFCLASSNONE 0 /* Invalid class */ #define ELFCLASS32 1 /* 32-bit objects */ #define ELFCLASS64 2 /* 64-bit objects */ #define ELFCLASSNUM 3 #define EI_DATA 5 /* Data encoding byte index */ #define ELFDATANONE 0 /* Invalid data encoding */ #define ELFDATA2LSB 1 /* 2's complement, little endian */ #define ELFDATA2MSB 2 /* 2's complement, big endian */ #define ELFDATANUM 3 #define EI_VERSION 6 /* File version byte index */ /* Value must be EV_CURRENT */ #define EI_OSABI 7 /* OS ABI identification */ #define ELFOSABI_NONE 0 /* UNIX System V ABI */ #define ELFOSABI_SYSV 0 /* Alias. */ #define ELFOSABI_HPUX 1 /* HP-UX */ #define ELFOSABI_NETBSD 2 /* NetBSD. */ #define ELFOSABI_LINUX 3 /* Linux. */ #define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ #define ELFOSABI_AIX 7 /* IBM AIX. */ #define ELFOSABI_IRIX 8 /* SGI Irix. */ #define ELFOSABI_FREEBSD 9 /* FreeBSD. */ #define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ #define ELFOSABI_MODESTO 11 /* Novell Modesto. */ #define ELFOSABI_OPENBSD 12 /* OpenBSD. */ #define ELFOSABI_ARM 97 /* ARM */ #define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ #define EI_ABIVERSION 8 /* ABI version */ #define EI_PAD 9 /* Byte index of padding bytes */ /* Legal values for e_type (object file type). */ #define ET_NONE 0 /* No file type */ #define ET_REL 1 /* Relocatable file */ #define ET_EXEC 2 /* Executable file */ #define ET_DYN 3 /* Shared object file */ #define ET_CORE 4 /* Core file */ #define ET_NUM 5 /* Number of defined types */ #define ET_LOOS 0xfe00 /* OS-specific range start */ #define ET_HIOS 0xfeff /* OS-specific range end */ #define ET_LOPROC 0xff00 /* Processor-specific range start */ #define ET_HIPROC 0xffff /* Processor-specific range end */ /* Legal values for e_machine (architecture). */ #define EM_NONE 0 /* No machine */ #define EM_M32 1 /* AT&T WE 32100 */ #define EM_SPARC 2 /* SUN SPARC */ #define EM_386 3 /* Intel 80386 */ #define EM_68K 4 /* Motorola m68k family */ #define EM_88K 5 /* Motorola m88k family */ #define EM_860 7 /* Intel 80860 */ #define EM_MIPS 8 /* MIPS R3000 big-endian */ #define EM_S370 9 /* IBM System/370 */ #define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ #define EM_PARISC 15 /* HPPA */ #define EM_VPP500 17 /* Fujitsu VPP500 */ #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ #define EM_960 19 /* Intel 80960 */ #define EM_PPC 20 /* PowerPC */ #define EM_PPC64 21 /* PowerPC 64-bit */ #define EM_S390 22 /* IBM S390 */ #define EM_V800 36 /* NEC V800 series */ #define EM_FR20 37 /* Fujitsu FR20 */ #define EM_RH32 38 /* TRW RH-32 */ #define EM_RCE 39 /* Motorola RCE */ #define EM_ARM 40 /* ARM */ #define EM_FAKE_ALPHA 41 /* Digital Alpha */ #define EM_SH 42 /* Hitachi SH */ #define EM_SPARCV9 43 /* SPARC v9 64-bit */ #define EM_TRICORE 44 /* Siemens Tricore */ #define EM_ARC 45 /* Argonaut RISC Core */ #define EM_H8_300 46 /* Hitachi H8/300 */ #define EM_H8_300H 47 /* Hitachi H8/300H */ #define EM_H8S 48 /* Hitachi H8S */ #define EM_H8_500 49 /* Hitachi H8/500 */ #define EM_IA_64 50 /* Intel Merced */ #define EM_MIPS_X 51 /* Stanford MIPS-X */ #define EM_COLDFIRE 52 /* Motorola Coldfire */ #define EM_68HC12 53 /* Motorola M68HC12 */ #define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ #define EM_PCP 55 /* Siemens PCP */ #define EM_NCPU 56 /* Sony nCPU embeeded RISC */ #define EM_NDR1 57 /* Denso NDR1 microprocessor */ #define EM_STARCORE 58 /* Motorola Start*Core processor */ #define EM_ME16 59 /* Toyota ME16 processor */ #define EM_ST100 60 /* STMicroelectronic ST100 processor */ #define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ #define EM_X86_64 62 /* AMD x86-64 architecture */ #define EM_PDSP 63 /* Sony DSP Processor */ #define EM_FX66 66 /* Siemens FX66 microcontroller */ #define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ #define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ #define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ #define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ #define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ #define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ #define EM_SVX 73 /* Silicon Graphics SVx */ #define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ #define EM_VAX 75 /* Digital VAX */ #define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ #define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ #define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ #define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ #define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ #define EM_HUANY 81 /* Harvard University machine-independent object files */ #define EM_PRISM 82 /* SiTera Prism */ #define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ #define EM_FR30 84 /* Fujitsu FR30 */ #define EM_D10V 85 /* Mitsubishi D10V */ #define EM_D30V 86 /* Mitsubishi D30V */ #define EM_V850 87 /* NEC v850 */ #define EM_M32R 88 /* Mitsubishi M32R */ #define EM_MN10300 89 /* Matsushita MN10300 */ #define EM_MN10200 90 /* Matsushita MN10200 */ #define EM_PJ 91 /* picoJava */ #define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ #define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ #define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ #define EM_NUM 95 /* If it is necessary to assign new unofficial EM_* values, please pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision with official or non-GNU unofficial values. */ #define EM_ALPHA 0x9026 /* Legal values for e_version (version). */ #define EV_NONE 0 /* Invalid ELF version */ #define EV_CURRENT 1 /* Current version */ #define EV_NUM 2 /* Section header. */ typedef struct { Elf32_Word sh_name; /* Section name (string tbl index) */ Elf32_Word sh_type; /* Section type */ Elf32_Word sh_flags; /* Section flags */ Elf32_Addr sh_addr; /* Section virtual addr at execution */ Elf32_Off sh_offset; /* Section file offset */ Elf32_Word sh_size; /* Section size in bytes */ Elf32_Word sh_link; /* Link to another section */ Elf32_Word sh_info; /* Additional section information */ Elf32_Word sh_addralign; /* Section alignment */ Elf32_Word sh_entsize; /* Entry size if section holds table */ } Elf32_Shdr; typedef struct { Elf64_Word sh_name; /* Section name (string tbl index) */ Elf64_Word sh_type; /* Section type */ Elf64_Xword sh_flags; /* Section flags */ Elf64_Addr sh_addr; /* Section virtual addr at execution */ Elf64_Off sh_offset; /* Section file offset */ Elf64_Xword sh_size; /* Section size in bytes */ Elf64_Word sh_link; /* Link to another section */ Elf64_Word sh_info; /* Additional section information */ Elf64_Xword sh_addralign; /* Section alignment */ Elf64_Xword sh_entsize; /* Entry size if section holds table */ } Elf64_Shdr; /* Special section indices. */ #define SHN_UNDEF 0 /* Undefined section */ #define SHN_LORESERVE 0xff00 /* Start of reserved indices */ #define SHN_LOPROC 0xff00 /* Start of processor-specific */ #define SHN_BEFORE \ 0xff00 /* Order section before all others \ (Solaris). */ #define SHN_AFTER \ 0xff01 /* Order section after all others \ (Solaris). */ #define SHN_HIPROC 0xff1f /* End of processor-specific */ #define SHN_LOOS 0xff20 /* Start of OS-specific */ #define SHN_HIOS 0xff3f /* End of OS-specific */ #define SHN_ABS 0xfff1 /* Associated symbol is absolute */ #define SHN_COMMON 0xfff2 /* Associated symbol is common */ #define SHN_XINDEX 0xffff /* Index is in extra table. */ #define SHN_HIRESERVE 0xffff /* End of reserved indices */ /* Legal values for sh_type (section type). */ #define SHT_NULL 0 /* Section header table entry unused */ #define SHT_PROGBITS 1 /* Program data */ #define SHT_SYMTAB 2 /* Symbol table */ #define SHT_STRTAB 3 /* String table */ #define SHT_RELA 4 /* Relocation entries with addends */ #define SHT_HASH 5 /* Symbol hash table */ #define SHT_DYNAMIC 6 /* Dynamic linking information */ #define SHT_NOTE 7 /* Notes */ #define SHT_NOBITS 8 /* Program space with no data (bss) */ #define SHT_REL 9 /* Relocation entries, no addends */ #define SHT_SHLIB 10 /* Reserved */ #define SHT_DYNSYM 11 /* Dynamic linker symbol table */ #define SHT_INIT_ARRAY 14 /* Array of constructors */ #define SHT_FINI_ARRAY 15 /* Array of destructors */ #define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ #define SHT_GROUP 17 /* Section group */ #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ #define SHT_NUM 19 /* Number of defined types. */ #define SHT_LOOS 0x60000000 /* Start OS-specific. */ #define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ #define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ #define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ #define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ #define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ #define SHT_SUNW_move 0x6ffffffa #define SHT_SUNW_COMDAT 0x6ffffffb #define SHT_SUNW_syminfo 0x6ffffffc #define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ #define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ #define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ #define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ #define SHT_HIOS 0x6fffffff /* End OS-specific type */ #define SHT_LOPROC 0x70000000 /* Start of processor-specific */ #define SHT_HIPROC 0x7fffffff /* End of processor-specific */ #define SHT_LOUSER 0x80000000 /* Start of application-specific */ #define SHT_HIUSER 0x8fffffff /* End of application-specific */ /* Legal values for sh_flags (section flags). */ #define SHF_WRITE (1 << 0) /* Writable */ #define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ #define SHF_EXECINSTR (1 << 2) /* Executable */ #define SHF_MERGE (1 << 4) /* Might be merged */ #define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ #define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ #define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ #define SHF_OS_NONCONFORMING \ (1 << 8) /* Non-standard OS specific handling \ required */ #define SHF_GROUP (1 << 9) /* Section is member of a group. */ #define SHF_TLS (1 << 10) /* Section hold thread-local data. */ #define SHF_MASKOS 0x0ff00000 /* OS-specific. */ #define SHF_MASKPROC 0xf0000000 /* Processor-specific */ #define SHF_ORDERED \ (1 << 30) /* Special ordering requirement \ (Solaris). */ #define SHF_EXCLUDE \ (1 << 31) /* Section is excluded unless \ referenced or allocated (Solaris).*/ /* Section group handling. */ #define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ /* Symbol table entry. */ typedef struct { Elf32_Word st_name; /* Symbol name (string tbl index) */ Elf32_Addr st_value; /* Symbol value */ Elf32_Word st_size; /* Symbol size */ unsigned char st_info; /* Symbol type and binding */ unsigned char st_other; /* Symbol visibility */ Elf32_Section st_shndx; /* Section index */ } Elf32_Sym; typedef struct { Elf64_Word st_name; /* Symbol name (string tbl index) */ unsigned char st_info; /* Symbol type and binding */ unsigned char st_other; /* Symbol visibility */ Elf64_Section st_shndx; /* Section index */ Elf64_Addr st_value; /* Symbol value */ Elf64_Xword st_size; /* Symbol size */ } Elf64_Sym; /* The syminfo section if available contains additional information about every dynamic symbol. */ typedef struct { Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ Elf32_Half si_flags; /* Per symbol flags */ } Elf32_Syminfo; typedef struct { Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ Elf64_Half si_flags; /* Per symbol flags */ } Elf64_Syminfo; /* Possible values for si_boundto. */ #define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ #define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ #define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ /* Possible bitmasks for si_flags. */ #define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ #define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ #define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ #define SYMINFO_FLG_LAZYLOAD \ 0x0008 /* Symbol bound to object to be lazy \ loaded */ /* Syminfo version values. */ #define SYMINFO_NONE 0 #define SYMINFO_CURRENT 1 #define SYMINFO_NUM 2 /* How to extract and insert information held in the st_info field. */ #define ELF32_ST_BIND(val) (((unsigned char)(val)) >> 4) #define ELF32_ST_TYPE(val) ((val)&0xf) #define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf)) /* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ #define ELF64_ST_BIND(val) ELF32_ST_BIND(val) #define ELF64_ST_TYPE(val) ELF32_ST_TYPE(val) #define ELF64_ST_INFO(bind, type) ELF32_ST_INFO((bind), (type)) /* Legal values for ST_BIND subfield of st_info (symbol binding). */ #define STB_LOCAL 0 /* Local symbol */ #define STB_GLOBAL 1 /* Global symbol */ #define STB_WEAK 2 /* Weak symbol */ #define STB_NUM 3 /* Number of defined types. */ #define STB_LOOS 10 /* Start of OS-specific */ #define STB_HIOS 12 /* End of OS-specific */ #define STB_LOPROC 13 /* Start of processor-specific */ #define STB_HIPROC 15 /* End of processor-specific */ /* Legal values for ST_TYPE subfield of st_info (symbol type). */ #define STT_NOTYPE 0 /* Symbol type is unspecified */ #define STT_OBJECT 1 /* Symbol is a data object */ #define STT_FUNC 2 /* Symbol is a code object */ #define STT_SECTION 3 /* Symbol associated with a section */ #define STT_FILE 4 /* Symbol's name is file name */ #define STT_COMMON 5 /* Symbol is a common data object */ #define STT_TLS 6 /* Symbol is thread-local data object*/ #define STT_NUM 7 /* Number of defined types. */ #define STT_LOOS 10 /* Start of OS-specific */ #define STT_HIOS 12 /* End of OS-specific */ #define STT_LOPROC 13 /* Start of processor-specific */ #define STT_HIPROC 15 /* End of processor-specific */ /* Symbol table indices are found in the hash buckets and chain table of a symbol hash table section. This special index value indicates the end of a chain, meaning no further symbols are found in that bucket. */ #define STN_UNDEF 0 /* End of a chain. */ /* How to extract and insert information held in the st_other field. */ #define ELF32_ST_VISIBILITY(o) ((o)&0x03) /* For ELF64 the definitions are the same. */ #define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o) /* Symbol visibility specification encoded in the st_other field. */ #define STV_DEFAULT 0 /* Default symbol visibility rules */ #define STV_INTERNAL 1 /* Processor specific hidden class */ #define STV_HIDDEN 2 /* Sym unavailable in other modules */ #define STV_PROTECTED 3 /* Not preemptible, not exported */ /* Relocation table entry without addend (in section of type SHT_REL). */ typedef struct { Elf32_Addr r_offset; /* Address */ Elf32_Word r_info; /* Relocation type and symbol index */ } Elf32_Rel; /* I have seen two different definitions of the Elf64_Rel and Elf64_Rela structures, so we'll leave them out until Novell (or whoever) gets their act together. */ /* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ typedef struct { Elf64_Addr r_offset; /* Address */ Elf64_Xword r_info; /* Relocation type and symbol index */ } Elf64_Rel; /* Relocation table entry with addend (in section of type SHT_RELA). */ typedef struct { Elf32_Addr r_offset; /* Address */ Elf32_Word r_info; /* Relocation type and symbol index */ Elf32_Sword r_addend; /* Addend */ } Elf32_Rela; typedef struct { Elf64_Addr r_offset; /* Address */ Elf64_Xword r_info; /* Relocation type and symbol index */ Elf64_Sxword r_addend; /* Addend */ } Elf64_Rela; /* How to extract and insert information held in the r_info field. */ #define ELF32_R_SYM(val) ((val) >> 8) #define ELF32_R_TYPE(val) ((val)&0xff) #define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type)&0xff)) #define ELF64_R_SYM(i) ((i) >> 32) #define ELF64_R_TYPE(i) ((i)&0xffffffff) #define ELF64_R_INFO(sym, type) ((((Elf64_Xword)(sym)) << 32) + (type)) /* Program segment header. */ typedef struct { Elf32_Word p_type; /* Segment type */ Elf32_Off p_offset; /* Segment file offset */ Elf32_Addr p_vaddr; /* Segment virtual address */ Elf32_Addr p_paddr; /* Segment physical address */ Elf32_Word p_filesz; /* Segment size in file */ Elf32_Word p_memsz; /* Segment size in memory */ Elf32_Word p_flags; /* Segment flags */ Elf32_Word p_align; /* Segment alignment */ } Elf32_Phdr; typedef struct { Elf64_Word p_type; /* Segment type */ Elf64_Word p_flags; /* Segment flags */ Elf64_Off p_offset; /* Segment file offset */ Elf64_Addr p_vaddr; /* Segment virtual address */ Elf64_Addr p_paddr; /* Segment physical address */ Elf64_Xword p_filesz; /* Segment size in file */ Elf64_Xword p_memsz; /* Segment size in memory */ Elf64_Xword p_align; /* Segment alignment */ } Elf64_Phdr; /* Legal values for p_type (segment type). */ #define PT_NULL 0 /* Program header table entry unused */ #define PT_LOAD 1 /* Loadable program segment */ #define PT_DYNAMIC 2 /* Dynamic linking information */ #define PT_INTERP 3 /* Program interpreter */ #define PT_NOTE 4 /* Auxiliary information */ #define PT_SHLIB 5 /* Reserved */ #define PT_PHDR 6 /* Entry for header table itself */ #define PT_TLS 7 /* Thread-local storage segment */ #define PT_NUM 8 /* Number of defined types */ #define PT_LOOS 0x60000000 /* Start of OS-specific */ #define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ #define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ #define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ #define PT_LOSUNW 0x6ffffffa #define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ #define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ #define PT_HISUNW 0x6fffffff #define PT_HIOS 0x6fffffff /* End of OS-specific */ #define PT_LOPROC 0x70000000 /* Start of processor-specific */ #define PT_HIPROC 0x7fffffff /* End of processor-specific */ /* Legal values for p_flags (segment flags). */ #define PF_X (1 << 0) /* Segment is executable */ #define PF_W (1 << 1) /* Segment is writable */ #define PF_R (1 << 2) /* Segment is readable */ #define PF_MASKOS 0x0ff00000 /* OS-specific */ #define PF_MASKPROC 0xf0000000 /* Processor-specific */ /* Legal values for note segment descriptor types for core files. */ #define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ #define NT_FPREGSET 2 /* Contains copy of fpregset struct */ #define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ #define NT_PRXREG 4 /* Contains copy of prxregset struct */ #define NT_TASKSTRUCT 4 /* Contains copy of task structure */ #define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ #define NT_AUXV 6 /* Contains copy of auxv array */ #define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ #define NT_ASRS 8 /* Contains copy of asrset struct */ #define NT_PSTATUS 10 /* Contains copy of pstatus struct */ #define NT_PSINFO 13 /* Contains copy of psinfo struct */ #define NT_PRCRED 14 /* Contains copy of prcred struct */ #define NT_UTSNAME 15 /* Contains copy of utsname struct */ #define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ #define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ #define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ #define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ #define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ #define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ #define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ /* Legal values for the note segment descriptor types for object files. */ #define NT_VERSION 1 /* Contains a version string. */ /* Dynamic section entry. */ typedef struct { Elf32_Sword d_tag; /* Dynamic entry type */ union { Elf32_Word d_val; /* Integer value */ Elf32_Addr d_ptr; /* Address value */ } d_un; } Elf32_Dyn; typedef struct { Elf64_Sxword d_tag; /* Dynamic entry type */ union { Elf64_Xword d_val; /* Integer value */ Elf64_Addr d_ptr; /* Address value */ } d_un; } Elf64_Dyn; /* Legal values for d_tag (dynamic entry type). */ #define DT_NULL 0 /* Marks end of dynamic section */ #define DT_NEEDED 1 /* Name of needed library */ #define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ #define DT_PLTGOT 3 /* Processor defined value */ #define DT_HASH 4 /* Address of symbol hash table */ #define DT_STRTAB 5 /* Address of string table */ #define DT_SYMTAB 6 /* Address of symbol table */ #define DT_RELA 7 /* Address of Rela relocs */ #define DT_RELASZ 8 /* Total size of Rela relocs */ #define DT_RELAENT 9 /* Size of one Rela reloc */ #define DT_STRSZ 10 /* Size of string table */ #define DT_SYMENT 11 /* Size of one symbol table entry */ #define DT_INIT 12 /* Address of init function */ #define DT_FINI 13 /* Address of termination function */ #define DT_SONAME 14 /* Name of shared object */ #define DT_RPATH 15 /* Library search path (deprecated) */ #define DT_SYMBOLIC 16 /* Start symbol search here */ #define DT_REL 17 /* Address of Rel relocs */ #define DT_RELSZ 18 /* Total size of Rel relocs */ #define DT_RELENT 19 /* Size of one Rel reloc */ #define DT_PLTREL 20 /* Type of reloc in PLT */ #define DT_DEBUG 21 /* For debugging; unspecified */ #define DT_TEXTREL 22 /* Reloc might modify .text */ #define DT_JMPREL 23 /* Address of PLT relocs */ #define DT_BIND_NOW 24 /* Process relocations of object */ #define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ #define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ #define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ #define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ #define DT_RUNPATH 29 /* Library search path */ #define DT_FLAGS 30 /* Flags for the object being loaded */ #define DT_ENCODING 32 /* Start of encoded range */ #define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ #define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ #define DT_NUM 34 /* Number used */ #define DT_LOOS 0x6000000d /* Start of OS-specific */ #define DT_HIOS 0x6ffff000 /* End of OS-specific */ #define DT_LOPROC 0x70000000 /* Start of processor-specific */ #define DT_HIPROC 0x7fffffff /* End of processor-specific */ #define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ /* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's approach. */ #define DT_VALRNGLO 0x6ffffd00 #define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ #define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ #define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ #define DT_CHECKSUM 0x6ffffdf8 #define DT_PLTPADSZ 0x6ffffdf9 #define DT_MOVEENT 0x6ffffdfa #define DT_MOVESZ 0x6ffffdfb #define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ #define DT_POSFLAG_1 \ 0x6ffffdfd /* Flags for DT_* entries, effecting \ the following DT_* entry. */ #define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ #define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ #define DT_VALRNGHI 0x6ffffdff #define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ #define DT_VALNUM 12 /* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the Dyn.d_un.d_ptr field of the Elf*_Dyn structure. If any adjustment is made to the ELF object after it has been built these entries will need to be adjusted. */ #define DT_ADDRRNGLO 0x6ffffe00 #define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ #define DT_TLSDESC_PLT 0x6ffffef6 #define DT_TLSDESC_GOT 0x6ffffef7 #define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ #define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ #define DT_CONFIG 0x6ffffefa /* Configuration information. */ #define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ #define DT_AUDIT 0x6ffffefc /* Object auditing. */ #define DT_PLTPAD 0x6ffffefd /* PLT padding. */ #define DT_MOVETAB 0x6ffffefe /* Move table. */ #define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ #define DT_ADDRRNGHI 0x6ffffeff #define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ #define DT_ADDRNUM 11 /* The versioning entry types. The next are defined as part of the GNU extension. */ #define DT_VERSYM 0x6ffffff0 #define DT_RELACOUNT 0x6ffffff9 #define DT_RELCOUNT 0x6ffffffa /* These were chosen by Sun. */ #define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ #define DT_VERDEF \ 0x6ffffffc /* Address of version definition \ table */ #define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ #define DT_VERNEED \ 0x6ffffffe /* Address of table with needed \ versions */ #define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ #define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ #define DT_VERSIONTAGNUM 16 /* Sun added these machine-independent extensions in the "processor-specific" range. Be compatible. */ #define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ #define DT_FILTER 0x7fffffff /* Shared object to get values from */ #define DT_EXTRATAGIDX(tag) ((Elf32_Word) - ((Elf32_Sword)(tag) << 1 >> 1) - 1) #define DT_EXTRANUM 3 /* Values of `d_un.d_val' in the DT_FLAGS entry. */ #define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ #define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ #define DF_TEXTREL 0x00000004 /* Object contains text relocations */ #define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ #define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ /* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 entry in the dynamic section. */ #define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ #define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ #define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ #define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ #define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ #define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ #define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ #define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ #define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ #define DF_1_TRANS 0x00000200 #define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ #define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ #define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ #define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ #define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ #define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ #define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ /* Flags for the feature selection in DT_FEATURE_1. */ #define DTF_1_PARINIT 0x00000001 #define DTF_1_CONFEXP 0x00000002 /* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ #define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ #define DF_P1_GROUPPERM \ 0x00000002 /* Symbols from next object are not \ generally available. */ /* Version definition sections. */ typedef struct { Elf32_Half vd_version; /* Version revision */ Elf32_Half vd_flags; /* Version information */ Elf32_Half vd_ndx; /* Version Index */ Elf32_Half vd_cnt; /* Number of associated aux entries */ Elf32_Word vd_hash; /* Version name hash value */ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ Elf32_Word vd_next; /* Offset in bytes to next verdef entry */ } Elf32_Verdef; typedef struct { Elf64_Half vd_version; /* Version revision */ Elf64_Half vd_flags; /* Version information */ Elf64_Half vd_ndx; /* Version Index */ Elf64_Half vd_cnt; /* Number of associated aux entries */ Elf64_Word vd_hash; /* Version name hash value */ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ Elf64_Word vd_next; /* Offset in bytes to next verdef entry */ } Elf64_Verdef; /* Legal values for vd_version (version revision). */ #define VER_DEF_NONE 0 /* No version */ #define VER_DEF_CURRENT 1 /* Current version */ #define VER_DEF_NUM 2 /* Given version number */ /* Legal values for vd_flags (version information flags). */ #define VER_FLG_BASE 0x1 /* Version definition of file itself */ #define VER_FLG_WEAK 0x2 /* Weak version identifier */ /* Versym symbol index values. */ #define VER_NDX_LOCAL 0 /* Symbol is local. */ #define VER_NDX_GLOBAL 1 /* Symbol is global. */ #define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ #define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ /* Auxialiary version information. */ typedef struct { Elf32_Word vda_name; /* Version or dependency names */ Elf32_Word vda_next; /* Offset in bytes to next verdaux entry */ } Elf32_Verdaux; typedef struct { Elf64_Word vda_name; /* Version or dependency names */ Elf64_Word vda_next; /* Offset in bytes to next verdaux entry */ } Elf64_Verdaux; /* Version dependency section. */ typedef struct { Elf32_Half vn_version; /* Version of structure */ Elf32_Half vn_cnt; /* Number of associated aux entries */ Elf32_Word vn_file; /* Offset of filename for this dependency */ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ Elf32_Word vn_next; /* Offset in bytes to next verneed entry */ } Elf32_Verneed; typedef struct { Elf64_Half vn_version; /* Version of structure */ Elf64_Half vn_cnt; /* Number of associated aux entries */ Elf64_Word vn_file; /* Offset of filename for this dependency */ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ Elf64_Word vn_next; /* Offset in bytes to next verneed entry */ } Elf64_Verneed; /* Legal values for vn_version (version revision). */ #define VER_NEED_NONE 0 /* No version */ #define VER_NEED_CURRENT 1 /* Current version */ #define VER_NEED_NUM 2 /* Given version number */ /* Auxiliary needed version information. */ typedef struct { Elf32_Word vna_hash; /* Hash value of dependency name */ Elf32_Half vna_flags; /* Dependency specific information */ Elf32_Half vna_other; /* Unused */ Elf32_Word vna_name; /* Dependency name string offset */ Elf32_Word vna_next; /* Offset in bytes to next vernaux entry */ } Elf32_Vernaux; typedef struct { Elf64_Word vna_hash; /* Hash value of dependency name */ Elf64_Half vna_flags; /* Dependency specific information */ Elf64_Half vna_other; /* Unused */ Elf64_Word vna_name; /* Dependency name string offset */ Elf64_Word vna_next; /* Offset in bytes to next vernaux entry */ } Elf64_Vernaux; /* Legal values for vna_flags. */ #define VER_FLG_WEAK 0x2 /* Weak version identifier */ /* Auxiliary vector. */ /* This vector is normally only used by the program interpreter. The usual definition in an ABI supplement uses the name auxv_t. The vector is not usually defined in a standard file, but it can't hurt. We rename it to avoid conflicts. The sizes of these types are an arrangement between the exec server and the program interpreter, so we don't fully specify them here. */ typedef struct { uint32_t a_type; /* Entry type */ union { uint32_t a_val; /* Integer value */ /* We use to have pointer elements added here. We cannot do that, though, since it does not work when using 32-bit definitions on 64-bit platforms and vice versa. */ } a_un; } Elf32_auxv_t; typedef struct { uint64_t a_type; /* Entry type */ union { uint64_t a_val; /* Integer value */ /* We use to have pointer elements added here. We cannot do that, though, since it does not work when using 32-bit definitions on 64-bit platforms and vice versa. */ } a_un; } Elf64_auxv_t; /* Legal values for a_type (entry type). */ #define AT_NULL 0 /* End of vector */ #define AT_IGNORE 1 /* Entry should be ignored */ #define AT_EXECFD 2 /* File descriptor of program */ #define AT_PHDR 3 /* Program headers for program */ #define AT_PHENT 4 /* Size of program header entry */ #define AT_PHNUM 5 /* Number of program headers */ #define AT_PAGESZ 6 /* System page size */ #define AT_BASE 7 /* Base address of interpreter */ #define AT_FLAGS 8 /* Flags */ #define AT_ENTRY 9 /* Entry point of program */ #define AT_NOTELF 10 /* Program is not ELF */ #define AT_UID 11 /* Real uid */ #define AT_EUID 12 /* Effective uid */ #define AT_GID 13 /* Real gid */ #define AT_EGID 14 /* Effective gid */ #define AT_CLKTCK 17 /* Frequency of times() */ /* Some more special a_type values describing the hardware. */ #define AT_PLATFORM 15 /* String identifying platform. */ #define AT_HWCAP \ 16 /* Machine dependent hints about \ processor capabilities. */ /* This entry gives some information about the FPU initialization performed by the kernel. */ #define AT_FPUCW 18 /* Used FPU control word. */ /* Cache block sizes. */ #define AT_DCACHEBSIZE 19 /* Data cache block size. */ #define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ #define AT_UCACHEBSIZE 21 /* Unified cache block size. */ /* A special ignored value for PPC, used by the kernel to control the interpretation of the AUXV. Must be > 16. */ #define AT_IGNOREPPC 22 /* Entry should be ignored. */ #define AT_SECURE 23 /* Boolean, was exec setuid-like? */ #define AT_EXECFN 31 /* Filename of executable. */ /* Pointer to the global system page used for system calls and other nice things. */ #define AT_SYSINFO 32 #define AT_SYSINFO_EHDR 33 /* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains log2 of line size; mask those to get cache size. */ #define AT_L1I_CACHESHAPE 34 #define AT_L1D_CACHESHAPE 35 #define AT_L2_CACHESHAPE 36 #define AT_L3_CACHESHAPE 37 /* Note section contents. Each entry in the note section begins with a header of a fixed form. */ typedef struct { Elf32_Word n_namesz; /* Length of the note's name. */ Elf32_Word n_descsz; /* Length of the note's descriptor. */ Elf32_Word n_type; /* Type of the note. */ } Elf32_Nhdr; typedef struct { Elf64_Word n_namesz; /* Length of the note's name. */ Elf64_Word n_descsz; /* Length of the note's descriptor. */ Elf64_Word n_type; /* Type of the note. */ } Elf64_Nhdr; /* Known names of notes. */ /* Solaris entries in the note section have this name. */ #define ELF_NOTE_SOLARIS "SUNW Solaris" /* Note entries for GNU systems have this name. */ #define ELF_NOTE_GNU "GNU" /* Defined types of notes for Solaris. */ /* Value of descriptor (one word) is desired pagesize for the binary. */ #define ELF_NOTE_PAGESIZE_HINT 1 /* Defined note types for GNU systems. */ /* ABI information. The descriptor consists of words: word 0: OS descriptor word 1: major version of the ABI word 2: minor version of the ABI word 3: subminor version of the ABI */ #define NT_GNU_ABI_TAG 1 #define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ /* Known OSes. These values can appear in word 0 of an NT_GNU_ABI_TAG note section entry. */ #define ELF_NOTE_OS_LINUX 0 #define ELF_NOTE_OS_GNU 1 #define ELF_NOTE_OS_SOLARIS2 2 #define ELF_NOTE_OS_FREEBSD 3 /* Synthetic hwcap information. The descriptor begins with two words: word 0: number of entries word 1: bitmask of enabled entries Then follow variable-length entries, one byte followed by a '\0'-terminated hwcap name string. The byte gives the bit number to test if enabled, (1U << bit) & bitmask. */ #define NT_GNU_HWCAP 2 /* Build ID bits as generated by ld --build-id. The descriptor consists of any nonzero number of bytes. */ #define NT_GNU_BUILD_ID 3 /* Move records. */ typedef struct { Elf32_Xword m_value; /* Symbol value. */ Elf32_Word m_info; /* Size and index. */ Elf32_Word m_poffset; /* Symbol offset. */ Elf32_Half m_repeat; /* Repeat count. */ Elf32_Half m_stride; /* Stride info. */ } Elf32_Move; typedef struct { Elf64_Xword m_value; /* Symbol value. */ Elf64_Xword m_info; /* Size and index. */ Elf64_Xword m_poffset; /* Symbol offset. */ Elf64_Half m_repeat; /* Repeat count. */ Elf64_Half m_stride; /* Stride info. */ } Elf64_Move; /* Macro to construct move records. */ #define ELF32_M_SYM(info) ((info) >> 8) #define ELF32_M_SIZE(info) ((unsigned char)(info)) #define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char)(size)) #define ELF64_M_SYM(info) ELF32_M_SYM(info) #define ELF64_M_SIZE(info) ELF32_M_SIZE(info) #define ELF64_M_INFO(sym, size) ELF32_M_INFO(sym, size) /* Motorola 68k specific definitions. */ /* Values for Elf32_Ehdr.e_flags. */ #define EF_CPU32 0x00810000 /* m68k relocs. */ #define R_68K_NONE 0 /* No reloc */ #define R_68K_32 1 /* Direct 32 bit */ #define R_68K_16 2 /* Direct 16 bit */ #define R_68K_8 3 /* Direct 8 bit */ #define R_68K_PC32 4 /* PC relative 32 bit */ #define R_68K_PC16 5 /* PC relative 16 bit */ #define R_68K_PC8 6 /* PC relative 8 bit */ #define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ #define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ #define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ #define R_68K_GOT32O 10 /* 32 bit GOT offset */ #define R_68K_GOT16O 11 /* 16 bit GOT offset */ #define R_68K_GOT8O 12 /* 8 bit GOT offset */ #define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ #define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ #define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ #define R_68K_PLT32O 16 /* 32 bit PLT offset */ #define R_68K_PLT16O 17 /* 16 bit PLT offset */ #define R_68K_PLT8O 18 /* 8 bit PLT offset */ #define R_68K_COPY 19 /* Copy symbol at runtime */ #define R_68K_GLOB_DAT 20 /* Create GOT entry */ #define R_68K_JMP_SLOT 21 /* Create PLT entry */ #define R_68K_RELATIVE 22 /* Adjust by program base */ /* Keep this the last entry. */ #define R_68K_NUM 23 /* Intel 80386 specific definitions. */ /* i386 relocs. */ #define R_386_NONE 0 /* No reloc */ #define R_386_32 1 /* Direct 32 bit */ #define R_386_PC32 2 /* PC relative 32 bit */ #define R_386_GOT32 3 /* 32 bit GOT entry */ #define R_386_PLT32 4 /* 32 bit PLT address */ #define R_386_COPY 5 /* Copy symbol at runtime */ #define R_386_GLOB_DAT 6 /* Create GOT entry */ #define R_386_JMP_SLOT 7 /* Create PLT entry */ #define R_386_RELATIVE 8 /* Adjust by program base */ #define R_386_GOTOFF 9 /* 32 bit offset to GOT */ #define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ #define R_386_32PLT 11 #define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ #define R_386_TLS_IE \ 15 /* Address of GOT entry for static TLS \ block offset */ #define R_386_TLS_GOTIE \ 16 /* GOT entry for static TLS block \ offset */ #define R_386_TLS_LE \ 17 /* Offset relative to static TLS \ block */ #define R_386_TLS_GD \ 18 /* Direct 32 bit for GNU version of \ general dynamic thread local data */ #define R_386_TLS_LDM \ 19 /* Direct 32 bit for GNU version of \ local dynamic thread local data \ in LE code */ #define R_386_16 20 #define R_386_PC16 21 #define R_386_8 22 #define R_386_PC8 23 #define R_386_TLS_GD_32 \ 24 /* Direct 32 bit for general dynamic \ thread local data */ #define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ #define R_386_TLS_GD_CALL \ 26 /* Relocation for call to \ __tls_get_addr() */ #define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ #define R_386_TLS_LDM_32 \ 28 /* Direct 32 bit for local dynamic \ thread local data in LE code */ #define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ #define R_386_TLS_LDM_CALL \ 30 /* Relocation for call to \ __tls_get_addr() in LDM code */ #define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ #define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ #define R_386_TLS_IE_32 \ 33 /* GOT entry for negated static TLS \ block offset */ #define R_386_TLS_LE_32 \ 34 /* Negated offset relative to static \ TLS block */ #define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ #define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ #define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ /* 38? */ #define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ #define R_386_TLS_DESC_CALL \ 40 /* Marker of call through TLS \ descriptor for \ relaxation. */ #define R_386_TLS_DESC \ 41 /* TLS descriptor containing \ pointer to code and to \ argument, returning the TLS \ offset for the symbol. */ /* Keep this the last entry. */ #define R_386_NUM 42 /* SUN SPARC specific definitions. */ /* Legal values for ST_TYPE subfield of st_info (symbol type). */ #define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ /* Values for Elf64_Ehdr.e_flags. */ #define EF_SPARCV9_MM 3 #define EF_SPARCV9_TSO 0 #define EF_SPARCV9_PSO 1 #define EF_SPARCV9_RMO 2 #define EF_SPARC_LEDATA 0x800000 /* little endian data */ #define EF_SPARC_EXT_MASK 0xFFFF00 #define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ #define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ #define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ #define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ /* SPARC relocs. */ #define R_SPARC_NONE 0 /* No reloc */ #define R_SPARC_8 1 /* Direct 8 bit */ #define R_SPARC_16 2 /* Direct 16 bit */ #define R_SPARC_32 3 /* Direct 32 bit */ #define R_SPARC_DISP8 4 /* PC relative 8 bit */ #define R_SPARC_DISP16 5 /* PC relative 16 bit */ #define R_SPARC_DISP32 6 /* PC relative 32 bit */ #define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ #define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ #define R_SPARC_HI22 9 /* High 22 bit */ #define R_SPARC_22 10 /* Direct 22 bit */ #define R_SPARC_13 11 /* Direct 13 bit */ #define R_SPARC_LO10 12 /* Truncated 10 bit */ #define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ #define R_SPARC_GOT13 14 /* 13 bit GOT entry */ #define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ #define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ #define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ #define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ #define R_SPARC_COPY 19 /* Copy symbol at runtime */ #define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ #define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ #define R_SPARC_RELATIVE 22 /* Adjust by program base */ #define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ /* Additional Sparc64 relocs. */ #define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ #define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ #define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ #define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ #define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ #define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ #define R_SPARC_10 30 /* Direct 10 bit */ #define R_SPARC_11 31 /* Direct 11 bit */ #define R_SPARC_64 32 /* Direct 64 bit */ #define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ #define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ #define R_SPARC_HM10 35 /* High middle 10 bits of ... */ #define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ #define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ #define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ #define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ #define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ #define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ #define R_SPARC_7 43 /* Direct 7 bit */ #define R_SPARC_5 44 /* Direct 5 bit */ #define R_SPARC_6 45 /* Direct 6 bit */ #define R_SPARC_DISP64 46 /* PC relative 64 bit */ #define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ #define R_SPARC_HIX22 48 /* High 22 bit complemented */ #define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ #define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ #define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ #define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ #define R_SPARC_REGISTER 53 /* Global register usage */ #define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ #define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ #define R_SPARC_TLS_GD_HI22 56 #define R_SPARC_TLS_GD_LO10 57 #define R_SPARC_TLS_GD_ADD 58 #define R_SPARC_TLS_GD_CALL 59 #define R_SPARC_TLS_LDM_HI22 60 #define R_SPARC_TLS_LDM_LO10 61 #define R_SPARC_TLS_LDM_ADD 62 #define R_SPARC_TLS_LDM_CALL 63 #define R_SPARC_TLS_LDO_HIX22 64 #define R_SPARC_TLS_LDO_LOX10 65 #define R_SPARC_TLS_LDO_ADD 66 #define R_SPARC_TLS_IE_HI22 67 #define R_SPARC_TLS_IE_LO10 68 #define R_SPARC_TLS_IE_LD 69 #define R_SPARC_TLS_IE_LDX 70 #define R_SPARC_TLS_IE_ADD 71 #define R_SPARC_TLS_LE_HIX22 72 #define R_SPARC_TLS_LE_LOX10 73 #define R_SPARC_TLS_DTPMOD32 74 #define R_SPARC_TLS_DTPMOD64 75 #define R_SPARC_TLS_DTPOFF32 76 #define R_SPARC_TLS_DTPOFF64 77 #define R_SPARC_TLS_TPOFF32 78 #define R_SPARC_TLS_TPOFF64 79 /* Keep this the last entry. */ #define R_SPARC_NUM 80 /* For Sparc64, legal values for d_tag of Elf64_Dyn. */ #define DT_SPARC_REGISTER 0x70000001 #define DT_SPARC_NUM 2 /* Bits present in AT_HWCAP on SPARC. */ #define HWCAP_SPARC_FLUSH 1 /* The CPU supports flush insn. */ #define HWCAP_SPARC_STBAR 2 #define HWCAP_SPARC_SWAP 4 #define HWCAP_SPARC_MULDIV 8 #define HWCAP_SPARC_V9 16 /* The CPU is v9, so v8plus is ok. */ #define HWCAP_SPARC_ULTRA3 32 #define HWCAP_SPARC_BLKINIT 64 /* Sun4v with block-init/load-twin. */ #define HWCAP_SPARC_N2 128 /* MIPS R3000 specific definitions. */ /* Legal values for e_flags field of Elf32_Ehdr. */ #define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ #define EF_MIPS_PIC 2 /* Contains PIC code */ #define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ #define EF_MIPS_XGOT 8 #define EF_MIPS_64BIT_WHIRL 16 #define EF_MIPS_ABI2 32 #define EF_MIPS_ABI_ON32 64 #define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ /* Legal values for MIPS architecture level. */ #define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ #define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ #define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ #define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ #define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ #define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ #define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ /* The following are non-official names and should not be used. */ #define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ #define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ #define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ #define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ #define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ #define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ #define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ /* Special section indices. */ #define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ #define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ #define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ #define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ #define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ /* Legal values for sh_type field of Elf32_Shdr. */ #define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ #define SHT_MIPS_MSYM 0x70000001 #define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ #define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ #define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ #define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ #define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ #define SHT_MIPS_PACKAGE 0x70000007 #define SHT_MIPS_PACKSYM 0x70000008 #define SHT_MIPS_RELD 0x70000009 #define SHT_MIPS_IFACE 0x7000000b #define SHT_MIPS_CONTENT 0x7000000c #define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ #define SHT_MIPS_SHDR 0x70000010 #define SHT_MIPS_FDESC 0x70000011 #define SHT_MIPS_EXTSYM 0x70000012 #define SHT_MIPS_DENSE 0x70000013 #define SHT_MIPS_PDESC 0x70000014 #define SHT_MIPS_LOCSYM 0x70000015 #define SHT_MIPS_AUXSYM 0x70000016 #define SHT_MIPS_OPTSYM 0x70000017 #define SHT_MIPS_LOCSTR 0x70000018 #define SHT_MIPS_LINE 0x70000019 #define SHT_MIPS_RFDESC 0x7000001a #define SHT_MIPS_DELTASYM 0x7000001b #define SHT_MIPS_DELTAINST 0x7000001c #define SHT_MIPS_DELTACLASS 0x7000001d #define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ #define SHT_MIPS_DELTADECL 0x7000001f #define SHT_MIPS_SYMBOL_LIB 0x70000020 #define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ #define SHT_MIPS_TRANSLATE 0x70000022 #define SHT_MIPS_PIXIE 0x70000023 #define SHT_MIPS_XLATE 0x70000024 #define SHT_MIPS_XLATE_DEBUG 0x70000025 #define SHT_MIPS_WHIRL 0x70000026 #define SHT_MIPS_EH_REGION 0x70000027 #define SHT_MIPS_XLATE_OLD 0x70000028 #define SHT_MIPS_PDR_EXCEPTION 0x70000029 /* Legal values for sh_flags field of Elf32_Shdr. */ #define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ #define SHF_MIPS_MERGE 0x20000000 #define SHF_MIPS_ADDR 0x40000000 #define SHF_MIPS_STRINGS 0x80000000 #define SHF_MIPS_NOSTRIP 0x08000000 #define SHF_MIPS_LOCAL 0x04000000 #define SHF_MIPS_NAMES 0x02000000 #define SHF_MIPS_NODUPE 0x01000000 /* Symbol tables. */ /* MIPS specific values for `st_other'. */ #define STO_MIPS_DEFAULT 0x0 #define STO_MIPS_INTERNAL 0x1 #define STO_MIPS_HIDDEN 0x2 #define STO_MIPS_PROTECTED 0x3 #define STO_MIPS_PLT 0x8 #define STO_MIPS_SC_ALIGN_UNUSED 0xff /* MIPS specific values for `st_info'. */ #define STB_MIPS_SPLIT_COMMON 13 /* Entries found in sections of type SHT_MIPS_GPTAB. */ typedef union { struct { Elf32_Word gt_current_g_value; /* -G value used for compilation */ Elf32_Word gt_unused; /* Not used */ } gt_header; /* First entry in section */ struct { Elf32_Word gt_g_value; /* If this value were used for -G */ Elf32_Word gt_bytes; /* This many bytes would be used */ } gt_entry; /* Subsequent entries in section */ } Elf32_gptab; /* Entry found in sections of type SHT_MIPS_REGINFO. */ typedef struct { Elf32_Word ri_gprmask; /* General registers used */ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ Elf32_Sword ri_gp_value; /* $gp register value */ } Elf32_RegInfo; /* Entries found in sections of type SHT_MIPS_OPTIONS. */ typedef struct { unsigned char kind; /* Determines interpretation of the variable part of descriptor. */ unsigned char size; /* Size of descriptor, including header. */ Elf32_Section section; /* Section header index of section affected, 0 for global options. */ Elf32_Word info; /* Kind-specific information. */ } Elf_Options; /* Values for `kind' field in Elf_Options. */ #define ODK_NULL 0 /* Undefined. */ #define ODK_REGINFO 1 /* Register usage information. */ #define ODK_EXCEPTIONS 2 /* Exception processing options. */ #define ODK_PAD 3 /* Section padding options. */ #define ODK_HWPATCH 4 /* Hardware workarounds performed */ #define ODK_FILL 5 /* record the fill value used by the linker. */ #define ODK_TAGS 6 /* reserve space for desktop tools to write. */ #define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ #define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ /* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ #define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ #define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ #define OEX_PAGE0 0x10000 /* page zero must be mapped. */ #define OEX_SMM 0x20000 /* Force sequential memory mode? */ #define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ #define OEX_PRECISEFP OEX_FPDBUG #define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ #define OEX_FPU_INVAL 0x10 #define OEX_FPU_DIV0 0x08 #define OEX_FPU_OFLO 0x04 #define OEX_FPU_UFLO 0x02 #define OEX_FPU_INEX 0x01 /* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ #define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ #define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ #define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ #define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ #define OPAD_PREFIX 0x1 #define OPAD_POSTFIX 0x2 #define OPAD_SYMBOL 0x4 /* Entry found in `.options' section. */ typedef struct { Elf32_Word hwp_flags1; /* Extra flags. */ Elf32_Word hwp_flags2; /* Extra flags. */ } Elf_Options_Hw; /* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ #define OHWA0_R4KEOP_CHECKED 0x00000001 #define OHWA1_R4KEOP_CLEAN 0x00000002 /* MIPS relocs. */ #define R_MIPS_NONE 0 /* No reloc */ #define R_MIPS_16 1 /* Direct 16 bit */ #define R_MIPS_32 2 /* Direct 32 bit */ #define R_MIPS_REL32 3 /* PC relative 32 bit */ #define R_MIPS_26 4 /* Direct 26 bit shifted */ #define R_MIPS_HI16 5 /* High 16 bit */ #define R_MIPS_LO16 6 /* Low 16 bit */ #define R_MIPS_GPREL16 7 /* GP relative 16 bit */ #define R_MIPS_LITERAL 8 /* 16 bit literal entry */ #define R_MIPS_GOT16 9 /* 16 bit GOT entry */ #define R_MIPS_PC16 10 /* PC relative 16 bit */ #define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ #define R_MIPS_GPREL32 12 /* GP relative 32 bit */ #define R_MIPS_SHIFT5 16 #define R_MIPS_SHIFT6 17 #define R_MIPS_64 18 #define R_MIPS_GOT_DISP 19 #define R_MIPS_GOT_PAGE 20 #define R_MIPS_GOT_OFST 21 #define R_MIPS_GOT_HI16 22 #define R_MIPS_GOT_LO16 23 #define R_MIPS_SUB 24 #define R_MIPS_INSERT_A 25 #define R_MIPS_INSERT_B 26 #define R_MIPS_DELETE 27 #define R_MIPS_HIGHER 28 #define R_MIPS_HIGHEST 29 #define R_MIPS_CALL_HI16 30 #define R_MIPS_CALL_LO16 31 #define R_MIPS_SCN_DISP 32 #define R_MIPS_REL16 33 #define R_MIPS_ADD_IMMEDIATE 34 #define R_MIPS_PJUMP 35 #define R_MIPS_RELGOT 36 #define R_MIPS_JALR 37 #define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ #define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ #define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ #define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ #define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ #define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ #define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ #define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ #define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ #define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ #define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ #define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ #define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ #define R_MIPS_GLOB_DAT 51 #define R_MIPS_COPY 126 #define R_MIPS_JUMP_SLOT 127 /* Keep this the last entry. */ #define R_MIPS_NUM 128 /* Legal values for p_type field of Elf32_Phdr. */ #define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ #define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ #define PT_MIPS_OPTIONS 0x70000002 /* Special program header types. */ #define PF_MIPS_LOCAL 0x10000000 /* Legal values for d_tag field of Elf32_Dyn. */ #define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ #define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ #define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ #define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ #define DT_MIPS_FLAGS 0x70000005 /* Flags */ #define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ #define DT_MIPS_MSYM 0x70000007 #define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ #define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ #define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ #define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ #define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ #define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ #define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ #define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ #define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ #define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ #define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ #define DT_MIPS_DELTA_CLASS_NO \ 0x70000018 /* Number of entries in \ DT_MIPS_DELTA_CLASS. */ #define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ #define DT_MIPS_DELTA_INSTANCE_NO \ 0x7000001a /* Number of entries in \ DT_MIPS_DELTA_INSTANCE. */ #define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ #define DT_MIPS_DELTA_RELOC_NO \ 0x7000001c /* Number of entries in \ DT_MIPS_DELTA_RELOC. */ #define DT_MIPS_DELTA_SYM \ 0x7000001d /* Delta symbols that Delta \ relocations refer to. */ #define DT_MIPS_DELTA_SYM_NO \ 0x7000001e /* Number of entries in \ DT_MIPS_DELTA_SYM. */ #define DT_MIPS_DELTA_CLASSSYM \ 0x70000020 /* Delta symbols that hold the \ class declaration. */ #define DT_MIPS_DELTA_CLASSSYM_NO \ 0x70000021 /* Number of entries in \ DT_MIPS_DELTA_CLASSSYM. */ #define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ #define DT_MIPS_PIXIE_INIT 0x70000023 #define DT_MIPS_SYMBOL_LIB 0x70000024 #define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 #define DT_MIPS_LOCAL_GOTIDX 0x70000026 #define DT_MIPS_HIDDEN_GOTIDX 0x70000027 #define DT_MIPS_PROTECTED_GOTIDX 0x70000028 #define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ #define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ #define DT_MIPS_DYNSTR_ALIGN 0x7000002b #define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ #define DT_MIPS_RLD_TEXT_RESOLVE_ADDR \ 0x7000002d /* Address of rld_text_rsolve \ function stored in GOT. */ #define DT_MIPS_PERF_SUFFIX \ 0x7000002e /* Default suffix of dso to be added \ by rld on dlopen() calls. */ #define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ #define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ #define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ /* The address of .got.plt in an executable using the new non-PIC ABI. */ #define DT_MIPS_PLTGOT 0x70000032 /* The base of the PLT in an executable using the new non-PIC ABI if that PLT is writable. For a non-writable PLT, this is omitted or has a zero value. */ #define DT_MIPS_RWPLT 0x70000034 #define DT_MIPS_NUM 0x35 /* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ #define RHF_NONE 0 /* No flags */ #define RHF_QUICKSTART (1 << 0) /* Use quickstart */ #define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ #define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ #define RHF_NO_MOVE (1 << 3) #define RHF_SGI_ONLY (1 << 4) #define RHF_GUARANTEE_INIT (1 << 5) #define RHF_DELTA_C_PLUS_PLUS (1 << 6) #define RHF_GUARANTEE_START_INIT (1 << 7) #define RHF_PIXIE (1 << 8) #define RHF_DEFAULT_DELAY_LOAD (1 << 9) #define RHF_REQUICKSTART (1 << 10) #define RHF_REQUICKSTARTED (1 << 11) #define RHF_CORD (1 << 12) #define RHF_NO_UNRES_UNDEF (1 << 13) #define RHF_RLD_ORDER_SAFE (1 << 14) /* Entries found in sections of type SHT_MIPS_LIBLIST. */ typedef struct { Elf32_Word l_name; /* Name (string table index) */ Elf32_Word l_time_stamp; /* Timestamp */ Elf32_Word l_checksum; /* Checksum */ Elf32_Word l_version; /* Interface version */ Elf32_Word l_flags; /* Flags */ } Elf32_Lib; typedef struct { Elf64_Word l_name; /* Name (string table index) */ Elf64_Word l_time_stamp; /* Timestamp */ Elf64_Word l_checksum; /* Checksum */ Elf64_Word l_version; /* Interface version */ Elf64_Word l_flags; /* Flags */ } Elf64_Lib; /* Legal values for l_flags. */ #define LL_NONE 0 #define LL_EXACT_MATCH (1 << 0) /* Require exact match */ #define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ #define LL_REQUIRE_MINOR (1 << 2) #define LL_EXPORTS (1 << 3) #define LL_DELAY_LOAD (1 << 4) #define LL_DELTA (1 << 5) /* Entries found in sections of type SHT_MIPS_CONFLICT. */ typedef Elf32_Addr Elf32_Conflict; /* HPPA specific definitions. */ /* Legal values for e_flags field of Elf32_Ehdr. */ #define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ #define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ #define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ #define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ #define EF_PARISC_NO_KABP \ 0x00100000 /* No kernel assisted branch \ prediction. */ #define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ #define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ /* Defined values for `e_flags & EF_PARISC_ARCH' are: */ #define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ #define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ #define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ /* Additional section indeces. */ #define SHN_PARISC_ANSI_COMMON \ 0xff00 /* Section for tenatively declared \ symbols in ANSI C. */ #define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ /* Legal values for sh_type field of Elf32_Shdr. */ #define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ #define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ #define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ /* Legal values for sh_flags field of Elf32_Shdr. */ #define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ #define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ #define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ /* Legal values for ST_TYPE subfield of st_info (symbol type). */ #define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ #define STT_HP_OPAQUE (STT_LOOS + 0x1) #define STT_HP_STUB (STT_LOOS + 0x2) /* HPPA relocs. */ #define R_PARISC_NONE 0 /* No reloc. */ #define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ #define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ #define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ #define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ #define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ #define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ #define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ #define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ #define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ #define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ #define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ #define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ #define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ #define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ #define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ #define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ #define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ #define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ #define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ #define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ #define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ #define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ #define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ #define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ #define R_PARISC_FPTR64 64 /* 64 bits function address. */ #define R_PARISC_PLABEL32 65 /* 32 bits function address. */ #define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ #define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ #define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ #define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ #define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ #define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ #define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ #define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ #define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ #define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ #define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ #define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ #define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ #define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ #define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ #define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ #define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ #define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ #define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ #define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ #define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ #define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ #define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ #define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ #define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ #define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ #define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ #define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ #define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ #define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ #define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ #define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ #define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ #define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ #define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ #define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ #define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ #define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ #define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ #define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ #define R_PARISC_LORESERVE 128 #define R_PARISC_COPY 128 /* Copy relocation. */ #define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ #define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ #define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ #define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ #define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ #define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ #define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ #define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ #define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ #define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ #define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ #define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ #define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ #define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ #define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ #define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ #define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ #define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ #define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ #define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ #define R_PARISC_GNU_VTENTRY 232 #define R_PARISC_GNU_VTINHERIT 233 #define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ #define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ #define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ #define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ #define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ #define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ #define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ #define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ #define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ #define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ #define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ #define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ #define R_PARISC_TLS_LE21L R_PARISC_TPREL21L #define R_PARISC_TLS_LE14R R_PARISC_TPREL14R #define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L #define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R #define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 #define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 #define R_PARISC_HIRESERVE 255 /* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ #define PT_HP_TLS (PT_LOOS + 0x0) #define PT_HP_CORE_NONE (PT_LOOS + 0x1) #define PT_HP_CORE_VERSION (PT_LOOS + 0x2) #define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) #define PT_HP_CORE_COMM (PT_LOOS + 0x4) #define PT_HP_CORE_PROC (PT_LOOS + 0x5) #define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) #define PT_HP_CORE_STACK (PT_LOOS + 0x7) #define PT_HP_CORE_SHM (PT_LOOS + 0x8) #define PT_HP_CORE_MMF (PT_LOOS + 0x9) #define PT_HP_PARALLEL (PT_LOOS + 0x10) #define PT_HP_FASTBIND (PT_LOOS + 0x11) #define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) #define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) #define PT_HP_STACK (PT_LOOS + 0x14) #define PT_PARISC_ARCHEXT 0x70000000 #define PT_PARISC_UNWIND 0x70000001 /* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ #define PF_PARISC_SBP 0x08000000 #define PF_HP_PAGE_SIZE 0x00100000 #define PF_HP_FAR_SHARED 0x00200000 #define PF_HP_NEAR_SHARED 0x00400000 #define PF_HP_CODE 0x01000000 #define PF_HP_MODIFY 0x02000000 #define PF_HP_LAZYSWAP 0x04000000 #define PF_HP_SBP 0x08000000 /* Alpha specific definitions. */ /* Legal values for e_flags field of Elf64_Ehdr. */ #define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ #define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ /* Legal values for sh_type field of Elf64_Shdr. */ /* These two are primerily concerned with ECOFF debugging info. */ #define SHT_ALPHA_DEBUG 0x70000001 #define SHT_ALPHA_REGINFO 0x70000002 /* Legal values for sh_flags field of Elf64_Shdr. */ #define SHF_ALPHA_GPREL 0x10000000 /* Legal values for st_other field of Elf64_Sym. */ #define STO_ALPHA_NOPV 0x80 /* No PV required. */ #define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ /* Alpha relocs. */ #define R_ALPHA_NONE 0 /* No reloc */ #define R_ALPHA_REFLONG 1 /* Direct 32 bit */ #define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ #define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ #define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ #define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ #define R_ALPHA_GPDISP 6 /* Add displacement to GP */ #define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ #define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ #define R_ALPHA_SREL16 9 /* PC relative 16 bit */ #define R_ALPHA_SREL32 10 /* PC relative 32 bit */ #define R_ALPHA_SREL64 11 /* PC relative 64 bit */ #define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ #define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ #define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ #define R_ALPHA_COPY 24 /* Copy symbol at runtime */ #define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ #define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ #define R_ALPHA_RELATIVE 27 /* Adjust by program base */ #define R_ALPHA_TLS_GD_HI 28 #define R_ALPHA_TLSGD 29 #define R_ALPHA_TLS_LDM 30 #define R_ALPHA_DTPMOD64 31 #define R_ALPHA_GOTDTPREL 32 #define R_ALPHA_DTPREL64 33 #define R_ALPHA_DTPRELHI 34 #define R_ALPHA_DTPRELLO 35 #define R_ALPHA_DTPREL16 36 #define R_ALPHA_GOTTPREL 37 #define R_ALPHA_TPREL64 38 #define R_ALPHA_TPRELHI 39 #define R_ALPHA_TPRELLO 40 #define R_ALPHA_TPREL16 41 /* Keep this the last entry. */ #define R_ALPHA_NUM 46 /* Magic values of the LITUSE relocation addend. */ #define LITUSE_ALPHA_ADDR 0 #define LITUSE_ALPHA_BASE 1 #define LITUSE_ALPHA_BYTOFF 2 #define LITUSE_ALPHA_JSR 3 #define LITUSE_ALPHA_TLS_GD 4 #define LITUSE_ALPHA_TLS_LDM 5 /* Legal values for d_tag of Elf64_Dyn. */ #define DT_ALPHA_PLTRO (DT_LOPROC + 0) #define DT_ALPHA_NUM 1 /* PowerPC specific declarations */ /* Values for Elf32/64_Ehdr.e_flags. */ #define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ /* Cygnus local bits below */ #define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ #define EF_PPC_RELOCATABLE_LIB \ 0x00008000 /* PowerPC -mrelocatable-lib \ flag */ /* PowerPC relocations defined by the ABIs */ #define R_PPC_NONE 0 #define R_PPC_ADDR32 1 /* 32bit absolute address */ #define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ #define R_PPC_ADDR16 3 /* 16bit absolute address */ #define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ #define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ #define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ #define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ #define R_PPC_ADDR14_BRTAKEN 8 #define R_PPC_ADDR14_BRNTAKEN 9 #define R_PPC_REL24 10 /* PC relative 26 bit */ #define R_PPC_REL14 11 /* PC relative 16 bit */ #define R_PPC_REL14_BRTAKEN 12 #define R_PPC_REL14_BRNTAKEN 13 #define R_PPC_GOT16 14 #define R_PPC_GOT16_LO 15 #define R_PPC_GOT16_HI 16 #define R_PPC_GOT16_HA 17 #define R_PPC_PLTREL24 18 #define R_PPC_COPY 19 #define R_PPC_GLOB_DAT 20 #define R_PPC_JMP_SLOT 21 #define R_PPC_RELATIVE 22 #define R_PPC_LOCAL24PC 23 #define R_PPC_UADDR32 24 #define R_PPC_UADDR16 25 #define R_PPC_REL32 26 #define R_PPC_PLT32 27 #define R_PPC_PLTREL32 28 #define R_PPC_PLT16_LO 29 #define R_PPC_PLT16_HI 30 #define R_PPC_PLT16_HA 31 #define R_PPC_SDAREL16 32 #define R_PPC_SECTOFF 33 #define R_PPC_SECTOFF_LO 34 #define R_PPC_SECTOFF_HI 35 #define R_PPC_SECTOFF_HA 36 /* PowerPC relocations defined for the TLS access ABI. */ #define R_PPC_TLS 67 /* none (sym+add)@tls */ #define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ #define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ #define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ #define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ #define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ #define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ #define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ #define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ #define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ #define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ #define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ #define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ #define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ #define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ #define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ #define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ #define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ #define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ #define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ #define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ #define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ #define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ #define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ #define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ #define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ #define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ #define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ /* Keep this the last entry. */ #define R_PPC_NUM 95 /* The remaining relocs are from the Embedded ELF ABI, and are not in the SVR4 ELF ABI. */ #define R_PPC_EMB_NADDR32 101 #define R_PPC_EMB_NADDR16 102 #define R_PPC_EMB_NADDR16_LO 103 #define R_PPC_EMB_NADDR16_HI 104 #define R_PPC_EMB_NADDR16_HA 105 #define R_PPC_EMB_SDAI16 106 #define R_PPC_EMB_SDA2I16 107 #define R_PPC_EMB_SDA2REL 108 #define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ #define R_PPC_EMB_MRKREF 110 #define R_PPC_EMB_RELSEC16 111 #define R_PPC_EMB_RELST_LO 112 #define R_PPC_EMB_RELST_HI 113 #define R_PPC_EMB_RELST_HA 114 #define R_PPC_EMB_BIT_FLD 115 #define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ /* Diab tool relocations. */ #define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ #define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ #define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ #define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ #define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ #define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ /* GNU relocs used in PIC code sequences. */ #define R_PPC_REL16 249 /* word32 (sym-.) */ #define R_PPC_REL16_LO 250 /* half16 (sym-.)@l */ #define R_PPC_REL16_HI 251 /* half16 (sym-.)@h */ #define R_PPC_REL16_HA 252 /* half16 (sym-.)@ha */ /* This is a phony reloc to handle any old fashioned TOC16 references that may still be in object files. */ #define R_PPC_TOC16 255 /* PowerPC specific values for the Dyn d_tag field. */ #define DT_PPC_GOT (DT_LOPROC + 0) #define DT_PPC_NUM 1 /* PowerPC64 relocations defined by the ABIs */ #define R_PPC64_NONE R_PPC_NONE #define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ #define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ #define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ #define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ #define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ #define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ #define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ #define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN #define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN #define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ #define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ #define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN #define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN #define R_PPC64_GOT16 R_PPC_GOT16 #define R_PPC64_GOT16_LO R_PPC_GOT16_LO #define R_PPC64_GOT16_HI R_PPC_GOT16_HI #define R_PPC64_GOT16_HA R_PPC_GOT16_HA #define R_PPC64_COPY R_PPC_COPY #define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT #define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT #define R_PPC64_RELATIVE R_PPC_RELATIVE #define R_PPC64_UADDR32 R_PPC_UADDR32 #define R_PPC64_UADDR16 R_PPC_UADDR16 #define R_PPC64_REL32 R_PPC_REL32 #define R_PPC64_PLT32 R_PPC_PLT32 #define R_PPC64_PLTREL32 R_PPC_PLTREL32 #define R_PPC64_PLT16_LO R_PPC_PLT16_LO #define R_PPC64_PLT16_HI R_PPC_PLT16_HI #define R_PPC64_PLT16_HA R_PPC_PLT16_HA #define R_PPC64_SECTOFF R_PPC_SECTOFF #define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO #define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI #define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA #define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ #define R_PPC64_ADDR64 38 /* doubleword64 S + A */ #define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ #define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ #define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ #define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ #define R_PPC64_UADDR64 43 /* doubleword64 S + A */ #define R_PPC64_REL64 44 /* doubleword64 S + A - P */ #define R_PPC64_PLT64 45 /* doubleword64 L + A */ #define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ #define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ #define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ #define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ #define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ #define R_PPC64_TOC 51 /* doubleword64 .TOC */ #define R_PPC64_PLTGOT16 52 /* half16* M + A */ #define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ #define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ #define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ #define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ #define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ #define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ #define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ #define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ #define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ #define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ #define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ #define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ #define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ #define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ /* PowerPC64 relocations defined for the TLS access ABI. */ #define R_PPC64_TLS 67 /* none (sym+add)@tls */ #define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ #define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ #define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ #define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ #define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ #define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ #define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ #define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ #define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ #define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ #define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ #define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ #define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ #define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ #define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ #define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ #define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ #define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ #define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ #define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ #define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ #define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ #define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ #define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ #define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ #define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ #define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ #define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ #define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ #define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ #define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ #define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ #define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ #define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ #define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ #define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ #define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ #define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ #define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ /* Keep this the last entry. */ #define R_PPC64_NUM 107 /* PowerPC64 specific values for the Dyn d_tag field. */ #define DT_PPC64_GLINK (DT_LOPROC + 0) #define DT_PPC64_OPD (DT_LOPROC + 1) #define DT_PPC64_OPDSZ (DT_LOPROC + 2) #define DT_PPC64_NUM 3 /* ARM specific declarations */ /* Processor specific flags for the ELF header e_flags field. */ #define EF_ARM_RELEXEC 0x01 #define EF_ARM_HASENTRY 0x02 #define EF_ARM_INTERWORK 0x04 #define EF_ARM_APCS_26 0x08 #define EF_ARM_APCS_FLOAT 0x10 #define EF_ARM_PIC 0x20 #define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ #define EF_ARM_NEW_ABI 0x80 #define EF_ARM_OLD_ABI 0x100 /* Other constants defined in the ARM ELF spec. version B-01. */ /* NB. These conflict with values defined above. */ #define EF_ARM_SYMSARESORTED 0x04 #define EF_ARM_DYNSYMSUSESEGIDX 0x08 #define EF_ARM_MAPSYMSFIRST 0x10 #define EF_ARM_EABIMASK 0XFF000000 #define EF_ARM_EABI_VERSION(flags) ((flags)&EF_ARM_EABIMASK) #define EF_ARM_EABI_UNKNOWN 0x00000000 #define EF_ARM_EABI_VER1 0x01000000 #define EF_ARM_EABI_VER2 0x02000000 /* Additional symbol types for Thumb */ #define STT_ARM_TFUNC 0xd /* ARM-specific values for sh_flags */ #define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ #define SHF_ARM_COMDEF \ 0x80000000 /* Section may be multiply defined \ in the input to a link step */ /* ARM-specific program header flags */ #define PF_ARM_SB \ 0x10000000 /* Segment contains the location \ addressed by the static base */ /* Processor specific values for the Phdr p_type field. */ #define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */ /* ARM relocs. */ #define R_ARM_NONE 0 /* No reloc */ #define R_ARM_PC24 1 /* PC relative 26 bit branch */ #define R_ARM_ABS32 2 /* Direct 32 bit */ #define R_ARM_REL32 3 /* PC relative 32 bit */ #define R_ARM_PC13 4 #define R_ARM_ABS16 5 /* Direct 16 bit */ #define R_ARM_ABS12 6 /* Direct 12 bit */ #define R_ARM_THM_ABS5 7 #define R_ARM_ABS8 8 /* Direct 8 bit */ #define R_ARM_SBREL32 9 #define R_ARM_THM_PC22 10 #define R_ARM_THM_PC8 11 #define R_ARM_AMP_VCALL9 12 #define R_ARM_SWI24 13 #define R_ARM_THM_SWI8 14 #define R_ARM_XPC25 15 #define R_ARM_THM_XPC22 16 #define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ #define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ #define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ #define R_ARM_COPY 20 /* Copy symbol at runtime */ #define R_ARM_GLOB_DAT 21 /* Create GOT entry */ #define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ #define R_ARM_RELATIVE 23 /* Adjust by program base */ #define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ #define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ #define R_ARM_GOT32 26 /* 32 bit GOT entry */ #define R_ARM_PLT32 27 /* 32 bit PLT address */ #define R_ARM_ALU_PCREL_7_0 32 #define R_ARM_ALU_PCREL_15_8 33 #define R_ARM_ALU_PCREL_23_15 34 #define R_ARM_LDR_SBREL_11_0 35 #define R_ARM_ALU_SBREL_19_12 36 #define R_ARM_ALU_SBREL_27_20 37 #define R_ARM_GNU_VTENTRY 100 #define R_ARM_GNU_VTINHERIT 101 #define R_ARM_THM_PC11 102 /* thumb unconditional branch */ #define R_ARM_THM_PC9 103 /* thumb conditional branch */ #define R_ARM_TLS_GD32 \ 104 /* PC-rel 32 bit for global dynamic \ thread local data */ #define R_ARM_TLS_LDM32 \ 105 /* PC-rel 32 bit for local dynamic \ thread local data */ #define R_ARM_TLS_LDO32 \ 106 /* 32 bit offset relative to TLS \ block */ #define R_ARM_TLS_IE32 \ 107 /* PC-rel 32 bit for GOT entry of \ static TLS block offset */ #define R_ARM_TLS_LE32 \ 108 /* 32 bit offset relative to static \ TLS block */ #define R_ARM_RXPC25 249 #define R_ARM_RSBREL32 250 #define R_ARM_THM_RPC22 251 #define R_ARM_RREL32 252 #define R_ARM_RABS22 253 #define R_ARM_RPC24 254 #define R_ARM_RBASE 255 /* Keep this the last entry. */ #define R_ARM_NUM 256 /* IA-64 specific declarations. */ /* Processor specific flags for the Ehdr e_flags field. */ #define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ #define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ #define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ /* Processor specific values for the Phdr p_type field. */ #define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ #define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ #define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) #define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) #define PT_IA_64_HP_STACK (PT_LOOS + 0x14) /* Processor specific flags for the Phdr p_flags field. */ #define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ /* Processor specific values for the Shdr sh_type field. */ #define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ #define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ /* Processor specific flags for the Shdr sh_flags field. */ #define SHF_IA_64_SHORT 0x10000000 /* section near gp */ #define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ /* Processor specific values for the Dyn d_tag field. */ #define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) #define DT_IA_64_NUM 1 /* IA-64 relocations. */ #define R_IA64_NONE 0x00 /* none */ #define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ #define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ #define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ #define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ #define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ #define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ #define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ #define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ #define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ #define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ #define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ #define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ #define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ #define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ #define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ #define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ #define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ #define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ #define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ #define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ #define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ #define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ #define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ #define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ #define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ #define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ #define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ #define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ #define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ #define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ #define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ #define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ #define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ #define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ #define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ #define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ #define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ #define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ #define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ #define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ #define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ #define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ #define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ #define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ #define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ #define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ #define R_IA64_REL32MSB 0x6c /* data 4 + REL */ #define R_IA64_REL32LSB 0x6d /* data 4 + REL */ #define R_IA64_REL64MSB 0x6e /* data 8 + REL */ #define R_IA64_REL64LSB 0x6f /* data 8 + REL */ #define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ #define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ #define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ #define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ #define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ #define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ #define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ #define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ #define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ #define R_IA64_COPY 0x84 /* copy relocation */ #define R_IA64_SUB 0x85 /* Addend and symbol difference */ #define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ #define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ #define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ #define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ #define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ #define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ #define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ #define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ #define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ #define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ #define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ #define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ #define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ #define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ #define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ #define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ #define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ #define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ #define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ /* SH specific declarations */ /* SH relocs. */ #define R_SH_NONE 0 #define R_SH_DIR32 1 #define R_SH_REL32 2 #define R_SH_DIR8WPN 3 #define R_SH_IND12W 4 #define R_SH_DIR8WPL 5 #define R_SH_DIR8WPZ 6 #define R_SH_DIR8BP 7 #define R_SH_DIR8W 8 #define R_SH_DIR8L 9 #define R_SH_SWITCH16 25 #define R_SH_SWITCH32 26 #define R_SH_USES 27 #define R_SH_COUNT 28 #define R_SH_ALIGN 29 #define R_SH_CODE 30 #define R_SH_DATA 31 #define R_SH_LABEL 32 #define R_SH_SWITCH8 33 #define R_SH_GNU_VTINHERIT 34 #define R_SH_GNU_VTENTRY 35 #define R_SH_TLS_GD_32 144 #define R_SH_TLS_LD_32 145 #define R_SH_TLS_LDO_32 146 #define R_SH_TLS_IE_32 147 #define R_SH_TLS_LE_32 148 #define R_SH_TLS_DTPMOD32 149 #define R_SH_TLS_DTPOFF32 150 #define R_SH_TLS_TPOFF32 151 #define R_SH_GOT32 160 #define R_SH_PLT32 161 #define R_SH_COPY 162 #define R_SH_GLOB_DAT 163 #define R_SH_JMP_SLOT 164 #define R_SH_RELATIVE 165 #define R_SH_GOTOFF 166 #define R_SH_GOTPC 167 /* Keep this the last entry. */ #define R_SH_NUM 256 /* Additional s390 relocs */ #define R_390_NONE 0 /* No reloc. */ #define R_390_8 1 /* Direct 8 bit. */ #define R_390_12 2 /* Direct 12 bit. */ #define R_390_16 3 /* Direct 16 bit. */ #define R_390_32 4 /* Direct 32 bit. */ #define R_390_PC32 5 /* PC relative 32 bit. */ #define R_390_GOT12 6 /* 12 bit GOT offset. */ #define R_390_GOT32 7 /* 32 bit GOT offset. */ #define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ #define R_390_COPY 9 /* Copy symbol at runtime. */ #define R_390_GLOB_DAT 10 /* Create GOT entry. */ #define R_390_JMP_SLOT 11 /* Create PLT entry. */ #define R_390_RELATIVE 12 /* Adjust by program base. */ #define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ #define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ #define R_390_GOT16 15 /* 16 bit GOT offset. */ #define R_390_PC16 16 /* PC relative 16 bit. */ #define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ #define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ #define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ #define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ #define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ #define R_390_64 22 /* Direct 64 bit. */ #define R_390_PC64 23 /* PC relative 64 bit. */ #define R_390_GOT64 24 /* 64 bit GOT offset. */ #define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ #define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ #define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ #define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ #define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ #define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ #define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ #define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ #define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ #define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ #define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ #define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ #define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ #define R_390_TLS_GDCALL \ 38 /* Tag for function call in general \ dynamic TLS code. */ #define R_390_TLS_LDCALL \ 39 /* Tag for function call in local \ dynamic TLS code. */ #define R_390_TLS_GD32 \ 40 /* Direct 32 bit for general dynamic \ thread local data. */ #define R_390_TLS_GD64 \ 41 /* Direct 64 bit for general dynamic \ thread local data. */ #define R_390_TLS_GOTIE12 \ 42 /* 12 bit GOT offset for static TLS \ block offset. */ #define R_390_TLS_GOTIE32 \ 43 /* 32 bit GOT offset for static TLS \ block offset. */ #define R_390_TLS_GOTIE64 \ 44 /* 64 bit GOT offset for static TLS \ block offset. */ #define R_390_TLS_LDM32 \ 45 /* Direct 32 bit for local dynamic \ thread local data in LE code. */ #define R_390_TLS_LDM64 \ 46 /* Direct 64 bit for local dynamic \ thread local data in LE code. */ #define R_390_TLS_IE32 \ 47 /* 32 bit address of GOT entry for \ negated static TLS block offset. */ #define R_390_TLS_IE64 \ 48 /* 64 bit address of GOT entry for \ negated static TLS block offset. */ #define R_390_TLS_IEENT \ 49 /* 32 bit rel. offset to GOT entry for \ negated static TLS block offset. */ #define R_390_TLS_LE32 \ 50 /* 32 bit negated offset relative to \ static TLS block. */ #define R_390_TLS_LE64 \ 51 /* 64 bit negated offset relative to \ static TLS block. */ #define R_390_TLS_LDO32 \ 52 /* 32 bit offset relative to TLS \ block. */ #define R_390_TLS_LDO64 \ 53 /* 64 bit offset relative to TLS \ block. */ #define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ #define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ #define R_390_TLS_TPOFF \ 56 /* Negated offset in static TLS \ block. */ #define R_390_20 57 /* Direct 20 bit. */ #define R_390_GOT20 58 /* 20 bit GOT offset. */ #define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ #define R_390_TLS_GOTIE20 \ 60 /* 20 bit GOT offset for static TLS \ block offset. */ /* Keep this the last entry. */ #define R_390_NUM 61 /* CRIS relocations. */ #define R_CRIS_NONE 0 #define R_CRIS_8 1 #define R_CRIS_16 2 #define R_CRIS_32 3 #define R_CRIS_8_PCREL 4 #define R_CRIS_16_PCREL 5 #define R_CRIS_32_PCREL 6 #define R_CRIS_GNU_VTINHERIT 7 #define R_CRIS_GNU_VTENTRY 8 #define R_CRIS_COPY 9 #define R_CRIS_GLOB_DAT 10 #define R_CRIS_JUMP_SLOT 11 #define R_CRIS_RELATIVE 12 #define R_CRIS_16_GOT 13 #define R_CRIS_32_GOT 14 #define R_CRIS_16_GOTPLT 15 #define R_CRIS_32_GOTPLT 16 #define R_CRIS_32_GOTREL 17 #define R_CRIS_32_PLT_GOTREL 18 #define R_CRIS_32_PLT_PCREL 19 #define R_CRIS_NUM 20 /* AMD x86-64 relocations. */ #define R_X86_64_NONE 0 /* No reloc */ #define R_X86_64_64 1 /* Direct 64 bit */ #define R_X86_64_PC32 2 /* PC relative 32 bit signed */ #define R_X86_64_GOT32 3 /* 32 bit GOT entry */ #define R_X86_64_PLT32 4 /* 32 bit PLT address */ #define R_X86_64_COPY 5 /* Copy symbol at runtime */ #define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ #define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ #define R_X86_64_RELATIVE 8 /* Adjust by program base */ #define R_X86_64_GOTPCREL \ 9 /* 32 bit signed PC relative \ offset to GOT */ #define R_X86_64_32 10 /* Direct 32 bit zero extended */ #define R_X86_64_32S 11 /* Direct 32 bit sign extended */ #define R_X86_64_16 12 /* Direct 16 bit zero extended */ #define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ #define R_X86_64_8 14 /* Direct 8 bit sign extended */ #define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ #define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ #define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ #define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ #define R_X86_64_TLSGD \ 19 /* 32 bit signed PC relative offset \ to two GOT entries for GD symbol */ #define R_X86_64_TLSLD \ 20 /* 32 bit signed PC relative offset \ to two GOT entries for LD symbol */ #define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ #define R_X86_64_GOTTPOFF \ 22 /* 32 bit signed PC relative offset \ to GOT entry for IE symbol */ #define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ #define R_X86_64_PC64 24 /* PC relative 64 bit */ #define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ #define R_X86_64_GOTPC32 \ 26 /* 32 bit signed pc relative \ offset to GOT */ /* 27 .. 33 */ #define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ #define R_X86_64_TLSDESC_CALL \ 35 /* Marker for call through TLS \ descriptor. */ #define R_X86_64_TLSDESC 36 /* TLS descriptor. */ #define R_X86_64_NUM 37 /* AM33 relocations. */ #define R_MN10300_NONE 0 /* No reloc. */ #define R_MN10300_32 1 /* Direct 32 bit. */ #define R_MN10300_16 2 /* Direct 16 bit. */ #define R_MN10300_8 3 /* Direct 8 bit. */ #define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ #define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ #define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ #define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ #define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ #define R_MN10300_24 9 /* Direct 24 bit. */ #define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ #define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ #define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ #define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ #define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ #define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ #define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ #define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ #define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ #define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ #define R_MN10300_COPY 20 /* Copy symbol at runtime. */ #define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ #define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ #define R_MN10300_RELATIVE 23 /* Adjust by program base. */ #define R_MN10300_NUM 24 /* M32R relocs. */ #define R_M32R_NONE 0 /* No reloc. */ #define R_M32R_16 1 /* Direct 16 bit. */ #define R_M32R_32 2 /* Direct 32 bit. */ #define R_M32R_24 3 /* Direct 24 bit. */ #define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ #define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ #define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ #define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ #define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ #define R_M32R_LO16 9 /* Low 16 bit. */ #define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ #define R_M32R_GNU_VTINHERIT 11 #define R_M32R_GNU_VTENTRY 12 /* M32R relocs use SHT_RELA. */ #define R_M32R_16_RELA 33 /* Direct 16 bit. */ #define R_M32R_32_RELA 34 /* Direct 32 bit. */ #define R_M32R_24_RELA 35 /* Direct 24 bit. */ #define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ #define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ #define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ #define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ #define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ #define R_M32R_LO16_RELA 41 /* Low 16 bit */ #define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ #define R_M32R_RELA_GNU_VTINHERIT 43 #define R_M32R_RELA_GNU_VTENTRY 44 #define R_M32R_REL32 45 /* PC relative 32 bit. */ #define R_M32R_GOT24 48 /* 24 bit GOT entry */ #define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ #define R_M32R_COPY 50 /* Copy symbol at runtime */ #define R_M32R_GLOB_DAT 51 /* Create GOT entry */ #define R_M32R_JMP_SLOT 52 /* Create PLT entry */ #define R_M32R_RELATIVE 53 /* Adjust by program base */ #define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ #define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ #define R_M32R_GOT16_HI_ULO \ 56 /* High 16 bit GOT entry with unsigned \ low */ #define R_M32R_GOT16_HI_SLO \ 57 /* High 16 bit GOT entry with signed \ low */ #define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ #define R_M32R_GOTPC_HI_ULO \ 59 /* High 16 bit PC relative offset to \ GOT with unsigned low */ #define R_M32R_GOTPC_HI_SLO \ 60 /* High 16 bit PC relative offset to \ GOT with signed low */ #define R_M32R_GOTPC_LO \ 61 /* Low 16 bit PC relative offset to \ GOT */ #define R_M32R_GOTOFF_HI_ULO \ 62 /* High 16 bit offset to GOT \ with unsigned low */ #define R_M32R_GOTOFF_HI_SLO \ 63 /* High 16 bit offset to GOT \ with signed low */ #define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ #define R_M32R_NUM 256 /* Keep this the last entry. */ #endif /* elf.h */ ================================================ FILE: buildutils/patchelf/patchelf.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "elf.h" using namespace std; #ifdef MIPSEL /* The lemote fuloong 2f kernel defconfig sets a page size of 16KB */ const unsigned int pageSize = 4096 * 4; #else const unsigned int pageSize = 4096; #endif static bool debugMode = false; static bool forceRPath = false; static string fileName; off_t fileSize, maxSize; unsigned char *contents = 0; #define ElfFileParams class Elf_Ehdr, class Elf_Phdr, class Elf_Shdr, class Elf_Addr, class Elf_Off, class Elf_Dyn, class Elf_Sym #define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym template class ElfFile { Elf_Ehdr * hdr; vector phdrs; vector shdrs; bool littleEndian; bool changed; bool isExecutable; typedef string SectionName; typedef map ReplacedSections; ReplacedSections replacedSections; string sectionNames; /* content of the .shstrtab section */ /* Align on 4 or 8 bytes boundaries on 32- or 64-bit platforms respectively. */ unsigned int sectionAlignment; vector sectionsByOldIndex; public: ElfFile() { changed = false; sectionAlignment = sizeof(Elf_Off); } bool isChanged() { return changed; } void parse(); private: struct CompPhdr { ElfFile *elfFile; bool operator()(const Elf_Phdr &x, const Elf_Phdr &y) { if (x.p_type == PT_PHDR) return true; if (y.p_type == PT_PHDR) return false; return elfFile->rdi(x.p_paddr) < elfFile->rdi(y.p_paddr); } }; friend struct CompPhdr; void sortPhdrs(); struct CompShdr { ElfFile *elfFile; bool operator()(const Elf_Shdr &x, const Elf_Shdr &y) { return elfFile->rdi(x.sh_offset) < elfFile->rdi(y.sh_offset); } }; friend struct CompShdr; void sortShdrs(); void shiftFile(unsigned int extraPages, Elf_Addr startPage); string getSectionName(const Elf_Shdr &shdr); Elf_Shdr &findSection(const SectionName §ionName); Elf_Shdr *findSection2(const SectionName §ionName); unsigned int findSection3(const SectionName §ionName); string &replaceSection(const SectionName §ionName, unsigned int size); void writeReplacedSections(Elf_Off &curOff, Elf_Addr startAddr, Elf_Off startOffset); void rewriteHeaders(Elf_Addr phdrAddress); void rewriteSectionsLibrary(); void rewriteSectionsExecutable(); public: void rewriteSections(); string getInterpreter(); void setInterpreter(const string &newInterpreter); typedef enum { rpPrint, rpShrink, rpSet } RPathOp; void modifyRPath(RPathOp op, string newRPath); void removeNeeded(set libs); private: /* Convert an integer in big or little endian representation (as specified by the ELF header) to this platform's integer representation. */ template I rdi(I i); /* Convert back to the ELF representation. */ template I wri(I &t, unsigned long long i) { t = rdi((I)i); return i; } }; /* !!! G++ creates broken code if this function is inlined, don't know why... */ template template I ElfFile::rdi(I i) { I r = 0; if (littleEndian) { for (unsigned int n = 0; n < sizeof(I); ++n) { r |= ((I) * (((unsigned char *)&i) + n)) << (n * 8); } } else { for (unsigned int n = 0; n < sizeof(I); ++n) { r |= ((I) * (((unsigned char *)&i) + n)) << ((sizeof(I) - n - 1) * 8); } } return r; } /* Ugly: used to erase DT_RUNPATH when using --force-rpath. */ #define DT_IGNORE 0x00726e67 static void debug(const char *format, ...) { if (debugMode) { va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); } } static void error(string msg) { if (errno) perror(msg.c_str()); else fprintf(stderr, "%s\n", msg.c_str()); exit(1); } static void growFile(off_t newSize) { if (newSize > maxSize) error("maximum file size exceeded"); if (newSize <= fileSize) return; if (newSize > fileSize) memset(contents + fileSize, 0, newSize - fileSize); fileSize = newSize; } static void readFile(string fileName, mode_t *fileMode) { struct stat st; if (stat(fileName.c_str(), &st) != 0) error("stat"); fileSize = st.st_size; *fileMode = st.st_mode; maxSize = fileSize + 8 * 1024 * 1024; contents = (unsigned char *)malloc(fileSize + maxSize); if (!contents) abort(); int fd = open(fileName.c_str(), O_RDONLY); if (fd == -1) error("open"); if (read(fd, contents, fileSize) != fileSize) error("read"); close(fd); } static void checkPointer(void *p, unsigned int size) { unsigned char *q = (unsigned char *)p; assert(q >= contents && q + size <= contents + fileSize); } template void ElfFile::parse() { isExecutable = false; /* Check the ELF header for basic validity. */ if (fileSize < (off_t)sizeof(Elf_Ehdr)) error("missing ELF header"); hdr = (Elf_Ehdr *)contents; if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0) error("not an ELF executable"); littleEndian = contents[EI_DATA] == ELFDATA2LSB; if (rdi(hdr->e_type) != ET_EXEC && rdi(hdr->e_type) != ET_DYN) error("wrong ELF type"); if ((off_t)(rdi(hdr->e_phoff) + rdi(hdr->e_phnum) * rdi(hdr->e_phentsize)) > fileSize) error("missing program headers"); if ((off_t)(rdi(hdr->e_shoff) + rdi(hdr->e_shnum) * rdi(hdr->e_shentsize)) > fileSize) error("missing section headers"); if (rdi(hdr->e_phentsize) != sizeof(Elf_Phdr)) error("program headers have wrong size"); /* Copy the program and section headers. */ for (int i = 0; i < rdi(hdr->e_phnum); ++i) { phdrs.push_back(*((Elf_Phdr *)(contents + rdi(hdr->e_phoff)) + i)); if (rdi(phdrs[i].p_type) == PT_INTERP) isExecutable = true; } for (int i = 0; i < rdi(hdr->e_shnum); ++i) shdrs.push_back(*((Elf_Shdr *)(contents + rdi(hdr->e_shoff)) + i)); /* Get the section header string table section (".shstrtab"). Its index in the section header table is given by e_shstrndx field of the ELF header. */ unsigned int shstrtabIndex = rdi(hdr->e_shstrndx); assert(shstrtabIndex < shdrs.size()); unsigned int shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size); char * shstrtab = (char *)contents + rdi(shdrs[shstrtabIndex].sh_offset); checkPointer(shstrtab, shstrtabSize); assert(shstrtabSize > 0); assert(shstrtab[shstrtabSize - 1] == 0); sectionNames = string(shstrtab, shstrtabSize); sectionsByOldIndex.resize(hdr->e_shnum); for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) sectionsByOldIndex[i] = getSectionName(shdrs[i]); } template void ElfFile::sortPhdrs() { /* Sort the segments by offset. */ CompPhdr comp; comp.elfFile = this; sort(phdrs.begin(), phdrs.end(), comp); } template void ElfFile::sortShdrs() { /* Translate sh_link mappings to section names, since sorting the sections will invalidate the sh_link fields. */ map linkage; for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) if (rdi(shdrs[i].sh_link) != 0) linkage[getSectionName(shdrs[i])] = getSectionName(shdrs[rdi(shdrs[i].sh_link)]); /* Idem for sh_info on certain sections. */ map info; for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) if (rdi(shdrs[i].sh_info) != 0 && (rdi(shdrs[i].sh_type) == SHT_REL || rdi(shdrs[i].sh_type) == SHT_RELA)) info[getSectionName(shdrs[i])] = getSectionName(shdrs[rdi(shdrs[i].sh_info)]); /* Idem for the index of the .shstrtab section in the ELF header. */ SectionName shstrtabName = getSectionName(shdrs[rdi(hdr->e_shstrndx)]); /* Sort the sections by offset. */ CompShdr comp; comp.elfFile = this; sort(shdrs.begin(), shdrs.end(), comp); /* Restore the sh_link mappings. */ for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) if (rdi(shdrs[i].sh_link) != 0) wri(shdrs[i].sh_link, findSection3(linkage[getSectionName(shdrs[i])])); /* And the st_info mappings. */ for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) if (rdi(shdrs[i].sh_info) != 0 && (rdi(shdrs[i].sh_type) == SHT_REL || rdi(shdrs[i].sh_type) == SHT_RELA)) wri(shdrs[i].sh_info, findSection3(info[getSectionName(shdrs[i])])); /* And the .shstrtab index. */ wri(hdr->e_shstrndx, findSection3(shstrtabName)); } static void writeFile(string fileName, mode_t fileMode) { string fileName2 = fileName + "_patchelf_tmp"; int fd = open(fileName2.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0700); if (fd == -1) error("open"); if (write(fd, contents, fileSize) != fileSize) error("write"); if (close(fd) != 0) error("close"); if (chmod(fileName2.c_str(), fileMode) != 0) error("chmod"); if (rename(fileName2.c_str(), fileName.c_str()) != 0) error("rename"); } static unsigned int roundUp(unsigned int n, unsigned int m) { return ((n - 1) / m + 1) * m; } template void ElfFile::shiftFile(unsigned int extraPages, Elf_Addr startPage) { /* Move the entire contents of the file `extraPages' pages further. */ unsigned int oldSize = fileSize; unsigned int shift = extraPages * pageSize; growFile(fileSize + extraPages * pageSize); memmove(contents + extraPages * pageSize, contents, oldSize); memset(contents + sizeof(Elf_Ehdr), 0, shift - sizeof(Elf_Ehdr)); /* Adjust the ELF header. */ wri(hdr->e_phoff, sizeof(Elf_Ehdr)); wri(hdr->e_shoff, rdi(hdr->e_shoff) + shift); /* Update the offsets in the section headers. */ for (int i = 1; i < rdi(hdr->e_shnum); ++i) wri(shdrs[i].sh_offset, rdi(shdrs[i].sh_offset) + shift); /* Update the offsets in the program headers. */ for (int i = 0; i < rdi(hdr->e_phnum); ++i) { wri(phdrs[i].p_offset, rdi(phdrs[i].p_offset) + shift); if (rdi(phdrs[i].p_align) != 0 && (rdi(phdrs[i].p_vaddr) - rdi(phdrs[i].p_offset)) % rdi(phdrs[i].p_align) != 0) { debug("changing alignment of program header %d from %d to %d\n", i, rdi(phdrs[i].p_align), pageSize); wri(phdrs[i].p_align, pageSize); } } /* Add a segment that maps the new program/section headers and PT_INTERP segment into memory. Otherwise glibc will choke. */ phdrs.resize(rdi(hdr->e_phnum) + 1); wri(hdr->e_phnum, rdi(hdr->e_phnum) + 1); Elf_Phdr &phdr = phdrs[rdi(hdr->e_phnum) - 1]; wri(phdr.p_type, PT_LOAD); wri(phdr.p_offset, 0); wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage)); wri(phdr.p_filesz, wri(phdr.p_memsz, shift)); wri(phdr.p_flags, PF_R | PF_W); wri(phdr.p_align, pageSize); } template string ElfFile::getSectionName(const Elf_Shdr &shdr) { return string(sectionNames.c_str() + rdi(shdr.sh_name)); } template Elf_Shdr &ElfFile::findSection(const SectionName §ionName) { Elf_Shdr *shdr = findSection2(sectionName); if (!shdr) error("cannot find section " + sectionName); return *shdr; } template Elf_Shdr *ElfFile::findSection2(const SectionName §ionName) { unsigned int i = findSection3(sectionName); return i ? &shdrs[i] : 0; } template unsigned int ElfFile::findSection3(const SectionName §ionName) { for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) if (getSectionName(shdrs[i]) == sectionName) return i; return 0; } template string &ElfFile::replaceSection(const SectionName §ionName, unsigned int size) { ReplacedSections::iterator i = replacedSections.find(sectionName); string s; if (i != replacedSections.end()) { s = string(i->second); } else { Elf_Shdr &shdr = findSection(sectionName); s = string((char *)contents + rdi(shdr.sh_offset), rdi(shdr.sh_size)); } s.resize(size); replacedSections[sectionName] = s; return replacedSections[sectionName]; } template void ElfFile::writeReplacedSections(Elf_Off &curOff, Elf_Addr startAddr, Elf_Off startOffset) { /* Overwrite the old section contents with 'X's. Do this *before* writing the new section contents (below) to prevent clobbering previously written new section contents. */ for (ReplacedSections::iterator i = replacedSections.begin(); i != replacedSections.end(); ++i) { string sectionName = i->first; Elf_Shdr &shdr = findSection(sectionName); memset(contents + rdi(shdr.sh_offset), 'X', rdi(shdr.sh_size)); } for (ReplacedSections::iterator i = replacedSections.begin(); i != replacedSections.end(); ++i) { string sectionName = i->first; Elf_Shdr &shdr = findSection(sectionName); debug("rewriting section `%s' from offset 0x%x (size %d) to offset 0x%x (size %d)\n", sectionName.c_str(), rdi(shdr.sh_offset), rdi(shdr.sh_size), curOff, i->second.size()); memcpy(contents + curOff, (unsigned char *)i->second.c_str(), i->second.size()); /* Update the section header for this section. */ wri(shdr.sh_offset, curOff); wri(shdr.sh_addr, startAddr + (curOff - startOffset)); wri(shdr.sh_size, i->second.size()); wri(shdr.sh_addralign, sectionAlignment); /* If this is the .interp section, then the PT_INTERP segment must be sync'ed with it. */ if (sectionName == ".interp") { for (unsigned int j = 0; j < phdrs.size(); ++j) if (rdi(phdrs[j].p_type) == PT_INTERP) { phdrs[j].p_offset = shdr.sh_offset; phdrs[j].p_vaddr = phdrs[j].p_paddr = shdr.sh_addr; phdrs[j].p_filesz = phdrs[j].p_memsz = shdr.sh_size; } } /* If this is the .dynamic section, then the PT_DYNAMIC segment must be sync'ed with it. */ if (sectionName == ".dynamic") { for (unsigned int j = 0; j < phdrs.size(); ++j) if (rdi(phdrs[j].p_type) == PT_DYNAMIC) { phdrs[j].p_offset = shdr.sh_offset; phdrs[j].p_vaddr = phdrs[j].p_paddr = shdr.sh_addr; phdrs[j].p_filesz = phdrs[j].p_memsz = shdr.sh_size; } } curOff += roundUp(i->second.size(), sectionAlignment); } replacedSections.clear(); } template void ElfFile::rewriteSectionsLibrary() { /* For dynamic libraries, we just place the replacement sections at the end of the file. They're mapped into memory by a PT_LOAD segment located directly after the last virtual address page of other segments. */ Elf_Addr startPage = 0; for (unsigned int i = 0; i < phdrs.size(); ++i) { Elf_Addr thisPage = roundUp(rdi(phdrs[i].p_vaddr) + rdi(phdrs[i].p_memsz), pageSize); if (thisPage > startPage) startPage = thisPage; } debug("last page is 0x%llx\n", (unsigned long long)startPage); /* Compute the total space needed for the replaced sections and the program headers. */ off_t neededSpace = (phdrs.size() + 1) * sizeof(Elf_Phdr); for (ReplacedSections::iterator i = replacedSections.begin(); i != replacedSections.end(); ++i) neededSpace += roundUp(i->second.size(), sectionAlignment); debug("needed space is %d\n", neededSpace); size_t startOffset = roundUp(fileSize, pageSize); growFile(startOffset + neededSpace); /* Even though this file is of type ET_DYN, it could actually be an executable. For instance, Gold produces executables marked ET_DYN. In that case we can still hit the kernel bug that necessitated rewriteSectionsExecutable(). However, such executables also tend to start at virtual address 0, so rewriteSectionsExecutable() won't work because it doesn't have any virtual address space to grow downwards into. As a workaround, make sure that the virtual address of our new PT_LOAD segment relative to the first PT_LOAD segment is equal to its offset; otherwise we hit the kernel bug. This may require creating a hole in the executable. The bigger the size of the uninitialised data segment, the bigger the hole. */ if (isExecutable) { if (startOffset >= startPage) { debug("shifting new PT_LOAD segment by %d bytes to work around a Linux kernel bug\n", startOffset - startPage); } else { size_t hole = startPage - startOffset; /* Print a warning, because the hole could be very big. */ fprintf(stderr, "warning: working around a Linux kernel bug by creating a hole of %zu bytes in ‘%s’\n", hole, fileName.c_str()); assert(hole % pageSize == 0); /* !!! We could create an actual hole in the file here, but it's probably not worth the effort. */ growFile(fileSize + hole); startOffset += hole; } startPage = startOffset; } /* Add a segment that maps the replaced sections and program headers into memory. */ phdrs.resize(rdi(hdr->e_phnum) + 1); wri(hdr->e_phnum, rdi(hdr->e_phnum) + 1); Elf_Phdr &phdr = phdrs[rdi(hdr->e_phnum) - 1]; wri(phdr.p_type, PT_LOAD); wri(phdr.p_offset, startOffset); wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage)); wri(phdr.p_filesz, wri(phdr.p_memsz, neededSpace)); wri(phdr.p_flags, PF_R | PF_W); wri(phdr.p_align, pageSize); /* Write out the replaced sections. */ Elf_Off curOff = startOffset + phdrs.size() * sizeof(Elf_Phdr); writeReplacedSections(curOff, startPage, startOffset); assert((off_t)curOff == startOffset + neededSpace); /* Move the program header to the start of the new area. */ wri(hdr->e_phoff, startOffset); rewriteHeaders(startPage); } template void ElfFile::rewriteSectionsExecutable() { /* Sort the sections by offset, otherwise we won't correctly find all the sections before the last replaced section. */ sortShdrs(); /* What is the index of the last replaced section? */ unsigned int lastReplaced = 0; for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) { string sectionName = getSectionName(shdrs[i]); if (replacedSections.find(sectionName) != replacedSections.end()) { debug("using replaced section `%s'\n", sectionName.c_str()); lastReplaced = i; } } assert(lastReplaced != 0); debug("last replaced is %d\n", lastReplaced); /* Try to replace all sections before that, as far as possible. Stop when we reach an irreplacable section (such as one of type SHT_PROGBITS). These cannot be moved in virtual address space since that would invalidate absolute references to them. */ assert(lastReplaced + 1 < shdrs.size()); /* !!! I'm lazy. */ size_t startOffset = rdi(shdrs[lastReplaced + 1].sh_offset); Elf_Addr startAddr = rdi(shdrs[lastReplaced + 1].sh_addr); string prevSection; for (unsigned int i = 1; i <= lastReplaced; ++i) { Elf_Shdr &shdr(shdrs[i]); string sectionName = getSectionName(shdr); debug("looking at section `%s'\n", sectionName.c_str()); /* !!! Why do we stop after a .dynstr section? I can't remember! */ if ((rdi(shdr.sh_type) == SHT_PROGBITS && sectionName != ".interp") || prevSection == ".dynstr") { startOffset = rdi(shdr.sh_offset); startAddr = rdi(shdr.sh_addr); lastReplaced = i - 1; break; } else { if (replacedSections.find(sectionName) == replacedSections.end()) { debug("replacing section `%s' which is in the way\n", sectionName.c_str()); replaceSection(sectionName, rdi(shdr.sh_size)); } } prevSection = sectionName; } debug("first reserved offset/addr is 0x%x/0x%llx\n", startOffset, (unsigned long long)startAddr); assert(startAddr % pageSize == startOffset % pageSize); Elf_Addr firstPage = startAddr - startOffset; debug("first page is 0x%llx\n", (unsigned long long)firstPage); /* Right now we assume that the section headers are somewhere near the end, which appears to be the case most of the time. Therefore they're not accidentally overwritten by the replaced sections. !!! Fix this. */ assert((off_t)rdi(hdr->e_shoff) >= startOffset); /* Compute the total space needed for the replaced sections, the ELF header, and the program headers. */ size_t neededSpace = sizeof(Elf_Ehdr) + phdrs.size() * sizeof(Elf_Phdr); for (ReplacedSections::iterator i = replacedSections.begin(); i != replacedSections.end(); ++i) neededSpace += roundUp(i->second.size(), sectionAlignment); debug("needed space is %d\n", neededSpace); /* If we need more space at the start of the file, then grow the file by the minimum number of pages and adjust internal offsets. */ if (neededSpace > startOffset) { /* We also need an additional program header, so adjust for that. */ neededSpace += sizeof(Elf_Phdr); debug("needed space is %d\n", neededSpace); unsigned int neededPages = roundUp(neededSpace - startOffset, pageSize) / pageSize; debug("needed pages is %d\n", neededPages); if (neededPages * pageSize > firstPage) error("virtual address space underrun!"); firstPage -= neededPages * pageSize; startOffset += neededPages * pageSize; shiftFile(neededPages, firstPage); } /* Clear out the free space. */ Elf_Off curOff = sizeof(Elf_Ehdr) + phdrs.size() * sizeof(Elf_Phdr); debug("clearing first %d bytes\n", startOffset - curOff); memset(contents + curOff, 0, startOffset - curOff); /* Write out the replaced sections. */ writeReplacedSections(curOff, firstPage, 0); assert((off_t)curOff == neededSpace); rewriteHeaders(firstPage + rdi(hdr->e_phoff)); } template void ElfFile::rewriteSections() { if (replacedSections.empty()) return; for (ReplacedSections::iterator i = replacedSections.begin(); i != replacedSections.end(); ++i) debug("replacing section `%s' with size %d\n", i->first.c_str(), i->second.size()); if (rdi(hdr->e_type) == ET_DYN) { debug("this is a dynamic library\n"); rewriteSectionsLibrary(); } else if (rdi(hdr->e_type) == ET_EXEC) { debug("this is an executable\n"); rewriteSectionsExecutable(); } else error("unknown ELF type"); } template void ElfFile::rewriteHeaders(Elf_Addr phdrAddress) { /* Rewrite the program header table. */ /* If there is a segment for the program header table, update it. (According to the ELF spec, it must be the first entry.) */ if (rdi(phdrs[0].p_type) == PT_PHDR) { phdrs[0].p_offset = hdr->e_phoff; wri(phdrs[0].p_vaddr, wri(phdrs[0].p_paddr, phdrAddress)); wri(phdrs[0].p_filesz, wri(phdrs[0].p_memsz, phdrs.size() * sizeof(Elf_Phdr))); } sortPhdrs(); for (unsigned int i = 0; i < phdrs.size(); ++i) *((Elf_Phdr *)(contents + rdi(hdr->e_phoff)) + i) = phdrs[i]; /* Rewrite the section header table. For neatness, keep the sections sorted. */ assert(rdi(hdr->e_shnum) == shdrs.size()); sortShdrs(); for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) *((Elf_Shdr *)(contents + rdi(hdr->e_shoff)) + i) = shdrs[i]; /* Update all those nasty virtual addresses in the .dynamic section. Note that not all executables have .dynamic sections (e.g., those produced by klibc's klcc). */ Elf_Shdr *shdrDynamic = findSection2(".dynamic"); if (shdrDynamic) { Elf_Dyn * dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic->sh_offset)); unsigned int d_tag; for (; (d_tag = rdi(dyn->d_tag)) != DT_NULL; dyn++) if (d_tag == DT_STRTAB) dyn->d_un.d_ptr = findSection(".dynstr").sh_addr; else if (d_tag == DT_STRSZ) dyn->d_un.d_val = findSection(".dynstr").sh_size; else if (d_tag == DT_SYMTAB) dyn->d_un.d_ptr = findSection(".dynsym").sh_addr; else if (d_tag == DT_HASH) dyn->d_un.d_ptr = findSection(".hash").sh_addr; else if (d_tag == DT_GNU_HASH) dyn->d_un.d_ptr = findSection(".gnu.hash").sh_addr; else if (d_tag == DT_JMPREL) { Elf_Shdr *shdr = findSection2(".rel.plt"); if (!shdr) shdr = findSection2(".rela.plt"); /* 64-bit Linux, x86-64 */ if (!shdr) shdr = findSection2(".rela.IA_64.pltoff"); /* 64-bit Linux, IA-64 */ if (!shdr) error("cannot find section corresponding to DT_JMPREL"); dyn->d_un.d_ptr = shdr->sh_addr; } else if (d_tag == DT_REL) { /* !!! hack! */ Elf_Shdr *shdr = findSection2(".rel.dyn"); /* no idea if this makes sense, but it was needed for some program */ if (!shdr) shdr = findSection2(".rel.got"); if (!shdr) error("cannot find .rel.dyn or .rel.got"); dyn->d_un.d_ptr = shdr->sh_addr; } else if (d_tag == DT_RELA) dyn->d_un.d_ptr = findSection(".rela.dyn").sh_addr; /* PPC Linux */ else if (d_tag == DT_VERNEED) dyn->d_un.d_ptr = findSection(".gnu.version_r").sh_addr; else if (d_tag == DT_VERSYM) dyn->d_un.d_ptr = findSection(".gnu.version").sh_addr; } /* Rewrite the .dynsym section. It contains the indices of the sections in which symbols appear, so these need to be remapped. */ for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) { if (rdi(shdrs[i].sh_type) != SHT_SYMTAB && rdi(shdrs[i].sh_type) != SHT_DYNSYM) continue; debug("rewriting symbol table section %d\n", i); for (size_t entry = 0; (entry + 1) * sizeof(Elf_Sym) <= rdi(shdrs[i].sh_size); entry++) { Elf_Sym * sym = (Elf_Sym *)(contents + rdi(shdrs[i].sh_offset) + entry * sizeof(Elf_Sym)); unsigned int shndx = rdi(sym->st_shndx); if (shndx != SHN_UNDEF && shndx < SHN_LORESERVE) { if (shndx >= sectionsByOldIndex.size()) { fprintf(stderr, "warning: entry %d in symbol table refers to a non-existent section, skipping\n", shndx); continue; } string section = sectionsByOldIndex.at(shndx); assert(!section.empty()); unsigned int newIndex = findSection3(section); // inefficient // debug("rewriting symbol %d: index = %d (%s) -> %d\n", entry, shndx, section.c_str(), newIndex); wri(sym->st_shndx, newIndex); /* Rewrite st_value. FIXME: we should do this for all types, but most don't actually change. */ if (ELF32_ST_TYPE(rdi(sym->st_info)) == STT_SECTION) wri(sym->st_value, rdi(shdrs[newIndex].sh_addr)); } } } } static void setSubstr(string &s, unsigned int pos, const string &t) { assert(pos + t.size() <= s.size()); copy(t.begin(), t.end(), s.begin() + pos); } template string ElfFile::getInterpreter() { Elf_Shdr &shdr = findSection(".interp"); return string((char *)contents + rdi(shdr.sh_offset), rdi(shdr.sh_size)); } template void ElfFile::setInterpreter(const string &newInterpreter) { string §ion = replaceSection(".interp", newInterpreter.size() + 1); setSubstr(section, 0, newInterpreter + '\0'); changed = true; } static void concatToRPath(string &rpath, const string &path) { if (!rpath.empty()) rpath += ":"; rpath += path; } template void ElfFile::modifyRPath(RPathOp op, string newRPath) { Elf_Shdr &shdrDynamic = findSection(".dynamic"); /* !!! We assume that the virtual address in the DT_STRTAB entry of the dynamic section corresponds to the .dynstr section. */ Elf_Shdr &shdrDynStr = findSection(".dynstr"); char * strTab = (char *)contents + rdi(shdrDynStr.sh_offset); /* Find the DT_STRTAB entry in the dynamic section. */ Elf_Dyn *dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic.sh_offset)); Elf_Addr strTabAddr = 0; for (; rdi(dyn->d_tag) != DT_NULL; dyn++) if (rdi(dyn->d_tag) == DT_STRTAB) strTabAddr = rdi(dyn->d_un.d_ptr); if (!strTabAddr) error("strange: no string table"); assert(strTabAddr == rdi(shdrDynStr.sh_addr)); /* Walk through the dynamic section, look for the RPATH/RUNPATH entry. According to the ld.so docs, DT_RPATH is obsolete, we should use DT_RUNPATH. DT_RUNPATH has two advantages: it can be overriden by LD_LIBRARY_PATH, and it's scoped (the DT_RUNPATH for an executable or library doesn't affect the search path for libraries used by it). DT_RPATH is ignored if DT_RUNPATH is present. The binutils `ld' still generates only DT_RPATH, unless you use its `--enable-new-dtag' option, in which case it generates a DT_RPATH and DT_RUNPATH pointing at the same string. */ static vector neededLibs; dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic.sh_offset)); Elf_Dyn *dynRPath = 0, *dynRunPath = 0; char * rpath = 0; for (; rdi(dyn->d_tag) != DT_NULL; dyn++) { if (rdi(dyn->d_tag) == DT_RPATH) { dynRPath = dyn; /* Only use DT_RPATH if there is no DT_RUNPATH. */ if (!dynRunPath) rpath = strTab + rdi(dyn->d_un.d_val); } else if (rdi(dyn->d_tag) == DT_RUNPATH) { dynRunPath = dyn; rpath = strTab + rdi(dyn->d_un.d_val); } else if (rdi(dyn->d_tag) == DT_NEEDED) neededLibs.push_back(string(strTab + rdi(dyn->d_un.d_val))); } if (op == rpPrint) { printf("%s\n", rpath ? rpath : ""); return; } if (op == rpShrink && !rpath) { debug("no RPATH to shrink\n"); return; } /* For each directory in the RPATH, check if it contains any needed library. */ if (op == rpShrink) { static vector neededLibFound(neededLibs.size(), false); newRPath = ""; char *pos = rpath; while (*pos) { char *end = strchr(pos, ':'); if (!end) end = strchr(pos, 0); /* Get the name of the directory. */ string dirName(pos, end - pos); if (*end == ':') ++end; pos = end; /* Non-absolute entries are allowed (e.g., the special "$ORIGIN" hack). */ if (dirName[0] != '/') { concatToRPath(newRPath, dirName); continue; } /* For each library that we haven't found yet, see if it exists in this directory. */ bool libFound = false; for (unsigned int j = 0; j < neededLibs.size(); ++j) if (!neededLibFound[j]) { string libName = dirName + "/" + neededLibs[j]; struct stat st; if (stat(libName.c_str(), &st) == 0) { neededLibFound[j] = true; libFound = true; } } if (!libFound) debug("removing directory `%s' from RPATH\n", dirName.c_str()); else concatToRPath(newRPath, dirName); } } if (string(rpath ? rpath : "") == newRPath) return; changed = true; /* Zero out the previous rpath to prevent retained dependencies in Nix. */ unsigned int rpathSize = 0; if (rpath) { rpathSize = strlen(rpath); memset(rpath, 'X', rpathSize); } debug("new rpath is `%s'\n", newRPath.c_str()); if (!forceRPath && dynRPath && !dynRunPath) { /* convert DT_RPATH to DT_RUNPATH */ dynRPath->d_tag = DT_RUNPATH; dynRunPath = dynRPath; dynRPath = 0; } if (forceRPath && dynRPath && dynRunPath) { /* convert DT_RUNPATH to DT_RPATH */ dynRunPath->d_tag = DT_IGNORE; } if (newRPath.size() <= rpathSize) { strcpy(rpath, newRPath.c_str()); return; } /* Grow the .dynstr section to make room for the new RPATH. */ debug("rpath is too long, resizing...\n"); string &newDynStr = replaceSection(".dynstr", rdi(shdrDynStr.sh_size) + newRPath.size() + 1); setSubstr(newDynStr, rdi(shdrDynStr.sh_size), newRPath + '\0'); /* Update the DT_RUNPATH and DT_RPATH entries. */ if (dynRunPath || dynRPath) { if (dynRunPath) dynRunPath->d_un.d_val = shdrDynStr.sh_size; if (dynRPath) dynRPath->d_un.d_val = shdrDynStr.sh_size; } else { /* There is no DT_RUNPATH entry in the .dynamic section, so we have to grow the .dynamic section. */ string &newDynamic = replaceSection(".dynamic", rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn)); unsigned int idx = 0; for (; rdi(((Elf_Dyn *)newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++) ; debug("DT_NULL index is %d\n", idx); /* Shift all entries down by one. */ setSubstr(newDynamic, sizeof(Elf_Dyn), string(newDynamic, 0, sizeof(Elf_Dyn) * (idx + 1))); /* Add the DT_RUNPATH entry at the top. */ Elf_Dyn newDyn; wri(newDyn.d_tag, forceRPath ? DT_RPATH : DT_RUNPATH); newDyn.d_un.d_val = shdrDynStr.sh_size; setSubstr(newDynamic, 0, string((char *)&newDyn, sizeof(Elf_Dyn))); } } template void ElfFile::removeNeeded(set libs) { if (libs.empty()) return; Elf_Shdr &shdrDynamic = findSection(".dynamic"); Elf_Shdr &shdrDynStr = findSection(".dynstr"); char * strTab = (char *)contents + rdi(shdrDynStr.sh_offset); Elf_Dyn *dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic.sh_offset)); Elf_Dyn *last = dyn; for (; rdi(dyn->d_tag) != DT_NULL; dyn++) { if (rdi(dyn->d_tag) == DT_NEEDED) { char *name = strTab + rdi(dyn->d_un.d_val); if (libs.find(name) != libs.end()) { debug("removing DT_NEEDED entry `%s'\n", name); changed = true; } else { debug("keeping DT_NEEDED entry `%s'\n", name); *last++ = *dyn; } } else *last++ = *dyn; } memset(last, 0, sizeof(Elf_Dyn) * (dyn - last)); } static bool printInterpreter = false; static string newInterpreter; static bool shrinkRPath = false; static bool setRPath = false; static bool printRPath = false; static string newRPath; static set neededLibsToRemove; template static void patchElf2(ElfFile &elfFile, mode_t fileMode) { elfFile.parse(); if (printInterpreter) printf("%s\n", elfFile.getInterpreter().c_str()); if (newInterpreter != "") elfFile.setInterpreter(newInterpreter); if (printRPath) elfFile.modifyRPath(elfFile.rpPrint, ""); if (shrinkRPath) elfFile.modifyRPath(elfFile.rpShrink, ""); else if (setRPath) elfFile.modifyRPath(elfFile.rpSet, newRPath); elfFile.removeNeeded(neededLibsToRemove); if (elfFile.isChanged()) { elfFile.rewriteSections(); writeFile(fileName, fileMode); } } static void patchElf() { if (!printInterpreter && !printRPath) debug("patching ELF file `%s'\n", fileName.c_str()); mode_t fileMode; readFile(fileName, &fileMode); /* Check the ELF header for basic validity. */ if (fileSize < (off_t)sizeof(Elf32_Ehdr)) error("missing ELF header"); if (memcmp(contents, ELFMAG, SELFMAG) != 0) error("not an ELF executable"); if (contents[EI_CLASS] == ELFCLASS32 && contents[EI_VERSION] == EV_CURRENT) { ElfFile elfFile; patchElf2(elfFile, fileMode); } else if (contents[EI_CLASS] == ELFCLASS64 && contents[EI_VERSION] == EV_CURRENT) { ElfFile elfFile; patchElf2(elfFile, fileMode); } else { error("ELF executable is not 32/64-bit, little/big-endian, version 1"); } } void showHelp(const string &progName) { fprintf(stderr, "syntax: %s\n\ [--set-interpreter FILENAME]\n\ [--print-interpreter]\n\ [--set-rpath RPATH]\n\ [--shrink-rpath]\n\ [--print-rpath]\n\ [--force-rpath]\n\ [--remove-needed LIBRARY]\n\ [--debug]\n\ [--version]\n\ FILENAME\n", progName.c_str()); } int main(int argc, char **argv) { if (argc <= 1) { showHelp(argv[0]); return 1; } if (getenv("PATCHELF_DEBUG") != 0) debugMode = true; int i; for (i = 1; i < argc; ++i) { string arg(argv[i]); if (arg == "--set-interpreter" || arg == "--interpreter") { if (++i == argc) error("missing argument"); newInterpreter = argv[i]; } else if (arg == "--print-interpreter") { printInterpreter = true; } else if (arg == "--shrink-rpath") { shrinkRPath = true; } else if (arg == "--set-rpath") { if (++i == argc) error("missing argument"); setRPath = true; newRPath = argv[i]; } else if (arg == "--print-rpath") { printRPath = true; } else if (arg == "--force-rpath") { /* Generally we prefer to emit DT_RUNPATH instead of DT_RPATH, as the latter is obsolete. However, there is a slight semantic difference: DT_RUNPATH is "scoped", it only affects the executable or library in question, not its recursive imports. So maybe you really want to force the use of DT_RPATH. That's what this option does. Without it, DT_RPATH (if encountered) is converted to DT_RUNPATH, and if neither is present, a DT_RUNPATH is added. With it, DT_RPATH isn't converted to DT_RUNPATH, and if neither is present, a DT_RPATH is added. */ forceRPath = true; } else if (arg == "--remove-needed") { if (++i == argc) error("missing argument"); neededLibsToRemove.insert(argv[i]); } else if (arg == "--debug") { debugMode = true; } else if (arg == "--help") { showHelp(argv[0]); return 0; } else if (arg == "--version") { printf(PACKAGE_STRING "\n"); return 0; } else break; } if (i == argc) error("missing filename"); fileName = argv[i]; patchElf(); return 0; } ================================================ FILE: buildutils/postflight ================================================ #!/bin/csh -f # This postflight script echoes the values of the available # arguments and environmental variables. # echo "Start postflight script" echo "" echo "Finished postflight script" exit 0 ================================================ FILE: buildutils/postinstall ================================================ #!/bin/csh -f # This postinstall script echoes the values of the available # arguments and environmental variables. # echo "Start postinstall script" echo "" set InstDest = $argv[2] set vapor_root = $InstDest/VAPOR3/VAPOR.app set bindir = $vapor_root/Contents/MacOS set lib_search_dirs = $bindir set mandir = $vapor_root/Contents/share/man set sharedir = $vapor_root/Contents/share set sedcmd = sed if (-e /bin/sed) set sedcmd = /bin/sed if (-e /usr/bin/sed) set sedcmd = /usr/bin/sed # # Edit the user environment setup scripts # set old0 = 'set[ ][ ]*root[ ][ ]*=.*$' set new0 = "set root = $vapor_root" set old1 = 'set[ ][ ]*lib_search_dirs[ ][ ]*=.*$' set new1 = "set lib_search_dirs = $lib_search_dirs" set old2 = 'set[ ][ ]*bindir[ ][ ]*=.*$' set new2 = "set bindir = $bindir" set old3 = 'set[ ][ ]*mandir[ ][ ]*=.*$' set new3 = "set mandir = $mandir" set old4 = 'set[ ][ ]*sharedir[ ][ ]*=.*$' set new4 = "set sharedir = $sharedir" $sedcmd -e "s#$old0#$new0#" -e "s#$old1#$new1#" -e "s#$old2#$new2#" -e "s#$old3#$new3#" -e "s#$old4#$new4#" < $bindir/vapor-setup.csh >! $bindir/vapor-setup.tmp /bin/mv $bindir/vapor-setup.tmp $bindir/vapor-setup.csh set old0 = 'root=.*$' set new0 = "root=$vapor_root" set old1 = 'lib_search_dirs=.*$' set new1 = "lib_search_dirs=$lib_search_dirs" set old2 = 'bindir=.*$' set new2 = "bindir=$bindir" set old3 = 'mandir=.*$' set new3 = "mandir=$mandir" set old4 = 'sharedir=.*$' set new4 = "sharedir=$sharedir" $sedcmd -e "s#$old0#$new0#" -e "s#$old1#$new1#" -e "s#$old2#$new2#" -e "s#$old3#$new3#" -e "s#$old4#$new4#" < $bindir/vapor-setup.sh >! $bindir/vapor-setup.tmp /bin/mv $bindir/vapor-setup.tmp $bindir/vapor-setup.sh echo "Finish postinstall script" exit 0 ================================================ FILE: buildutils/postupgrade ================================================ #!/bin/csh -f # This postupgrade script echoes the values of the available # arguments and environmental variables. # echo "Start postupgrade script" echo "" set InstDest = $argv[2] set vapor_root = $InstDest/VAPOR3/VAPOR.app set bindir = $vapor_root/Contents/MacOS set lib_search_dirs = $bindir set mandir = $vapor_root/Contents/share/man set sharedir = $vapor_root/Contents/share set sedcmd = sed if (-e /bin/sed) set sedcmd = /bin/sed if (-e /usr/bin/sed) set sedcmd = /usr/bin/sed # # Edit the user environment setup scripts # set old0 = 'set[ ][ ]*root[ ][ ]*=.*$' set new0 = "set root = $vapor_root" set old1 = 'set[ ][ ]*lib_search_dirs[ ][ ]*=.*$' set new1 = "set lib_search_dirs = $lib_search_dirs" set old2 = 'set[ ][ ]*bindir[ ][ ]*=.*$' set new2 = "set bindir = $bindir" set old3 = 'set[ ][ ]*mandir[ ][ ]*=.*$' set new3 = "set mandir = $mandir" set old4 = 'set[ ][ ]*sharedir[ ][ ]*=.*$' set new4 = "set sharedir = $sharedir" $sedcmd -e "s#$old0#$new0#" -e "s#$old1#$new1#" -e "s#$old2#$new2#" -e "s#$old3#$new3#" -e "s#$old4#$new4#" < $bindir/vapor-setup.csh >! $bindir/vapor-setup.tmp /bin/mv $bindir/vapor-setup.tmp $bindir/vapor-setup.csh set old0 = 'root=.*$' set new0 = "root=$vapor_root" set old1 = 'lib_search_dirs=.*$' set new1 = "lib_search_dirs=$lib_search_dirs" set old2 = 'bindir=.*$' set new2 = "bindir=$bindir" set old3 = 'mandir=.*$' set new3 = "mandir=$mandir" set old4 = 'sharedir=.*$' set new4 = "sharedir=$sharedir" $sedcmd -e "s#$old0#$new0#" -e "s#$old1#$new1#" -e "s#$old2#$new2#" -e "s#$old3#$new3#" -e "s#$old4#$new4#" < $bindir/vapor-setup.sh >! $bindir/vapor-setup.tmp /bin/mv $bindir/vapor-setup.tmp $bindir/vapor-setup.sh echo "Finish postupgrade script" exit 0 ================================================ FILE: buildutils/renameomp.sh ================================================ #!/bin/bash LIB="`otool -L "$1" | grep -F libomp | xargs | cut -d\ -f1`" install_name_tool -change "$LIB" "@rpath/libomp.dylib" "$1" ================================================ FILE: buildutils/sgiinstall.sh ================================================ #!/bin/sh # flags="" dst="" src="" dostrip="" owner="" mode="" while [ x$1 != x ]; do case $1 in -c) shift continue;; -m) flags="$flags $1 $2 " mode="$2" shift shift continue;; -o) flags="$flags -u $2 " owner="$2" shift shift continue;; -g) flags="$flags $1 $2 " shift shift continue;; -s) dostrip="strip" shift continue;; *) if [ x$src = x ] then src=$1 else dst=$1 fi shift continue;; esac done case "$mode" in "") ;; *) case "$owner" in "") # flags="$flags -u root" ;; esac ;; esac if [ x$src = x ] then echo "$0: no input file specified" exit 1 fi if [ x$dst = x ] then echo "$0: no destination specified" exit 1 fi # set up some variable to be used later rmcmd="" srcdir="." # if the destination isn't a directory we'll need to copy it first if [ ! -d $dst ] then dstbase=`basename $dst` cp $src /tmp/$dstbase rmcmd="rm -f /tmp/$dstbase" src=$dstbase srcdir=/tmp dst="`echo $dst | sed 's,^\(.*\)/.*$,\1,'`" if [ x$dst = x ] then dst="." fi fi # If the src file has a directory, copy it to /tmp to make install happy srcbase=`basename $src` if [ "$src" != "$srcbase" ] && [ "$src" != "./$srcbase" ] then cp $src /tmp/$srcbase src=$srcbase srcdir=/tmp rmcmd="rm -f /tmp/$srcbase" fi # do the actual install if [ -f /usr/sbin/install ] then installcmd=/usr/sbin/install elif [ -f /etc/install ] then installcmd=/etc/install else installcmd=install fi # This rm is commented out because some people want to be able to # install through symbolic links. Uncomment it if it offends you. # rm -f $dst/$srcbase (cd $srcdir ; $installcmd -f $dst $flags $src) if [ x$dostrip = xstrip ] then strip $dst/$srcbase fi # and clean up $rmcmd ================================================ FILE: buildutils/vapor.desktop ================================================ [Desktop Entry] Type=Application Name=VAPOR Comment=Visualization and Analysis Platform for Ocean, Atmosphere, and Solar Researchers Exec=bin/vapor Icon=VAPOR Categories=Science;Geoscience;DataVisualization; ================================================ FILE: conda/vapor/build.sh ================================================ #!/bin/sh # Inputs [[ -z "$DEBUG_BUILD" ]] && DEBUG_BUILD=true CMAKE_EXTRA="" # The env can be either PREFIX or BUILD_PREFIX depending on the build requirements. # Conda does not configure its variables accordingly. export ENV="$BUILD_PREFIX" export PATH="$ENV/bin:$PATH" # Conda will sometimes set PYTHON to a path that does not exist export PYTHON="`which python`" if $DEBUG_BUILD; then # If optimizations are disabled, need to disable fortify source otherwise will get barraged with warnings export CPPFLAGS="`echo $CPPFLAGS|sed 's/-D_FORTIFY_SOURCE=2//g'`" CMAKE_EXTRA="$CMAKE_EXTRA -DCMAKE_BUILD_TYPE=Debug" else CMAKE_EXTRA="$CMAKE_EXTRA -DCMAKE_BUILD_TYPE=Release" fi CMAKE_EXTRA="$CMAKE_EXTRA -DINSTALLER_OMIT_MAPS=ON" # Ignore extra warnings export CPPFLAGS=" \ $CPPFLAGS \ -Wno-unused-function \ -Wno-conversion-null \ -Wno-deprecated-declarations \ -Wno-catch-value \ -Wno-unknown-warning-option \ -Wno-array-parameter \ " # Vapor legacy configuration export CPPFLAGS="-isystem $ENV/include/freetype2 $CPPFLAGS" export CPPFLAGS="$CPPFLAGS -isystem $ENV/include" # cmake ignores CPPFLAGS export CXXFLAGS="$CXXFLAGS $CPPFLAGS" export CFLAGS="$CFLAGS $CPPFLAGS" # Conda will sometimes set these to invalid values which end up breaking the build unset CMAKE_ARGS unset CMAKE_PREFIX_PATH # Prevent linking outside libraries export CMAKE_LIBRARY_PATH="$PREFIX/lib:$BUILD_PREFIX/lib" export CMAKE_PREFIX_PATH="$PREFIX:$BUILD_PREFIX" # CMAKE_EXTRA="$CMAKE_EXTRA -DCMAKE_FIND_FRAMEWORK=NEVER" # CMAKE_EXTRA="$CMAKE_EXTRA -DCMAKE_FIND_APPBUNDLE=NEVER" # When conda messes up the build environment it not only points the python install target to the wrong root, # it also sometimes points it to the wrong version of python. SP_DIR="`python -c 'import site; print(site.getsitepackages()[0].replace(\"'$BUILD_PREFIX'\", \"'$PREFIX'\"))'`" # It also will sometimes decide not to make this dir mkdir -p "$SP_DIR" # Our third party libs have a non-standard copy of the GTE library so it is packaged and extracted here. unzip -d include buildutils/GTE.zip mkdir -p build cd build cmake .. \ -G 'Unix Makefiles' \ -DCONDA_BUILD=ON \ -DBUILD_PYTHON=ON \ -DBUILD_DOC=ON \ -DBUILD_UTL=OFF \ -DBUILD_GUI=OFF \ -DBUILD_OSP=OFF \ -DPython_EXECUTABLE="$PYTHON" \ -DCMAKE_INSTALL_PREFIX="$PREFIX" \ $CMAKE_EXTRA \ make -j$(($CPU_COUNT+1)) make doc make install ================================================ FILE: conda/vapor/jupyter_installer_fix.py ================================================ import argparse import os import shutil parser = argparse.ArgumentParser() parser.add_argument('-n', '--dryRun', action='store_true') parser.add_argument('-w', '--widgetDir', required=True) parser.add_argument('-o', '--outRootDir', required=True) args = parser.parse_args() print(args) widgetRoot = args.widgetDir widgetSetup = f"{widgetRoot}/setup.py" root = args.outRootDir assert(os.path.isdir(widgetRoot)) def nullFunc(ret=None): return lambda *args, **kwargs: ret import setuptools setuptools.setup = nullFunc() import jupyter_packaging jupyter_packaging.create_cmdclass = nullFunc(ret=dict()) jupyter_packaging.combine_commands = nullFunc() jupyter_packaging.install_npm = nullFunc() with open(widgetSetup) as f: exec(compile(f.read(), widgetSetup, "exec")) # print("data_files_spec =", data_files_spec) toInstall = jupyter_packaging.get_data_files(data_specs=data_files_spec, top=widgetRoot) for outDir, files in toInstall: outDir = root + "/" + outDir if not args.dryRun: os.makedirs(outDir, exist_ok=True) for file in files: print(f"Install {file} in {outDir}") if not args.dryRun: shutil.copy(widgetRoot+"/"+file, outDir) ================================================ FILE: conda/vapor/make_installer.sh ================================================ echo Generating vapor installer echo echo NOTE: Due to the oddities of conda, this should not be run from the directory from which you also build. echo NOTE: If you do, make sure to remove any generated files before calling conda build again. echo CHANNEL=__vapor_install_temp_vapor-channel mkdir -p $CHANNEL/linux-64/ cp `find $CONDA_PREFIX -name 'vapor*.bz2'` $CHANNEL/linux-64/ conda index $CHANNEL cat > install_vapor.sh << EOF [ "" = "\$CONDA_PREFIX" ] && echo This installer requires conda && exit 1 [ "" != "\`conda list | grep -v '^#'\`" ] && echo Please run in empty conda environment && exit 1 tail -n +___START_LINE___ "\$0" | tar -xf - conda install -c conda-forge -c file:/\`pwd\`/$CHANNEL vapor rm -rf $CHANNEL echo echo Vapor installed echo Examples can be found at \$CONDA_PREFIX/lib/python3.9/site-packages/vapor/examples echo Examples jupyter notebooks can be found at \$CONDA_PREFIX/lib/python3.9/site-packages/vapor/example_notebooks echo exit ___START_EMBEDDED_DATA___ EOF LINE=`grep -n ___START_EMBEDDED_DATA___ install_vapor.sh | tail -n1 | cut -f1 -d:` LINE=$(($LINE+1)) sed -i "s/___START_LINE___/$LINE/g" install_vapor.sh tar -cf - $CHANNEL >> install_vapor.sh rm -rf $CHANNEL echo Done ================================================ FILE: conda/vapor/meta.yaml ================================================ package: name: vapor version: "3.11.0" source: git_url: https://github.com/NCAR/VAPOR.git build: skip_compile_pyc: - "*.py" script_env: - DEBUG_BUILD requirements: build: # Build-Only # ========================================== - {{ compiler('cxx') }} - make=4.3 - cmake=3.21.3 - unzip=6.0 - jupytext=1.13.8 # Generate notebooks - doxygen=1.9.1 - esbuild - git # Both # (Needs to be specified manually in both rather than just in host because otherwise conda will install multiple versions of some packages and break the install) # ========================================== - python=3.9 - proj=7.2.0 - glm=0.9.9.4 - jpeg=9e {% if osx and arm64 %} - numpy=1.21.4 - assimp=5.0.1 - freetype=2.10.4 - hdf5=1.12.1 - geotiff=1.6.0 - udunits2=2.2.28 - netcdf4=1.5.8 - libtiff=4.3|4.4 - mesalib=21.2.5 - expat=2.4 - libcxx=14.0 {% else %} - numpy=1.26 - assimp=5.3 - freetype=2.12 - hdf5=1.12 - geotiff=1.6 - udunits2=2.2 - netcdf4=1.6 - libtiff=4.4 - mesalib=23.0.2 - expat=2.7 - libcxx=18 - libxcrypt # [linux] {% endif %} run: # Run only - xarray=2022 #=2022.3.0 - ipython=8 #=8.3.0 - jupyter=1 #=1.0.0 - hdf5plugin=4 - vapor-maps=1.0 # [not os.environ.get('DEBUG_BUILD', '1').lower() in ('true', '1', '')] - wurlitzer - bqplot - anywidget # Both - python=3.9 # pin_compatible('python') sometimes selects incompatible python (e.g. pin_compatible(python=3.9) selects python=3.10) - {{ pin_compatible('numpy') }} - {{ pin_compatible('assimp') }} - {{ pin_compatible('freetype') }} - {{ pin_compatible('hdf5') }} - {{ pin_compatible('jpeg') }} - {{ pin_compatible('geotiff') }} - {{ pin_compatible('udunits2') }} - {{ pin_compatible('netcdf4') }} - {{ pin_compatible('proj') }} - {{ pin_compatible('glm') }} - {{ pin_compatible('mesalib') }} - {{ pin_compatible('expat') }} - {{ pin_compatible('libcxx') }} {% if osx and arm64 %} - cppyy=2.2 # If this is in build conda will load an old clang compiler which fails to compile macOS headers - matplotlib=3 #=3.3.2 - py-opencv=4 #=4.5.3 - libtiff=4.3|4.4 # pin_compatible pins an incompatible version {% else %} - cppyy=3.5 # [osx] - cppyy=3.1.2 # [linux] - matplotlib=3.10 # [osx] - matplotlib=3.9 # [linux] - py-opencv=4.6 - {{ pin_compatible('libtiff') }} {% endif %} about: home: https://www.vapor.ucar.edu license: MIT summary: VAPOR is the Visualization and Analysis Platform for Ocean, Atmosphere, and Solar Researchers dev_url: https://github.com/NCAR/VAPOR ================================================ FILE: conda/vapor-maps/meta.yaml ================================================ package: name: vapor-maps version: "1.0.0" source: - url: https://github.com/NCAR/VAPOR-Data/archive/refs/tags/1.0.tar.gz build: noarch: generic script: | DEST="$PREFIX/share/images" install -d "$DEST" cp -r images/NaturalEarth* "$DEST" ================================================ FILE: conda/vapor-maps-extra/meta.yaml ================================================ package: name: vapor-maps-extra version: "1.0.0" source: - url: https://github.com/NCAR/VAPOR-Data/archive/refs/tags/1.0.tar.gz build: noarch: generic script: | DEST="$PREFIX/share/images" install -d "$DEST" cp -r images/BigBlueMarble* images/*.tif "$DEST" ================================================ FILE: include/CMakeLists.txt ================================================ ================================================ FILE: include/vapor/Advection.h ================================================ /* * This class performances advection calculations. * It also holds all the particles resulting from an advection. */ #ifndef ADVECTION_H #define ADVECTION_H #include "vapor/Particle.h" #include "vapor/Field.h" #include "vapor/common.h" #include #include namespace flow { class FLOW_API Advection final { public: enum class ADVECTION_METHOD { EULER = 0, RK4 = 1 // Runge-Kutta 4th order }; // Constructor and destructor Advection(); // // Major action functions // // Advect all particles as long as they are within spatial and temporal boundary // for a specified number if steps. int AdvectSteps(Field *velocityField, double deltaT, size_t maxSteps, bool fixedStepSize, ADVECTION_METHOD method = ADVECTION_METHOD::RK4); // Advect as many steps as necessary to reach a certain time: targetT. // Note: it only considers particles that have already passed startT. int AdvectTillTime(Field *velocityField, double startT, double deltaT, double targetT, bool fixedStepSize, ADVECTION_METHOD method = ADVECTION_METHOD::RK4); // Retrieve field values of a particle based on its location, and put the result in // the "value" field or the "properties" field of a particle // If "skipNonZero" is true, then this function only overwrites zeros. // Otherwise, it will overwrite values anyway. int CalculateParticleValues(Field *scalarField, bool skipNonZero); int CalculateParticleIntegratedValues(Field *scalarField, const bool skipNonZero, const float distScale = 1.f, const std::vector &integrateWithinVolumeMin = {-FLT_MAX, -FLT_MAX, -FLT_MAX}, const std::vector &integrateWithinVolumeMax = {FLT_MAX, FLT_MAX, FLT_MAX}); void SetAllStreamValuesToFinalValue(int realNSamples); int CalculateParticleProperties(Field *scalarField); void CalculateParticleHistogram(std::vector &bounds, std::vector &bins); // Reset all particle values to zero void ResetParticleValues(); // Clear all existing properties of a particle void ClearParticleProperties(); // Clear particle property with a certain name. // If the the specified property name does not exist, then nothing is done. void RemoveParticleProperty(const std::string &); // Set advection basics void UseSeedParticles(const std::vector &seeds); // Retrieve the resulting particles as "streams." size_t GetNumberOfStreams() const; const std::vector &GetStreamAt(size_t i) const; // Retrieve the maximum number of particles in any stream size_t GetMaxNumOfPart() const; // Query properties (most are properties of the velocity field) int CheckReady() const; // Specify periodicity, and periodic bounds on each dimension void SetXPeriodicity(bool, float min, float max); void SetYPeriodicity(bool, float min, float max); void SetZPeriodicity(bool, float min, float max); // Retrieve the names of value variable and property variables. auto GetValueVarName() const -> std::string; auto GetPropertyVarNames() const -> std::vector; private: std::vector> _streams; std::string _valueVarName; std::vector _propertyVarNames; const float _lowerAngle, _upperAngle; // Thresholds for step size adjustment float _lowerAngleCos, _upperAngleCos; // Cosine values of the threshold angles std::vector _separatorCount; // how many separators does each stream have. // Useful to determine how many steps are there in a stream. // If the advection is performed in a periodic fashion along one or more dimensions. // These variables are **not** intended to be decided by Advection, but by someone // who's more knowledgeable about the field. std::array _isPeriodic; // is it periodic in X, Y, Z dimensions? std::array _periodicBounds; // periodic boundaries in X, Y, Z dimensions // Advection methods here could assume all input is valid. int _advectEuler(Field *, const Particle &, double deltaT, // Input Particle &p1) const; // Output int _advectRK4(Field *, const Particle &, double deltaT, // Input Particle &p1) const; // Output // Get an adjust factor for deltaT based on how curvy the past two steps are. // A value in range (0.0, 1.0) means shrink deltaT. // A value in range (1.0, inf) means enlarge deltaT. // A value equals to 1.0 means not touching deltaT. float _calcAdjustFactor(const Particle &past2, const Particle &past1, const Particle ¤t) const; // Adjust input "val" according to the bound specified by min and max. // Returns the value after adjustment. float _applyPeriodic(float val, float min, float max) const; // Print return code if it's non-zero and compiled in debug mode. void _printNonZero(int rtn, const char *file, const char *func, int line) const; void _calculateParticleIntegratedValue(Particle &p, const Particle &prev, const Field *scalarField, const bool skipNonZero, const float distScale, const std::vector &integrateWithinVolumeMin, const std::vector &integrateWithinVolumeMax) const; static bool _isParticleInsideVolume(const Particle &p, const std::vector &min, const std::vector &max); }; }; // namespace flow #endif ================================================ FILE: include/vapor/AdvectionIO.h ================================================ /* * Define input/output operations given an Advection. * Specifically, it can read a list of seeds for the advection class to start with, * and also output the trajectory of advectios to a text file. */ #ifndef ADVECTION_IO_H #define ADVECTION_IO_H #include #include "vapor/Advection.h" namespace flow { // Output a certain number of steps from an advection. // When `append == false`, a header will also be output; otherwise, only trajectories are output. FLOW_API auto OutputFlowlinesNumSteps(const Advection *adv, const char *filename, size_t numStep, const std::string &proj4string, bool append) -> int; // Output trajectory to a maximum time. // When `append == false`, a header will also be output; otherwise, only trajectories are output. FLOW_API auto OutputFlowlinesMaxTime(const Advection *adv, const char *filename, double maxTime, const std::string &proj4string, bool append) -> int; // Input a list of seeds from lines of CSVs. // In case of any error occurs, it returns an empty list. FLOW_API auto InputSeedsCSV(const std::string &filename) -> std::vector; }; // namespace flow #endif ================================================ FILE: include/vapor/AnimationParams.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: AnimationParams.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: January 2005 // // Description: Defines the AnimationParams class // This is derived from the Params class // It contains all the parameters required for animation // #ifndef ANIMATIONPARAMS_H #define ANIMATIONPARAMS_H #include //! \class AnimationParams //! \ingroup Public_Params //! \brief A class that specifies parameters used in animation //! \author Alan Norton //! \version 3.0 //! \date February 2014 //! When this class is local, it controls the time-steps in one visualizer. //! The global (shared) AnimationParams controls the animation in any number of visualizers. class PARAMS_API AnimationParams : public VAPoR::ParamsBase { public: enum CaptureMode { SingleImage, TimeSeries }; enum CaptureType { TIFF, PNG }; AnimationParams(ParamsBase::StateSave *ssave); AnimationParams(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node); virtual ~AnimationParams(); //! Identify the current data timestep being used //! \retval long current time step // size_t GetCurrentTimestep() const { return (size_t)GetValueLong(_currentTimestepTag, 0); } //! Set the current data timestep being used //! \param long current time step //! \retval int 0 if successful // void SetCurrentTimestep(size_t ts) { SetValueLong(_currentTimestepTag, "Set timestep", (long)ts); } //! Identify the starting time step currently set in the UI. //! \retval int starting frame number. // size_t GetStartTimestep() const { return (size_t)GetValueLong(_startTimestepTag, 0); } //! set the starting time step //! \param int starting timestep //! \retval int 0 if successful // void SetStartTimestep(size_t ts) { SetValueLong(_startTimestepTag, "Set start timestep", (long)ts); SetValueLong(CaptureStartTag, "Set end timestep for image capture", (long)ts); } //! Identify the ending time step used during playback //! \retval int ending timestep // size_t GetEndTimestep() const { return (size_t)GetValueLong(_endTimestepTag, (long)0); } //! set the ending time step //! \param int ending timestep //! \retval int 0 if success // void SetEndTimestep(size_t val) { SetValueLong(_endTimestepTag, "Set end timestep", (long)val); SetValueLong(CaptureEndTag, "Set end timestep for image capture", (long)val); } //! Get the current play direction //! \retval bool True if playing backwards // bool GetPlayBackwards() const { return GetValueLong(_playBackwardsTag, 0); } //! Set the play direction //! \param int play direction // void SetPlayBackwards(bool val) { SetValueLong(_playBackwardsTag, "Set play direction", (long)val); } //! Determine max frames per second //! \retval double max frames per second // double GetMaxFrameRate() { return GetValueDouble(_maxRateTag, 1.0); } //! Set max frames per second //! \param double fps //! \retval int 0 if successful //! void SetMaxFrameRate(double rate) { SetValueDouble(_maxRateTag, "Set max frame rate", rate); } // Get static string identifier for this params class // static string GetClassType() { return ("AnimationParams"); } public: static const string _maxRateTag; static const string _startTimestepTag; static const string _endTimestepTag; static const string _playBackwardsTag; static const string _currentTimestepTag; static const string CaptureModeTag; static const string CaptureTypeTag; static const string CaptureStartTag; static const string CaptureEndTag; static const string CaptureFileNameTag; static const string CaptureFileDirTag; static const string CaptureFileTimeTag; static const string CaptureTimeSeriesFileNameTag; static const string CaptureTimeSeriesTimeTag; private: //! Put a params instance into default state with no data. void _init(); }; #endif // ANIMATIONPARAMS_H ================================================ FILE: include/vapor/AnnotationParams.h ================================================ //************************************************************************ // * // Copyright (C) 2015 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: AnnotationParams.h // // Author: Scott Pearse // Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: June 2015 // // Description: Defines the AnnotationParams class. // This class supports parameters associted with the // vizfeature panel, describing the visual features in the visualizer // #ifndef ANNOTATIONPARAMS_H #define ANNOTATIONPARAMS_H #include #include #include #include using namespace Wasp; namespace VAPoR { class XmlNode; //! \class AnnotationParams //! \ingroup Public_Params //! \brief A class for describing visual features displayed in the visualizer. //! \author Alan Norton //! \version 3.0 //! \date June 2015 //! The AnnotationParams class controls various features displayed in the visualizers //! There is a global AnnotationParams, that //! is shared by all windows whose vizfeature is set to "global". There is also //! a local AnnotationParams for each window, that users can select whenever there are multiple windows. //! When local settings are used, they only affect one currently active visualizer. //! The AnnotationParams class also has several methods that are useful in setting up data requests from the DataMgr. //! class PARAMS_API AnnotationParams : public ParamsBase { public: //! Create a AnnotationParams object from scratch // AnnotationParams(ParamsBase::StateSave *ssave); //! Create a AnnotationParams object from an existing XmlNode tree // AnnotationParams(ParamsBase::StateSave *ssave, XmlNode *node); //! Copy from already existing instance // AnnotationParams(const AnnotationParams &rhs); virtual ~AnnotationParams(){}; void GetDomainColor(double color[3]) const; void GetDomainColor(std::vector &color) const { _getColor(color, _domainColorTag); } void SetDomainColor(vector color); bool GetUseDomainFrame() const { return (0 != GetValueLong(_domainFrameTag, (long)false)); } void SetUseDomainFrame(bool onOff) { SetValueLong(_domainFrameTag, "toggle domain frame", (long)onOff); } bool GetUseRegionFrame() const { return (0 != GetValueLong(_regionFrameTag, (long)false)); } void SetUseRegionFrame(bool onOff) { SetValueLong(_regionFrameTag, "toggle region frame", (long)onOff); } void GetRegionColor(double color[3]) const; void GetRegionColor(std::vector &color) const { _getColor(color, _regionColorTag); } void SetRegionColor(vector color); void GetBackgroundColor(double color[3]) const; void GetBackgroundColor(std::vector &color) const { _getColor(color, _backgroundColorTag); } void SetBackgroundColor(std::vector color); string GetCurrentAxisDataMgrName() const; void SetCurrentAxisDataMgrName(string dataMgr = "default"); AxisAnnotation *GetAxisAnnotation(); void SetAxisFontSize(int size); int GetAxisFontSize(); double GetTimeLLX() const; void SetTimeLLX(double llx); double GetTimeLLY() const; void SetTimeLLY(double lly); std::vector GetTimeColor() const; template void GetTimeColor(T color[]) const { m_getColor(color, _timeColorTag); }; void SetTimeColor(std::vector color); int GetTimeType() const; void SetTimeType(int type); int GetTimeSize() const; void SetTimeSize(int size); bool GetAxisArrowEnabled() const; double GetAxisArrowSize() const; double GetAxisArrowXPos() const; double GetAxisArrowYPos() const; void SetAxisArrowEnabled(bool enabled); void SetAxisArrowSize(double pos); void SetAxisArrowXPos(double pos); void SetAxisArrowYPos(double pos); static string GetClassType() { return ("AnnotationParams"); } static const string AxisArrowSizeTag; static const string AxisArrowXPosTag; static const string AxisArrowYPosTag; static const string AxisArrowEnabledTag; private: ParamsContainer *_axisAnnotations; public: static const string _domainColorTag; static const string _domainFrameTag; static const string _regionFrameTag; static const string _regionColorTag; static const string _axisColorTag; static const string _axisDigitsTag; static const string _axisTextHeightTag; static const string _axisFontSizeTag; static const string _ticWidthTag; static const string _ticDirsTag; static const string _ticSizeTag; static const string _minTicsTag; static const string _maxTicsTag; static const string _numTicsTag; static const string _axisOriginTag; static const string _backgroundColorTag; static const string _axisAnnotationEnabledTag; static const string _axisAnnotationsTag; static const string _latLonAxesTag; static const string _currentAxisDataMgrTag; static vector _previousStretch; static const string _timeLLXTag; static const string _timeLLYTag; static const string _timeColorTag; static const string _timeTypeTag; static const string _timeSizeTag; static const string _projStringTag; private: void _init(); template void m_getColor(T color[3], string tag) const { vector defaultv(3, 1.0); vector val = GetValueDoubleVec(tag, defaultv); for (int i = 0; i < val.size(); i++) { color[i] = val[i]; if (color[i] < 0.0) color[i] = 0.0; if (color[i] > 1.0) color[i] = 1.0; } } // void m_getColor(double color[3], string tag) const; void _getColor(vector &color, string tag) const; void m_setColor(vector color, string tag, string msg); }; }; // namespace VAPoR #endif // ANNOTATIONPARAMS_H ================================================ FILE: include/vapor/AnnotationRenderer.h ================================================ //-- AnnotationRenderer.h ---------------------------------------------------------- // // Copyright (C) 2011 // University Corporation for Atmospheric Research // All Rights Reserved // //---------------------------------------------------------------------------- // // File: AnnotationRenderer.h // // Author: Alan Norton // // // Description: Definition of AnnotationRenderer class // // // //---------------------------------------------------------------------------- #ifndef ANNOTATIONRENDERER_H #define ANNOTATIONRENDERER_H #include #include #include #include #include namespace VAPoR { class DataStatus; struct GLManager; //! \class AnnotationRenderer //! \brief Class that draws various geometry as specified by AnnotationParams //! \author Alan Norton //! \version 3.0 //! \date July 2015 class RENDER_API AnnotationRenderer : public MyBase { private: struct billboard; public: //! Constructor, must invoke Renderer constructor AnnotationRenderer(const ParamsMgr *pm, const DataStatus *dataStatus, string winName); //! Method to initialize GL rendering. Must be called from a GL context. void InitializeGL(GLManager *glManager); //! Destructor virtual ~AnnotationRenderer(); //! Render the in-scene features void InScenePaint(size_t ts); //! Render the overlay features void OverlayPaint(size_t ts); void AddText(string text, int x, int y, int size, float color[3], int type = 0); void AddTextNormalizedCoords(string text, float x, float y, int size, float color[3], int type = 0); void DrawText(); void DrawText(vector billboards); void ClearText(int type = -1); //! Draw Axis arrows void DrawAxisArrows(); #ifdef VAPOR3_0_0_ALPHA //! Clear all the text objects void invalidateCache(); #endif protected: private: struct billboard { string text; double x; double y; float xn; float yn; int size; float color[3]; }; vector _billboards; vector _timeAnnot; vector _axisAnnot; vector _miscAnnot; const ParamsMgr * m_paramsMgr; const DataStatus *m_dataStatus; string m_winName; GLManager * _glManager; int _currentTimestep; string _fontFile; string _fontName; void _drawAxes(std::vector min, std::vector max, std::vector origin, std::vector color, double width); void _drawTic(double startPosn[], double endPosn[], double width, std::vector color); void _drawTimeAnnotation(); void _makeTransformMatrix(const Transform *transform, glm::mat4 &transformMatrix) const; void _applyDataMgrCornerToDomain(std::vector &domainExtents, const glm::vec4 &dataMgrCorner, const glm::mat4 &transformMatrix) const; void _getDataMgrCorner(const int cornerNumber, glm::vec4 &dataMgrCorner, const CoordType &minDataMgrExtents, const CoordType &maxDataMgrExtents) const; void _applyDataMgrToDomainExtents(std::vector &domainExtents, const CoordType &dataMgrMinExts, const CoordType &dataMgrMaxExts, const Transform *transform) const; void _calculateDomainExtents(std::vector &domainExtents) const; void drawDomainFrame(const std::vector corners) const; std::vector getDomainExtents() const; AxisAnnotation * getCurrentAxisAnnotation(); string getCurrentDataMgrName() const; void scaleNormalizedCoordinatesToWorld(std::vector &coords, string dataMgrName); //! Configure the MVP matrix for drawing axis orientation arrows. These //! arrows are drawn on top of the scene at an X/Y pixel location. Users //! define this location by selecting an X and Y value between 0 and 1, //! which correspond to the minimum and maximum pixel id's on the X and Y //! axes. void _configureMatrixForArrows(MatrixManager *matrixManager); #ifdef VAPOR3_0_0_ALPHA //! Render the region frame void drawRegionBounds(size_t ts) const; #endif // Draw the axis lines, while building text labels. // void drawAxisTics(AxisAnnotation *aa = NULL); void drawAxisTics(AxisAnnotation *aa, std::vector minTic, std::vector maxTic); void applyTransform(Transform *t); void renderText(double text, double coords[], AxisAnnotation *aa = NULL); Transform *getTransform(string dataMgr = ""); void convertPointToLonLat(double &xCoord, double &yCoord); #ifdef VAPOR3_0_0_ALPHA //! Static method to convert axis coordinates between user and lat-lon //! It is OK for outputs to equal corresponding inputs. //! \param[in] toLatLon indicates whether conversion is to LatLon (true) or to user (false) //! \param[in] ticDirs are directions of tics on each axis. //! \param[in] fromMinTic is a 3-vector indicating minimum tic coordinates being mapped. //! \param[in] fromMaxTic is a 3-vector indicating maximum tic coordinates being mapped. //! \param[in] fromOrigin is a 3-vector indicating origin coordinates being mapped. //! \param[in] fromTicLength is a 3-vector indicating tic lengths before conversion //! \param[out] toMinTic is result 3-vector of minimum tic coordinates //! \param[out] toMaxTic is result 3-vector of maximum tic coordinates //! \param[out] toOrigin is result 3-vector of origin coordinates //! \param[out] toTicLength is a 3-vector indicating tic lengths after conversion static void ConvertAxes(bool toLatLon, const vector ticDirs, const vector fromMinTic, const vector fromMaxTic, const vector fromOrigin, const vector fromTicLength, double toMinTic[3], double toMaxTic[3], double toOrigin[3], double toTicLength[3]); // This method converts lon lat to user coords, assuming a "flat" earth so axes will not wrap. static void flatConvertFromLonLat(double x[2], double minLon, double maxLon, double minX, double maxX); #endif }; }; // namespace VAPoR #endif // ANNOTATIONRENDERER_H ================================================ FILE: include/vapor/AnnotationsParams.h ================================================ //************************************************************************ // * // Copyright (C) 2015 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: AnnotationsParams.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: June 2015 // // Description: Defines the AnnotationsParams class. // This class supports parameters associted with the // vizfeature panel, describing the visual features in the visualizer // #ifndef ANNOTATIONSPARAMS_H #define ANNOTATIONSPARAMS_H #include #include #include #include using namespace Wasp; namespace VAPoR { class XmlNode; //! \class AnnotationsParams //! \ingroup Public_Params //! \brief A class for describing visual features displayed in the visualizer. //! \author Alan Norton //! \version 3.0 //! \date June 2015 //! The AnnotationsParams class controls various features displayed in the visualizers //! There is a global AnnotationsParams, that //! is shared by all windows whose vizfeature is set to "global". There is also //! a local AnnotationsParams for each window, that users can select whenever there are multiple windows. //! When local settings are used, they only affect one currently active visualizer. //! The AnnotationsParams class also has several methods that are useful in setting up data requests from the DataMgr. //! class PARAMS_API AnnotationsParams : public ParamsBase { public: //! Create a AnnotationsParams object from scratch // AnnotationsParams(ParamsBase::StateSave *ssave); //! Create a AnnotationsParams object from an existing XmlNode tree // AnnotationsParams(ParamsBase::StateSave *ssave, XmlNode *node); //! Copy from already existing instance // AnnotationsParams(const AnnotationsParams &rhs); virtual ~AnnotationsParams(){}; //! Obtain domain frame color void GetDomainColor(double color[3]) const; void GetDomainColor(std::vector &color) const { _getColor(color, _domainColorTag); } //! Set domain frame color void SetDomainColor(vector color); bool GetUseDomainFrame() const { return (0 != GetValueLong(_domainFrameTag, (long)false)); } void SetUseDomainFrame(bool onOff) { SetValueLong(_domainFrameTag, "toggle domain frame", (long)onOff); } bool GetUseRegionFrame() const { return (0 != GetValueLong(_regionFrameTag, (long)false)); } void SetUseRegionFrame(bool onOff) { SetValueLong(_regionFrameTag, "toggle region frame", (long)onOff); } //! Obtain region frame color void GetRegionColor(double color[3]) const; void GetRegionColor(std::vector &color) const { _getColor(color, _regionColorTag); } //! Set region frame color void SetRegionColor(vector color); //! Obtain background color void GetBackgroundColor(double color[3]) const; void GetBackgroundColor(std::vector &color) const { _getColor(color, _backgroundColorTag); } //! Set background color void SetBackgroundColor(std::vector color); string GetCurrentAxisDataMgrName() const; void SetCurrentAxisDataMgrName(string dataMgr); AxisAnnotation *GetAxisAnnotation(string dataMgr = ""); void SetAxisArrowCoords(std::vector coords); std::vector GetAxisArrowCoords() const; bool GetShowAxisArrows() const; void SetShowAxisArrows(bool val); void SetAxisFontSize(int size); int GetAxisFontSize(); // Get static string identifier for this params class // static string GetClassType() { return ("AnnotationsParams"); } private: #ifdef VAPOR3_0_0_ALPHA static void changeStretch(vector prevStretch, vector newStretch); #endif ParamsContainer *_axisAnnotations; static const string _domainColorTag; static const string _domainFrameTag; static const string _regionFrameTag; static const string _regionColorTag; static const string _axisColorTag; static const string _axisDigitsTag; static const string _axisTextHeightTag; static const string _axisFontSizeTag; static const string _ticWidthTag; static const string _ticDirsTag; static const string _ticSizeTag; static const string _minTicsTag; static const string _maxTicsTag; static const string _numTicsTag; static const string _axisOriginTag; static const string _backgroundColorTag; static const string _axisAnnotationEnabledTag; static const string _axisAnnotationsTag; static const string _latLonAxesTag; static const string _axisArrowCoordsTag; static const string _showAxisArrowsTag; static const string _currentAxisDataMgrTag; static vector _previousStretch; void _init(); void m_getColor(double color[3], string tag) const; void _getColor(vector &color, string tag) const; void m_setColor(vector color, string tag, string msg); }; }; // namespace VAPoR #endif // ANNOTATIONSPARAMS_H ================================================ FILE: include/vapor/ArbitrarilyOrientedRegularGrid.h ================================================ #pragma once #include #include #include #include #include // clang-format off //! A struct that describes a 2D plane that will sample a 3D grid through that grid's extents. //! The 2D plane will have an equal number of samples on its side, determined by sideSize. Users //! will need to define an origin for the 2D plane, as well as its rotation in degrees on the X, Y, //! and Z axes. struct planeDescription { size_t sideSize; std::vector origin; std::vector normal; VAPoR::CoordType boxMin; VAPoR::CoordType boxMax; }; namespace VAPoR { //! Create a 2D RegularGrid that is rotated along an arbitrary orientation. This new grid //! samples a given 3D Grid object along a plane, through that grid's extents. The "planeDescription" //! variable includes parameters that define the 2D plane's origin, rotation, and valid extents. Points on the //! 2D RegularGrid that are outside of the valid extents will be assigned as missingValues. This Grid class //! will always be valid, even if the the plane's description lies outside of the box. In this case, the //! plane will contain all missing values. //! //! Note: The boxMin and boxMax values within the planeDescription should come from //! the current RenderParams' Box class. //! //! \param[in] grid3d A variable's 3D grid to be sampled along a plane, to generate a 2D grid object //! \param[in] description A set of std::vector values that define the origin, rotation, and extents of the returned 2D grid //! \param[in] dims The sampling rate that the new grid will be defined upon, along its X and Y axes //! \param[out] data An array of sideSize*sideSize values that contain floating point values of the sampled data. //! class VDF_API ArbitrarilyOrientedRegularGrid : public RegularGrid { public: ArbitrarilyOrientedRegularGrid( const VAPoR::Grid* grid3d, planeDescription& pd, const DimsType& dims ); ArbitrarilyOrientedRegularGrid() = default; virtual ~ArbitrarilyOrientedRegularGrid(); static std::string GetClassType() { return ("ArbitrarilyOrientedRegular"); } std::string GetType() const override { return (GetClassType()); } //! \copydoc Grid::GetUserCoordinates() // virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override; // Deleted fuctions that use CoordType virtual void GetUserCoordinates (size_t i, size_t j, size_t k, double &x, double &y, double &z) = delete; virtual void GetUserExtents (CoordType &minu, CoordType &maxu) = delete; virtual void GetBoundingBox (const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) = delete; virtual bool GetEnclosingRegion (const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) = delete; virtual bool GetIndicesCell (const CoordType &coords, DimsType &indices) = delete; virtual bool InsideGrid (const CoordType &coords) = delete; virtual void ClampCoord (const CoordType &coords, CoordType &cCoords) = delete; static glm::vec3 GetNormalFromRotations(const std::vector &rotations); static std::pair GetOffsetRange(const planeDescription &pd); private: std::vector> _rectangle2D; size_t _sideSize; glm::tvec3 _normal, _origin, _axis1, _axis2; float* _myBlks; void _makeEmptyGrid(); void _populateData( const VAPoR::Grid *grid, const planeDescription& description ); void _getMinimumAreaRectangle( const std::vector>& vertices ); void _findIntercepts( const VAPoR::CoordType& boxMin, const VAPoR::CoordType& boxMax, std::vector> &vertices ); glm::tvec3 _getOrthogonal( const glm::tvec3& u ); void _rotate(); }; }; // namespace VAPoR // clang-format on ================================================ FILE: include/vapor/AxisAnnotation.h ================================================ #ifndef AXISANNOTATION_H #define AXISANNOTATION_H /* * This class describes a viewpoint */ #include namespace VAPoR { //! \class AxisAnnotation //! \ingroup Public_Params //! \brief class that indicates location and direction of view //! \author Scott Pearse //! \version 3.0 //! \date January 2018 //! \par //! This class contains all the parameters associated with axis annotations, //! for a DataMgr or Renderer. class PARAMS_API AxisAnnotation : public ParamsBase { public: enum Flags {}; AxisAnnotation(ParamsBase::StateSave *ssave); AxisAnnotation(ParamsBase::StateSave *ssave, XmlNode *node); virtual ~AxisAnnotation(); void Initialize(); void SetAxisAnnotationEnabled(bool val); bool GetAxisAnnotationEnabled() const; vector GetAxisBackgroundColor() const; void GetAxisBackgroundColor(float bgColor[]) const; void SetAxisBackgroundColor(vector color); vector GetAxisColor() const; void SetAxisColor(vector color); void SetNumTics(vector ticnums); vector GetNumTics() const; void SetAxisOrigin(vector orig); vector GetAxisOrigin() const; void SetMinTics(vector ticmins); vector GetMinTics() const; void SetMaxTics(vector ticmaxs); vector GetMaxTics() const; void SetTicSize(vector ticsizes); vector GetTicSize() const; void SetXTicDir(double dir); int GetXTicDir() const; void SetYTicDir(double dir); int GetYTicDir() const; void SetZTicDir(double dir); int GetZTicDir() const; void SetTicDirs(vector ticdirs); vector GetTicDirs() const; double GetTicWidth() const; void SetTicWidth(double val); long GetAxisTextHeight() const; void SetAxisTextHeight(long val); long GetAxisDigits() const; void SetAxisDigits(long val); void SetLatLonAxesEnabled(bool val); bool GetLatLonAxesEnabled() const; string GetDataMgrName() const; void SetDataMgrName(string dataMgr); bool GetShowAxisArrows() const; void SetShowAxisArrows(bool val); void SetAxisFontSize(int size); int GetAxisFontSize() const; bool GetAxisAnnotationInitialized() const; void SetAxisAnnotationInitialized(bool val); static string GetClassType() { return ("AxisAnnotation"); } static const string _colorTag; static const string _digitsTag; static const string _textHeightTag; static const string _fontSizeTag; static const string _ticWidthTag; static const string _ticDirsTag; static const string _ticSizeTag; static const string _minTicsTag; static const string _maxTicsTag; static const string _numTicsTag; static const string _originTag; static const string _backgroundColorTag; static const string _annotationEnabledTag; static const string _latLonAxesTag; static const string _dataMgrTag; static const string _initializedTag; }; }; // namespace VAPoR #endif // AXISANNOTATION_H ================================================ FILE: include/vapor/BOVCollection.h ================================================ #pragma once #include #include #include #include #include namespace VAPoR { class BOVCollection : public Wasp::MyBase { public: enum class parseCodes { PARSE_ERROR = -1, NOT_FOUND = 0, FOUND = 1 }; BOVCollection(); int Initialize(const std::vector &paths); std::vector GetDataVariableNames() const; std::string GetTimeDimension() const; std::vector GetUserTimes() const; float GetUserTime(size_t ts) const { return GetUserTimes()[ts]; }; std::array GetDataSize() const; std::array GetSpatialDimensions() const; DC::XType GetDataFormat() const; std::array GetBrickOrigin() const; std::array GetBrickSize() const; template int ReadRegion(std::string varname, size_t ts, const std::vector &min, const std::vector &max, T region); private: std::string _currentFilePath; float _time; std::vector _times; std::string _dataFile; std::vector _dataFiles; std::array _gridSize; DC::XType _dataFormat; std::string _variable; std::vector _variables; std::array _brickOrigin; std::array _brickSize; size_t _byteOffset; // These values are currently parsed and assigned, but are unimplemented (not used) bool _divideBrick; std::string _dataEndian; std::string _centering; int _dataComponents; std::array _dataBricklets; // Placeholder variables to store values read from BOV descriptor files. // These values must be consistent among BOV files, and are validated before // assigning to "actual" values such as _gridSize, declaired above. DC::XType _tmpDataFormat; std::array _tmpBrickOrigin; std::array _tmpBrickSize; size_t _tmpByteOffset; // Note - _tmpGridSize is an array of int type // - _gridSize is of type size_t // The reason for this is when we caluclate data indices like so... // // int xSize = INT_MAX // int ySize = INT_MAX // int zSize = INT_MAX // size_t index = xSize*ySize*zSize; // // ...the rvalue causes integer overflow. // // _tmpGridSize cannot be an array of size_t because users may write // negative values. The parser uses std::stringstream to convert // strings to different datatypes. Unfortunately it does not fail when // converting negative string values such as "-10" to a size_t. Rather, // it converts "-10" to a large positive value". // // Therefore, we read the values in with _tmpGridSize as integers, // and then assign the integers to _gridSize if validation passes. // (Validation in this case: ensure non-negative values, and consistency across files) std::array _tmpGridSize; bool _gridSizeAssigned; bool _formatAssigned; bool _brickOriginAssigned; bool _brickSizeAssigned; bool _byteOffsetAssigned; // _dataFileMap allows us to access binary data files with a // varname/timestep pair std::map> _dataFileMap; std::array _spatialDimensions; int _validateParsedValues(); std::string _timeDimension; int _parseHeader(std::ifstream &header); int _populateDataFileMap(); template int _findToken(const std::string &token, std::string &line, T &value, bool verbose = false); template int _findToken(const std::string &token, std::string &line, std::array &value, bool verbose = false); void _findTokenValue(std::string &line) const; int _sizeOfFormat(DC::XType) const; int _invalidVarNameError() const; int _invalidFileSizeError(size_t numElements) const; int _invalidFileError() const; int _invalidDimensionError(const std::string &token) const; int _invalidFormatError(const std::string &token) const; int _failureToReadError(const std::string &token) const; int _inconsistentValueError(const std::string &token) const; int _invalidValueError(const std::string &token) const; int _missingValueError(const std::string &token) const; static const std::string TIME_TOKEN; static const std::string DATA_FILE_TOKEN; static const std::string GRID_SIZE_TOKEN; static const std::string FORMAT_TOKEN; static const std::string VARIABLE_TOKEN; static const std::string ORIGIN_TOKEN; static const std::string BRICK_SIZE_TOKEN; static const std::string OFFSET_TOKEN; // These tokens are currently parsed but are not used static const std::string ENDIAN_TOKEN; static const std::string CENTERING_TOKEN; static const std::string DIVIDE_BRICK_TOKEN; static const std::string DATA_BRICKLETS_TOKEN; static const std::string DATA_COMPONENTS_TOKEN; static const double _defaultTime; static const std::string _defaultFile; static const DC::XType _defaultFormat; static const std::string _defaultVar; static const size_t _defaultByteOffset; static const std::array _defaultOrigin; static const std::array _defaultBrickSize; static const std::array _defaultGridSize; // These defaults are currently unimplemented in the BOV reader logic static const std::string _defaultEndian; static const std::string _defaultCentering; static const bool _defaultDivBrick; static const std::array _defaultBricklets; static const size_t _defaultComponents; static const std::string _xDim; static const std::string _yDim; static const std::string _zDim; static const std::string _timeDim; static const std::string _byteFormatString; static const std::string _shortFormatString; static const std::string _intFormatString; static const std::string _floatFormatString; static const std::string _doubleFormatString; }; // Make gcc happy by moving template specialization outside of the class body // template<> int BOVCollection::_findToken(const std::string &token, std::string &line, DC::XType &value, bool verbose); } // namespace VAPoR ================================================ FILE: include/vapor/BarbParams.h ================================================ #ifndef BARBPARAMS_H #define BARBPARAMS_H #include #include namespace VAPoR { //! \class BarbParams //! \brief Class that supports drawing Barbs based on 2D or 3D vector field //! \author Scott Pearse //! \version 3.0 //! \date June 2017 class PARAMS_API BarbParams : public RenderParams { public: BarbParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave); BarbParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node); virtual ~BarbParams(); bool GetNeedToRecalculateScales() const { return (bool)GetValueDouble(_needToRecalculateScalesTag, 0.0); } void SetNeedToRecalculateScales(bool val); //! Get the length scaling factor //! \retval double scale factor // double GetLengthScale() const { return GetValueDouble(_lengthScaleTag, 1.f); } void SetLengthScale(double val) { SetValueDouble(_lengthScaleTag, "Barb length", val); } //! Determine the size of the discrete grid //! E.g. the grid on which barbs are placed. //! \retval vector grid const vector GetGrid() const { vector dims(3); dims[0] = GetValueLong(_xBarbsCountTag, 10); dims[1] = GetValueLong(_yBarbsCountTag, 10); dims[2] = GetValueLong(_zBarbsCountTag, 1); return dims; } //! Specify the size of a discrete grid //! E.g. the grid on which barbs are placed. //! \param[in] int array of size 3 - Specifies the barb distribution on the X, Y, and Z axes. void SetGrid(const int grid[3]) { SetValueLong(_xBarbsCountTag, "", grid[0]); SetValueLong(_yBarbsCountTag, "", grid[1]); SetValueLong(_zBarbsCountTag, "", grid[2]); } //! Query line thickness as a multiplier that's applied to the default value. //! \retval double line thickness. double GetLineThickness() const { return GetValueDouble(_thicknessScaleTag, 1.f); } //! Set line thickness as a multiplier that's applied to the default value. //! \param[in] double - Line thickness. void SetLineThickness(double val) { SetValueDouble(_thicknessScaleTag, "Barb thickness", val); } // Get static string identifier for this params class // static string GetClassType() { return ("BarbParams"); } //! \copydoc RenderParams::GetRenderDim() // virtual size_t GetRenderDim() const override { for (const auto &p : GetFieldVariableNames()) { if (!p.empty()) return _dataMgr->GetVarTopologyDim(p); } return GetBox()->IsPlanar() ? 2 : 3; } //! \copydoc RenderParams::GetActualColorMapVariableName() virtual string GetActualColorMapVariableName() const override { if (UseSingleColor()) return ""; else return GetColorMapVariableName(); } protected: virtual bool GetUseSingleColorDefault() const override { return true; } private: void _init(); public: static const string _needToRecalculateScalesTag; static const string _lengthScaleTag; static const string _thicknessScaleTag; //! Number of barbs displayed on X axis static const string _xBarbsCountTag; //! Number of barbs displayed on Y axis static const string _yBarbsCountTag; //! Number of barbs displayed on Z axis static const string _zBarbsCountTag; static const string _alignGridTag; static const string _alignGridStridesTag; static const string _varsAre3dTag; }; // End of Class BarbParams }; // namespace VAPoR #endif ================================================ FILE: include/vapor/BarbRenderer.h ================================================ //************************************************************** // // Copyright (C) 2017 // University Corporation for Atmospheric Research // All Rights Reserved // // ************************************************************* #ifndef VAPOR_BARBRENDERER_H #define VAPOR_BARBRENDERER_H #include // Must be included first!!! #include #include #include #include #include namespace VAPoR { //! \class BarbRenderer //! \brief Class that draws the barbs as specified by BarbParams //! \author Scott Pearse and Alan Norton //! \version 3.0 //! \date June 2017 class RENDER_API BarbRenderer : public Renderer { public: BarbRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr); virtual ~BarbRenderer(); static string GetClassType() { return ("Barb"); } protected: virtual std::string _getColorbarVariableName() const; private: vector _fieldVariables; // old, used instead of _currentVarname double _vectorScaleFactor; double _maxThickness; vector _currentBoxMinExts; vector _currentBoxMaxExts; string _currentHgtVar; vector _currentBoxMinExtsTex; vector _currentBoxMaxExtsTex; double _maxValue; void _getMagnitudeAtPoint(std::vector variables, float point[3]); void _recalculateScales(std::vector &varData, int ts); double _getDomainHypotenuse(size_t ts) const; void _setDefaultLengthAndThicknessScales(size_t ts, const std::vector &varData, const BarbParams *bParams); void _getGridRequirements(int &ts, int &refLevel, int &lod, CoordType &minExts, CoordType &maxExts) const; //! \copydoc Renderer::_initializeGL() virtual int _initializeGL(); //! \copydoc Renderer::_paintGL() virtual int _paintGL(bool fast); int _generateBarbs(); int _getVectorVarGrids(int ts, int refLevel, int lod, CoordType minExts, CoordType maxExts, std::vector &varData); int _getVarGrid(int ts, int refLevel, int lod, string varName, CoordType minExts, CoordType maxExts, std::vector &varData); void _setUpLightingAndColor(); void _reFormatExtents(vector &rakeExts) const; void _makeRakeGrid(vector &rakeGrid) const; //! Protected method that performs rendering of all barbs. //! \param[in] DataMgr* current DataMgr //! \param[in] const BarbParams* associated BarbParams //! \param[in] int actualRefLevel refinement level to be rendered. //! \param[in] float vectorScale Scale factor to be applied to barbs. //! \param[in] float barbRadius Radius of barbs in voxel diameters. //! \param[in] Grid Grid used in rendering. //! The first three are the vector field, Grid[3] is the Height variable, Grid[4] is the color variable. //! \retval int zero if successful // int performRendering(BarbParams* rParams, // int actualRefLevel, // vector variableData // ); float _getHeightOffset(Grid *heightVar, float xCoord, float yCoord, bool &missing) const; bool _makeCLUT(float clut[1024]) const; void _getDirection(float direction[3], std::vector varData, float xCoord, float yCoord, float zCoord, bool &missing) const; vector _getScales(); float _calculateLength(float start[3], float end[3]) const; void _makeStartAndEndPoint(float start[3], float end[3], float direction[3]); void _getStrides(vector &strides, vector &rakeGrid, vector &rakeExts) const; bool _defineBarb(const std::vector, float start[3], float end[3], float *value, bool doColorMapping, const float clut[1024]); void _operateOnGrid(vector variableData, bool drawBarb = true); bool _getColorMapping(float val, const float clut[256 * 4]); float _calculateDirVec(const float start[3], const float end[3], float dirVec[3]); void _drawBackOfBarb(const float dirVec[3], const float startVertex[3]) const; void _drawCylinderSides(const float nextNormal[3], const float nextVertex[3], const float startNormal[3], const float startVertex[3]) const; void _drawBarbHead(const float dirVec[3], const float vertexPoint[3], const float startNormal[3], const float startVertex[3]) const; //! Protected method to draw one barb (a hexagonal tube with a cone barbhead) //! \param[in] const float startPoint[3] beginning position of barb //! \param[in] const float endPoint[3] ending position of barb // void drawBarb(const float startPoint[3], const float endPoint[3]); void _drawBarb(const std::vector variableData, const float startPoint[3], bool doColorMapping, const float clut[1024]); void _setBarbColor(float value, const float clut[1024], double crange[2]) const; struct Barb; void _drawBarb(Barb b, bool doColorMapping, const float clut[1024], double crange[2]); #ifdef DEBUG _printBackDiameter(const float startVertex[18]) const; #endif struct { vector fieldVarNames; string heightVarName; string colorVarName; size_t ts; int level; int lod; bool useSingleColor; float constantColor[3]; double lineThickness; double opacity; double lengthScale; vector grid; vector boxMin, boxMax; float minMapValue; float maxMapValue; float colorSamples[10][3]; float alphaSamples[10]; bool needToRecalc; } _cacheParams; bool _isCacheDirty() const; void _saveCacheParams(); void _clearCache() { _cacheParams.fieldVarNames.clear(); } struct Barb { float startPoint[3]; float endPoint[3]; float value; float lengthScalar; }; vector _barbCache; }; }; // namespace VAPoR #endif // VAPOR_BARBRENDERER_H ================================================ FILE: include/vapor/Base16StringStream.h ================================================ #pragma once #include #include #include #include #include //! \class Base16StreamBuf //! //! \brief A custom std stream buffer that saves data piped through it into a base16 encoded string. //! //! \author Stanislaw Jaroszynski class COMMON_API Base16StreamBuf : public std::streambuf { public: std::string _string; int _i = 0; virtual int_type overflow(int_type c) override; }; //! \class Base16StringStream //! //! \brief An implementation similar to std::stringstream which results in a base16 encoded string. //! //! \author Stanislaw Jaroszynski class COMMON_API Base16StringStream : public std::ostream { Base16StreamBuf _buf; public: Base16StringStream() : std::ostream(&_buf) {} const std::string &ToString() { return _buf._string; } }; //! \class Base16DecoderStream //! //! \brief Creates a raw std istream from a base16 encoded string. //! //! \author Stanislaw Jaroszynski class COMMON_API Base16DecoderStream : public std::istream { struct MemBuf : std::streambuf { MemBuf(char *buf, size_t size) { this->setg(buf, buf, buf + size); } }; static void Base16Decode(const std::string &in, char *out); std::unique_ptr _data; MemBuf _buf; public: Base16DecoderStream(const std::string &s); }; ================================================ FILE: include/vapor/BlkMemMgr.h ================================================ // // $Id$ // #ifndef _BlkMemMgr_h_ #define _BlkMemMgr_h_ #include namespace VAPoR { // //! \class BlkMemMgr //! \brief The Wasp BlkMemMgr class //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! A block-based memory allocator. Allocates contiguous runs of //! memory blocks from a memory pool of user defined size. //! //! N.B. the memory pool is stored in a static class member and //! can only be freed by calling RequestMemSize() with a zero value //! after all instances of this class have been destroyed // class BlkMemMgr : public Wasp::MyBase { public: //! Initialize a memory allocator // //! Initialize a block-based memory allocator // BlkMemMgr(); virtual ~BlkMemMgr(); //! Alloc space from memory pool // //! Return a pointer to the specified amount of memory from the memory pool //! \param[in] num_blks Size of memory region requested in blocks //! \param[in] fill If true, the allocated memory will be cleared to zero //! \retval ptr A pointer to the requested memory pool // void *Alloc(size_t num_blks, bool fill = false); //! Free memory // //! Frees memory previosly allocated with the \b Alloc() method. //! \param[in] ptr Pointer to memory returned by previous call to //! \b Alloc(). void FreeMem(void *ptr); //! Set the size of the memory pool used by the memory allocator // //! Initialize a block-based memory allocator. The static memory pool //! is not changed until the first instance of an object of this //! class is created, or if there are no instances of objects the //! memmory pool is changed immediately. The only way to free memory //! from the static memory pool is to call this static method with //! either \p blk_size or \p num_blks set to zero. //! //! \param[in] blk_size Size of a single memory block in bytes //! \param[in] num_blks Size of memory pool in blocks. This is the //! maximum amount that will be available through subsequent //! \b Alloc() calls. //! \param[in] page_aligned If true, start address of memory pool //! will be page aligned // static int RequestMemSize(size_t blk_size, size_t num_blks, bool page_aligned = true); static size_t GetBlkSize() { return (_blk_size); } private: typedef struct { size_t _nfree; // number of contiguous free blocks size_t _nused; // number of contiguous used blocks void * _blk; // pointer to first free/used block } _mem_allocation_t; static vector> _mem_regions; static vector _mem_region_sizes; // size of mem in blocks static vector _blks; // memory pool static size_t _mem_size_max_req; // max requested size of mem in blocks static bool _page_aligned_req; // requested page align memory static size_t _blk_size_req; // requested size of block in bytes static size_t _mem_size_max; // max size of mem in blocks static bool _page_aligned; // page align memory static size_t _blk_size; // size of block in bytes static int _ref_count; // # instances of object. static int _Reinit(size_t n); }; }; // namespace VAPoR #endif // _BlkMemMgr_h_ ================================================ FILE: include/vapor/BookmarkParams.h ================================================ //************************************************************************ // * // Copyright (C) 2016 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: BookmarkParams // // Author: Stas Jaroszynski // National Center for Atmospheric Research // PO 3000, Boulder, Colorado #pragma once #include class MouseModeParams; class PARAMS_API BookmarkParams : public VAPoR::ParamsBase { public: BookmarkParams(VAPoR::ParamsBase::StateSave *ssave); BookmarkParams(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node); BookmarkParams(const BookmarkParams &rhs); static string GetClassType() { return ("BookmarkParams"); } static const string NameTag; static const string DataTag; static const string IconDataTag; static const string IconSizeTag; void SetName(const string &name) { SetValueString(NameTag, "", name); } string GetName() const { return GetValueString(NameTag, ""); } void SetData(const string &data) { SetValueString(DataTag, "", data); } string GetData() const { return GetValueString(DataTag, ""); } string GetIconData() const { return GetValueString(IconDataTag, ""); } int GetIconSize() const { return GetValueLong(IconSizeTag, 0); } size_t GetIconDataSize() const { size_t s = GetIconSize(); return s * s * 3; } void SetIcon(int size, const string &data) { SetIconData(data); SetIconSize(size); } static int DefaultIconSize() { return 32; } private: void SetIconData(const string &data) { SetValueString(IconDataTag, "", data); } void SetIconSize(int size) { SetValueLong(IconSizeTag, "", size); } void _init(); }; ================================================ FILE: include/vapor/Box.h ================================================ //************************************************************************ // * // Copyright (C) 2011 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: Box.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: April 2011 // // Description: Defines the Box class // This supports control of a 2D or 3D box-shaped region that can be // rotated and changed over time. // #ifndef BOX_H #define BOX_H #include #include namespace VAPoR { //! \class Box //! \ingroup Public_Params //! \brief 3D or 2D box with options for orientation angles . //! \author Alan Norton //! \version 3.0 //! \date March 2014 //! The Box class supports various rectangular boxes, possibly rotated, //! used in VAPOR to specify extents and also used in Manipulators. //! class PARAMS_API Box : public ParamsBase { public: enum Orientation { XY = 0, XZ = 1, YZ = 2, XYZ = 3 }; //! Create a Box object from scratch // Box(ParamsBase::StateSave *ssave, string name = Box::GetClassType()); //! Create a Box object from an existing XmlNode tree // Box(ParamsBase::StateSave *ssave, XmlNode *node); virtual ~Box(); //! Set the box min and max extents //! //! Set the extents of the box. //! //! \param[in] minExt 2 or 3-element vector containing the minimum coordinates //! of the box, specified in the order X, Y, Z //! \param[in] maxExt 2 or 3-element vector containing the maximum coordinates //! of the box, specified in the order X, Y, Z //! // virtual void SetExtents(const vector &minExt, const vector &maxExt); virtual void SetExtents(const VAPoR::CoordType &minExt, const VAPoR::CoordType &maxExt); //! Get the box min and max extents //! //! Get the box's coordinate extents. If IsPlanar() is true a 2-element //! array is returned for \p minExt and \p maxExt, if false a //! 3-element array is returned. //! //! \param[out] minExt 2 or 3-element vector containing the minimum //! coordinates //! of the box, specified in the order X, Y, Z //! \param[out] maxExt 2 or 3-element vector containing the //! maximum coordinates //! of the box, specified in the order X, Y, Z //! //! \sa IsPlanar(), GetOrientation(), SetExtents() // void GetExtents(vector &minExt, vector &maxExt) const; void GetExtents(VAPoR::CoordType &minExt, VAPoR::CoordType &maxExt) const; //! Indicate whether or not the box is constrained to be planar. //! //! \retval bool True if the box is planar //! //! \sa GetOrientation() // bool IsPlanar() const; //! Constain the box to be planar or not //! //! Set the value of the planar state, indicating whether or not //! the box is constrained to be planar. //! //! \param[in] value bool indicates whether or be planar //! //! \sa SetExtents() // void SetPlanar(bool value); //! Indicate the orientation of a (2D) box //! This is 0,1, or 2 based on the axis orthogonal to the box. //! A 0 indiciates the XY plane, 1 indicates the XZ plane, and 2 YZ plane //! axis. //! //! \retval int The plane that the box resides in, if planar. Otherwise //! the return value is meaningless. //! //! \sa IsPlanar() // int GetOrientation() const { return GetValueLong(Box::m_orientationTag, XY); } //! Set the value of the orientation state, indicating the axis //! orthogonal to a 2D box //! //! \param[in] value long indicates the orientation value //! //! \sa IsPlanar(), GetOrientation() // void SetOrientation(long value) { SetValueLong(Box::m_orientationTag, "Set box orientation", (long)value); } #if 0 //! Get the stretched local box extents as a float array. If timestep is >= 0, then get it just //! for the specified timestep //! \param[out] extents[6] float Returned extents //! \param[in] timestep int Specific time step being retrieved, or -1 for generic time steps //! \retcode int zero if successful. int GetStretchedLocalExtents(double extents[6], int timestep = -1); //! Get the local box extents as a vector. First 6 values are default; additional //! values are associated with non-default regions //! \sa GetTimes() //! //! \param[out] extents const vector& returned extents vector GetLocalExtents() const { const vector localExtents(6, 0); return GetValueDoubleVec(_extentsTag, localExtents); } //! Specify the local extents. If time step is -1, then set the generic extents. //! Otherwise set the extents for a specific timestep. //! \param[in] extents vector& Six doubles that will be new extents //! \param[in] timestep int Specified time step, or -1 for generic times //! \retval int zero if successful. void SetLocalExtents(const vector& extents, int timestep = -1); void SetLocalExtents( const vector& minExt, const vector& maxExt, int timestep = -1 ) { VAssert(minExt.size() == maxExt.size() && minExt.size() == 3); vector extents = minExt; extents.insert(extents.end(), maxExt.begin(), maxExt.end()); SetLocalExtents(extents, timestep); } //! Specify the local extents as a double array. If time step is -1, then set the generic extents. //! Otherwise set the extents for a specific timestep. //! \param[in] double extents[6] 6 doubles that will be new extents //! \param[in] int timestep specified time step, or -1 for generic times //! \retval int zero if successful. void SetLocalExtents(const double extents[6], int timestep = -1); //! Specify the local extents as a float array. If time step is -1, then set the generic extents. //! Otherwise set the extents for a specific timestep. //! \param[in] float extents[6] //! \param[in] int timestep specified time step, or -1 for generic times //! \retval int zero if successful. void SetLocalExtents(const float extents[6], int timestep = -1); #endif #if 0 //! Specify the stretched local extents as a float array. If time step is -1, then set the generic extents. //! Otherwise set the extents for a specific timestep. //! \param[in] float extents[6] //! \param[in] int timestep specified time step, or -1 for generic times //! \retval int zero if successful. void SetStretchedLocalExtents(const double extents[6], int timestep = -1); #endif //! Get the three orientation angles (theta, phi, psi) //! Defaults to empty vector if no angles are set. //! \retval const vector vector of length 3 of angles. vector GetAngles() const { const vector defaultAngles(3, 0.); return GetValueDoubleVec(Box::m_anglesTag, defaultAngles); } #if 0 //! Get the angles as a double array //! \param [out] double angles[3] array of three doubles for theta, phi, psi //! \retval int zero if successful void GetAngles(double ang[3]){ const vector angv = GetAngles(); for (int i=0; i<3; i++) ang[i] = angv[i]; } //! Get the angles as a float array //! \param [out] angles[3] float array of three floats for theta, phi, psi //! \retval zero if successful void GetAngles(float ang[3]){ const vector angv = GetAngles(); for (int i=0; i<3; i++) ang[i] = angv[i]; } #endif //! Set the angles from a double array //! \param [in] ang double[3] array of three doubles for theta, phi, psi //! \retval int zero on success void SetAngles(const double angles[3]) { vector ang; for (int i = 0; i < 3; i++) ang.push_back(angles[i]); SetValueDoubleVec(m_anglesTag, "change box angles", ang); } //! Set the angles from a float array //! \param [in] angles float[3] array of three floats for theta, phi, psi //! \retval int zero on success void SetAngles(const float angles[3]) { vector angl; for (int i = 0; i < 3; i++) angl.push_back((double)angles[i]); SetValueDoubleVec(m_anglesTag, "change box angles", angl); } //! Set the three orientation angles (theta, phi, psi) from a vector of doubles //! \param[in] vals const vector& vector of length 3 of angles. void SetAngles(const vector &vals) { SetValueDoubleVec(m_anglesTag, "Change box angles", vals); } #if 0 //! Get the time(s) as a long vector. //! The first one should be negative, marking the default extents. //! Subsequent times are nonnegative integers indicating times for nondefault extents. //! Number of times should be 1/6 of the number of extents values //! \sa GetExtents() //! \retval vector& vector of longs const vector GetTimes() { return( GetValueLongVec(Box::_timesTag)); } //! Set the time(s) as a long vector. //! The first one should be negative, marking the default extents. //! Subsequent times are nonnegative integers indicating times for nondefault extents. //! This vector should be the same size as the extents vector. //! \param [in] const vector& vector of times void SetTimes(const vector& times) { SetValueLongVec(Box::_timesTag, "Change box times",times); } void buildLocalCoordTransform( double transformMatrix[12], double extraThickness, int timestep, double rotation = 0., int axis= -1 ) const; #endif // Get static string identifier for this params class // static string GetClassType() { return ("BoxParams"); } private: #if 0 //! method supports rotated boxes such as probe //! Specifies an axis-aligned box containing the rotated box. //! By default it just finds the box extents. //! Caller must supply extents array, which gets its values filled in. //! \param[out] float[6] Extents of containing box //! \params[in] rotated indicates if the box is possibly rotated void calcContainingBoxExtents( double extents[6], bool rotated = false ) const { if (!rotated) GetLocalExtents(extents,-1); else calcRotatedBoxExtents(extents); } //! If the box is rotated, this method calculated the minimal axis-aligned extents //! containing all 8 corners of the box. //! \param[out] double extents[6] is smallest extents containing the box. void calcRotatedBoxExtents(double extents[6]) const; //! method supports rotated boxes such as probe //! Specifies an axis-aligned box containing the stretched rotated box. //! By default it just finds the box extents. //! Caller must supply extents array, which gets its values filled in. //! \param[out] float[6] Extents of containing box //! \params[in] rotated indicates if the box is possibly rotated void calcContainingStretchedBoxExtents( double extents[6], bool rotated = false ) const { VAssert( ! rotated); if (!rotated) GetStretchedLocalExtents(extents,-1); //else calcRotatedStretchedBoxExtents(extents); } //! If the box is rotated, this method calculated the minimal axis-aligned extents //! of a stretched box containing all 8 corners of the box. //! \param[out] double extents[6] is smallest extents containing the box. void calcRotatedStretchedBoxExtents( vector stretchFactors, double extents[6] ) const; //Used only by params with rotated boxes: bool cropToBox(const double boxExts[6]); bool intersectRotatedBox(double boxexts[6], double pointFound[3], double probeCoords[2]); bool fitToBox(const double boxExts[6]); void setBoxToExtents(const double extents[6]); int interceptBox(const double boxExts[6], double intercept[6][3]); void getRotatedVoxelExtents(string varname, float voxdims[2], int numRefinements); void rotateAndRenormalize(int axis, double rotVal); ///@} void convertThetaPhiPsi( double *newTheta, double* newPhi, double* newPsi, int axis, double rotation ) const; //Not part of public API void calcLocalBoxCorners( double corners[8][3], float extraThickness, int timestep, double rotation = 0., int axis = -1 ) const ; #endif public: static const string m_anglesTag; static const string m_extentsTag; static const string m_planarTag; static const string m_orientationTag; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/CFuncs.h ================================================ // // $Id$ // //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: Mon Nov 29 11:49:03 MST 2004 // // Description: A collection of common C system routines that // aren't always portable across OS platforms // #ifndef _CFuncs_h_ #define _CFuncs_h_ #include #include #include namespace Wasp { COMMON_API void Splitpath(std::string path, std::string &volume, std::string &dir, std::string &file, bool nofile); COMMON_API double GetTime(); COMMON_API int MkDirHier(const std::string &dir); COMMON_API std::string GetEnvironmentalVariable(const std::string &name); }; // namespace Wasp #endif // _CFuncs_h_ ================================================ FILE: include/vapor/CMakeConfig.h ================================================ #ifndef CMAKECONFIG_H #define CMAKECONFIG_H #include #define CMakeConfigStringType std::string extern const int MAJOR; extern const int MINOR; extern const int MICRO; extern const CMakeConfigStringType VERSION_RC; extern const CMakeConfigStringType VERSION_DATE; extern const CMakeConfigStringType VERSION_COMMIT; extern const CMakeConfigStringType VERSION_STRING; extern const CMakeConfigStringType VERSION_STRING_FULL; extern const CMakeConfigStringType BUILD_TYPE; extern const CMakeConfigStringType SOURCE_DIR; extern const CMakeConfigStringType THIRD_PARTY_DIR; extern const CMakeConfigStringType PYTHON_VERSION; extern const CMakeConfigStringType PYTHON_DIR; extern const CMakeConfigStringType PYTHON_PATH; #endif ================================================ FILE: include/vapor/CalcEngineMgr.h ================================================ #pragma once #include #include namespace VAPoR { class DataStatus; class ParamsMgr; class PyEngine; class ControlExec; //! \class CalcEngineMgr //! \brief A class for managing CalcEngine class instances //! \author John Clyne // class RENDER_API CalcEngineMgr : public Wasp::MyBase { public: //! Constructor for CalcEngineMgr class //! //! \param[in] dataMgr A pointer to a DataMgr instance upon which derived //! variables created by this class will be managed. // CalcEngineMgr(DataStatus *dataStatus, ParamsMgr *paramsMgr) { VAssert(dataStatus != NULL); VAssert(paramsMgr != NULL); _dataStatus = dataStatus; _paramsMgr = paramsMgr; } ~CalcEngineMgr(); int AddFunction(string scriptType, string dataSetName, string scriptName, string script, const vector &inputVarNames, const vector &outputVarNames, const vector &outputVarMeshes, bool coordFlag = false); void RemoveFunction(string scriptType, string dataSetName, string scriptName); bool GetFunctionScript(string scriptType, string datasetName, string scriptName, string &script, vector &inputVarNames, vector &outputVarNames, vector &outputVarMeshes, bool &coordFlag); string GetFunctionStdout(string scriptType, string dataSetName, string scriptName); std::vector GetFunctionNames(string scriptType, string datasetName); //! Rebuild from params database //! //! When invoked this method rebuilds internal state using the ParamsMgr //! \p paramsMgr passed in to the constructor // void ReinitFromState(); //! Remove all functions added with AddFunction() //! //! \sa AddFunction() void Clean() { _clean(); } void SyncWithParams(); private: const DataStatus *_dataStatus; const ParamsMgr * _paramsMgr; CalcEngineMgr() {} void _clean(); void SetCacheDirty() { _isDataCacheDirty = true; _wasCacheDirty = true; } std::map _pyScripts; bool _isDataCacheDirty; bool _wasCacheDirty; friend class ControlExec; }; }; // namespace VAPoR ================================================ FILE: include/vapor/ColorMap.h ================================================ //--ColorMap.h --------------------------------------------------------- // // Copyright (C) 2006 Kenny Gruchalla. All rights reserved. // // A map from data value to/from color. // //---------------------------------------------------------------------------- #ifndef ColorMap_H #define ColorMap_H #include #include namespace VAPoR { class PARAMS_API ColorMap : public ParamsBase { public: class PARAMS_API Color { public: Color(); Color(float h, float s, float v); Color(double h, double s, double v); Color(const Color &color); void toRGB(float *rgb) const; void hue(float h) { _hue = h; } float hue() const { return _hue; } void sat(float s) { _sat = s; } float sat() const { return _sat; } void val(float v) { _val = v; } float val() const { return _val; } private: float _hue; float _sat; float _val; }; //! Create a ColorMap object from scratch // ColorMap(ParamsBase::StateSave *ssave); //! Create a ColorMap object from an existing XmlNode tree // ColorMap(ParamsBase::StateSave *ssave, XmlNode *node); virtual ~ColorMap(); void clear(); TFInterpolator::type GetInterpType() const { long defaultv = TFInterpolator::diverging; return (TFInterpolator::type)GetValueLong(_interpTypeTag, defaultv); } void SetInterpType(TFInterpolator::type t); void SetUseWhitespace(bool enabled); bool GetUseWhitespace() const; int numControlPoints() const { return (int)(GetControlPoints().size() / 4); } Color controlPointColor(int index) const; void controlPointColor(int index, Color color); float controlPointValue(int index) const; // Data Coordinates float controlPointValueNormalized(int index) const; void controlPointValue(int index, float value); // Data Coordinates void controlPointValueNormalized(int index, float value); void addControlPointAt(float value); int addNormControlPointAt(float value); void addControlPointAt(float value, Color color); int addNormControlPoint(float normValue, Color color); void deleteControlPoint(int index); void move(int index, float delta); Color color(float value) const; Color colorNormalized(float nv) const; Color getDivergingColor(float ratio, float index) const; Color getCorrectiveDivergingColor(float ratio, float index) const; // Method to obtain the control points as a double vector, with // 4 entries for each control point // in the order hue,sat,value, datavalue vector GetControlPoints() const; void SetControlPoints(const vector &controlPoints); //! //! The minimum value is stored as normalized coordinates in the parameter //! space. Therefore, the color map will change relative to any changes in //! the parameter space. True??? // void SetDataBounds(const vector &bounds); vector GetDataBounds() const; float minValue() const { return (GetDataBounds()[0]); } float maxValue() const { return (GetDataBounds()[1]); } void Reverse(); // Get static string identifier for this params class // static string GetClassType() { return ("ColorMapParams"); } public: static const string _controlPointsTag; static const string _interpTypeTag; static const string _useWhitespaceTag; static const string _dataBoundsTag; private: int leftIndex(float val) const; }; class PARAMS_API ARGB { public: ARGB(int r, int g, int b) { _argbvalue = ((r & 255) << 16) | ((g & 255) << 8) | (b & 255); } private: unsigned int _argbvalue; }; }; // namespace VAPoR #endif // ColorMap_H ================================================ FILE: include/vapor/ColorbarPbase.h ================================================ //************************************************************************ // * // Copyright (C) 2016 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: ColorbarPbase.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: February 2016 // // Description: Defines the ColorbarPbase class, derived from ParamsBase. // This supports parameters controlling the display of color bars. // #ifndef COLORBARPBASE_H #define COLORBARPBASE_H #include namespace VAPoR { //! \class ColorbarPbase //! \ingroup Public_Params //! \brief Settings for color bar displayed in scene //! Intended to be used in any Params class //! \author Alan Norton //! \version 3.0 //! \date February 2016 //! The ColorbarPbase class is a ParamsBase class that manages the settings associated with a color bar. //! There is a corresponding ColorbarFrame class in the GUI that manages display of these settings. //! //! //! class PARAMS_API ColorbarPbase : public ParamsBase { public: //! Create a ColorbarPbase object from scratch // ColorbarPbase(ParamsBase::StateSave *ssave); //! Create a ColorbarPbase object from an existing XmlNode tree // ColorbarPbase(ParamsBase::StateSave *ssave, XmlNode *node); virtual ~ColorbarPbase(); //! Get the X,Y corner (upper left) coordinates //! Relative to [0,1] //! \retval pair of x,y coordinates vector GetCornerPosition() const; //! Set the X,Y corner (upper left) coordinates //! Relative to [0,1] //! \param[in] posn = x,y coordinates void SetCornerPosition(vector posn); //! Get the X,Y size //! Relative to [0,1] //! \retval pair of x,y sizes vector GetSize() const; //! Set the X,Y sizes //! Relative to [0,1] //! \param[in] posn = x,y sizes void SetSize(vector sz); //! Get the title text //! (displayed after variable name) //! \retval title string GetTitle() const { return GetValueString(_colorbarTitleTag, ""); } //! Set the title text //! \param[in] text to display void SetTitle(string text) { SetValueString(_colorbarTitleTag, "Set colorbar title", text); } //! Determine if colorbar is enabled //! \return true if enabled bool IsEnabled() const { return (GetValueLong(_colorbarEnabledTag, (long)false) != 0); } //! Enable or disable colorbar //! \param[in] bool true if enabled void SetEnabled(bool val) { SetValueLong(_colorbarEnabledTag, "enable/disable colorbar", val); } //! Determine colorbar text size //! \return pointsize long GetFontSize() const; //! Set colorbar text size //! \param[in] val text point size void SetFontSize(long val); //! Determine colorbar num tics //! \return number of tics long GetNumTicks() const; //! Set colorbar number of tic marks //! \param[in] val number of tics void SetNumTicks(long val); //! Determine colorbar num digits to display //! \return number of digits long GetNumDigits() const; //! Set colorbar number of digits //! \param[in] val number of digits void SetNumDigits(long val); //! Get the background color //! as an rgb triple //! \retval rgb color vector GetBackgroundColor() const; //! Set the background color as an rgb triple //! \param[in] color = (r,g,b) void SetBackgroundColor(vector color); vector GetForegroundColor() const; void SetForegroundColor(vector color); //! Copy the settings (except enablement, title, and position) to another ColobarPbase. //! \param[in] target ColorbarPbase that is target of the copy. void copyTo(ColorbarPbase *target); // Get static string identifier for this params class // static string GetClassType() { return ("ColorBarSettingParams"); } public: static const string _colorbarBackColorTag; static const string _colorbarFrontColorTag; static const string _colorbarSizeXTag; static const string _colorbarSizeYTag; static const string _colorbarPositionXTag; static const string _colorbarPositionYTag; static const string _colorbarFontSizeTag; static const string _colorbarNumDigitsTag; static const string _colorbarTitleTag; static const string _colorbarNumTicksTag; static const string _colorbarEnabledTag; static const string UseScientificNotationTag; }; }; // namespace VAPoR #endif // COLORBARPBASE_H ================================================ FILE: include/vapor/ColorbarRenderer.h ================================================ #pragma once #include #include namespace VAPoR { struct GLManager; class RenderParams; class MapperFunction; //! \class ColorbarRenderer //! \ingroup Public_Render //! \brief Renders annotation colorbar for a given Mapper Function //! \author Stanislaw Jaroszynski //! class ColorbarRenderer { public: static void Render(GLManager *glm, RenderParams *rp); private: static std::function makeFormatter(MapperFunction *mf, int sigFigs, bool scientific); }; } // namespace VAPoR ================================================ FILE: include/vapor/Compressor.h ================================================ // // $Id$ // #ifndef _Compressor_h_ #define _Compressor_h_ #include #include "SignificanceMap.h" #include "MatWaveWavedec.h" namespace VAPoR { //! \class Compressor //! \brief A class for managing data set metadata //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! //! This class performs either lossy compression //! decomposition on an array with an arbitrary //! number of dimensions (up to 3 presently). Compression //! is performed by transforming //! data with a wavelet transform, sorting the resulting //! coefficients, and returning the n largest magnitude coefficients. // class WASP_API Compressor : public MatWaveWavedec { public: //! Constructor for compressor class //! //! This construct initializes a Compressor class object for use //! in compression or decomposition. The parameter \p wname specifies //! the name of the wavelet to use for subsequent wavelet transforms. //! The parameter \p wmode specifies the boundary extention mode //! to employ for transforms. //! For non-periodic data the biorthogonal wavelets with a //! with an appropriate symetric extension are recommended. //! //! \param[in] dims Vector specifying dimensions of arrays to be compressed //! \param[in] wname Name of wavelet to use in transform //! \param[in] wmode Boundary extention mode //! //! \sa MatWaveBase, WaveFiltBase // Compressor(std::vector dims, const string &wname, const string &mode); Compressor(std::vector dims, const string &wname); virtual ~Compressor(); //! Compress an array //! //! This method compresses an input array and returns a compressed version //! of the data. Compression is performed by wavelet transforming the data //! and sorting the resulting wavelet coefficients. Only the largest //! \p dst_arr_len coefficients are returned. //! //! \param[in] src_arr The input array. The dimensions are determined //! by the constructor's \p dims parameter. //! \param[out] dst_arr The output array that will contain the largest //! \p dst_arr_len coefficients from the transformed input array. \p dst_arr //! must point to enough space to contain \p dst_arr_len elements. //! \param[out] dst_arr_len Length of \p dst_arr. //! \param[in,out] A signficance map that, upon return, will provide //! the coordinates of the output coefficents returned. //! //! \retval status A negative value indicates failure //! \sa SignificanceMap, KeepAppOnOff() // int Compress(const float *src_arr, float *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap); int Compress(const double *src_arr, double *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap); int Compress(const int *src_arr, int *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap); int Compress(const long *src_arr, long *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap); //! Decompress an array previously compressed with Compress() //! //! \param[in] src_arr The input array containing the coefficients //! previsously computed by Compress(). //! \param[out] dst_arr The output array that will contain uncompressed //! array. \p dst_arr //! must point to enough space to contain The entire uncompressed array //! \param[in] The signficance map that returned by Compress() //! for \p src_arr //! //! \retval status A negative value indicates failure //! \sa Compress() // int Decompress(const float *src_arr, float *dst_arr, SignificanceMap *sigmap); int Decompress(const double *src_arr, double *dst_arr, SignificanceMap *sigmap); int Decompress(const int *src_arr, int *dst_arr, SignificanceMap *sigmap); int Decompress(const long *src_arr, long *dst_arr, SignificanceMap *sigmap); //! Decompose an array into a series of approximations of increasingly //! better fidelity. //! //! This method performs a wavelet decomposition of an array, sorts //! the resulting coefficients from largest to smallest, and returns //! the sorted coefficients as a collection of \p n sets, Si. //! The absolute value //! of each element of a set Si will be less than each //! element of a set Si+1. //! //! \param[in] src_arr The input array. The dimensions are determined //! by the constructor's \p dims parameter. //! //! \param[out] dst_arr The output array that will contain all of //! the sorted coefficients for each collection Si. //! //! \param[in] dst_arr_lens A vector whose size determines the number //! of collections Si, and whose elements specify the number //! of elements in each collection Si. The sum of all elements //! of \p dst_arr_lens must be less than or equal the total number of wavelet //! coefficients generated by the wavelet transform. The total is given //! by the size of the vector returned by GetSigMapShape(). //! //! \param[out] sigmaps An array of significance maps, one map for //! each coefficient collection, Si //! //! \retval status A negative value indicates failure //! \sa SignificanceMap, KeepAppOnOff(), Compress() // int Decompose(const float *src_arr, float *dst_arr, const vector &dst_arr_lens, vector &sigmaps); int Decompose(const double *src_arr, double *dst_arr, const vector &dst_arr_lens, vector &sigmaps); int Decompose(const int *src_arr, int *dst_arr, const vector &dst_arr_lens, vector &sigmaps); int Decompose(const long *src_arr, long *dst_arr, const vector &dst_arr_lens, vector &sigmaps); //! Reconstruct a signal decomposed with Decompose() //! //! This method reconstructs a signal previosly decomposed with Decompose(). //! Partial reconstructions are possible using one of two methods, both //! of which may be combined. In the first the a subset of //! coefficient collections Si may be used for reconstruction. //! In this case missing coefficients are simply treated as having //! value zero. Note that arbitrary Si cannot be specified: the //! collections must be ordered with i less than or equal to //! the total number of collections returned by Decompose(). //! //! The second method of partial reconstruction is to limit the number of //! inverse wavelet transforms applied to the coefficients. In this case //! the reconstructed array will be coarsened (contain fewer elements) //! than the original. The dimensions of the reconstructed array //! are given by GetDimension(). //! //! \param[in] src_arr The input array containing the coefficients //! previsously computed by Decompose(). //! //! \param[out] dst_arr The output array containing reconstructed signal. //! The dimensions of \p dst_arr are determined by GetDimension(). If //! \p l is -1, the dimensions will be the same as those specified by //! the class constructor's \p dims parameter //! //! \param[in] sigmaps An array of significance maps previosly returned //! by Decompose() //! //! \param[in] l The refinement level. \p l must be in the range -1 to //! max, where max is the value returned by GetNumLevels(). If \p is -1 //! its value will be set to max. A value of zero coresponds to the //! approximation level coefficients. //! //! \retval status A negative value indicates failure //! \sa SignificanceMap, KeepAppOnOff(), Compress() //! int Reconstruct(const float *src_arr, float *dst_arr, vector &sigmaps, int l); int Reconstruct(const double *src_arr, double *dst_arr, vector &sigmaps, int l); int Reconstruct(const int *src_arr, int *dst_arr, vector &sigmaps, int l); int Reconstruct(const long *src_arr, long *dst_arr, vector &sigmaps, int l); //! Return true if the given grid array is compressible //! //! Return true if the given grid array is compressible based on //! it's dimension and the requested wavelet. I.e. returns true //! if at least one dimension is wide enough for a single wavelet transform //! //! \param[in] dims Vector specifying dimensions of arrays to be compressed //! \param[in] wname Name of wavelet to use in transform //! \param[in] wmode Boundary extention mode //! //! \sa MatWaveBase, WaveFiltBase //! // static bool IsCompressible( // std::vector dims, const string &wavename, const string &mode //); //! Returns the shape of significance maps based on constructor //! //! This method returns the shape of any significance maps configured //! by the Compress() or Decompose() method based on parameters passed //! to the class constructor. //! //! \param[out] dims A vector describing the shap (dimensions) of a //! significance map //! //! \sa SignificanceMap, Compress(), Decompose() //! void GetSigMapShape(std::vector &dims) const { dims.clear(); dims.push_back(_CLen); }; //! Returns the number of wavelet coefficients resulting from //! a forward wavelet transformation of an array. //! //! Returns the number of wavelet coefficients resulting from //! a forward wavelet transformation of an array based on //! the parameters supplied to the class constructor. The //! number of coefficients resulting from a wavelet transform //! is a function of the dimensions of the array, the wavlet //! familiy used, the boundary handling method, and the number of //! transformation levels. //! //! \note For periodic boundary handling, or symetric wavelets matched //! with appropriate symetric boundary handling, the number of coefficients //! in the transform is guaranteed to match the number of coefficients //! in the input array. //! //! \sa Compress(), Decompose() //! size_t GetNumWaveCoeffs() const { return (_CLen); }; //! Returns the size of an encoded SignficanceMap() //! //! Returns the size in bytes of an encoded SignificanceMap() //! used to store \p num_entries entries. //! //! \sa Compress(), Decompose() //! size_t GetSigMapSize(size_t num_entries) const { std::vector dims; dims.push_back(GetNumWaveCoeffs()); return (SignificanceMap::GetMapSize(dims, num_entries)); }; //! Returns the dimensions of a reconstructed array //! //! This method returns the dimensions of an array reconstructed with //! either the Reconstruct() or Decompress() methods. The parameter //! \p l specifies the number of inverse transformation passes //! applied in the range -1 to max, where max is the value returned by //! GetNumLevels(). A value of -1 corresponds to max levels. A value of //! zero implies no inverse transformations are performed (the dimensions //! returned are those of the wavelet approximation coefficients). //! //! \param[out] dims The dimensions of the reconstructed array. //! \param[in] l The number of inverse transforms to apply //! //! \sa Compressor(), GetNumLevels() void GetDimension(vector &dims, int l) const; //! Returns the number of transformation levels //! //! Returns the number of forward or inverse wavelet transformations //! applied to compress or fully reconstruct an array. The number of //! of transforms is determined by a combination of the wavelet, //! the boundary extension handling method, and the dimensions of the //! array. //! //! \retval nlevels Number of transformation levels // int GetNumLevels() const { return (_nlevels); }; //! Returns the number of coefficients in the smallest allowable compression //! //! Returns the minimum number of wavelet coefficients allowable //! after compression. //! The minimum number of //! of coefficients is determined by a combination of the wavelet, //! the boundary extension handling method, the dimensions of the //! array, and the setting of KeepAppOnOff() //! //! \retval nlevels Number of transformation levels // size_t GetMinCompression() const; //! Set or get the keep approximations attribute //! //! When set, this attribute ensures that all wavelet approximation //! coefficients are retained during compression or decomposition. Setting //! this attribute will decrease the maximum possible compression, but may //! significantly improve the fidelity of the approximation //! bool &KeepAppOnOff() { return (_keepapp); }; //! Set or get the min range clamping attribute //! //! When set, this attribute will clamp the minimum data value //! reconstructed to the value of ClampMin(). I.e. all data values //! reconstructed by Decompress() or Reconstruct() will be greater //! than or equal to the value returned by ClampMin(). By default //! clamping is disabled. //! //! \sa ClampMin(), Decompress(), Reconstruct() //! bool &ClampMinOnOff() { return (_clamp_min_flag); }; //! Set or get the minimum range clamp value //! //! \sa ClampMinOnOff(), Decompress(), Reconstruct() //! double &ClampMin() { return (_clamp_min); }; //! Set or get the max range clamping attribute //! //! When set, this attribute will clamp the maximum data value //! reconstructed to the value of ClampMax(). I.e. all data values //! reconstructed by Decompress() or Reconstruct() will be less //! than or equal to the value returned by ClampMax(). By default //! clamping is disabled. //! //! \sa ClampMin(), Decompress(), Reconstruct() //! bool &ClampMaxOnOff() { return (_clamp_max_flag); }; //! Set or get the maximum range clamp value //! //! \sa ClampMaxOnOff(), Decompress(), Reconstruct() //! double &ClampMax() { return (_clamp_max); }; //! Set or get the epsilon attribute //! //! When set, this attribute will compare the absolute value of //! reconstructed data with Epsilon(). If abs(v) is less than epsilon //! the value of v is set to 0.0. //! By default //! the epsilon comparison is disabled. //! //! \sa Epsilon(), Decompress(), Reconstruct() //! bool &EpsilonOnOff() { return (_epsilon_flag); }; //! Set or get the epsilon value //! //! \sa EpsilonOnOff(), Decompress(), Reconstruct() //! double &Epsilon() { return (_epsilon); }; static bool CompressionInfo(vector dims, const string wavename, bool keepapp, size_t &nlevels, size_t &maxcratio); friend std::ostream &operator<<(std::ostream &o, const Compressor &rhs); private: vector _dims; // dimensions of array int _nlevels; // Number of wavelet transformation levels vector _indexvec; // used to sort wavelet coefficients size_t _nx; size_t _ny; size_t _nz; double * _C; // storage for wavelet coefficients size_t _CLen; size_t * _L; // wavelet coefficient book keeping array size_t _LLen; bool _keepapp; // if true, approximation coeffs are not used in compression bool _clamp_min_flag; bool _clamp_max_flag; bool _epsilon_flag; double _clamp_min; double _clamp_max; double _epsilon; void _Compressor(std::vector dims); }; } // namespace VAPoR #endif ================================================ FILE: include/vapor/ConstantGrid.h ================================================ #ifndef CONSTANTGRID_H #define CONSTANTGRID_H /* * This class represents a constant field. That means, * querying values from any location of this field will return that constant value. * * It also implements pure virtual functions of the Grid class in the simplest possible fashion, * but those functions do not perform any calculation, and should not be used. * * Finally, a DataMgr would not return a ConstantGrid at any occasion; rather, this * class is supposed to be created and used locally by its user. */ #include "vapor/Grid.h" namespace VAPoR { class VDF_API ConstantGrid : public Grid { public: // The constant value is specified via the constructor // It also requires specification of the dimentionality. ConstantGrid(float v, size_t d); // // Useful functions of ConstantGrid. // Additional ones could be added when needed. // // The following four GetValue methods all return the constant value of this grid. float GetConstantValue() const; float GetValue(const CoordType &coords) const override; float GetValueNearestNeighbor(const CoordType &coords) const override; float GetValueLinear(const CoordType &coords) const override; // This version of ConstantGrid is considered to have infinity extents, // so the following method will return numerical mins and maxes. // Note: other flavors of ConstantGrids may have specific user extents. virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override; // Similarly, this will always return true. virtual bool InsideGrid(const CoordType &coords) const override; std::string GetType() const override; // Overwrites the same function from Grid, which will always give you a zero. virtual size_t GetTopologyDim() const override; private: // // Pure virtual functions from Grid class. // They do nothing and return meaningless values. // Do not use! // DimsType GetCoordDimensions(size_t) const override; size_t GetGeometryDim() const override; const DimsType & GetNodeDimensions() const override; const size_t GetNumNodeDimensions() const override; const DimsType & GetCellDimensions() const override; const size_t GetNumCellDimensions() const override; void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override {} bool GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const override { return (false); } virtual void GetUserCoordinates(const DimsType &, CoordType &) const override {} bool GetIndicesCell(const CoordType &coords, DimsType &indices) const override; bool GetCellNodes(const DimsType &, std::vector &) const override; bool GetCellNeighbors(const DimsType &, std::vector &) const override; bool GetNodeCells(const DimsType &, std::vector &) const override; size_t GetMaxVertexPerFace() const override; size_t GetMaxVertexPerCell() const override; void ClampCoord(const CoordType &coords, CoordType &cCoords) const override { cCoords = coords; } ConstCoordItr ConstCoordBegin() const override; ConstCoordItr ConstCoordEnd() const override; // Private data member that holds this constant value. const float _value; const size_t _topologyDim; // Not to be confused with _topologyDimension in // the base Grid class, which is private to Grid. mutable VAPoR::DimsType _duplicate; }; // end ConstantGrid class }; // namespace VAPoR #endif ================================================ FILE: include/vapor/ContourParams.h ================================================ #ifndef CONTOURPARAMS_H #define CONTOURPARAMS_H #include #include #include namespace VAPoR { // class ContourParams::Contours; //! \class ContourParams //! \brief Class that supports drawing Contours based on 2D or 3D vector field //! \author Scott Pearse //! \version 3.0 //! \date June 2017 class PARAMS_API ContourParams : public RenderParams { public: class Contours; ContourParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave); ContourParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node); ContourParams(const ContourParams &rhs); ContourParams &operator=(const ContourParams &rhs); virtual ~ContourParams(); Contours *GetCurrentContours(); void MakeNewContours(string varName); void GenerateContourValues(double start, double spacing, int num, Contours *c = nullptr); //! Determine line thickness in voxels //! \retval double line thickness double GetLineThickness() const { return (GetValueDouble(_thicknessScaleTag, 1.0)); } void SetLineThickness(double val) { SetValueDouble(_thicknessScaleTag, "Contour thickness", val); } int GetContourCount(); double GetContourMin(); double GetContourSpacing(); double GetContourMax(); void SetContourCount(int num); void SetContourMin(double val); void SetContourSpacing(double val); void GetLineColor(int lineNum, float color[3]); void SetLineColor(vector vec) { SetValueDoubleVec(_lineColorTag, "Line color", vec); } void SetLockToTF(bool lock); bool GetLockToTF() const; bool HasIsoValues() const override { return true; } vector GetIsoValues(const string &variable) override; void SetIsoValues(const string &variable, const vector &values) override; vector GetContourValues(const string &varName); void SetContourValues(const string &varName, const vector &vals); // Get static string identifier for this params class // static string GetClassType() { return ("ContourParams"); } //! \copydoc RenderParams::GetRenderDim() // virtual size_t GetRenderDim() const override { return _dataMgr->GetVarTopologyDim(GetVariableName()); } virtual bool GetOrientable() const override { return true; } //! \copydoc RenderParams::GetActualColorMapVariableName() virtual string GetActualColorMapVariableName() const override { return GetVariableName(); } int GetNumDigits() const { double val = GetValueDouble(_numDigitsTag, 1.0); return (int)val; } void SetNumDigits(int digits) { SetValueDouble(_numDigitsTag, "Number of digits in contour annotation", digits); } int GetTextDensity() const { double val = GetValueDouble(_textDensityTag, 1.0); return (int)val; } void SetTextDensity(int density) { SetValueDouble(_textDensityTag, "Density of contour annotations", density); } bool GetTextEnabled() const; void SetTFLock(bool lock); bool GetTFLock(); private: void _init(); static const string _thicknessScaleTag; static const string _lineColorTag; static const string _contoursTag; static const string _numDigitsTag; static const string _textDensityTag; static const string _textEnabledTag; static const string _lockToTFTag; ParamsContainer * _contours; vector _slicePlaneQuad; public: class PARAMS_API Contours : public ParamsBase { public: Contours(ParamsBase::StateSave *ssave); Contours(ParamsBase::StateSave *ssave, XmlNode *node); virtual ~Contours(); vector GetContourValues() const { vector defaultv(7, 0.); if (!_node->HasElementDouble(_valuesTag)) return defaultv; vector val = GetValueDoubleVec(_valuesTag); return val; } void SetContourValues(vector vals) { SetValueDoubleVec(_valuesTag, "Set contour values", vals); } double GetMin() const; int GetCount() const; // { double GetSpacing() const; //{ static string GetClassType() { return ("Contours"); } private: static const string _valuesTag; }; }; // End of Class ContourParams }; // namespace VAPoR #endif ================================================ FILE: include/vapor/ContourRenderer.h ================================================ //************************************************************************ // * // Copyright (C) 2018 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: ContourRenderer.cpp // // Author: Stas Jaroszynski // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: March 2018 // // Description: // Definition of ContourRenderer // #ifndef CONTOURRENDERER_H #define CONTOURRENDERER_H #include #include "vapor/VAssert.h" #include #include #include #include #include namespace VAPoR { class DataMgr; //! \class ContourRenderer //! \brief Class that draws the contours (contours) as specified by IsolineParams //! \author Stas Jaroszynski //! \version 1.0 //! \date March 2018 class RENDER_API ContourRenderer : public Renderer { public: ContourRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr); virtual ~ContourRenderer(); static string GetClassType() { return ("Contour"); } //! \copydoc Renderer::_initializeGL() virtual int _initializeGL(); //! \copydoc Renderer::_paintGL() virtual int _paintGL(bool fast); private: GLuint _VAO, _VBO; Texture1D _lutTexture; unsigned int _nVertices; struct VertexData; struct { string varName; string heightVarName; size_t ts; int level; int lod; double lineThickness; vector boxMin, boxMax; vector contourValues; vector sliceRotation; vector sliceNormal; vector sliceOrigin; double sliceOffset; double sliceResolution; int sliceOrientationMode; } _cacheParams; int _buildCache(bool fast); bool _isCacheDirty() const; void _saveCacheParams(); void _clearCache() { _cacheParams.varName.clear(); } vector _sliceQuad; glm::vec3 _finalOrigin; }; }; // namespace VAPoR #endif // CONTOURRENDERER_H ================================================ FILE: include/vapor/ControlExecutive.h ================================================ #ifndef ControlExec_h #define ControlExec_h #include #include #include #include #include #include using namespace std; namespace VAPoR { class CalcEngineMgr; class Visualizer; class DataStatus; class VisualizerGLContextManager; //! \class ControlExec //! \ingroup Public //! \brief Provides API for VAPOR visualizer User Interfaces (UIs) // class RENDER_API ControlExec : public MyBase { public: //! Initialize the control executive //! //! \param[in] appParamsNames A vector of unique ParamsBase class //! \param[in] cacheSizeMB Size of data cache expressed in Megabytes //! //! names that will be passed to the ParamsMgr constructor //! //! \sa ParamsMgr(); // ControlExec(ParamsMgr *pm, size_t cacheSize = 1000, int nThreads = 0); ControlExec() : ControlExec(new ParamsMgr) {} virtual ~ControlExec(); //! Set the ControlExec to a default state: //! Remove all visualizers // virtual void LoadState(); //! Load state from an Xml tree //! //! Load state from an Xml state tree. Any unrecognized nodes //! in the tree are simply ignored. //! //! \sa ParamsMgr::LoadState(const XmlNode *node); // virtual void LoadState(const XmlNode *node); class RelAndAbsPathsExistException : public std::exception { public: const std::string AbsolutePath; const std::string RelativePath; RelAndAbsPathsExistException(const std::string &absolute, const std::string &relative) : AbsolutePath(absolute), RelativePath(relative) {} }; enum class LoadStateRelAndAbsPathsExistAction { Ask, LoadAbs, LoadRel }; //! Restore the session state from a session state file //! //! This method sets the session state based on the contents of the //! session file specified by \p file. It also has the side effect //! of deactivating all renderers and unloading any data set //! previously loaded by LoadData(). If successful, the state of all //! Params objects may have changed. //! //! \param[in] file Path to the input file //! //! \return status A negative int indicates failure. If the method //! fails the session state remains unchanged //! // virtual int LoadState(string stateFile, LoadStateRelAndAbsPathsExistAction relAndAbsPathsExistAction = LoadStateRelAndAbsPathsExistAction::LoadAbs); //! Set number of execution threads //! //! Set the number of execution threads. If \p nThreads == 0, the //! default, //! the system will attempt to set the number of threads equal to //! the number of cores detected. Has no effect until //! the next data set is loaded. // void SetNumThreads(size_t nthreads); size_t GetNumThreads() const; //! Set the data cache size //! //! Set the size of the data cache in MBs. //! Has no effect until //! the next data set is loaded. //! //! \sa DataMgr // void SetCacheSize(size_t sizeMB); //! Create a new visualizer //! //! This method creates a new visualizer. A visualizer is a drawable //! OpenGL object (e.g. window or pbuffer). The caller is responsible //! for establishing an OpenGL drawable object and making its context //! current before calling NewVisualizer(). //! //! \param[in] name Specifies the name for the new visualizer. //! If name visualizer with name \p name already exists the //! existing visualizer will be destroyed and a new one created //! with the same name. //! //! \param[in] withDatasets is the list of currently opened datasets. //! When a dataset is loaded, it loops over the existing visualizers //! and adds params for the currently loading dataset. Since datasets //! could've been loaded prior to the creation of this visualizer, //! they need to be manually added here. //! //! \note Need to establish what OpenGL state mgt, if any, is performed //! by UI. For example, who calls swapbuffers? //! //! \note Since the UI is responsible for setting up the graphics //! contexts we may need a method that allows the ControlExec //! to provide //! hints about what kind of graphics context is needed //! (e.g. double buffering) // int NewVisualizer(string name); void SyncWithParams(); void EnforceDefaultAppState(); //! Delete an existing visualizer //! //! Deletes visualizer and all of its renderers //! //! \param[in] name handle to existing visualizer returned by //! NewVisualizer(). This method is a no-op if a Visualizer named //! \p name doesn't exist //! //! \param[in] hasOpenGLContext If true it is the callers job to ensure //! that the OpenGL Context for the window \p winName is active. In //! this case the renderer is destroyed immediately. If false the //! renderer is queue'd for later destruction //! when \p winName has an active OpenGL context. //! // void RemoveVisualizer(string name, bool hasOpenGLContext = false); //! Removes objects associated with visualizer params. void CleanupVisualizer(string winName, bool hasOpenGLContext); //! Perform OpenGL initialization of specified visualizer //! //! \param[in] name handle to existing visualizer returned by //! NewVisualizer(). This method is a no-op if a Visualizer named //! //! This method should be called by the UI once before any //! rendering is performed. //! The UI should make the OGL context associated with \p viz //! current prior to calling this method. // int InitializeViz(string name, GLManager *glManager); //! Notify the control executive that a drawing object has //! changed size. //! //! \param[in] name handle to existing visualizer returned by //! NewVisualizer(). //! \param[in] width Width of visualizer //! \param[in] height Height of visualizer //! //! This method should be called by the UI whenever the drawing //! object (e.g. window) associated with \p viz has changed size. //! The UI should make the OGL context associated with \p viz //! current prior to calling this method. // int ResizeViz(string name, int width, int height); void ClearRenderCache(const string &winName, const string &inst); void ClearAllRenderCaches(); GLManager::Vendor GetGPUVendor() const; //! Determine how many visualizer windows are present //! \return number of visualizers //! int GetNumVisualizers() const { return (int)_visualizers.size(); } //! Return the names of all of the defined visualizers //! vector GetVisualizerNames() const; //! Render the contents of a drawable //! //! Tells the control executive to invoke all active renderers associated //! with the visualizer \p name. The control executive may elect to //! ignore this method if it believes the rendering state to be current, //! unless \p force is true. //! //! The UI should make the OGL context associated with \p viz //! current prior to calling this method. //! //! \param[in] name handle to existing visualizer returned by //! NewVisualizer(). //! \param[in] force If true all active renderers will rerender //! their scenes. If false, rendering will only be performed if //! the params objects associated with any of the active renderers //! on this visualizer have changed state. //! \return rc is 0 if actual painting occurred, -1 if not. //! //! int Paint(string name, bool force = false); //! Activate or Deactivate a renderer //! //! Create and activate a new renderer instance. //! This renderer instance is inserted in the queue of active renderers //! for the visualizer. //! To deactivate a renderer, the associated Renderer instance is removed //! from the queue of active renderers in the Visualizer, and then deleted. //! //! \param[in] winName The visualizer associated with this renderer //! \param[in] type The type of renderer; i.e. the tag for the RenderParams. //! \param[in] renderName The instance name associated with this //! renderer. //! \param[in] on A boolean indicating if the renderer is to be made //! active (true) or inactive (off) //! //! \return status A negative int is returned on failure, indicating that //! the renderer cannot be activated // int ActivateRender(string winName, string dataSetName, string renderType, string renderName, bool on); //! Remove (destroy) the indicated renderer //! //! \param[in] hasOpenGLContext If true it is the callers job to ensure that the //! OpenGL Context for the window \p winName is active. In this case the renderer //! is destroyed immediately. If false the renderer is queue'd for later destruction //! when \p winName has an active OpenGL context. //! void RemoveRenderer(string winName, string dataSetName, string renderType, string renderName, bool hasOpenGLContext); //! Remove (destroy) all renderers on this window //! //! \param[in] hasOpenGLContext If true it is the callers job to ensure that the //! OpenGL Context for the window \p winName is active. In this case the renderer //! is destroyed immediately. If false the renderer is queue'd for later destruction //! when \p winName has an active OpenGL context. //! void RemoveAllRenderers(string winName, bool hasOpenGLContext = false, bool removeFromParamsFlag=true); //! Obtain the ParamsMgr, for use in accessing the Params instances. //! \return ParamsMgr* // ParamsMgr *GetParamsMgr() const { return _paramsMgr; } //! Save the current session state to a file //! //! This method saves all current session state information //! to the file specified by path \p file. All session state information //! is stored in Params objects and their derivatives //! //! \param[in] file Path to the output file //! //! \return status A negative int indicates failure //! //! \sa RestoreSession() // int SaveSession(string file); #ifdef VAPOR3_0_0_ALPHA //! Save user preferences to a file //! //! This method saves all preference information //! to the file specified by path \p file. //! //! \param[in] file Path to the output file //! //! \return status A negative int indicates failure //! //! \sa RestorePreferences() // int SavePreferences(string file); //! Restore the preferences from a preference file //! //! This method sets the preferences based on the contents of the //! preferences file specified by \p file. //! //! \param[in] file Path to the input file //! //! \return status A negative int indicates failure. If the method //! fails the preferences remain unchanged (is it possible to //! guarantee this? ) //! //! \sa SavePreferences() // int RestorePreferences(string file); #endif //! Load a data set into the current session //! //! Loads a data set specified by the list of files in \p files //! //! \param[in] files A vector of data file paths. For data sets //! not containing explicit time information the ordering of //! time varying data will be determined by the order of the files //! in \p files. //! //! //! \note The proposed DataMgr API doesn't provide methods to easily //! query some of the information that will be required by the UI, for //! example, the coordinate extents of a variable. These methods //! should either be added to the DataMgr, or the current DataStatus //! class might be cleaned up. Hence, DataInfo might be an enhanced //! DataMgr, or a class object designed specifically for returning //! metadata to the UI. //! \note (AN) It would be much better to incorporate the //! DataStatus methods into //! the DataMgr class, rather than keeping them separate. // int OpenData(const std::vector &files, string dataSetName, string type = "vdc"); //! Unloads the specified data set //! void CloseData(string dataSetName); //! Return list of currently open data set names //! //! \sa OpenData(), CloseData() // std::vector GetDataNames() const { return (_dataStatus->GetDataMgrNames()); } //! Obtain the current DataStatus //! Needed to store in GUI when the DataStatus changes. //! \return DataStatus* DataStatus *GetDataStatus() const { return _dataStatus; } //! Get RenderParams for an active renderer //! //! Return the RenderParams for a render of type \p renderType, associated //! the visualizer \p winName, and named \p instName //! with the specified // RenderParams *GetRenderParams(string winName, string dataSetName, string renderType, string instName) const; //! Get all activated render class names //! //! Get a list of all render class names currently active for //! the visualizer named by \p winName //! std::vector GetRenderClassNames(string winName) const; //! Get all activated render class instance names //! //! Get a list of all render class instance names currently active for //! the visualizer named by \p winName of type \p renderType //! std::vector GetRenderInstances(string winName, string renderType) const; //! Get all available render class types //! //! Return a vector of all availble render class type names //! static vector GetAllRenderClasses(); //! Lookup window, data set, and class name from a render instance name //! //! This method returns the window name \p winName, data set name //! \p dataSetName, and render type \p rendererType that are associated //! with the render instance name \p instName. //! //! \retval status True on success, false if \p instName is not a previously //! defined render instance name //! //! \sa ActivateRender // bool RenderLookup(string instName, string &winName, string &dataSetName, string &rendererType) const; string MakeRendererNameUnique(string name) const; //! Enable or disable state saving //! //! Enable or disable session state saving. When enabled all state //! changes are recorded and it is possible to undo previous changes, //! or save current session state to a file //! //! State saving is disabled by default //! //! \sa Undo(), Redo(), SaveSession() // void SetSaveStateEnabled(bool enabled) { _paramsMgr->SetSaveStateEnabled(enabled); } bool GetSaveStateEnabled() const { return (_paramsMgr->GetSaveStateEnabled()); } //! Re-base state saving //! //! Set's the base state to the current node //! void RebaseStateSave() { _paramsMgr->RebaseStateSave(); } //! Capture the next rendered image to a file //! When this method is called, the next time Paint() is called for //! the specified visualizer, the rendered image //! will be written to the specified (.jpg, .tif, ...) file. //! The UI must call Paint(viz, true) after this method is called. //! If this is called concurrently with a call to Paint(), the //! image will not be captured until that rendering completes //! and another Paint() is initiated. //! Only one image will be captured. //! \param[in] filename is either .jpg, .tif, or .tiff file name to capture //! \param[in] viz Valid visualizer handle int EnableImageCapture(string filename, string winName, bool fast=false); //! Start or stop capturing a sequence of rendered images //! When this method is called, the next time Paint() is called for //! the specified visualizer, the rendered image //! will be written to the specified (.jpg, .tif, ...) file. //! The UI must call Paint(viz, true) after this method is called. //! Subsequent renders in the same visualizer will result in capture to a file //! and the filename will be incremented by 1. //! The starting filename should terminate with digits to permit incrementing. //! filename is ignored if capture is being disabled //! \param[in] viz Valid visualizer handle //! \param[in] doEnable true to start capture, false to end. //! \param[in] filestart is either .jpg, .tif, or .tiff file //! name for first capture. Ignored if doEnable = false. //! int EnableAnimationCapture(string winName, bool doEnable, string filename = ""); //! Make string conformant for library //! //! Many of the methods provided by the API accept string arguments //! defining names of objects. These user-defined names must conform //! to Xml element name requirements: //! //! \li Element names are case-sensitive //! \li Element names must start with a letter or underscore //! \li Element names cannot start with the letters xml (or XML, or Xml, etc) //! \li Element names can contain letters, digits, hyphens, //! underscores, and periods //! \li Element names cannot contain spaces //! //! This method ensures \p s is conformant, returning a possibly //! modified string meeting the above requirements //! //! \param[in] s a string //! \retval Returns \p s, possibly modified to be XML element conformant // static string MakeStringConformant(string s); //! Add a variable calculation function //! //! This method adds one or more derived variables to the data set //! specified by \p dataSetName. //! Each derived variable is calculated on-the-fly as needed //! by executing //! the script \p script. //! //! \param[in] scriptName A string identifier for the collection //! of derived variables //! computed by \p script //! //! \param[in] scriptType The language the script contained in \p script //! is implemented in. Currently the only accepted value is "Python". //! //! \param[in] dataSetName The name of the data set for which this //! script is to be run. See DataStatus::GetDataMgrNames() //! //! \param[in] script A script that will be invoked each time //! one of the variables listed in \p outputs is accessed. The scope of //! the script will contain NumPy Array (numpy.array) variables named //! in \p inputs. //! //! \param[in] inputVarNames A list of input variable names. The named //! variables will be made available in the scope of the Python //! script as NumPy Arrays. The variables must exist as native variables //! of the dataset named by \p dataSetName. I.e. Input variables cannot //! be derived variables themselves. //! //! \param[in] outputVarNames A list of derived variable names. The named //! variables are expected to be computed by \p script as NumPy Arrays //! and will appear as derived variables in the dataset named by //! \p dataSetName. //! //! \param[in] outVarMeshes A list of output mesh names, one for each output //! variable listed in \p outputVarNames. The output mesh names must be known //! to the dataset. Each output variable created by \p script is expected //! to be sampled by the named mesh. See DataMgr::GetMesh() //! //! \retval status A negative integer is returned on failure and an error //! message is reported with MyBase::SetErrMsg(). AddFunction() will fail //! if any of the output variables named in \p outputVarNames already exist //! in the dataset as returned by DataMgr::GetDataVarNames(), or if any of //! the output mesh names in \p outVarMeshes are not known to the //! DataMgr (see DataMgr::GetMeshNames()) //! //! \note The Python script \p script is executed when one of the output //! variables is read. Depending on the region requested only a subset //! of the native variable may be provided to \p script as a NumPy //! array. Currently this occurs if all of the input variables named //! by \p inputs and the requested output variable are sampled on the //! same mesh. //! //! \sa PyEngine::AddFunction(), CalcEngineMgr::AddFunction() // int AddFunction(string scriptType, string dataSetName, string scriptName, string script, const vector &inputVarNames, const vector &outputVarNames, const vector &outputVarMeshes, bool coordFlag = false); //! Remove a previously defined function //! //! This method removes the function previously created by AddFunction() //! All of the associated derived variables are //! removed from the dataset. The method is a no-op if \p scriptName is not //! an active function. //! //! \param[in] scriptType Language of script. Currently only "Python" is //! supported //! //! \param[in] dataSetName Name of data set for which \p scriptName is to //! be removed. //! //! \param[in] scriptName Name of script to remove //! //! \sa PyEngineMgr::RemoveFunction() // void RemoveFunction(string scriptType, string dataSetName, string scriptName); //! Return the script for a named function //! //! This method returns as a string the script associated with the //! function named by \p name. It also returns the input and output //! variable names, and the output variable mesh names. //! //! \param[in] scriptType Type of script //! \param[in] dataSetName Name of data set //! \param[in] scriptName Name of script //! //! \param[out] script Script returned as a string //! \param[out] inputVarNames Vector of input variable names to script //! \param[out] outputVarNames Vector of output variable names generated //! by script //! \param[out] outputVarMeshes Vector of output variable mesh names //! associated with \p outputVarNames //! //! \retval status Returns true upon success. If the tupple \p scriptName //! \p dataSetName, \p scriptName is invalid false is returned. //! //! \sa AddFunction(), RemoveFunction() // bool GetFunction(string scriptType, string dataSetName, string scriptName, string &script, vector &inputVarNames, vector &outputVarNames, vector &outputVarMeshes, bool &coordFlag) const; //! Return any standard output from the last invocation of a script //! //! This method returns as a string any standard output from the last //! (most recent) invocation of the named script // string GetFunctionStdout(string scriptType, string dataSetName, string scriptName) const; //! Return a list of all active function names //! //! This method returns a vector of names for all active (not previously //! removed) functions created with AddFunction() for the specified //! dataset \p dataSetName and the specifed script language type \p scriptType //! //! \sa AddFunction(); //! std::vector GetFunctionNames(string scriptType, string dataSetName) const; void SetVisualizerGLContextManager(VisualizerGLContextManager *mgr) { _vizGLMgr = mgr; } template T* GetParams() const { return (T*)GetParamsMgr()->GetParams(T::GetClassType()); } // "was" allows other components synced after CE to act accordingly bool WasDataCacheDirty() const; void SetDataCacheDirty(const string &dataset="", const string &variable="") { _dataStatus->SetCacheDirty(dataset, variable); } private: ParamsMgr * _paramsMgr; DataStatus * _dataStatus; CalcEngineMgr * _calcEngineMgr; VisualizerGLContextManager * _vizGLMgr = nullptr; std::map _visualizers; string _dataCachedProjStr; GLManager::Vendor _cachedVendor = GLManager::Vendor::Unknown; //! obtain an existing visualizer //! \param[in] viz Handle of desired visualizer //! \return pointer to specified visualizer //! Visualizer *getVisualizer(string winName) const { std::map::const_iterator it; it = _visualizers.find(winName); if (it == _visualizers.end()) return NULL; return it->second; } void syncVisualizersWithParams(); void syncDatasetsWithParams(); void _removeRendererHelper(string winName, string dataSetName, string paramsType, string renderName, bool hasOpenGLContext); void _autoStretchExtents(string dataSetName); void _setDefaultOrigin(string datasetName); }; }; // namespace VAPoR #endif // ControlExec_h ================================================ FILE: include/vapor/CurvilinearGrid.h ================================================ #ifndef _CurvilinearGrid_ #define _CurvilinearGrid_ #include #include #include #include namespace VAPoR { //! \class CurvilinearGrid //! //! \brief This class implements a 2D or 3D curvilinear grid. //! //! This class implements a 2D or 3D curvilinear grid: a //! specialization of StructuredGrid class where cells are //! quadrilaterals (2D), or cuboids (3D). Hence, curvlinear grids are //! topologically, but the location of each grid point is expressed //! by functions: //! //! \code //! x = X(i,j) //! y = Y(i,j) //! z = Z(i,j,k) //! \endcode //! //! or //! //! \code //! x = X(i,j) //! y = Y(i,j) //! z = Z(k) //! \endcode //! // class VDF_API CurvilinearGrid : public StructuredGrid { public: //! \copydoc StructuredGrid::StructuredGrid() //! //! Construct a vetically stretched, horizontally curvlinear 3D grid //! //! This constructor instantiates a curvilinear grid where the x,y,z //! user coordinates are expressed as follows: //! //! \code //! x = X(i,j) //! y = Y(i,j) //! z = Z(k) //! \endcode //! //! The X and Y user coordinates are specified with \p xrg and \p yrg, //! respectively, and the Z coordinates are specified by the //! vector \p zcoords. //! //! Adds new parameters: //! //! \param[in] xrg A 2D RegularGrid instance whose //! I and J dimensionality matches that of this class instance, and whose //! values specify the X user coordinates. //! \param[in] yrg A 2D RegularGrid instance whose //! I and J dimensionality matches that of this class instance, and whose //! values specify the Y user coordinates. //! \param[in] zcoords A 1D vector whose size matches that of the K //! dimension of this class, and whose values specify the Z user coordinates. //! \param[in] qtr A QuadTreeRectangleP instance that contains a quad tree //! that may be used to find the cell(s) containing a given point //! expressed in user coordintes. if \p qtr is NULL the class will //! generate its own QuadTreeRectangleP instance. //! //! //! \sa RegularGrid() // CurvilinearGrid(const DimsType &dims, const DimsType &bs, const std::vector &blks, const RegularGrid &xrg, const RegularGrid &yrg, const std::vector &zcoords, std::shared_ptr qtr); CurvilinearGrid(const std::vector &dims, const std::vector &bs, const std::vector &blks, const RegularGrid &xrg, const RegularGrid &yrg, const std::vector &zcoords, std::shared_ptr qtr); //! \copydoc StructuredGrid::StructuredGrid() //! //! Construct a layered, horizontally curvlinear 3D grid //! //! This constructor instantiates a curvilinear grid where the x,y,z //! user coordinates are expressed as follows: //! //! \code //! x = X(i,j) //! y = Y(i,j) //! z = Z(i,j,k) //! \endcode //! //! The X and Y user coordinates are specified with \p xrg and \p yrg, //! respectively, and the Z coordinates are specified by the //! \p zrg //! //! Adds new parameters: //! //! \param[in] xrg A 2D RegularGrid instance whose //! I and J dimensionality matches that of this class instance, and whose //! values specify the X user coordinates. //! \param[in] yrg A 2D RegularGrid instance whose //! I and J dimensionality matches that of this class instance, and whose //! values specify the Y user coordinates. //! \param[in] zrg A 3D RegularGrid instance whose //! I, J, K dimensionality matches that of this class instance, and whose //! values specify the Z user coordinates. //! \param[in] qtr A QuadTreeRectangleP instance that contains a quad tree //! that may be used to find the cell(s) containing a given point //! expressed in user coordintes. if \p qtr is NULL the class will //! generate its own QuadTreeRectangleP instance. //! //! //! \sa RegularGrid() // CurvilinearGrid(const DimsType &dims, const DimsType &bs, const std::vector &blks, const RegularGrid &xrg, const RegularGrid &yrg, const RegularGrid &zrg, std::shared_ptr qtr); CurvilinearGrid(const std::vector &dims, const std::vector &bs, const std::vector &blks, const RegularGrid &xrg, const RegularGrid &yrg, const RegularGrid &zrg, std::shared_ptr qtr); //! \copydoc StructuredGrid::StructuredGrid() //! //! Construct a curvlinear 2D grid //! //! This constructor instantiates a curvilinear grid where the x,y //! user coordinates are expressed as follows: //! //! \code //! x = X(i,j) //! y = Y(i,j) //! \endcode //! //! The X and Y user coordinates are specified with \p xrg and \p yrg, //! respectively. //! //! Adds new parameters: //! //! \param[in] xrg A 2D RegularGrid instance whose //! I and J dimensionality matches that of this class instance, and whose //! values specify the X user coordinates. //! \param[in] yrg A 2D RegularGrid instance whose //! I and J dimensionality matches that of this class instance, and whose //! values specify the Y user coordinates. //! \param[in] qtr A QuadTreeRectangleP instance that contains a quad tree //! that may be used to find the cell(s) containing a given point //! expressed in user coordintes. if \p qtr is NULL the class will //! generate its own QuadTreeRectangleP instance. //! //! //! \sa RegularGrid() // CurvilinearGrid(const DimsType &dims, const DimsType &bs, const std::vector &blks, const RegularGrid &xrg, const RegularGrid &yrg, std::shared_ptr qtr); CurvilinearGrid(const std::vector &dims, const std::vector &bs, const std::vector &blks, const RegularGrid &xrg, const RegularGrid &yrg, std::shared_ptr qtr); CurvilinearGrid() = default; virtual ~CurvilinearGrid() { if (_qtr) { _qtr = nullptr; // qtr is a C++ shared pointer } } std::shared_ptr GetQuadTreeRectangle() const { return (_qtr); } static std::string GetClassType() { return ("Curvilinear"); } std::string GetType() const override { return (GetClassType()); } virtual DimsType GetCoordDimensions(size_t dim) const override; virtual size_t GetGeometryDim() const override { return (GetTopologyDim()); }; // \copydoc GetGrid::GetBoundingBox() // virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override; // \copydoc GetGrid::GetUserCoordinates() // virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override; //! \copydoc Grid::GetIndicesCell //! virtual bool GetIndicesCell(const CoordType &coords, DimsType &indices) const override; // \copydoc GetGrid::InsideGrid() // virtual bool InsideGrid(const CoordType &coords) const override; //! Returns reference to RegularGrid instance containing X user coordinates //! //! Returns reference to RegularGrid instance passed to constructor //! containing X user coordinates //! const RegularGrid &GetXRG() const { return (_xrg); }; //! Returns reference to RegularGrid instance containing Y user coordinates //! //! Returns reference to RegularGrid instance passed to constructor //! containing Y user coordinates //! const RegularGrid &GetYRG() const { return (_yrg); }; //! Returns reference to vector containing Z user coordinates //! //! Returns reference to vector passed to constructor //! containing Z user coordinates //! const std::vector &GetZCoords() const { return (_zcoords); }; class ConstCoordItrCG : public Grid::ConstCoordItrAbstract { public: ConstCoordItrCG(const CurvilinearGrid *cg, bool begin); ConstCoordItrCG(const ConstCoordItrCG &rhs); ConstCoordItrCG(); virtual ~ConstCoordItrCG() {} virtual void next(); virtual void next(const long &offset); virtual ConstCoordType &deref() const { return (_coords); } virtual const void * address() const { return this; }; virtual bool equal(const void *rhs) const { const ConstCoordItrCG *itrptr = static_cast(rhs); return (_index == itrptr->_index); } virtual std::unique_ptr clone() const { return std::unique_ptr(new ConstCoordItrCG(*this)); }; private: const CurvilinearGrid *_cg; DimsType _index; CoordType _coords; ConstIterator _xCoordItr; ConstIterator _yCoordItr; ConstIterator _zCoordItr; bool _terrainFollowing; }; virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrCG(this, true))); } virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrCG(this, false))); } protected: virtual float GetValueNearestNeighbor(const CoordType &coords) const override; virtual float GetValueLinear(const CoordType &coords) const override; // \copydoc GetGrid::GetUserExtents() // virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override; private: std::vector _zcoords; CoordType _minu = {{0.0, 0.0, 0.0}}; CoordType _maxu = {{0.0, 0.0, 0.0}}; RegularGrid _xrg; RegularGrid _yrg; RegularGrid _zrg; bool _terrainFollowing; std::shared_ptr _qtr; void _curvilinearGrid(const RegularGrid &xrg, const RegularGrid &yrg, const RegularGrid &zrg, const std::vector &zcoords, std::shared_ptr qtr); bool _insideFace(const DimsType &face, double pt[2], double lambda[4], std::vector &nodes) const; bool _insideGrid(double x, double y, double z, size_t &i, size_t &j, size_t &k, double lambda[4], double zwgt[2]) const; void _getIndicesHelper(const std::vector &coords, std::vector &indices) const; bool _insideGridHelperStretched(double z, size_t &k, double zwgt[2]) const; bool _insideGridHelperTerrain(double x, double y, double z, const size_t &i, const size_t &j, size_t &k, double zwgt[2]) const; std::shared_ptr _makeQuadTreeRectangle() const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/DC.h ================================================ #include #include #include #include #include #ifndef _DC_H_ #define _DC_H_ namespace VAPoR { //! //! \class DC //! \ingroup Public_VDC //! //! \brief A Template Method design pattern for reading a collection of data. //! //! \author John Clyne //! \date January, 2015 //! //! The Data Collection (DC) class defines an Template Method for //! reading metadata and sampled //! data from a data collection. A data collection is a set of //! related data, most typically the discrete outputs from a single numerical //! simulation. The DC class is a Template Method: if provides an //! abstract interface for accessing a data collection, and a set of //! protected pure virtual functions that must be implemented by //! derived classes providing access to a particular file format. //! //! Variables in a DC may have 1, 2, or 3 topological dimensions, and 0 or 1 //! temporal dimensions. //! //! The DC is structured in the spirit of the "NetCDF Climate and Forecast //! (CF) Metadata Conventions", version 1.6, 5, December 2011. //! It supports only a subset of the CF functionality (e.g. there is no //! support for "Discrete Sampling Geometries"). Moreover, it is //! more restrictive than the CF in a number of areas. Particular //! items of note include: //! //! \li The API supports variables with 0 to 3 topological dimensions only. //! //! \li Coordinate variables representing time must be 1D //! //! \li All data variables have a "coordinate" attribute identifying //! the coordinate (or auxiliary coordinate) variables associated with //! each axis //! //! \li To be consistent with VAPOR, when specified in vector form the //! ordering of dimension lengths //! and dimension names is from fastest varying dimension to slowest. //! For example, if //! 'dims' is a vector of dimensions, then dims[0] is the fastest varying //! dimension, dim[1] is the next fastest, and so on. This ordering is the //! opposite of the ordering used by NetCDF. //! //! \li The API supports unstructured grids and attempts to follow //! the UGRID conventions. //! //! This class inherits from Wasp::MyBase. Unless otherwise documented //! any method that returns an integer value is returning status. A negative //! value indicates failure. Error messages are logged via //! Wasp::MyBase::SetErrMsg(). Methods that return a boolean do //! not, unless otherwise documented, log an error message upon //! failure (return of false). //! //! \param level //! \parblock //! Grid refinement level for multiresolution variables. //! Compressed variables in the DC, if they exist, have a multi-resolution //! representation: the sampling grid for multi-resolution variables //! is hierarchical, and the dimension lengths of adjacent levels in the //! hierarchy differ by a factor of two. The \p level parameter is //! used to select a particular depth of the hierarchy. //! //! To provide maximum flexibility as well as compatibility with previous //! versions of the DC the interpretation of \p level is somewhat //! complex. Both positive and negative values may be used to specify //! the refinement level and have different interpretations. //! //! For positive //! values of \p level, a value of \b 0 indicates the coarsest //! member of the //! grid hierarchy. A value of \b 1 indicates the next grid refinement //! after the coarsest, and so on. Using postive values the finest level //! in the hierarchy is given by GetNumRefLevels() - 1. Values of \p level //! that are greater than GetNumRefLevels() - 1 are treated as if they //! were equal to GetNumRefLevels() - 1. //! //! For negative values of \p level a value of -1 indicates the //! variable's native grid resolution (the finest resolution available). //! A value of -2 indicates the next coarsest member in the hierarchy after //! the finest, and so //! on. Using negative values the coarsest available level in the hierarchy is //! given by negating the value returned by GetNumRefLevels(). Values of //! \p level that are less than the negation of GetNumRefLevels() are //! treated as if they were equal to the negation of the GetNumRefLevels() //! return value. //! \endparblock //! \param lod //! \parblock //! The level-of-detail parameter, \p lod, selects //! the approximation level for a compressed variable. //! The \p lod parameter is similar to the \p level parameter in that it //! provides control over accuracy of a compressed variable. However, instead //! of selecting the grid resolution the \p lod parameter controls //! the compression factor by indexing into the \p cratios vector (see below). //! As with the \p level parameter, both positive and negative values may be //! used to index into \p cratios and //! different interpretations. //! //! For positive //! values of \p lod, a value of \b 0 indicates the //! the first element of \p cratios, a value of \b 1 indicates //! the second element, and so on up to the size of the //! \p cratios vector (See DC::GetCRatios()). //! //! For negative values of \p lod a value of \b -1 indexes the //! last element of \p cratios, a value of \b -2 indexes the //! second to last element, and so on. //! Using negative values the first element of \p cratios - the greatest //! compression rate - is indexed by negating the size of the //! \p cratios vector. //! \endparblock //! \param cratios A monotonically decreasing vector of //! compression ratios. Compressed variables in the DC are stored //! with a fixed, finite number of compression factors. The \p cratios //! vector is used to specify the available compression factors (ratios). //! A compression factor of 1 indicates no compression (1:1). A value //! of 2 indciates two to one compression (2:1), and so on. The minimum //! valid value of \p cratios is \b 1. The maximum value is determined //! by a number of factors and can be obtained using the CompressionInfo() //! method. //! //! \param bs An ordered list of block dimensions that specifies the //! spatial block decomposition of the variable. The rank of \p bs may be less //! than that of a variable's array dimensions (or empty), in which case only //! the \b n fastest varying variable dimensions will be blocked, where //! \b n is the rank of \p bs. The ordering of the dimensions in \p bs //! is from fastest to slowest. A block is the basic unit of compression //! in the DC: variables are decomposed into blocks, and individual blocks //! are compressed independently. Note, the time dimension is never blocked. //! //! \param wname Name of wavelet used for transforming compressed //! variables between wavelet and physical space. Valid values //! are "bior1.1", "bior1.3", "bior1.5", "bior2.2", "bior2.4", //! "bior2.6", "bior2.8", "bior3.1", "bior3.3", "bior3.5", "bior3.7", //! "bior3.9", "bior4.4" //! //! class VDF_API DC : public Wasp::MyBase { public: //! External storage types for primitive data // enum XType { INVALID = -1, FLOAT, DOUBLE, UINT8, INT8, INT32, INT64, TEXT }; //! \class Dimension //! //! \brief Metadata describing a named dimension length //! //! Describes an array dimension with a name and an //! associated length. Dimension lengths may vary (e.g. over time). //! class Dimension { public: Dimension() { _name.clear(); _lengths.clear(); } //! Dimension class constructor for multi-length dimension //! //! \param[in] name The name of dimension //! \param[in] lengths A vector of dimension lengths. //! Dimension(std::string name, std::vector lengths) { _name = name; _lengths = lengths; }; //! Dimension class constructor for constant-length dimension //! //! \param[in] name The name of dimension //! \param[in] length The dimension length. //! Dimension(std::string name, size_t length) { _name = name; _lengths.clear(); _lengths.push_back(length); }; virtual ~Dimension(){}; //! Get dimension name // string GetName() const { return (_name); }; //! Return dimension length //! //! For a multi-length dimension the first length is returned //! size_t GetLength() const { return (_lengths.size() ? _lengths[0] : 0); }; //! Return a dimension length //! //! \param[in] index Return the length of the dimension for the indicated //! element. If \p index is out of range the value 0 is returned //! size_t GetLength(size_t index) const { return (index < _lengths.size() ? _lengths[index] : 0); }; //! Return boolean indicating whether dimension can vary over time //! //! This method returns true if the dimesion length can vary over time. // bool IsTimeVarying() const { return (_lengths.size() > 1); } friend std::ostream &operator<<(std::ostream &o, const Dimension &dimension); private: string _name; std::vector _lengths; }; //! \class Mesh //! \version 3.1 //! //! \brief Metadata describing a computational mesh //! //! This class describes the properties of a computational mesh upon //! which data variables are sampled. The class can represent both //! structured and unstructured grids. //! The design of the Mesh class is inspired by the capabilities of the //! UGRID conventions: //! UGRID //! //! Towards that end we adopt some of UGRID's terminology: //! //! \b Definitions //! //! \li \b node A point, a coordinate pair or triplet: the most basic //! element of the topology. Aka "vertext". //! //! \li \b edge A line bounded by two nodes. //! //! \li \b face A plane or surface enclosed by a set of edges. In a 2D //! horizontal application one may consider the word "polygon", but in the //! hierarchy of elements the word "face" is most common. //! //! \li \b volume A volume enclosed by a set of faces. Aka "cell". //! //! \li \b topology The topology defines the connectivity of the //! vertices and defines the elements. //! //! \param[in] name A string containing the name of the mesh. //! //! \param[in] coord_vars A list of names of the coordinate variables, //! each specifying the X, Y, or Z spatial coordinates for the nodes //! in the mesh. If a coordinate variable for an X, Y, or Z axis //! is not specified the node's coordinate's for the missing axis are //! assumed to be zero. The dimensionality of the coordinate variable //! may be less than that of the dimensionality of the grid, in which //! case the coordinates along the unspecified dimension are assumed //! invariant. //! //! \param[in] max_nodes_per_face Specifies maximum number of nodes //! (or edges) a face of the mesh may have. //! //! \param[in] max_faces_per_node Specifies maximum number of faces //! that may share a node //! //! \param[in] node_dim_name A string containing the name of the dimension //! specifying the total number of nodes in the unstructured //! portion of the mesh; for layered-grid unstructured meshes \p node_dim_name //! specifies the number of nodes in a single layer //! //! \param[in] face_dim_name A string containing the name of the dimension //! specifying the total number of faces in the unstructured //! portion of the mesh; for layered-grid unstructured meshes \p face_dim_name //! specifies the number of faces in a single layer //! //! \param[in] face_node_var The name of a 2D Auxiliary variable //! (See DC:AuxVar) with //! integer type identifying for //! every face the indices of its corner nodes. The corner nodes should be //! specified in anticlockwise direction as viewed from above The //! connectivity array will be a matrix of size //! face_dim x \p max_nodes_per_face, where face_dim is the length of the //! dimension named by \p face_dim_name, and is the slowest varying //! of the two dimensions. If a face has less corner nodes //! \p max_nodes_per_face then the last node indices shall be equal to -1. //! Indecies start from zero. //! //! \param[in] node_face_var The name of a 2D Auxiliary variable //! (See DC:AuxVar) with //! integer type identifying for //! every node the indices of the faces that share the node. //! The faces should be //! specified in anticlockwise direction as viewed from above The //! connectivity array will be a matrix of size //! node_dim x \p max_faces_per_node , where node_dim is the length of the //! dimension named by \p node_dim_name, and is the slowest varying //! of the two dimensions. If a node has less faces then //! \p max_faces_per_node then the last face indices shall be equal to -1. //! Indecies start from zero. //! //! \note The \p node_face_var is not defined by the UGRID conventions //! class Mesh { public: //! Type of mesh // enum Type { STRUCTURED, //!< A structured mesh UNSTRUC_2D, //!< An unstructured mesh with 2D topology UNSTRUC_LAYERED, //!< An unstructured layered mesh UNSTRUC_3D //!< An fully unstructured mesh with 3D topology }; //! Location of sampled data variables within the mesh // enum Location { NODE, //!< Samples located at mesh nodes EDGE, //!< Samples located at mesh edge centers FACE, //!< Samples located at mesh face centers VOLUME //!< Samples located at mesh volume centers }; Mesh() { _name.clear(); _dim_names.clear(); _coord_vars.clear(); _max_nodes_per_face = 0; _max_faces_per_node = 0; _node_dim_name.clear(); _face_dim_name.clear(); _layers_dim_name.clear(); _face_node_var.clear(); _node_face_var.clear(); _face_edge_var.clear(); _face_face_var.clear(); _edge_dim_name.clear(); _edge_node_var.clear(); _edge_face_var.clear(); _mtype = STRUCTURED; } //! Construct structured mesh //! //! This method constructs a structured mesh. //! //! \param[in] name Name of the mesh. If \p name is the empty string //! a name will be created from the concatenation of the elements //! of the \p dim_names parameter //! //! \param[in] dim_names An ordered list of names of the //! spatial dimensions of //! the mesh. The ordering is from fastest varying dimension to slowest. //! The number of elements in \p dim_names determines the dimensionality //! of the mesh, but not, in general, the topological dimension of the //! mesh. The rank of \p dim_names defines //! the topological dimension. //! Mesh(std::string name, std::vector dim_names, std::vector coord_vars); //! Construct unstructured 2D mesh //! //! This method constructs an unstructured mesh with 2D topology. //! Mesh(std::string name, size_t max_nodes_per_face, size_t max_faces_per_node, std::string node_dim_name, std::string face_dim_name, std::vector coord_vars, std::string face_node_var, std::string node_face_var); //! Construct unstructured layered mesh //! //! This method constructs an unstructured layered mesh. //! //! \param[in] layers_dim_name Name of dimension specifying the number //! of layers in the mesh. // Mesh(std::string name, size_t max_nodes_per_face, size_t max_faces_per_node, std::string node_dim_name, std::string face_dim_name, std::string layers_dim_name, std::vector coord_vars, std::string face_node_var, std::string node_face_var); //! Construct unstructured 3d mesh //! //! This method constructs an unstructured 3d mesh. //! //! \param[in] layers_dim_name Name of dimension specifying the number //! of layers in the mesh. // Mesh(std::string name, int max_nodes_per_face, int max_faces_per_node, std::string node_dim_name, std::string face_dim_name, std::vector coord_vars); //! Return the type of mesh //! //! Returns one of: //! //! \li \c STRUCTURED A structured mesh //! //! \li \c UNSTRUC_2D An unstructured mesh with 2D topology //! //! \li \c UNSTRUC_LAYERED An unstructured layered mesh //! //! \li \c UNSTRUC_3D An fully unstructured mesh with 3D topology //! //! Mesh::Type GetMeshType() const { return (_mtype); } //! Get mesh name // string GetName() const { return (_name); }; //! Get dim names //! //! Returns ordered list of dimension names for the mesh nodes. The //! ordering is from fastest to slowest varying dimension. //! For //! structured meshes the size of the returned vector matches the //! topological dimensionality of the mesh. //! //! For //! unstructured meshes the returned contains the names of the //! node dimensions. // std::vector GetDimNames() const { return (_dim_names); }; //! Get coordinate variable names //! //! Returns the list of coordinate variable names associated with //! the nodes of the mesh. // std::vector GetCoordVars() const { return (_coord_vars); }; void SetCoordVars(std::vector coord_vars) { _coord_vars = coord_vars; }; //! Get geometric dimension of cells //! //! Returns the geometric dimension of the cells in the mesh. I.e. //! the number of spatial spatial coordinates for each grid point. //! Valid values are 0..3. The geometric dimension must be equal to //! or greater than the topology dimension. //! //! \sa GetTopologyDim() // size_t GetGeometryDim() const { return (_coord_vars.size()); } //! Get the maximum number of nodes per face //! //! Return the maximum number of nodes that a face in the mesh may have. //! For structured meshes this value is always four. //! size_t GetMaxNodesPerFace() const { return (_max_nodes_per_face); }; //! Get the maximum number of faces per node //! //! Return the maximum number of faces that a node in the mesh may have. //! For structured meshes this value is always four. //! size_t GetMaxFacesPerNode() const { return (_max_faces_per_node); }; //! Get the name of the node dimension //! //! For unstructured meshes this method returns the name of the //! node dimension. For structured meshes an emptry string is returned. //! string GetNodeDimName() const { return (_node_dim_name); }; //! Get the name of the face dimension //! //! For unstructured meshes this method returns the name of the //! face dimension. For structured meshes an emptry string is returned. //! string GetFaceDimName() const { return (_face_dim_name); }; //! Get the name of the layers dimension //! //! For unstructured layered meshes this method returns the name of the //! node dimension. For other meshes an empty string is returned. //! string GetLayersDimName() const { return (_layers_dim_name); }; //! Get the name of face node connectivity var //! //! Return the name of the face node connecity variable //! string GetFaceNodeVar() const { return (_face_node_var); } void SetFaceNodeVar(std::string face_node_var) { if (_mtype == STRUCTURED) return; _face_node_var = face_node_var; } //! Get the name of node face connectivity var //! //! Return the name of the node face connecity variable //! string GetNodeFaceVar() const { return (_node_face_var); } void SetNodeFaceVar(std::string node_face_var) { if (_mtype == STRUCTURED) return; _node_face_var = node_face_var; } //! Set the name of the optional edge dimension //! //! For unstructured meshes this method sets the name of the optional //! edge dimension. It is only needed if data are located on mesh edges. //! //! \param[in] edge_dim_name Name of the edge dimension //! void SetEdgeDimName(std::string edge_dim_name) { if (_mtype == STRUCTURED) return; _edge_dim_name = edge_dim_name; } //! Get the name of the optional edge dimension //! //! This method gets the name of the optional //! edge dimension. If not explicitly set with SetEdgeDimName() an //! empty string is returned. //! std::string GetEdgeDimName() const { return (_edge_dim_name); } //! Set the name of optional edge node connectivity index variable //! //! For meshes with data located on edges this method specifies the //! name of an index variable identifying for every edge the indices of its //! begining and ending nodes. The connectivity array will thus be a matrix //! of size edge_dim x 2, where edge_dim is the dimension length named //! by edge_dim_name. //! //! \sa GetEdgeDimName() //! void SetEdgeNodeVar(std::string edge_node_var) { if (_mtype == STRUCTURED) return; _edge_node_var = edge_node_var; } //! Get the name of optional edge node connectivity index variable //! //! An emptry string is returned if not explicitly set with //! SetEdgeNodeVar() // std::string GetEdgeNodeVar() const { return (_edge_node_var); } //! Set the name of optional face edge connectivity index variable //! //! The name of an optional 2D Auxiliary variable //! (See DC:AuxVar) with //! integer type. //! If specified, names an index variable identifying //! for every face the indices of its edges. The edges should be specified //! in anticlockwise direction as viewed from above. This connectivity //! array will be a matrix of size face_dim x max_faces_per_node, //! where face_dim is the dimension length named by \p face_dim_name, //! and is the slowest varying of the two dimensions. //! If a face //! has less corners/edges than max_faces_per_node then the last edge //! indices shall be equal to -1. The starting index is 0. //! // void SetFaceEdgeVar(std::string face_edge_var) { if (_mtype == STRUCTURED) return; _face_edge_var = face_edge_var; } //! Get the name of optional face edge connectivity index variable //! //! An emptry string is returned if not explicitly set with //! SetFaceEdgeVar() // std::string GetFaceEdgeVar() const { return (_face_edge_var); } //! Set the name of optional face-face connectivity index variable //! //! The name of an optional 2D Auxiliary variable //! (See DC:AuxVar) with //! integer type. //! If specified, names an index variable identifying //! for every face the indices of its adjacent faces. The faces should //! be specified //! in anticlockwise direction as viewed from above. This connectivity //! array will be a matrix of size face_dim x max_faces_per_node, where //! face_dim is the dimension length named by \p face_dim_name, and //! is the slowest varying of the two dimensions. If a face //! has less corners/edges than max_faces_per_node then the last face //! indices shall be equal to -1. The starting index is 0. //! // void SetFaceFaceVar(std::string face_face_var) { if (_mtype == STRUCTURED) return; _face_face_var = face_face_var; } //! Get the name of optional face edge connectivity index variable //! //! An emptry string is returned if not explicitly set with //! SetFaceFaceVar() // std::string GetFaceFaceVar() const { return (_face_face_var); } //! Set the name of optional edge-face connectivity index variable //! //! The name of an optional 2D Auxiliary variable //! (See DC:AuxVar) with //! integer type. //! If specified, names an index variable identifying //! for every edge the indices of its adjacent faces. //! This connectivity array is thus a matrix of size edge_dim x 2, //! where edge_dim is the dimension length named by \p edge_dim_name, and //! is the slowest varying of the two dimensions. It is //! intended to be used in combination with data defined on edges. //! The starting index is 0. //! //! \sa SetEdgeDimName() // void SetEdgeFaceVar(std::string edge_face_var) { if (_mtype == STRUCTURED) return; _edge_face_var = edge_face_var; } //! Get the name of optional face edge connectivity index variable //! //! An emptry string is returned if not explicitly set with //! SetEdgeFaceVar() // std::string GetEdgeFaceVar() const { return (_edge_face_var); } //! Get topological dimension of the mesh //! //! Return the number of topological dimensions for the mesh cells. Valid //! values are in the range 0..3, with, for example, 0 corresponding //! to points; 1 to lines; 2 to triangles, quadrilaterals, etc.; and //! 3 to hexahedron, tetrahedron, etc. //! //! \sa GetGeometryDim() // size_t GetTopologyDim() const; //! Generate a mesh name from a list of strings. The //! generated name is simply the join of the elements of \p s //! using 'x' as a delimiter // static string MakeMeshName(std::vector s); friend std::ostream &operator<<(std::ostream &o, const Mesh &mesh); private: string _name; std::vector _dim_names; std::vector _coord_vars; size_t _max_nodes_per_face; size_t _max_faces_per_node; string _node_dim_name; string _face_dim_name; string _layers_dim_name; string _face_node_var; string _node_face_var; string _face_edge_var; string _face_face_var; string _edge_dim_name; string _edge_node_var; string _edge_face_var; Mesh::Type _mtype; void _Mesh(string name, std::vector coord_vars, int max_nodes_per_face, int max_faces_per_node, Type type); }; //! \class Attribute //! //! \brief Variable or global metadata //! class Attribute { public: Attribute() { _name = ""; _type = FLOAT; _values.clear(); }; //! Attribute constructor //! //! \param[in] name The name of the attribute //! \param[in] type External representation format //! \param[in] values A vector specifying the attribute's values // Attribute(string name, XType type, const std::vector &values); Attribute(string name, XType type, const std::vector &values); Attribute(string name, XType type, const std::vector &values); Attribute(string name, XType type, const std::vector &values); Attribute(string name, XType type, const string &values); Attribute(string name, XType type) { _name = name; _type = type; _values.clear(); }; virtual ~Attribute(){}; //! Get attribute name // string GetName() const { return (_name); }; //! Get an attribute's external representation type // XType GetXType() const { return (_type); }; //! Get an attribute's value(s) //! //! Get the value(s) for an attribute, performing type conversion //! as necessary from the external storage type to the desired type //! VDF_API void GetValues(std::vector &values) const; VDF_API void GetValues(std::vector &values) const; VDF_API void GetValues(std::vector &values) const; VDF_API void GetValues(std::vector &values) const; VDF_API void GetValues(string &values) const; //! Set an attribute's value(s) //! //! Set the value(s) for an attribute, performing type conversion //! as necessary to meet the external storage type. //! void SetValues(const std::vector &values); void SetValues(const std::vector &values); void SetValues(const std::vector &values); void SetValues(const std::vector &values); void SetValues(const string &values); friend std::ostream &operator<<(std::ostream &o, const Attribute &attr); private: string _name; XType _type; union podunion { float f; double d; int i; long l; char c; }; std::vector _values; }; //! \class BaseVar //! //! \brief Base class for storing variable metadata // class BaseVar { public: BaseVar() { _name.clear(); _units.clear(); _type = FLOAT; _wname.clear(); _cratios.clear(); _periodic.clear(); _atts.clear(); } //! Constructor //! //! \param[in] name The variable's name //! //! \param[in] units A string recognized by Udunits-2 specifying the //! unit measure for the variable. An empty string indicates that the //! variable is unitless. //! \param[in] type The external storage type for variable data //! \param[in] wname The wavelet family name for compressed variables //! \param[in] cratios Specifies a vector of compression factors for //! compressed variable definitions. If empty, or if cratios.size()==1 //! and cratios[0]==1, the variable is not //! compressed //! //! \deprecated Results are undefined if the rank of //! of \p periodic does not match that of \p dimensions. //! BaseVar(string name, string units, XType type, string wname, std::vector cratios, std::vector periodic) : _name(name), _units(units), _type(type), _wname(wname), _cratios(cratios), _periodic(periodic) { if (_cratios.size() == 0) _cratios.push_back(1); }; //! No compression constructor //! //! \param[in] name The variable's name //! \deprecated \param[in] dimensions An ordered vector //! specifying the variable's spatial //! and/or temporal dimensions //! //! \param[in] units A string recognized by Udunits-2 specifying the //! unit measure for the variable. An empty string indicates that the //! variable is unitless. //! \param[in] type The external storage type for variable data //! factor for the variable. //! \deprecated \param[in] periodic An ordered array of booleans //! specifying the //! spatial boundary periodicity. //! Results are undefined if the rank of //! of \p periodic does not match that of \p dimensions. //! BaseVar(string name, string units, XType type, std::vector periodic); virtual ~BaseVar(){}; //! Get variable name // string GetName() const { return (_name); }; void SetName(string name) { _name = name; }; //! Access variable units // string GetUnits() const { return (_units); }; void SetUnits(string units) { _units = units; }; //! Access variable external storage type // XType GetXType() const { return (_type); }; void SetXType(XType type) { _type = type; }; //! Access variable's wavelet family name // string GetWName() const { return (_wname); }; void SetWName(string wname) { _wname = wname; }; //! Access variable's compression ratios // std::vector GetCRatios() const { return (_cratios); }; void SetCRatios(std::vector cratios) { _cratios = cratios; if (_cratios.size() == 0) _cratios.push_back(1); }; //! \deprecated Access variable bounary periodic // std::vector GetPeriodic() const { return (_periodic); }; void SetPeriodic(std::vector periodic) { _periodic = periodic; }; //! Access variable attributes // const std::map &GetAttributes() const { return (_atts); }; void SetAttributes(std::map &atts) { _atts = atts; }; bool GetAttribute(string name, Attribute &att) const { std::map::const_iterator itr = _atts.find(name); if (itr == _atts.end()) return (false); att = itr->second; return (true); } void SetAttribute(const Attribute &att) { _atts[att.GetName()] = att; } //! Return true if no wavelet is defined // bool IsCompressed() const { return (!_wname.empty()); }; friend std::ostream &operator<<(std::ostream &o, const BaseVar &var); private: string _name; string _units; XType _type; string _wname; std::vector _cratios; std::vector _periodic; std::map _atts; }; //! \class CoordVar //! \brief Coordinate variable metadata // class CoordVar : public BaseVar { public: CoordVar() { _dim_names.clear(); _time_dim_name.clear(); _axis = 0; _uniform = true; } //! Construct coordinate variable //! //! \copydetails BaseVar(string name, //! string units, XType type, bool compressed, //! string wname, //! std::vector cratios, //! std::vector periodic) //! //! \param[in] dim_names An ordered list of names of the spatial //! dimensions of //! the coordinate variable. The ordering is from fastest varying //! dimension to slowest. //! The number of elements in \p dim_names determines the dimensionality //! of the coordinate variable. //! //! \param[in] time_dim_name Name of time varying dimension, if any. If //! the coordinate variable varies over time this parameter names //! the time dimension. If \p time_dim_name is the empty string //! the coordiante variable is constant over time. //! //! \param[in] axis an int in the range 0..3 indicating the coordinate //! axis, one of X, Y, Z, or T, respectively //! \param[in] uniform A bool indicating whether the coordinate variable //! is uniformly sampled. // CoordVar(string name, string units, XType type, string wname, std::vector cratios, std::vector periodic, std::vector dim_names, string time_dim_name, int axis, bool uniform) : BaseVar(name, units, type, wname, cratios, periodic), _dim_names(dim_names), _time_dim_name(time_dim_name), _axis(axis), _uniform(uniform) { } //! Construct coordinate variable without compression //! //! \copydetails BaseVar(string name, //! string units, XType type, std::vector periodic) //! //! \param[in] dim_names An ordered list of names of the spatial //! dimensions of //! the coordinate variable. The ordering is from fastest varying //! dimension to slowest. //! The number of elements in \p dim_names determines the dimensionality //! of the coordinate variable. //! //! \param[in] time_dim_name Name of time varying dimension, if any. If //! the coordinate variable varies over time this parameter names //! the time dimension. If \p time_dim_name is the empty string //! the coordiante variable is constant over time. //! //! \param[in] axis an int in the range 0..3 indicating the coordinate //! axis, one of X, Y, Z, or T, respectively //! \param[in] uniform A bool indicating whether the coordinate variable //! is uniformly sampled. // CoordVar(string name, string units, XType type, std::vector periodic, int axis, bool uniform, std::vector dim_names, string time_dim_name) : BaseVar(name, units, type, periodic), _dim_names(dim_names), _time_dim_name(time_dim_name), _axis(axis), _uniform(uniform) { } virtual ~CoordVar(){}; //! Access coordinate variable spatial dimension names //! \version 3.1 // std::vector GetDimNames() const { return (_dim_names); }; void SetDimNames(std::vector dim_names) { _dim_names = dim_names; }; //! Access coordinate variable time dimension name //! \version 3.1 // string GetTimeDimName() const { return (_time_dim_name); }; void SetTimeDimName(string time_dim_name) { _time_dim_name = time_dim_name; }; //! Access coordinate variable axis // int GetAxis() const { return (_axis); }; void SetAxis(int axis) { _axis = axis; }; //! Access coordinate variable uniform sampling flag // bool GetUniform() const { return (_uniform); }; void SetUniform(bool uniform) { _uniform = uniform; }; friend std::ostream &operator<<(std::ostream &o, const CoordVar &var); private: std::vector _dim_names; string _time_dim_name; int _axis; bool _uniform; }; //! \class DataVar //! \brief Data variable metadata //! //! This class defines metadata associatd with a Data variable //! class DataVar : public BaseVar { public: DataVar() { _mesh.clear(); _time_coord_var.clear(); _location = Mesh::NODE; _maskvar.clear(); _has_missing = false; _missing_value = 0.0; } //! Construct Data variable definition with missing values //! //! Elements of the variable whose value matches that specified by //! \p missing_value are considered invalid //! //! \copydetails BaseVar(string name, //! string units, XType type, //! string wname, //! std::vector cratios, //! std::vector periodic) //! //! \param[in] mesh Name of mesh upon which this variable is sampled //! //! \param[in] time_coord_var Name of time coordinate variable. If //! the variable is time varying this parameter provides the name of //! it's time coordinate variable. If the variable is invariant over time //! \p time_coord_var should be the empty string. //! //! \param[in] location Location of samples on Mesh. Samples can be //! located at the Mesh nodes, edge centers, face centers, or //! volume centers. //! //! \param[in] missing_value Value of the missing value indicator //! DataVar(string name, string units, XType type, string wname, std::vector cratios, std::vector periodic, string mesh, string time_coord_var, Mesh::Location location, double missing_value) : BaseVar(name, units, type, wname, cratios, periodic), _mesh(mesh), _time_coord_var(time_coord_var), _location(location), _maskvar(""), _has_missing(true), _missing_value(missing_value) { } //! Construct Data variable definition with a mask variable //! //! This version of the constructor specifies the name of a variable //! \p varmask whose contents indicate the presense or absense of invalid //! entries in the data variable. The contents of the mask array are treated //! as booleans, true values indicating valid data. The rank of of the //! variable may be less than or equal to that of \p name. The dimensions //! of \p maskvar must match the fastest varying dimensions of \p name. //! //! \copydetails BaseVar(string name, //! string units, XType type, //! string wname, //! std::vector cratios, //! std::vector periodic) //! //! \param[in] mesh Name of mesh upon which this variable is sampled //! //! \param[in] time_coord_var Name of time coordinate variable. If //! the variable is time varying this parameter provides the name of //! it's time coordinate variable. If the variable is invariant over time //! \p time_coord_var should be the empty string. //! //! \param[in] location Location of samples on Mesh. Samples can be //! located at the Mesh nodes, edge centers, face centers, or //! volume centers. //! //! \param[in] missing_value Value used to fill masked values //! \param[in] maskvar Name of variable containing mask array. //! DataVar(string name, string units, XType type, string wname, std::vector cratios, std::vector periodic, string mesh, string time_coord_var, Mesh::Location location, double missing_value, string maskvar) : BaseVar(name, units, type, wname, cratios, periodic), _mesh(mesh), _time_coord_var(time_coord_var), _location(location), _maskvar(maskvar), _has_missing(true), _missing_value(missing_value) { } //! Construct Data variable definition without missing values //! //! \copydetails BaseVar(string name, //! string units, XType type, //! string wname, //! std::vector cratios, //! vector periodic) //! //! \deprecated \param[in] coord_vars Names of coordinate variables //! associated //! with this variables dimensions //! //! \param[in] mesh Name of mesh upon which this variable is sampled //! //! \param[in] time_coord_var Name of time coordinate variable. If //! the variable is time varying this parameter provides the name of //! it's time coordinate variable. If the variable is invariant over time //! \p time_coord_var should be the empty string. //! //! \param[in] location Location of samples on Mesh. Samples can be //! located at the Mesh nodes, edge centers, face centers, or //! volume centers. //! DataVar(string name, string units, XType type, string wname, std::vector cratios, std::vector periodic, string mesh, string time_coord_var, Mesh::Location location) : BaseVar(name, units, type, wname, cratios, periodic), _mesh(mesh), _time_coord_var(time_coord_var), _location(location), _maskvar(""), _has_missing(false), _missing_value(0.0) { } //! Construct Data variable definition with missing values but no compression //! //! \copydetails BaseVar(string name, //! string units, XType type, //! std::vector periodic) //! //! \deprecated \param[in] coord_vars Names of coordinate variables //! associated //! with this variables dimensions //! //! \param[in] mesh Name of mesh upon which this variable is sampled //! //! \param[in] time_coord_var Name of time coordinate variable. If //! the variable is time varying this parameter provides the name of //! it's time coordinate variable. If the variable is invariant over time //! \p time_coord_var should be the empty string. //! //! \param[in] location Location of samples on Mesh. Samples can be //! located at the Mesh nodes, edge centers, face centers, or //! volume centers. //! //! \param[in] missing_value Value of the missing value indicator //! DataVar(string name, string units, XType type, std::vector periodic, string mesh, string time_coord_var, Mesh::Location location, double missing_value) : BaseVar(name, units, type, periodic), _mesh(mesh), _time_coord_var(time_coord_var), _location(location), _maskvar(""), _has_missing(true), _missing_value(missing_value) { } //! Construct Data variable definition with a mask but no compression //! //! This version of the constructor specifies the name of a variable //! \p varmask whose contents indicate the presense or absense of invalid //! entries in the data variable. The contents of the mask array are treated //! as booleans, true values indicating valid data. The rank of of the //! variable may be less than or equal to that of \p name. The dimensions //! of \p maskvar must match the fastest varying dimensions of \p name. //! //! \copydetails BaseVar(string name, //! string units, XType type, //! std::vector periodic) //! //! \deprecated \param[in] coord_vars Names of coordinate //! variables associated //! //! \param[in] mesh Name of mesh upon which this variable is sampled //! //! \param[in] time_coord_var Name of time coordinate variable. If //! the variable is time varying this parameter provides the name of //! it's time coordinate variable. If the variable is invariant over time //! \p time_coord_var should be the empty string. //! //! \param[in] location Location of samples on Mesh. Samples can be //! located at the Mesh nodes, edge centers, face centers, or //! volume centers. //! //! with this variables dimensions //! \param[in] missing_value Value used to fill masked values //! \param[in] maskvar Name of variable containing mask array. //! DataVar(string name, string units, XType type, std::vector periodic, string mesh, string time_coord_var, Mesh::Location location, double missing_value, string maskvar) : BaseVar(name, units, type, periodic), _mesh(mesh), _time_coord_var(time_coord_var), _location(location), _maskvar(maskvar), _has_missing(true), _missing_value(missing_value) { } //! Construct Data variable definition with no missing values or compression //! //! \copydetails BaseVar(string name, //! string units, XType type, //! std::vector periodic) //! //! \param[in] coord_vars Names of coordinate variables associated //! with this variables dimensions //! //! \param[in] time_coord_var Name of time coordinate variable. If //! the variable is time varying this parameter provides the name of //! it's time coordinate variable. If the variable is invariant over time //! \p time_coord_var should be the empty string. //! //! DataVar(string name, string units, XType type, std::vector periodic, string mesh, string time_coord_var, Mesh::Location location) : BaseVar(name, units, type, periodic), _mesh(mesh), _time_coord_var(time_coord_var), _location(location), _maskvar(""), _has_missing(false), _missing_value(0.0) { } virtual ~DataVar(){}; //! Access variable's mesh name //! \version 3.1 // string GetMeshName() const { return (_mesh); }; void SetMeshName(string mesh) { _mesh = mesh; }; //! Access variable's time coordinate variable name //! \version 3.1 // string GetTimeCoordVar() const { return (_time_coord_var); } void SetTimeCoordVar(string time_coord_var) { _time_coord_var = time_coord_var; } //! Access variable's sampling location on mesh //! \version 3.1 // Mesh::Location GetSamplingLocation() const { return (_location); } //! Access data variable's mask variable names // string GetMaskvar() const { return (_maskvar); }; void SetMaskvar(string maskvar) { _maskvar = maskvar; }; //! Access data variable's missing data flag // bool GetHasMissing() const { return (_has_missing); }; void SetHasMissing(bool has_missing) { _has_missing = has_missing; }; //! Access data variable's missing data value // double GetMissingValue() const { return (_missing_value); }; void SetMissingValue(double missing_value) { _missing_value = missing_value; }; VDF_API friend std::ostream &operator<<(std::ostream &o, const DataVar &var); private: string _mesh; string _time_coord_var; Mesh::Location _location; string _maskvar; bool _has_missing; double _missing_value; }; //! \class AuxVar //! \version 3.1 //! //! \brief Auxiliary variable metadata //! //! This class defines metadata associatd with an Auxiliary variable. //! An Auxiliary variable is neither a data variable, nor a coordinate //! variable. //! class AuxVar : public BaseVar { public: AuxVar() { _dim_names.clear(); _offset = 0; } //! Construct Auxiliary variable definition //! //! \copydetails BaseVar(string name, //! string units, XType type, //! string wname, //! std::vector cratios, //! std::vector periodic) //! //! \param[in] dim_names An ordered list of names of the dimensions of //! the coordinate variable. The ordering is from fastest varying //! dimension to slowest. //! The number of elements in \p dim_names determines the dimensionality //! of the auxiliary variable. //! AuxVar(string name, string units, XType type, string wname, std::vector cratios, std::vector periodic, std::vector dim_names) : BaseVar(name, units, type, wname, cratios, periodic), _dim_names(dim_names), _offset(0) { } virtual ~AuxVar(){}; //! Access Auxiliary variable dimension names // std::vector GetDimNames() const { return (_dim_names); }; void SetDimNames(std::vector dim_names) { _dim_names = dim_names; }; //! Access Auxiliary variable's offset //! //! The value of \p offset should be added to the Auxiliary variable's data // long GetOffset() const { return (_offset); }; void SetOffset(long offset) { _offset = offset; }; VDF_API friend std::ostream &operator<<(std::ostream &o, const AuxVar &var); private: std::vector _dim_names; long _offset; }; //! Class constuctor //! //! DC(); virtual ~DC(){}; //! Initialize the DC class //! //! Prepare a DC for reading. This method prepares //! the master DC file indicated by \p path for reading. //! The method should be called immediately after the constructor, //! before any other class methods. This method //! exists only because C++ constructors can not return error codes. //! //! \param[in] path Path name of file that contains, or will //! contain, the DC master file for this data collection //! //! \param[in] options A vector of option pairs (name, value) that //! may be accepted by the derived class. //! //! \retval status A negative int is returned on failure //! // virtual int Initialize(const std::vector &paths, const std::vector &options = std::vector()) { return (initialize(paths, options)); } //! Return a dimensions's definition //! //! This method returns the definition of the dimension named //! by \p dimname as a reference to a DC::Dimension object. If //! \p dimname is not defined as a dimension then the name of \p dimension //! will be the empty string() //! //! \param[in] dimname A string specifying the name of the dimension. //! \param[out] dimension The returned Dimension object reference //! \retval bool If the named dimension can not be found false is returned. //! virtual bool GetDimension(string dimname, DC::Dimension &dimension, long ts) const { return (getDimension(dimname, dimension, ts)); } //! Return names of all defined dimensions //! //! This method returns the list of names of all of the dimensions //! defined in the DC. //! virtual std::vector GetDimensionNames() const { return (getDimensionNames()); } //! Return names of all defined meshes //! //! This method returns the list of names of all of the meshes //! defined in the DC. //! virtual std::vector GetMeshNames() const { return (getMeshNames()); } //! Return a Mesh's definition //! //! This method returns the definition of the mesh named //! by \p mesh_name as a reference to a DC::Mesh object. //! //! \param[in] mesh_name A string specifying the name of the Mesh. //! \param[out] mesh The returned Mesh object reference //! \retval bool If the named mesh can not be found false is returned. //! virtual bool GetMesh(string mesh_name, DC::Mesh &mesh) const { return (getMesh(mesh_name, mesh)); } //! Return the ordered list of dimensions for a mesh //! //! This method is a convenience function that returns the ordered //! vector of dimension lengths for the mesh named \p mesh. If \p mesh //! is unknown, or invalid false is returned. //! //! \sa DC::GetMesh(), DC::GetDimension() // virtual bool GetMeshDimLens(const string &mesh_name, std::vector &dims, long ts = -1) const; //! Return the ordered list of dimension names for a mesh //! //! This method is a convenience function that returns the ordered //! vector of dimension names for the mesh named \p mesh. If \p mesh //! is unknown, or invalid false is returned. //! //! \sa DC::GetMesh(), DC::GetDimension() // virtual bool GetMeshDimNames(const string &mesh_name, std::vector &dimnames) const; //! Return a coordinate variable's definition //! //! Return a reference to a DC::CoordVar object describing //! the coordinate variable named by \p varname //! //! \param[in] varname A string specifying the name of the coordinate //! variable. //! \param[out] coordvar A CoordVar object containing the definition //! of the named variable. //! \retval bool False is returned if the named coordinate variable does //! not exist, and the contents of \p cvar will be undefined. //! virtual bool GetCoordVarInfo(string varname, DC::CoordVar &cvar) const { return (getCoordVarInfo(varname, cvar)); } //! Return a data variable's definition //! //! Return a reference to a DC::DataVar object describing //! the data variable named by \p varname //! //! \param[in] varname A string specifying the name of the variable. //! \param[out] datavar A DataVar object containing the definition //! of the named Data variable. //! //! \retval bool If the named data variable cannot be found false //! is returned and the values of \p datavar are undefined. //! virtual bool GetDataVarInfo(string varname, DC::DataVar &datavar) const { return (getDataVarInfo(varname, datavar)); } //! Return metadata about an auxiliary variable //! //! If the variable \p varname is defined as an auxiliary //! variable its metadata will //! be returned in \p var. //! //! \retval bool If the named variable cannot be found false //! is returned and the values of \p var are undefined. //! //! \sa GetDataVarInfo(), GetCoordVarInfo() // virtual bool GetAuxVarInfo(string varname, DC::AuxVar &var) const { return (getAuxVarInfo(varname, var)); } //! Return metadata about a data or coordinate variable //! //! If the variable \p varname is defined as either a //! data or coordinate variable its metadata will //! be returned in \p var. //! //! \retval bool If the named variable cannot be found false //! is returned and the values of \p var are undefined. //! //! \sa GetDataVarInfo(), GetCoordVarInfo() // virtual bool GetBaseVarInfo(string varname, DC::BaseVar &var) const { return (getBaseVarInfo(varname, var)); } //! Return a list of names for all of the defined data variables. //! //! Returns a list of names for all data variables defined //! //! \sa DC::DataVar // virtual std::vector GetDataVarNames() const { return (getDataVarNames()); } //! Return a list of names for all of the defined coordinate variables. //! //! Returns a list of names for all coordinate variables defined //! //! \sa DC::CoordVar // virtual std::vector GetCoordVarNames() const { return (getCoordVarNames()); } //! Return a list of names for all of the defined Auxiliary variables. //! //! Returns a list of names for all Auxiliary variables defined //! //! \sa DC::AuxVar // virtual std::vector GetAuxVarNames() const { return (getAuxVarNames()); } //! Return the number of refinement levels for the indicated variable //! //! Compressed variables may have a multi-resolution grid representation. //! This method returns the number of levels in the hiearchy. A value //! of one indicates that only the native resolution is available. //! A value of two indicates that two levels, the native plus the //! next coarsest are available, and so on. //! //! \param[in] varname Data or coordinate variable name. //! //! \retval num If \p varname is unknown one is returned. if \p varname //! is not compressed (has no multi-resolution representation) one is //! returned. Otherwise the total number of levels in the multi-resolution //! hierarchy are returned. // virtual size_t GetNumRefLevels(string varname) const { return (getNumRefLevels(varname)); } //! Read an attribute //! //! This method reads an attribute from the DC. The attribute can either //! be "global", if \p varname is the empty string, or bound to a variable //! if \p varname indentifies a variable in the DC. //! //! \param[in] varname The name of the variable the attribute is bound to, //! or the empty string if the attribute is global //! \param[in] attname The attributes name //! \param[out] type The primitive data type storage format. //! This is the type that will be used to store the //! attribute on disk //! \param[out] values A vector to contain the returned floating point //! attribute values //! //! \retval status True is returned on success. False is returned if either //! the variable or the attribute is undefined. //! // virtual bool GetAtt(string varname, string attname, vector &values) const { return (getAtt(varname, attname, values)); } virtual bool GetAtt(string varname, string attname, vector &values) const { return (getAtt(varname, attname, values)); } virtual bool GetAtt(string varname, string attname, string &values) const { return (getAtt(varname, attname, values)); } //! Return a list of available attribute's names //! //! Returns a vector of all attribute names for the //! variable, \p varname. If \p varname is the empty string the names //! of all of the global attributes are returned. If \p varname is //! not defined an empty vector is returned. //! //! \param[in] varname The name of the variable to query, //! or the empty string if the names of global attributes are desired. //! \retval attnames A vector of returned attribute names //! //! \sa GetAtt() // virtual std::vector GetAttNames(string varname) const { return (getAttNames(varname)); } //! Return the external data type for an attribute //! //! Returns the external storage type of the named variable attribute. //! //! \param[in] varname The name of the variable to query, //! or the empty string if the names of global attributes are desired. //! \param[in] name Name of the attribute. //! //! \retval If an attribute named by \p name does not exist, a //! negative value is returned. //! virtual XType GetAttType(string varname, string attname) const { return (getAttType(varname, attname)); } //! Return a variable's array dimension lengths at a specified refinement level //! //! Compressed variables may have a multi-resolution grid representation. //! This method returns the variable's ordered array //! dimension lengths, //! and block dimensions //! at the multiresolution refinement level specified by \p level. //! //! If the variable named by \p varname is not compressed the variable's //! native dimensions are returned. //! //! \note The number of elements in \p dims_at_level will match that of //! \p bs_at_level. If the data are not blocked the value of each //! element of \p bs_at_level will be 1. //! //! \param[in] varname Data or coordinate variable name. //! \param[in] level Specifies a member of a multi-resolution variable's //! grid hierarchy as described above. //! \param[out] dims_at_level An ordered vector containing the variable's //! dimensions at the specified refinement level //! \param[out] bs_at_level An ordered vector containing the variable's //! block dimensions at the specified refinement level //! //! \retval status Zero is returned upon success, otherwise -1. //! //! \note For unstructured grids the number of dimensions may be //! less than the topological dimension returned by DC::Mesh::GetTopologyDim(). //! //! \sa VAPoR::DC, DC::DataVar::GetBS(), DC::GetVarDimLens() // virtual int GetDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level, long ts = -1) const { return (getDimLensAtLevel(varname, level, dims_at_level, bs_at_level, ts)); } //! Return a variable's array dimension lengths //! //! This method is equivalent to calling GetDimLensAtLevel() with \p level //! equal to -1 //! virtual int GetDimLens(string varname, std::vector &dims, long ts = -1) { vector dummy; return (GetDimLensAtLevel(varname, -1, dims, dummy, ts)); } //! Return default Proj4 map projection string. //! //! For georeference data sets that have map projections this //! method returns the default properly formatted Proj4 projection string //! for mapping from geographic to cartographic coordinates. //! If no //! projection exists, an empty string is returned. //! //! \retval projstring An empty string if a Proj4 map projection is //! not available for the named variable, otherwise a properly //! formatted Proj4 projection //! string is returned. //! // virtual string GetMapProjection() const { return (getMapProjection()); } //! Open the named variable for reading //! //! This method prepares a data or coordinate variable, indicated by a //! variable name and time step pair, for subsequent read operations by //! methods of this class. The value of the refinement levels //! parameter, \p level, indicates the resolution of the volume in //! the multiresolution hierarchy as described by GetDimLensAtLevel(). //! //! The level-of-detail parameter, \p lod, selects //! the approximation level. Valid values for \p lod are integers in //! the range 0..n-1, where \e n is returned by //! DC::BaseVar::GetCRatios().size(), or the value -1 may be used //! to select the best approximation available. //! //! An error occurs, indicated by a negative return value, if the //! volume identified by the {varname, timestep, level, lod} tupple //! is not available. Note the availability of a volume can be tested //! with the VariableExists() method. //! //! \param[in] ts Time step of the variable to read. This is the integer //! offset into the variable's temporal dimension. If the variable //! does not have a temporal dimension \p ts is ignored. //! \param[in] varname Name of the variable to read //! \param[in] level Refinement level of the variable. Ignored if the //! variable is not compressed. //! \param[in] lod Approximation level of the variable. A value of -1 //! indicates the maximum approximation level defined for the DC. //! Ignored if the variable is not compressed. //! //! \retval status Returns a non-negative file descriptor on success //! //! //! \sa GetNumRefLevels(), DC::BaseVar::GetCRatios(), OpenVariableRead() // virtual int OpenVariableRead(size_t ts, string varname, int level = 0, int lod = 0) { return (_openVariableRead(ts, varname, level, lod)); } //! Close the currently opened variable //! //! Close the handle for variable opened with OpenVariableRead() //! \param[in] fd A valid file descriptor returned by OpenVariableRead() //! //! \sa OpenVariableRead() // virtual int CloseVariable(int fd) { return (_closeVariable(fd)); } //! Read all spatial values of the currently opened variable //! //! This method reads, and decompresses as necessary, //! the contents of the currently opened variable into the array //! \p data. The number of values //! read into \p data is given by the product of the spatial //! dimensions of the open variable at the refinement level specified. //! //! It is the caller's responsibility to ensure \p data points //! to adequate space. //! //! \param[in] fd A valid file descriptor returned by OpenVariableRead() //! \param[out] data An array of data to be written //! \retval status Returns a non-negative value on success //! //! \sa OpenVariableRead() // int virtual Read(int fd, float *data) { return (_readTemplate(fd, data)); } int virtual Read(int fd, double *data) { return (_readTemplate(fd, data)); } int virtual Read(int fd, int *data) { return (_readTemplate(fd, data)); } //! Read a single slice of data from the currently opened variable //! //! Decompress, as necessary, and read a single hyperslice of //! data from the variable //! indicated by the most recent call to OpenVariableRead(). //! The dimensions and number of slices are given by //! GetHyperSliceInfo(). //! //! This method should be called exactly NZ times for each opened variable, //! where NZ is the dimension of slowest varying dimension returned by //! GetDimLensAtLevel(). //! //! It is the caller's responsibility to ensure \p slice points //! to adequate space. //! //! \param[in] fd A valid file descriptor returned by OpenVariableRead() //! \param[out] slice A slice of data //! \retval status Returns a non-negative value on success //! //! \sa OpenVariableRead(), GetHyperSliceInfo() //! virtual int ReadSlice(int fd, float *slice) { return (_readSliceTemplate(fd, slice)); } virtual int ReadSlice(int fd, double *slice) { return (_readSliceTemplate(fd, slice)); } virtual int ReadSlice(int fd, int *slice) { return (_readSliceTemplate(fd, slice)); } //! Read in and return a subregion from the currently opened //! variable //! //! This method reads and returns a subset of variable data. //! The \p min and \p max vectors, whose dimensions must match the //! spatial rank of the currently opened variable, identify the minimum and //! maximum extents, in grid coordinates, of the subregion of interest. The //! minimum and maximum valid values of an element of \b min or \b max //! are \b 0 and //! \b n-1, respectively, where \b n is the length of the associated //! dimension at the opened refinement level. //! //! The region //! returned is stored in the memory region pointed to by \p region. It //! is the caller's responsbility to ensure adequate space is available. //! //! \param[in] fd A valid file descriptor returned by OpenVariableRead() //! \param[in] min Minimum region extents in grid coordinates //! \param[in] max Maximum region extents in grid coordinates //! \param[out] region The requested volume subregion //! //! \retval status Returns a non-negative value on success //! \sa OpenVariableRead(), GetDimLensAtLevel(), GetDimensionNames() // virtual int ReadRegion(int fd, const vector &min, const vector &max, float *region) { return (readRegion(fd, min, max, region)); } virtual int ReadRegion(int fd, const vector &min, const vector &max, double *region) { return (readRegion(fd, min, max, region)); } virtual int ReadRegion(int fd, const vector &min, const vector &max, int *region) { return (readRegion(fd, min, max, region)); } //! Read an entire variable in one call //! //! This method reads and entire variable (all time steps, all grid points) //! from a DC. This is the simplest interface for reading data from //! a DC. If the variable is split across multiple files GetVar() //! ensures that the data are correctly gathered and assembled into memory //! Any variables currently opened with OpenVariableRead() are first closed. //! Thus variables need not be opened with OpenVariableRead() prior to //! calling GetVar(); //! //! It is an error to call this method in \b define mode //! //! \param[in] varname Name of the variable to write //! \param[in] level Refinement level of the variable. //! Ignored if the variable is not compressed. //! \param[in] lod Approximation level of the variable. A value of -1 //! indicates the maximum approximation level defined for the DC. //! Ignored if the variable is not compressed. //! \param[out] data Pointer to where data will be copied. It is the //! caller's responsbility to ensure \p data points to sufficient memory. //! //! \retval status A negative int is returned on failure //! // virtual int GetVar(string varname, int level, int lod, float *data) { return (_getVarTemplate(varname, level, lod, data)); } virtual int GetVar(string varname, int level, int lod, double *data) { return (_getVarTemplate(varname, level, lod, data)); } virtual int GetVar(string varname, int level, int lod, int *data) { return (_getVarTemplate(varname, level, lod, data)); } //! Read an entire variable at a given time step in one call //! //! This method reads and entire variable (all grid points) at //! time step \p ts //! from a DC. This is the simplest interface for reading data from //! a DC. //! Any variables currently opened with OpenVariableRead() are first closed. //! Thus variables need not be opened with OpenVariableRead() prior to //! calling GetVar(); //! //! It is an error to call this method in \b define mode //! //! \param[in] ts Time step of the variable to write. This is the integer //! offset into the variable's temporal dimension. If the variable //! does not have a temporal dimension \p ts is ignored. //! \param[in] varname Name of the variable to write //! \param[in] level Refinement level of the variable. //! Ignored if the variable is not compressed. //! \param[in] lod Approximation level of the variable. A value of -1 //! indicates the maximum approximation level defined for the DC. //! Ignored if the variable is not compressed. //! \param[out] data Pointer to where data will be copied. It is the //! caller's responsbility to ensure \p data points to sufficient memory. //! //! \retval status A negative int is returned on failure //! // virtual int GetVar(size_t ts, string varname, int level, int lod, float *data) { return (_getVarTemplate(ts, varname, level, lod, data)); } virtual int GetVar(size_t ts, string varname, int level, int lod, double *data) { return (_getVarTemplate(ts, varname, level, lod, data)); } virtual int GetVar(size_t ts, string varname, int level, int lod, int *data) { return (_getVarTemplate(ts, varname, level, lod, data)); } //! Returns true if indicated data volume is available //! //! Returns true if the variable identified by the timestep, variable //! name, refinement level, and level-of-detail is present in //! the data set. Returns false if //! the variable is not available. //! //! \param[in] ts A valid time step between 0 and GetNumTimesteps()-1 //! \param[in] varname A valid variable name //! \param[in] reflevel Refinement level requested. //! \param[in] lod Compression level of detail requested. //! refinement level contained in the DC. // virtual bool VariableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const { return (variableExists(ts, varname, reflevel, lod)); }; //! Get dimensions of hyperslice read by ReadSlice //! //! Returns the dimensions of a hyperslice when the variable //! \p varname is opened at level \p level and read using ReadSlice(); //! //! \param[in] varname A valid variable name //! \param[in] reflevel Refinement level requested. //! \param[out] dims An ordered vector containing the variable's //! hyperslice dimensions at the specified refinement level //! \param[out] nslice Number of hyperslices //! //! \sa GetDimLensAtLevel(), OpenVariableRead(), ReadSlice() //! virtual int GetHyperSliceInfo(string varname, int level, std::vector &dims, size_t &nslice, long ts = -1); //! Return a list of data variables with a given topological dimension //! //! Returns a list of all data variables defined having a //! a topological dimension \p ndim. //! //! \param[in] ndim Topological dimension //! //! \sa GetVarTopologyDim() // virtual std::vector GetDataVarNames(int ndim) const; // //! Return an ordered list of the variables dimensions //! //! Returns a list of a variables dimensions ordered from fastest //! to slowest. If \p time is true and the variable is time varying //! the time dimension will be included. The time dimension is always //! the slowest varying dimension. //! //! \param[in] varname A valid variable name //! \param[in] spatial If true only return spatial dimensions //! //! \param[out] dimensions Ordered list of variable dimensions //! on success. //! //! \retval Returns true upon success, false if the variable is //! not defined. //! // virtual bool GetVarDimensions(string varname, bool spatial, vector &dimensions, long ts) const; // //! Return an ordered list of the variables dimension lengths //! //! Returns a list of a variables dimension lengths ordered from fastest //! to slowest. If \p spatial is true and the variable is time varying //! the time dimension will be included. The time dimension is always //! the slowest varying dimension. //! //! \param[in] varname A valid variable name //! \param[in] spatial If true only return spatial dimensions //! //! \param[out] dimensions Ordered list of variable dimension lengths //! on success. //! //! \retval Returns true upon success, false if the variable is //! not defined. //! // virtual bool GetVarDimLens(string varname, bool spatial, vector &dimlens, long ts = -1) const; //! Return an ordered list of the variables dimension lengths //! //! Returns a list of a variable's spatial dimension lengths ordered from //! fastest to slowest, and, if the variable is time varying, the variable's //! time dimension lengths is returned as well. //! //! \param[in] varname A valid variable name //! \param[out] sdimlens Ordered list of variable spatial dimension lengths //! on success. //! \param[out] time_dimlen The variable's time dimension length. If //! the variable is not time varying \p time_dim_length will be set to 0. //! //! \retval Returns true upon success, false if the variable is //! not defined. //! // virtual bool GetVarDimLens(string varname, vector &sdimlens, size_t &time_dimlen, long ts = -1) const; //! Return an ordered list of the variables dimension names //! //! Returns a list of a variables dimension names ordered from fastest //! to slowest. If \p spatial is true and the variable is time varying //! the time dimension names will be included. The time dimension is always //! the slowest varying dimension. //! //! \param[in] varname A valid variable name //! \param[in] spatial If true only return spatial dimensions //! //! \param[out] dimensions Ordered list of variable dimension names //! on success. //! //! \retval Returns true upon success, false if the variable is //! not defined. //! // virtual bool GetVarDimNames(string varname, bool spatial, vector &dimnames) const; //! Return an ordered list of the variables dimension names //! //! Returns a list of a variable's spatial dimension names ordered from //! fastest to slowest, and, if the variable is time varying, the variable's //! time dimension name is returned as well. //! //! \param[in] varname A valid variable name //! \param[out] sdimnames Ordered list of variable spatial dimension names //! on success. //! \param[out] time_dimname The variable's time dimension name. If //! the variable is not time varying \p time_dim_name will be set to the //! emptry string. //! //! \retval Returns true upon success, false if the variable is //! not defined. //! // virtual bool GetVarDimNames(string varname, vector &sdimnames, string &time_dimname) const; //! Return the topological dimension of a variable //! //! Return the topological dimension of the mesh the defines //! the variable data \p varname //! //! \retval dim Topological dimension or zero if variable is not known //! //! \sa DC::Mesh::GetTopologyDim() // virtual size_t GetVarTopologyDim(string varname) const; //! Return the geometric dimension of a variable //! //! Return the geometric dimension of the mesh the defines //! the variable data \p varname. I.e. return the number of spatial coordinate //! variables associated with each node in the mesh. //! //! \retval dim Geometric dimension or zero if variable is not known //! //! \sa DC::Mesh::GetGeometryDim() // virtual size_t GetVarGeometryDim(string varname) const; //! Return a boolean indicating whether a variable is time varying //! //! This method returns \b true if the variable named by \p varname is //! a DataVar and it has a time coordiante //! (See DataVar::GetTimeCoord()), or if the variable is a CoordVar and //! its axis is time. Otherwise false is returnd. //! //! \param[in] varname A string specifying the name of the variable. //! \retval bool Returns true if variable \p varname exists and is //! time varying. //! virtual bool IsTimeVarying(string varname) const; //! Return a boolean indicating whether a variable is compressed //! //! This method returns \b true if the variable named by \p varname is defined //! and it has a compressed representation. If either of these conditions //! is not true the method returns false. //! //! \param[in] varname A string specifying the name of the variable. //! \retval bool Returns true if variable \p varname exists and is //! compressed //! // virtual bool IsCompressed(string varname) const; //! Return the time dimension length for a variable //! //! Returns the number of time steps (length of the time dimension) //! for which a variable is defined. If \p varname does not have a //! time coordinate 1 is returned. If \p varname is not defined //! as a variable zero is returned; //! //! \param[in] varname A string specifying the name of the variable. //! \retval count The length of the time dimension, or a negative //! int if \p varname is undefined. //! //! \retval n Returns the number of time steps for which the variable is //! defined, or zero if the variable is not defined. //! //! \sa IsTimeVarying() //! // virtual int GetNumTimeSteps(string varname) const; //! Return the compression ratio vector for the indicated variable //! //! Return the compression ratio vector for the indicated variable. //! The vector returned contains an ordered list of available //! compression ratios for the variable named by \p variable. //! If the variable is not compressed, or the variable named //! \p varname does not exist, the \p cratios parameter will //! contain a single element, one. //! //! \retval cratios Ordered vector of compression ratios //! // virtual std::vector GetCRatios(string varname) const; //! Return a boolean indicating whether a variable is a data variable //! //! This method returns \b true if a data variable is defined //! with the name \p varname. Otherwise the method returns false. //! //! \retval bool Returns true if \p varname names a defined data variable //! virtual bool IsDataVar(string varname) const { vector names = GetDataVarNames(); return (find(names.begin(), names.end(), varname) != names.end()); } //! Return a boolean indicating whether a variable is a coordinate variable //! //! This method returns \b true if a coordinate variable is defined //! with the name \p varname. Otherwise the method returns false. //! //! \retval bool Returns true if \p varname names a defined coordinate //! variable //! virtual bool IsCoordVar(string varname) const { vector names = GetCoordVarNames(); return (find(names.begin(), names.end(), varname) != names.end()); } //! Return a boolean indicating whether a variable is an Auxiliary variable //! \version 3.1 //! //! This method returns \b true if a Auxiliary variable is defined //! with the name \p varname. Otherwise the method returns false. //! //! \retval bool Returns true if \p varname names a defined Auxiliary //! variable //! virtual bool IsAuxVar(string varname) const { vector names = GetAuxVarNames(); return (find(names.begin(), names.end(), varname) != names.end()); } //! Return an ordered list of a data variable's coordinate names //! //! Returns a list of a coordinate variable names for the variable //! \p varname, ordered from fastest //! to slowest. If \p spatial is true and the variable is time varying //! the time coordinate variable name will be included. The time //! coordinate variable is always //! the slowest varying coordinate axis //! //! \param[in] varname A valid variable name //! \param[in] spatial If true only return spatial dimensions //! //! \param[out] coordvars Ordered list of coordinate variable names. //! //! \retval Returns true upon success, false if the variable is //! not defined. //! // virtual bool GetVarCoordVars(string varname, bool spatial, std::vector &coord_vars) const; //! Get mesh connectivity variables for a data variable //! //! Return the mesh connectivity variables for a data variable. For //! a structured grid all connectivity variables will be empty. For //! an unstructured mesh only the \p face_node_var, \p node_face_var //! are guaranteed to be set to valid variable names //! bool GetVarConnVars(string varname, string &face_node_var, string &node_face_var, string &face_edge_var, string &face_face_var, string &edge_node_var, string &edge_face_var) const; //! Get the rank of a variable //! //! This method returns the number of rank of the array describing a //! variable. For structured data variables the rank is equal to //! the topological dimension (See GetTopologyDim()). //! //! \param[in] varname Name of variable to query //! //! \retval Array rank. A value between 0 and 3, inclusive. If //! \p varname is unknown 0 is returned. //! virtual size_t GetNumDimensions(string varname) const; //! Return a list of all of the available time coordinate variables //! //! This method returns all time coordinate variables defined //! std::vector GetTimeCoordVarNames() const; class VDF_API FileTable { public: FileTable(); virtual ~FileTable(); class FileObject { public: FileObject() : _ts(0), _varname(""), _level(0), _lod(0), _slice(0), _aux(0) {} FileObject(size_t ts, string varname, int level = 0, int lod = 0, int aux = 0) : _ts(ts), _varname(varname), _level(level), _lod(lod), _slice(0), _aux(aux) {} size_t GetTS() const { return (_ts); } string GetVarname() const { return (_varname); } int GetLevel() const { return (_level); } int GetLOD() const { return (_lod); } int GetSlice() const { return (_slice); } void SetSlice(int slice) { _slice = slice; } int GetAux() const { return (_aux); } private: size_t _ts; string _varname; int _level; int _lod; int _slice; int _aux; }; int AddEntry(FileObject *obj); FileObject *GetEntry(int fd) const; void RemoveEntry(int fd); vector GetEntries() const; private: std::vector _table; }; protected: DC::FileTable _fileTable; //! \copydoc Initialize() // virtual int initialize(const std::vector &paths, const std::vector &options = std::vector()) = 0; //! \copydoc GetDimension() // virtual bool getDimension(string dimname, DC::Dimension &dimension) const = 0; //! \copydoc GetDimension() // virtual bool getDimension(string dimname, DC::Dimension &dimension, long ts) const { return getDimension(dimname, dimension); }; //! \copydoc GetDimensionNames() // virtual std::vector getDimensionNames() const = 0; //! \copydoc GetMeshNames() // virtual std::vector getMeshNames() const = 0; //! \copydoc GetMesh() // virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const = 0; //! \copydoc GetCoordVarInfo() // virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const = 0; //! \copydoc GetDataVarInfo() // virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const = 0; //! \copydoc GetAuxVarInfo() // virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const = 0; //! \copydoc GetBaseVarInfo() // virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const = 0; //! \copydoc GetDataVarNames() // virtual std::vector getDataVarNames() const = 0; //! \copydoc GetCoordVarNames() // virtual std::vector getCoordVarNames() const = 0; //! \copydoc GetAuxVarNames() // virtual std::vector getAuxVarNames() const = 0; //! \copydoc GetNumRefLevels() // virtual size_t getNumRefLevels(string varname) const = 0; //! \copydoc GetAtt(string varname, string attname, vector &values) // virtual bool getAtt(string varname, string attname, vector &values) const = 0; //! \copydoc GetAtt(string varname, string attname, vector &values) // virtual bool getAtt(string varname, string attname, vector &values) const = 0; //! \copydoc GetAtt(string varname, string attname, string &values) // virtual bool getAtt(string varname, string attname, string &values) const = 0; //! \copydoc GetAttNames() // virtual std::vector getAttNames(string varname) const = 0; //! \copydoc GetAttType() // virtual XType getAttType(string varname, string attname) const = 0; //! \copydoc GetBlockSize() // virtual vector getBlockSize() const { return (vector()); } //! \copydoc GetDimLensAtLevel() // virtual int getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level) const = 0; //! \copydoc GetDimLensAtLevel() // virtual int getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level, long ts) const { return getDimLensAtLevel(varname, level, dims_at_level, bs_at_level); }; //! \copydoc GetMapProjection() // virtual string getMapProjection() const = 0; //! \copydoc OpenVariableRead() // virtual int openVariableRead(size_t ts, string varname, int level = 0, int lod = 0) = 0; //! \copydoc CloseVariable() // virtual int closeVariable(int fd) = 0; //! \copydoc ReadRegion() // virtual int readRegion(int fd, const vector &min, const vector &max, float *region) = 0; virtual int readRegion(int fd, const vector &min, const vector &max, double *region) = 0; virtual int readRegion(int fd, const vector &min, const vector &max, int *region) = 0; //! \copydoc VariableExists() // virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const = 0; private: virtual bool _getCoordVarDimensions(string varname, bool spatial, vector &dimensions, long ts) const; virtual bool _getDataVarDimensions(string varname, bool spatial, vector &dimensions, long ts) const; virtual bool _getAuxVarDimensions(string varname, vector &dimensions, long ts) const; vector _getBlockSize() const; virtual int _openVariableRead(size_t ts, string varname, int level = 0, int lod = 0); virtual int _closeVariable(int fd); template int _readSliceTemplate(int fd, T *slice); template int _readTemplate(int fd, T *data); template int _getVarTemplate(string varname, int level, int lod, T *data); template int _getVarTemplate(size_t ts, string varname, int level, int lod, T *data); }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/DCBOV.h ================================================ #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace VAPoR { class BOVCollection; // Example BOV header file, bovA1.bov // // # TIME is a floating point value specifying the timestep being read in DATA_FILE // TIME: 1.1 // // # DATA_FILE points to a binary data file. It can be a full file path, or a path relative to the BOV header. // DATA_FILE: bovA1.bin // // # The data size corresponds to NX,NY,NZ in the above example code. It must contain three values // DATA_SIZE: 10 10 10 // // # Allowable values for DATA_FORMAT are: INT,FLOAT,DOUBLE // DATA_FORMAT: FLOAT // // # VARIABLE is a string that specifies the variable being read in DATA_FILE. Must be alphanumeric (abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-) // VARIABLE: myVariable // // # BRICK_ORIGIN lets you specify a new coordinate system origin for # the mesh that will be created to suit your data. It must contain three values. // BRICK_ORIGIN: 0. 0. 0. // // # BRICK_SIZE lets you specify the size of the brick on X, Y, and Z. It must contain three values. // BRICK_SIZE: 10. 20. 5. // // # BYTE_OFFSET is optional and lets you specify some number of // # bytes to skip at the front of the file. This can be useful for # skipping the 4-byte header that Fortran tends to write to files. # If your file does not have a header then DO NOT USE // BYTE_OFFSET. BYTE_OFFSET: 4 //! //! \class DCBOV //! \ingroup Public_VDCBOV //! //! \brief Class for reading a "Brick of Values", explained in section 3.1 (page 11) in the //! following VisIt document: https://github.com/NCAR/VAPOR/files/6341067/GettingDataIntoVisIt2.0.0.pdf //! //! The following BOV tags are mandatory for Vapor to ingest data: //! - DATA_FILE (type: string) //! - DATA_SIZE (type: three integer values that are >1) //! - DATA_FORMAT (type: string of either INT, FLOAT, or DOUBLE) //! - TIME (type: one floating point value. May not be equal to FLT_MIN) //! //! The following BOV tags are optional: //! - BRICK_ORIGIN (type: three floating point values, default: 0., 0., 0.) //! - BRICK_SIZE (type: three floating point values, default: 1., 1., 1.) //! - VARIABLE (type: one alphanumeric string value, default: "brickVar") //! - BYTE_OFFSET (type: one integer value, default: 0) //! //! The following BOV tags are currently unsupported. They can be included in a BOV header, //! but they will be unused. //! - DATA_ENDIAN //! - CENTERING //! - DIVIDE_BRICK //! - DATA_BRICKLETS //! - DATA_COMPONENTS //! //! Each .bov file can only refer to a single data file for a single variable, at a single timestep. //! If duplicate key/value pairs exist in a BOV header, the value closest to the bottom of the file will be used. //! If duplicate values exist for whatever reason, all entries must be valid (except for DATA_FILE, which gets validated after parsing) //! Scientific notation is supported for floating point values like BRICK_ORIGIN and BRICK_SIZE. //! Scientific notation is not supported for integer values like DATA_SIZE. //! DATA_SIZE must contain three values greater than 1. //! Wild card characters are not currently supported in the DATA_FILE token. //! VARIABLE must be alphanumeric (abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-) //! //! \author Scott Pearse //! \date May, 2021 //! class VDF_API DCBOV : public VAPoR::DC { public: //! Class constuctor //! //! DCBOV(); virtual ~DCBOV(); protected: //! Initialize the DCBOV class //! //! Prepare a BOV data set for reading. This method prepares //! the DCBOV class for reading the files indicated by //! \p paths. //! The method should be called immediately after the constructor, //! before any other class methods. This method //! exists only because C++ constructors can not return error codes. //! //! \param[in] path A single BOV header file describing a the structore of a "Brick //! of raw IEEE floating point numbers stored in a file. //! a single CF model run. //! //! \retval status A negative int is returned on failure //! //! \sa EndDefine(); // virtual int initialize(const vector &paths, const std::vector &options); //! \copydoc DC::getDimension() //! virtual bool getDimension(string dimname, DC::Dimension &dimension) const; //! \copydoc DC::getDimensionNames() //! virtual std::vector getDimensionNames() const; //! \copydoc DC::getMeshNames() //! std::vector getMeshNames() const; //! \copydoc DC::getMesh() //! virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const; //! \copydoc DC::GetCoordVarInfo() //! virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const; //! \copydoc DC::GetDataVarInfo() //! virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const; //! \copydoc DC::GetAuxVarInfo() //! virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const { return (false); } //! \copydoc DC::GetBaseVarInfo() // virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const; //! \copydoc DC::GetDataVarNames() //! virtual std::vector getDataVarNames() const; virtual std::vector getAuxVarNames() const { return (vector()); } //! \copydoc DC::GetCoordVarNames() //! virtual std::vector getCoordVarNames() const; //! \copydoc DC::GetCoordVarNames() //! virtual size_t getNumRefLevels(string varname) const { return (1); } //! \copydoc DC::GetMapProjection() //! virtual string getMapProjection() const { return (""); } //! \copydoc DC::GetAtt() //! virtual bool getAtt(string varname, string attname, vector &values) const; virtual bool getAtt(string varname, string attname, vector &values) const; virtual bool getAtt(string varname, string attname, string &values) const; //! \copydoc DC::GetAttNames() //! virtual std::vector getAttNames(string varname) const; //! \copydoc DC::GetAttType() //! virtual XType getAttType(string varname, string attname) const; //! \copydoc DC::GetDimLensAtLevel() //! virtual int getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level) const; //! \copydoc DC::OpenVariableRead() //! virtual int openVariableRead(size_t ts, string varname, int, int) { return (DCBOV::openVariableRead(ts, varname)); } virtual int openVariableRead(size_t ts, string varname); //! \copydoc DC::CloseVariable() //! virtual int closeVariable(int fd); //! \copydoc DC::ReadRegion() // virtual int readRegion(int fd, const vector &min, const vector &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegion(int fd, const vector &min, const vector &max, double *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegion(int fd, const vector &min, const vector &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); } //! \copydoc DC::VariableExists() //! virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const; private: VAPoR::UDUnits _udunits; BOVCollection *_bovCollection; string _varname; std::map _dimsMap; std::map _coordVarsMap; std::map _meshMap; std::map _dataVarsMap; std::map _coordVarKeys; void _InitCoordinates(); void _InitDimensions(); void _InitVars(); int _isCoordinateVariable(std::string variable) const; template void _generateCoordinates(int dim, const vector &min, const vector &max, T *region) const; template int _readRegionTemplate(int fd, const vector &min, const vector &max, T *region); }; } // namespace VAPoR ================================================ FILE: include/vapor/DCCF.h ================================================ #include #include #include #include #include #include #include #include #include #include #include #ifndef _DCCF_H_ #define _DCCF_H_ namespace VAPoR { //! //! \class DCCF //! \ingroup Public_VDCCF //! //! \brief Class for reading a NetCDF Climate Forecast (CF) data set //! stored as a series //! of NetCDF files. //! //! \author John Clyne //! \date March, 2015 //! class VDF_API DCCF : public VAPoR::DC { public: //! Class constuctor //! //! DCCF(); virtual ~DCCF(); int BuildCache(); int Reinitialize(); protected: NetCDFCFCollection *_ncdfc = nullptr; vector _paths; //! Initialize the DCCF class //! //! Prepare a CF data set for reading. This method prepares //! the DCCF class for reading the files indicated by //! \p paths. //! The method should be called immediately after the constructor, //! before any other class methods. This method //! exists only because C++ constructors can not return error codes. //! //! \param[in] path A list of CF NetCDF files comprising the output of //! a single CF model run. //! //! \retval status A negative int is returned on failure //! //! \sa EndDefine(); // virtual int initialize(const vector &paths, const std::vector &options); virtual int initialize_impl(const vector &paths, const std::vector &options, std::unique_ptr ncdfc); //! \copydoc DC::getDimension() //! virtual bool getDimension(string dimname, DC::Dimension &dimension) const; //! \copydoc DC::getDimensionNames() //! virtual std::vector getDimensionNames() const; //! \copydoc DC::getMeshNames() //! std::vector getMeshNames() const; //! \copydoc DC::getMesh() //! virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const; //! \copydoc DC::GetCoordVarInfo() //! virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const; //! \copydoc DC::GetDataVarInfo() //! virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const; //! \copydoc DC::GetAuxVarInfo() //! virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const; //! \copydoc DC::GetBaseVarInfo() // virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const; //! \copydoc DC::GetDataVarNames() //! virtual std::vector getDataVarNames() const; virtual std::vector getAuxVarNames() const; //! \copydoc DC::GetCoordVarNames() //! virtual std::vector getCoordVarNames() const; //! \copydoc DC::GetCoordVarNames() //! virtual size_t getNumRefLevels(string varname) const { return (1); } //! \copydoc DC::GetMapProjection() //! virtual string getMapProjection() const { // Projections not supported yet :-( // return (_proj4String); } //! \copydoc DC::GetAtt() //! virtual bool getAtt(string varname, string attname, vector &values) const; virtual bool getAtt(string varname, string attname, vector &values) const; virtual bool getAtt(string varname, string attname, string &values) const; //! \copydoc DC::GetAttNames() //! virtual std::vector getAttNames(string varname) const; //! \copydoc DC::GetAttType() //! virtual XType getAttType(string varname, string attname) const; //! \copydoc DC::GetDimLensAtLevel() //! virtual int getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level) const; //! \copydoc DC::OpenVariableRead() //! virtual int openVariableRead(size_t ts, string varname, int, int) { return (DCCF::openVariableRead(ts, varname)); } virtual int openVariableRead(size_t ts, string varname); //! \copydoc DC::CloseVariable() //! virtual int closeVariable(int fd); //! \copydoc DC::ReadRegion() // virtual int readRegion(int fd, const vector &min, const vector &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegion(int fd, const vector &min, const vector &max, double *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegion(int fd, const vector &min, const vector &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); } //! \copydoc DC::VariableExists() //! virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const; virtual int initDimensions(NetCDFCFCollection *ncdfc, std::map &dimsMap); virtual int initCoordinates(NetCDFCFCollection *ncdfc, std::map &coordVarsMap); virtual int addCoordvars(NetCDFCFCollection *ncdfc, const vector &cvars, std::map &coordVarsMap); virtual int initDataVars(NetCDFCFCollection *ncdfc, std::map &dataVarsMap); virtual int initAuxilliaryVars(NetCDFCFCollection *ncdfc, std::map &auxVarsMap); virtual int initMesh(NetCDFCFCollection *ncdfc, std::map &_meshMap); virtual int getVarCoordinates(NetCDFCFCollection *ncdfc, string varname, vector &sdimnames, vector &scoordvars, string &time_dim_name, string &time_coordvar) const; private: VAPoR::UDUnits _udunits; string _proj4String; std::map _dimsMap; std::map _coordVarsMap; std::map _meshMap; std::map _dataVarsMap; std::map _auxVarsMap; int _initHorizontalCoordinates(NetCDFCFCollection *ncdfc, std::map &coordVarsMap); int _initVerticalCoordinates(NetCDFCFCollection *ncdfc, std::map &coordVarsMap); int _initTimeCoordinates(NetCDFCFCollection *ncdfc, std::map &coordVarsMap); // Return true if a 1D variable has uniform, absolute deltas between elements // bool _isUniform(NetCDFCFCollection *ncdfc, string varname); template int _readRegionTemplate(int fd, const vector &min, const vector &max, T *region); template bool _getAttTemplate(string varname, string attname, T &values) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/DCMPAS.h ================================================ #include #include #include #include #include #include #include #include #include #include #include #ifndef _DCMPAS_H_ #define _DCMPAS_H_ namespace VAPoR { class DerivedCoordVar_WRFTime; //! //! \class DCMPAS //! \ingroup Public_VDCMPAS //! //! \brief Class for reading a NetCDF Climate Forecast (MPAS) data set //! stored as a series //! of NetCDF files. //! //! \author John Clyne //! \date March, 2015 //! class VDF_API DCMPAS : public VAPoR::DC { public: //! Class constuctor //! //! DCMPAS(); virtual ~DCMPAS(); protected: //! Initialize the DCMPAS class //! //! Prepare a MPAS data set for reading. This method prepares //! the DCMPAS class for reading the files indicated by //! \p paths. //! The method should be called immediately after the constructor, //! before any other class methods. This method //! exists only because C++ constructors can not return error codes. //! //! \param[in] path A list of MPAS NetCDF files comprising the output of //! a single MPAS model run. //! //! \retval status A negative int is returned on failure //! //! \sa EndDefine(); // virtual int initialize(const vector &paths, const std::vector &options); //! \copydoc DC::GetDimension() //! virtual bool getDimension(string dimname, DC::Dimension &dimension) const; //! \copydoc DC::getDimensionNames() //! virtual std::vector getDimensionNames() const; //! \copydoc DC::getMeshNames() //! std::vector getMeshNames() const; //! \copydoc DC::getMesh() //! virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const; //! \copydoc DC::GetCoordVarInfo() //! virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const; //! \copydoc DC::GetDataVarInfo() //! virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const; //! \copydoc DC::GetAuxVarInfo() // virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const; //! \copydoc DC::GetBaseVarInfo() // virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const; //! \copydoc DC::GetDataVarNames() //! virtual std::vector getDataVarNames() const; //! \copydoc DC::GetCoordVarNames() //! virtual std::vector getCoordVarNames() const; virtual std::vector getAuxVarNames() const; //! \copydoc DC::GetCoordVarNames() //! virtual size_t getNumRefLevels(string varname) const { return (1); } //! \copydoc DC::GetMapProjection() //! virtual string getMapProjection() const { return ("+proj=eqc +ellps=WGS84 +lon_0=0.0 +lat_0=0.0"); } //! \copydoc DC::GetAtt() //! virtual bool getAtt(string varname, string attname, vector &values) const; virtual bool getAtt(string varname, string attname, vector &values) const; virtual bool getAtt(string varname, string attname, string &values) const; //! \copydoc DC::GetAttNames() //! virtual std::vector getAttNames(string varname) const; //! \copydoc DC::GetAttType() //! virtual XType getAttType(string varname, string attname) const; //! \copydoc DC::GetDimLensAtLevel() //! virtual int getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual int openVariableRead(size_t ts, string varname, int, int); //! \copydoc DC::CloseVariable() //! virtual int closeVariable(int fd); //! \copydoc DC::ReadRegion() // virtual int readRegion(int fd, const vector &min, const vector &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegion(int fd, const vector &min, const vector &max, double *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegion(int fd, const vector &min, const vector &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); } //! \copydoc DC::VariableExists() //! virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const; private: NetCDFCollection *_ncdfc; VAPoR::UDUnits _udunits; DerivedVarMgr _dvm; bool _hasVertical; // has 3D data (i.e. vertical data) class MPASFileObject : public DC::FileTable::FileObject { public: MPASFileObject(size_t ts, string varname, int level, int lod, int fd, bool derivedFlag) : FileObject(ts, varname, level, lod, fd), _derivedFlag(derivedFlag) {} bool GetDerivedFlag() const { return (_derivedFlag); } private: bool _derivedFlag; }; std::map _dimsMap; std::map _coordVarsMap; std::map _meshMap; std::map _dataVarsMap; std::map _auxVarsMap; std::vector _cellVars; std::vector _pointVars; std::vector _edgeVars; Wasp::SmartBuf _nEdgesOnCellBuf; Wasp::SmartBuf _lonCellSmartBuf; Wasp::SmartBuf _lonVertexSmartBuf; int _InitDerivedVars(NetCDFCollection *ncdfc); int _InitCoordvars(NetCDFCollection *ncdfc); int _InitVerticalCoordinatesDerivedAtmosphere(NetCDFCollection *ncdfc); int _InitVerticalCoordinatesDerivedOcean(NetCDFCollection *ncdfc); int _CheckRequiredFields(NetCDFCollection *ncdfc) const; bool _HasVertical(NetCDFCollection *ncdfc) const; int _InitDimensions(NetCDFCollection *ncdfc); int _GetVarCoordinates(NetCDFCollection *ncdfc, string varname, vector &sdimnames, vector &scoordvars, string &time_dim_name, string &time_coordvar); int _InitMeshes(NetCDFCollection *ncdfc); int _InitAuxVars(NetCDFCollection *ncdfc); int _InitDataVars(NetCDFCollection *ncdfc); vector _GetSpatialDimNames(NetCDFCollection *ncdfc, string varname) const; bool _isAtmosphere(NetCDFCollection *ncdfc) const; bool _isOcean(NetCDFCollection *ncdfc) const; bool _isCoordVar(string varname) const; bool _isDataVar(string varname) const; int _read_nEdgesOnCell(size_t ts); void _addMissingFlag(int *data) const; int _readVarToSmartBuf(size_t ts, string varname, Wasp::SmartBuf &smartBuf); int _readCoordinates(size_t ts); void _splitOnBoundary(string varname, int *connData) const; int _readRegionTransposed(MPASFileObject *w, const vector &min, const vector &max, float *region); int _readRegionEdgeVariable(MPASFileObject *w, const vector &min, const vector &max, float *region); template int _readRegionTemplate(int fd, const vector &min, const vector &max, T *region); template bool _getAttTemplate(string varname, string attname, T &values) const; // Derive vertical coordinate variable for dual mesh from primary mesh // class DerivedCoordVertFromCell : public DerivedCoordVar { public: DerivedCoordVertFromCell(string derivedVarName, string derivedDimName, DC *dc, string inName, string cellsOnVertexName); int Initialize(); bool GetBaseVarInfo(DC::BaseVar &var) const; bool GetCoordVarInfo(DC::CoordVar &cvar) const; virtual std::vector GetInputs() const { return (std::vector{_inName}); } int GetDimLensAtLevel(int, std::vector &dims_at_level, std::vector &bs_at_level) const; int OpenVariableRead(size_t ts, int, int); int CloseVariable(int fd); int ReadRegion(int fd, const vector &min, const vector &max, float *region); bool VariableExists(size_t ts, int, int) const; private: string _derivedDimName; DC * _dc; string _inName; string _cellsOnVertexName; DC::CoordVar _coordVarInfo; float *_getCellData(); int *_getCellsOnVertex(size_t i0, size_t i1, int &vertexDegree); }; // Derive Uzonal and Umeridional data variable // class DerivedZonalMeridonal : public DerivedDataVar { public: DerivedZonalMeridonal(string derivedVarName, DC *dc, NetCDFCollection *ncdfc, string normalVarName, string tangentialVarName, bool zonalFlag); int Initialize(); bool GetBaseVarInfo(DC::BaseVar &var) const; bool GetDataVarInfo(DC::DataVar &cvar) const; virtual std::vector GetInputs() const { return (std::vector{_normalVarName, _tangentialVarName}); } int GetDimLensAtLevel(int, std::vector &dims_at_level, std::vector &bs_at_level) const; int OpenVariableRead(size_t ts, int, int); int CloseVariable(int fd); int ReadRegion(int fd, const vector &min, const vector &max, float *region); bool VariableExists(size_t ts, int, int) const; private: DC * _dc; NetCDFCollection *_ncdfc; string _normalVarName; string _tangentialVarName; bool _zonalFlag; DC::DataVar _dataVarInfo; }; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/DCMelanie.h ================================================ #ifdef BUILD_DC_MELANIE #include #include #include #include #include #include #include #include #include #include #include #ifndef _DCMelanie_H_ #define _DCMelanie_H_ namespace VAPoR { class VDF_API DCMelanie : public VAPoR::DC { public: DCMelanie(); virtual ~DCMelanie(); protected: //! Initialize the DCMelanie class //! //! Prepare a CF data set for reading. This method prepares //! the DCMelanie class for reading the files indicated by //! \p paths. //! The method should be called immediately after the constructor, //! before any other class methods. This method //! exists only because C++ constructors can not return error codes. //! //! \param[in] path A list of CF NetCDF files comprising the output of //! a single CF model run. //! //! \retval status A negative int is returned on failure //! //! \sa EndDefine(); // virtual int initialize(const vector &paths, const std::vector &options); //! \copydoc DC::getDimension() //! virtual bool getDimension(string dimname, DC::Dimension &dimension) const; //! \copydoc DC::getDimensionNames() //! virtual std::vector getDimensionNames() const; //! \copydoc DC::getMeshNames() //! std::vector getMeshNames() const; //! \copydoc DC::getMesh() //! virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const; //! \copydoc DC::GetCoordVarInfo() //! virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const; //! \copydoc DC::GetDataVarInfo() //! virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const; //! \copydoc DC::GetAuxVarInfo() //! virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const; //! \copydoc DC::GetBaseVarInfo() // virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const; //! \copydoc DC::GetDataVarNames() //! virtual std::vector getDataVarNames() const; virtual std::vector getAuxVarNames() const; //! \copydoc DC::GetCoordVarNames() //! virtual std::vector getCoordVarNames() const; //! \copydoc DC::GetCoordVarNames() //! virtual size_t getNumRefLevels(string varname) const { return (1); } //! \copydoc DC::GetMapProjection() //! virtual string getMapProjection() const { // Projections not supported yet :-( // return (_proj4String); } //! \copydoc DC::GetAtt() //! virtual bool getAtt(string varname, string attname, vector &values) const; virtual bool getAtt(string varname, string attname, vector &values) const; virtual bool getAtt(string varname, string attname, string &values) const; //! \copydoc DC::GetAttNames() //! virtual std::vector getAttNames(string varname) const; //! \copydoc DC::GetAttType() //! virtual XType getAttType(string varname, string attname) const; //! \copydoc DC::GetDimLensAtLevel() //! virtual int getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level) const; //! \copydoc DC::OpenVariableRead() //! virtual int openVariableRead(size_t ts, string varname, int, int) { return (DCMelanie::openVariableRead(ts, varname)); } virtual int openVariableRead(size_t ts, string varname); //! \copydoc DC::CloseVariable() //! virtual int closeVariable(int fd); //! \copydoc DC::ReadRegion() // virtual int readRegion(int fd, const vector &min, const vector &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegion(int fd, const vector &min, const vector &max, double *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegion(int fd, const vector &min, const vector &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); } //! \copydoc DC::VariableExists() //! virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const; private: NetCDFCFCollection *_ncdfc; VAPoR::UDUnits _udunits; string _proj4String; std::map _dimsMap; std::map _coordVarsMap; std::map _auxVarsMap; std::map _meshMap; std::map _dataVarsMap; std::map _coordVarKeys; std::map _sanitizedToOriginalMap; std::vector _derivedVars; const string nodeFaceVar = "cellsOnVertex"; const string faceNodeVar = "verticesOnCell"; const vector fakeVars = {nodeFaceVar, faceNodeVar}; int fakeVarsFileCounterStart = 10000; int fakeVarsFileCounter = fakeVarsFileCounterStart; std::map _fdMap; string sanitizeVarName(const string &name); string getOriginalVarName(const string &name) const; template int _readRegionTemplate(int fd, const vector &min, const vector &max, T *region); template bool _getAttTemplate(string varname, string attname, T &values) const; }; }; // namespace VAPoR #endif #endif ================================================ FILE: include/vapor/DCP.h ================================================ #include #include #include #include #include #include #include #include #include #include #include #ifndef _DCP_H_ #define _DCP_H_ //! This enables a beta feature which automatically generates particle density fields //! when importing particle data. In it's current state, if DCP_ENABLE_PARTICLE_DENSITY //! is set to 1, it will work but the volume will have a fixed grid size and it uses a sub-optimal sampling algorithm. #define DCP_ENABLE_PARTICLE_DENSITY 0 namespace VAPoR { //! DCP is a simple daa format for particle data. The full specification can be found at //! vapor/share/doc/DCP_Format.md class VDF_API DCP : public VAPoR::DC { public: DCP(); virtual ~DCP(); protected: //! Initialize the DCP class //! //! Prepare a CF data set for reading. This method prepares //! the DCP class for reading the files indicated by //! \p paths. //! The method should be called immediately after the constructor, //! before any other class methods. This method //! exists only because C++ constructors can not return error codes. //! //! \param[in] path A list of CF NetCDF files comprising the output of //! a single CF model run. //! //! \retval status A negative int is returned on failure //! //! \sa EndDefine(); // virtual int initialize(const vector &paths, const std::vector &options); //! \copydoc DC::getDimension() //! virtual bool getDimension(string dimname, DC::Dimension &dimension) const; virtual bool getDimension(string dimname, DC::Dimension &dimension, long ts) const; //! \copydoc DC::getDimensionNames() //! virtual std::vector getDimensionNames() const; //! \copydoc DC::getMeshNames() //! std::vector getMeshNames() const; //! \copydoc DC::getMesh() //! virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const; //! \copydoc DC::GetCoordVarInfo() //! virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const; //! \copydoc DC::GetDataVarInfo() //! virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const; //! \copydoc DC::GetAuxVarInfo() //! virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const; //! \copydoc DC::GetBaseVarInfo() // virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const; //! \copydoc DC::GetDataVarNames() //! virtual std::vector getDataVarNames() const; virtual std::vector getAuxVarNames() const; //! \copydoc DC::GetCoordVarNames() //! virtual std::vector getCoordVarNames() const; //! \copydoc DC::GetCoordVarNames() //! virtual size_t getNumRefLevels(string varname) const { return (1); } //! \copydoc DC::GetMapProjection() //! virtual string getMapProjection() const { // Projections not supported yet :-( // return (_proj4String); } //! \copydoc DC::GetAtt() //! virtual bool getAtt(string varname, string attname, vector &values) const; virtual bool getAtt(string varname, string attname, vector &values) const; virtual bool getAtt(string varname, string attname, string &values) const; //! \copydoc DC::GetAttNames() //! virtual std::vector getAttNames(string varname) const; //! \copydoc DC::GetAttType() //! virtual XType getAttType(string varname, string attname) const; //! \copydoc DC::GetDimLensAtLevel() //! virtual int getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual int getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level, long ts) const; //! \copydoc DC::OpenVariableRead() //! virtual int openVariableRead(size_t ts, string varname, int, int) { return (DCP::openVariableRead(ts, varname)); } virtual int openVariableRead(size_t ts, string varname); //! \copydoc DC::CloseVariable() //! virtual int closeVariable(int fd); //! \copydoc DC::ReadRegion() // virtual int readRegion(int fd, const vector &min, const vector &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegion(int fd, const vector &min, const vector &max, double *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegion(int fd, const vector &min, const vector &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); } //! \copydoc DC::VariableExists() //! virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const; private: NetCDFCollection *_ncdfc; VAPoR::UDUnits _udunits; string _proj4String; std::map _dimsMap; std::map _coordVarsMap; std::map _auxVarsMap; std::map _meshMap; std::map _dataVarsMap; std::map _coordVarKeys; std::map _sanitizedToOriginalMap; const string _nodeFaceVar = "cellsOnVertex"; const string _faceNodeVar = "verticesOnCell"; const string _fakeEmptyVar = "empty"; vector _fakeVars = {_nodeFaceVar, _faceNodeVar}; int _fakeVarsFileCounterStart = 10000; int _fakeVarsFileCounter = _fakeVarsFileCounterStart; std::map _fdMap; string sanitizeVarName(const string &name); string getOriginalVarName(const string &name) const; bool isCoordVar(const string &var) const; int getAxis(const string &var) const; string getUnits(const string &var) const; string getTimeCoordVar(const string &var) const; template int _readRegionTemplate(int fd, const vector &min, const vector &max, T *region); template bool _getAttTemplate(string varname, string attname, T &values) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/DCRAM.h ================================================ #include #include #include #include #include #include #include #include #include #include #include #pragma once namespace VAPoR { //! \class DCRAM //! \brief DCRAM is a virtual data collection used to allow data to be loaded from ram. Specifically, this is used by PythonDataMgr //! \author Stas Jaroszynski class VDF_API DCRAM : public VAPoR::DC { public: DCRAM(); virtual ~DCRAM(); void Test(); void AddDimension(const DC::Dimension &dim); void AddMesh(const DC::Mesh &mesh); void AddCoordVar(const DC::CoordVar &var, const float *buf); void AddDataVar(const DC::DataVar &var, const float *buf); protected: map _dataMap; void copyVarData(const DC::BaseVar &var, const float *buf, const size_t size); //! \copydoc DC::Initialize() //! virtual int initialize(const vector &paths, const std::vector &options); //! \copydoc DC::getDimension() //! virtual bool getDimension(string dimname, DC::Dimension &dimension) const; virtual bool getDimension(string dimname, DC::Dimension &dimension, long ts) const; //! \copydoc DC::getDimensionNames() //! virtual std::vector getDimensionNames() const; //! \copydoc DC::getMeshNames() //! std::vector getMeshNames() const; //! \copydoc DC::getMesh() //! virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const; //! \copydoc DC::GetCoordVarInfo() //! virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const; //! \copydoc DC::GetDataVarInfo() //! virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const; //! \copydoc DC::GetAuxVarInfo() //! virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const; //! \copydoc DC::GetBaseVarInfo() // virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const; //! \copydoc DC::GetDataVarNames() //! virtual std::vector getDataVarNames() const; virtual std::vector getAuxVarNames() const; //! \copydoc DC::GetCoordVarNames() //! virtual std::vector getCoordVarNames() const; //! \copydoc DC::GetCoordVarNames() //! virtual size_t getNumRefLevels(string varname) const { return (1); } //! \copydoc DC::GetMapProjection() //! virtual string getMapProjection() const { return ""; } //! \copydoc DC::GetAtt() //! virtual bool getAtt(string varname, string attname, vector &values) const; virtual bool getAtt(string varname, string attname, vector &values) const; virtual bool getAtt(string varname, string attname, string &values) const; //! \copydoc DC::GetAttNames() //! virtual std::vector getAttNames(string varname) const; //! \copydoc DC::GetAttType() //! virtual XType getAttType(string varname, string attname) const; //! \copydoc DC::GetDimLensAtLevel() //! virtual int getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual int getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level, long ts) const; //! \copydoc DC::OpenVariableRead() //! virtual int openVariableRead(size_t ts, string varname, int, int) { return (DCRAM::openVariableRead(ts, varname)); } virtual int openVariableRead(size_t ts, string varname); //! \copydoc DC::CloseVariable() //! virtual int closeVariable(int fd); //! \copydoc DC::ReadRegion() // virtual int readRegion(int fd, const vector &min, const vector &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegion(int fd, const vector &min, const vector &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegion(int fd, const vector &min, const vector &max, double *region) { VAssert(!"DCRAM: double data not supported"); return -1; } //! \copydoc DC::ReadRegionBlock() //! virtual int readRegionBlock(int fd, const vector &min, const vector &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); }; virtual int readRegionBlock(int fd, const vector &min, const vector &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegionBlock(int fd, const vector &min, const vector &max, double *region) { VAssert(!"DCRAM: double data not supported"); return -1; } //! \copydoc DC::VariableExists() //! virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const; private: std::map _dimsMap; std::map _coordVarsMap; std::map _auxVarsMap; std::map _meshMap; std::map _dataVarsMap; int _fakeVarsFileCounterStart = 10000; int _fakeVarsFileCounter = _fakeVarsFileCounterStart; std::map _fdMap; template int _readRegionTemplate(int fd, const vector &min, const vector &max, T *region); template bool _getAttTemplate(string varname, string attname, T &values) const; }; }; // namespace VAPoR ================================================ FILE: include/vapor/DCUGRID.h ================================================ #include #include #include #include #include #include #include #include #include #include #include #pragma once namespace VAPoR { //! //! \class DCUGRID //! \ingroup Public_VDCUGRID //! //! \brief Class for reading a UGRID data set //! stored as a series //! of NetCDF files: https://ugrid-conventions.github.io/ugrid-conventions/ //! //! \author John Clyne //! \date July, 2021 //! class VDF_API DCUGRID : public VAPoR::DCCF { public: int OpenVariableRead(size_t ts, string varname, int level = 0, int lod = 0) override; int Read(int fd, int *data) override; int ReadRegion(int fd, const vector &min, const vector &max, int *data) override; int CloseVariable(int fd) override; protected: int initialize(const vector &paths, const std::vector &options) override; int initAuxilliaryVars(NetCDFCFCollection *ncdfc, std::map &auxVarsMap) override; int initDataVars(NetCDFCFCollection *ncdfc, std::map &dataVarsMap) override; int initMesh(NetCDFCFCollection *ncdfc, std::map &meshMap) override; string getMapProjection() const override { return ("+proj=eqc +ellps=WGS84 +lon_0=0.0 +lat_0=0.0"); } private: // Struct to contain the most general form of UGRID mesh // struct uGridMeshType { int topology; vector nodeCoordinates; string faceNodeConnectivity; string faceDimension; string edgeNodeConnectivity; string edgeDimension; string faceEdgeConnectivity; string faceFaceConnectivity; string edgeFaceConnectivity; string boundaryNodeConnectivity; vector faceCoordinates; vector edgeCoordinates; }; std::map _uGridMeshMap; std::map> _faceNodeConnectivityMap; std::map _openConnectivityMaps; string _getLayeredVerticalCoordVar(NetCDFCFCollection *ncdfc, string varName) const; void _getUGridMeshFromFile(NetCDFCFCollection *ncdfc, string meshVarName, uGridMeshType &m); string _getMeshNodeDimName(NetCDFCFCollection *ncdf, const uGridMeshType &m) const; string _getMeshFaceDimName(NetCDFCFCollection *ncdf, const uGridMeshType &m) const; size_t _getMeshMaxNodesPerFace(NetCDFCFCollection *ncdf, const uGridMeshType &m) const; bool _getVarTimeCoords(NetCDFCFCollection *ncdfc, string varName, string &coordName) const; int _initFaceNodeConnectivityMap(NetCDFCFCollection *ncdfc); }; }; // namespace VAPoR ================================================ FILE: include/vapor/DCUtils.h ================================================ //************************************************************************ // * // Copyright (C) 2018 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: DCUtils.h // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: February 2018 // // Description: Defines the DC free functions. // // These functions operate on instances of the DC class. // #ifndef DCUTILS_H #define DCUTILS_H #include #include #include #include namespace VAPoR { class NetCDFCollection; namespace DCUtils { int CopyAtt(const NetCDFCollection &ncdfc, string varname, string attname, DC::BaseVar &var); int CopyAtt(const NetCDFCollection &ncdfc, string varname, DC::BaseVar &var); }; // namespace DCUtils }; // namespace VAPoR #endif ================================================ FILE: include/vapor/DCWRF.h ================================================ #include #include #include #include #include #include #include #include #include #include #ifndef _DCWRF_H_ #define _DCWRF_H_ namespace VAPoR { class DerivedCoordVar_CF1D; class DerivedCoordVar_WRFTime; class DerivedCoordVar_Staggered; //! //! \class DCWRF //! \ingroup Public_VDCWRF //! //! \brief Class for reading a WRF data set stored as a series //! of NetCDF files. //! //! \author John Clyne //! \date January, 2015 //! class VDF_API DCWRF : public VAPoR::DC { public: //! Class constuctor //! //! DCWRF(); virtual ~DCWRF(); protected: //! Initialize the DCWRF class //! //! Prepare a WRF data set for reading. This method prepares //! the DCWRF class for reading the files indicated by //! \p paths. //! The method should be called immediately after the constructor, //! before any other class methods. This method //! exists only because C++ constructors can not return error codes. //! //! \param[in] path A list of WRF NetCDF files comprising the output of //! a single WRF model run. //! //! \retval status A negative int is returned on failure //! //! \sa EndDefine(); // virtual int initialize(const vector &paths, const std::vector &options); //! \copydoc DC::GetDimension() //! virtual bool getDimension(string dimname, DC::Dimension &dimension) const; //! \copydoc DC::getDimensionNames() //! virtual std::vector getDimensionNames() const; //! \copydoc DC::getMeshNames() //! std::vector getMeshNames() const; //! \copydoc DC::GetMesh() //! virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const; //! \copydoc DC::GetCoordVarInfo() //! virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const; //! \copydoc DC::GetDataVarInfo() //! virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const; //! \copydoc DC::GetBaseVarInfo() // virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const { return (false); } //! \copydoc DC::GetBaseVarInfo() // virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const; //! \copydoc DC::GetDataVarNames() //! virtual std::vector getDataVarNames() const; //! \copydoc DC::GetCoordVarNames() //! virtual std::vector getCoordVarNames() const; virtual std::vector getAuxVarNames() const { return (vector()); } //! \copydoc DC::GetNumRefLevels() //! virtual size_t getNumRefLevels(string varname) const { return (1); } //! \copydoc DC::GetMapProjection() //! virtual string getMapProjection() const; //! \copydoc DC::GetAtt() //! virtual bool getAtt(string varname, string attname, vector &values) const; virtual bool getAtt(string varname, string attname, vector &values) const; virtual bool getAtt(string varname, string attname, string &values) const; //! \copydoc DC::GetAttNames() //! virtual std::vector getAttNames(string varname) const; //! \copydoc DC::GetAttType() //! virtual XType getAttType(string varname, string attname) const; //! \copydoc DC::GetDimLensAtLevel() //! virtual int getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level) const; //! \copydoc DC::OpenVariableRead() //! virtual int openVariableRead(size_t ts, string varname, int, int) { return (DCWRF::openVariableRead(ts, varname)); } virtual int openVariableRead(size_t ts, string varname); //! \copydoc DC::CloseVariable() //! virtual int closeVariable(int fd); //! \copydoc DC::ReadRegion() // virtual int readRegion(int fd, const vector &min, const vector &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegion(int fd, const vector &min, const vector &max, double *region) { return (_readRegionTemplate(fd, min, max, region)); } virtual int readRegion(int fd, const vector &min, const vector &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); } //! \copydoc DC::VariableExists() //! virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const; private: NetCDFCollection *_ncdfc; VAPoR::UDUnits _udunits; // // Various attributes from a WRF data file needed for computing map // projections // float _dx; float _dy; float _cen_lat; float _cen_lon; float _true_lat1; float _true_lat2; float _pole_lat; float _pole_lon; float _grav; float _radius; float _p2si; float _mapProj; string _proj4String; DerivedVarMgr _dvm; class WRFFileObject : public DC::FileTable::FileObject { public: WRFFileObject(size_t ts, string varname, int level, int lod, int fd, bool derivedFlag) : FileObject(ts, varname, level, lod, fd), _derivedFlag(derivedFlag) {} bool GetDerivedFlag() const { return (_derivedFlag); } private: bool _derivedFlag; }; std::vector _derivedVars; DerivedCoordVar_WRFTime *_derivedTime; std::map _dimsMap; std::map _coordVarsMap; std::map _meshMap; std::map _dataVarsMap; std::vector _timeLookup; vector _GetSpatialDims(NetCDFCollection *ncdfc, string varname) const; vector _GetSpatialDimNames(NetCDFCollection *ncdfc, string varname) const; int _InitAtts(NetCDFCollection *ncdfc); int _GetProj4String(NetCDFCollection *ncdfc, float radius, int map_proj, string &projstring); bool _isConstantValuedVariable(NetCDFCollection *ncdfc, string varname) const; bool _isIdealized(NetCDFCollection *ncdfc) const; bool _isWRFSFIRE(NetCDFCollection *ncdfc) const; int _InitProjection(NetCDFCollection *ncdfc, float radius); DerivedCoordVar_CF2D *_makeDerivedHorizontalIdealized(NetCDFCollection *ncdfc, string name, string &timeDimName, vector &spaceDimNames); DerivedCoordVar_Staggered *_makeDerivedHorizontalStaggered(NetCDFCollection *ncdfc, string name, string &timeDimName, vector &spaceDimNames); int _InitHorizontalCoordinatesHelper(NetCDFCollection *ncdfc, string name, int axis); int _InitHorizontalCoordinates(NetCDFCollection *ncdfc); DerivedCoordVar_CF1D *_InitVerticalCoordinatesHelper(string varName, string dimName); int _InitVerticalCoordinates(NetCDFCollection *ncdfc); int _InitTime(NetCDFCollection *ncdfc); int _InitDimensions(NetCDFCollection *ncdfc); int _GetCoordVars(NetCDFCollection *ncdfc, string varname, vector &cvarnames); bool _GetVarCoordinates(NetCDFCollection *ncdfc, string varname, std::vector &dimnames, std::vector &coordvars, string &time_dim_name, string &time_coordvar); int _InitVars(NetCDFCollection *ncdfc); template int _readRegionTemplate(int fd, const vector &min, const vector &max, T *region); template bool _getAttTemplate(string varname, string attname, T &values) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/DataMgr.h ================================================ #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include #include #include #include #include #include #ifndef DataMgvV3_0_h #define DataMgvV3_0_h using namespace std; namespace VAPoR { class PipeLine; class DerivedVar; class DerivedDataVar; class DerivedCoordVar; //! \class DataMgr //! \brief A cache based data reader //! \author John Clyne //! //! The DataMgr class is an abstract class that defines public methods for //! accessing (reading) 1D, 2D and 3D field variables. The class implements a //! memory cache to speed data access -- once a variable is read it is //! stored in cache for subsequent access. The DataMgr class is abstract: //! it declares a number of public and protected pure virtual methods //! that must be //! implemented by specializations of this class to allow access to particular //! file formats. //! //! This class inherits from Wasp::MyBase. Unless otherwise documented //! any method that returns an integer value is returning status. A negative //! value indicates failure. Error messages are logged via //! Wasp::MyBase::SetErrMsg(). //! //! Methods that return a boolean do //! not, unless otherwise documented, log an error message upon //! failure (return of false). //! //! \param level //! \parblock //! Grid refinement level for multiresolution variables. //! Compressed variables in the VDC have a multi-resolution //! representation: the sampling grid for multi-resolution variables //! is hierarchical, and the dimension lengths of adjacent levels in the //! hierarchy differ by a factor of two. The \p level parameter is //! used to select a particular depth of the hierarchy. //! //! To provide maximum flexibility as well as compatibility with previous //! versions of the VDC the interpretation of \p level is somewhat //! complex. Both positive and negative values may be used to specify //! the refinement level and have different interpretations. //! //! For positive //! values of \p level, a value of \b 0 indicates the coarsest //! member of the //! grid hierarchy. A value of \b 1 indicates the next grid refinement //! after the coarsest, and so on. Using postive values the finest level //! in the hierarchy is given by GetNumRefLevels() - 1. Values of \p level //! that are greater than GetNumRefLevels() - 1 are treated as if they //! were equal to GetNumRefLevels() - 1. //! //! For negative values of \p level a value of -1 indicates the //! variable's native grid resolution (the finest resolution available). //! A value of -2 indicates the next coarsest member in the hierarchy after //! the finest, and so //! on. Using negative values the coarsest available level in the hierarchy is //! given by negating the value returned by GetNumRefLevels(). Values of //! \p level that are less than the negation of GetNumRefLevels() are //! treated as if they were equal to the negation of the GetNumRefLevels() //! return value. //! \endparblock //! //! \param lod //! \parblock //! The level-of-detail parameter, \p lod, selects //! the approximation level for a compressed variable. //! The \p lod parameter is similar to the \p level parameter in that it //! provides control over accuracy of a compressed variable. However, instead //! of selecting the grid resolution the \p lod parameter controls //! the compression factor by indexing into the \p cratios vector (see below). //! As with the \p level parameter, both positive and negative values may be //! used to index into \p cratios and //! different interpretations. //! //! For positive //! values of \p lod, a value of \b 0 indicates the //! the first element of \p cratios, a value of \b 1 indicates //! the second element, and so on up to the size of the //! \p cratios vector (See DC::GetCRatios()). //! //! For negative values of \p lod a value of \b -1 indexes the //! last element of \p cratios, a value of \b -2 indexes the //! second to last element, and so on. //! Using negative values the first element of \p cratios - the greatest //! compression rate - is indexed by negating the size of the //! \p cratios vector. //! \endparblock // class VDF_API DataMgr : public Wasp::MyBase { public: //! Constructor for the DataMgr class. //! //! The DataMgr will attempt to cache previously read data and coordinate //! variables in memory. The \p mem_size specifies the requested cache //! size in MEGABYTES!!! //! //! \param[in] format A string indicating the format of data collection. //! //! \param[in] mem_size Size of memory cache to be created, specified //! in MEGABYTES!! If 0, not restriction is placed on the cache size; the DataMgr will //! attempt to allocate as much memory is needed. //! //! \param[in] numthreads Number of parallel execution threads //! to be run during encoding and decoding of compressed data. A value //! of 0, the default, indicates that the thread count should be //! determined by the environment in a platform-specific manner, for //! example using sysconf(_SC_NPROCESSORS_ONLN) under *nix OSes. //! // DataMgr(string format, size_t mem_size, int nthreads = 0); virtual ~DataMgr(); //! Initialize the class //! //! This method must be called to initialize the DataMgr class with //! a list of input data files. //! //! \param[in] files A list of file paths //! //! \retval status A negative int is returned on failure and an error //! message will be logged with MyBase::SetErrMsg() //! // virtual int Initialize(const vector &paths, const std::vector &options); //! \copydoc DC::GetDimensionNames() // std::vector GetDimensionNames() const { VAssert(_dc); return (_dc->GetDimensionNames()); } //! \copydoc DC::GetAtt(string, string, vector&) // bool GetAtt (string varname, string attname, vector< double > &values) const { VAssert(_dc); return (_dc->GetAtt(varname, attname, values)); } //! \copydoc DC::GetAtt(string, string, vector&) // bool GetAtt (string varname, string attname, vector &values) const { VAssert(_dc); return (_dc->GetAtt(varname, attname, values)); } //! \copydoc DC::GetAtt(string, string, string&) // bool GetAtt (string varname, string attname, string &values) const { VAssert(_dc); return (_dc->GetAtt(varname, attname, values)); } //! \copydoc DC::GetAttNames(string) // std::vector GetAttNames(string varname) const { VAssert(_dc); return (_dc->GetAttNames(varname)); } //! \copydoc DC::GetAttType(string, string) // DC::XType GetAttType(string varname, string attname) const { VAssert(_dc); return (_dc->GetAttType(varname, attname)); } //! \copydoc DC::GetDimension() // bool GetDimension(string dimname, DC::Dimension &dimension, long ts) const { VAssert(_dc); return (_dc->GetDimension(dimname, dimension, ts)); } //! Returns the length of a dimension at a given timestep //! //! \retval length A negative int is returned on failure //! long GetDimensionLength(string name, long ts) const { VAssert(_dc); DC::Dimension dimension; bool ok = GetDimension(name, dimension, ts); if (ok) return dimension.GetLength(); return -1; } //! \copydoc DC::GetMeshNames() // std::vector GetMeshNames() const { VAssert(_dc); return (_dc->GetMeshNames()); } //! \copydoc DC::GetMesh() // bool GetMesh(string meshname, DC::Mesh &mesh) const; DC::Mesh GetMesh(string meshname) const { DC::Mesh mesh; GetMesh(meshname, mesh); return mesh; } //! Return a list of names for all of the defined data variables. //! //! This method returns a list of all data variables defined //! in the data set. //! //! \retval list A vector containing a list of all the data variable names //! //! \sa GetCoordVarNames() //! //! \test New in 3.0 virtual std::vector GetDataVarNames() const; //! Return a list of data variables with a given spatial dimension rank //! //! This method returns a list of all data variables defined //! in the data set with the specified dimension rank (number of dimensions). //! Data variables may have 0 to 3 spatial dimensions //! //! \param[in] ndim Variable rank (number of dimensions) //! //! \retval list A vector containing a list of all the data variable names //! with the specified number of dimensions (rank). //! //! \test New in 3.0 enum class VarType { Any, Scalar, Particle }; virtual std::vector GetDataVarNames(int ndim, VarType type = VarType::Any) const; //! Return a list of names for all of the defined coordinate variables. //! //! This method returns a list of all coordinate variables defined //! in the data set. //! //! \retval list A vector containing a list of all the coordinate //! variable names //! //! \sa GetDataVarNames() //! virtual std::vector GetCoordVarNames() const; //! Get time coordinates //! //! Get a sorted list of all time coordinates defined for the //! data set. Multiple time coordinate variables may be defined. This method //! collects the time coordinates from all time coordinate variables //! and sorts them into a single, global time coordinate variable. //! //! \note Need to deal with different units (e.g. seconds and days). //! \note Should methods that take a time step argument \p ts expect //! "local" or "global" time steps //! void GetTimeCoordinates(std::vector &timecoords) const { timecoords = _timeCoordinates; }; const std::vector &GetTimeCoordinates() const { return (_timeCoordinates); }; //! Get time coordinate var name //! //! Return the name of the time coordinate variable. If no time coordinate //! variable is defined the empty string is returned. // string GetTimeCoordVarName() const; bool HasTimeVaryingCoordinates() const; bool HasMovingDomain() const; //! Return an ordered list of a data variable's coordinate names //! //! Returns a list of a coordinate variable names for the variable //! \p varname, ordered from fastest //! to slowest. If \p spatial is true and the variable is time varying //! the time coordinate variable name will be included. The time //! coordinate variable is always //! the slowest varying coordinate axis //! //! \param[in] varname A valid variable name //! \param[in] spatial If true only return spatial dimensions //! //! \param[out] coordvars Ordered list of coordinate variable names. //! //! \retval Returns true upon success, false if the variable is //! not defined. //! // virtual bool GetVarCoordVars(string varname, bool spatial, std::vector &coord_vars) const; vector GetVarCoordVars(string varname, bool spatial) const; //! Return a data variable's definition //! //! Return a reference to a DC::DataVar object describing //! the data variable named by \p varname //! //! \param[in] varname A string specifying the name of the variable. //! \param[out] datavar A DataVar object containing the definition //! of the named Data variable. //! //! \retval bool If true the method was successful. If false the //! named variable is invalid (unknown) //! //! \sa GetCoordVarInfo() //! bool GetDataVarInfo(string varname, VAPoR::DC::DataVar &datavar) const; //! Return metadata about a data or coordinate variable //! //! If the variable \p varname is defined as either a //! data or coordinate variable its metadata will //! be returned in \p var. //! //! \retval bool If true the method was successful. If false the //! named variable is invalid (unknown) //! //! \sa GetDataVarInfo(), GetCoordVarInfo() // bool GetBaseVarInfo(string varname, VAPoR::DC::BaseVar &var) const; //! Return a coordinate variable's definition //! //! Return a reference to a DC::CoordVar object describing //! the coordinate variable named by \p varname //! //! \param[in] varname A string specifying the name of the coordinate //! variable. //! \param[out] coordvar A CoordVar object containing the definition //! of the named variable. //! //! \retval bool If true the method was successful. If false the //! named variable is invalid (unknown) //! //! \sa GetDataVarInfo() //! bool GetCoordVarInfo(string varname, VAPoR::DC::CoordVar &cvar) const; //! Return a boolean indicating whether a variable is time varying //! //! This method returns \b true if the variable named by \p varname //! is defined and it has a time axis dimension. If either of these conditions //! is not true the method returns false. //! //! \param[in] varname A string specifying the name of the variable. //! \retval bool Returns true if variable \p varname exists and is //! time varying. //! bool IsTimeVarying(string varname) const; //! Return a boolean indicating whether a variable is compressed //! //! This method returns \b true if the variable named by \p varname is defined //! and it has a compressed representation. If either of these conditions //! is not true the method returns false. //! //! \param[in] varname A string specifying the name of the variable. //! \retval bool Returns true if variable \p varname exists and is //! compressed //! //! \sa DefineCoordVar(), DefineDataVar(), DC::BaseVar::GetCompressed() // bool IsCompressed(string varname) const; //! Return the time dimension length for a variable //! //! Returns the number of time steps (length of the time dimension) //! for which a variable is defined. If \p varname does not have a //! time coordinate 1 is returned. If \p varname is not defined //! as a variable a negative int is returned. //! //! \param[in] varname A string specifying the name of the variable. //! \retval count The length of the time dimension, or a negative //! int if \p varname is undefined. //! //! \sa IsTimeVarying() // int GetNumTimeSteps(string varname) const; //! Return the maximum time dimension length for this data set //! //! Returns the number of time steps (length of the time dimension) //! for any variable is defined. // int GetNumTimeSteps() const; //! \copydoc DC::GetNumRefLevels() // size_t GetNumRefLevels(string varname) const; //! \copydoc DC::GetCRatios() // std::vector GetCRatios(string varname) const; //! Read and return variable data //! //! Reads all data for the data or coordinate variable named by \p varname //! for the time step, refinement level, and leve-of-detail indicated //! by \p ts, \p level, and \p lod, respectively. //! //! \param[in] ts //! An integer offset into the time coordinate variable //! returned by GetTimeCoordinates() indicting the time step of the //! variable to access. //! //! \param[in] varname The name of the data or coordinate variable to access //! //! \param[in] level Grid refinement level. See DataMgr //! //! \param[in] lod The level-of-detail parameter, \p lod, selects //! the approximation level. See DataMgr. // VAPoR::Grid *GetVariable(size_t ts, string varname, int level, int lod, bool lock = false); //! Read and return a variable hyperslab //! //! This method is identical to the GetVariable() method, however, //! a subregion is specified in the user coordinate system. //! \p min and \p max specify the minimum and maximum extents of an //! axis-aligned bounding box containing the region of interest. The //! VAPoR::Grid object returned contains the intersection //! between the //! specified //! hyperslab and the variable's spatial domain (which is not necessarily //! rectangular or axis-aligned). //! If the requested hyperslab lies entirely outside of the domain of the //! requested variable NULL is returned //! //! \param[in] min A one, two, or three element array specifying the //! minimum extents, in user coordinates, of an axis-aligned box defining //! the region-of-interest. The spatial dimensionality of the variable //! determines the number of elements in \p min. //! //! \param[in] max A one, two, or three element array specifying the //! maximum extents, in user coordinates, of an axis-aligned box defining //! the region-of-interest. The spatial dimensionality of the variable //! determines the number of elements in \p max. //! //! \note The Grid structure returned is allocated from the heap. //! it is the caller's responsiblity to delete the returned object //! when it is no longer in use. //! VAPoR::Grid *GetVariable(size_t ts, string varname, int level, int lod, CoordType min, CoordType max, bool lock = false); VAPoR::Grid *GetVariable(size_t ts, string varname, int level, int lod, DimsType min, DimsType max, bool lock = false); //! Compute the coordinate extents of a variable //! //! This method finds the spatial domain extents of a variable //! //! This method returns the min and max extents //! specified in user //! coordinates, of the smallest axis-aligned bounding box that is //! guaranteed to contain //! the variable(s) indicated by \p varname, and the given refinement level, //! \p level //! int GetVariableExtents(size_t ts, string varname, int level, int lod, CoordType &min, CoordType &max); //! Compute the min and max value of a variable //! //! This method finds the minimum and maximum value of a variable //! //! \param[out] range A two element vector containing the minimum and maximum //! value, respectively, for the variable \p varname at the specified //! time step, lod, etc. // int GetDataRange(size_t ts, string varname, int level, int lod, std::vector &range); //! Compute min and max value of a variable within a specified ROI //! //! This method finds the minimum and maximum value of a variable within //! the region of interest (ROI) specified by \p min and \p max. Note, the //! results returned by this method are equivalent to calling the //! Grid::GetRange() method on a grid returned by DataMgr::GetVariable //! using the same arguments provided here. // int GetDataRange(size_t ts, string varname, int level, int lod, CoordType min, CoordType max, std::vector &range); //! \copydoc DC::GetDimLensAtLevel() //! virtual int GetDimLensAtLevel(string varname, int level, std::vector &dims_at_level, long ts) const { std::vector dummy; return (GetDimLensAtLevel(varname, level, dims_at_level, dummy, ts)); } //! Return a variable's array dimension lengths //! //! This method is equivalent to calling GetDimLensAtLevel() with \p level //! equal to -1 //! virtual int GetDimLens(string varname, std::vector &dims, long ts) { return (GetDimLensAtLevel(varname, -1, dims, ts)); } std::vector GetDimLens(string varname) { std::vector dims; GetDimLens(varname, dims, 0); return dims; } //! Unlock a floating-point region of memory //! //! Decrement the lock counter associatd with a //! region of memory, and if zero, //! unlock region of memory previously locked with GetVariable(). //! When the lock counter reaches zero the region is simply //! marked available for //! internal garbage collection during subsequent GetVariable() calls //! //! \param[in] rg A pointer to a Grid previosly //! returned by GetVariable() //! //! \retval status Returns a non-negative value on success //! //! \sa GetVariable() // void UnlockGrid(const VAPoR::Grid *rg); //! \copydoc DC::GetNumDimensions( //! string varname //! ) const; // size_t GetNumDimensions(string varname) const; //! \copydoc DC:GetVarTopologyDim() //! size_t GetVarTopologyDim(string varname) const; //! \copydoc DC:GetVarGeometryDim() //! size_t GetVarGeometryDim(string varname) const; //! Clear the memory cache //! //! This method clears the internal memory cache of all entries // void Clear(); //! Returns true if indicated data volume is available //! //! Returns true if the variable identified by the timestep, variable //! name, refinement level, and level-of-detail is present in //! the data set. Returns false if //! the variable is not available. //! //! \param[in] ts A valid time step between 0 and GetNumTimesteps()-1 //! \param[in] varname A valid variable name //! \param[in] level Refinement level requested. //! \param[in] lod Compression level of detail requested. //! refinement level contained in the DC. // virtual bool VariableExists(size_t ts, string varname, int level = 0, int lod = 0) const; //! \copydoc DC::GetMapProjection() const; // virtual string GetMapProjection() const { return (_proj4String); } //! \copydoc DC::GetMapProjectionDefault() const; // virtual string GetMapProjectionDefault() const { return (_proj4StringDefault); } #ifdef VAPOR3_0_0_ALPHA //! //! Add a pipeline stage to produce derived variables //! //! Add a new pipline stage for derived variable calculation. If a //! pipeline already exists with the same //! name it is replaced. The output variable names are added to //! the list of variables available for this data //! set (see GetVariables3D, etc.). //! //! An error occurs if: //! //! \li The output variable names match any of the native variable //! names - variable names returned via _GetVariables3D(), etc. //! \li The output variable names match the output variable names //! of pipeline stage previously added with NewPipeline() //! \li A circular dependency is introduced by adding \p pipeline //! //! \retval status A negative int is returned on failure. //! int NewPipeline(PipeLine *pipeline); //! //! Remove the named pipline if it exists. Otherwise this method is a //! no-op //! //! \param[in] name The name of the pipeline as returned by //! PipeLine::GetName() //! void RemovePipeline(string name); #endif //! Return true if the named variable is the output of a pipeline //! //! This method returns true if \p varname matches a variable name //! in the output list (PipeLine::GetOutputs()) of any pipeline added //! with NewPipeline() //! //! \sa NewPipeline() // bool IsVariableDerived(string varname) const; //! Return true if the named variable is availble from the derived //! classes data access methods. //! //! A return value of true does not imply that the variable can //! be read (\see VariableExists()), only that it is part of the //! data set known to the derived class //! //! \sa NewPipeline() // bool IsVariableNative(string varname) const; int AddDerivedVar(DerivedDataVar *derivedVar); void RemoveDerivedVar(string varname); //! Purge the cache of a variable //! //! \param[in] varname is the variable name //! void PurgeVariable(string varname); class BlkExts { public: BlkExts(){}; BlkExts(const DimsType &bmin, const DimsType &bmax); void Insert(const DimsType &bcoord, const CoordType &min, const CoordType &max); bool Intersect(const CoordType &min, const CoordType &max, DimsType &bmin, DimsType &bmax, int nCoords = 3) const; friend std::ostream &operator<<(std::ostream &o, const BlkExts &b); private: DimsType _bmin = {{0, 0, 0}}; DimsType _bmax = {{0, 0, 0}}; std::vector _mins; std::vector _maxs; }; protected: // // Cache for various metadata attributes // template class VarInfoCache { public: // // void Set(size_t ts, std::vector varnames, int level, int lod, string key, const std::vector &values); void Set(size_t ts, string varname, int level, int lod, string key, const std::vector &values) { std::vector varnames; varnames.push_back(varname); Set(ts, varnames, level, lod, key, values); } bool Get(size_t ts, std::vector varnames, int level, int lod, string key, std::vector &values) const; bool Get(size_t ts, string varname, int level, int lod, string key, std::vector &values) const { std::vector varnames; varnames.push_back(varname); return Get(ts, varnames, level, lod, key, values); } void Purge(size_t ts, std::vector varnames, int level, int lod, string key); void Purge(size_t ts, string varname, int level, int lod, string key) { std::vector varnames; varnames.push_back(varname); Purge(ts, varnames, level, lod, key); } void Purge(std::vector varnames); void Clear() { _cache.clear(); } static string _make_hash(string key, size_t ts, std::vector cvars, int level, int lod); void _decode_hash(const string &hash, string &key, size_t &ts, vector &varnames, int &level, int &lod); private: std::map> _cache; }; mutable std::map, std::vector> _dataVarNamesCache; string _format; int _nthreads; size_t _mem_size; DC * _dc; VAPoR::UDUnits _udunits; VAPoR::GridHelper _gridHelper; DerivedVarMgr _dvm; bool _doTransformHorizontal; bool _doTransformVertical; string _openVarName; std::vector _timeCoordinates; string _proj4String; string _proj4StringDefault; DimsType _bs; typedef struct { size_t ts; string varname; int level; int lod; DimsType bmin; DimsType bmax; int lock_counter; void * blks; } region_t; // a list of all allocated regions std::list _regionsList; VAPoR::BlkMemMgr *_blk_mem_mgr; std::vector _PipeLines; mutable VarInfoCache _varInfoCacheSize_T; mutable VarInfoCache _varInfoCacheDouble; mutable VarInfoCache _varInfoCacheVoidPtr; std::map _blkExtsCache; std::map> _lockedFloatBlks; std::map> _lockedIntBlks; // Get the immediate variable dependencies of a variable // std::vector _get_var_dependencies_1(string varname) const; // Recursively get all of the dependencies of a list of variables. // Handles cycles in the dependency graph // std::vector _get_var_dependencies_all(std::vector varnames, std::vector dependencies) const; // Return true if native data has a transformable horizontal coordinate // bool _hasHorizontalXForm() const; // Return true if native mesh has a transformable horizontal coordinate // bool _hasHorizontalXForm(string meshname) const; bool _get_coord_vars(string varname, std::vector &scvars, string &tcvar) const; bool _get_coord_vars(string varname, vector &scvarsinfo, DC::CoordVar &tcvarinfo) const; int _initTimeCoord(); int _get_default_projection(string &projection); VAPoR::RegularGrid *_make_grid_regular(const DimsType &dims, const std::vector &blkvec, DimsType &bs, DimsType &bmin, const DimsType &bmax) const; VAPoR::StretchedGrid *_make_grid_stretched(const DimsType &dims, const std::vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax) const; VAPoR::LayeredGrid *_make_grid_layered(const DimsType &dims, const std::vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax) const; VAPoR::CurvilinearGrid *_make_grid_curvilinear(size_t ts, int level, int lod, const vector &cvarsinfo, const DimsType &dims, const std::vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax); void _ugrid_setup(const DC::DataVar &var, DimsType &vertexDims, DimsType &faceDims, DimsType &edgeDims, UnstructuredGrid::Location &location, // node,face, edge size_t &maxVertexPerFace, size_t &maxFacePerVertex, long &vertexOffset, long &faceOffset, long ts) const; UnstructuredGrid2D *_make_grid_unstructured2d(size_t ts, int level, int lod, const DC::DataVar &dvarinfo, const vector &cvarsinfo, const DimsType, const vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, const vector &conn_blkvec, const DimsType &conn_bs, const DimsType &conn_bmin, const DimsType &conn_bmax); VAPoR::Grid *_make_grid(size_t ts, int level, int lod, const VAPoR::DC::DataVar &var, const DimsType &roi_dims, const DimsType &dims, const std::vector &blkvec, const std::vector &bsvec, const std::vector &bminvec, const std::vector &bmaxvec, const vector &conn_blkvec, const vector &conn_bsvec, const vector &conn_bminvec, const vector &conn_bmaxvec); string _get_grid_type(string varname) const; int _find_bounding_grid(size_t ts, string varname, int level, int lod, CoordType min, CoordType max, DimsType &min_ui, DimsType &max_ui); void _setupCoordVecsHelper(string data_varname, const DimsType &data_dimlens, const DimsType &data_bmin, const DimsType &data_bmax, string coord_varname, int order, DimsType &coord_dimlens, DimsType &coord_bmin, DimsType &coord_bmax, bool structured, long ts) const; int _setupCoordVecs(size_t ts, string varname, int level, int lod, const DimsType &min, const DimsType &max, vector &varnames, DimsType &roi_dims, vector &dimsvec, vector &bsvec, vector &bminvec, vector &bmaxvec, bool structured) const; int _setupConnVecs(size_t ts, string varname, int level, int lod, vector &varnames, vector &dimsvec, vector &bsvec, vector &bminvec, vector &bmaxvec) const; VAPoR::Grid *_getVariable(size_t ts, string varname, int level, int lod, bool lock, bool dataless); VAPoR::Grid *_getVariable(size_t ts, string varname, int level, int lod, DimsType min, DimsType max, bool lock, bool dataless); int _parseOptions(vector &options); template T *_get_region_from_cache(size_t ts, string varname, int level, int lod, const DimsType &bmin, const DimsType &bmax, bool lock); template int _get_unblocked_region_from_fs(size_t ts, string varname, int level, int lod, const DimsType &grid_dims, const DimsType &grid_bs, const DimsType &grid_min, const DimsType &grid_max, T *blks); template int _get_blocked_region_from_fs(size_t ts, string varname, int level, int lod, const DimsType &file_bs, const DimsType &file_dims, const DimsType &grid_dims, const DimsType &grid_bs, const DimsType &grid_min, const DimsType &grid_max, T *blks); template T *_get_region_from_fs(size_t ts, string varname, int level, int lod, const DimsType &grid_dims, const DimsType &grid_bs, const DimsType &grid_bmin, const DimsType &grid_bmax, bool lock); template T *_get_region(size_t ts, string varname, int level, int lod, int nlods, const DimsType &dims, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, bool lock); template int _get_regions(size_t ts, const std::vector &varnames, int level, int lod, bool lock, const std::vector &dimsvec, const std::vector &bsvec, const std::vector &bminvec, const std::vector &bmaxvec, std::vector &blkvec); void _unlock_blocks(const void *blks); std::vector _get_native_variables() const; void *_alloc_region(size_t ts, string varname, int level, int lod, DimsType bmin, DimsType bmax, DimsType bs, int element_sz, bool lock, bool fill); void _free_region(size_t ts, string varname, int level, int lod, DimsType bmin, DimsType bmax, bool forceFlag = false); bool _free_lru(); void _free_var(string varname); int _level_correction(string varname, int &level) const; int _lod_correction(string varname, int &lod) const; vector _getDataVarNamesDerived(int ndim) const; bool _hasCoordForAxis(vector coord_vars, int axis) const; string _defaultCoordVar(const DC::Mesh &m, int axis) const; void _assignHorizontalCoords(vector &coord_vars) const; bool _getVarDimensions(string varname, vector &dimensions, long ts) const; bool _getDataVarDimensions(string varname, vector &dimensions, long ts) const; bool _getCoordVarDimensions(string varname, vector &dimensions, long ts) const; bool _getVarDimNames(string varname, vector &dimnames) const; bool _isDataVar(string varname) const { vector names = GetDataVarNames(); return (find(names.begin(), names.end(), varname) != names.end()); } bool _isCoordVar(string varname) const { vector names = GetCoordVarNames(); return (find(names.begin(), names.end(), varname) != names.end()); } bool _getVarConnVars(string varname, string &face_node_var, string &node_face_var, string &face_edge_var, string &face_face_var, string &edge_node_var, string &edge_face_var) const; DerivedVar * _getDerivedVar(string varname) const; DerivedDataVar * _getDerivedDataVar(string varname) const; DerivedCoordVar *_getDerivedCoordVar(string varname) const; int _openVariableRead(size_t ts, string varname, int level, int lod); template int _readRegion(int fd, const DimsType &min, const DimsType &max, size_t ndims, T *region); int _closeVariable(int fd); template int _getVar(string varname, int level, int lod, T *data); template int _getVar(size_t ts, string varname, int level, int lod, T *data); void _getLonExtents(std::vector &lons, DimsType dims, float &min, float &max) const; void _getLatExtents(std::vector &lons, DimsType dims, float &min, float &max) const; int _getCoordPairExtents(string lon, string lat, float &lonmin, float &lonmax, float &latmin, float &latmax, long ts); int _initProj4StringDefault(); int _initHorizontalCoordVars(); int _initVerticalCoordVars(); bool _hasVerticalXForm() const; bool _hasVerticalXForm(string meshname, string &standard_name, string &formula_terms) const; bool _hasVerticalXForm(string meshname) const { string standard_name, formula_terms; return (_hasVerticalXForm(meshname, standard_name, formula_terms)); } bool _isCoordVarInUse(string varName) const; // Hide public DC::GetDimLensAtLevel by making it private // virtual int GetDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level, long ts) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/DataMgrFactory.h ================================================ // // $Id$ // #ifndef _DataMgrFactory_h_ #define _DataMgrFactory_h_ #include #include #include namespace VAPoR { class VDF_API DataMgrFactory : public Wasp::MyBase { public: static DataMgr *New(const vector &files, size_t mem_size, string ftype = "vdf"); }; }; // namespace VAPoR #endif // _DataMgrFactory_h_ ================================================ FILE: include/vapor/DataMgrUtils.h ================================================ //************************************************************************ // * // Copyright (C) 2017 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: DataMgrUtils.h // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: February 2017 // // Description: Defines the DataMgrUtils free functions. // // These functions operate on instances of the DataMgr class. // #ifndef DATAMGRUTILS_H #define DATAMGRUTILS_H #include #include #include #include namespace VAPoR { namespace DataMgrUtils { //! Return the maximum available transform level for a variable. //! //! This method checks for the existence of a variable at all //! available transform levels (see DataMgr::GetNumRefLevels()), and //! returns the highest available level. The minimum level is zero //! and the max is DataMgr::GetNumRefLevels() - 1. //! //! \param[in] timestep Time Step //! \param[in] varname variable name //! \param[out] maxXForm Maximum available level //! //! \return status Return true on success. Return false if the no //! transform levels exist e.g. the variable does not exist. // VDF_API bool MaxXFormPresent(const DataMgr *dataMgr, size_t timestep, string varname, size_t &maxXForm); //! Return the maximum available LOD level for a variable. //! //! This method checks for the existence of a variable at all //! available levels of detail (see DataMgr::GetCRatios()), and //! returns the highest available level. The minimum level is zero //! and the max is DataMgr::GetCRatios().size() - 1. //! //! \param[in] timestep Time Step //! \param[in] varname variable name //! \param[out] maxLOD Maximum available level //! //! \return status Return true on success. Return false if the no //! LOD levels exist e.g. the variable does not exist. // VDF_API bool MaxLODPresent(const DataMgr *dataMgr, size_t timestep, string varname, size_t &maxLOD); //! Convert Projected Coordinate System coordinates to lon/lat in-place. //! //! Perform in-place conversion of an array of interleaved pairs of //! coordinates from PCS //! to lon-lat coordinates. The input pairs are ordered X, then Y. The output //! pairs are ordered Longitude, then Latitude //! Return false if can't do it. //! //! \param[in/out] coords coordinates to be converted //! \param[in] npoints Number of points to convert. //! \return true if successful //! VDF_API int ConvertPCSToLonLat(const DataMgr *dataMgr, double coords[], int npoints = 1); VDF_API int ConvertPCSToLonLat(string projString, double coords[], int npoints = 1); //! Convert lon/lat coordinates to Projected Coordinate System coordinates, //! in-place. //! //! Perform in-place conversion of an array of interleaved pairs of //! coordinates from lon-lat //! to PCS coordinates. The input pairs are ordered longitude, then //! latitude. The output //! pairs are ordered X, then Y //! Return false if can't do it. //! //! \param[in/out] coords coordinates to be converted //! \param[in] npoints Number of points to convert. //! \return true if successful //! VDF_API int ConvertLonLatToPCS(const DataMgr *dataMgr, double coords[], int npoints = 1); VDF_API int ConvertLonLatToPCS(string projString, double coords[], int npoints = 1); //! Method that obtains one or more regular grids at specified timestep, //! extents, refinement, and lod. //! If the data is available, but not at the requested extents, //! refinement or lod, then the extents may //! be reduced, and the data accuracy may be reduced. //! //! All variables must have same spatial dimensionality //! //! \param[in] ts timestep being requested //! \param[in] variable name(s) being requested //! \param[in] minExtsReq Minimum requested extents //! \param[in] maxExtsReq Maximum requested extents //! \param[in/out] *refLevel : requested refinement may be //! reduced if only a lower level is available //! \param[in] useLowerAccuracy If true use lower accuracy data then //! requested if the requested accuracy is not available //! \param[in/out] *lod : requested lod may be reduced if only //! a lower lod is available. //! \param[out] grid is a vector of Grid* pointers, one //! for each variable //! \param[in] lock : if false, the default, UnlockGrids() will be called on each of the grids //! after they are all successfully allocated. Otherwise, the the grids will be locked in //! memory until released by an explicit call to UnlockGrids() // template VDF_API int GetGrids(DataMgr *dataMgr, size_t ts, const vector &varnames, const T &minExtsReq, const T &maxExtsReq, bool useLowerAccuracy, int *refLevel, int *lod, std::vector &grids, bool lock = false); VDF_API int GetGrids(DataMgr *dataMgr, size_t ts, string varname, const CoordType &minExtsReq, const CoordType &maxExtsReq, bool useLowerAccuracy, int *refLevel, int *lod, Grid **gridptr, bool lock = false); VDF_API int GetGrids(DataMgr *dataMgr, size_t ts, string varname, const DimsType &minExtsReq, const DimsType &maxExtsReq, bool useLowerAccuracy, int *refLevel, int *lod, Grid **gridptr, bool lock = false); VDF_API int GetGrids(DataMgr *dataMgr, size_t ts, const vector &varnames, bool useLowerAccuracy, int *refLevel, int *lod, std::vector &grids, bool lock = false); VDF_API int GetGrids(DataMgr *dataMgr, size_t ts, string varname, bool useLowerAccuracy, int *refLevel, int *lod, Grid **gridptr, bool lock = false); VDF_API void UnlockGrids(DataMgr *dataMgr, const std::vector &grids); //! Get the spatial coordinate axes for a variable //! //! Returns the ordered (fastest to slowest varying) coordinate axis //! for a named variable. //! //! \param[in] varname Name of variable //! \param[out] axes Ordered list of axis indecies. The range of possible //! axes values is [0..2], with 0 corresponding to the X coordinate axis, //! 1 corresponding to Y, and 2 to Z. //! bool GetAxes(const DataMgr *dataMgr, string varname, vector &axes); //! Get a variables coordinate extents //! //! Get the minimum and maximum coordinate extents of a name variable //! at a given time step. The extents are returned in \p minExts and //! \p maxExts. The size of these vectors will match the dimensionality //! of the variable. The GetAxes() method can be used to determine which //! coordinate axes the returned extents correspond to. //! //! If \p varname is an empty string the function scans the list of //! available data variables looking for the highest dimension variable //! available. //! //! \param[in] timestep Time step of variable. Ignored for variables that //! are not time-varying. //! \param[in] Name of variable //! \param[out] minExts A vector whose size matches the dimensionality //! of the variable, and containing the minimum ordered coordinate //! extents of \p varname at time step \p timestep. //! \param[out] maxExts A vector whose size matches the dimensionality //! of the variable, and containing the maximum ordered coordinate //! extents of \p varname at time step \p timestep. //! //! \sa GetAxes() // VDF_API bool GetExtents(DataMgr *dataMgr, size_t timestep, string varname, int refLevel, int lod, CoordType &minExts, CoordType &maxExts); //! Get coordinate extents for one or more variables. //! //! Get the minimum and maximum coordinate extents of a list of variables //! at a given time step. This function handles variables with mixed //! dimensionality, and 2D variables that are defined on different planes. //! The extents are returned in \p minExts and //! \p maxExts. //! //! \param[in] timestep Time step of variable. Ignored for variables that //! are not time-varying. //! \param[in] Name of variable //! \param[out] minExts A vector whose size matches the dimensionality //! of the variable, and containing the minimum ordered coordinate //! extents of \p varname at time step \p timestep. //! \param[out] maxExts A vector whose size matches the dimensionality //! of the variable, and containing the maximum ordered coordinate //! extents of \p varname at time step \p timestep. //! //! \param[out] axes A vector indicating the axis of each coordinate //! returned in \p minExts and \p maxExts. See GetAxes() //! //! \sa GetAxes() // VDF_API bool GetExtents(DataMgr *dataMgr, size_t timestep, const vector &varnames, int refLevel, int lod, CoordType &minExts, CoordType &maxExts, vector &axes); //! Used by the histo for calculating some meta data. VDF_API int GetDefaultMetaInfoStride(DataMgr *dataMgr, std::string varname, int refinementLevel); //! Get default z value at the base of the domain. Useful //! for applying a height value to 2D renderers. //! \param[in] dataMgr Current (valid) dataMgr //! \retval default height value for current dataset VDF_API double Get2DRendererDefaultZ(DataMgr *dataMgr, size_t ts, int refLevel, int lod); //! Find the first variable that exists //! //! This function searches a data collection looking over all //! time steps and variable names for the first available //! variable it can find with a given dimension \p ndim, refinement level //! \p level, and level of detail \p lod. A variable is "available" if //! DataMgr::VariableExists() returns true //! //! \param[in] ndim Number of spatial dimensions //! //! \param[out] varname Returns the name of the first variable found //! \param[out] ts Returns the time step of the first variable found //! \retval status Returns true if a variable is found, false otherwise //! //! \sa DataMgr::VariableExists() // VDF_API bool GetFirstExistingVariable(DataMgr *dataMgr, int level, int lod, int ndim, string &varname, size_t &ts); //! Find the first variable that exists at a given time step //! //! This function searches a data collection looking over all //! variable names for the first available //! variable it can find with a given dimension \p ndim, time step \p ts, //! refinement level //! \p level, and level of detail \p lod. A variable is "available" if //! DataMgr::VariableExists() returns true //! //! \param[in] ndim Number of spatial dimensions //! //! \param[out] varname Returns the name of the first variable found //! \retval status Returns true if a variable is found, false otherwise //! //! \sa DataMgr::VariableExists() // VDF_API bool GetFirstExistingVariable(DataMgr *dataMgr, size_t ts, int level, int lod, int ndim, string &varname); #ifdef VAPOR3_0_0_ALPHA //! Determine the size of a voxel in user coordinates, along a specific dimension, //! or its maximum or minimum dimension //! \param[in] timestep of variable used to determine dimensions //! \param[in] varname Variable name used for determining dimension. //! \param[in] reflevel Refinement level at which voxel is measured, or -1 for maximum ref level //! \param[in] dir is 0,1,2 for x,y,z dimension. Dir is -1 for maximum, -2 for minimum. double getVoxelSize(size_t timestep, string varname, int refLevel, int dir); //! Determine the number of active 3D variables. This includes 3D variables in the VDC as well as any 3D derived variables //! \return number of active 3D variables int getNumActiveVariables3D() { return _dataMgr->GetDataVarNames(3).size(); } //! Determine the number of active 2D variables. This includes 2D variables in the VDC as well as any 2D derived variables //! \return number of active 2D variables int getNumActiveVariables2D() { return _dataMgr->GetDataVarNames(2).size(); } //! Determine the number of active variables. This includes variables in the VDC as well as any derived variables //! \return number of active variables int getNumActiveVariables() { return getNumActiveVariables3D() + getNumActiveVariables2D(); } //! Map corners of box to voxel coordinates. //! Result is zero if box does not lie in data domain. //! \param[in] box is Box to be mapped //! \param[in] varname Name of variable whose coordinates to use //! \param[in] refLevel is refinement level to be used in the mapping //! \param[in] lod is LOD level to be used for the mapping //! \param[in] timestep is time step to use in the mapping //! \param[out] voxExts Voxel extents of box, zeroes if not in data bounds void mapBoxToVox(Box *box, string varname, int refLevel, int lod, int timestep, size_t voxExts[6]); #endif }; // namespace DataMgrUtils }; // namespace VAPoR #endif // DATAMGRUTILS_H ================================================ FILE: include/vapor/DataStatus.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: DataStatus.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: February 2006 // // Description: Defines the DataStatus class. // This class maintains information about the data that is currently // loaded. Maintained and accessed mostly through the Session #ifndef DATASTATUS_H #define DATASTATUS_H #include #include #include #include #include #include namespace VAPoR { //! \class DataStatus //! \ingroup Public_Params //! \brief A class for describing the currently loaded dataset //! \author Alan Norton //! \version 3.0 //! \date January 2016 //! //! The DataStatus class keeps track of available variables, timesteps, resolutions, and data ranges. //! It is constructed by the Session whenever a new metadata is loaded. //! It keeps a lazily evaluated value of min/max of each variable for each timestep. //! Variables can be referenced using the variable name, the session variable num (a numbering all the variables in //! the session) or by the active variable num. Active variables are all those in the metadata plus all //! the derived variables, and are a subset of the session variables. //! Session variables are those that were specified in the session plus those that are derived, and these may not all be available in the metadata. //! To support using active variables and session variable nums, //! mappings are provided between active names/nums and session nums, and also between variable names and //! their 2D and 3D session variable numbers and active variable numbers. class PARAMS_API DataStatus { public: DataStatus(size_t cacheSize, int nThreads = 0); DataStatus() { DataStatus(1000); } virtual ~DataStatus(); int Open(const std::vector &files, const std::vector &options, string name, string format); void Close(string name); // const DataMrgV3_0 *GetDataMgr(string name) const; DataMgr *GetDataMgr(string name) const; vector GetDataMgrNames() const; //! Get domain extents for all active variables //! //! This method returns the union of the domain extents for //! all active variables on the window named by \p winName. //! A variable is considered active if it //! it currrently in use by an enabled RenderParams instance. //! //! The domain extents returned are always 3D. I.e. \p minExts //! and \p maxExts will always have three elements. //! //! If no variable is active all elements of \p minExts will be zero, //! and all elements of maxExts will be one. //! //! \param[in] datasetName If provided, will only return extents for //! that dataset. //! //! \param[in] paramsMgr Active variables are determined by //! querying the ParamsMgr. //! \param[out] minExts //! //! \sa ParamsMgr::GetRenderParams() // void GetActiveExtents(const ParamsMgr *paramsMgr, string winName, string datasetName, size_t ts, CoordType &minExts, CoordType &maxExts) const; void GetActiveExtents(const ParamsMgr *paramsMgr, string winName, size_t ts, CoordType &minExts, CoordType &maxExts) const; void GetActiveExtents(const ParamsMgr *paramsMgr, size_t ts, CoordType &minExts, CoordType &maxExts) const; //! Return the aggregated time coordinates for all data sets //! //! This method returns the aggregated time coordinates in //! user defined units for all of the currently opened data sets //! The time coordinates vector monotonically increasing, and contains //! no duplicates. //! //! \sa GetTimeCoordsFormatted() // const vector &GetTimeCoordinates() const { return (_timeCoords); } //! Returns a vector of formatted time coordinate strings //! //! This method interprets the values returned by GetTimeCoordinates() //! as seconds since the EPOCH and uses UDUNITS2 to encode the values //! the values as year, month, day, hour, minute, second, which are //! then formatted as a date-time string. // const vector &GetTimeCoordsFormatted() const { return (_timeCoordsFormatted); } //! Map a global to a local time step //! //! Map the global time step \p ts to the closest "local" time step //! in the data set named by \p dataSetName. If \p ts is greater //! than or equal to GetTimeCoordinates().size then the last time //! step in \p dataSetName is returned. //! //! \return local_ts Returns the local time step, or zero if //! \p dataSetName is not recognized. //! //! \sa GetTimeCoordinates(). // size_t MapGlobalToLocalTimeStep(string dataSetName, size_t ts) const; //! Map a local time step to a global time step range //! //! Map the local time step \p local_ts for the data set named //! \p dataSetName to the possible range of global //! //! //! \sa GetTimeCoordinates(). // void MapLocalToGlobalTimeRange(string dataSetName, size_t local_ts, size_t &min_ts, size_t &max_ts) const; //! Set number of execution threads //! //! Set the number of execution threads. If \p nThreads == 0, the //! default, //! the system will attempt to set the number of threads equal to //! the number of cores detected. Has no effect until //! the next data set is loaded. // void SetNumThreads(size_t nthreads) { _nThreads = nthreads; } size_t GetNumThreads() const { return _nThreads; } //! Set the data cache size //! //! Set the size of the data cache in MBs. //! Has no effect until //! the next data set is loaded. //! //! \sa DataMgr // void SetCacheSize(size_t sizeMB) { _cacheSize = sizeMB; } string GetMapProjection() const; string GetMapProjectionDefault(string dataSetName) const; //! Determine the minimum time step for which there is any data. //! \retval size_t value of smallest time step size_t getMinTimestep() { return 0; } //! Determine the maximum time step for which there is any data. //! \retval size_t value of largest time step size_t getMaxTimestep() { return _timeCoords.size() ? _timeCoords.size() - 1 : 0; } //! Determine the maximum refinement level present for a variable at a timestep bool WasCacheDirty() const { return _wasCacheDirty; } void SetCacheDirty(const string &dataset="", const string &variable="") { (void)dataset; (void)variable; _isDataCacheDirty = true; _wasCacheDirty = true; } private: typedef struct { std::vector varnames; int refLevel; int compLevel; } var_info_t; void _getExtents(size_t ts, const map> &variables, CoordType &minExt, CoordType &maxExt) const; map> _getFirstVar(string dataSetName, size_t &ts) const; void reset_time(); void reset_time_helper(); #ifndef DOXYGEN_SKIP_THIS size_t _cacheSize; int _nThreads; map _dataMgrs; map> _timeMap; vector _timeCoords; vector _timeCoordsFormatted; bool _isDataCacheDirty; bool _wasCacheDirty; #endif // DOXYGEN_SKIP_THIS friend class ControlExec; }; }; // namespace VAPoR #endif // DATASTATUS_H ================================================ FILE: include/vapor/DatasetsParams.h ================================================ #pragma once #include #include namespace VAPoR { // // A collection of Dataset params // // These are not the dataset params. These are the python script generated var params. // class PARAMS_API DatasetsParams : public ParamsBase { public: DatasetsParams(ParamsBase::StateSave *ssave); DatasetsParams(ParamsBase::StateSave *ssave, XmlNode *node); DatasetsParams(const DatasetsParams &rhs); DatasetsParams &operator=(const DatasetsParams &rhs); virtual ~DatasetsParams(); void SetScript(string datasetName, string name, string script, const vector &inputVarNames, const vector &outputVarNames, const vector &outputVarMeshes, bool coordFlag); bool GetScript(string datasetName, string name, string &script, vector &inputVarNames, vector &outputVarNames, vector &outputVarMeshes, bool &coordFlag) const; void RemoveDataset(string datasetName) { _datasets->Remove(datasetName); } void RemoveScript(string datasetName, string scriptName); vector GetScriptNames(string datasetName) const; // Get static string identifier for this params class // static string GetClassType() { return ("DatasetsParams"); } private: static const string _datasetsTag; ParamsContainer *_datasets; }; // // Dataset params // class PARAMS_API DatasetParams : public ParamsBase { public: DatasetParams(ParamsBase::StateSave *ssave); DatasetParams(ParamsBase::StateSave *ssave, XmlNode *node); DatasetParams(const DatasetParams &rhs); DatasetParams &operator=(const DatasetParams &rhs); virtual ~DatasetParams(); void SetScript(string name, string script, const vector &inputVarNames, const vector &outputVarNames, const vector &outputVarMeshes, bool coordFlag); bool GetScript(string name, string &script, vector &inputVarNames, vector &outputVarNames, vector &outputVarMeshes, bool &coordFlag) const; void RemoveScript(string name) { _scripts->Remove(name); } vector GetScriptNames() const { return (_scripts->GetNames()); } // Get static string identifier for this params class // static string GetClassType() { return ("DatasetParams"); } class PARAMS_API ScriptParams : public ParamsBase { public: ScriptParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, ScriptParams::GetClassType()) {} ScriptParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {} virtual ~ScriptParams() {} void SetScript(string script, const vector &inputVarNames, const vector &outputVarNames, const vector &outputVarMeshes, bool coordFlag) { _ssave->BeginGroup("Set derived variable script"); SetValueString(_scriptTag, "", script); SetValueStringVec(_inputVarNamesTag, "", inputVarNames); SetValueStringVec(_outputVarNamesTag, "", outputVarNames); SetValueStringVec(_outputVarMeshesTag, "", outputVarMeshes); SetValueLong(_coordFlagTag, "", 0); _ssave->EndGroup(); } void GetScript(string &script, vector &inputVarNames, vector &outputVarNames, vector &outputVarMeshes, bool &coordFlag) { script = GetValueString(_scriptTag, ""); inputVarNames = GetValueStringVec(_inputVarNamesTag); outputVarNames = GetValueStringVec(_outputVarNamesTag); outputVarMeshes = GetValueStringVec(_outputVarMeshesTag); coordFlag = GetValueLong(_coordFlagTag, 0); } static string GetClassType() { return ("ScriptParams"); } private: static const string _scriptTag; static const string _inputVarNamesTag; static const string _outputVarNamesTag; static const string _outputVarMeshesTag; static const string _coordFlagTag; }; private: static const string _datasetTag; static const string _scriptsTag; ParamsContainer *_scripts; }; // End of Class DatasetParams }; // namespace VAPoR ================================================ FILE: include/vapor/DerivedParticleDensity.h ================================================ #pragma once #include #include namespace VAPoR { class DerivedParticleDensity : public DerivedDataVar { DC * _dc; string _meshName; DataMgr *_dataMgr; public: DerivedParticleDensity(string varName, DC *dc, string meshName, DataMgr *dataMgr); virtual int Initialize() override; virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0) override; virtual int CloseVariable(int fd) override; virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region) override; virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const override; virtual bool VariableExists(size_t ts, int reflevel, int lod) const override; virtual bool GetBaseVarInfo(DC::BaseVar &var) const override; virtual bool GetDataVarInfo(DC::DataVar &cvar) const override; virtual std::vector GetInputs() const override; protected: string _dataVar; virtual void compute(Grid *inGrid, float *output, int xd, int yd, int zd, size_t realNP) const; }; class DerivedParticleAverage : public DerivedParticleDensity { public: DerivedParticleAverage(string varName, DC *dc, string meshName, DataMgr *dataMgr, string inputVar); virtual int Initialize() override { return 0; } protected: virtual void compute(Grid *inGrid, float *output, int xd, int yd, int zd, size_t realNP) const override; }; class DerivedCoordVar1DSpan : public DerivedCoordVar_CF1D { DC * _dc; float _minExt, _maxExt; string _inputCoordVar; public: DerivedCoordVar1DSpan(string derivedVarName, DC *dc, string dimName, int axis, string units, float minExt, float maxExt); DerivedCoordVar1DSpan(string derivedVarName, DC *dc, string dimName, int axis, string units, string inputCoordVar); virtual ~DerivedCoordVar1DSpan() {} virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region) override; virtual std::vector GetInputs() const override; }; } // namespace VAPoR ================================================ FILE: include/vapor/DerivedVar.h ================================================ #include #include #include #include #include #include #ifndef _DERIVEDVAR_H_ #define _DERIVEDVAR_H_ namespace VAPoR { class NetCDFCollection; //! //! \class DerivedVar //! //! \brief Derived variable abstract class //! //! This abstract base class defines an API for the internal creation of //! derived data and coordinate variables. Derived variables may be used //! to support the results of a data operator (e.g. computing wind speed //! from velocity component variables), creating of a dimensioned coordinate //! variable from a dimensionless one (e.g. supporting the CF conventions //! \a formula_terms attribute), resampling a variable to a different mesh ( //! resampling a staggered variable to an unstaggered mesh), or //! conversion of units (e.g. converting formatted time strings to time //! in seconds). //! //! \author John Clyne //! \date January, 2017 //! //! class VDF_API DerivedVar : public Wasp::MyBase { public: DerivedVar(string varName) { _derivedVarName = varName; }; virtual ~DerivedVar() {} virtual int Initialize() = 0; string GetName() const { return (_derivedVarName); } virtual bool GetBaseVarInfo(DC::BaseVar &var) const = 0; virtual bool GetAtt(string attname, std::vector &values) const { values.clear(); return (false); } virtual bool GetAtt(string attname, std::vector &values) const { values.clear(); return (false); } virtual bool GetAtt(string attname, string &values) const { values.clear(); return (false); } virtual std::vector GetAttNames() const { return (std::vector()); } virtual DC::XType GetAttType(string attname) const { return (DC::INVALID); } virtual std::vector GetInputs() const = 0; virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const = 0; virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level, long ts) const { return GetDimLensAtLevel(level, dims_at_level, bs_at_level); } virtual size_t GetNumRefLevels() const { return (1); } virtual std::vector GetCRatios() const { return (std::vector(1, 1)); } virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0) = 0; virtual int CloseVariable(int fd) = 0; virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region) = 0; virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, double *region); virtual bool VariableExists(size_t ts, int reflevel, int lod) const = 0; protected: string _derivedVarName; DC::FileTable _fileTable; int _getVar(DC *dc, size_t ts, string varname, int level, int lod, const std::vector &min, const std::vector &max, float *region) const; int _getVarDestagger(DC *dc, size_t ts, string varname, int level, int lod, const std::vector &min, const std::vector &max, float *region, int stagDim) const; }; //! //! \class DerivedCoordVar //! //! \brief Derived coordinate variable abstract class //! //! \author John Clyne //! \date Februrary, 2018 //! //! class VDF_API DerivedCoordVar : public DerivedVar { public: DerivedCoordVar(string varName) : DerivedVar(varName) {} virtual ~DerivedCoordVar() {} virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const = 0; }; //! //! \class DerivedCFVertCoordVar //! //! \brief Derived coordinate variable abstract class //! //! \author John Clyne //! \date July, 2018 //! //! class VDF_API DerivedCFVertCoordVar : public DerivedCoordVar { public: DerivedCFVertCoordVar(string varName, DC *dc, string mesh, string formula) : DerivedCoordVar(varName), _dc(dc), _mesh(mesh), _formula(formula) {} virtual ~DerivedCFVertCoordVar() {} virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const = 0; //! Parse a CF conventions forumla string into terms and variables //! //! This static method parse the CF conventions //! formula string, typically //! associated with the \a formula_terms attribute, into a std::map //! of term names and variable names. //! //! If \p formula cannot be parsed false is returned. //! //! \param[in] formula : A formatted CF formula string //! \param[out] parse_terms A map from term names to variable names //! //! \sa http://cfconventions.org/ //! static bool ParseFormula(string formula_terms, map &parsed_terms); //! validate that a CF conventions forumla string is syntactically correct //! //! This static method checks to see if \p formula contains a //! syntactically valid CF conventions formula string, typically //! associated with the \a formula_terms attribute, and ensures //! that all of required formula terms in \p required_terms //! are present in the forumla string. If either of these conditions are //! not met the method returns false, otherwise true is returned //! //! \param[in] required_terms : A vector of term names required to //! be found in \p formula //! \param[in] formula : A formatted CF formula string //! //! \sa http://cfconventions.org/ //! static bool ValidFormula(const vector &required_terms, string formula); protected: DC * _dc; string _mesh; string _formula; }; ////////////////////////////////////////////////////////////////////////// // // DerivedCFVertCoordVarFactory Class // ///////////////////////////////////////////////////////////////////////// class VDF_API DerivedCFVertCoordVarFactory { public: static DerivedCFVertCoordVarFactory *Instance() { static DerivedCFVertCoordVarFactory instance; return &instance; } void RegisterFactoryFunction(string name, function classFactoryFunction) { // register the class factory function _factoryFunctionRegistry[name] = classFactoryFunction; } DerivedCFVertCoordVar *(CreateInstance(string standard_name, DC *, string, string)); vector GetFactoryNames() const; private: map> _factoryFunctionRegistry; DerivedCFVertCoordVarFactory() {} DerivedCFVertCoordVarFactory(const DerivedCFVertCoordVarFactory &) {} DerivedCFVertCoordVarFactory &operator=(const DerivedCFVertCoordVarFactory &) { return *this; } }; ////////////////////////////////////////////////////////////////////////// // // DerivedCFVertCoordVarFactoryRegistrar Class // // Register DerivedCFVertCoordVar derived class with: // // static DerivedCFVertCoordVarFactoryRegistrar registrar("standard_name"); // // where 'class' is a class derived from 'DerivedCFVertCoordVar', and // "standard_name" is the value of the CF "standard_name" attribute. // ///////////////////////////////////////////////////////////////////////// template class DerivedCFVertCoordVarFactoryRegistrar { public: DerivedCFVertCoordVarFactoryRegistrar(string standard_name) { // register the class factory function // DerivedCFVertCoordVarFactory::Instance()->RegisterFactoryFunction(standard_name, [](DC *dc, string mesh, string formula) -> DerivedCFVertCoordVar * { return new T(dc, mesh, formula); }); } }; //! //! \class DerivedDataVar //! //! \brief Derived data variable abstract class //! //! \author John Clyne //! \date Februrary, 2018 //! //! class VDF_API DerivedDataVar : public DerivedVar { public: DerivedDataVar(string varName) : DerivedVar(varName) {} virtual ~DerivedDataVar() {} virtual bool GetDataVarInfo(DC::DataVar &cvar) const = 0; }; //! //! \class DerivedCoordVar_PCSFromLatLon //! //! \brief Derived PCS coordinate variable from lat-lon coordinate pairs //! //! \author John Clyne //! \date Februrary, 2018 //! //! class VDF_API DerivedCoordVar_PCSFromLatLon : public DerivedCoordVar { public: DerivedCoordVar_PCSFromLatLon(string derivedVarName, DC *dc, std::vector inNames, string proj4String, bool uGridFlag, bool lonFlag); virtual ~DerivedCoordVar_PCSFromLatLon() {} virtual int Initialize(); virtual bool GetBaseVarInfo(DC::BaseVar &var) const; virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const; virtual std::vector GetInputs() const { return (std::vector{_lonName, _latName}); } virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0); virtual int CloseVariable(int fd); virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region); virtual bool VariableExists(size_t ts, int reflevel, int lod) const; private: DC * _dc; string _proj4String; string _lonName; string _latName; string _xCoordName; string _yCoordName; bool _make2DFlag; bool _uGridFlag; bool _lonFlag; std::vector _dimLens; Proj4API _proj4API; DC::CoordVar _coordVarInfo; int _setupVar(); int _readRegionHelperCylindrical(DC::FileTable::FileObject *f, const std::vector &min, const std::vector &max, float *region); int _readRegionHelper1D(DC::FileTable::FileObject *f, const std::vector &min, const std::vector &max, float *region); int _readRegionHelper2D(DC::FileTable::FileObject *f, const std::vector &min, const std::vector &max, float *region); }; //! //! \class DerivedCoordVar_CF1D //! //! \brief Derived 1D CF conventions coordinate variable using //! grid coordinates //! //! \author John Clyne //! \date Februrary, 2018 //! //! class VDF_API DerivedCoordVar_CF1D : public DerivedCoordVar { public: DerivedCoordVar_CF1D(string derivedVarName, DC *dc, string dimName, int axis, string units); virtual ~DerivedCoordVar_CF1D() {} virtual int Initialize(); virtual bool GetBaseVarInfo(DC::BaseVar &var) const; virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const; virtual std::vector GetInputs() const { return (std::vector()); } virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level, long ts) const; virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0); virtual int CloseVariable(int fd); virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region); virtual bool VariableExists(size_t ts, int reflevel, int lod) const; private: DC * _dc; string _dimName; DC::CoordVar _coordVarInfo; }; //! //! \class DerivedCoordVar_CF2D //! //! \brief Derived 2D CF conventions coordinate variable . Coordinates //! are provided by \p data, whose length must be dimlens[0] * dimLens[1] //! //! \author John Clyne //! \date Februrary, 2018 //! //! class VDF_API DerivedCoordVar_CF2D : public DerivedCoordVar { public: DerivedCoordVar_CF2D(string derivedVarName, std::vector dimNames, std::vector dimLens, int axis, string units, const vector &data); virtual ~DerivedCoordVar_CF2D() {} virtual int Initialize(); virtual bool GetBaseVarInfo(DC::BaseVar &var) const; virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const; virtual std::vector GetInputs() const { return (std::vector()); } virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0); virtual int CloseVariable(int fd); virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region); virtual bool VariableExists(size_t ts, int reflevel, int lod) const; private: std::vector _dimNames; std::vector _dimLens; std::vector _data; DC::CoordVar _coordVarInfo; }; //! //! \class DerivedCoordVar_WRFTime //! //! \brief Derived WRF Time coordinate variable //! //! \author John Clyne //! \date Februrary, 2018 //! //! class VDF_API DerivedCoordVar_WRFTime : public DerivedCoordVar { public: DerivedCoordVar_WRFTime(string derivedVarName, NetCDFCollection *ncdfc, string wrfTimeVar, string dimName, float p2si = 1.0); virtual ~DerivedCoordVar_WRFTime() {} virtual int Initialize(); virtual bool GetBaseVarInfo(DC::BaseVar &var) const; virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const; virtual std::vector GetInputs() const { return (std::vector{_wrfTimeVar}); } virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0); virtual int CloseVariable(int fd); virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region); virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, double *region); virtual bool VariableExists(size_t ts, int reflevel, int lod) const; size_t TimeLookup(size_t ts) const { return (ts < _timePerm.size() ? _timePerm[ts] : 0); } private: NetCDFCollection * _ncdfc; std::vector _times; std::vector _timePerm; string _wrfTimeVar; float _p2si; size_t _ovr_ts; DC::CoordVar _coordVarInfo; int _encodeTime(UDUnits &udunits, const vector &timeStrings, vector ×) const; }; //! //! \class DerivedCoordVar_TimeInSeconds //! //! \brief Derived time coordinate variable //! //! \author John Clyne //! \date Februrary, 2018 //! //! class VDF_API DerivedCoordVar_TimeInSeconds : public DerivedCoordVar { public: DerivedCoordVar_TimeInSeconds(string derivedVarName, DC *dc, string nativeTimeVar, string dimName); virtual ~DerivedCoordVar_TimeInSeconds() {} virtual int Initialize(); virtual bool GetBaseVarInfo(DC::BaseVar &var) const; virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const; virtual std::vector GetInputs() const { return (std::vector{_nativeTimeVar}); } virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0); virtual int CloseVariable(int fd); virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region); virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, double *region); virtual bool VariableExists(size_t ts, int reflevel, int lod) const; const vector &GetTimes() const { return (_times); } private: DC * _dc; std::vector _times; string _nativeTimeVar; DC::CoordVar _coordVarInfo; }; //! //! \class DerivedCoordVar_Time //! //! \brief Synthesize a time coordinate variable //! //! Creates a time coordinate variable with \p n user times, running //! from 0.0 to n-1. //! //! \author John Clyne //! \date Novermber, 2020 //! //! class VDF_API DerivedCoordVar_Time : public DerivedCoordVar { public: DerivedCoordVar_Time(string derivedVarName, string dimName, size_t n); virtual ~DerivedCoordVar_Time() {} virtual int Initialize(); virtual bool GetBaseVarInfo(DC::BaseVar &var) const; virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const; virtual std::vector GetInputs() const { return (std::vector()); } virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0); virtual int CloseVariable(int fd); virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region); virtual bool VariableExists(size_t ts, int reflevel, int lod) const; const vector &GetTimes() const { return (_times); } private: std::vector _times; DC::CoordVar _coordVarInfo; }; class VDF_API DerivedCoordVar_Staggered : public DerivedCoordVar { public: DerivedCoordVar_Staggered(string derivedVarName, string stagDimName, DC *dc, string inName, string dimName); virtual ~DerivedCoordVar_Staggered() {} virtual int Initialize(); virtual bool GetBaseVarInfo(DC::BaseVar &var) const; virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const; virtual std::vector GetInputs() const { return (std::vector{_inName}); } virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0); virtual int CloseVariable(int fd); virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region); virtual bool VariableExists(size_t ts, int reflevel, int lod) const; private: string _inName; string _stagDimName; string _dimName; DC * _dc; DC::CoordVar _coordVarInfo; int _stagDim; }; class VDF_API DerivedCoordVar_UnStaggered : public DerivedCoordVar { public: DerivedCoordVar_UnStaggered(string derivedVarName, string unstagDimName, DC *dc, string inName, string dimName); virtual ~DerivedCoordVar_UnStaggered() {} virtual int Initialize(); virtual bool GetBaseVarInfo(DC::BaseVar &var) const; virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const; virtual std::vector GetInputs() const { return (std::vector{_inName}); } virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0); virtual int CloseVariable(int fd); virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region); virtual bool VariableExists(size_t ts, int reflevel, int lod) const; private: string _inName; string _unstagDimName; string _dimName; DC * _dc; DC::CoordVar _coordVarInfo; int _stagDim; }; class VDF_API DerivedCoordVarStandardWRF_Terrain : public DerivedCFVertCoordVar { public: DerivedCoordVarStandardWRF_Terrain(DC *dc, string mesh, string formula); virtual ~DerivedCoordVarStandardWRF_Terrain() {} virtual int Initialize(); virtual bool GetBaseVarInfo(DC::BaseVar &var) const; virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const; virtual std::vector GetInputs() const { return (std::vector{"PH", "PHB"}); } virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual size_t GetNumRefLevels() const { return (_dc->GetNumRefLevels(_PHVar)); } virtual std::vector GetCRatios() const { return (_dc->GetCRatios(_PHVar)); } virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0); virtual int CloseVariable(int fd); virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region); virtual bool VariableExists(size_t ts, int reflevel, int lod) const; static bool ValidFormula(string formula); private: string _PHVar; string _PHBVar; float _grav; DC::CoordVar _coordVarInfo; }; //! \class DerivedCoordVarStandardOceanSCoordinate //! //! \brief Convert a CF parameterless vertical coordinate to an Ocean //! s-coordinate, generic form 1 or 2 //! //! This derived class converts a dimensionless sigma coordinate variable //! to either a Ocean s-coordinate, generic form 1 or 2 //! //! \sa http://cfconventions.org/ // class VDF_API DerivedCoordVarStandardOceanSCoordinate : public DerivedCFVertCoordVar { public: DerivedCoordVarStandardOceanSCoordinate(DC *dc, string mesh, string formula); virtual ~DerivedCoordVarStandardOceanSCoordinate() {} virtual int Initialize(); virtual bool GetBaseVarInfo(DC::BaseVar &var) const; virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const; virtual std::vector GetInputs() const; virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual size_t GetNumRefLevels() const { return (1); } virtual std::vector GetCRatios() const { return (std::vector(1, 1)); } virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0); virtual int CloseVariable(int fd); virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region); virtual bool VariableExists(size_t ts, int reflevel, int lod) const; static bool ValidFormula(string formula); private: string _standard_name; string _sVar; string _CVar; string _etaVar; string _depthVar; string _depth_cVar; double _CVarMV; double _etaVarMV; double _depthVarMV; bool _destaggerEtaXDim; bool _destaggerEtaYDim; bool _destaggerDepthXDim; bool _destaggerDepthYDim; DC::CoordVar _coordVarInfo; int initialize_missing_values(); int initialize_stagger_flags(); void compute_g1(const vector &min, const vector &max, const float *s, const float *C, const float *eta, const float *depth, float depth_c, float *region) const; void compute_g2(const vector &min, const vector &max, const float *s, const float *C, const float *eta, const float *depth, float depth_c, float *region) const; }; //! \class DerivedCoordVarStandardAHSPC //! //! \brief Convert a CF parameterless vertical coordinate to an Ocean //! s-coordinate, generic form 1 or 2 //! //! This derived class converts a dimensionless sigma coordinate variable //! to either a Ocean s-coordinate, generic form 1 or 2 //! //! \sa http://cfconventions.org/ // class VDF_API DerivedCoordVarStandardAHSPC : public DerivedCFVertCoordVar { public: DerivedCoordVarStandardAHSPC(DC *dc, string mesh, string formula); virtual ~DerivedCoordVarStandardAHSPC() {} virtual int Initialize(); virtual bool GetBaseVarInfo(DC::BaseVar &var) const; virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const; virtual std::vector GetInputs() const; virtual int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual size_t GetNumRefLevels() const { return (1); } virtual std::vector GetCRatios() const { return (std::vector(1, 1)); } virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0); virtual int CloseVariable(int fd); virtual int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region); virtual bool VariableExists(size_t ts, int reflevel, int lod) const; static bool ValidFormula(string formula); private: string _standard_name; string _aVar; string _apVar; string _bVar; string _p0Var; string _psVar; double _psVarMV; DC::CoordVar _coordVarInfo; int initialize_missing_values(); void compute_a(const vector &min, const vector &max, const float *a, const float *b, const float *ps, float p0, float *region) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/DerivedVarMgr.h ================================================ #include #include #include #include #ifndef _DERIVEDVARMGR_H_ #define _DERIVEDVARMGR_H_ namespace VAPoR { //! //! \class DerivedVarMgr //! //! \brief Derived variables constructed from other variables //! //! \author John Clyne //! \date January, 2017 //! //! class VDF_API DerivedVarMgr : public VAPoR::DC { public: //! Class constuctor //! DerivedVarMgr(); virtual ~DerivedVarMgr(){}; void AddCoordVar(DerivedCoordVar *cvar); void AddDataVar(DerivedDataVar *dvar); void RemoveVar(const DerivedVar *var); DerivedVar *GetVar(string name) const; bool HasVar(string name) const { return (GetVar(name) != NULL); } void AddMesh(const Mesh &m); protected: //! \copydoc Initialize() // virtual int initialize(const std::vector &paths, const std::vector &options = std::vector()); //! \copydoc GetDimension() // virtual bool getDimension(string dimname, DC::Dimension &dimension) const { return (false); } //! \copydoc GetDimensionNames() // virtual std::vector getDimensionNames() const { return (std::vector()); } //! \copydoc GetMeshNames() // virtual std::vector getMeshNames() const; //! \copydoc GetMesh() // virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const; //! \copydoc GetCoordVarInfo() // virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvarInfo) const; //! \copydoc GetDataVarInfo() // virtual bool getDataVarInfo(string varname, DC::DataVar &datavarInfo) const; //! \copydoc GetAuxVarInfo() // virtual bool getAuxVarInfo(string varname, DC::AuxVar &varInfo) const { return (false); } //! \copydoc GetBaseVarInfo() // virtual bool getBaseVarInfo(string varname, DC::BaseVar &varInfo) const; //! \copydoc GetDataVarNames() // virtual std::vector getDataVarNames() const; //! \copydoc GetCoordVarNames() // virtual std::vector getCoordVarNames() const; //! \copydoc GetAuxVarNames() // virtual std::vector getAuxVarNames() const { return (std::vector()); } //! \copydoc GetNumRefLevels() // virtual size_t getNumRefLevels(string varname) const; //! \copydoc GetAtt(string varname, string attname, vector &values) // virtual bool getAtt(string varname, string attname, vector &values) const; //! \copydoc GetAtt(string varname, string attname, vector &values) // virtual bool getAtt(string varname, string attname, vector &values) const; //! \copydoc GetAtt(string varname, string attname, string &values) // virtual bool getAtt(string varname, string attname, string &values) const; //! \copydoc GetAttNames() // virtual std::vector getAttNames(string varname) const; //! \copydoc GetAttType() // virtual XType getAttType(string varname, string attname) const; //! \copydoc GetDimLensAtLevel() // virtual int getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level) const; //! \copydoc GetMapProjection() // virtual string getMapProjection() const { return (string("")); } //! \copydoc OpenVariableRead() // virtual int openVariableRead(size_t ts, string varname, int level = 0, int lod = 0); //! \copydoc CloseVariable() // virtual int closeVariable(int fd); //! \copydoc ReadRegion() // virtual int readRegion(int fd, const vector &min, const vector &max, double *region); virtual int readRegion(int fd, const vector &min, const vector &max, float *region); virtual int readRegion(int fd, const vector &min, const vector &max, int *region) { return (-1); } //! \copydoc VariableExists() // virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const; private: std::map _vars; std::map _dataVars; std::map _coordVars; std::map _meshes; DerivedVar * _getVar(string name) const; DerivedDataVar * _getDataVar(string name) const; DerivedCoordVar *_getCoordVar(string name) const; private: DC::FileTable _fileTable; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/EasyThreads.h ================================================ #ifndef _EasyThreads_h_ #define _EasyThreads_h_ #include #ifndef WIN32 #include #else #include #include #endif #include "MyBase.h" namespace Wasp { class COMMON_API EasyThreads : public MyBase { public: EasyThreads(int nthreads); ~EasyThreads(); int ParRun(void *(*start)(void *), std::vector arg); int ParRun(void *(*start)(void *), void **arg); int Barrier(); int MutexLock(); int MutexUnlock(); static void Decompose(int n, int size, int rank, int *offset, int *length); static int NProc(); int GetNumThreads() const { return (nthreads_c); } private: #ifndef WIN32 int nthreads_c; pthread_t * threads_c; pthread_attr_t attr_c; pthread_cond_t cond_c; pthread_mutex_t barrier_lock_c; pthread_mutex_t mutex_lock_c; int block_c; int count_c; // counters for barrier #else bool initialized_c; int nblocked_c; int nthreads_c; HANDLE *threads_c; HANDLE *mutices_c; HANDLE *bMutices_c; HANDLE mutex_c; HANDLE bMutex_c; #endif }; }; // namespace Wasp #endif ================================================ FILE: include/vapor/Field.h ================================================ /* * The base class of all possible fields for flow integration. */ #ifndef FIELD_H #define FIELD_H #include #include #include #include namespace flow { class FLOW_API Field { public: // Constructor and destructor. // This class complies with rule of zero. Field() = default; virtual ~Field() = default; // // If a given position at a given time is inside of this field // virtual bool InsideVolumeVelocity(double time, glm::vec3 pos) const = 0; virtual bool InsideVolumeScalar(double time, glm::vec3 pos) const = 0; // // Retrieve the number of time steps in this field // virtual uint32_t GetNumberOfTimesteps() const = 0; // // Get the field value at a certain position, at a certain time. // virtual int GetScalar(double time, glm::vec3 pos, // input float &val) const = 0; // output // // Get the velocity value at a certain position, at a certain time. // virtual int GetVelocity(double time, glm::vec3 pos, // input glm::vec3 &vel) const = 0; // output // // Returns the number of empty velocity variable names. // It is 3 when the object is newly created, or is used to represent a scalar field // int GetNumOfEmptyVelocityNames() const; // // Provide an option to cache and lock certain parameters. // Both functions return 0 on success. // virtual auto LockParams() -> int = 0; virtual auto UnlockParams() -> int = 0; // Class members bool IsSteady = false; std::string ScalarName = ""; std::array VelocityNames = {{"", "", ""}}; }; }; // namespace flow #endif ================================================ FILE: include/vapor/FileUtils.h ================================================ #pragma once #include #include #include #include namespace Wasp { namespace FileUtils { enum class FileType { File, Directory, Other, Does_Not_Exist }; extern COMMON_API const std::string Separator; COMMON_API std::string ReadFileToString(const std::string &path); COMMON_API std::string HomeDir(); COMMON_API std::string Basename(const std::string &path); COMMON_API std::string Dirname(const std::string &path); COMMON_API std::string Realpath(const std::string &path); COMMON_API std::string Relpath(std::string path, std::string to); COMMON_API std::string CommonAncestor(const std::vector &paths); COMMON_API std::string Extension(const std::string &path); COMMON_API std::string RemoveExtension(const std::string &path); COMMON_API std::string POSIXPathToWindows(std::string path); COMMON_API std::string POSIXPathToCurrentOS(const std::string &path); COMMON_API std::string CleanupPath(std::string path); COMMON_API long GetFileModifiedTime(const std::string &path); COMMON_API bool IsPathAbsolute(const std::string &path); COMMON_API bool Exists(const std::string &path); COMMON_API bool IsRegularFile(const std::string &path); COMMON_API bool IsDirectory(const std::string &path); COMMON_API bool IsSubpath(const std::string &dir, const std::string &path); COMMON_API bool AreSameFile(const std::string &pathA, const std::string &pathB); COMMON_API FileType GetFileType(const std::string &path); COMMON_API long long GetFileSize(const std::string &path); COMMON_API std::vector ListFiles(const std::string &path); //! @code JoinPaths({"home", "a/b"}); @endcode COMMON_API std::string JoinPaths(const std::vector &paths); COMMON_API std::vector SplitPath(std::string path); COMMON_API int MakeDir(const std::string &path); COMMON_API const char *LegacyBasename(const char *path); } // namespace FileUtils } // namespace Wasp ================================================ FILE: include/vapor/FlowParams.h ================================================ #ifndef FLOWPARAMS_H #define FLOWPARAMS_H #include #include #include #include namespace VAPoR { // // These two enums are used across params, GUI, and renderer. // Note: use static_cast to cast between them and int types. // enum class FlowSeedMode : int { UNIFORM = 0, RANDOM = 1, RANDOM_BIAS = 2, LIST = 3 }; enum class FlowDir : int { FORWARD = 0, BACKWARD = 1, BI_DIR = 2 }; class FlowParams; class PARAMS_API FakeRakeBox : public Box { string _tag; public: using Box::Box; FlowParams *parent = nullptr; void Initialize(string tag); void SetExtents(const vector &minExt, const vector &maxExt) override; }; class PARAMS_API FlowParams : public RenderParams { StateSave _fakeRakeStateSave; FakeRakeBox *_fakeRakeBox = nullptr; FakeRakeBox *_fakeIntegrationBox = nullptr; bool _initialized = false; void _setRakeCenter(int dim, double center); double _getRakeCenter(int dim); public: enum RenderType { RenderTypeStream, RenderTypeSamples, RenderTypeDensity }; enum GlpyhType { GlpyhTypeSphere, GlpyhTypeArrow }; // Constructors FlowParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave); FlowParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, XmlNode *xmlNode); FlowParams(const FlowParams &rhs); FlowParams &operator=(const FlowParams &rhs); virtual ~FlowParams(); virtual int Initialize() override; static std::string GetClassType() { return ("FlowParams"); } //! \copydoc RenderParams::SetDefaultVariables() void SetDefaultVariables(int dim = 3, bool secondaryColormapVariable = false) override; //! Sets the type of flow rendering algorithm being used. //! \details Steady flow (streamlines) renders time-invariant trajectories that follow a vector field at a single timestep.\n //! Unsteady flow (pathlines) render time-variant trajectories that advect through the timeseries of a loaded dataset. //! \param[in] bool - Steady/streamlines = true, Unsteady/pathlines = false void SetIsSteady(bool steady); //! Gets the type of flow rendering algorithm being used. //! \copydetails FlowParams::SetIsSteady(bool) //! \retval bool - Steady/streamlines = true, Unsteady/pathlines = false bool GetIsSteady() const; //! Get the multiplier being applied to the flow advection algorithm. //! \details If there happens to be a mismatch between the units of your data's domain and the units of a variable such as wind speed,\n //! you can scale the wind field with this parameter. IE - If your data's domain is written in kilometers but your wind\n //! vectors are in meters, you can apply a velocity multiplyer of 0.001 to correct the mismatch. //! \retval double - Velocity field multiplier for flow rendering double GetVelocityMultiplier() const; //! Get the multiplier being applied to the first step size of flow integration. //! \details VAPOR estimates a step size to be applied to the first step of flow integration,\n //! and then dynamically adjusts that value afterwards. However, VAPOR may fail to produce a proper estimate \n //! (mostly too big of an estimate) and result in obviously wrong flow lines. \n //! In such cases, users may manually apply a multiplier to the first step size. //! \retval double - First step size multiplier for flow rendering. double GetFirstStepSizeMultiplier() const; //! Get the boolean that indicates if the flow advection uses fixed step sizes. //! \details VAPOR adjusts its advection step sizes automatically based on the curvature of the past few steps.\n //! This behavior, however, can be disabled, in which case the user-provided step size will be used.\n //! \retval bool - If VAPOR uses fixed advection steps. bool GetUseFixedAdvectionSteps() const; //! Get the fixed advection step size to be used. //! \copydetails FlowParams::GetUseFixedAdvectionSteps() //! \retval double - Fixed advection step size to be used. double GetFixedAdvectionStepSize() const; //! Set the multiplier being applied to the flow advection algorithm. //! \copydetails FlowParams::GetVelocityMultiplier() //! \param[in] double - Velocity field multiplier for flow rendering void SetVelocityMultiplier(double); //! Set the multiplier being applied to the first step size of flow advection. //! \copydetails FlowParams::GetFirstStepSizeMultiplier() //! \param[in] double - Velocity field multiplier for flow rendering void SetFirstStepSizeMultiplier(double); //! Set the boolean that indicates if the flow advection uses fixed step sizes. //! \copydetails FlowParams::GetUseFixedAdvectionSteps() //! \param[in] bool - If VAPOR uses fixed advection steps. void SetUseFixedAdvectionSteps(bool); //! Set the fixed advection step size to be used. //! \copydetails FlowParams::GetUseFixedAdvectionSteps() //! \param[in] bool - User-specified value to be used for fixed step advection. void SetFixedAdvectionStepSize(double); //! Get the target number of steps to advect a steady flow line (aka a streamline). //! \copydetails FlowParams::SetSteadyNumOfSteps() //! \retval long - The number of steps a steady flow line targets to advect. long GetSteadyNumOfSteps() const; //! Set the target number of steps to advect a steady flow line (aka a streamline). //! \details Note 1: Advection can terminate before hitting the specified target number of steps. Common reasons are 1) it travels \n //! out of the volume, and 2) it enters a "sink" where velocity is zero and no longer travels.\n //! Note 2: The advection step size is adjusted internally based on the current curvature, so even with the same steps\n //! being advected, the lengths of advected trajectories can still differ. //! \param[in] long - The number of steps a steady flow line targets to advect. void SetSteadyNumOfSteps(long); //! Get the mode for generating seeds (points of origin) for the flow renderer. //! \retval int - The current seed generation mode for the flow renderer. 0 = Gridded, 1 = Random, 2 = Random with bias, 3 = List of seeds int GetSeedGenMode() const; //! Set the mode for generating seeds (points of origin) for the flow renderer. //! \param[in] int - The current seed generation mode for the flow renderer. 0 = Gridded, 1 = Random, 2 = Random with bias, 3 = List of seeds void SetSeedGenMode(int); //! Enable or disable the writing of flow renderer data values to a text file. //! \param[in] bool - Enable (true) or disable (false) the writing of trajectory data values to a text file. void SetNeedFlowlineOutput(bool); //! Inquire whether the writing of flow renderer data values are being written to a text file. //! \retval bool - Enable (true) or disable (false) the writing of trajectory data values to a text file. bool GetNeedFlowlineOutput() const; //! Get the current flow renderer's advection direction. //! \retval int - The advection direction for the current flow renderer. (0 = forward, 1 = backward, 2 = bi-directional) int GetFlowDirection() const; //! Set the current flow renderer's advection direction. //! \param[in] int - The advection direction for the current flow renderer. (0 = forward, 1 = backward, 2 = bi-directional) void SetFlowDirection(int); //! Get the file name/path to a file containing a list of seed points to advect from. //! \details See https://ncar.github.io/VaporDocumentationWebsite/vaporApplicationReference/flowRenderer.html#seed-distribution-settings //! \retval string - A file path containing a defined list of seed points to advect from std::string GetSeedInputFilename() const; //! Set the file name/path to a file containing a list of seed points to advect from. //! \copydetails FlowParams::GetSeedInputFilename() //! \param[in] string - A file path containing a defined list of seed points to advect from void SetSeedInputFilename(const std::string &); //! This will return the file path to the text file that data will be written to when outputing flow lines. //! \retval string - The file path of the data file that contains sample values along streamlines/pathlines. std::string GetFlowlineOutputFilename() const; //! Sets the file path to the text file that flowline output will be written to. //! \param[in] string - The file path of the data file that contains sample data along streamlines/pathlines. void SetFlowlineOutputFilename(const std::string &); //! If more than one variable is being sampled along flowlines and is being written to an output file, this returns those variables. //! \retval std::vector - A vector containing the variables being written to the specified output file name. std::vector GetFlowOutputMoreVariables() const; //! One or more variable to be sampled along flowlines and written to an output file. //! \param[in] std::vector - A vector containing the variables being written to the specified output file name. void SetFlowOutputMoreVariables(std::vector vars); //! Inquires whether the current flow advection scheme is periodic. //! \details IE - Do pathlines or streamlines continue on the opposite side of the domain when the exit it? Similar to when PAC-MAN exits the right side of the screen, and re-enters on the left.\n //! Note: this result vector could be of size 2 or 3. //! \retval std::vector - A vector consisting of booleans that indicate periodicity on the X, Y, and Z axes. (false = non-periodic, true = periodic) std::vector GetPeriodic() const; //! Gets whether the current flow advection scheme is periodic. //! \copydetails FlowParams::GetPeriodic() //! \param[in] std::vector - A vector consisting of booleans that indicate periodicity on the X, Y, and Z axes. (false = non-periodic, true = periodic) void SetPeriodic(const std::vector &); /* * 6 values to represent a rake in this particular order: * xmin, xmax, ymin, ymax, zmin, zmax * If the rake wasn't set by users, it returns a vector containing nans. * If it represents a 2D area, then it will contain the first 4 elements. */ Box * GetRakeBox(); std::vector GetRake() const; void SetRake(const std::vector &); Box *GetIntegrationBox(); void SetIntegrationVolume(const std::vector &); //! Returns the number of seed points on the X, Y, and Z axes if the seeding distribution is Gridded, as determined by GetSeedGenMode() //! \retval std::vector - Number of seeds distributed on the X, Y, and Z axes. std::vector GetGridNumOfSeeds() const; //! Sets the number of seed points on the X, Y, and Z axes if the seeding distribution is Gridded, as determined by GetSeedGenMode() //! \retval std::vector - Number of seeds distributed on the X, Y, and Z axes. void SetGridNumOfSeeds(const std::vector &); //! Returns the number of seed points randomly generated if the seeding distribution is randomly generated, as determined by GetSeedGenMode() //! \retval long - Number of seeds randomly distributed within the seeding rake region. long GetRandomNumOfSeeds() const; //! Sets the number of seed points randomly generated if the seeding distribution is randomly generated, as determined by GetSeedGenMode() //! \param[in] long - Number of seeds randomly distributed within the seeding rake region. void SetRandomNumOfSeeds(long); //! Returns the bias variable that randomly seeded flow-lines are distributed towards if the seed generation mode is "Random w/ Bias." //! \retval string - The variable that seeds are biased distributed for. std::string GetRakeBiasVariable() const; //! Sets the bias variable that randomly seeded flow-lines are distributed towards if the seed generation mode is "Random w/ Bias." //! \retval string - The variable that seeds are biased distributed for. void SetRakeBiasVariable(const std::string &); //! When randomly seeding flowlines with bias towards along a chosen variable's distribution, this returns the bias strength. //! \details Negative bias will place seeds at locations where the bias value has low values. Positive bias will place seeds where the bias variable has high values. //! \retval int - The bias of the seed distribution. long GetRakeBiasStrength() const; //! When randomly seeding flowlines with bias towards along a chosen variable's distribution, this sets the bias strength. //! \copydetails //! \param[in] long - The bias of the seed distribution. void SetRakeBiasStrength(long); int GetPastNumOfTimeSteps() const; void SetPastNumOfTimeSteps(int); //! Returns the interval that new pathlines are injected into the scene. //! \retval int - The seed injection interval. int GetSeedInjInterval() const; //! Sets the interval w.r.t. the time steps that new pathlines are injected into the scene. //! For example, 1 means that seeds are injected at every time step, and 2 means that seeds are injected at every other time step. Note "time step" refers to the data set time step, not the integration time step //! \param[in] int - The seed injection interval. void SetSeedInjInterval(int); //! \copydoc RenderParams::GetRenderDim() // virtual size_t GetRenderDim() const override { for (const auto &p : GetFieldVariableNames()) { if (!p.empty()) return _dataMgr->GetVarTopologyDim(p); } return GetBox()->IsPlanar() ? 2 : 3; } //! \copydoc RenderParams::GetActualColorMapVariableName() virtual string GetActualColorMapVariableName() const override { if (UseSingleColor()) return ""; else return GetColorMapVariableName(); } //! Get the rake's center position on the X axis //! \retval X rake center double GetXRakeCenter(); //! Set the rake's center position on the X axis //! \param[in] Rake center position on X axis void SetXRakeCenter(double center); //! Get the rake's center position on the Y axis //! \retval Y rake center double GetYRakeCenter(); //! Set the rake's center position on the Y axis //! \param[in] Rake center position on Y axis void SetYRakeCenter(double center); //! Get the rake's center position on the Z axis //! \retval Z rake center double GetZRakeCenter(); //! Set the rake's center position on the Z axis //! \param[in] Rake center position on Z axis void SetZRakeCenter(double center); //! The rendering type that represents the flow paths. //! See RenderType enum class. static const std::string RenderTypeTag; static const std::string RenderRadiusBaseTag; //! Scales the radius of the flow tube rendering. //! Applies data of type: double. //! Typical values: 0.1 to 5.0. //! Valid values: DBL_MIN to DBL_MAX. static const std::string RenderRadiusScalarTag; //! Toggles between rendering 2d glyphs and 3d geometry of the render type. //! Applies data of type: bool. //! Valid values: 0 = off, 1 = on. static const std::string RenderGeom3DTag; static const std::string RenderLightAtCameraTag; //! Draws the direction of the flow stream. //! Applies data of type: bool. //! Valid values: 0 = off, 1 = on. static const std::string RenderShowStreamDirTag; //! When rendering samples, determines whether samples are rendered as circles or arrows. //! Applies data of type: long. //! Valid values: 0 = FloatParams::GlyphTypeSphere, 1 = FloatParams::GlyphTypeArrow. static const std::string RenderGlyphTypeTag; //! When rendering samples, draw every N samples. //! Applies data of type: int. //! Typical values: 1 to 20. //! Valid values: INT_MIN to INT_MAX. static const std::string RenderGlyphStrideTag; //! When rendering samples, only draw the leading sample in a path. //! Applies data of type: bool. //! Valid values: 0 = off, 1 = on. static const std::string RenderGlyphOnlyLeadingTag; //! Falloff parameter for the flow density rendering mode as specified in //! https://www.researchgate.net/publication/261329939_Trajectory_Density_Projection_for_Vector_Field_Visualization //! Applies data of type: double. //! Typical values: 0.5 to 10.0. //! Valid values: DBL_MIN to DBL_MAX. static const std::string RenderDensityFalloffTag; //! ToneMapping parameter for the flow density rendering mode as specified in //! https://www.researchgate.net/publication/261329939_Trajectory_Density_Projection_for_Vector_Field_Visualization //! Applies data of type: double. //! Typical values: 0.0 to 1.0. //! Valid values: DBL_MIN to DBL_MAX. static const std::string RenderDensityToneMappingTag; //! Applies transparency to the tails of pathlines and streamlines. //! Applies data of type: bool. //! Valid values: 0 = off, 1 = on. static const std::string RenderFadeTailTag; //! Specifies the starting integration step for fading a flow line's tail. //! Applies data of type: int. //! Typical values: 1 to 100. //! Valid values: INT_MIN to INT_MAX. static const std::string RenderFadeTailStartTag; //! Specifies the stopping integration step for fading a flow line's tail. //! Applies data of type: int. //! Typical values: 1 to 100. //! Valid values: INT_MIN to INT_MAX. static const std::string RenderFadeTailStopTag; //! Specifies the length of a faded flow line when animating steady flow. //! Applies data of type: int. //! Typical values: 1 to 100. //! Valid values: INT_MIN to INT_MAX. static const std::string RenderFadeTailLengthTag; //! Specifies the Phong Ambient lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model). //! Applies data of type: double. //! Typical values: 0.0 to 1.0. //! Valid values: DBL_MIN to DBL_MAX. static const std::string PhongAmbientTag; //! Specifies the Phong Diffuse lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model). //! Applies data of type: double. //! Typical values: 0.0 to 1.0. //! Valid values: DBL_MIN to DBL_MAX. static const std::string PhongDiffuseTag; //! Specifies the Phong Specular lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model). //! Applies data of type: double. //! Typical values: 0.0 to 1.0. //! Valid values: DBL_MIN to DBL_MAX. static const std::string PhongSpecularTag; //! Specifies the Phong Shininess lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model). //! Applies data of type: double. //! Typical values: 0.0 to 100.0. //! Valid values: DBL_MIN to DBL_MAX. static const std::string PhongShininessTag; static const std::string _isSteadyTag; static const std::string _velocityMultiplierTag; static const std::string _firstStepSizeMultiplierTag; static const std::string _fixedAdvectionStepTag; static const std::string _fixedAdvectionStepSizeTag; static const std::string _steadyNumOfStepsTag; static const std::string _seedGenModeTag; static const std::string _seedInputFilenameTag; static const std::string _flowlineOutputFilenameTag; static const std::string _flowOutputMoreVariablesTag; static const std::string _flowDirectionTag; static const std::string _needFlowlineOutputTag; static const std::string _xPeriodicTag; static const std::string _yPeriodicTag; static const std::string _zPeriodicTag; static const std::string _rakeTag; static const std::string _doIntegrationTag; static const std::string _integrationScalarTag; static const std::string _integrationSetAllToFinalValueTag; static const std::string _integrationBoxTag; static const std::string _rakeBiasVariable; static const std::string _rakeBiasStrength; static const std::string _pastNumOfTimeSteps; static const std::string _seedInjInterval; static const std::string _xGridNumOfSeedsTag; static const std::string _yGridNumOfSeedsTag; static const std::string _zGridNumOfSeedsTag; static const std::string _randomNumOfSeedsTag; // maps between ints and "human readable" strings const std::vector> _seed2Str = {{static_cast(FlowSeedMode::UNIFORM), ""}, // default value {static_cast(FlowSeedMode::UNIFORM), "UNIFORM"}, {static_cast(FlowSeedMode::RANDOM), "RANDOM"}, {static_cast(FlowSeedMode::RANDOM_BIAS), "RANDOM_BIAS"}, {static_cast(FlowSeedMode::LIST), "LIST"}}; const std::vector> _dir2Str = {{static_cast(FlowDir::FORWARD), ""}, // default value {static_cast(FlowDir::FORWARD), "FORWARD"}, {static_cast(FlowDir::BACKWARD), "BACKWARD"}, {static_cast(FlowDir::BI_DIR), "BI_DIRECTIONAL"}}; }; } // namespace VAPoR #endif ================================================ FILE: include/vapor/FlowRenderer.h ================================================ #ifndef FLOWRENDERER_H #define FLOWRENDERER_H #include "vapor/glutil.h" #include "vapor/Renderer.h" #include "vapor/FlowParams.h" #include "vapor/GLManager.h" #include "vapor/Advection.h" #include "vapor/VaporField.h" #include namespace VAPoR { class RENDER_API FlowRenderer final : public Renderer { public: FlowRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string &instName, DataMgr *dataMgr); // Rule of five ~FlowRenderer(); FlowRenderer(const FlowRenderer &) = delete; FlowRenderer(const FlowRenderer &&) = delete; FlowRenderer &operator=(const FlowRenderer &) = delete; FlowRenderer &operator=(const FlowRenderer &&) = delete; static std::string GetClassType() { return ("Flow"); } protected: virtual std::string _getColorbarVariableName() const override; private: // Define two enums for this class use only enum class FlowStatus { SIMPLE_OUTOFDATE, // When variable name or compression is out of date, TIME_STEP_OOD, // Existing particles are good, but need to advect more UPTODATE // Everything is up-to-date }; // C++ stuff: pure virtual functions from Renderer int _initializeGL() override; int _paintGL(bool fast) override; void _clearCache() override{}; // Member variables flow::Advection _advection; flow::VaporField _velocityField; flow::VaporField _colorField; std::vector _colorMap; std::vector _timestamps; float _colorMapRange[3]; // min, max, and their diff bool _advectionComplete = false; bool _coloringComplete = false; // A few variables to keep the current advection states. // Some of them are initialized to be at an illegal state. int _cache_refinementLevel = 0; int _cache_compressionLevel = 0; double _cache_velocityMltp = 1.0; double _cache_firstStepSizeMltp = 1.0; bool _cache_isSteady = false; long _cache_steadyNumOfSteps = 0; size_t _cache_currentTS = 0; std::vector _cache_periodic{false, false, false}; std::vector _cache_rake{0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; std::vector _cache_gridNumOfSeeds{5, 5, 5}; long _cache_randNumOfSeeds = 5; int _cache_seedInjInterval = 0; int _cache_pastNumOfTimeSteps = 0; long _cache_rakeBiasStrength = 0; double _cache_deltaT = 0.05; FlowSeedMode _cache_seedGenMode = FlowSeedMode::UNIFORM; FlowDir _cache_flowDir = FlowDir::FORWARD; FlowStatus _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; FlowStatus _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; FlowStatus _renderStatus = FlowStatus::SIMPLE_OUTOFDATE; std::string _cache_rakeBiasVariable; std::string _cache_seedInputFilename; bool _cache_doIntegration; bool _cache_integrationSetAllToFinalValue; float _cache_integrationDistScalar; std::vector _cache_integrationVolume; bool _cache_useFixedAdvectionSteps = false; double _cache_fixedAdvectionStepSize = 0.0; // This Advection class is only used in bi-directional advection mode std::unique_ptr _2ndAdvection; // Member variables for OpenGL const GLint _colorMapTexOffset; ShaderProgram *_shader = nullptr; GLuint _vertexArrayId = 0; GLuint _vertexBufferId = 0; GLuint _colorMapTexId = 0; unsigned int _VAO = 0; unsigned int _VBO = 0; vector _streamSizes; // // Member functions // int _genSeedsRakeUniform(std::vector &seeds) const; int _genSeedsRakeRandom(std::vector &seeds) const; int _genSeedsRakeRandomBiased(std::vector &seeds) const; int _genSeedsFromList(std::vector &seeds) const; int _renderFromAnAdvectionLegacy(const flow::Advection *, FlowParams *, bool fast); int _renderAdvection(const flow::Advection *adv); int _renderAdvectionHelper(bool renderDirection = false); void _prepareColormap(FlowParams *); void _particleHelper1(std::vector &vec, const flow::Particle &p, bool singleColor) const; int _drawALineStrip(const float *buf, size_t numOfParts, bool singleColor) const; void _restoreGLState() const; glm::vec3 _getScales(); // Update values of _cache_* and _state_* member variables. int _updateFlowCacheAndStates(const FlowParams *); int _updateAdvectionPeriodicity(flow::Advection *advc); int _outputFlowLines(); void _dupSeedsNewTime(std::vector &seeds, size_t firstN, // First N particles to duplicate double newTime) const; // New time to assign to particles // Print return code if it's non-zero and compiled in debug mode. void _printNonZero(int rtn, const char *file, const char *func, int line) const; }; // End of class FlowRenderer }; // End of namespace VAPoR #endif ================================================ FILE: include/vapor/Font.h ================================================ #pragma once #include #include #include #include "vapor/MyBase.h" #include #include FT_FREETYPE_H namespace VAPoR { struct GLManager; //! \class Font //! \ingroup Public_Render //! //! \brief Renders charachter glyphs using FreeType2 //! This class does not do any transformation, formatting, //! etc., please use the TextLabel class for that. //! //! \author Stanislaw Jaroszynski class RENDER_API Font : public Wasp::MyBase { struct Glyph { unsigned int textureID; int sizeX; int sizeY; int bearingX; int bearingY; long advance; }; GLManager *_glManager; FT_Library _library; FT_Face _face; std::map _glyphMap; int _size; unsigned int _VAO, _VBO; bool LoadGlyph(int c); Glyph GetGlyph(int c); public: Font(GLManager *glManager, const std::string &path, int size, FT_Library library = nullptr); ~Font(); //! Draws text in pixel coordinates i.e. if font is 10px, //! text will be 10 OpenGL units tall. //! //! \param[in] text //! \param[in] color default is white //! void DrawText(const std::string &text, const glm::vec4 &color = glm::vec4(1)); //! Returns pixel dimensions of text //! glm::vec2 TextDimensions(const std::string &text); float LineHeight() const; }; } // namespace VAPoR ================================================ FILE: include/vapor/FontManager.h ================================================ #pragma once #include "vapor/IResourceManager.h" #include "vapor/Font.h" namespace VAPoR { struct GLManager; class RENDER_API FontManager : public IResourceManager, Font> { GLManager *_glManager; FT_Library _library; public: FontManager(GLManager *glManager); ~FontManager(); Font *GetFont(const std::string &name, unsigned int size); int LoadResourceByKey(const std::pair &key); }; } // namespace VAPoR ================================================ FILE: include/vapor/Framebuffer.h ================================================ #pragma once #include #include namespace VAPoR { //! \class Framebuffer //! \ingroup Public_Render //! \brief Wrapper class for an OpenGL Framebuffer //! \author Stas Jaroszynski //! \version 1.0 //! \date May 2019 //! //! This class is intended to be used as a member object for a renderer. //! Any use of this class (including the destructor and except the constructor) //! must occur inside the correct OpenGL context. //! //! To use a depth buffer, EnableDepthBuffer must be called before calling //! Generate() //! class Framebuffer : private NonCopyableMixin { unsigned int _id = 0; int _width = 0; int _height = 0; bool _hasDepthBuffer = false; Texture2D _colorBuffer; Texture2D _depthBuffer; public: ~Framebuffer(); int Generate(); bool Initialized() const; bool IsComplete() const; int GetStatus() const; const char *GetStatusString() const; static const char *GetStatusString(int status); void Bind(); void UnBind(); void SetSize(int width, int height); void GetSize(int *width, int *height) const; int MakeRenderTarget(); void EnableDepthBuffer(); const Texture2D *GetColorTexture() const; const Texture2D *GetDepthTexture() const; }; }; // namespace VAPoR ================================================ FILE: include/vapor/GLManager.h ================================================ #pragma once #include "vapor/ShaderManager.h" #include "vapor/MatrixManager.h" namespace VAPoR { class LegacyGL; class FontManager; //! \class GLManager //! \ingroup Public_Render //! //! \brief Contains references to context scope OpenGL data //! //! \author Stanislaw Jaroszynski struct RENDER_API GLManager { ShaderManager *shaderManager; FontManager * fontManager; MatrixManager *matrixManager; LegacyGL * legacy; GLManager(); ~GLManager(); //! \retval vector[4] from glGetIntegerv(GL_VIEWPORT) //! static std::vector GetViewport(); static glm::vec2 GetViewportSize(); //! Utility function that pushes the current matrix state and //! sets up a pixel coorinate 2D orthographic projection //! void PixelCoordinateSystemPush(); void PixelCoordinateSystemPop(); enum class Vendor { Intel, Nvidia, AMD, Mesa, Other, Unknown }; static Vendor GetVendor(); static void GetGLVersion(int *major, int *minor); static int GetGLSLVersion(); static bool IsCurrentOpenGLVersionSupported(); static bool CheckError(); #ifndef NDEBUG //! Draws the depth buffer in the top right corner //! void ShowDepthBuffer(); #endif static void * BeginTimer(); static double EndTimer(void *startTime); private: static Vendor _cachedVendor; void _queryVendor(); }; } // namespace VAPoR ================================================ FILE: include/vapor/GUIStateParams.h ================================================ //************************************************************************ // * // Copyright (C) 2016 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: GUIStateParams // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: August 2016 // // Description: Maintains various GUI state settings // #ifndef GUISTATEPARAMS_H #define GUISTATEPARAMS_H #include class MouseModeParams; class BookmarkParams; class PARAMS_API GUIStateParams : public VAPoR::ParamsBase { public: GUIStateParams(VAPoR::ParamsBase::StateSave *ssave); GUIStateParams(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node); GUIStateParams(const GUIStateParams &rhs); GUIStateParams &operator=(const GUIStateParams &rhs); virtual ~GUIStateParams(); string GetActiveVizName() const; void SetActiveVizName(string vizWin); //! Get active renderer class and instance name for a visualizer // void GetActiveRenderer(string vizWin, string &renderType, string &renderInst) const; string GetActiveRendererInst() const; //! Get active renderer class and instance name for a visualizer // void SetActiveRenderer(string vizWin, string renderType, string renderInst); string GetActiveDataset() const ; void SetActiveDataset(string name); //! method identifies the current session file //! \retval session file path string GetCurrentSessionFile() const; //! method sets the current session file path //! \param[in] path string void SetCurrentSessionFile(string path); //! Get names of currently opened data sets //! std::vector GetOpenDataSetNames() const { return (m_openDataSets->GetNames()); } std::vector GetOpenDataSetPaths(string dataSetName) const; std::vector GetOpenDataSetRelativePaths(string dataSetName) const; string GetOpenDataSetFormat(string dataSetName) const; void RemoveOpenDataSet(string dataSetName) { m_openDataSets->Remove(dataSetName); } void InsertOpenDataSet(string dataSetName, string format, const std::vector &paths, const std::vector &relPaths={}); //! method sets the current session path //! \param[in] path string void SetOpenDataSets(const std::vector &paths, const std::vector &names); //! method identifies the current session file //! \retval session file path string GetCurrentImagePath() const; //! method sets the current session path //! \param[in] path string void SetCurrentImagePath(string path); //! method identifies the current session file //! \retval session file path string GetCurrentImageSavePath() const; //! method sets the current session path //! \param[in] path string void SetCurrentImageSavePath(string path); //! method identifies the current session file //! \retval session file path string GetCurrentTFPath(); //! method sets the current session path //! \param[in] path string void SetCurrentTFPath(string path); //! method identifies the current session file //! \retval session file path string GetCurrentPythonPath() const; //! method sets the current session path //! \param[in] path string void SetCurrentPythonPath(string path); //! method identifies the current session file //! \retval session file path string GetCurrentFlowPath() const; //! method sets the current session path //! \param[in] path string void SetCurrentFlowPath(string path); MouseModeParams *GetMouseModeParams() const; //! method sets and gets the active data set name in Statistics //! std::string GetStatsDatasetName() const; void SetStatsDatasetName(std::string &name); //! method sets and gets the active data set name in Plot utility //! std::string GetPlotDatasetName() const; void SetPlotDatasetName(std::string &name); string ActiveTab() const; void SetActiveTab(const string &t); int GetFlowDimensionality() const; void SetFlowDimensionality(int nDims); void SetProjectionString(string proj4String) { SetValueString(m_proj4StringTag, "Set Proj4 projection string", proj4String); } string GetProjectionString() const { string defaultv; return (GetValueString(m_proj4StringTag, defaultv)); } class DataSetParam : public ParamsBase { public: DataSetParam(VAPoR::ParamsBase::StateSave *ssave) : ParamsBase(ssave, DataSetParam::GetClassType()) {} DataSetParam(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node) : ParamsBase(ssave, node) {} virtual ~DataSetParam(){}; void SetPaths(const std::vector &paths) { SetValueStringVec(m_dataSetPathsTag, "Data set paths", paths); } std::vector GetPaths() const { return (GetValueStringVec(m_dataSetPathsTag)); }; void SetRelativePaths(const std::vector &paths) { SetValueStringVec(m_dataSetRelativePathsTag, "Data set relative paths", paths); } std::vector GetRelativePaths() const { return (GetValueStringVec(m_dataSetRelativePathsTag)); }; bool HasRelativePaths() const { return !GetRelativePaths().empty(); }; void SetFormat(string format) { SetValueString(m_dataSetFormatTag, "Data set format", format); } string GetFormat() const { return (GetValueString(m_dataSetFormatTag, "vdc")); } static string GetClassType() { return ("DataSetParam"); } private: static const string m_dataSetPathsTag; static const string m_dataSetRelativePathsTag; static const string m_dataSetFormatTag; }; // Get static string identifier for this params class // static string GetClassType() { return ("GUIStateParams"); } void AddBookmark(BookmarkParams *bookmark); BookmarkParams * CreateBookmark(); void SetBookmarks(const vector &all); void DeleteBookmark(int i); void ClearBookmarks(); vector GetBookmarks() const; int GetNumBookmarks() const; BookmarkParams * GetBookmark(int i) const; private: class ActiveRenderer : public ParamsBase { public: ActiveRenderer(VAPoR::ParamsBase::StateSave *ssave) : ParamsBase(ssave, ActiveRenderer::GetClassType()) {} ActiveRenderer(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node) : ParamsBase(ssave, node) {} virtual ~ActiveRenderer(){}; void SetActiveRenderer(string vizWin, string renderType, string renderInst); void GetActiveRenderer(string vizWin, string &renderType, string &renderInst) const; static string GetClassType() { return ("ActiveRenderer"); } }; ActiveRenderer *m_activeRenderer; public: static const string m_activeVisualizer; static const string m_pathParamsTag; static const string m_sessionFileTag; static const string m_imagePathTag; static const string m_imageSavePathTag; static const string m_pythonPathTag; static const string m_flowPathTag; static const string m_tfPathTag; static const string m_statsDatasetNameTag; static const string m_plotDatasetNameTag; static const string m_proj4StringTag; static const string m_openDataSetsTag; static const string _flowDimensionalityTag; static const string BookmarksTag; static const string MovingDomainTrackCameraTag; static const string MovingDomainTrackRenderRegionsTag; static const string ImportDataTypeTag; static const string SessionNewTag; private: MouseModeParams *m_mouseModeParams; VAPoR::ParamsContainer *m_openDataSets; VAPoR::ParamsContainer *_bookmarks; void _init(); }; #endif // GUISTATEPARAMS_H ================================================ FILE: include/vapor/GeoImage.h ================================================ #ifndef _GeoImage_h_ #define _GeoImage_h_ #ifdef WIN32 #include #else #include #endif #include namespace VAPoR { //! \class GeoImage //! \brief An abstract class for managing geo-referenced images //! \author John Clyne //! // class RENDER_API GeoImage : public Wasp::MyBase { public: GeoImage(); //! \param[in] pixelsize Size, in bits, of returned pixel channel //! \param[i] nbands Number of channel in a returned image // GeoImage(int pixelsize, int nbands); virtual ~GeoImage(); //! Initialize the class //! //! \param[in] path Path to file or directory containing image //! database //! //! \param[in] times Times coordinate variable. If image database contains //! time-varying images the time stamps of the images will be compared //! against \p times and the best match will be returned //! //! \retval status return -1 on failure // virtual int Initialize(string path, std::vector times) = 0; //! Fetch a non-georeferenced image //! //! Return an image without any geo-referencing information. //! //! \param[in] ts time step of image //! \param[out] width Width in pixels of returned image //! \param[out] height Height in pixels of returned image //! //! \retval image Upon success at 2D texture with n channels //! (See GeoImage::GeoImage()) is returned. Memory for the returned image //! is managed by the class, and should not be freed. //! virtual unsigned char *GetImage(size_t ts, size_t &width, size_t &height) = 0; //! Fetch a georeferenced image //! //! \param[in] ts time step //! \param[in] pcsExtentsReq A four-element array containing the //! extents (llx, lly, urx, ury) of the //! requested region in Projected Coordinates. //! //! \param[in] proj4StringReq The Proj4 string that maps lat-long coordinates //! into the PCS coordinates used in \p pcsExtentsReq. //! //! \param[in] maxWidthReq The requested maximum width in pixels of the //! returned image //! \param[in] maxHeightReq The requested maximum height in pixels of the //! returned image //! //! \param[out] pcsExtentsImg A four-element array containing the //! extents (llx, lly, urx, ury) of the //! returned image map in Projected Coordinates of the *image*. //! //! \param[out] geoCornersImg An eight-element array containing the //! corner points (llx, lly, ulx, uly, urx, ury, lrx, lry) of the //! returned image map in Geographic coordinates //! //! \param[out] width The actual width in pixels of the //! returned image //! \param[out] height The actual height in pixels of the //! returned image //! //! \retval image Upon success at 2D texture with n channels //! (See GeoImage::GeoImage()) is returned. Memory for the returned image //! is managed by the class, and should not be freed. // virtual unsigned char *GetImage(size_t ts, const double pcsExtentsReq[4], string proj4StringReq, size_t maxWidthReq, size_t maxHeightReq, double pcsExtentsImg[4], double geoCornersImg[8], string &proj4StringImg, size_t &width, size_t &height) = 0; protected: int _pixelsize; int _nbands; // Support routines for reading tiff images // int TiffOpen(string path); void TiffClose(); int TiffGetImageDimensions(int dirnum, size_t &width, size_t &height) const; int TiffReadImage(int dirnum, unsigned char *texture) const; TIFF *TiffGetHandle() const { return (_tif); } int CornerExtents(const double srccoords[4], double dstcoords[4], string proj4src) const; private: TIFF * _tif; string _path; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/GeoImageGeoTiff.h ================================================ #ifndef _GeoImageGeoTiff_h_ #define _GeoImageGeoTiff_h_ #ifdef WIN32 #include #include #else #include #include #endif #include #include #include "GeoImage.h" namespace VAPoR { //! \class GeoImageGeoTiff //! \brief A class for managing GeoTiff images //! \author John Clyne //! // class RENDER_API GeoImageGeoTiff : public GeoImage { public: GeoImageGeoTiff(); virtual ~GeoImageGeoTiff(); int Initialize(string path, vector times); unsigned char *GetImage(size_t ts, size_t &width, size_t &height); unsigned char *GetImage(size_t ts, const double pcsExtentsReq[4], string proj4StringReq, size_t maxWidthReq, size_t maxHeightReq, double pcsExtentsImg[4], double geoCornersImg[8], string &proj4StringImg, size_t &width, size_t &height); private: string _proj4String; std::vector _tiffTimes; std::vector _times; unsigned char * _texture; // storage for texture image size_t _textureSize; // Texture size. No smart buffers :-( string _getProjectionFromGTIF(GTIF *gtifHandle) const; void _initTimeVector(TIFF *tif, const vector ×); bool _getTiffTime(TIFF *tif, UDUnits *udunits, double &tifftime) const; int _getBestDirNum(size_t ts) const; int _getGTIFInfo(TIFF *tif, size_t width, size_t height, double pcsExtents[4], double geoCorners[8], string &proj4String) const; bool _extractSubtexture(unsigned char *texture, size_t width, size_t height, const double pcsExtentsReq[4], string proj4StringReq, const double pcsExtentsImg[4], const double geoCornersImg[8], string proj4StringImg, string &subProj4StringImg, size_t &subWidth, size_t &subHeight, double subPCSExtentsImg[4], double subGeoCornersImg[8]) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/GeoImageTMS.h ================================================ #ifndef _GeoImageTMS_h_ #define _GeoImageTMS_h_ #ifdef WIN32 #include #include #else #include #include #endif #include #include #include #include #include #include "GeoTileMercator.h" #include "GeoImage.h" namespace VAPoR { //! \class GeoImageTMS //! \brief A class for managing OSGeo Tile Map Service Specification images //! \author John Clyne //! // class RENDER_API GeoImageTMS : public GeoImage { public: GeoImageTMS(); virtual ~GeoImageTMS(); int Initialize(string path, vector times); void SetLOD(int lod); unsigned char *GetImage(size_t ts, size_t &width, size_t &height); unsigned char *GetImage(size_t ts, const double pcsExtentsReq[4], string proj4StringReq, size_t maxWidthReq, size_t maxHeightReq, double pcsExtentsImg[4], double geoCornersImg[8], string &proj4StringImg, size_t &width, size_t &height); private: string _dir; // path to TMS directory int _maxLOD; // Maximum LOD available in TMS int _currentLOD; // Current LOD in TMS unsigned char *_texture; // storage for texture image size_t _textureSize; unsigned char *_tileBuf; // storage for a single tile size_t _tileBufSize; GeoTileMercator *_geotile; string _defaultProj4String; // proj4 string for global mercator int _tileSize(string dir, size_t tileX, size_t tileY, int lod, size_t &w, size_t &h); int _tileRead(string dir, size_t tileX, size_t tileY, int lod, unsigned char *tile); int _getBestLOD(const double myGeoExtentsData[4], int maxWidthReq, int maxHeightReq) const; int _getMap(const size_t pixelSW[2], const size_t pixelNE[2], int lod, unsigned char *texture); }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/GeoTIFWriter.h ================================================ #pragma once #include "vapor/TIFWriter.h" #ifdef WIN32 #include #else #include #endif namespace VAPoR { //! \class GeoTIFWriter //! \ingroup Public_Render //! \brief Writes a TIF image with GeoTIF metadata //! \author Stanislaw Jaroszynski //! class RENDER_API GeoTIFWriter : public TIFWriter { GTIF *gtif; bool _hasTiePoint; bool _hasPixelScale; bool _geoTiffWasConfigured; public: GeoTIFWriter(const std::string &path); ~GeoTIFWriter(); int Write(const unsigned char *buffer, const unsigned int width, const unsigned int height); int ConfigureFromProj4(const std::string proj4String); void SetTiePoint(double worldX, double worldY, double rasterX = 0, double rasterY = 0); void SetPixelScale(double x, double y); }; } // namespace VAPoR ================================================ FILE: include/vapor/GeoTile.h ================================================ #ifndef GeoTile_h_ #define GeoTile_h_ #include #include #ifdef _WINDOWS #pragma warning(disable : 4251) #endif // //! \class GeoTile //! //! \brief An abstract class for managing geo-referenced world maps, //! decomposed into tiles, and supporting level-of-detail refinement. //! //! This representation is based on Microsoft's Virtual Earth Tile System //! (Bing Maps), described here //! \sa http://msdn.microsoft.com/en-us/library/bb259689 //! //! The image tiles are also compatible with the tiling system used by //! Google Maps and the open source Tile Map Service, differing only //! in how the tiles are indexed. Microsoft (and this class) use //! "quadkeys", whereas, Google and TMS employ different indexing/naming //! conventions for tiles. The encoding of quadkeys in this implementation //! differs from Microsoft's in one respect: a quadkey == "" (empty string) //! is a valid key, coresponding to level-of-detail zero, a single tile //! covering the entire globe. I.e. the coarsest lod permitted by Microsoft is //! level one, and coresponds to a four-tile decomposition of the global //! map projection. A single tile, level-zero, map is permitted by this class. //! //! The above world map tiling systems all employ a Mercator projection. //! No projection is specified by this base class. The projection type //! is left to derived classes. //! //! \note Much of this code is based on the sample representation provided //! by Microsoft. //! //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! #include #ifdef WINDOWS #pragma warning(disable : 4251) #endif namespace VAPoR { class RENDER_API GeoTile { public: //! Create a GeoTile object //! //! \param[in] tile_width The width of a tile in pixels //! \param[in] tile_height The height of a tile in pixels //! \param[in] pixelsize The size of a pixel in bytes //! \param[in] min_lon The minimum valid longitude for the map projection //! \param[in] min_lat The minimum valid lattitude for the map projection //! \param[in] max_lon The maximum valid longitude for the map projection //! \param[in] max_lat The maximum valid lattitude for the map projection //! GeoTile(size_t tile_width, size_t tile_height, size_t pixelsize, double min_lon, double min_lat, double max_lon, double max_lat); virtual ~GeoTile(); //! Insert an image tile into the class object //! //! This method is used to add geo-referenced image tiles to the class. //! //! \param[in] quadkey A string encoding the location (index) and level //! of detail of \p image //! \param[in] image A pointer to the image tile to be copied into //! the object class. The size of the image tile must be \p tile_width * //! \p tile_height * \p pixelsize //! //! \sa GeoTile() // int Insert(std::string quadkey, const unsigned char *image); //! Converts a point from latitude/longitude WGS-84 coordinates (in degrees) //! into pixel XY coordinates at a specified level of detail. //! //! \param[in] lon Longitude of the point, in degrees. //! \param[in] lat Latitude of the point, in degrees. //! \param[in] lod Level of detail, from 0 (lowest detail) //! to 23 (highest detail). //! \param[out] pixelX Output parameter receiving the X coordinate in pixels. //! \param[out] pixelY Output parameter receiving the Y coordinate in pixels. //! //! \sa PixelXYToLatLong() // virtual void LatLongToPixelXY(double lon, double lat, int lod, size_t &pixelX, size_t &pixelY) const = 0; //! Converts a pixel from pixel XY coordinates at a specified level of detail //! into latitude/longitude WGS-84 coordinates (in degrees). //! //! \param [in] pixelX X coordinate of the point, in pixels. //! \param [in] pixelY Y coordinates of the point, in pixels. //! \param [in] lod Level of detail, from 0 (lowest detail) //! to 23 (highest detail). //! \param [out] lat Output parameter receiving the latitude in degrees. //! \param [out] lon Output parameter receiving the longitude in degrees //! //! \sa LatLongToPixelXY() //! virtual void PixelXYToLatLon(size_t pixelX, size_t pixelY, int lod, double &lon, double &lat) const = 0; //! Converts pixel XY coordinates into tile XY coordinates of the tile //! containing the specified pixel. //! //! Given a map coordinate in pixels, this method returns the index of //! of the tile containing the pixel, as well as the pixel's location //! within the tile coordinate system. //! //! \param [in] pixelX Pixel X coordinate. //! \param [in] pixelY Pixel Y coordinate. //! \param [in] tileX Output parameter receiving the tile's X coordinate. //! \param [in] tileY Output parameter receiving the tile's Y coordinate. //! \param [in] tilePixelX Output parameter receiving the pixel's X //! in the tile's local coordinate system. //! \param [in] tilePixelY Output parameter receiving the pixel's Y //! in the tile's local coordinate system. //! void PixelXYToTileXY(size_t pixelX, size_t pixelY, size_t &tileX, size_t &tileY, size_t &tilePixelX, size_t &tilePixelY) const; //! Converts tile XY coordinates into pixel XY coordinates of the //! upper-left pixel of the specified tile. //! //! \param [in] tileX Tile X coordinate. //! \param [in] tileY Tile Y coordinate. //! \param [out] pixelX Output parameter receiving the pixel X coordinate. //! \param [out] pixelY Output parameter receiving the pixel Y coordinate. //! void TileXYToPixelXY(size_t tileX, size_t tileY, size_t &pixelX, size_t &pixelY) const; //! Return a pointer to the image tile associated with a quadkey //! //! This method returns a pointer to the image tile associated with //! the Quad Key \p quadkey. If no image tile has been added to the //! class for \p quadkey, a null pointer is returned. //! //! \param[in] quadkey A Quad Key //! \retval tile If the tile associated with \p quadkey exists, a pointer //! to it is returned. If the tile does not exist (or if \p quadkey is //! not a valid key), the NULL pointer is returned //! //! \sa Insert() // const unsigned char *GetTile(std::string quadkey) const; //! Return a pointer to an image tile //! //! This method returns a pointer to the image tile associated with //! a tile index and level of detail. //! If no image tile has been added to the //! class for combination of tile index and lod, a null pointer is returned. //! //! \param[in] tileX X coordinate of tile //! \param[in] tileY X coordinate of tile //! \param[in] lod level of detail of tile //! \retval tile If the tile associated with \p tileX, \p tileY, and //! \p lod, a pointer //! to it is returned. If the tile does not exist (or if \p quadkey is //! not a valid key), the NULL pointer is returned //! //! \sa Insert() // const unsigned char *GetTile(size_t tileX, size_t tileY, int lod) const { std::string quadkey = TileXYToQuadKey(tileX, tileY, lod); return (GetTile(quadkey)); } //! This method contructs a continuous (non-tiled) map from the //! tiles contained within the class. //! //! Given a rectangular boundary described to two points (the north-west and //! south-east corner) in pixel coordinates, and a level of detail, this //! method constructs and returns a continuous map. //! //! \param[in] pixelX0 X coordinate of north-west corner in pixel coordinates //! \param[in] pixelY0 Y coordinate of north-west corner in pixel coordinates //! \param[in] pixelX0 X coordinate of south-east corner in pixel coordinates //! \param[in] pixelY0 Y coordinate of south-east corner in pixel coordinates //! \param[in] lod Level of detail //! \param[out] map_image The constructed map is copied to the location //! pointed to by \p map_image. The memory referenced by \p map_image //! must of sufficient size to accommodate the map. //! //! \retval status A zero is returned on success. If the coordinates //! are invalid, or if all of the tiles needed are not present, a negative //! value is returned. //! //! \sa MapSize(), Insert(), LatLongToPixelXY(). // int GetMap(size_t pixelX0, size_t pixelY0, size_t pixelX1, size_t pixelY1, int lod, unsigned char *map_image) const; //! Converts tile XY coordinates into a QuadKey at a specified level of detail. //! //! \param[in] tileX Tile X coordinate. //! \param[in] tileY Tile Y coordinate. //! \param[in] lod Level of detail, from 0 (lowest detail) //! to 23 (highest detail). //! //! \retval quadkey A string containing the QuadKey. // static std::string TileXYToQuadKey(size_t tileX, size_t tileY, int lod); //! Converts a QuadKey into tile XY coordinates. //! //! \param[in] quadKey QuadKey of the tile. //! \param[out] tileX Output parameter receiving the tile X coordinate. //! \param[out] tileY Output parameter receiving the tile Y coordinate. //! \param[out] lod Output parameter receiving the level of detail. //! //! \retval status A zero is returned on success, otherwise a negative //! value is returned if the supplied inputs are invalid //! static int QuadKeyToTileXY(std::string quadKey, size_t &tileX, size_t &tileY, int &lod); //! Compute the size of the global map in pixels at a specified lod //! //! This method calculates the width and height, in pixels, of the global //! map at a specified level of detail //! //! \param[in] lod The level of detail //! \param[out] nx Width of the map in pixels //! \param[out] ny Height of the map in pixels // void MapSize(int lod, size_t &nx, size_t &ny) const; //! Compute the size of a map in pixels at a specified lod and coordinates //! //! Given a rectangular boundary described by two points (the north-west and //! south-east corner) in pixel coordinates, and a level of detail, this //! method computes the size of the map (width and height) in pixels. //! //! \param[in] pixelX0 X coordinate of north-west corner in pixel coordinates //! \param[in] pixelY0 Y coordinate of north-west corner in pixel coordinates //! \param[in] pixelX0 X coordinate of south-east corner in pixel coordinates //! \param[in] pixelY0 Y coordinate of south-east corner in pixel coordinates //! \param[in] lod The level of detail //! \param[out] nx Width of the map in pixels //! \param[out] ny Height of the map in pixels // int MapSize(size_t pixelX0, size_t pixelY0, size_t pixelX1, size_t pixelY1, int lod, size_t &nx, size_t &ny) const; void GetLatLonExtents(double &minlon, double &minlat, double &maxlon, double &maxlat) const { minlon = _MinLongitude; minlat = _MinLatitude; maxlon = _MaxLongitude; maxlat = _MaxLatitude; } void GetTileSize(size_t &w, size_t &h) const { w = _tile_width; h = _tile_height; } //! Map a rectanular region described by lat-lon coordinates to pixel coordinates //! //! //! \param[in] geoSW A two-element array containing the longitude, and latitude coordinate, respectively, //! of the south-west corner of the region //! \param[in] geoNE A two-element array containing the longitude, and latitude coordinate, respectively, //! of the north-east corner of the region //! \param[in] lod The level of detail //! \param[out] pixelSW Returns a two-element array containing the X, and Y pixel coordinates, respectively, //! of the south-west corner of the region //! \param[out] pixelNE Returns a two-element array containing the X, and Y pixel coordinates, respectively, //! of the north-east corner of the region // void LatLongRectToPixelRect(const double geoSW[2], const double geoNE[2], int lod, size_t pixelSW[2], size_t pixelNE[2]) const; private: size_t _pixel_size; std::map _tiles; void _CopyTileToMap(const unsigned char *tile, size_t tilePixelX0, size_t tilePixelY0, size_t tilePixelX1, size_t tilePixelY1, unsigned char *map, size_t pixelX0, size_t pixelX1, size_t nx, size_t ny) const; protected: size_t _tile_width; size_t _tile_height; double _MinLatitude; double _MaxLatitude; double _MinLongitude; double _MaxLongitude; double _Clip(double n, double minValue, double maxValue) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/GeoTileEquirectangular.h ================================================ #ifndef GeoTileEquirectangular_h_ #define GeoTileEquirectangular_h_ #ifdef _WINDOWS #pragma warning(disable : 4251) #endif #include "GeoTile.h" #include namespace VAPoR { //! \class GeoTileEquirectangular //! //! This class derives the GetTile base class to provide a tiled world //! mapping system using the Equirectangular projection. //! //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! class RENDER_API GeoTileEquirectangular : public GeoTile { public: //! GeoTileEquirectangular class constructor //! //! \param[in] tile_height Height of an image tile in pixels. The tile //! width must be twice the tile height //! \param[in] pixelsize The size of a pixel in bytes //! //! GeoTileEquirectangular(size_t tile_width, size_t tile_height, size_t pixelsize) : GeoTile(tile_width, tile_height, pixelsize, -180.0, -90.0, 180.0, 90.0) {} //! copydoc GeoTile::LatLongToPixelXY() // virtual void LatLongToPixelXY(double lon, double lat, int lod, size_t &pixelX, size_t &pixelY) const; //! copydoc GeoTile::PixelXYToLatLon() // virtual void PixelXYToLatLon(size_t pixelX, size_t pixelY, int lod, double &lon, double &lat) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/GeoTileMercator.h ================================================ #ifndef GeoTileMercator_h_ #define GeoTileMercator_h_ #ifdef _WINDOWS #pragma warning(disable : 4251) #endif #include "GeoTile.h" #include //! \class GeoTileMercator //! //! This class derives the GetTile base class to provide a tiled world //! mapping system using the Web "Pseudo-Mercator" projection. //! //! The following GDAL commands wered used to transform the NASA blue //! marble image into a suitable Mercator //! //! gdal_translate -of GTiff -a_srs EPSG:4326 -gcp 0 0 -180 90 //! -gcp 4096 0 180 90 -gcp 4096 2048 180 -90 BBM.4096.png bluemarble1.tif //! //! gdalwarp -t_srs EPSG:4326 bluemarble1 bluemarble2.tif //! //! gdalwarp -s_srs EPSG:4326 -t_srs EPSG:3857 -r bilinear //! -ts 4096 4096 -te -20037508.34 -20037508.34 20037508.34 20037508.34 //! bluemarble1.tif bluemarble3.tif //! //! \sa https://www.mapbox.com/tilemill/docs/guides/reprojecting-geotiff/ //! //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! namespace VAPoR { class RENDER_API GeoTileMercator : public GeoTile { public: //! GeoTileMercator class constructor //! //! \param[in] tile_height Height of an image tile in pixels. The tile //! width must the same as the tile height //! \param[in] pixelsize The size of a pixel in bytes //! //! GeoTileMercator(size_t tile_width, size_t tile_height, size_t pixelsize) : GeoTile(tile_width, tile_height, pixelsize, -180.0, -85.05112878, 180.0, 85.05112878) {} GeoTileMercator(size_t tile_width, size_t tile_height, size_t pixelsize, double min_lon, double min_lat, double max_lon, double max_lat) : GeoTile(tile_width, tile_height, pixelsize, min_lon, min_lat, max_lon, max_lat) { } //! copydoc GeoTile::LatLongToPixelXY() // virtual void LatLongToPixelXY(double lon, double lat, int lod, size_t &pixelX, size_t &pixelY) const; //! copydoc GeoTile::PixelXYToLatLon() // virtual void PixelXYToLatLon(size_t pixelX, size_t pixelY, int lod, double &lon, double &lat) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/GeoUtil.h ================================================ // $Id$ // #ifndef _GeoUtil_h_ #define _GeoUtil_h_ #include #include namespace VAPoR { // //! \class GeoUtil //! \brief Misc. utilities for operating on geographic coordinates //! //! //! \author John Clyne //! class VDF_API GeoUtil : public Wasp::MyBase { public: //! Shift a container of longitude values so that all //! values are in the range [-bound .. bound] // static void ShiftLon(vector::iterator first, vector::iterator last, double bound = 360.0); static void ShiftLon(vector::iterator first, vector::iterator last, double bound = 360.0); static void ShiftLon(float *first, float *last, double bound = 360.0); //! Unwrap any wrapped longitued values //! //! Iteratively adds 360.0 to each value in a container that is less than //! the first value until the new value is greater than the first. // static void UnwrapLongitude(vector::iterator first, vector::iterator last); static void UnwrapLongitude(vector::iterator first, vector::iterator last); static void UnwrapLongitude(float *first, float *last); //! Extract boundary points from a 2D grid //! //! This method walks a 2D array, \p a, in counter-clockwise order, visiting //! each boundary grid point exactly once, copying the value //! to the array \p bdry. A total of 2*nx + 2*ny - 4 grid points are //! copied. //! //! \param[in] a An 2D array dimensioned \p nx by \p ny //! \param[in] nx dimension of fastest moving coordinate //! \param[in] ny dimension of slowest moving coordinate //! \param[output] bdry Output array containing the boundary values //! of \p a. The number of elements copied to \p bdry is //! 2 * \p nx + 2 * \p ny - 4. // static void ExtractBoundary(const float *a, int nx, int ny, float *bdry); static void ExtractBoundary(const double *a, int nx, int ny, double *bdry); private: }; }; // namespace VAPoR #endif // _GeoUtil_h_ ================================================ FILE: include/vapor/GetAppPath.h ================================================ // // $Id$ // #ifndef INCLUDE_DEPRECATED_GET_APP_PATH #error GetAppPath.h is deprecated. Please use ResourcePath.h #endif #ifndef _GetAppPath_h_ #define _GetAppPath_h_ #include namespace Wasp { COMMON_API std::string GetAppPath(const string &app, const string &name, const vector &paths, #ifdef _WINDOWS // Windows default is backwards slash for separator bool forwardSeparator = false #else bool forwardSeparator = true #endif ); }; // namespace Wasp #endif ================================================ FILE: include/vapor/Grid.h ================================================ #ifndef _Grid_ #define _Grid_ #include #include #include #include #include #include #include #include #include "vapor/VAssert.h" #include #include #ifdef WIN32 #pragma warning(disable : 4661 4251) // needed for template class #endif namespace VAPoR { //! Type for specifying floating point coordinates using CoordType = std::array; //! Type for specifying integer indices using DimsType = std::array; //! \class Grid //! \brief Abstract base class for a 2D or 3D structured or unstructured //! grid. //! \author John Clyne //! //! This abstract base class defines a 2D or 3D structured or unstructured //! grid. //! //! The grid samples a scalar function at each grid point. Each //! grid point can be addressed by a 3-element array defined as //! type \p DimsType. //! The fastest varying dimension is //! given by indices[0], etc. //! //! Because grid samples are repesented internally as arrays, when accessing //! multiple grid points better performance is achieved by using //! unit stride. //! //! \param indices A \b DimsType i in the range 0..max, //! where max is one minus the value of the corresponding element //! returned by GetDimensions(). //! //! \param coords A \b CoordType //! containig the coordinates of a point in user-defined //! coordinates. Elements with indices greater than GetGeometryDim()-1 are //! ignored. //! // class VDF_API Grid { public: //! //! Construct a structured or unstructured grid sampling a 3D or //! 2D scalar function //! //! \param[in] dims Dimensions of arrays containing grid data. //! //! \param[in] bs A \b DimsType with, specifying the //! dimensions of //! each block storing the sampled scalar function. //! //! \param[in] blks An array of blocks containing the sampled function. //! The dimensions of each block //! is given by \p bs. The number of blocks is given by the product //! of the terms: //! //! \code (((dims[i]-1) / bs[i]) + 1) \endcode //! //! over i = 0..dims.size()-1 //! //! A shallow copy of the blocks is made by the constructor. Memory //! referenced by the elements of \p blks should remain valid //! until the class instance is destroyed. //! //! \param[in] topology_dimension Topological dimension of //! grid: 1, 2 or 3, for 1D, 2D or 3D, respectively. Grids with 2D //! topology are composed of 2D polygons, while //! grids with 3D topology are composed of 3D polyhedron //! Grid(const std::vector &dims, const std::vector &bs, const std::vector &blks, size_t topology_dimension); Grid(const DimsType &dims, const DimsType &bs, const std::vector &blks, size_t topology_dimension); Grid(); virtual ~Grid() = default; //! Return the dimensions of grid connectivity array //! //! \param[out] dims The value of \p dims parameter provided to //! the constructor. If the parameter has less than 3 values, then //! number 1 will be filled. //! //! \sa GetGeometryDim(), GetTopologyDim() //! const DimsType &GetDimensions() const { return _dims; } //! Return the useful number of dimensions of grid connectivity array //! //! \param[out] dims The number of non-unit components of \p dims parameter provided to //! the constructor. //! size_t GetNumDimensions() const { return GetNumDimensions(_dims); } //! Return the number of non-unit dimensions //! //! Return the number of non-unit dimensions in \p dims //! //! \param[in] dims //! static size_t GetNumDimensions(DimsType dims); //! Return the dimensions of the specified coordinate variable //! //! \param[in] dim An integer between 0 and the return value //! of GetGeometryDim() - 1, indicating which //! coordinate dimensions are to be returned. //! //! if \p dim is greater than or equal to GetGeometryDim() - 1 //! a vector of length one with its single component equal to //! one is returned. //! virtual DimsType GetCoordDimensions(size_t dim) const = 0; virtual std::string GetType() const = 0; //! Get geometric dimension of cells //! //! Returns the geometric dimension of the cells in the mesh. I.e. //! the number of spatial coordinates for each grid point. //! Valid values are 0..3. The geometric dimension must be equal to //! or greater than the topology dimension. //! //! \sa GetTopologyDim() // virtual size_t GetGeometryDim() const = 0; virtual const DimsType &GetNodeDimensions() const = 0; virtual const size_t GetNumNodeDimensions() const = 0; virtual const DimsType &GetCellDimensions() const = 0; virtual const size_t GetNumCellDimensions() const = 0; //! Return the ijk dimensions of grid in blocks //! //! Returns the number of blocks defined along each axis of the grid //! //! \param[out] dims A two or three element array containing the grid //! dimension in blocks //! //! \sa GetBlockSize(); // const std::vector GetDimensionInBlks() const { return (_bdimsDeprecated); } //! Return the internal blocking factor //! //! This method returns the internal blocking factor passed //! to the constructor. // const std::vector &GetBlockSize() const { return (_bsDeprecated); } //! Return the internal data structure containing a copy of the blocks //! passed in by the constructor //! const std::vector &GetBlks() const { return (_blks); }; //! Get the data value at the indicated grid point //! //! This method provides read access to the scalar data value //! defined at the grid point indicated by \p indices. The range //! of valid indices is between zero and \a dim - 1, where \a dim //! is the dimesion of the grid returned by GetDimensions() //! //! If any of the \p indecies are outside of the //! valid range the results are undefined //! //! \param[in] indices of grid point along fastest varying dimension. //! virtual float GetValueAtIndex(const DimsType &indices) const; //! \deprecated // virtual float GetValueAtIndex(const std::vector &indices) const { DimsType a = {0, 0, 0}; CopyToArr3(indices, a); return (GetValueAtIndex(a)); } //! Set the data value at the indicated grid point //! //! This method sets the data value of the grid point indexed by //! \p indices to \p value. //! virtual void SetValue(const DimsType &indices, float value); //! \deprecated // virtual void SetValue(const size_t indices[3], float value) { DimsType i3 = {0, 0, 0}; CopyToArr3(indices, GetNodeDimensions().size(), i3); SetValue(i3, value); } //! This method provides an alternate interface to Grid::GetValueAtIndex() //! If the dimensionality of the grid as determined by GetDimensions() is //! less than three subsequent parameters are ignored. Parameters //! that are outside of range are clamped to boundaries. //! //! \param[in] i Index into first fastest varying dimension //! \param[in] j Index into second fastest varying dimension //! \param[in] k Index into third fastest varying dimension // virtual float AccessIJK(size_t i, size_t j = 0, size_t k = 0) const; void SetValueIJK(size_t i, size_t j, size_t k, float v); void SetValueIJK(size_t i, size_t j, float v) { SetValueIJK(i, j, 0, v); } void SetValueIJK(size_t i, float v) { SetValueIJK(i, 0, 0, v); } //! Get the reconstructed value of the sampled scalar function //! //! This method reconstructs the scalar field at an arbitrary point //! in space. If the point's coordinates are outside of the grid's //! coordinate extents as returned by GetUserExtents(), and the grid //! is not periodic along the out-of-bounds axis, the value //! returned will be the \a missing_value. //! //! If the value of any of the grid point samples used in the reconstruction //! is the \a missing_value then the result returned is the \a missing_value. //! //! The reconstruction method used is determined by interpolation //! order returned by GetInterpolationOrder() //! //! \param[in] coords A vector of size matching the topology dimension //! of the mesh whose contents specify the coordinates of a point in space. //! //! \sa GetInterpolationOrder(), HasPeriodic(), GetMissingValue() //! \sa GetUserExtents() //! virtual float GetValue(const CoordType &coords) const; //! \deprecated // virtual float GetValue(const std::vector &coords) const { CoordType c3 = {0.0, 0.0, 0.0}; CopyToArr3(coords, c3); return (GetValue(c3)); }; //! \deprecated // virtual float GetValue(const double coords[]) const { CoordType c3 = {0.0, 0.0, 0.0}; CopyToArr3(coords, GetGeometryDim(), c3); return (GetValue(c3)); } virtual float GetValue(double x, double y) const { double coords[] = {x, y, 0.0}; return (GetValue(coords)); } virtual float GetValue(double x, double y, double z) const { double coords[] = {x, y, z}; return (GetValue(coords)); } //! Return the extents of the user coordinate system //! //! This pure virtual method returns min and max extents of //! the user coordinate //! system defined on the grid. The extents of the returned box //! are guaranteed to contain all points in the grid. //! //! \param[out] minu A two or three element array containing the minimum //! user coordinates. //! \param[out] maxu A two or three element array containing the maximum //! user coordinates. //! //! \sa GetDimensions(), Grid() //! virtual void GetUserExtents(CoordType &minu, CoordType &maxu) const; //! \deprecated // virtual void GetUserExtents(double minu[3], double maxu[3]) const { CoordType minu3 = {0.0, 0.0, 0.0}; CoordType maxu3 = {0.0, 0.0, 0.0}; GetUserExtents(minu3, maxu3); CopyFromArr3(minu3, minu); CopyFromArr3(maxu3, maxu); } //! \deprecated // virtual void GetUserExtents(std::vector &minu, std::vector &maxu) const { CoordType minu3 = {0.0, 0.0, 0.0}; CoordType maxu3 = {0.0, 0.0, 0.0}; GetUserExtents(minu3, maxu3); CopyFromArr3(minu3, minu); CopyFromArr3(maxu3, maxu); // Much of the use of this method assumes that the size of the minu,maxu // vectors can be used to determine the number of coordinates. So we // maintain this property for now. // minu.resize(GetGeometryDim()); maxu.resize(GetGeometryDim()); } //! Return the extents of the axis-aligned bounding box enclosign a region //! //! This pure virtual method returns min and max extents, in user coordinates, //! of the smallest axis-aligned box enclosing the region defined //! by the grid indices, \p min and \p max. Every grid point in //! the range \p min to \p max will be contained in, or reside on, the //! box (rectangle) whose extents are given by \p minu and \p maxu. //! //! \note The results are undefined if any index of \p min is //! greater than the coresponding coordinate of \p max, or if \p max //! is outside of the valid dimension range (See GetDimension()). //! //! The size of \p min and \p max must match the grid's dimension //! as returned by GetDimension() //! //! \param[in] min An array containing the minimum //! grid indices (offsets). //! \param[in] max An array containing the maximum //! grid indices (offsets). //! \param[out] minu A two-to-three element array containing the minimum //! user coordinates. //! \param[out] maxu A two-to-three element array containing the maximum //! user coordinates. //! //! \sa GetDimensions(), Grid() //! virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const = 0; virtual void GetBoundingBox(const std::vector &min, const std::vector &max, std::vector &minu, std::vector &maxu) const { VAssert(min.size() == max.size()); DimsType min3 = {0, 0, 0}; DimsType max3 = {0, 0, 0}; CoordType minu3 = {0.0, 0.0, 0.0}; CoordType maxu3 = {0.0, 0.0, 0.0}; CopyToArr3(min, min3); CopyToArr3(max, max3); GetBoundingBox(min3, max3, minu3, maxu3); CopyFromArr3(minu3, minu); CopyFromArr3(maxu3, maxu); } //! //! Get bounding indices of grid containing a region //! //! Calculates the starting and ending grid indices of the //! smallest grid //! completely containing the rectangular region defined by the user //! coordinates \p minu and \p maxu //! If rectangluar region defined by \p minu and \p maxu can //! not be contained the //! minimum and maximum indices are returned in //! \p min and \p max, respectively //! //! \param[in] minu User coordinates of minimum coorner //! \param[in] maxu User coordinates of maximum coorner //! \param[out] min Integer coordinates of minimum coorner //! \param[out] max Integer coordinates of maximum coorner //! virtual bool GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const = 0; //! Return the value of the \a missing_value parameter //! //! The missing value is a special value intended to indicate that the //! value of the sampled or reconstructed function is unknown at a //! particular point. //! virtual float GetMissingValue() const; //! Set the missing value indicator //! //! This method sets the value of the missing value indicator. The //! method does not alter the value of any grid point locations, nor //! does it alter the missing data flag set with the constructor. //! //! \sa HasMissingData(), GetMissingValue() //! void SetMissingValue(float missing_value) { _missingValue = missing_value; }; //! Set missing data flag //! //! Set this flag if missing values may exist in the data. This missing //! values are denoted by the value GetMissingValue(). Subsequent processing //! of grid data will be compared against the value of GetMissingValue() //! if this flag is set. // void SetHasMissingValues(bool flag) { _hasMissing = flag; } //! Return missing data flag //! //! This method returns true if the missing data flag is set. //! This does not //! imply that grid points exist with missing data, only that the //! the grid points should be compared against the value of //! GetMissingValue() whenever operations are performed on them. // bool HasMissingData() const { return (_hasMissing); }; //! Return true if mesh primitives have counter clockwise winding //! order. // virtual bool HasInvertedCoordinateSystemHandiness() const { return (true); } //! Return the interpolation order to be used during function reconstruction //! //! This method returns the order of the interpolation method that will //! be used when reconstructing the sampled scalar function //! //! \sa SetInterpolationOrder() //! virtual int GetInterpolationOrder() const { return _interpolationOrder; }; //! Set the interpolation order to be used during function reconstruction //! //! This method sets the order of the interpolation method that will //! be used when reconstructing the sampled scalar function. Valid values //! of \p order are 0 and 1, corresponding to nearest-neighbor and linear //! interpolation, respectively. If \p order is invalid it will be silently //! set to 1. The default interpolation order is 1 //! //! \param[in] order interpolation order //! \sa GetInterpolationOrder() //! virtual void SetInterpolationOrder(int order); //! Compute the dimensions of a rectangular region bounded //! by \p min and \p max coordinates // static DimsType Dims(const DimsType &min, const DimsType &max); //! Return the user coordinates of a grid point //! //! This method returns the user coordinates of the grid point //! specified by \p indices //! //! Results are undefined if \p indices is out of range. //! //! \param[in] index Logical index into coordinate array. The dimensionality //! and range of component values are given by GetNodeDimensions(). The //! starting value for each component of \p index is zero. \p index must contain //! GetNodeDimensions().size() elements. //! //! \param[out] coord User coordinates of grid point with indices //! given by \p indices. \p coord must have space for the number of elements //! returned by GetGeometryDim(). //! virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const = 0; virtual void GetUserCoordinates(const size_t indices[], double coords[]) const { DimsType indices3 = {0, 0, 0}; CoordType coords3 = {0.0, 0.0, 0.0}; CopyToArr3(indices, GetNodeDimensions().size(), indices3); GetUserCoordinates(indices3, coords3); CopyFromArr3(coords3, coords); } virtual void GetUserCoordinates(const std::vector &indices, std::vector &coords) const { DimsType indices3 = {0, 0, 0}; CoordType coords3 = {0.0, 0.0, 0.0}; CopyToArr3(indices, indices3); GetUserCoordinates(indices3, coords3); CopyFromArr3(coords3, coords); } virtual void GetUserCoordinates(size_t i, double &x, double &y, double &z) const; virtual void GetUserCoordinates(size_t i, size_t j, double &x, double &y, double &z) const; virtual void GetUserCoordinates(size_t i, size_t j, size_t k, double &x, double &y, double &z) const; //! Return the indices of the cell containing the //! specified user coordinates //! //! This method returns the cell ID (index) of the cell containing //! the specified user coordinates. If any //! of the input coordinates correspond to periodic dimensions the //! the coordinate(s) are first re-mapped to lie inside the grid //! extents as returned by GetUserExtents() //! //! If the specified coordinates lie outside of the grid (are not //! contained by any cell) the method returns false, otherwise true is //! returned. //! //! \retval status true on success, false if the point is not contained //! by any cell. //! virtual bool GetIndicesCell(const CoordType &coords, DimsType &indices) const = 0; //! \deprecated // virtual bool GetIndicesCell(const double coords[3], size_t indices[3]) const { CoordType c3 = {0.0, 0.0, 0.0}; DimsType i3 = {0, 0, 0}; CopyToArr3(coords, GetGeometryDim(), c3); bool status = GetIndicesCell(c3, i3); CopyFromArr3(i3, indices); return (status); } //! \deprecated // virtual bool GetIndicesCell(const std::vector &coords, std::vector &indices) const { CoordType c3 = {0.0, 0.0, 0.0}; DimsType i3 = {0, 0, 0}; CopyToArr3(coords, c3); bool status = GetIndicesCell(c3, i3); CopyFromArr3(i3, indices); return (status); } //! Return the min and max data value //! //! This method returns the values of grid points with min and max values, //! respectively. //! //! For dataless grids the missing value is returned. //! //! \param[out] range[2] A two-element array containing the mininum and //! maximum values, in that order //! virtual void GetRange(float range[2]) const; virtual void GetRange(const DimsType &min, const DimsType &max, float range[2]) const; //! \deprecated // virtual void GetRange(std::vector min, std::vector max, float range[2]) const { DimsType min3 = {0, 0, 0}; DimsType max3 = {0, 0, 0}; CopyToArr3(min, min3); CopyToArr3(max, max3); GetRange(min3, max3, range); } //! Return true if the specified point lies inside the grid //! //! This method can be used to determine if a point expressed in //! user coordinates reside inside or outside the grid //! //! \param[in] coords User coordinates of point in space //! //! \retval bool True if point is inside the grid //! virtual bool InsideGrid(const CoordType &coords) const = 0; //! \deprecated // virtual bool InsideGrid(const double coords[3]) const { CoordType c3 = {0.0, 0.0, 0.0}; CopyToArr3(coords, GetGeometryDim(), c3); return (InsideGrid(c3)); } //! \deprecated // virtual bool InsideGrid(const std::vector &coords) const { CoordType c3 = {0.0, 0.0, 0.0}; CopyToArr3(coords, c3); return (InsideGrid(c3)); } //! Get the indices of the nodes that define a cell //! //! This method returns a vector of index vectors. Each index vector //! contains the indices for a node that defines the given cell ID //! \p indices. //! //! For 2D cells the node IDs are returned in counter-clockwise order. //! For 3D cells the ordering is dependent on the shape of the node. TBD. //! //! \param[in] cindices An array of size Grid::GetDimensions.size() specifying //! the index of the cell to query. //! \param[out] nodes An array of size //! Grid::GetMaxVertexPerCell() x Grid::GetDimensions.size() that will contain //! the concatenated list of node indices on return. //! \param[out] n The number of node indices returned in \p nodes, an integer //! in the range (0..Grid::GetMaxVertexPerCell()). //! //! virtual bool GetCellNodes(const DimsType &cindices, std::vector &nodes) const = 0; //! \deprecated // virtual bool GetCellNodes(const size_t cindices[], std::vector &nodes) const { DimsType i3 = {0, 0, 0}; CopyToArr3(cindices, GetCellDimensions().size(), i3); return (GetCellNodes(i3, nodes)); } //! Get the IDs (indices) of all of the cells that border a cell //! //! This method returns a vector of index vectors. Each index vector //! contains the indices of a cell that borders the cell given by //! \p indices. If a //! cell edge is a boundary edge, having no neighbors, the associated //! index vector for that border will be empty. //! The cell IDs are returned in counter-clockwise order //! //! \param[in] cindices An ordered vector of multi-dimensional cell //! indices. //! \param[out] cells A vector of index vectors. Each index vector //! has size given by GetDimensions.size() //! virtual bool GetCellNeighbors(const DimsType &cindices, std::vector &cells) const = 0; //! Get the IDs (indices) of all of the cells that share a node //! //! This method returns a vector of index vectors. Each index vector //! contains the indices of a cell that share the node given by //! \p indices. //! The cell IDs are returned in counter-clockwise order //! //! \param[out] nodes A vector of index vectors . Each index vector //! has size given by GetDimensions.size() //! virtual bool GetNodeCells(const DimsType &indices, std::vector &cells) const = 0; //! Return the maximum number of vertices per cell face //! virtual size_t GetMaxVertexPerFace() const = 0; //! Return the maximum number of vertices per cell //! virtual size_t GetMaxVertexPerCell() const = 0; //! Clamp periodic coordinates and ensure valid coordinate vector dimension //! //! This method ensures that periodic coordinates are within the bounding //! box of the grid and that the coordinate vector dimension does not //! exceed the number of allowable coordinates as returned by //! GetGeometryDim(). //! //! \param[in] coords A coordinate vector //! \param[out] cCoords The clamped coordintes \p coords //! \sa GetGeometryDim() // virtual void ClampCoord(const CoordType &coords, CoordType &cCoords) const = 0; //! \deprecated // virtual void ClampCoord(const double coords[3], double cCoords[3]) const { CoordType c3 = {coords[0], coords[1], coords[2]}; CoordType cC3; ClampCoord(c3, cC3); cCoords[0] = cC3[0]; cCoords[1] = cC3[1]; cCoords[2] = cC3[2]; } //! Clamp grid array indices //! //! This method ensures that grid indices are not out of bounds, clamping //! any elements of \p indices that exceeds or equals the corresponding element of //! GetNodeDimensions() to that value minus 1. //! //! \param[in] indices An array index vector //! \param[out] cindices An array index vector, clamped as described above //! //! \sa GetNodeDimensions() // virtual void ClampIndex(const DimsType &indices, DimsType &cIndices) const { ClampIndex(GetNodeDimensions(), indices, cIndices); } //! Clamp grid cell indices //! //! Same as ClampIndex() accept that indices are clamped to GetCellDimensions() //! //! \sa ClampIndex() // virtual void ClampCellIndex(const DimsType &indices, DimsType &cIndices) const { ClampIndex(GetCellDimensions(), indices, cIndices); } //! Set periodic boundaries //! //! This method changes the periodicity of boundaries set //! by the class constructor //! //! \param[in] periodic A boolean vector of size given by //! GetGeometryDim() indicating //! which coordinate axes are periodic. // virtual void SetPeriodic(const std::vector &periodic) { _periodic.clear(); int i = 0; for (; i < periodic.size() && i < GetGeometryDim(); i++) { _periodic.push_back(periodic[i]); } for (; i < GetGeometryDim(); i++) { _periodic.push_back(false); } } //! Check for periodic boundaries //! // virtual const std::vector &GetPeriodic() const { return (_periodic); } //! Get topological dimension of the mesh //! //! Return the number of topological dimensions for the mesh cells. Valid //! values are in the range 0..3, with, for example, 0 corresponding //! to points; 1 to lines; 2 to triangles, quadrilaterals, etc.; and //! 3 to hexahedron, tetrahedron, etc. //! //! \sa GetGeometryDim() // virtual size_t GetTopologyDim() const { return (_topologyDimension); } //! Get the linear offset to the node IDs //! //! Return the smallest node ID. The default is zero // virtual long GetNodeOffset() const { return (_nodeIDOffset); } virtual void SetNodeOffset(long offset) { _nodeIDOffset = offset; } //! Get the linear offset to the cell IDs //! //! Return the smallest Cell ID. The default is zero // virtual long GetCellOffset() const { return (_cellIDOffset); } virtual void SetCellOffset(long offset) { _cellIDOffset = offset; } //! Return the absolute minimum grid coordinate //! //! This method returns the absolute minimum grid coordinate. If //! the Grid contains a subregion extracted from a larger mesh this //! absolute minimum grid coordinate gives the offset of the first //! gridpoint in this grid relative to the larger mesh. //! //! \note The value of returned is not used within the Grid class //! and any value can be stored here using SetMinAbs(). //! virtual DimsType GetMinAbs() const { return (_minAbs); } //! Set the absolute minimum grid coordinate //! //! \param[in] minAbs Must have same dimensionality as constructors \p dims //! parameter. Otherwise may contain any value, but is intended to contain //! the offset to the first grid point in the mesh. The default is the //! zero vector // virtual void SetMinAbs(const DimsType &minAbs) { _minAbs = minAbs; } //! Test whether a point is contained in a bounding rectangle //! //! This static method checks to see if a 2D point \p pt is contained //! in the smallest rectangle that bounds the list of 2D points (vertices) //! given by \p verts. If \p pt is inside or on the boundary of the bounding //! rectangle true is returned, otherwise false //! //! \param[in] pt A two-element array of point coordinates //! \param[in] verts An array of dimensions \p n * 2 containing //! a list of \p points. //! \param[in] n The number of 2D points in \p verts //! //! \retval status Returns true if \pt is inside or on the bounding rectangle //! of \p verts. False otherwise. // static bool PointInsideBoundingRectangle(const double pt[], const double verts[], int n) { VAssert(n > 2); double left = verts[0]; double right = verts[0]; double top = verts[1]; double bottom = verts[1]; for (int i = 1; i < n; i++) { if (verts[i * 2 + 0] < left) left = verts[i * 2 + 0]; if (verts[i * 2 + 0] > right) right = verts[i * 2 + 0]; if (verts[i * 2 + 1] < top) top = verts[i * 2 + 1]; if (verts[i * 2 + 1] > bottom) bottom = verts[i * 2 + 1]; } return ((left <= pt[0]) && (right >= pt[0]) && (top <= pt[1]) && (bottom >= pt[1])); } VDF_API friend std::ostream &operator<<(std::ostream &o, const Grid &g); ///////////////////////////////////////////////////////////////////////////// // // Iterators // ///////////////////////////////////////////////////////////////////////////// //! Inside a box functor //! //! operator() returns true if point pt is on or inside the axis-aligned //! box defined by min and max // class InsideBox { public: InsideBox(const CoordType &min, const CoordType &max) : _min(min), _max(max) {} InsideBox() {} bool operator()(const CoordType &pt) const { if (_min == _max) return (true); for (int i = 0; i < _min.size() && i < pt.size(); i++) { if (pt[i] < _min[i] || pt[i] > _max[i]) return (false); } return (true); } bool operator()(const double pt[]) const { if (_min == _max) return (true); for (int i = 0; i < _min.size(); i++) { if (pt[i] < _min[i] || pt[i] > _max[i]) return (false); } return (true); } bool Enabled() const { return (_min != _max); } private: CoordType _min; CoordType _max; }; // // Define polymorphic iterator that can be used with any // class derived from this class // // // Interface for iterator specializations // template class AbstractIterator { public: virtual ~AbstractIterator() {} virtual void next() = 0; virtual void next(const long &offset) = 0; virtual T & deref() const = 0; virtual const void * address() const = 0; virtual bool equal(const void *other) const = 0; virtual std::unique_ptr clone() const = 0; }; // Overloaded operators that will act on spealizations of // AbstractIterator // template class PolyIterator { public: PolyIterator(std::unique_ptr> it) : _impl(std::move(it)) {} PolyIterator(PolyIterator const &rhs) : _impl(rhs._impl->clone()) {} PolyIterator &operator=(PolyIterator const &rhs) { _impl = rhs._impl->clone(); return *this; } // PolyIterator has a unique_ptr member so we must provide // std::move constructors // PolyIterator(PolyIterator &&rhs) { _impl = std::move(rhs._impl); } PolyIterator &operator=(PolyIterator &&rhs) { if (this != &rhs) { _impl = std::move(rhs._impl); } return (*this); } PolyIterator() : _impl(nullptr) {} PolyIterator &operator++() { // ++prefix _impl->next(); return *this; }; PolyIterator operator++(int) { // postfix++ PolyIterator temp(*this); ++(*this); return (temp); }; PolyIterator &operator+=(const long &offset) { _impl->next(offset); return (*this); }; PolyIterator operator+(const long &offset) const { PolyIterator temp(*this); temp += offset; return (temp); } const T &operator*() const { return _impl->deref(); } bool operator==(const PolyIterator &rhs) const { return (_impl->equal(rhs._impl->address())); } bool operator!=(const PolyIterator &rhs) const { return (!(*this == rhs)); } private: std::unique_ptr> _impl; }; //! Coordinate iterator. Iterates over grid node/cell coordinates //! //! The ConstCoordItr can be dererenced to return a grid node or //! cell's coordinates. The determination, node or cell, is determined //! by the location of the sampled data within the grid (node, face, //! cell, etc) //! //! N.B. Current only works with node coordinates //! // typedef const CoordType ConstCoordType; typedef Grid::PolyIterator ConstCoordItr; typedef Grid::AbstractIterator ConstCoordItrAbstract; //! Return constant grid coordinate iterator // virtual ConstCoordItr ConstCoordBegin() const = 0; virtual ConstCoordItr ConstCoordEnd() const = 0; //! Node index iterator. Iterates over grid node indices //! //! The ConstNodeIterator is dereferenced to give the index of //! a node within the grid //! typedef const DimsType ConstIndexType; typedef Grid::PolyIterator ConstNodeIterator; typedef Grid::AbstractIterator ConstNodeIteratorAbstract; //! Cell index iterator. Iterates over grid cell indices // typedef Grid::PolyIterator ConstCellIterator; typedef Grid::AbstractIterator ConstCellIteratorAbstract; ///////////////////////////////////////////////////////////////////////////// // // Iterators // ///////////////////////////////////////////////////////////////////////////// // // Node index iterator. Iterates over node indices // class ConstNodeIteratorSG : public Grid::ConstNodeIteratorAbstract { public: ConstNodeIteratorSG(const Grid *g, bool begin); ConstNodeIteratorSG(const ConstNodeIteratorSG &rhs); ConstNodeIteratorSG(); virtual ~ConstNodeIteratorSG() {} virtual void next(); virtual void next(const long &offset); virtual ConstIndexType &deref() const { return (_index); } virtual const void * address() const { return this; }; virtual bool equal(const void *rhs) const { const ConstNodeIteratorSG *itrptr = static_cast(rhs); return (_index == itrptr->_index); } virtual std::unique_ptr clone() const { return std::unique_ptr(new ConstNodeIteratorSG(*this)); }; protected: DimsType _dims; DimsType _index; DimsType _lastIndex; }; class ConstNodeIteratorBoxSG : public ConstNodeIteratorSG { public: ConstNodeIteratorBoxSG(const Grid *g, const CoordType &minu, const CoordType &maxu); ConstNodeIteratorBoxSG(const ConstNodeIteratorBoxSG &rhs); ConstNodeIteratorBoxSG(); virtual ~ConstNodeIteratorBoxSG() {} virtual void next(); virtual void next(const long &offset); virtual std::unique_ptr clone() const { return std::unique_ptr(new ConstNodeIteratorBoxSG(*this)); }; private: InsideBox _pred; ConstCoordItr _coordItr; }; //! Return constant grid node coordinate iterator //! //! If \p minu and \p maxu are specified the iterator is constrained to //! operation within the axis-aligned box defined by \p minu and \p maxu. //! //! \param[in] minu Minimum box coordinate. //! \param[in] maxu Maximum box coordinate. //! virtual ConstNodeIterator ConstNodeBegin() const { return ConstNodeIterator(std::unique_ptr(new ConstNodeIteratorSG(this, true))); } virtual ConstNodeIterator ConstNodeBegin(const CoordType &minu, const CoordType &maxu) const { return ConstNodeIterator(std::unique_ptr(new ConstNodeIteratorBoxSG(this, minu, maxu))); } virtual ConstNodeIterator ConstNodeBegin(const std::vector &minu, const std::vector &maxu) const { CoordType minuCT, maxuCT; CopyToArr3(minu, minuCT); CopyToArr3(maxu, maxuCT); return ConstNodeBegin(minuCT, maxuCT); } virtual ConstNodeIterator ConstNodeEnd() const { return ConstNodeIterator(std::unique_ptr(new ConstNodeIteratorSG(this, false))); } // // Cell index iterator. Iterates over cell indices // class ConstCellIteratorSG : public Grid::ConstCellIteratorAbstract { public: ConstCellIteratorSG(const Grid *g, bool begin); ConstCellIteratorSG(const ConstCellIteratorSG &rhs); ConstCellIteratorSG(); virtual ~ConstCellIteratorSG() {} virtual void next(); virtual void next(const long &offset); virtual ConstIndexType &deref() const { return (_index); } virtual const void * address() const { return this; }; virtual bool equal(const void *rhs) const { const ConstCellIteratorSG *itrptr = static_cast(rhs); return (_index == itrptr->_index); } virtual std::unique_ptr clone() const { return std::unique_ptr(new ConstCellIteratorSG(*this)); }; protected: DimsType _dims; DimsType _index; DimsType _lastIndex; }; class ConstCellIteratorBoxSG : public ConstCellIteratorSG { public: ConstCellIteratorBoxSG(const Grid *g, const CoordType &minu, const CoordType &maxu); ConstCellIteratorBoxSG(const ConstCellIteratorBoxSG &rhs); ConstCellIteratorBoxSG(); virtual ~ConstCellIteratorBoxSG() {} virtual void next(); virtual void next(const long &offset); virtual std::unique_ptr clone() const { return std::unique_ptr(new ConstCellIteratorBoxSG(*this)); }; private: InsideBox _pred; const Grid *_g; bool _cellInsideBox(const size_t cindices[]) const; }; //! Return constant grid cell coordinate iterator //! //! If \p minu and \p maxu are specified the iterator is constrained to //! operation within the axis-aligned box defined by \p minu and \p maxu. //! //! \param[in] minu Minimum box coordinate. //! \param[in] maxu Maximum box coordinate. //! virtual ConstCellIterator ConstCellBegin() const { return ConstCellIterator(std::unique_ptr(new ConstCellIteratorSG(this, true))); } virtual ConstCellIterator ConstCellBegin(const CoordType &minu, const CoordType &maxu) const { return ConstCellIterator(std::unique_ptr(new ConstCellIteratorBoxSG(this, minu, maxu))); } virtual ConstCellIterator ConstCellBegin(const std::vector &minu, const std::vector &maxu) const { CoordType minuCT, maxuCT; CopyToArr3(minu, minuCT); CopyToArr3(maxu, maxuCT); return ConstCellBegin(minuCT, maxuCT); } virtual ConstCellIterator ConstCellEnd() const { return ConstCellIterator(std::unique_ptr(new ConstCellIteratorSG(this, false))); } //! A forward iterator for accessing the data elements of the //! structured grid. //! //! This class provides a C++ STL style Forward Iterator for //! accessing grid elements passed to the constructor. All Forward //! Iterator expressions are supported. In addition, the following //! Random Access Iterator expressions are supported: //! //! \li \c a + n //! \li \c n + a //! //! where \i a are objects of type ForwardIterator, and \i n is an int. //! //! N.B. this class does NOT need to be a template. It's a historical //! implementation. // template class VDF_API ForwardIterator { public: ForwardIterator(T *rg, bool begin = true, const CoordType &minu = {0.0, 0.0, 0.0}, const CoordType &maxu = {0.0, 0.0, 0.0}); ForwardIterator(); ForwardIterator(const ForwardIterator &) = default; ForwardIterator(ForwardIterator &&rhs); ~ForwardIterator() {} float &operator*() { return (*_itr); } ForwardIterator &operator++(); // ++prefix ForwardIterator operator++(int); // postfix++ ForwardIterator &operator+=(const long int &offset); ForwardIterator operator+(const long int &offset) const; ForwardIterator &operator=(ForwardIterator rhs); ForwardIterator &operator=(ForwardIterator &rhs) = delete; bool operator==(const ForwardIterator &rhs) const { return (_index == rhs._index); } bool operator!=(const ForwardIterator &rhs) { return (_index != rhs._index); } const ConstCoordItr &GetCoordItr() { return (_coordItr); } friend void swap(Grid::ForwardIterator &a, Grid::ForwardIterator &b) { std::swap(a._blks, b._blks); std::swap(a._dims3d, b._dims3d); std::swap(a._bdims3d, b._bdims3d); std::swap(a._bs3d, b._bs3d); std::swap(a._blocksize, b._blocksize); std::swap(a._coordItr, b._coordItr); std::swap(a._index, b._index); std::swap(a._lastIndex, b._lastIndex); std::swap(a._xb, b._xb); std::swap(a._itr, b._itr); std::swap(a._pred, b._pred); } private: std::vector _blks; DimsType _dims3d; DimsType _bdims3d; DimsType _bs3d; size_t _blocksize; ConstCoordItr _coordItr; DimsType _index; // current index into grid DimsType _lastIndex; // Last valid index size_t _xb; // x index within a block float * _itr; InsideBox _pred; }; typedef Grid::ForwardIterator Iterator; typedef Grid::ForwardIterator ConstIterator; //! Construct a begin iterator that will iterate through elements //! inside or on the box defined by \p minu and \p maxu // Iterator begin(const CoordType &minu, const CoordType &maxu) { return (Iterator(this, true, minu, maxu)); } Iterator begin(const std::vector &minu, const std::vector &maxu) { CoordType minuCT, maxuCT; CopyToArr3(minu, minuCT); CopyToArr3(maxu, maxuCT); return begin(minuCT, maxuCT); } Iterator begin() { return (Iterator(this, true)); } Iterator end() { return (Iterator(this, false)); } ConstIterator cbegin(const CoordType &minu, const CoordType &maxu) const { return (ConstIterator(this, true, minu, maxu)); } ConstIterator cbegin(const std::vector &minu, const std::vector &maxu) { CoordType minuCT, maxuCT; CopyToArr3(minu, minuCT); CopyToArr3(maxu, maxuCT); return cbegin(minuCT, maxuCT); } ConstIterator cbegin() const { return (ConstIterator(this, true)); } ConstIterator cend() const { return (ConstIterator(this, false)); } template static void CopyToArr3(const std::vector &src, std::array &dst) { for (int i = 0; i < src.size() && i < dst.size(); i++) { dst[i] = src[i]; } } template static void CopyToArr3(const T *src, size_t n, std::array &dst) { for (int i = 0; i < n && i < dst.size(); i++) { dst[i] = src[i]; } } template static void CopyFromArr3(const std::array &src, std::vector &dst) { dst.resize(src.size()); for (int i = 0; i < src.size() && i < dst.size(); i++) { dst[i] = src[i]; } } template static void CopyFromArr3(const std::array &src, T *dst) { for (int i = 0; i < src.size(); i++) { dst[i] = src[i]; } } protected: virtual float GetValueNearestNeighbor(const CoordType &coords) const = 0; virtual float GetValueLinear(const CoordType &coords) const = 0; virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const = 0; virtual float *GetValuePtrAtIndex(const std::vector &blks, const DimsType &indices) const; // Deprecated virtual void ClampIndex(const std::vector &dims, const DimsType indices, DimsType &cIndices) const { cIndices = {0, 0, 0}; for (int i = 0; i < dims.size(); i++) { cIndices[i] = indices[i]; if (cIndices[i] >= dims[i]) { cIndices[i] = dims[i] - 1; } } } virtual void ClampIndex(const DimsType &dims, const DimsType indices, DimsType &cIndices) const { cIndices = {0, 0, 0}; for (int i = 0; i < dims.size(); i++) { cIndices[i] = indices[i]; if (cIndices[i] >= dims[i]) { assert(dims[i] > 0); cIndices[i] = dims[i] - 1; } } } float BilinearInterpolate(size_t i, size_t j, size_t k, const double xwgt, const double ywgt) const; float TrilinearInterpolate(size_t i, size_t j, size_t k, const double xwgt, const double ywgt, const double zwgt) const; private: DimsType _dims; // dimensions of grid arrays DimsType _bs = {{1, 1, 1}}; // dimensions of each block DimsType _bdims = {{1, 1, 1}}; // dimensions (specified in blocks) of ROI std::vector _bsDeprecated; // legacy API std::vector _bdimsDeprecated; // legacy API std::vector _blks; std::vector _periodic; // periodicity of boundaries DimsType _minAbs; // Offset to start of grid size_t _topologyDimension = 0; float _missingValue = std::numeric_limits::infinity(); bool _hasMissing = false; int _interpolationOrder = 1; // Order of interpolation long _nodeIDOffset = 0; long _cellIDOffset = 0; mutable CoordType _minuCache = {{std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()}}; mutable CoordType _maxuCache = {{std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()}}; void _grid(const DimsType &dims, const DimsType &bs, const std::vector &blks, size_t topology_dimension); }; template void Grid::CopyToArr3(const std::vector &src, std::array &dst); }; // namespace VAPoR #endif ================================================ FILE: include/vapor/GridHelper.h ================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef GRIDMGR_H #define GRIDMGR_H namespace VAPoR { class UnstructuredGrid3D; class VDF_API GridHelper : public Wasp::MyBase { public: GridHelper(size_t max_size = 10) : _qtrCache(max_size) {} ~GridHelper(); string GetGridType(const DC::Mesh &m, const std::vector &cvarsinfo, const std::vector> &cdimnames) const; bool IsUnstructured(std::string gridType) const; bool IsStructured(std::string gridType) const; // var: variable info // roi_dims: spatial dimensions of ROI // dims: spatial dimensions of full variable domain in voxels // blkvec: data blocks, and coordinate blocks // bsvec: data block dimensions, and coordinate block dimensions // bminvec: ROI offsets in blocks, full domain, data and coordinates // bmaxvec: ROI offsets in blocks, full domain, data and coordinates // StructuredGrid *MakeGridStructured(string gridType, size_t ts, int level, int lod, const DC::DataVar &var, const std::vector &cvarsinfo, const DimsType &roi_dims, const DimsType &dims, const std::vector &blkvec, const std::vector &bsvec, const std::vector &bminvec, const std::vector &bmaxvec); UnstructuredGrid *MakeGridUnstructured(string gridType, size_t ts, int level, int lod, const DC::DataVar &var, const std::vector &cvarsinfo, const DimsType &roi_dims, const DimsType &dims, const std::vector &blkvec, const std::vector &bsvec, const std::vector &bminvec, const std::vector &bmaxvec, const std::vector &conn_blkvec, const std::vector &conn_bsvec, const std::vector &conn_bminvec, const std::vector &conn_bmaxvec, const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace, size_t maxFacePerVertex, long vertexOffset, long faceOffset); private: template class lru_cache { public: typedef typename std::pair key_value_pair_t; typedef typename std::list::iterator list_iterator_t; lru_cache() : _max_size(10) {} lru_cache(size_t max_size) : _max_size(max_size) {} value_t put(const key_t &key, value_t value) { value_t rvalue = NULL; auto it = _cache_items_map.find(key); _cache_items_list.push_front(key_value_pair_t(key, value)); if (it != _cache_items_map.end()) { rvalue = it->second->second; _cache_items_list.erase(it->second); _cache_items_map.erase(it); } _cache_items_map[key] = _cache_items_list.begin(); if (_cache_items_map.size() > _max_size) { auto last = _cache_items_list.end(); last--; rvalue = last->second; _cache_items_map.erase(last->first); _cache_items_list.pop_back(); } return (rvalue); } value_t get(const key_t &key) { auto it = _cache_items_map.find(key); if (it == _cache_items_map.end()) return (NULL); _cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second); return it->second->second; } value_t remove_lru() { if (!_cache_items_map.size()) return (NULL); auto last = _cache_items_list.end(); last--; value_t rvalue = last->second; last->second = nullptr; // necessary for delete? _cache_items_map.erase(last->first); _cache_items_list.pop_back(); return (rvalue); } bool exists(const key_t &key) const; size_t size() const { return _cache_items_map.size(); } private: std::list _cache_items_list; std::unordered_map _cache_items_map; size_t _max_size; }; lru_cache> _qtrCache; RegularGrid *_make_grid_regular(const DimsType &dims, const std::vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax ) const; StretchedGrid *_make_grid_stretched(const DimsType &dims, const std::vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax) const; LayeredGrid *_make_grid_layered(const DimsType &dims, const std::vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax) const; CurvilinearGrid *_make_grid_curvilinear(size_t ts, int level, int lod, const std::vector &cvarsinfo, const DimsType &dims, const std::vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax); UnstructuredGrid2D *_make_grid_unstructured2d(size_t ts, int level, int lod, const DC::DataVar &var, const std::vector &cvarsinfo, const DimsType &dims, const std::vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, const std::vector &conn_blkvec, const DimsType &conn_bs, const DimsType &conn_bmin, const DimsType &conn_bmax, const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace, size_t maxFacePerVertex, long vertexOffset, long faceOffset); UnstructuredGridLayered *_make_grid_unstructured_layered(size_t ts, int level, int lod, const DC::DataVar &var, const vector &cvarsinfo, const DimsType &dims, const vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, const vector &conn_blkvec, const DimsType &conn_bs, const DimsType &conn_bmin, const DimsType &conn_bmax, const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace, size_t maxFacePerVertex, long vertexOffset, long faceOffset); UnstructuredGrid3D *_make_grid_unstructured_3d(size_t ts, int level, int lod, const DC::DataVar &var, const vector &cvarsinfo, const DimsType &dims, const vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, const vector &conn_blkvec, const DimsType &conn_bs, const DimsType &conn_bmin, const DimsType &conn_bmax, const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace, size_t maxFacePerVertex, long vertexOffset, long faceOffset); void _makeGridHelper(const DC::DataVar &var, const DimsType &roi_dims, const DimsType &dims, Grid *g) const; string _getQuadTreeRectangleKey(size_t ts, int level, int lod, const vector &cvarsinfo, const DimsType &bmin, const DimsType &bmax) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/HelloParams.h ================================================ #ifndef HELLOPARAMS_H #define HELLOPARAMS_H #include namespace VAPoR { //! \class HelloParams //! \brief Class that supports drawing a line connecting two points. //! \author Alan Norton //! \version 3.0 //! \date June 2015 class PARAMS_API HelloParams : public RenderParams { public: HelloParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave); HelloParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node); virtual ~HelloParams(); //! Determine line thickness in voxels //! \retval double line thickness double GetLineThickness() { return (GetValueDouble(m_lineThicknessTag, 1.0)); } //! Set the line thickness //! \param[in] double thickness //! \retval int 0 if success void SetLineThickness(double val) { SetValueDouble(m_lineThicknessTag, "Set line thickness", val); } //! Obtain the first endpoint in user coordinates. const vector GetPoint1() { vector defaultv(3, 0.0); return GetValueDoubleVec(m_point1Tag, defaultv); } //! Obtain the second endpoint in user coordinates. const vector GetPoint2() { vector defaultv(3, 1.0); return GetValueDoubleVec(m_point2Tag, defaultv); } //! Set the first endpoint void SetPoint1(vector pt) { SetValueDoubleVec(m_point1Tag, "Set First Endpoint", pt); } //! Set the second endpoint void SetPoint2(vector pt) { SetValueDoubleVec(m_point2Tag, "Set Second Endpoint", pt); } // Get static string identifier for this params class // static string GetClassType() { return ("HelloParams"); } virtual size_t GetRenderDim() const override { return (0); } //! \copydoc RenderParams::GetActualColorMapVariableName() virtual string GetActualColorMapVariableName() const override { return GetColorMapVariableName(); } private: static const string m_lineThicknessTag; static const string m_point1Tag; static const string m_point2Tag; void _init(); }; // End of Class HelloParams }; // namespace VAPoR #endif // HELLOPARAMS_H ================================================ FILE: include/vapor/HelloRenderer.h ================================================ //-- HelloRenderer.h ---------------------------------------------------------- // // Copyright (C) 2011 // University Corporation for Atmospheric Research // All Rights Reserved // //---------------------------------------------------------------------------- // // File: HelloRenderer.h // // Author: Alan Norton // // // Description: Definition of HelloRenderer class // // // //---------------------------------------------------------------------------- #ifndef HELLORENDERER_H #define HELLORENDERER_H #include #include #include namespace VAPoR { //! \class HelloRenderer //! \brief Class that draws a line as specified by HelloParams //! \author Alan Norton //! \version 3.0 //! \date June 2015 class RENDER_API HelloRenderer : public Renderer { public: HelloRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr); ~HelloRenderer(); // Get static string identifier for this Render class // static string GetClassType() { return ("Hello"); } protected: //! \copydoc Renderer::_initializeGL() virtual int _initializeGL(); //! \copydoc Renderer::_paintGL() virtual int _paintGL(bool fast); private: void _clearCache() {} }; }; // namespace VAPoR #endif // HELLORENDERER_H ================================================ FILE: include/vapor/Histo.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: Histo.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: November 2004 // // Description: Definition of Histo class: // it contains a histogram derived from volume data. // Used by TFEditor to draw histogram behind transfer function opacity // #ifndef HISTO_H #define HISTO_H #include #include #include #include #include #include #include class RENDER_API Histo { public: Histo(int numberBins, float mnData, float mxData, string var, int ts); Histo(int numberBins); Histo(); ~Histo(); void reset(int newNumBins = -1); void reset(int newNumBins, float mnData, float mxData); void addToBin(float val); void setBins(const vector &bins); int getMaxBinSize(); int getMaxBinSizeBetweenIndices(const int start, const int end) const; int getNumBins() const; int getBinSize(int index) const; int getBinSize(int index, int stride) const; float getNormalizedBinSize(int bin) const; float getNormalizedBinSizeForValue(float v) const; float getNormalizedBinSizeForNormalizedValue(float v) const; int getBinIndexForValue(float v); float getMinMapData() { return _minMapData; } float getMaxMapData() { return _maxMapData; } float getRange() { return _range; } int getTimestepOfUpdate() { return _timestepOfUpdate; } string getVarnameOfUpdate() { return _varnameOfUpdate; } int Populate(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp); bool NeedsUpdate(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp); int PopulateIfNeeded(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp); static vector GetDataSamples(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp); private: unsigned int *_binArray = nullptr; unsigned int *_below = nullptr; unsigned int *_above = nullptr; int _nBinsBelow = 0, _nBinsAbove = 0; long _numSamplesBelow, _numSamplesAbove; int _numBins = 0; float _minMapData, _maxMapData, _range; float _minData, _maxData; long _maxBinSize = -1; int _refLevel = INT_MIN, _lod = INT_MIN; std::vector _minExts, _maxExts; bool _populated = false; int _timestepOfUpdate; string _varnameOfUpdate; bool autoSetProperties = false; static vector getDataSamplesIterating(const VAPoR::Grid *grid, const int stride); static vector getDataSamplesSampling(const VAPoR::Grid *grid, const vector &minExts, const vector &maxExts); void populateIteratingHistogram(const VAPoR::Grid *grid, const int stride); void populateSamplingHistogram(const VAPoR::Grid *grid, const vector &minExts, const vector &maxExts); static int calculateStride(const std::string &varName, VAPoR::DataMgr *dm, const VAPoR::RenderParams *rp); static bool shouldUseSampling(const std::string &varName, VAPoR::DataMgr *dm, const VAPoR::RenderParams *rp); void setProperties(float mnData, float mxData, string var, int ts); void calculateMaxBinSize(); void _getDataRange(const std::string &varName, VAPoR::DataMgr *d, VAPoR::RenderParams *r, float *min, float *max) const; }; #endif // HISTO_H ================================================ FILE: include/vapor/IResourceManager.h ================================================ #pragma once #include #include #include "vapor/VAssert.h" #include "vapor/MyBase.h" #ifdef WIN32 #ifdef RENDER_EXPORTS #define IRESOURCEMANAGER_IMPLEMENT #endif #else #define IRESOURCEMANAGER_IMPLEMENT #endif namespace VAPoR { template class RENDER_API IResourceManager : public Wasp::MyBase { protected: std::map _map; T *GetResource(const K &key); public: virtual ~IResourceManager(); bool HasResource(const K &key) const; bool HasResource(const T *resource) const; virtual int LoadResourceByKey(const K &key) = 0; bool AddResource(const K &key, T *resource); void DeleteResource(const K &key); }; #ifdef IRESOURCEMANAGER_IMPLEMENT template IResourceManager::~IResourceManager() { for (auto it = _map.begin(); it != _map.end(); ++it) delete it->second; } template T *IResourceManager::GetResource(const K &key) { auto it = _map.find(key); if (it == _map.end()) { if (LoadResourceByKey(key) < 0) { SetErrMsg("Resource does not exist and unable to load by name"); return nullptr; } it = _map.find(key); } return it->second; } template bool IResourceManager::HasResource(const K &key) const { return _map.find(key) != _map.end(); } template bool IResourceManager::HasResource(const T *resource) const { for (auto it = _map.begin(); it != _map.end(); ++it) if (it->second == resource) return true; return false; } template bool IResourceManager::AddResource(const K &key, T *resource) { if (HasResource(key) || HasResource(resource)) { VAssert(!"Resource already exists"); return false; } _map.insert(std::pair(key, resource)); return true; } template void IResourceManager::DeleteResource(const K &key) { VAssert(HasResource(key)); delete _map[key]; _map.erase(key); } #endif } // namespace VAPoR ================================================ FILE: include/vapor/ImageParams.h ================================================ #ifndef IMAGEPARAMS_H #define IMAGEPARAMS_H #include #include #include namespace VAPoR { class PARAMS_API ImageParams : public RenderParams { public: ImageParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave); ImageParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, XmlNode *xmlNode); virtual ~ImageParams(); virtual int Initialize() override; static std::string GetClassType() { return ("ImageParams"); } //! \copydoc RenderParams::GetRenderDim() // virtual size_t GetRenderDim() const override { return (2); } //! Set file path for the image to be read and displayed. //! \param[in] string - Path to image file void SetImagePath(std::string file) { BeginGroup("Set image path"); SetValueString(_fileNameTag, "Set image file path", file); if (Wasp::TMSUtils::IsTMSFile(file)) { int numTMSLODs = Wasp::TMSUtils::GetNumTMSLODs(file); _setNumTMSLODs(numTMSLODs); } EndGroup(); } //! Set image file path //! \retval string - Path to image file std::string GetImagePath() const; //! Inquire whether the currently selected image is georeferenced //! Valid values: 0 = do not use georeference information, 1 = use georeference information //! \retval bool - State indicating whether current image is georeferenced bool GetIsGeoRef() const { return (GetValueLong(_isGeoRefTag, (long)true)); } //! If the raster image contained in the path returned by GetImagePath() has georeference information (e.g. the file is a GeoTIFF) this boolean determines whether or not the georeference information is honored //! Valid values: 0 = do not use georeference information, 1 = use georeference information //! \param[in] bool - State indicating whether current image is georeferenced void SetIsGeoRef(bool val) { SetValueLong(_isGeoRefTag, "Geo-reference the image", (long)val); } //! Get whether transparency is being ignored regarding the currently selected image //! Valid values: 0 = transparency is being honored, 1 = transparency is being ignored //! \retval bool - State whether transparency is being ignored bool GetIgnoreTransparency() const { return (0 != GetValueLong(_ignoreTransparencyTag, (long)false)); } //! Set whether transparency is being ignored regarding the currently selected image //! Valid values: 0 = transparency is being honored, 1 = transparency is being ignored //! \param[in] bool - State whether transparency is being ignored void SetIgnoreTransparency(bool val) { SetValueLong(_ignoreTransparencyTag, "if transparence is ignored", (long)val); } // // Get and set opacity value // /* double GetOpacity() const { return GetValueDouble( _opacityTag, 1.0 ); } void SetOpacity( double val ) { SetValueDouble( _opacityTag, "set opacity value", val ); } */ // // Get and set orientation // int GetOrientation() const { return GetValueLong(_orientationTag, 2); } void SetOrientation(int val) { SetValueLong(_orientationTag, "set orientation value", val); } //! Get the TMS level of detail //! \retval int Currently selected TMS level of detail. Value of -1 means we are computing a default value. int GetTMSLOD() const { int value = ((int)GetValueLong(_TMSLODTag, -1)); return value; } //! Set the current TMS level of detail //! \param[in] val int val, the TMS level of detail to be applied. Value of 0 means we are computing a default value. void SetTMSLOD(int val) { SetValueLong(_TMSLODTag, "TMS level of detail", (long)val); } //! Get the number of available levels of detail in the currently selected file. //! \retval int The currently available levels of detail in the current file. int GetNumTMSLODs() const { int value = ((int)GetValueLong(_numTMSLODTag, 4)); return value; } //! \copydoc RenderParams::GetActualColorMapVariableName() virtual string GetActualColorMapVariableName() const override { return ""; } public: static const std::string _fileNameTag; static const std::string _isGeoRefTag; static const std::string _ignoreTransparencyTag; static const std::string _opacityTag; static const std::string _TMSLODTag; static const std::string _numTMSLODTag; static const std::string _orientationTag; // If it's X-Y (orientation = 2) // If it's X-Z (orientation = 1) // If it's Y-Z (orientation = 0) private: bool _initialized = false; //! Set the number of TMS levels of detail for the currently selected image //! \param[in] val int val, the number of TMS levels of detail available in the current file. void _setNumTMSLODs(int val) { SetValueLong(_numTMSLODTag, "Number of TMS levels of detail", (long)val); } }; } // namespace VAPoR #endif ================================================ FILE: include/vapor/ImageRenderer.h ================================================ #ifndef IMAGERENDERER_H #define IMAGERENDERER_H #include #include #include #include #include #include #include namespace VAPoR { class RENDER_API ImageRenderer : public TwoDRenderer { public: ImageRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr); virtual ~ImageRenderer(); static std::string GetClassType() { return ("Image"); } protected: int GetMesh(DataMgr *dataMgr, GLfloat **verts, GLfloat **normals, GLsizei &nverts, GLsizei &width, GLsizei &height, GLuint **indices, GLsizei &nindices, bool &structuredMesh); const GLvoid *GetTexture(DataMgr *dataMgr, GLsizei &width, GLsizei &height, GLint &internalFormat, GLenum &format, GLenum &type, size_t &texelSize, bool &gridAligned); private: GeoImage * _geoImage; unsigned char *_twoDTex; string _cacheImgFileName; vector _cacheTimes; vector _pcsExtentsData; double _pcsExtentsImg[4]; string _proj4StringImg; GLsizei _texWidth; GLsizei _texHeight; const int _maxResamplingResolution; size_t _cacheTimestep; int _cacheRefLevel; int _cacheLod; int _cacheTMSLOD; vector _cacheBoxExtents; size_t _cacheTimestepTex; string _cacheHgtVar; int _cacheGeoreferenced; vector _cacheBoxExtentsTex; SmartBuf _sb_verts; SmartBuf _sb_normals; SmartBuf _sb_indices; GLsizei _vertsWidth; GLsizei _vertsHeight; GLsizei _nindices; GLsizei _nverts; unsigned char *_getTexture(DataMgr *dataMgr); bool _gridStateDirty() const; void _gridStateClear(); void _gridStateSet(); bool _imageStateDirty(const vector ×) const; void _imageStateSet(const vector ×); void _imageStateClear(); bool _texStateDirty(DataMgr *dataMgr) const; void _texStateSet(DataMgr *dataMgr); void _texStateClear(); int _reinit(string path, vector times); unsigned char *_getImage(GeoImage *geoimage, size_t ts, string proj4StringData, vector pcsExtentsDataVec, double pcsExtentsImg[4], double geoCornersImg[8], string &proj4StringImg, GLsizei &width, GLsizei &height) const; int _getMeshDisplacedGeo(DataMgr *dataMgr, Grid *hgtGrid, GLsizei width, GLsizei height, double defaultZ); // Compute _verts for displayed, non-georeferenced image // int _getMeshDisplacedNoGeo(DataMgr *dataMgr, Grid *hgtGrid, GLsizei width, GLsizei height, const vector &minExt, const vector &maxExt, double defaultZ); int _getMeshDisplaced(DataMgr *dataMgr, GLsizei width, GLsizei height, const vector &minBox, const vector &maxBox, double defaultZ); int _getMeshPlane(const vector &minBox, const vector &maxBox, double defaultZ); // Get the selected horizontal ROI in PCS data coordinates // vector _getPCSExtentsData() const; // Transform verts from absolute to local coordinates // void _transformToLocal(size_t width, size_t height, const vector &scaleFac) const; void _clearCache() { _cacheHgtVar.clear(); } }; }; // namespace VAPoR #endif // TWODRENDERER_H ================================================ FILE: include/vapor/ImageWriter.h ================================================ #pragma once #include #include namespace VAPoR { class ImageWriterFactory; //! \class ImageWriter //! \ingroup Public_Render //! \brief Interface for image writers //! \author Stanislaw Jaroszynski //! class RENDER_API ImageWriter : public Wasp::MyBase { public: enum class Format { RGB }; // virtual static std::vector GetFileExtensions(); virtual int Write(const unsigned char *buffer, const unsigned int width, const unsigned int height) = 0; virtual ~ImageWriter(){}; static ImageWriter *CreateImageWriterForFile(const std::string &path); static void RegisterFactory(ImageWriterFactory *factory); protected: Format format; std::string path; bool opened; ImageWriter(const std::string &path); private: static std::vector factories; }; class ImageWriterFactory { public: const std::vector Extensions; virtual ImageWriter * Create(const std::string &path) = 0; protected: ImageWriterFactory(std::vector extensions) : Extensions(extensions) {} }; #define REGISTER_IMAGEWRITER(name) \ class name##Factory : public ImageWriterFactory { \ public: \ name##Factory() : ImageWriterFactory(name::GetFileExtensions()) { ImageWriter::RegisterFactory(this); } \ virtual ImageWriter *Create(const std::string &path) { return new name(path); } \ }; \ static name##Factory registration_##name##Factory; } // namespace VAPoR ================================================ FILE: include/vapor/ImpExp.h ================================================ // // $Id$ // #ifndef _ImpExp_h_ #define _ImpExp_h_ #include #include #include #include #include #include #ifdef WIN32 #pragma warning(disable : 4251) #endif namespace VAPoR { // //! \class ImpExp //! \brief A class for managing data set metadata //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! The ImpExp class is used to import/export state to/from a VAPoR session //! class VDF_API ImpExp : public Wasp::MyBase, public ParsedXml { public: //! Create an Import Export object //! // ImpExp(); virtual ~ImpExp(); //! Export a volume subregion description for use by another application //! //! This method exports data set state information to facilitate sharing //! with another application. In particular, the path name of the VDF file, //! a volume time step, a named volume variable, and volumetric region //! of interest are exported. The exported information may be retreive //! via the Import() method //! //! \note The region bounds are specified relative to the finest //! resolution volume //! //! \note Presently the medium of exchange is an XML file, the path to //! which is internally hardwired and based on the user's uid. //! Thus it is not possible for applications running under different uid's //! to share data. Furthermore, there exists only one XML file per uid //! on a system. This will undoubtedly change in the future. //! //! \param[in] path Path to the metadata file //! \param[in] ts Time step of exported volume //! \param[in] varname Variable name of exported volume //! \param[in] min Minimum region extents in voxel coordinates relative //! to the \b finest resolution //! \param[in] max Maximum region extents in voxel coordinates relative //! to the \b finest resolution //! \param[in] timeseg Time segment range //! \retval status Returns a non-negative integer on success //! \sa Import() // int Export(const string &path, size_t ts, const string &varname, const size_t min[3], const size_t max[3], const size_t timeseg[2]); //! Import a volume subregion description for use by another application //! //! This method imports data set state information to facilitate sharing //! with another application. In particular, the path name of the VDF file, //! a volume time step, a named volume variable, and volumetric region //! of interest are imported. The imported information is assumed to //! have been generated via the the most recent call to the Export() method. //! //! \param[out] path Path to the metadata file //! \param[out] ts Time step of exported volume //! \param[out] varname Variable name of exported volume //! \param[out] min Minimum region extents in voxel coordinates relative //! to the \b finest resolution //! \param[out] max Maximum region extents in voxel coordinates relative //! to the \b finest resolution //! \param[out] timeseg Time segment range //! \retval status Returns a non-negative integer on success //! \sa Export() // int Import(string *path, size_t *ts, string *varname, size_t min[3], size_t max[3], size_t timeseg[2]); static string GetPath(); private: int _objInitialized; // has the obj successfully been initialized? XmlNode *_rootnode; // root node of the xml tree static const string _rootTag; static const string _pathNameTag; static const string _timeStepTag; static const string _varNameTag; static const string _regionTag; static const string _timeSegmentTag; bool elementStartHandler(ExpatParseMgr *, int depth, std::string &tag, const char **attr); bool elementEndHandler(ExpatParseMgr *, int depth, std::string &); // XML Expat element handler helpers. A different handler is defined // for each possible state (depth of XML tree) from 0 to 1 // void _startElementHandler0(ExpatParseMgr *, const string &tag, const char **attrs); void _startElementHandler1(ExpatParseMgr *, const string &tag, const char **attrs); void _endElementHandler0(ExpatParseMgr *, const string &tag); void _endElementHandler1(ExpatParseMgr *, const string &tag); }; }; // namespace VAPoR #endif // _ImpExp_h_ ================================================ FILE: include/vapor/JPGWriter.h ================================================ #pragma once #include "vapor/ImageWriter.h" #include namespace VAPoR { class RENDER_API JPGWriter : public ImageWriter { FILE *fp; public: static int DefaultQuality; int Quality; JPGWriter(const std::string &path); ~JPGWriter(); static std::vector GetFileExtensions(); int Write(const unsigned char *buffer, const unsigned int width, const unsigned int height); }; } // namespace VAPoR ================================================ FILE: include/vapor/KDTreeRG.h ================================================ #ifndef _KDTreeRG_ #define _KDTreeRG_ #include #include #include #include "nanoflann.hpp" struct kdtree; namespace VAPoR { // //! \class KDTreeRG //! \brief This class implements a k-d space partitioning tree. //! //! This class provides an object-oriented interface to kdtree.c, which //! implements a k-d space partitioning tree. //! //! \sa https://en.wikipedia.org/wiki/K-d_tree // class VDF_API KDTreeRG { public: //! Construct a 2D k-d tree for a structured grid //! //! Creates a 2D k-d space partitioning tree for a structured grid //! defined by a pair of Grid instances. The data values of the //! \p xg and \p yg //! Grid instances provide the coordinates of all of the points //! to be inserted into the k-d tree. //! //! \param[in] xg A Grid instance giving the X user coordinates //! for each point in the k-d tree. //! \param[in] yg A Grid instance giving the Y user coordinates //! for each point in the k-d tree. The \p xg and \p yg Grid //! instances must have identical configurations, differing only in their //! data values. //! //! \sa Grid() // KDTreeRG(const Grid &xg, const Grid &yg); //! Construct a 3D k-d tree for a structured grid //! //! Creates a 3D k-d space partitioning tree for a structured grid //! //! \param[in] xg A Grid instance giving the X user coordinates //! for each point in the k-d tree. //! \param[in] yg A Grid instance giving the Y user coordinates //! for each point in the k-d tree. //! \param[in] zg A Grid instance giving the Z user coordinates //! for each point in the k-d tree. The \p xg, \p yg, and \p yg Grid //! instances must have identical configurations, differing only in their //! data values. //! //! \sa KDTreeRG(const Grid, const Grid) // // KDTreeRG( const Grid &xg, const Grid &yg, const Grid &zg ); virtual ~KDTreeRG(); //! Return indecies of nearest point //! //! This method returns the \a ijk indeces of the grid vertex nearest, by //! measure of Cartesian distance, a specified point. The returned //! indeces may be used to access the \p xg, \p yg, and \p zg //! Grid instances passed into the constructor. //! //! \param[in] coordu A 2D or 3D vector of user coordinates specifying //! the location of a point in space. //! //! \param[out] index The \a ijk indecies of the grid vertex nearest //! \p coordu. // void Nearest(const std::vector &coordu, std::vector &index) const; void Nearest(const std::vector &coordu, std::vector &index) const { std::vector coordu_f; for (int i = 0; i < coordu.size(); i++) coordu_f.push_back(coordu[i]); this->Nearest(coordu_f, index); } //! Returns the dimesionality of the structured grids passed to the //! constructor. //! //! This method returns a two or three element vector containing the //! dimensions of the Grid class instances passed to the //! constructor. //! //! \retval vector std::vector GetDimensions() const { return (_dims); } private: class PointCloud2D { public: // Constructor PointCloud2D(const Grid &xg, const Grid &yg) { VAssert(xg.GetDimensions() == yg.GetDimensions()); VAssert(xg.GetNumDimensions() <= 2); // number of elements auto dims = xg.GetDimensions(); size_t nelem = 1; for (int i = 0; i < dims.size(); i++) nelem *= dims[i]; this->X.resize(nelem); this->Y.resize(nelem); // Store the point coordinates in the k-d tree Grid::ConstIterator xitr = xg.cbegin(); Grid::ConstIterator yitr = yg.cbegin(); for (size_t i = 0; i < nelem; ++i, ++xitr, ++yitr) { this->X[i] = *xitr; this->Y[i] = *yitr; } } // end of the Constructor // Must return the number of data points inline size_t kdtree_get_point_count() const { VAssert(X.size() == Y.size()); return X.size(); } // Returns the dim'th component of the idx'th point in the class: // Since this is inlined and the "dim" argument is typically an immediate value, the // "if/else's" are actually solved at compile time. inline float kdtree_get_pt(const size_t idx, int dim) const { if (dim == 0) return X[idx]; else return Y[idx]; } // Optional bounding-box computation: return false to default to a standard bbox computation loop. // Return true if the BBOX was already computed by the class and returned in "bb" // so it can be avoided to redo it again. // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds) template bool kdtree_get_bbox(BBOX & /* bb */) const { return false; } private: std::vector X, Y; }; // end of class PointCloud2D typedef nanoflann::KDTreeSingleIndexAdaptor, PointCloud2D, 2 /* dimension */> KDTreeType; PointCloud2D _points; KDTreeType _kdtree; std::vector _dims; }; // end of class KDTreeRG. //! class KDTreeRGSubset //! \brief This class implements a k-d tree for a structured grid over //! a reduced region-of-interest (ROI) //! //! This class provides a k-d tree for a structured grid over an ROI. The //! class constructor is passed a pointer to a KDTreeRG instance that //! defines a k-d tree over a structured grid. This class can be used //! to cull out points outside of an axis-aligned region of interest //! specified by \p min and \p max. The advantage of using this class //! over simply creating a new instance of KDTreeRG is the avoidance //! of the cost of rebuilding the k-d tree from scratch. //! class VDF_API KDTreeRGSubset { public: KDTreeRGSubset(); //! Construct a KDTreeRGSubset instance. //! //! Construct a KDTreeRGSubset instance. //! //! \param[in] kdtreerg A pointer to a KDTreeRG instance. The pointer //! is shallow copied and the referenced contents should remain valid //! until this class instance is destroyed. //! //! \param[in] min A two or three element vector of \a ijk coordinate indeces //! of the first grid point defined by \a xg, \a yg, and \a zg. //! \param[in] max A two or three element vector of \a ijk coordinate indeces //! of the last grid point defined by \a xg, \a yg, and \a zg. //! //! \note \p kdtreerg is shallow copied and the referenced contents //! should remain valid //! until this class instance is destroyed. // KDTreeRGSubset(const KDTreeRG *kdtreerg, const std::vector &min, const std::vector &max); ~KDTreeRGSubset() {} //! Return indecies of nearest point //! //! This method returns the \a ijk index of the grid vertex nearest, by //! measure of Cartesian distance, a specified point. The returned //! indecies may be used to access the \p xg, \p yg, and \p zg //! Grid instances passed into the constructor used to //! create \p kdtreerg. //! //! \param[in] coordu A 2D or 3D vector of user coordinates specifying //! the location of a point in space. //! //! \param[out] index The \a ijk indecies of the grid vertex nearest //! \p coordu. // void Nearest(const std::vector &coordu, std::vector &coord) const; void Nearest(const std::vector &coordu, std::vector &index) const { std::vector coordu_f; for (int i = 0; i < coordu.size(); i++) coordu_f.push_back(coordu[i]); Nearest(coordu_f, index); } std::vector GetDimensions() const { std::vector dims; for (int i = 0; i < _min.size(); i++) { dims.push_back(_max[i] - _min[i] + 1); } return (dims); } private: const KDTreeRG * _kdtree; std::vector _min; std::vector _max; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/LayeredGrid.h ================================================ #ifndef _LayeredGrid_ #define _LayeredGrid_ #include #include "RegularGrid.h" #include "StretchedGrid.h" namespace VAPoR { //! \class LayeredGrid //! //! \brief This class implements a 2D or 3D layered grid. //! //! This class implements a 3D layered grid: a generalization //! of a stretched grid where the spacing of grid points along the K dimension //! varies at each grid point. The spacing along the remaining I and J //! dimensions is invariant between grid points. I.e. //! z coordinate is given by some //! function f(i,j,k): //! //! z = f(i,j,k) //! //! where f() is monotonically increasing (or decreasing) with k. //! The remaining x and y coordinates are givey by (i*dx, j*dy) //! for some real dx and dy . //! // class VDF_API LayeredGrid : public StructuredGrid { public: //! //! Construct a layered grid sampling a 3D or 2D scalar function //! //! \copydoc StructuredGrid::StructuredGrid() //! //! //! Adds or changes parameters: //! //! \param[in] xcoords A 1D vector whose size matches that of the I //! dimension of this class, and whose values specify the X user coordinates. //! \param[in] ycoords A 1D vector whose size matches that of the J //! of the last grid point. //! //! \param[in] rg A RegularGrid instance with the same dimensionality and //! min/max offsets as specified by \p bs, \p min, and \p max. The //! data values of \p rg provide the user coordinates for the Z dinmension. //! LayeredGrid(const DimsType &dims, const DimsType &bs, const std::vector &blks, const std::vector &xcoords, const std::vector &ycoords, const RegularGrid &rg); LayeredGrid(const std::vector &dims, const std::vector &bs, const std::vector &blks, const std::vector &xcoords, const std::vector &ycoords, const RegularGrid &rg); LayeredGrid() = default; virtual ~LayeredGrid() = default; virtual size_t GetGeometryDim() const override { return (3); } virtual DimsType GetCoordDimensions(size_t dim) const override; static std::string GetClassType() { return ("Layered"); } std::string GetType() const override { return (GetClassType()); } //! \copydoc RegularGrid::GetValue() //! float GetValue(const CoordType &coords) const override; //! \copydoc Grid::GetInterpolationOrder() // virtual int GetInterpolationOrder() const override { return _interpolationOrder; }; //! Set the interpolation order to be used during function reconstruction //! //! This method sets the order of the interpolation method that will //! be used when reconstructing the sampled scalar function. Valid values //! of \p order are 0, 1, and 2, corresponding to nearest-neighbor,linear, //! and quadratic //! interpolation, respectively. If \p order is invalid it will be silently //! set to 2. The default interpolation order is 1 //! //! \param[in] order interpolation order //! \sa GetInterpolationOrder() //! virtual void SetInterpolationOrder(int order) override; //! \copydoc Grid::GetBoundingBox() //! virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override; //! \copydoc Grid::GetUserCoordinates() //! virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override; // For grandparent inheritance of // Grid::GetUserCoordinates(const size_t indices[], double coords[]) // using Grid::GetUserCoordinates; //! \copydoc Grid::GetIndicesCell //! virtual bool GetIndicesCell(const CoordType &coords, DimsType &indices) const override; // For grandparent inheritance of // Grid::GetIndicesCell(const double coords[3], size_t indices[3]) // using Grid::GetIndicesCell; //! \copydoc Grid::InsideGrid() //! bool InsideGrid(const CoordType &coords) const override; //! \copydoc Grid::GetPeriodic() //! //! Only horizonal dimensions can be periodic. Layered (third) dimension //! is ignored if set to periodic // virtual void SetPeriodic(const std::vector &periodic) override { VAssert(periodic.size() == 3); std::vector myPeriodic = periodic; myPeriodic[2] = false; Grid::SetPeriodic(myPeriodic); } //! Return the internal data structure containing a copy of the coordinate //! blocks passed in by the constructor //! const RegularGrid &GetZRG() const { return (_zrg); }; class ConstCoordItrLayered : public Grid::ConstCoordItrAbstract { public: ConstCoordItrLayered(const LayeredGrid *rg, bool begin); ConstCoordItrLayered(const ConstCoordItrLayered &rhs); ConstCoordItrLayered(); virtual ~ConstCoordItrLayered() {} virtual void next(); virtual void next(const long &offset); virtual ConstCoordType &deref() const { return (_coords); } virtual const void * address() const { return this; }; virtual bool equal(const void *rhs) const { const ConstCoordItrLayered *itrptr = static_cast(rhs); return (_zCoordItr == itrptr->_zCoordItr); } virtual std::unique_ptr clone() const { return std::unique_ptr(new ConstCoordItrLayered(*this)); }; private: const LayeredGrid * _lg; size_t _nElements2D; CoordType _coords; size_t _index2D; ConstIterator _zCoordItr; StretchedGrid::ConstCoordItr _itr2D; }; virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrLayered(this, true))); } virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrLayered(this, false))); } protected: //! \copydoc Grid::GetUserExtents() //! virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override; private: StretchedGrid _sg2d; // horizontal coordinates maintained in stretched grid RegularGrid _zrg; // vertical coords are the values of a regular grid std::vector _xcoords; std::vector _ycoords; CoordType _minu = {{0.0, 0.0, 0.0}}; CoordType _maxu = {{0.0, 0.0, 0.0}}; int _interpolationOrder; void _layeredGrid(const DimsType &dims, const DimsType &bs, const std::vector &blks, const std::vector &xcoords, const std::vector &ycoords, const RegularGrid &rg); virtual float GetValueNearestNeighbor(const CoordType &coords) const override; virtual float GetValueLinear(const CoordType &coords) const override; //! //! Return the bilinear interpolation weights of a point given in user //! coordinates. These weights apply to the x (iwgt) and y (jwgt) axes. //! //! This function applies the bilinear interpolation method to derive //! a the x and y axis weights of a point in user coordinates. //! //! \param[in] x coordinate of grid point along fastest varying dimension //! \param[in] y coordinate of grid point along second fastest //! varying dimension //! \param[out] a bilinearly calculated weight for the x axis //! \param[out] a bilinearly calculated weight for the y axis // void _getBilinearWeights(const double coords[3], double &iwgt, double &jwgt) const; //! This function applies the bilinear interpolation method to derive //! a the elevation from x and y axis weights of a point in user coordinates. //! //! \param[in] i index of bottom left cell corner //! \param[in] i index of top right cell corner //! \param[in] j index of bottom left cell corner //! \param[in] j index of top right cell corner //! \param[in] k index of the level to interpolate upon //! \param[in] the i-axis weight for bilinear interpolation //! \param[in] the j-axis weight for bilinear interpolation //! \param[out] a bilinearly calculated elevation value double _bilinearElevation(size_t i0, size_t i1, size_t j0, size_t j1, size_t k0, double iwgt, double jwgt) const; //! double _bilinearInterpolation(double x, double y, size_t k, //! double *iwgt, double *jwgt) const; //! //! Return the bilinearly interpolated value of the currently opened variable //! of a point given in user coordinates. //! //! This function applies the bilinear interpolation method to derive //! a variable value from x and y axis weights of a point in user coordinates. //! //! \param[in] i index of bottom left cell corner //! \param[in] i index of top right cell corner //! \param[in] j index of bottom left cell corner //! \param[in] j index of top right cell corner //! \param[in] k index of the level to interpolate upon //! \param[in] the i-axis weight for bilinear interpolation //! \param[in] the j-axis weight for bilinear interpolation //! \param[out] a bilinearly calculated value of the currently open variable double _bilinearInterpolation(size_t i0, size_t i1, size_t j0, size_t j1, size_t k0, double iwgt, double jwgt) const; //! Return the interpolated value of a point in user //! coordinates. This only interpolates in the vertical (z) direction. //! //! Return the quadratically interpolated value of a point in user //! coordinates. //! //! This function applies the quadratic interpolation method to derive //! a the value of a variable in user coordinates from its neighboring //! points in ijk space. Linear interpolation is applied at the boundaries //! of the domain. //! //! \param[in] x coordinate of grid point along fastest varying dimension //! \param[in] y coordinate of grid point along second fastest //! varying dimension //! \param[in] z coordinate of grid point along third fastest //! varying dimension //! \param[out] a quadratically interpolated value of a point in user //! coordinates //! float _getValueQuadratic(const double coords[3]) const; //! Return the linearly interpolated value of a point in user //! coordinates. This only interpolates in the vertical (z) direction. //! //! \param[in] x coordinate of grid point along fastest varying dimension //! \param[in] y coordinate of grid point along second fastest //! varying dimension //! \param[in] z coordinate of grid point along third fastest //! varying dimension //! \param[out] a linearly interpolated value of a point in user //! coordinates. //! double _verticalLinearInterpolation(double x, double y, double z) const; double _interpolateVaryingCoord(size_t i0, size_t j0, size_t k0, double x, double y) const; bool _insideGrid(const CoordType &coords, DimsType &indices, double wgts[3]) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/LegacyGL.h ================================================ #pragma once #include #include #include #ifdef GL_QUADS #define LGL_QUADS GL_QUADS #else #define LGL_QUADS 105999 #endif namespace VAPoR { struct GLManager; //! \class LegacyGL //! \ingroup Public_Render //! //! \brief Replements Legacy OpenGL API using OpenGL Core //! //! This class should not be used for any intensive rendering //! //! \author Stanislaw Jaroszynski //! \date August, 2018 class RENDER_API LegacyGL { #pragma pack(push, 4) struct VertexData { float x, y, z; float nx, ny, nz; float r, g, b, a; float s, t; }; #pragma pack(pop) GLManager * _glManager; std::vector _vertices; unsigned int _mode; bool _emulateQuads; bool _firstQuadTriangle; unsigned int _VAO, _VBO; float _nx, _ny, _nz; float _r, _g, _b, _a; float _s, _t; bool _initialized, _insideBeginEndBlock; bool _lightingEnabled, _textureEnabled; float _lightDir[3]; Texture2D _emptyTexture; public: LegacyGL(GLManager *glManager); ~LegacyGL(); void Initialize(); void Begin(unsigned int mode); void End(); void Vertex(glm::vec2); void Vertex(glm::vec3); void Vertex2f(float x, float y); void Vertex3f(float x, float y, float z); void Vertex3fv(const float *v); void Vertex3dv(const double *v); void Normal3f(float x, float y, float z); void Normal3fv(const float *n); void Color(glm::vec3); void Color(glm::vec4); void Color3f(float r, float g, float b); void Color3fv(const float *f); void Color4f(float r, float g, float b, float a); void Color4fv(const float *f); void TexCoord(glm::vec2); void TexCoord2f(float s, float t); void EnableLighting(); void DisableLighting(); void LightDirectionfv(const float *f); void EnableTexture(); void DisableTexture(); // void PushAttrib(int flag); }; } // namespace VAPoR ================================================ FILE: include/vapor/LegacyVectorMath.h ================================================ #pragma once #ifndef INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH #error LegacyVectorMath.h is deprecated. Please dont use unless necessary #endif #include #include #include #include namespace VAPoR { COMMON_API bool powerOf2(size_t n); COMMON_API size_t nextPowerOf2(size_t n); COMMON_API void computeGradientData(int dim[3], int numChan, unsigned char *volume, unsigned char *gradient); COMMON_API void makeModelviewMatrix(float *vpos, float *vdir, float *upvec, float *matrix); COMMON_API void makeModelviewMatrixD(double *vpos, double *vdir, double *upvec, double *matrix); COMMON_API void makeModelviewMatrixD(const std::vector &vpos, const std::vector &vdir, const std::vector &upvec, double *matrix); COMMON_API void makeTransMatrix(float *transVec, float *matrix); COMMON_API void makeTransMatrix(double *transVec, double *matrix); COMMON_API void makeTransMatrix(const std::vector &transVec, double *matrix); COMMON_API void makeScaleMatrix(const double *scaleVec, double *matrix); COMMON_API void vscale(float *v, float s); COMMON_API void vscale(double *v, double s); COMMON_API void vscale(std::vector v, double s); COMMON_API void vmult(const float *v, float s, float *w); COMMON_API void vmult(const double *v, double s, double *w); COMMON_API void vhalf(const float *v1, const float *v2, float *half); COMMON_API void vcross(const float *v1, const float *v2, float *cross); COMMON_API void vcross(const double *v1, const double *v2, double *cross); COMMON_API void vreflect(const float *in, const float *mirror, float *out); COMMON_API void vtransform(const float *v, float *mat, float *vt); COMMON_API void vtransform(const float *v, float *mat, double *vt); COMMON_API void vtransform(const double *v, float *mat, double *vt); COMMON_API void vtransform(const double *v, double *mat, double *vt); COMMON_API void vtransform4(const float *v, float *mat, float *vt); COMMON_API void vtransform3(const float *v, float *mat, float *vt); COMMON_API void vtransform3(const double *v, double *mat, double *vt); COMMON_API void vtransform3t(const float *v, float *mat, float *vt); COMMON_API bool pointOnRight(double *pt1, double *pt2, const double *testPt); COMMON_API void mcopy(float *m1, float *m2); COMMON_API void mcopy(double *m1, double *m2); COMMON_API void mmult(float *m1, float *m2, float *prod); COMMON_API void mmult(double *m1, double *m2, double *prod); COMMON_API int minvert(const float *mat, float *result); COMMON_API int minvert(const double *mat, double *result); // Some routines to handle 3x3 rotation matrices, represented as 9 floats, // where the column index increments faster (like in 4x4 case COMMON_API void mmult33(const double *m1, const double *m2, double *result); // Same as above, but use the transpose (i.e. inverse for rotations) on the left COMMON_API void mmultt33(const double *m1Trans, const double *m2, double *result); // Determine a rotation matrix from (theta, phi, psi) (radians), that is, // find the rotation matrix that first rotates in (x,y) by psi, then takes the vector (0,0,1) // to the vector with direction (theta,phi) by rotating by phi in the (x,z) plane and then // rotating in the (x,y)plane by theta. COMMON_API void getRotationMatrix(double theta, double phi, double psi, double *matrix); // Determine a rotation matrix about an axis: COMMON_API void getAxisRotation(int axis, double rotation, double *matrix); // Determine the psi, phi, theta from a rotation matrix: COMMON_API void getRotAngles(double *theta, double *phi, double *psi, const double *matrix); COMMON_API int rayBoxIntersect(const float rayStart[3], const float rayDir[3], const float boxExts[6], float results[2]); COMMON_API int rayBoxIntersect(const double rayStart[3], const double rayDir[3], const double boxExts[6], double results[2]); // Determine the minimum and maximum projection of box corners to ray COMMON_API void rayBoxProject(std::vector rayStart, std::vector rayDir, const double boxExts[6], double results[2]); COMMON_API void qnormal(float *q); COMMON_API void qinv(const float q1[4], float q2[4]); COMMON_API void qmult(const float *q1, const float *q2, float *dest); COMMON_API void qmult(const double *q1, const double *q2, double *dest); COMMON_API void qmatrix(const float *q, float *m); COMMON_API void qmatrix(const double *q, double *m); COMMON_API float ProjectToSphere(float r, float x, float y); COMMON_API void CalcRotation(float *q, float newX, float newY, float oldX, float oldY, float ballsize); COMMON_API void CalcRotation(double *q, double newX, double newY, double oldX, double oldY, double ballsize); COMMON_API float ScalePoint(long pt, long origin, long size); COMMON_API void rvec2q(const float rvec[3], float radians, float q[4]); COMMON_API void rvec2q(const double rvec[3], double radians, double q[4]); COMMON_API void rotmatrix2q(float *m, float *q); COMMON_API void rotmatrix2q(double *m, double *q); COMMON_API float getScale(float *rotmatrix); COMMON_API void view2Quat(float vdir[3], float upvec[3], float q[4]); COMMON_API void quat2View(float quat[4], float vdir[3], float upvec[3]); COMMON_API void qlog(float quat[4], float lquat[4]); COMMON_API void qconj(float quat[4], float conj[4]); COMMON_API void slerp(float quat1[4], float quat2[4], float t, float result[4]); COMMON_API void squad(float quat1[4], float quat2[4], float s1[4], float s2[4], float t, float result[4]); COMMON_API void imagQuat2View(const float q[3], float vdir[3], float upvec[3]); COMMON_API void views2ImagQuats(float vdir1[3], float upvec1[3], float vdir2[3], float upvec2[3], float q1[3], float q2[3]); inline void vset(float *a, const float x, const float y, const float z) { a[0] = x; a[1] = y; a[2] = z; } inline void vset(double *a, const double x, const double y, const double z) { a[0] = x; a[1] = y; a[2] = z; } inline float vdot(const float *a, const float *b) { return (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]); } inline float vdot(const float *a, const double *b) { return (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]); } inline double vdot(const double *a, const double *b) { return (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]); } inline float vlength(const float *a) { return sqrt(vdot(a, a)); } inline double vlength(const double *a) { return sqrt(vdot(a, a)); } inline double vlength(const std::vector a) { return sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]); } inline float vdist(const float *a, const float *b) { return (sqrt((a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) + (a[2] - b[2]) * (a[2] - b[2]))); } inline double vdist(const double *a, const double *b) { return (sqrt((a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) + (a[2] - b[2]) * (a[2] - b[2]))); } inline void vnormal(float *a) { vscale(a, 1 / vlength(a)); } inline void vnormal(double *a) { vscale(a, 1 / vlength(a)); } inline void vnormal(std::vector a) { vscale(a, 1. / vlength(a)); } inline void vcopy(const float *a, float *b) { b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; } inline void vcopy(const double *a, double *b) { b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; } inline void vsub(const double *a, const float *b, float *c) { c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[2] = a[2] - b[2]; } inline void vsub(const float *a, const float *b, float *c) { c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[2] = a[2] - b[2]; } inline void vsub(const double *a, const double *b, double *c) { c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[2] = a[2] - b[2]; } inline void vsub(const double *a, const std::vector b, double *c) { c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[2] = a[2] - b[2]; } inline void vsub(const std::vector &a, const std::vector &b, double *c) { c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[2] = a[2] - b[2]; } inline void vadd(const float *a, const float *b, float *c) { c[0] = a[0] + b[0]; c[1] = a[1] + b[1]; c[2] = a[2] + b[2]; } inline void vadd(const double *a, const double *b, double *c) { c[0] = a[0] + b[0]; c[1] = a[1] + b[1]; c[2] = a[2] + b[2]; } inline void vzero(float *a) { a[0] = a[1] = a[2] = 0.f; } inline void vzero(double *a) { a[0] = a[1] = a[2] = 0.; } inline void qset(float *a, float x, float y, float z, float w) { a[0] = x; a[1] = y; a[2] = z; a[3] = w; } inline void qcopy(const float *a, float *b) { b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; b[3] = a[3]; } inline void qcopy(const double *a, double *b) { b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; b[3] = a[3]; } inline void qzero(float *a) { a[0] = a[1] = a[2] = 0; a[3] = 1; } inline void qzero(double *a) { a[0] = a[1] = a[2] = 0.; a[3] = 1.; } inline void qadd(const float *a, const float *b, float *c) { vadd(a, b, c), c[3] = a[3] + b[3]; } inline float qlength(const float q[4]) { return sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]); } // Forward declarations for utility functions. // These should really go in glutil! int matrix4x4_inverse(const float *in, float *out); void matrix4x4_vec3_mult(const float m[16], const float a[4], float b[4]); void adjoint(const float *in, float *out); double det4x4(const float m[16]); double det2x2(double a, double b, double c, double d); double det3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3); }; // namespace VAPoR ================================================ FILE: include/vapor/MapperFunction.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: MapperFunction.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: August 2005 // // Description: Defines the MapperFunction class // This is the mathematical definition of a function // that can be used to map data to either colors or opacities // Subclasses can either implement color or transparency // mapping (or both), and/or identify one or more isovalues. #ifndef MAPPERFUNCTION_H #define MAPPERFUNCTION_H #include #include #include #include namespace VAPoR { class XmlNode; class ParamNode; //! \class MapperFunction //! \brief Parent class for TransferFunction and IsoControl, //! supports positioning histogram over color/opacity maps as well as //! a set of isovalues (as with Contours) //! \author Alan Norton //! \version 3.0 //! \date January 2016 class PARAMS_API MapperFunction : public ParamsBase { public: MapperFunction(ParamsBase::StateSave *ssave); MapperFunction(ParamsBase::StateSave *ssave, XmlNode *node); MapperFunction(const MapperFunction &rhs); MapperFunction &operator=(const MapperFunction &rhs); virtual ~MapperFunction(); //! Save this transfer function to a file //! \param[in] path Path of output file // int SaveToFile(string path); //! Load a transfer function from a file, //! \param[in] path Path of input file // int LoadFromFile(string path); int LoadColormapFromFile(string path); // Get static string identifier for this params class // static string GetClassType() { return ("MapperFunctionParams"); } //! Determine the opacity value at a particular data value //! \param[in] point float data value float getOpacityValueData(float point) const; //! Determine the color value (in HSV) at a data point //! \param[in] point Data value //! \param[out] h Hue //! \param[out] sat Saturation //! \param[out] val Value void hsvValue(float point, float *h, float *sat, float *val) const; //! Determine the color value (in RGB) at a data point //! \param[in] point Data value //! \param[out] rgb r,g,b floats void rgbValue(float point, float rgb[3]) const { float hsv[3]; hsvValue(point, hsv, hsv + 1, hsv + 2); hsvToRgb(hsv, rgb); } //! Determine the color (in RGB) and opacity at a data point //! \param[in] point Data value //! \param[out] rgb r,g,b, afloats void rgbaValue(float point, float rgba[4]) const { float hsv[3]; hsvValue(point, hsv, hsv + 1, hsv + 2); hsvToRgb(hsv, rgba); rgba[3] = getOpacityValueData(point); } //! Make the opacity map completely opaque (opacity 1) void setOpaque(); //! Determine if the map is totally opaque (opacity 1) //! \return true if opaque. bool isOpaque() const; //! Build a color/opacity lookup table. //! Caller must supply an array to be filled in. //! Each entry isa 4-tuple: r,g,b,opacity. //! \param[out] clut lookup table of size _numEntries*4 void makeLut(float *clut) const; void makeLut(std::vector &clut) const; std::vector makeLut() const; //! Obtain minimum mapping (histo) value //! \return Minimum mapping value float getMinMapValue() const { return (getMinMaxMapValue()[0]); }; //! Obtain maximum mapping (histo) value //! \return Maximum mapping value float getMaxMapValue() const { return (getMinMaxMapValue()[1]); }; //! Set both minimum and maximum mapping (histo) values //! \param[in] val1 minimum value //! \param[in] val2 maximum value void setMinMaxMapValue(float val1, float val2); void setMinMapValue(float val) { setMinMaxMapValue(val, getMaxMapValue()); } void setMaxMapValue(float val) { setMinMaxMapValue(getMinMapValue(), val); } //! Obtain min and max mapping (histo) values //! \return minimum and maximum as a 2-vector of doubles vector getMinMaxMapValue() const; //! Returns size 2 vector of the users custom slider range. Used by TFMappingRangeSelector vector GetCustomMappingSliderRange() const; bool IsUsingCustomMappingSliderRange() const; //! Set the size 2 vector of the users custom slider range. Used by TFMappingRangeSelector void SetCustomMappingSliderRange(const vector &range); void SetUsingCustomMappingSliderRange(bool b); //! Create an opacity map for this transfer function //! \param[in] type of opacity map virtual OpacityMap *createOpacityMap(OpacityMap::Type type = OpacityMap::CONTROL_POINT); //! Delete an opacity map from this transfer function //! \param[in] omap Pointer to map to delete // void DeleteOpacityMap(const OpacityMap *omap); //! Obtain the opacity map associated with an index. //! specified index identifies which of the opacity maps is requested. //! \param[in] index Opacity map index of desired map. virtual OpacityMap *GetOpacityMap(int index) const; //! Determine how many opacity maps are available //! \return number of opacity maps int getNumOpacityMaps() const { return (m_opacityMaps->Size()); }; //! Specify an opacity scale factor applied to all opacity maps //! \param[in] val opacity scale factor void setOpacityScale(double val) { SetValueDouble(_opacityScaleTag, "Set Opacity Scale", val); } //! Identify the current opacity scale factor //! \return current opacity scale factor double getOpacityScale() const { return GetValueDouble(_opacityScaleTag, 1.0); } //! Opacity composition types enum CompositionType { ADDITION = 0, MULTIPLICATION = 1 }; //! Specify the type of opacity composition (ADDITION or MULTIPLICATION) //! \param[in] t CompositionType void setOpacityComposition(CompositionType t) { SetValueLong(_opacityCompositionTag, "Set Opacity Composition Type", (long)t); } //! Obtain the type of opacity composition (ADDITION or MULTIPLICATION) //! \return CompositionType CompositionType getOpacityComposition() const { return (CompositionType)GetValueLong(_opacityCompositionTag, ADDITION); } //! Utility method converts HSV to RGB //! \param[in] hsv (HSV as float[3] array) //! \param[out] rgb (RGB as float[3] array) static void hsvToRgb(float *hsv, float *rgb); //! Utility method converts RGB to HSV //! \param[in] rgb (RGB as float[3] array) //! \param[out] hsv (HSV as float[3] array) static void rgbToHsv(float *rgb, float *hsv); static vector rgbToHsv(vector rgb); //! Obtain the number of entries in the color/opacity map //! \return number of entries int getNumEntries() const { return _numEntries; } //! Map and quantize a real value to the corresponding table index //! i.e., quantize to current Mapper function domain //! \param[in] point value to be quantized //! \return quantized value in [0,_numEntries-1] int mapFloatToIndex(float point) const { int indx = mapPosition(point, getMinMapValue(), getMaxMapValue(), _numEntries - 1); if (indx < 0) indx = 0; if (indx > _numEntries - 1) indx = _numEntries - 1; return indx; } //! Determine float value associated with index //! \param[in] indx index (between 0 and _numEntries) //! \return corresponding float value float mapIndexToFloat(int indx) const { return (float)(getMinMapValue() + ((float)indx) * (float)(getMaxMapValue() - getMinMapValue()) / (float)(_numEntries - 1)); } //! Obtain the color interpolation type //! \return TFInterpolator::type color interpolation type TFInterpolator::type getColorInterpType() { ColorMap *cmap = GetColorMap(); if (cmap) return cmap->GetInterpType(); return TFInterpolator::diverging; } //! Specify the color interpolation type //! \param[in] t color interpolation type void setColorInterpType(TFInterpolator::type t) { ColorMap *cmap = GetColorMap(); if (cmap) cmap->SetInterpType(t); } void setUseWhitespace(int state) { ColorMap *cmap = GetColorMap(); if (cmap) cmap->SetUseWhitespace(state); } int getUseWhitespace() const { ColorMap *cmap = GetColorMap(); return cmap->GetUseWhitespace(); } //! Method to get the Color Map from the Mapper Function //! \return ColorMap pointer to the Color Map virtual ColorMap *GetColorMap() const { return (m_colorMap); } //! Method to get the state of the automatic histogram //! update setting. //! \return The state of the autoUpdateHisto checkbox // bool GetAutoUpdateHisto() { return ((bool)GetValueLong(_autoUpdateHistoTag, (int)false)); } //! Method to set the state of the automatic histogram //! update setting. //! \param[in] State of the autoUpdateHisto setting // void SetAutoUpdateHisto(bool val) { SetValueLong(_autoUpdateHistoTag, "enable/disable auto update of histogram", val); } //! Method to get the state of whether the current mapper function //! applies color through a primary variable or secondary variable. //! For example, Barbs may have a "Color Mapped Variable" that colors //! the barbs according to a "Secondary variable", independent of //! the vector variables that define the Barbs. Isosurfaces can have //! Secondary Variable colorings too. //! bool GetSecondaryVarMapper() { return ((bool)GetValueLong(_autoUpdateHistoTag, (int)false)); } //! Method to set the state of whether the current mapper function //! applies color through a ColorMappedVariable, or a renderer's primary //! variable. //! \param[in] State of the Secondary Variable color setting // void SetSecondaryVarMapper(bool val) { SetValueLong(_secondaryVarMapperTag, "Apply color through a secondary color", val); } public: // // XML tags // static const string _dataBoundsTag; static const string _opacityCompositionTag; static const string _opacityScaleTag; static const string _opacityMapsTag; static const string _opacityMapTag; static const string _autoUpdateHistoTag; static const string _secondaryVarMapperTag; static const string CustomMappingSliderRangeTag; static const string IsUsingCustomMappingSliderRangeTag; private: // // Size of lookup table. Always 1<<8 currently! // const int _numEntries; ParamsContainer *m_opacityMaps; ColorMap * m_colorMap; //! //! Map a point to the specified range, and quantize it. //! \param[in] x point value //! \param[in] minvalue minimum value //! \param[in] maxValue maximum value //! static int mapPosition(float x, float minValue, float maxValue, int hSize); // Construct name for new parent of opac map node, unique for this instance; string getNewOpacMapTag(int *tagIndex); // Construct a map tag for a specific index string getOpacMapTag(int index) const; // Extract the index from the opacity map tag int getOpacMapNum(string tag); string _make_omap_name(int index) const; }; #ifdef VAPOR3_0_0_ALPHA //! \class MFContainer //! \brief A simple container class for managing a collection //! of MapperFunctions, typically each associated with a different //! variable. //! //! \author John Clyne //! \date February 2016 class PARAMS_API MFContainer : public MyBase { public: MFContainer(); //! Construct an empty container. //! //! \param[in] p A pointer to the RenderParams that will //! store the subsequent collection. //! \param[in] tag Name to give the collection //! //! \sa ParamsBase::SetParamsBase() // MFContainer(RenderParams *p, string tag); ~MFContainer(); //! Insert a MapperFunction in the collection //! //! This method inserts the MapperFunction \p mf into the //! collection and gives it the name specified by \p name // void Insert(string name, MapperFunction *mf); //! Return the named MapperFunction //! //! This method returns the MapperFunction named by \p name, if it //! exists. Otherwise it returns NULL. No error is generated //! MapperFunction *GetMF(string name) const; //! Remove all elements from list // void Clear(); //! Erase the named MapperFunction // void Erase(string name); //! Return a list of names of all of the MapperFunctions // vector GetNames() const; private: RenderParams *_params; string _tag; }; #endif }; // namespace VAPoR #endif // MAPPERFUNCTION_H ================================================ FILE: include/vapor/MatWaveBase.h ================================================ #ifndef _MatWaveBase_h_ #define _MatWaveBase_h_ #include #include "WaveFiltBase.h" using namespace std; namespace VAPoR { // //! \class MatWaveBase //! \brief A base class for a Matlab-like wavelet bank //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! The MatWaveBase class is a base class for building Matlab-inspired //! wavelet filter banks. In many cases the methods provided behave //! similarly - in some cases indentically - to the Matlab Wavelet Toolbox //! version 4 command of the same name. //! class WASP_API MatWaveBase : public Wasp::MyBase { public: //! \enum dwtmode_t //! Enumerated boundary extension modes //! enum dwtmode_t { INVALID = -1, ZPD, SYMH, SYMW, ASYMH, ASYMW, SP0, SP1, PPD, PER }; //! Create a wavelet filter bank //! //! \param[in] wname Name of wavelet. //! \param[in] mode The boundary extension mode. //! //! \sa dwtmode() //! MatWaveBase(const string &wname, const string &mode); MatWaveBase(const string &wname); virtual ~MatWaveBase(); //! Set the discrete wavelet extension transform mode //! //! \param[in] mode Valid values for mode are: "zpd", "symh", "symw", //! "asymh", "asymw", "sp0", "sp1", //! "spd", "ppd", and "per". //! //! \retval status a non-negative int is returned on success //! int dwtmode(const string &mode); //! Set the discrete wavelet extension transform mode //! //! \param[in] mode //! //! \retval status a non-negative int is returned on success //! \sa dwtmode_t //! int dwtmode(dwtmode_t mode); //! Get the current discrete wavelet extension transform mode //! //! \param[out] mode Current mode //! //! \retval status a non-negative int is returned on success //! const string dwtmode() const; //! Get the current discrete wavelet extension transform mode //! //! \retval mode //! dwtmode_t dwtmodeenum() const { return (_mode); }; //! //! Set the current wavelet //! //! Change the current wavelet to the one specified by \p wname. //! \param[in] wname Name of wavelet. //! //! \retval status a non-negative int is returned on success //! int wavelet(const string &wname); //! Get the current discrete wavelet name //! //! \retval name //! string wavelet_name() const { return (_wname); }; //! Get the current discrete wavelet //! //! \retval wavelet //! const WaveFiltBase *wavelet() const { return (_wf); }; //! Returns length of approximation coefficients generated in a //! decompostition pass //! //! This method returns the number of approximation coefficients //! generated by one decomposition pass through the filter bank for a signal //! of length, \p sigInLen. //! //! \param[in] sigInLen Length of input signal (number of samples) //! \retval length On success returns the number of coefficients. A //! negative int is returned on failure. //! //! \sa MatWaveDwt::dwt() // size_t approxlength(size_t sigInLen) const; //! Returns length of detail coefficients generated in a //! decompostition pass //! //! This method returns the number of detail coefficients //! generated by one decomposition pass through the filter bank for a signal //! of length, \p sigInLen. //! //! \param[in] sigInLen Length of input signal (number of samples) //! \retval length Returns the number of coefficients. //! //! \sa MatWaveDwt::dwt() // size_t detaillength(size_t sigInLen) const; //! Returns length of coefficients generated in a decompostition pass //! //! This method returns the number of coefficients (approximation plus detail) //! generated by one decomposition pass through the filter bank for a signal //! of length, \p sigInLen. //! //! \param[in] sigInLen Length of input signal (number of samples) //! \retval length Returns the number of coefficients. //! //! \sa MatWaveDwt::dwt() // size_t coefflength(size_t sigInLen) const { return (approxlength(sigInLen) + detaillength(sigInLen)); }; size_t coefflength2(size_t sigInX, size_t sigInY) const { return (coefflength(sigInX) * coefflength(sigInY)); }; size_t coefflength3(size_t sigInX, size_t sigInY, size_t sigInZ) const { return (coefflength(sigInX) * coefflength(sigInY) * coefflength(sigInZ)); }; //! Returns maximum wavelet decompostion level //! //! This method returns the maximum level decomposition of a signal //! of length, \p s. This is the //! maximum number of times that a single level decomposition can //! be applied to a signal //! //! \param[in] Length of input signal //! \retval length Returns the maximum number of //! decompositions. //! //! \sa MatWaveDwt::dwt(), MatWaveWavedec::wavedec() // size_t wmaxlev(size_t s) const; //! Set or get the abort-on-invalid-float flag //! //! When set, the presence of input data containing invalid floats - floats //! for which the math.h isfinite() function does not return true - results //! in the abnormal termination of the method. If the flag is not //! set invalid floats are set to zero. By default the flag is not set. //! //! \retval flag A reference to the abot-on-invalid-float flag // bool &InvalidFloatAbortOnOff() { return (_InvalidFloatAbort); }; protected: private: bool _InvalidFloatAbort; dwtmode_t _mode; WaveFiltBase *_wf; string _wname; WaveFiltBase *_create_wf(const string &wname) const; void _wave_len_validate(size_t sigInLen, int waveLength, size_t *lev, size_t *val) const; dwtmode_t _dwtmodestr2enum(const string &mode) const; string _dwtmodeenum2str(dwtmode_t mode) const; }; } // namespace VAPoR #endif ================================================ FILE: include/vapor/MatWaveDwt.h ================================================ #ifndef _MatWaveDwt_h_ #define _MatWaveDwt_h_ #include #include namespace VAPoR { // //! \class MatWaveDwt //! \brief Implements a single level wavelet filter //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! The MatWaveDwt class provides single-level wavelet filters similar //! to those provided by the Matlab dwt and idwt functions. 1D, 2D, and 3D //! transforms are provided. The API for dwt and idwt more closely //! matches the MatLab wavedec and waverec functions than the MatLab //! functions of the same name. //! class WASP_API MatWaveDwt : public MatWaveBase { public: //! Create a wavelet filter bank //! //! \param[in] wname The name of the wavelet to apply. //! \param[in] mode The boundary extension mode. //! //! \sa dwtmode() //! MatWaveDwt(const string &wname, const string &mode); MatWaveDwt(const string &wname); virtual ~MatWaveDwt(); //! Single-level discrete 1D wavelet transform //! //! This method performs a single-level, one-dimensional wavelet //! decomposition with respect to the current wavelet //! and boundary extension mode. //! //! \param[in] sigIn The discrete signal //! \param[in] sigInLength The length of \p sigIn //! \param[out] C The wavelet decompostion vector. The length of \p C, //! must be equal to //! the value returned by MatWaveWavedec::coefflength(). //! \param[out] cA The wavelet decompostion vector approximation coefficients //! \param[out] cD The wavelet decompostion vector detail coefficients //! \param[out] L[3] The book keeping vector. The length of \p L, must //! be equal to 3. \p L[0] provides the length of the approximation //! coefficients, \p L[1] provides the length of the detail coefficients, //! and \p L[2] is equal to \p sigInLength. //! //! \retval status A negative number indicates failure. //! //! \sa MatWaveBase::coefflength(), idwt() // int dwt(const double *sigIn, size_t sigInLength, double *C, size_t L[3]); int dwt(const float *sigIn, size_t sigInLength, float *C, size_t L[3]); int dwt(const double *sigIn, size_t sigInLength, double *cA, double *cD, size_t L[3]); int dwt(const float *sigIn, size_t sigInLength, float *cA, float *cD, size_t L[3]); int dwt(const long *sigIn, size_t sigInLength, long *C, size_t L[3]); int dwt(const int *sigIn, size_t sigInLength, int *C, size_t L[3]); int dwt(const long *sigIn, size_t sigInLength, long *cA, long *cD, size_t L[3]); int dwt(const int *sigIn, size_t sigInLength, int *cA, int *cD, size_t L[3]); //! Single-level inverse discrete 1D wavelet transform //! //! This method performs a single-level, one-dimensional wavelet //! reconstruction with respect to the current wavelet and //! boundary extension mode. //! //! \param[in] C The Wavelet decomposition vector, dimensioned according //! to \p L. //! \param[in] cA The wavelet decompostion vector approximation coefficients //! \param[in] cD The wavelet decompostion vector detail coefficients //! \param[in] L[3] The Wavelet decomposition book keeping vector. //! \param[out] sigOut Single-level reconstruction approximation based //! on the approximation and detail coefficients (\p C). The length of //! \p sigOut is must be \p L[2]. //! //! \retval status A negative number indicates failure. //! //! \sa MatWaveBase::coefflength(), dwt() // int idwt(const double *C, const size_t L[3], double *sigOut); int idwt(const float *C, const size_t L[3], float *sigOut); int idwt(const double *cA, const double *cD, const size_t L[3], double *sigOut); int idwt(const float *cA, const float *cD, const size_t L[3], float *sigOut); int idwt(const long *C, const size_t L[3], long *sigOut); int idwt(const int *C, const size_t L[3], int *sigOut); int idwt(const long *cA, const long *cD, const size_t L[3], long *sigOut); int idwt(const int *cA, const int *cD, const size_t L[3], int *sigOut); //! Single-level discrete 2D wavelet transform //! //! This method performs a single-level, two-dimensional wavelet //! decomposition with respect to the current wavelet and //! boundary extension mode. //! //! \param[in] sigIn The discrete signal //! \param[in] sigInX The length of the X dimension of \p sigIn //! \param[in] sigInY The length of the Y dimension of \p sigIn //! \param[out] C The wavelet decompostion vector. The length of \p C, //! must be equal to //! the value returned by MatWaveWavedec::coefflength2(). //! \param[out] cA The wavelet decompostion vector approximation coefficients //! \param[out] cDh The wavelet decompostion vector horizontal //! detail coefficients //! \param[out] cDv The wavelet decompostion vector vertical //! detail coefficients //! \param[out] cDv The wavelet decompostion vector diagonal //! detail coefficients //! \param[out] L[10] The book keeping vector. The length of \p L, must //! be equal to 6 + 4. \p L[0] and \L[1] provide the dimensions of //! the approximation //! coefficients, \p L[2] and \p L[3] provides the dimension of the //! horizontal detail coefficients, \p L[4] and \p L[5] the horizontal //! coefficients, \p L[6] and \p L[7] the diagonal detail coefficients, //! and \p L[8] \p L[9] are equal to \p sigInX and \p sigInY, respectively. //! //! //! \retval status A negative number indicates failure. //! //! \sa MatWaveBase::coefflength(), idwt() // int dwt2d(const double *sigIn, size_t sigInX, size_t sigInY, double *C, size_t L[10]); int dwt2d(const float *sigIn, size_t sigInX, size_t sigInY, float *C, size_t L[10]); int dwt2d(const double *sigIn, size_t sigInX, size_t sigInY, double *cA, double *cDh, double *cDv, double *cDd, size_t L[10]); int dwt2d(const float *sigIn, size_t sigInX, size_t sigInY, float *cA, float *cDh, float *cDv, float *cDd, size_t L[10]); int dwt2d(const long *sigIn, size_t sigInX, size_t sigInY, long *C, size_t L[10]); int dwt2d(const int *sigIn, size_t sigInX, size_t sigInY, int *C, size_t L[10]); int dwt2d(const long *sigIn, size_t sigInX, size_t sigInY, long *cA, long *cDh, long *cDv, long *cDd, size_t L[10]); int dwt2d(const int *sigIn, size_t sigInX, size_t sigInY, int *cA, int *cDh, int *cDv, int *cDd, size_t L[10]); //! Single-level inverse discrete 2D wavelet transform //! //! This method performs a single-level, two-dimensional wavelet //! reconstruction with respect to the current wavelet and boundary //! extension mode. //! //! \param[in] C The Wavelet decomposition vector, dimensioned according //! to \p L. //! \param[in] cA The wavelet decompostion vector approximation coefficients //! \param[in] cDh The wavelet decompostion vector horizontal //! detail coefficients //! \param[in] cDv The wavelet decompostion vector vertical //! detail coefficients //! \param[in] cDv The wavelet decompostion vector diagonal //! detail coefficients //! \param[in] L[10] The Wavelet decomposition book keeping vector. //! \param[out] sigOut Single-level reconstruction approximation based //! on the approximation and detail coefficients (\p C). The length of //! \p sigOut is must be \p L[8] * \p L[9]. //! //! \retval status A negative number indicates failure. //! //! \sa MatWaveBase::coefflength(), dwt() // int idwt2d(const double *C, const size_t L[10], double *sigOut); int idwt2d(const float *C, const size_t L[10], float *sigOut); int idwt2d(const double *cA, const double *cDh, const double *cDv, const double *cDd, const size_t L[10], double *sigOut); int idwt2d(const float *cA, const float *cDh, const float *cDv, const float *cDd, const size_t L[10], float *sigOut); int idwt2d(const long *C, const size_t L[10], long *sigOut); int idwt2d(const int *C, const size_t L[10], int *sigOut); int idwt2d(const long *cA, const long *cDh, const long *cDv, const long *cDd, const size_t L[10], long *sigOut); int idwt2d(const int *cA, const int *cDh, const int *cDv, const int *cDd, const size_t L[10], int *sigOut); //! Single-level discrete 3D wavelet transform //! //! C is partitioned in the order: LLL, LLH, LHL, LHH, HLL, //! HLH, HHL, HHH //! int dwt3d(const double *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, double *C, size_t L[27]); int dwt3d(const float *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, float *C, size_t L[27]); int dwt3d(const long *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, long *C, size_t L[27]); int dwt3d(const int *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int *C, size_t L[27]); //! Single-level inverse discrete 3D wavelet transform // int idwt3d(const double *C, const size_t L[27], double *sigOut); int idwt3d(const float *C, const size_t L[27], float *sigOut); int idwt3d(const double *cLLL, const double *cLLH, const double *cLHL, const double *cLHH, const double *cHLL, const double *cHLH, const double *cHHL, const double *cHHH, const size_t L[27], double *sigOut); int idwt3d(const float *cLLL, const float *cLLH, const float *cLHL, const float *cLHH, const float *cHLL, const float *cHLH, const float *cHHL, const float *cHHH, const size_t L[27], float *sigOut); int idwt3d(const long *C, const size_t L[27], long *sigOut); int idwt3d(const int *C, const size_t L[27], int *sigOut); int idwt3d(const long *cLLL, const long *cLLH, const long *cLHL, const long *cLHH, const long *cHLL, const long *cHLH, const long *cHHL, const long *cHHH, const size_t L[27], long *sigOut); int idwt3d(const int *cLLL, const int *cLLH, const int *cLHL, const int *cLHH, const int *cHLL, const int *cHLH, const int *cHHL, const int *cHHH, const size_t L[27], int *sigOut); private: // 1D buffers Wasp::SmartBuf _dwt1dSmartBuf; // 2D buffers Wasp::SmartBuf _dwt2dSmartBuf; // 3D buffers Wasp::SmartBuf _dwt3dSmartBuf1; Wasp::SmartBuf _dwt3dSmartBuf2; }; } // namespace VAPoR #endif ================================================ FILE: include/vapor/MatWaveWavedec.h ================================================ #ifndef _MatWaveWavedec_h_ #define _MatWaveWavedec_h_ #include "MatWaveDwt.h" namespace VAPoR { // //! \class MatWaveWavedec //! \brief Implements a multi-level wavelet filter //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! The MatWaveWavedec class provides multi-level wavelet filters similar //! to those provided by the Matlab wavedec and waverec functions. //! 1D, 2D, and 3D //! transforms are provided. //! class WASP_API MatWaveWavedec : public MatWaveDwt { public: //! Create a wavelet filter bank //! //! \param[in] wname The name of the wavelet to apply. //! \param[in] mode The boundary extension mode. //! //! \note To ensure that the number of coefficients in a decomposition //! is equal to the number of samples in the decomposed signal, \p mode //! must be set to 'per'; or a symmetric wavelet must be used and \p mode //! set to 'symw' if the filter length is odd, or set to 'symh' if //! the filter length is even. The one exception to this is the Haar //! wavelet for which the number of coefficients is the same as the //! signal length regardless of the boundary handling mode. //! //! \sa dwtmode() //! MatWaveWavedec(const string &wname, const string &mode); MatWaveWavedec(const string &wname); virtual ~MatWaveWavedec(); //! Multi-level discrete 1D wavelet decomposition //! //! This method performs a multi-level, one-dimensional wavelet //! decomposition with respect to the current wavelet. //! The number of decompositions to apply is specified by the //! parameter \p n, where \p n is in the range (0..max). \b max is the //! value returned by wmaxlev(). The format of the returned //! decomposition vector, \p C, and the bookkeeping vector, \p L, are //! as described by the Matlab documentation for the \b wavedec function. //! //! \param[in] sigIn The discrete signal //! \param[in] sigInLength The length of \p sigIn //! \param[in] n The transformation level //! \param[out] C The wavelet decompostion vector. The length of \p C //! must be equal to //! the value returned by MatWaveWavedec::coefflength(). //! \param[out] L The booking vector. The length of \p L must be equal to //! \p n + 2. //! //! \retval status A negative number indicates failure. //! //! \sa MatWaveWavedec::coefflength(), waverec(), wmaxlev() // int wavedec(const double *sigIn, size_t sigInLength, int n, double *C, size_t *L); int wavedec(const float *sigIn, size_t sigInLength, int n, float *C, size_t *L); int wavedec(const long *sigIn, size_t sigInLength, int n, long *C, size_t *L); int wavedec(const int *sigIn, size_t sigInLength, int n, int *C, size_t *L); //! Multi-level discrete 1D wavelet reconstruction //! //! This method performs a multi-level, one-dimensional wavelet //! reconstruction with respect to the current wavelet. //! The number of reconstructions to apply is \p n. //! //! \param[in] C The Wavelet decomposition vector //! \param[in] L The Wavelet decomposition bookkeping vector. The length //! of \p L must be equal to \p n + 2. //! \param[in] n The transformation level //! \param[out] sigOut The reconstructed signal. The length of //! \p sigOut is given by MatWaveWavedec::approxlength(). //! //! \retval status A negative number indicates failure. //! //! \sa wavedec() // int waverec(const double *C, const size_t *L, int n, double *sigOut); int waverec(const float *C, const size_t *L, int n, float *sigOut); int waverec(const long *C, const size_t *L, int n, long *sigOut); int waverec(const int *C, const size_t *L, int n, int *sigOut); //! Multi-level discrete 2D wavelet decomposition //! //! This method performs a multi-level, two-dimensional wavelet //! decomposition with respect to the current wavelet. //! The number of decompositions to apply is specified by the //! parameter \p n, where \p n is in the range (0..max). \b max is the //! value returned by wmaxlev() for the smallest input dimension (\p sigInX //! and \p sigOutY). The format of the returned //! decomposition vector, \p C, and the bookkeeping vector, \p L, are //! as described by the Matlab documentation for the \b wavedec2 function. //! //! \param[in] sigIn The discrete signal //! \param[in] sigInX The length of the X dimension of \p sigIn //! \param[in] sigInY The length of the Y dimension of \p sigIn //! \param[in] n The transformation level //! \param[out] C The wavelet decompostion vector. The length of \p C must //! be equal to the value returned by MatWaveWavedec::coefflength2(). //! \param[out] L The booking vector. The length of \p L must be equal to //! (\p n * 6) + 4. //! //! \retval status A negative number indicates failure. //! //! \sa MatWaveWavedec::coefflength2(), waverec2(), wmaxlev() // int wavedec2(const double *sigIn, size_t sigInX, size_t sigInY, int n, double *C, size_t *L); int wavedec2(const float *sigIn, size_t sigInX, size_t sigInY, int n, float *C, size_t *L); int wavedec2(const long *sigIn, size_t sigInX, size_t sigInY, int n, long *C, size_t *L); int wavedec2(const int *sigIn, size_t sigInX, size_t sigInY, int n, int *C, size_t *L); //! Multi-level discrete 2D wavelet reconstruction //! //! This method performs a multi-level, two-dimensional wavelet //! reconstruction with respect to the current wavelet. //! The number of reconstructions to apply is \p n. //! //! \param[in] C The Wavelet decomposition vector //! \param[in] L The Wavelet decomposition bookkeping vector. The length //! of \p L must be equal to \p n * 6 + 4. //! \param[in] n The transformation level //! \param[out] sigOut The reconstructed signal. The dimensions of //! \p sigOut are given by MatWaveWavedec::approxlength2(). //! //! \retval status A negative number indicates failure. //! //! \sa wavedec2() // int waverec2(const double *C, const size_t *L, int n, double *sigOut); int waverec2(const float *C, const size_t *L, int n, float *sigOut); int waverec2(const long *C, const size_t *L, int n, long *sigOut); int waverec2(const int *C, const size_t *L, int n, int *sigOut); //! Multi-level discrete 3D wavelet decomposition //! //! This method performs a multi-level, three-dimensional wavelet //! decomposition with respect to the current wavelet. //! The number of decompositions to apply is specified by the //! parameter \p n, where \p n is in the range (0..max). \b max is the //! value returned by wmaxlev() for the smallest input dimension (\p sigInX //! \p sigOutY, and \p sigOutZ). The format of the returned //! decomposition vector, \p C, and the bookkeeping vector, \p L, follows //! the pattern of the 1D and 2D transforms //! //! \param[in] sigIn The discrete signal //! \param[in] sigInX The length of the X dimension of \p sigIn //! \param[in] sigInY The length of the Y dimension of \p sigIn //! \param[in] sigInZ The length of the Z dimension of \p sigIn //! \param[in] n The transformation level //! \param[out] C The wavelet decompostion vector. The length of \p C must //! be equal to //! the value returned by MatWaveWavedec::coefflength3(). //! \param[out] L The booking vector. The length of \p L which must //! be equal to //! (\p n * 21) + 6. //! //! \retval status A negative number indicates failure. //! //! \sa MatWaveWavedec::coefflength3(), waverec3(), wmaxlev() // int wavedec3(const double *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, double *C, size_t *L); int wavedec3(const float *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, float *C, size_t *L); int wavedec3(const long *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, long *C, size_t *L); int wavedec3(const int *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, int *C, size_t *L); //! Multi-level discrete 3D wavelet reconstruction //! //! This method performs a multi-level, three-dimensional wavelet //! reconstruction with respect to the current wavelet. //! The number of reconstructions to apply is \p n. //! //! \param[in] C The Wavelet decomposition vector //! \param[in] L The Wavelet decomposition bookkeping vector. The length //! of \p L must be equal to (\p n * 21) + 6. //! \param[in] n The transformation level //! \param[out] sigOut The reconstructed signal. The dimensions of //! \p sigOut are given by MatWaveWavedec::approxlength3(). //! //! \retval status A negative number indicates failure. //! //! \sa wavedec3() // int waverec3(const double *C, const size_t *L, int n, double *sigOut); int waverec3(const float *C, const size_t *L, int n, float *sigOut); int waverec3(const long *C, const size_t *L, int n, long *sigOut); int waverec3(const int *C, const size_t *L, int n, int *sigOut); int appcoef(const double *C, const size_t *L, int n, int l, bool normal, double *sigOut); int appcoef(const float *C, const size_t *L, int n, int l, bool normal, float *sigOut); int appcoef2(const double *C, const size_t *L, int n, int l, bool normal, double *sigOut); int appcoef2(const float *C, const size_t *L, int n, int l, bool normal, float *sigOut); int appcoef3(const double *C, const size_t *L, int n, int l, bool normal, double *sigOut); int appcoef3(const float *C, const size_t *L, int n, int l, bool normal, float *sigOut); int appcoef(const long *C, const size_t *L, int n, int l, bool normal, long *sigOut); int appcoef(const int *C, const size_t *L, int n, int l, bool normal, int *sigOut); int appcoef2(const long *C, const size_t *L, int n, int l, bool normal, long *sigOut); int appcoef2(const int *C, const size_t *L, int n, int l, bool normal, int *sigOut); int appcoef3(const long *C, const size_t *L, int n, int l, bool normal, long *sigOut); int appcoef3(const int *C, const size_t *L, int n, int l, bool normal, int *sigOut); // //! Returns length of coefficient vector generated in a //! multi-level 1D decompostition pass //! //! This method returns the number of coefficients (approximation plus detail) //! generated by a multi-level, one-dimensional //! decomposition pass through the filter //! bank for a signal //! of length, \p sigInLen, using the current wavelet. //! //! \param[in] sigInLen Length of input signal (number of samples) //! \param[in] L The Wavelet decomposition bookkeping vector. The length //! of \p L must be equal to (\p n + 2). //! \param[in] n The transformation level //! \retval length returns the number of coefficients. //! //! \sa MatWaveDwt::wavdec() // size_t coefflength(size_t sigInLen, int n) const; size_t coefflength(const size_t *L, int n) const; // //! Returns the number of approximation coefficients in a //! reconstruction. //! //! This method returns the number of coefficients in the reconstruction //! of a signal of length \p sigInLen at level \p n. If \p n == 0, the //! return value equals \p sigInLen //! //! \param[in] sigInLen Length of input signal (number of samples) //! \param[in] n The transformation level //! \retval length returns the number of coefficients // size_t approxlength(size_t sigInLen, int n) const; // //! Returns the number of approximation coefficients in a //! reconstruction. //! //! This method returns the number of coefficients in the reconstruction //! of a signal whose decompostion is described by the book keeping //! vector, \p L. The total number of transformation levels in \p L //! is given by \p n. The approximation level is given by \p l. //! If \p l == 0, the number of coefficients equals the length of //! the orginal signal. //! //! \param[in] L The Wavelet decomposition bookkeping vector. The length //! of \p L must be equal to (\p n + 2). //! \param[in] n The transformation level //! \param[in] l The approximation level sought. \p l must be in the //! range (0..\p n ). //! \param[out] len The returned number of approximation coefficients // void approxlength(const size_t *L, int n, int l, size_t *len) const; // //! Returns length of coefficient vector generated in a //! multi-level 2D decompostition pass //! //! This method returns the number of coefficients (approximation plus detail) //! generated by a multi-level, two-dimensional //! decomposition pass through the filter //! bank for a signal //! of length, \p sigInLen, using the current wavelet. //! //! \param[in] sigInX Length X dimension of input signal (number of samples) //! \param[in] sigInY Length Y dimension of input signal (number of samples) //! \param[in] L The booking vector. The length of \p L must be equal to //! (\p n * 6) + 4. //! \param[in] n The transformation level //! \retval length returns the number of coefficients. //! //! \sa MatWaveDwt::wavdec2() // size_t coefflength2(size_t sigInX, size_t sigInY, int n) const; size_t coefflength2(const size_t *L, int n) const; // //! Returns the number of approximation coefficients in a //! reconstruction. //! //! This method returns the number of coefficients in the reconstruction //! of a 2D signal whose decompostion is described by the book keeping //! vector, \p L. The total number of transformation levels in \p L //! is given by \p n. The approximation level is given by \p l. //! If \p l == 0, the number of coefficients equals the length of //! the orginal signal. //! //! \param[in] L The Wavelet decomposition bookkeping vector. The length //! of \p L must be equal to (\p n * 6) + 4. //! \param[in] n The transformation level //! \param[in] l The approximation level sought. \p l must be in the //! range (0..\p n ). //! \param[out] lenx The returned X dimension of approximation coefficients //! \param[out] leny The returned Y dimension of approximation coefficients // void approxlength2(const size_t *L, int n, int l, size_t *lenx, size_t *leny) const; // //! Returns length of coefficient vector generated in a //! multi-level 3D decompostition pass //! //! This method returns the number of coefficients (approximation plus detail) //! generated by a multi-level, three-dimensional //! decomposition pass through the filter //! bank for a signal //! of length, \p sigInLen, using the current wavelet. //! //! \param[in] sigInX Length X dimension of input signal (number of samples) //! \param[in] sigInY Length Y dimension of input signal (number of samples) //! \param[in] sigInZ Length Z dimension of input signal (number of samples) //! \param[in] L The booking vector. The length of \p L must be equal to //! (\p n * 21) + 6. //! \param[in] n The transformation level //! \retval length returns the number of coefficients. //! //! \sa MatWaveDwt::wavdec3() size_t coefflength3(size_t sigInX, size_t sigInY, size_t sigInZ, int n) const; size_t coefflength3(const size_t *L, int n) const; //! Returns the number of approximation coefficients in a //! reconstruction. //! //! This method returns the number of coefficients in the reconstruction //! of a 3D signal whose decompostion is described by the book keeping //! vector, \p L. The total number of transformation levels in \p L //! is given by \p n. The approximation level is given by \p l. //! If \p l == 0, the number of coefficients equals the length of //! the orginal signal. //! //! \param[in] L The Wavelet decomposition bookkeping vector. The length //! of \p L must be equal to (\p n * 6) + 4. //! \param[in] n The transformation level //! \param[in] l The approximation level sought. \p l must be in the //! range (0..\p n ). //! \param[out] lenx The returned X dimension of approximation coefficients //! \param[out] leny The returned Y dimension of approximation coefficients //! \param[out] lenz The returned Z dimension of approximation coefficients // void approxlength3(const size_t *L, int n, int l, size_t *lenx, size_t *leny, size_t *lenz) const; // //! Computes the book keeping vector, L, for a 1D wavelet decomposition //! //! //! \param[in] sigInLength The length of the input signal //! \param[in] n The transformation level //! \param[out] L The booking vector. The length of \p L must be equal to //! \p n + 2. // void computeL(size_t sigInLen, int n, size_t *L) const; // //! Computes the book keeping vector, L, for a 2D wavelet decomposition //! //! //! \param[in] sigInX The length of the X dimension of input signal //! \param[in] sigInY The length of the Y dimension of input signal //! \param[in] n The transformation level //! \param[out] L The booking vector. The length of \p L must be equal to //! (\p n * 6) + 4. // void computeL2(size_t sigInX, size_t sigInY, int n, size_t *L) const; // //! Computes the book keeping vector, L, for a 3D wavelet decomposition //! //! //! \param[in] sigInX The length of the X dimension of input signal //! \param[in] sigInY The length of the Y dimension of input signal //! \param[in] sigInZ The length of the Z dimension of input signal //! \param[in] n The transformation level //! \param[out] L The booking vector. The length of \p L must be equal to //! (\p n * 21) + 6. // void computeL3(size_t sigInX, size_t sigInY, size_t sigInZ, int n, size_t *L) const; private: }; } // namespace VAPoR #endif ================================================ FILE: include/vapor/MatrixManager.h ================================================ #pragma once #include #include #include #include #include #include using std::map; using std::stack; using std::string; namespace VAPoR { //! \class MatrixManager //! \ingroup Public_Render //! //! \brief Replaces the OpenGL matrix stack. //! //! Most functions are one to one replacements and have the same //! effects as their OpenGL or GLUT equivalents. //! //! \author Stanislaw Jaroszynski //! \date August, 2018 class RENDER_API MatrixManager { public: enum class Mode { ModelView, Projection }; MatrixManager(); glm::mat4 GetCurrentMatrix() const; glm::mat4 GetProjectionMatrix() const; glm::mat4 GetModelViewMatrix() const; glm::mat4 GetModelViewProjectionMatrix() const; void SetCurrentMatrix(const glm::mat4 m); void MatrixModeProjection(); void MatrixModeModelView(); void PushMatrix(); void PopMatrix(); void LoadMatrixd(const double *m); void GetDoublev(Mode mode, double *m) const; void LoadIdentity(); void Translate(float x, float y, float z); void Scale(float x, float y, float z); void Rotate(float angle, float x, float y, float z); void Perspective(float fovy, float aspect, float zNear, float zFar); void Ortho(float left, float right, float bottom, float top); void Ortho(float left, float right, float bottom, float top, float zNear, float zFar); glm::vec2 ProjectToScreen(float x, float y, float z) const; glm::vec2 ProjectToScreen(const glm::vec3 &v) const; float GetProjectionAspectRatio() const; #ifdef LEGACY_GL_DEBUG int GetGLMatrixMode(); const char *GetGLMatrixModeStr(); int GetGLModelViewStackDepth(); int GetGLProjectionStackDepth(); int GetGLCurrentStackDepth(); const char *GetMatrixModeStr(); #endif float Near, Far, FOV, Aspect; private: stack _modelviewStack; stack _projectionStack; stack *_currentStack; Mode _mode; float _projectionAspectRatio = 0; glm::mat4 & top(); const glm::mat4 &top() const; }; } // namespace VAPoR ================================================ FILE: include/vapor/ModelParams.h ================================================ #pragma once #include #include namespace VAPoR { class PARAMS_API ModelParams : public RenderParams { public: //! Path to a 3D model file or Vapor vms scene file. //! 3D models can be in formats supported by the ASSIMP library. //! A description of the Vapor vms scene format can be found at //! https://ncar.github.io/VaporDocumentationWebsite/vaporApplicationReference/modelRenderer.html //! Applies to data of type: string static const std::string FileTag; ModelParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave); ModelParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, std::string classType); ModelParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node); virtual ~ModelParams(); static string GetClassType() { return ("ModelParams"); } //! \copydoc RenderParams::GetRenderDim() // virtual size_t GetRenderDim() const override { return (0); } //! \copydoc RenderParams::GetActualColorMapVariableName() virtual string GetActualColorMapVariableName() const override { return ""; } private: void _init(); }; }; // namespace VAPoR ================================================ FILE: include/vapor/ModelRenderer.h ================================================ //************************************************************************ // * // Copyright (C) 2018 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: ModelRenderer.cpp // // Author: Stas Jaroszynski // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: March 2018 // // Description: // Definition of ModelRenderer // #pragma once #include #include #include #include #include #include #include #include namespace VAPoR { class DataMgr; //! \class ModelRenderer //! \brief Class that draws the contours (contours) as specified by IsolineParams //! \author Stas Jaroszynski //! \version 1.0 //! \date March 2018 class RENDER_API ModelRenderer : public Renderer { public: ModelRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr); static string GetClassType() { return ("Model"); } //! \copydoc Renderer::_initializeGL() virtual int _initializeGL(); //! \copydoc Renderer::_paintGL() virtual int _paintGL(bool fast); virtual void _clearCache() {} private: class Model { Assimp::Importer _importer; const aiScene * _scene; glm::vec3 _min, _max; void renderNode(GLManager *gl, const aiNode *nd) const; void calculateBounds(const aiNode *nd, glm::mat4 transform = glm::mat4(1.0f)); glm::mat4 getMatrix(const aiNode *nd) const; public: void Render(GLManager *gl) const; void DrawBoundingBox(GLManager *gl) const; int Load(const std::string &path); glm::vec3 BoundsMin() const { return _min; } glm::vec3 BoundsMax() const { return _max; } glm::vec3 Center() const { return (_min + _max) / 2.f; } }; class Scene { struct ModelInstance { std::string name; std::string file; glm::vec3 translate = glm::vec3(0.f); glm::vec3 rotate = glm::vec3(0.f); glm::vec3 scale = glm::vec3(1.f); glm::vec3 origin = glm::vec3(0.f); }; std::vector _instances; std::map> _keyframes; std::map _models; public: ~Scene(); int Load(const std::string &path); void Render(GLManager *gl, const int ts = 0); glm::vec3 Center() const; private: std::vector getInstances(const int ts) const; int createSceneFromModelFile(const std::string &path); int loadSceneFile(const std::string &path); int handleInstanceNode(XmlNode *node, ModelInstance *instance); int handleTimeNode(XmlNode *node); int handleVectorNode(XmlNode *node, glm::vec3 *v); int handleFloatAttribute(XmlNode *node, const std::string &name, float *f); int parseIntString(const std::string &str, int *i) const; ModelInstance getInitInstance(const std::string &name) const; bool doesInstanceExist(const std::string &name) const; bool isModelCached(const std::string &file) const; }; Scene _scene; std::string _cachedFile; void _renderNode(const aiNode *node); }; }; // namespace VAPoR ================================================ FILE: include/vapor/MouseModeParams.h ================================================ //************************************************************************ // * // Copyright (C) 1024 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: MouseModeParams.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: April 2014 // // Description: Defines the MouseModeParams class. // This Params class is global. Specifies the current MouseMode. // #ifndef MOUSEMODEPARAMS_H #define MOUSEMODEPARAMS_H #include #include #include //! \class MouseModeParams //! \ingroup Public_Params //! \brief A class for describing mouse modes in use in VAPOR //! \author Alan Norton //! \version 3.0 //! \date April 2014 //! class PARAMS_API MouseModeParams : public VAPoR::ParamsBase { public: struct MouseMode { string name; const char *const *icon; }; //! Create a MouseModeParams object from scratch // MouseModeParams(VAPoR::ParamsBase::StateSave *ssave); //! Create a MouseModeParams object from an existing XmlNode tree // MouseModeParams(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node); virtual ~MouseModeParams(); //! method identifies pixmap icon for each mode const char *const *GetIcon(string name) const { auto itr = _modes.cbegin(); for (; itr != _modes.cend(); ++itr) if (itr->name == name) break; VAssert(itr != _modes.end()); return itr->icon; } //! method indicates the current mouse mode //! \retval current mouse mode // string GetCurrentMouseMode() const { return GetValueString(_currentMouseModeTag, GetNavigateModeName()); } //! method sets the current mouse mode //! //! \param[in] name current mouse mode // void SetCurrentMouseMode(string name); //! method indicates how many mouse modes are available. int GetNumMouseModes() { return _modes.size(); } //! Return a vector of all registered mouse mode names // vector GetAllMouseModes() { vector v; for (auto itr = _modes.cbegin(); itr != _modes.cend(); ++itr) { v.push_back(itr->name); } return (v); } // Get static string identifier for this params class // static string GetClassType() { return ("MouseModeParamsTag"); } static string GetNavigateModeName() { return ("Navigate"); } static string GetRegionModeName() { return ("Region"); } private: static const string _currentMouseModeTag; vector _modes; void _init(); void _setUpDefault(); }; #endif // MOUSEMODEPARAMS_H ================================================ FILE: include/vapor/MyBase.h ================================================ // // $Id$ // //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: Wed Sep 29 15:40:23 MDT 2004 // // Description: A collection of general purpose utilities - things that // probably should be in the STL but aren't. // #ifndef _MyBase_h_ #define _MyBase_h_ #include #include #include #include #include #include #ifdef NEW_DEBUG #include void *operator new(size_t sz); void *operator new[](size_t sz); #endif #ifdef WIN32 // Silence an annoying and unnecessary compiler warning #pragma warning(disable : 4251) #endif using namespace std; namespace Wasp { //! \class MyBase //! \brief Wasp base class //! \author John Clyne //! \version 0.1 //! \date Mon Dec 13 17:15:12 MST 2004 //! A collection of general purpose utilities - things that //! probably should be in the STL but aren't. //! // default values used for variables outside valid grid const float ABOVE_GRID = 0.f; const float BELOW_GRID = 0.f; // // The MyBase base class provides a simple error reporting mechanism // that can be used by derrived classes. N.B. the error messages/codes // are stored in static class members. // class COMMON_API MyBase { public: typedef void (*ErrMsgCB_T)(const char *msg, int err_code); typedef void (*DiagMsgCB_T)(const char *msg); MyBase(); const string &getClassName() const { return (_className); }; //! Record a formatted error message. // //! Formats and records an error message. Subsequent calls will overwrite //! the stored error message. The method will also set the error //! code to 1. //! \param[in] format A 'C' style sprintf format string. //! \param[in] args... Arguments to format //! \sa GetErrMsg(), GetErrCode() // static void SetErrMsg(const char *format, ...); //! Record a formatted error message and an error code. // //! Formats and records an error message. Subsequent calls will overwrite //! the stored error message. The method will also set the error //! code to \b err_code. //! \param[in] errcode A application-defined error code //! \param[in] format A 'C' style sprintf format string. //! \param[in] arg... Arguments to format //! \sa GetErrMsg(), GetErrCode() // static void SetErrMsg(int errcode, const char *format, ...); //! Retrieve the current error message //! //! Retrieves the last error message set with SetErrMsg(). //! It is the //! caller's responsibility to copy the message returned to user space. //! \sa SetErrMsg(), SetErrCode() //! \retval msg A pointer to null-terminated string. // static const char *GetErrMsg() { return (ErrMsg); } //! Record an error code // //! Sets the error code to the indicated value. //! \param[in] err_code The error code //! \sa GetErrMsg(), GetErrCode(), SetErrMsg() // static void SetErrCode(int err_code) { ErrCode = err_code; } //! Retrieve the current error code // //! Retrieves the last error code set either explicity with SetErrCode() //! or indirectly with a call to SetErrMsg(). //! \sa SetErrMsg(), SetErrCode() //! \retval code An erroor code // static int GetErrCode() { return (ErrCode); } //! Set a callback function for error messages //! //! Set the callback function to be called whenever SetErrMsg() //! is called. The callback function, \p cb, will be called and passed //! the formatted error message and the error code as an argument. The //! default callback function is NULL, i.e. no function is called //! //! \param[in] cb A callback function or NULL // static void SetErrMsgCB(ErrMsgCB_T cb) { ErrMsgCB = cb; }; //! Get the callback function for error messages //! //! Get the callback function to be called whenever SetErrMsg() //! is called. This method returns the address of the callback function //! set with the most recent call to SetErrMsgCB(). If no callback function //! is defined, NULL is returned. //! //! \sa SetErrMsgCB // static ErrMsgCB_T GetErrMsgCB() { return (ErrMsgCB); }; //! Set the file pointer to whence error messages are written //! //! This method permits the specification of a file pointer to which //! all messages logged with SetErrMsg() will be written. The default //! file pointer is NULL. I.e. by default error messages logged by //! SetErrMsg() are not written. //! \param[in] fp A file pointer opened for writing or NULL //! \sa SetErrMsg() // static void SetErrMsgFilePtr(FILE *fp) { ErrMsgFilePtr = fp; }; //! Get the file pointer to whence error messages are written //! //! This method returns the error message file pointer most recently //! set with SetErrMsgFilePtr(). //! //! \sa SetErrMsgFilePtr() // static const FILE *SetErrMsgFilePtr() { return (ErrMsgFilePtr); }; //! Record a formatted diagnostic message. // //! Formats and records a diagnostic message. Subsequent calls will overwrite //! the stored error message. This method differs from SetErrMsg() only //! in that no associated error code is set - the message is considered //! diagnostic only, not an error. //! \param[in] format A 'C' style sprintf format string. //! \param[in] arg... Arguments to format //! \sa GetDiagMsg() // static void SetDiagMsg(const char *format, ...); //! Retrieve the current diagnostic message //! //! Retrieves the last error message set with \b SetDiagMsg(). It is the //! caller's responsibility to copy the message returned to user space. //! \sa SetDiagMsg() //! \retval msg A pointer to null-terminated string. // static const char *GetDiagMsg() { return (DiagMsg); } //! Set a callback function for diagnostic messages //! //! Set the callback function to be called whenever SetDiagMsg() //! is called. The callback function, \p cb, will be called and passed //! the formatted error message as an argument. The //! default callback function is NULL, i.e. no function is called //! //! \param[in] cb A callback function or NULL // static void SetDiagMsgCB(DiagMsgCB_T cb) { DiagMsgCB = cb; }; //! Get the callback function for error messages //! //! Get the callback function to be called whenever SetDiagMsg() //! is called. This method returns the address of the callback function //! set with the most recent call to SetDiagMsgCB(). If no callback function //! is defined, NULL is returned. //! //! \sa SetDiagMsgCB // static DiagMsgCB_T GetDiagMsgCB() { return (DiagMsgCB); }; //! Set the file pointer to whence diagnostic messages are written //! //! This method permits the specification of a file pointer to which //! all messages logged with SetDiagMsg() will be written. The default //! file pointer is NULL. I.e. by default error messages logged by //! SetDiagMsg() are not written. //! \param[in] fp A file pointer opened for writing or NULL //! \sa SetDiagMsg() // static void SetDiagMsgFilePtr(FILE *fp) { DiagMsgFilePtr = fp; }; //! Get the file pointer to whence diagnostic messages are written //! //! This method returns the error message file pointer most recently //! set with SetDiagMsgFilePtr(). //! //! \sa SetDiagMsgFilePtr() // //! //! Enable or disable error message reporting. //! //! When disabled calls to SetErrMsg() report no error messages //! either through the error message callback or the error message //! FILE pointer. //! //! \param[in] enable Boolean flag to enable or disable error reporting //! static bool EnableErrMsg(bool enable) { bool prev = Enabled; Enabled = enable; return (prev); }; static bool GetEnableErrMsg() { return Enabled; } // N.B. the error codes/messages are stored in static class members!!! static char * ErrMsg; static int ErrCode; static int ErrMsgSize; static FILE * ErrMsgFilePtr; static ErrMsgCB_T ErrMsgCB; static char * DiagMsg; static int DiagMsgSize; static FILE * DiagMsgFilePtr; static DiagMsgCB_T DiagMsgCB; static bool Enabled; protected: void SetClassName(const string &name) { _className = name; }; private: static void _SetErrMsg(char **msg, int *sz, const char *format, va_list args); string _className; // name of class }; COMMON_API inline int IsOdd(int x) { return (x % 2); }; //! Return true if power of two // //! Returns a non-zero value if the input parameter is a power of two //! \param[in] x An integer //! \retval status COMMON_API int IsPowerOfTwo(unsigned int x); COMMON_API inline int Min(int a, int b) { return (a < b ? a : b); }; COMMON_API inline int Max(int a, int b) { return (a > b ? a : b); }; COMMON_API inline size_t Min(size_t a, size_t b) { return (a < b ? a : b); }; COMMON_API inline size_t Max(size_t a, size_t b) { return (a > b ? a : b); }; COMMON_API inline float Min(float a, float b) { return (a < b ? a : b); }; COMMON_API inline float Max(float a, float b) { return (a > b ? a : b); }; COMMON_API inline double Min(double a, double b) { return (a < b ? a : b); }; COMMON_API inline double Max(double a, double b) { return (a > b ? a : b); }; COMMON_API inline double LogBaseN(double x, double n) { return (log(x) / log(n)); }; // Find integer log, base 2: COMMON_API int ILog2(int n); //! Case-insensitive string comparison // //! Performs a case-insensitive comparison of two C++ strings. Behaviour //! is otherwise identical to the C++ std::string.compare() method. // COMMON_API int StrCmpNoCase(const string &s, const string &t); //! Remove white space from a string // //! Performs in-place removal of all white space from a string. //! \param[in,out] s The string. COMMON_API void StrRmWhiteSpace(string &s); //! Parse a string, returning a vector of words // //! Parses a string containing a white-space delimited collection //! of words. The words are in order of occurence and returned //! as a vector of strings with all white space removed. //! //! \param[in] s The input string. //! \param[out] v The output vector. // COMMON_API void StrToWordVec(const string &s, vector &v); COMMON_API std::vector &SplitString(const std::string &s, char delim, std::vector &elems); COMMON_API std::vector &SplitString(const std::string &s, char delim, std::vector &elems); COMMON_API std::vector &SplitString(const std::string &s, char delim, std::vector &elems); COMMON_API std::vector &SplitString(const std::string &s, char delim, std::vector &elems); COMMON_API std::vector &SplitString(const std::string &s, char delim, std::vector &elems); //! Retrieve a sequence of bits //! //! Extract \p n bits from \p targ starting at position //! \p pos counting from the left. E.g. GetBits64(I,4,3) will //! extract bits at bit position 4,3,2, right adjusted //! //! \retval returns the extracted bits //! \sa GetBits64() // COMMON_API unsigned long long GetBits64(unsigned long long targ, int pos, int n); //! Set a sequence of bits //! //! Set \p n bits in \p targ starting at position //! \p pos counting from the left. The bits are obtained from //! \p src //! //! \retval returns \targ with the indicated bits set //! \sa GetBits64() // COMMON_API unsigned long long SetBits64(unsigned long long targ, int pos, int n, unsigned long long src); // ran1 function declaration (from numerical recipes in C) COMMON_API double ran1(long *); }; // namespace Wasp // // Handle OS differences in 64-bit IO operators // // 64-bit fseek // #ifdef FSEEK64 #undef FSEEK64 #endif #if defined(WIN32) // Note: win32 won't seek beyond 32 bits #define FSEEK64 fseek #endif #if defined(Linux) || defined(AIX) #define FSEEK64 fseeko64 #endif #if defined(Darwin) #define FSEEK64 fseeko #endif #ifndef FSEEK64 #define FSEEK64 fseek64 #endif // 64-bit fopen // #ifdef FOPEN64 #undef FOPEN64 #endif #if defined(WIN32) || defined(Darwin) #define FOPEN64 fopen #endif #ifndef FOPEN64 #define FOPEN64 fopen64 #endif // 64-bit stat // #ifdef STAT64 #undef STAT64 #endif #ifdef STAT64_T #undef STAT64_T #endif #if defined(WIN32) #define STAT64_T _stat #define STAT64 _stat #endif #if defined(Darwin) #define STAT64_T stat #define STAT64 stat #endif #if defined(__CYGWIN__) #define STAT64_T stat #define STAT64 stat #endif #ifndef STAT64 #define STAT64_T stat64 #define STAT64 stat64 #endif #ifndef TIME64_T #ifdef WIN32 #define TIME64_T __int64 #else #define TIME64_T int64_t #endif #endif #endif // MYBASE_H ================================================ FILE: include/vapor/MyPython.h ================================================ // // $Id$ // #ifndef _MYPYTHON_h_ #define _MYPYTHON_h_ #include #if __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-register" #else #undef _POSIX_C_SOURCE #undef _XOPEN_SOURCE #endif #ifdef WIN32 #ifdef _DEBUG #undef _DEBUG #include #define _DEBUG #else #include #endif #else #include #endif #if __clang__ #pragma clang diagnostic pop #endif namespace Wasp { // //! \class MYPYTHON //! \brief A singleton class for initializing Python //! \author John Clyne //! //! This singleton class should be used to initialize the Python //! interpreter via Py_Initialize(); //! //! Quoated from the Python 2.7.11 API documentation: //! //! Bugs and caveats: The destruction of modules and objects in modules //! is done in random order; this may cause destructors (__del__() methods) //! to fail when they depend on other objects (even functions) or modules. //! Dynamically loaded extension modules loaded by Python are not //! unloaded. Small amounts of memory allocated by the Python interpreter //! may not be freed (if you find a leak, please report it). Memory tied //! up in circular references between objects is not freed. Some memory //! allocated by extension modules may not be freed. Some extensions may //! not work properly if their initialization routine is called more //! than once; this can happen if an application calls Py_Initialize() //! and Py_Finalize() more than once. //! //! Usage: MyPython::Instance()->Initialize(); // class RENDER_API MyPython : public Wasp::MyBase { public: static bool IsRunningFromPython; static MyPython *Instance(); //! Initialize the Python interpreter //! //! Checks value of VAPOR_PYHONHOME environment variable. If set, //! passes it's value to Py_SetPythonHome(). Otherwise uses GetAppsPath() //! to find the location of Python .so's and calls Py_SetPythonHome() //! with path returned by GetAppsPath(). Finally calls Py_Initialize() // int Initialize(); //! Return python errors as a string //! //! This method can be used to return errors generated by scripts launched //! by the python C API. For example, if a script run by PyRun_SimpleString //! fails and raises an exception this method will return the error string //! generated // string PyErr(); //! Return stdout message as a string // string PyOut(); //! Create a python function object from a script //! //! This method create a python function, named by \p funcName, //! from the Python script \p script. The script \p script must //! contain a python function definition for a function named by //! \p funcName. The function will be defined in the module //! named by \p moduleName. This module must already exist in //! the python environment. //! //! \param[in] moduleName Name of module in which to define //! the function. //! //! \param[in] name of function defined in the script \p script //! //! \param[in] script A string containing a valid python script //! //! \retval pFunc A new PyObject reference to the defined function, //! or NULL if any Python API calls fail // static PyObject *CreatePyFunc(string moduleName, string funcName, string script); private: static MyPython * m_instance; static bool m_isInitialized; static std::string m_pyHome; int pyImport(string lib); int rerouteSTDIO(); MyPython() {} // Don't implement MyPython(MyPython const &); // Don't Implement void operator=(MyPython const &); // Don't implement }; }; // namespace Wasp #endif ================================================ FILE: include/vapor/NavigationUtils.h ================================================ #pragma once #include #include using VAPoR::ControlExec; class GUIStateParams; class AnimationParams; namespace VAPoR { class ViewpointParams; } //! \class NavigationUtils //! \brief This class is just migrated legacy code to de-spaghetti other legacy code. //! (It is not written by me) class RENDER_API NavigationUtils : public Wasp::MyBase { public: static void SetHomeViewpoint(ControlExec *ce); static void UseHomeViewpoint(ControlExec *ce); static void ViewAll(ControlExec *ce); //! Align the view direction to one of the axes. //! axis is 2,3,4 for +X,Y,Z, and 5,6,7 for -X,-Y,-Z static void AlignView(ControlExec *ce, int axis); static void SetAllCameras(ControlExec *ce, const double position[3], const double direction[3], const double up[3], const double origin[3]); static void SetAllCameras(ControlExec *ce, const double position[3], const double direction[3], const double up[3]); static void SetAllCameras(ControlExec *ce, const vector &position, const vector &direction, const vector &up, const vector &origin); static void SetAllCameras(ControlExec *ce, const vector &position, const vector &direction, const vector &up); static void SetAllCameras(ControlExec *ce, const double matrix[16], const double origin[3]); static void SetAllCameras(ControlExec *ce, const vector &matrix, const vector &origin); static void SetAllCameras(ControlExec *ce, const Trackball &trackball); static void ConfigureTrackball(ControlExec *ce, Trackball &trackball); static void LookAt(ControlExec *ce, const vector &position, const vector &target, const vector &up); static void SetTimestep(ControlExec *ce, size_t ts); static void GetCameraProperties(ControlExec *ce, vector *position, vector *direction, vector *up, vector *target); static vector GetCameraPosition(ControlExec *ce); static vector GetCameraDirection(ControlExec *ce); static vector GetCameraUp(ControlExec *ce); static vector GetCameraTarget(ControlExec *ce); static void SetCameraPosition(ControlExec *ce, const vector &v); static void SetCameraDirection(ControlExec *ce, const vector &v); static void SetCameraUp(ControlExec *ce, const vector &v); static void SetCameraTarget(ControlExec *ce, const vector &v); static long GetCurrentTimeStep(ControlExec *ce); static VAPoR::ViewpointParams *GetActiveViewpointParams(ControlExec *ce); static GUIStateParams * GetGUIStateParams(ControlExec *ce); static AnimationParams * GetAnimationParams(ControlExec *ce); private: static void propagateTimestep(ControlExec *ce, size_t ts); static void handleMovingDomainAdjustments(ControlExec *ce, size_t ts_from, size_t ts_to); static std::tuple getDomainExtentsAtTimestep(ControlExec *ce, const std::string &dataset, size_t ts); static glm::vec3 getDomainMovementBetweenTimesteps(ControlExec *ce, std::string dataset, size_t from, size_t to); static std::tuple getRendererExtents(const VAPoR::RenderParams *rp); static void setRendererExtents(const VAPoR::RenderParams *rp, const glm::vec3 &minExts, const glm::vec3 &maxExts); static void movingDomainTrackCamera(ControlExec *ce, size_t from, size_t to); static void movingDomainTrackRenderRegions(ControlExec *ce, size_t from, size_t to); static void movingDomainTrackParticleRenderRegions(ControlExec *ce, size_t from, size_t to); }; ================================================ FILE: include/vapor/NetCDFCFCollection.h ================================================ // // $Id$ // #ifndef _NetCDFCFCollection_h_ #define _NetCDFCFCollection_h_ #include #include #include #include #include #include #include union ut_unit; struct ut_system; namespace VAPoR { // //! \class NetCDFCFCollection //! \brief Wrapper for a collection of netCDF files //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! This class provides access to CF-1 compliant collection of netCDF //! files. This work is based on the "NetCDF Climate and Forecast //! (CF) Metadata Conventions", version 1.6, 5, December 2011. // class VDF_API NetCDFCFCollection : public NetCDFCollection { public: NetCDFCFCollection(); virtual ~NetCDFCFCollection(); virtual int Initialize(const std::vector &files); //! Return boolean indicating whether variable is a CF "coordinate" variable //! //! This method returns true if the variable named by \p var is a //! "coordinate" variable as defined by the CF specification. I.e. //! the variable has a single spatial dimension whose name matches //! \p var name; the variable can be identified as a vertical, lat, lon, //! or time coordinate variable; or the variable is listed by some //! other variable's "coordinate" metadata attribute. //! //! //! \retval true if \p var is a coordinate variable, false otherwise //! //! \sa IsAuxCoordVarCF() // virtual bool IsCoordVarCF(string var) const { return (std::find(_coordinateVars.begin(), _coordinateVars.end(), var) != _coordinateVars.end()); } //! Return boolean indicating whether the named variable is a CF auxiliary //! coordinate variable //! //! This method returns true if the variable named by \p var is a //! "auxiliary coordinate variable" //! //! CF1.X Definition of auxiliary coordinate variable : //! //! Any netCDF variable that contains coordinate data, but is not //! a coordinate variable (in the sense of that term defined by the //! NUG and used by this standard - see below). Unlike coordinate //! variables, there is no relationship between the name of an auxiliary //! coordinate variable and the name(s) of its dimension(s). //! //! \retval true if \p var is an auxliary coordinate variable, false otherwise // virtual bool IsAuxCoordVarCF(string var) const { return (std::find(_auxCoordinateVars.begin(), _auxCoordinateVars.end(), var) != _auxCoordinateVars.end()); } //! Return boolean indicating whether the named variable is a //! NetCDF CF "coordinate" variable or a "auxilliary" coordinate //! variable. //! //! \sa IsAuxCoordVarCF(), IsCoordVarCF() // virtual bool IsCoordinateVar(string varName) const { return (IsCoordVarCF(varName) || IsAuxCoordVarCF(varName)); } //! Return boolean indicating whether the named variable represents //! latitude. //! //! This method returns true if the variable named by \p var is a //! latitude coordinate variable. See section 4.1 of the CF spec. //! //! \retval true if \p var is latitude coordinate variable, false otherwise // virtual bool IsLatCoordVar(string var) const { return (std::find(_latCoordVars.begin(), _latCoordVars.end(), var) != _latCoordVars.end()); } //! Return boolean indicating whether the named variable represents //! longitude. //! //! This method returns true if the variable named by \p var is a //! longitude coordinate variable. See section 4.2 of the CF spec. //! //! \retval true if \p var is longitude coordinate variable, false otherwise // virtual bool IsLonCoordVar(string var) const { return (std::find(_lonCoordVars.begin(), _lonCoordVars.end(), var) != _lonCoordVars.end()); } //! Return boolean indicating whether the named variable represents //! time. //! //! This method returns true if the variable named by \p var is a //! time coordinate variable. See section 4.4 of the CF spec. //! //! \retval true if \p var is a time coordinate variable, false otherwise // virtual bool IsTimeCoordVar(string var) const { return (std::find(_timeCoordVars.begin(), _timeCoordVars.end(), var) != _timeCoordVars.end()); } //! Return boolean indicating whether the named variable represents //! a vertical coordinate. //! //! This method returns true if the variable named by \p var is a //! dimesional or dimensionless vertical coordinate variable. //! See section 4.3 of the CF spec. //! //! \retval true if \p var is a time coordinate variable, false otherwise // virtual bool IsVertCoordVar(string var) const { return (std::find(_vertCoordVars.begin(), _vertCoordVars.end(), var) != _vertCoordVars.end()); } //! Return boolean indicating whether the named variable represents //! a vertical pressure coordinate. //! //! This method returns true if the variable named by \p var is a //! vertical coordinate variable with units of pressure. //! See section 4.3 of the CF spec. //! //! \retval true if \p var is a vertical pressure coordinate variable, //! false otherwise // virtual bool IsVertCoordVarPressure(string var) const; //! Return boolean indicating whether the named variable represents //! a vertical length coordinate. //! //! This method returns true if the variable named by \p var is a //! vertical coordinate variable with units of length (e.g. meters) //! See section 4.3 of the CF spec. //! //! \retval true if \p var is a vertical length coordinate variable, //! false otherwise // virtual bool IsVertCoordVarLength(string var) const; //! Return true if the increasing direction of the named vertical coordinate //! variable is up //! //! CF 1.x description of vertical coordinate direction: //! //! The direction of positive (i.e., the direction in which the coordinate //! values are increasing), whether up or down, cannot in all cases be //! inferred from the units. The direction of positive is useful for //! applications displaying the data. For this reason the attribute //! positive as defined in the COARDS standard is required if the //! vertical axis units are not a valid unit of pressure (a determination //! which can be made using the udunits routine, utScan) -- otherwise //! its inclusion is optional. The positive attribute may have the value //! up or down (case insensitive). //! virtual bool IsVertCoordVarUp(string var) const; //! Return a vector of all latitude coordinate variables //! virtual std::vector GetLatCoordVars() const { return (_latCoordVars); }; //! Return a vector of all longitude coordinate variables //! virtual std::vector GetLonCoordVars() const { return (_lonCoordVars); }; //! Return a vector of all time coordinate variables //! virtual std::vector GetTimeCoordVars() const { return (_timeCoordVars); }; //! Return a vector of all vertical coordinate variables //! virtual std::vector GetVertCoordVars() const { return (_vertCoordVars); }; //! Return a list of data variables with a given rank //! //! Returns a list of data variables having a dimension rank //! of \p ndim. If \p spatial is true only the data variable's spatial //! dimension rank is examined. //! Thus if \p spatial is true, and the named variable is explicitly //! time varying, the //! time-varying dimension is not counted. For example, if a variable //! named 'v' is defined with 4 dimensions in the netCDF file, and the //! slowest varying dimension name matches a named dimension //! specified in Initialize() //! by \p time_dimnames, then the variable 'v' would be returned by a //! query with ndim==3 and spatial==true. //! //! Names of variables that are coordinate or auxiliary coordinate //! variables are not returned, nor are variables that are missing //! coordinate variables. //! //! \param[in] ndim Rank of spatial dimensions //! \param[in] spatial Only compare spatial dimensions against \p ndim //! //! \sa NetCDFCollection::GetVariableNames() // virtual std::vector GetDataVariableNames(int ndim, bool spatial) const; //! //! Return ordered list of coordinate or auxliary coordinate //! variables for the named variable. //! //! This method returns in \p cvars an ordered list of all of the //! spatio-temporal coordinate or auxliary coordinate variables //! associated with the variable named by \p var. See Chapter 5 of //! the CF 1.X spec. for more detail, summarized here: //! //! CF1.X Chap. 5 excerpt : //! //! "The use of coordinate variables is required whenever they are //! applicable. That is, auxiliary coordinate variables may not be //! used as the only way to identify latitude and longitude coordinates //! that could be identified using coordinate variables. This is both //! to enhance conformance to COARDS and to facilitate the use of //! generic applications that recognize the NUG convention for coordinate //! variables. An application that is trying to find the latitude //! coordinate of a variable should always look first to see if any //! of the variable's dimensions correspond to a latitude coordinate //! variable. If the latitude coordinate is not found this way, then //! the auxiliary coordinate variables listed by the coordinates //! attribute should be checked. Note that it is permissible, but //! optional, to list coordinate variables as well as auxiliary //! coordinate variables in the coordinates attribute." //! //! \param[in] varname A variable name //! \param[out] cvars A ordered vector of coordinate variable names //! //! \retval status a negative int is returned if the number of //! elements in \p cvars does not match the number of spatio-temporal //! dimensions of the variable named by \p var // virtual int GetVarCoordVarNames(string var, std::vector &cvars) const; //! Return the value of the 'units' attribute for the named variable //! //! This method fetches the value of the 'units' attribute, if present, //! for the variable named by \p var. If a units attribute is not //! present then \p units will contain an empty string. //! //! \param[in] varname A variable name //! \param[out] units The value of the variable's 'units' attribute. If the //! 'units' attribute is not present the parameter will contain the //! empty string. //! //! \retval status a non-negative int is returned on success //! virtual int GetVarUnits(string var, string &units) const; //! Return a pointer to the internal UDUnits object used to perform //! unit conversion. //! const UDUnits *GetUDUnits() const { return (_udunit); }; //! Convert an array of floating point values from one unit to another //! //! This method uses the UDUnits class to convert an array of floating //! point values from one unit measure to another as supported by //! Unidata's udunits2 library. //! See //! //! \param[in] from A string containing the unit to convert //! from (e.g. "meters") //! \param[in] to A string containing the unit to convert //! to (e.g. "feet") //! \param[in] src An array of input values to be converted //! \param[out] dst An output buffer large enough to contained //! the converted data //! \param[in] n The number of elements in \p src //! //! \retval status a non-negative int is returned on success //! virtual int Convert(const string from, const string to, const double *src, double *dst, size_t n) const; virtual int Convert(const string from, const string to, const float *src, float *dst, size_t n) const; //! Return the missing value, if any, for a variable //! //! This method returns the value of the missing data value marker, //! if defined, for the variable named by \p varname. //! //! Missing data values are indicated using the \c _FillValue, or //! \c missing_value attributes as defined in section 2.5.1 of the CF 1.6 //! spec. //! //! \param[in] varname The variable name //! \param[out] mv The missing value for the variabled name by \p varname //! //! \retval bool The boolean true is returned if a missing value is defined. //! If no missing variable is defined the return value is false and the //! value of \p mv is not defined. //! virtual bool GetMissingValue(string varname, double &mv) const; //! \copydoc NetCDFCollection::OpenRead() //! virtual int OpenRead(size_t ts, string varname); //! Return true if the named variable is a dimensionless vertical //! coordinate variable. //! //! This method returns true if the variable named by \p cvar is both //! a vertical coordinate variable and it is dimensionless. See //! section 4.3.2 of the CF 1.6 spec. //! virtual bool IsVertDimensionless(string cvar) const; //! Get a map projection as a proj4 string //! //! If a variable has a map projection generate a proj4 //! transformation string for converting from geographic to //! Cartographic coordinates. Returns false if no proj4 string //! could be generated: either no map projection exists, or one //! exists but is not supported. // bool GetMapProjectionProj4(string varname, string &proj4string) const; void FormatTimeStr(double time, string &str) const; friend std::ostream &operator<<(std::ostream &o, const NetCDFCFCollection &ncdfc); private: std::vector _coordinateVars; std::vector _auxCoordinateVars; std::vector _lonCoordVars; std::vector _latCoordVars; std::vector _vertCoordVars; std::vector _timeCoordVars; UDUnits *_udunit; // // Map a variable name to it's missing value (if any) // std::map _missingValueMap; std::vector _GetCoordAttrs(const NetCDFSimple::Variable &varinfo) const; int _Initialize(const std::vector &files); //! CF1.X Definition of coordinate variable : //! //! "We use this term precisely as it is defined in section 2.3.1 of the NUG. //! It is a one- dimensional variable with the same name as its //! dimension [e.g., time(time)], and it is defined as a numeric data //! type with values that are ordered monotonically. Missing values are //! not allowed in coordinate variables." // bool _IsCoordinateVar(const NetCDFSimple::Variable &varinfo) const; //! //! CF1.X Determination of a longitude coordinate variable: //! //! "We recommend the determination that a coordinate is a longitude //! type should be done via a string match between the given unit and //! one of the acceptable forms of degrees_east. //! //! Optionally, the longitude type may be indicated additionally by //! providing the standard_name attribute with the value longitude, //! and/or the axis attribute with the value X. //! //! Coordinates of longitude with respect to a rotated pole should be //! given units of degrees, not degrees_east or equivalents, because //! applications which use the units to identify axes would have no //! means of distinguishing such an axis from real longitude, and might //! draw incorrect coastlines, for instance." bool _IsLonCoordVar(const NetCDFSimple::Variable &varinfo) const; //! CF1.X Determination of a latitude coordinate variable: //! //! Hence, determination that a coordinate is a latitude type should //! be done via a string match between the given unit and one of the //! acceptable forms of degrees_north. //! //! Optionally, the latitude type may be indicated additionally by //! providing the standard_name attribute with the value latitude, //! and/or the axis attribute with the value Y //! bool _IsLatCoordVar(const NetCDFSimple::Variable &varinfo) const; //! CF1.X Determination of vertical coordinate variable //! //! A vertical coordinate will be identifiable by: //! //! units of pressure; or //! //! the presence of the positive attribute with a value of up or down //! (case insensitive). //! //! Optionally, the vertical type may be indicated additionally by //! providing the standard_name attribute with an appropriate value, //! and/or the axis attribute with the value Z. //! bool _IsVertCoordVar(const NetCDFSimple::Variable &varinfo) const; //! CF1.X Determination of time coordinate variable //! //! A time coordinate is identifiable from its units string alone. The //! Udunits routines utScan() and utIsTime() can be used to make this //! determination. //! //! Optionally, the time coordinate may be indicated additionally by //! providing the standard_name attribute with an appropriate value, //! and/or the axis attribute with the value T. //! bool _IsTimeCoordVar(const NetCDFSimple::Variable &varinfo) const; bool _GetMissingValue(string varname, string attname, double &mv) const; void _GetMissingValueMap(map &missingValueMap) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/NetCDFCollection.h ================================================ // // $Id: NetCDFCollection.h,v 1.7 2013/05/16 21:39:38 clynejp Exp $ // #ifndef _NetCDFCollection_h_ #define _NetCDFCollection_h_ #include #include #include #include #include #include namespace VAPoR { // //! \class NetCDFCollection //! \brief Wrapper for a collection of netCDF files //! \author John Clyne //! \version $Revision: 1.7 $ //! \date $Date: 2013/05/16 21:39:38 $ //! //! This class treats a collection of netCDF files as a single, //! time-varying data set, providing a unified interface for accessing //! named 0D, 1D, 2D, and 3D spatial variables at a specified timestep, //! independent of which netCDF file contains the data. //! //! The netCDF variables may be "explicitly" time-varying: the slowest //! varying dimension may correspond to time, while the remaining dimensions //! correspond to space. Or the variables may be implicitly time-varying, //! possessing no explicit time dimension, in which case the time index //! of a variable is determined by file ordering. For example, if the //! variable "v" is found in the files "a.nc" and "b.nc" and nowhere else, //! and "a.nc" preceeds "b.nc" in the list of files provided to the class //! constructor, then a.nc is assumed to contain "v" at time step 0, //! and "b.nc" contains "v" at time step 1. //! //! \note The specification of dimensions and coordinates in this class //! follows the netCDF API convention of ordering from slowest //! varying dimension to fastest varying dimension. For example, if //! 'dims' is a vector of dimensions, then dims[0] is the slowest varying //! dimension, dim[1] is the next slowest, and so on. This ordering is the //! opposite of the ordering used by most of the VAPoR API. //! //! Several file organizations are supported and discussed below. To //! ease discussion we introduce the terminology: //! //! define TD : Time Dimension
//! define TCV : Time Coordinate Variable
//! define TVV : an explicitly Time Varying Variable (it has a time //! dimension)
//! define ITVV : an Implicit Time Varying Variable (has no //! time dimension, but has multiple occurences => order determines //! time)
//! define CV: Constant Variable (has no TD, occurs only once). CV variables //! are define for all time steps //! //! Four file organizations are supported as described below: //! //! case 1: No TD specified (therefore no TCV): //! + All variables are ITVV //! + synthesize TCV by order of appearance of variables (file order only) //! + ITVV time derived by order of appearance (file order only). //! + only one time step per variable per file //! //! case 2: TD specified, but no TCV: //! + All variables are TVV or CV //! + synthesize TCV by order of appearance (file order, then TD). //! + multiple time steps per variable per file //! + variables with TD are TVV //! + variables with no TD are CV (available for all time) //! + A CV that occurs multiple times overwrites prior occurence //! (there can be no ITVV variables). //! //! case 3a: TD & TCV specified, TCV appears in only file: //! + All variables are TVV or CV //! + TVVs indexed to time in TCV by order of appearance (file order, TD //! within file) //! + A CV that occurs multiple times overwrites prior occurence //! + Require TCV to appear in first file //! //! case 3b: TD & TCV specified, TCV appears in every file with TVV: //! + Only have TVV and CV variables //! + TVVs indexed to time by TD offset within a file //! + A CV that occurs multiple times overwrites prior occurence //! + Order of file specification is irrelevant (except for multiple //! occurences of CVs of same name) //! class VDF_API NetCDFCollection : public Wasp::MyBase { public: NetCDFCollection(); virtual ~NetCDFCollection(); //! Initialze a new collection //! //! Variables contained in the netCDF files may be explicitly time-varying //! (i.e. have a time dimension defined), or their time step may //! be determined implicitly by which file they are contained in. //! //! The time ordering of time-varying variables is determined by: //! //! 1. A 1D time coordinate variable, if it exists //! 2. A time dimension, if it exists //! 3. The ordering of the files in \p files in which the variable occurs //! //! \param[in] files A list of file containing time-varying 1D, 2D, and //! 3D variables. In the absense of an explicit time dimension, or time //! coordinate variable, the ordering of the files determines the //! the time steps of the variables contained therein. //! //! \param[in] time_dimnames A list of netCDF time dimensions. A variable //! whose slowest varying dimension name matches a name in \p time_dimnames //! is an explict time-varying variable with a time dimension. //! //! \param[in] time_coordvar The name of a coordinate variable containing //! time data. If a 1D variable with a name given by \p time_coordvar exists, //! this variable will be used to determine the time associated with each //! time step of a variable. //! virtual int Initialize(const std::vector &files, const std::vector &time_dimnames, const std::vector &time_coordvar); //! Return a boolean indicating whether a variable exists in the //! data collection. //! //! This method returns true if the variable named by \p varname is //! contained in the data collection. The variable may be present //! inside of a netCDF file, or may be a variable derived the the //! NetCDFCFCollection class. In the latter case all native variables //! used to construct \p varname must also be present. //! //! \param[in] varname A netCDF variable name //! //! \retval bool Returns true if \p varname is contained any one of the //! netCDF files used to instantiate the class, or if \p varname is a //! derived variable. //! //! \sa GetTimes(), GetVariables() // virtual bool VariableExists(string varname) const; //! Return a boolean indicating whether a variable is defined for a //! particular time step. //! //! This method returns true if the variable named by \p varname is //! contained in the data collection and defined for time step \p ts. //! The variable may be present //! inside of a netCDF file, or may be a variable derived the the //! NetCDFCFCollection class. In the latter case all native variables //! used to construct \p varname must also be present. //! //! \param[in] ts A valid data set time step in the range from zero to //! GetNumTimeSteps() - 1. //! \param[in] varname A netCDF variable name //! //! \retval bool Returns true if \p varname is contained any one of the //! netCDF files used to instantiate the class, or if \p varname is a //! derived variable. //! //! \sa GetTimes(), GetNumTimeSteps(), GetVariables() // virtual bool VariableExists(size_t ts, string varname) const; //! Return a list of variables with a given rank //! //! Returns a list of variables having a dimension rank //! of \p ndim. If \p spatial is true only the variable's spatial //! dimension rank is examined. //! Thus if \p spatial is true, and the named variable is explicitly //! time varying, the //! time-varying dimension is not counted. For example, if a variable //! named 'v' is defined with 4 dimensions in the netCDF file, and the //! slowest varying dimension name matches a named dimension //! specified in Initialize() //! by \p time_dimnames, then the variable 'v' would be returned by a //! query with ndim==3 and spatial==true. //! //! \param[in] ndim Rank of dimensions //! \param[in] spatial Only compare spatial dimensions against \p ndim // virtual std::vector GetVariableNames(int ndim, bool spatial) const; //! Return a variable's spatial dimensions //! //! Returns the ordered list of spatial dimensions of the named variable. //! \note The order follows the netCDF convention (slowest varying //! dimension is the first vector element returned), not the VDC //! convention. //! //! \param[in] varname Name of variable //! \retval dims An ordered vector containing the variables spatial //! dimensions. If \p varname is not defined a zero length vector is //! returned //! virtual std::vector GetSpatialDims(string varname) const; //! Return a variable's spatial dimension names //! //! Returns the ordered list of spatial dimension names of the named variable. //! \note The order follows the netCDF convention (slowest varying //! dimension is the first vector element returned), not the VDC //! convention. //! //! \param[in] varname Name of variable //! \retval dimnames An ordered vector containing the variable's spatial //! dimension names. If \p varname is not defined an empty list is returned. //! virtual std::vector GetSpatialDimNames(string varname) const; //! Return a variable's time dimension //! //! Returns time dimension of the named variable. //! //! \param[in] varname Name of variable //! \retval dim Number of time steps (time dimension) //! If \p varname is invalid or \p varname is not //! time varying 0 is returned. //! virtual size_t GetTimeDim(string varname) const; //! Return a variable's time dimension name //! //! Returns the time dimension name of the named variable. //! //! \param[in] varname Name of variable //! \retval name A string containing the variable's time //! dimension name. If \p varname is invalid or \p varname is not //! time varying the empty string is returned. //! virtual string GetTimeDimName(string varname) const; //! Return a variable's temporal and spatial dimensions //! //! Returns the ordered list of temporal and spatial dimensions of the //! named variable. //! \note The order follows the netCDF convention (slowest varying //! dimension is the first vector element returned), not the VDC //! convention. //! //! \param[in] varname Name of variable //! \retval dims An ordered vector containing the variables temporal and //! spatial //! dimensions. If \p varname is not defined a zero length vector is //! returned //! virtual std::vector GetDims(string varname) const; //! Return a variable's temporal and spatial dimension names //! //! Returns the ordered list of temporal and spatial dimension names of //! the named variable. //! \note The order follows the netCDF convention (slowest varying //! dimension is the first vector element returned), not the VDC //! convention. //! //! \param[in] varname Name of variable //! \retval dimnames An ordered vector containing the variable's temporal and //! spatial //! dimension names. If \p varname is not defined an empty list is returned. //! virtual std::vector GetDimNames(string varname) const; //! Return true if variable is time varying //! //! Returns true if the variable named by \p varname has a //! time varying coordinate //! //! \param[in] varname Name of variable // virtual bool IsTimeVarying(string varname) const; //! Return the netCDF external data type a variable //! //! Returns the nc_type of the named variable //! //! \param[in] varname The name of the variable to query. //! //! \retval If a variable named by \p name does not exist, a //! negative value is returned. //! int GetXType(string varname) const; //! Return a list of available attribute's names //! //! Returns a vector of all attribute names for the //! variable, \p varname. If \p varname is the empty string the names //! of all of the global attributes are returned. If \p varname is //! not defined an empty vector is returned. //! //! \param[in] varname The name of the variable to query, //! or the empty string if the names of global attributes are desired. //! \retval attnames A vector of returned attribute names //! // std::vector GetAttNames(string varname) const; //! Return the netCDF external data type for an attribute //! //! Returns the nc_type of the named variable attribute. //! //! \param[in] varname The name of the variable to query, //! or the empty string if the names of global attributes are desired. //! \param[in] name Name of the attribute. //! //! \retval If an attribute named by \p name does not exist, a //! negative value is returned. //! int GetAttType(string varname, string attname) const; //! Return attribute values for attribute of type float //! //! Return the values of the named attribute converted to type float. //! //! \note Attributes of type int are cast to float //! //! \note All attributes with floating point representation of //! any precision are returned by this method. Attributes that //! do not have floating point internal representations can not //! be returned. //! //! \param[in] attname Name of the attribute //! \param[out] values A vector of attribute values // void GetAtt(string varname, string attname, std::vector &values) const; void GetAtt(string varname, string attname, std::vector &values) const; void GetAtt(string varname, string attname, string &values) const; //! Return the names of all the dimensions. //! //! Returns a list of all dimension names defined by all netCDF //! files in the entire collection. The ordering of the returned list //! coresponds to the ordering of the list of dimenension lengths //! returned by GetDims(). I.e. the length of the dimension with //! name GetDimNames()[i] is GetDims[i]. //! //! \retval dimnames A vector containing all //! dimension names. //! //! \sa GetDims() // virtual std::vector GetDimNames() const { return (_dimNames); }; //! Return the lengths of all the dimensions. //! //! Returns a list of all dimension lengths defined by all netCDF //! files in the entire collection. The ordering of the returned list //! coresponds to the ordering of the list of dimenension names //! returned by GetDimNames(). I.e. the length of the dimension with //! name GetDimNames()[i] is GetDims[i]. //! //! \retval dimlens A vector containing all //! dimension lengths. //! //! \sa GetDimNames() // virtual std::vector GetDims() const { return (_dimLens); }; virtual std::vector GetDimsAreTimeVarying() const { return _dimIsTimeVarying; } long GetDimLengthAtTime(string name, long ts); //! Return the number of time steps in the data collection all variables //! //! Return the number of time steps present. The number of time steps //! returned is the number of unique times present, and //! //! \note Not all variables in a collection need have the same number //! of time steps //! //! \param[in] varname Name of variable //! //! \retval value The number of time steps //! // virtual size_t GetNumTimeSteps() const { return (_times.size()); } //! Return the number of time available for the named variable //! //! Return the number of time steps present for the variable //! named by \p varname. //! \note Not all variables in a collection need have the same number //! of time steps //! //! \param[in] varname Name of variable //! //! \retval value The number of time steps. If \p varname is either //! not defined, or is defined but not time varying, 0 is returned. //! // virtual size_t GetNumTimeSteps(string varname) const { return (NetCDFCollection::GetTimeDim(varname)); } //! Return the user time associated with a time step //! //! This method returns the time, in user-defined coordinates, //! associated with the time step, \p ts. //! If no time coordinate variable was specified the user time is //! equivalent to the time step, \p ts. //! //! \param[in] ts A valid data set time step in the range from zero to //! GetNumTimeSteps() - 1. //! //! \param[out] time The user time //! //! \retval retval A negative int is returned on failure. //! // virtual int GetTime(size_t ts, double &time) const; //! Return all the user times associated with a variable //! //! This method returns the times, in user-defined coordinates, //! associated with the the variable, \p varname. //! //! \param[in] varname Name of variable //! \param[times] time A vector of user times ordered by time step //! //! \retval retval A negative int is returned on failure. //! // virtual int GetTimes(string varname, std::vector ×) const; //! Return all the user times for this collection //! //! This method returns the times, in user-defined coordinates, //! for this data collection. //! //! //! \retval retval times A vector of user times. //! //! \sa Initialize() // virtual std::vector GetTimes() const { return (_times); }; //! Return the path to the netCDF file containing a variable //! //! This method returns the path to the netCDF file containing the //! variable \p varname, at the time step \p ts. //! //! \param[in] ts time step of variable //! \param[in] varname Name of variable //! \param[out] file The netCDF file path //! \param[out] local_ts local time index of variable within \p file //! //! \retval retval A negative int is returned on failure. //! // virtual int GetFile(size_t ts, string varname, string &file, size_t &local_ts) const; //! Return the NetCDFSimple::Variable for the named variable //! //! This method copies the contents of the NetCDFSimple::Variable //! class for the named variable into \p varinfo //! //! \param[in] varname Name of variable //! //! \retval retval A negative int is returned on failure. //! virtual int GetVariableInfo(string varname, NetCDFSimple::Variable &varinfo) const; //! Return the missing value, if any, for a variable //! //! This method returns the value of the missing data value marker, //! if defined, for the variable named by \p varname. //! //! \param[in] varname The variable name //! \param[out] mv The missing value for the variabled name by \p varname //! //! \retval bool The boolean true is returned if a missing value is defined. //! If no missing variable is defined the return value is false and the //! value of \p mv is not defined. //! virtual bool GetMissingValue(string varname, double &mv) const; //! Open the named variable for reading //! //! This method prepares a netCDF variable, indicated by a //! variable name and time step pair, for subsequent read operations by //! methods of this class. A small, non-negative integer for use in //! subsequent read operations is returned. //! The file descriptor returned by a //! successful call will be the lowest-numbered file descriptor not //! currently open for the process, starting with zero. //! //! \param[in] ts Time step of the variable to read //! \param[in] varname Name of the variable to read //! //! \retval status Returns a non-negative file descriptor on success //! //! \sa Read(), ReadSlice() //! virtual int OpenRead(size_t ts, string varname); //! Read data from the currently opened variable //! //! Read the hyperslice defined by \p start and \p count from //! the currently opened variable into the buffer pointed to by \p data. //! //! This method is identical in functionality to the netCDF function, //! nc_get_var_float, with the following exception: //! //! //! If the currently //! opened variable is explicitly time-varying (has a time-varying //! dimension), only the spatial dimensions should be provied //! by \p start and \p count. I.e. if the variable contains n dimensions //! in the netCDF file, only the n-1 fastest-varying (spatial) dimensions //! should be specified. //! //! \param[in] start Start vector with one element for each dimension //! \param[in] count Count vector with one element for each dimension //! \param[in] fd A currently opened file descriptor returned by OpenRead(). //! \retval retval A negative int is returned on failure. //! //! \sa NetCDFSimple::Read(), //! SetMissingValueAttName(), SetMissingValueAttName() //! virtual int Read(size_t start[], size_t count[], double *data, int fd = 0); virtual int Read(size_t start[], size_t count[], float *data, int fd = 0); virtual int Read(size_t start[], size_t count[], int *data, int fd = 0); virtual int Read(size_t start[], size_t count[], char *data, int fd = 0); virtual int Read(std::vector start, std::vector count, double *data, int fd = 0); virtual int Read(std::vector start, std::vector count, float *data, int fd = 0); virtual int Read(std::vector start, std::vector count, int *data, int fd = 0); virtual int Read(double *data, int fd = 0); virtual int Read(float *data, int fd = 0); virtual int Read(char *data, int fd = 0); virtual int Read(int *data, int fd = 0); //! Read a 2D slice from a 2D or 3D variable //! //! The method will read 2D slices from a 2D or 3D variable until all //! slices have been processed. //! For 3D data each call to ReadSlice() will return //! a subsequent slice until all slices have been processed. The total //! number of slices is the value of the slowest varying dimension. //! //! \param[in] fd A currently opened file descriptor returned by OpenRead(). //! \param[out] data The possibly resampled 2D data slice. It is the //! caller's responsibility to ensure that \p data points to sufficient //! space. //! //! \retval status Returns 1 if successful, 0 if there are no more //! slices to read, and a negative integer on error. //! //! \sa OpenRead(), Read(), //! SetMissingValueAttName(), SetMissingValueAttName() // virtual int ReadSlice(float *data, int fd = 0); //! Set the variable slice position indicator //! //! This method changes the position of the slice indicator //! for an open variable. Subsequent reads with ReadSlice() //! will position the slice offset based on //! \p offset. If \p whence is 0 then \p offset is added to //! the first variable slice. If \p whence is one then \p offset //! is added to the current slice position. If \p whence is 2 //! then \p offset is added to the last slice. If the resulting slice //! position, after adding \p offset, lies outside of the variable the //! offset will be mapped to the closest valid value (i.e. the first or //! last slice). //! //! \param[in] offset integer slice offset //! \param[in] whence one of 0, 1, 2 //! \param[in] fd A currently opened file descriptor returned by OpenRead(). //! \retval A negative int is returned if \p fd is not valid (an open //! file descriptor) or if \p whence is not one of 0, 1, or 2. // virtual int SeekSlice(int offset, int whence, int fd = 0); //! Close the currently opened variable //! //! \param[in] fd A currently opened file descriptor returned by OpenRead(). //! \sa OpenRead() // virtual int Close(int fd = 0); //! Identify missing value variable attribute name //! //! This method informs the class instance of the name of a netCDF //! variable attribute, if one exists, that contains the missing value //! for the variable. //! //! \param attname Name of netCDF variable attribute specifying the //! missing value // virtual void SetMissingValueAttName(string attname) { _missingValAttName = attname; } //! Return a list of variables that are not available for access //! //! This method returns a list of variables that were detected in the //! collection of netCDF files but are not accessible from the //! NetCDFCollection class. //! virtual std::vector GetFailedVars() const { return (_failedVars); }; friend std::ostream &operator<<(std::ostream &o, const NetCDFCollection &ncdfc); class TimeVaryingVar { public: TimeVaryingVar(); int Insert(const NetCDFSimple *netcdf, const NetCDFSimple::Variable &variable, string file, const std::vector &time_dimnames, const std::map> ×map, int file_org); std::vector GetSpatialDims() const { return (_spatial_dims); }; std::vector GetSpatialDimNames() const { return (_spatial_dim_names); }; string GetName() const { return (_name); }; size_t GetNumTimeSteps() const { return (_time_varying ? _tvmaps.size() : 1); }; string GetTimeDimName() const { return (_time_name); }; int GetTime(size_t ts, double &time) const; std::vector GetTimes() const; int GetTimeStep(double time, size_t &ts) const; size_t GetLocalTimeStep(size_t ts) const; int GetFile(size_t ts, string &file) const; void GetVariableInfo(NetCDFSimple::Variable &variable) const { variable = _variable; } bool GetTimeVarying() const { return (_time_varying); }; bool GetMissingValue(string attname, double &mv) const; void Sort(); friend std::ostream &operator<<(std::ostream &o, const TimeVaryingVar &var); typedef struct { int _fileidx; // Index into _files double _time; // user time for this time step size_t _local_ts; // time step offset within file } tvmap_t; private: NetCDFSimple::Variable _variable; std::vector _files; std::vector _tvmaps; std::vector _spatial_dims; // **spatial** dimensions std::vector _spatial_dim_names; string _time_name; // name of time dimension string _name; // variable name bool _time_varying; // true if variable's slowest varying dimension // is a time dimension. }; protected: bool _GetVariableInfo(string varname, NetCDFSimple::Variable &variable) const; private: std::map _variableList; std::map _ncdfmap; std::vector _dimNames; // Names of all dimensions std::vector _dimLens; // Names of all dimensions std::vector _dimIsTimeVarying; string _missingValAttName; std::map> _timesMap; // map variable to time std::vector _times; // all valid time coordinates std::vector _failedVars; // Varibles that could not be added // // file handle for an open variable // class fileHandle { public: fileHandle(); NetCDFSimple * _ncdfptr; int _fd; // NetCDFSimple open file descriptor size_t _local_ts; int _slice; bool _first_slice; unsigned char *_slicebuf; size_t _slicebufsz; unsigned char *_linebuf; size_t _linebufsz; TimeVaryingVar _tvvars; bool _has_missing; double _missing_value; }; // // Open file data // std::map _ovr_table; void ReInitialize(); int _InitializeTimesMap(const std::vector &files, const std::vector &time_dimnames, const std::vector &time_coordvars, std::map> ×Map, std::map &timeDimLens, std::vector ×, int &file_org) const; int _InitializeTimesMapCase1(const std::vector &files, std::map> ×Map, std::map &timeDimLens) const; int _InitializeTimesMapCase2(const std::vector &files, const std::vector &time_dimnames, std::map> ×Map, std::map &timeDimLens) const; int _InitializeTimesMapCase3(const std::vector &files, const std::vector &time_dimnames, const std::vector &time_coordvars, std::map> ×Map, map &timeDimLens) const; int _GetTimesMap(NetCDFSimple *netcdf, const std::vector &time_coordvars, const std::vector &time_dimnames, std::map> ×map) const; double *_Get1DVar(NetCDFSimple *netcdf, const NetCDFSimple::Variable &variable) const; int _get_var_index(const vector variables, string varname) const; template int _read_template(T *data, int fd); template int _read_template(size_t start[], size_t count[], T *data, int fd); template int _read_slice_template(T *data, int fd); }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/NetCDFCpp.h ================================================ #include #include #include #include #include #include #ifndef _NetCDFCpp_H_ #define _NetCDFCpp_H_ namespace VAPoR { //! \class NetCDFCpp //! \ingroup Public_VDC //! \brief Defines simple C++ wrapper for NetCDF //! //! This class provdies a simple object-oriented wrapper for the NetCDF //! API C language binding. In most cases the member functions provided //! by this class are identical or near identical to the NetCDF API //! functions of the same name. Only when significant differences //! exist between //! the NetCDF native functions and the member functions provided //! herein is anything other than brief documention provided. //! //! The ordering of dimension and coordinate parameters specified //! as arrays or STL vectors follows that of //! NetCDF: The first element is the slowest varying dimension, the //! second element is the next slowest, and so on. \note This ordering //! is the opposite of that used by the VAPoR::VDC class. //! //! One particular difference of note: the various identifiers used //! by NetCDF (e.g. variable id, dimesion id, etc) are not exposed by //! the NetCDFCpp class methods. These objects are instead referred to by //! their ascii string names. Moreover, as the file access methods //! Open() and Create() do not return a NetCDF file identifier, only a single //! NetCDF file may be opened at a time (multiple NetCDF files may be //! opened, if needed, by instantiating multiple NetCDFCpp objects). //! //! Unless otherwise noted the return value of any member function that //! returns an integer may be interpreted as status. A negative value //! indicates an error. Upon error an error message will //! be logged via Wasp::MyBase::SetErrMsg(). // class WASP_API NetCDFCpp : public Wasp::MyBase { public: NetCDFCpp(); virtual ~NetCDFCpp(); //! Create a new NetCDF file //! //! Create an new NetCDF file named by 'path'. Any currently opened //! NetCDF files //! are closed prior to attempting to create the named file // virtual int Create(string path, int cmode, size_t initialsz, size_t &bufrsizehintp); //! Open an existing NetCDF file //! //! Open an existing named file. Any currently opened NetCDF files //! are closed prior to attempting to open the named file // virtual int Open(string path, int mode); //! Define a dimension virtual int DefDim(string name, size_t len) const; //! Define a variable virtual int DefVar(string name, int xtype, vector dimnames); //! Learn the dimension names associated with a variable virtual int InqVarDims(string name, vector &dimnames, vector &dims) const; //! Learn the dimension names and lengths defined in a file // virtual int InqDims(vector &dimnames, vector &dims) const; //! Learn the length of a named dimension virtual int InqDimlen(string name, size_t &len) const; //! Learn the names of all the global or variable attributes // int InqAttnames(string varname, std::vector &attnames) const; //! Copy global or variable attribute //! //! This method copies an attribute from one open netCDF dataset to another. //! It can also be used to copy an attribute from one variable to another //! within the same netCDF. //! //! \param[in] varname_in Name of source variable, empty if global //! \param[in] attname Name of attribute to copy //! \param[in] ncdf_out Destination NetCDF object //! \param[in] varname_out Name of destination variable, empty if global //! int CopyAtt(string varname_in, string attname, NetCDFCpp &ncdf_out, string varname_out) const; // // PutAtt - Integer // //! Write an integer attribute virtual int PutAtt(string varname, string attname, int value) const; virtual int PutAtt(string varname, string attname, vector values) const; virtual int PutAtt(string varname, string attname, const int values[], size_t n) const; // // GetAtt - Integer // //! Read an integer attribute virtual int GetAtt(string varname, string attname, int &value) const; virtual int GetAtt(string varname, string attname, vector &values) const; virtual int GetAtt(string varname, string attname, int values[], size_t n) const; // // PutAtt - size_t // virtual int PutAtt(string varname, string attname, size_t value) const; virtual int PutAtt(string varname, string attname, vector values) const; virtual int PutAtt(string varname, string attname, const size_t values[], size_t n) const; // // GetAtt - size_t // virtual int GetAtt(string varname, string attname, size_t &value) const; virtual int GetAtt(string varname, string attname, vector &values) const; virtual int GetAtt(string varname, string attname, size_t values[], size_t n) const; // // PutAtt - Float // virtual int PutAtt(string varname, string attname, float value) const; virtual int PutAtt(string varname, string attname, vector values) const; virtual int PutAtt(string varname, string attname, const float values[], size_t n) const; // // GetAtt - Float // virtual int GetAtt(string varname, string attname, float &value) const; virtual int GetAtt(string varname, string attname, vector &values) const; virtual int GetAtt(string varname, string attname, float values[], size_t n) const; // // PutAtt - Double // virtual int PutAtt(string varname, string attname, double value) const; virtual int PutAtt(string varname, string attname, vector values) const; virtual int PutAtt(string varname, string attname, const double values[], size_t n) const; // // GetAtt - Double // virtual int GetAtt(string varname, string attname, double &value) const; virtual int GetAtt(string varname, string attname, vector &values) const; virtual int GetAtt(string varname, string attname, double values[], size_t n) const; // // PutAtt - String // virtual int PutAtt(string varname, string attname, string value) const; virtual int PutAtt(string varname, string attname, vector values) const; virtual int PutAtt(string varname, string attname, const char values[], size_t n) const; // // GetAtt - String // virtual int GetAtt(string varname, string attname, string &value) const; virtual int GetAtt(string varname, string attname, char values[], size_t n) const; //! Return a text attribute as a vector of strings //! //! This method attempts to return the value of the named //! text attribute as a vector of words. The value of the //! attribute named by \p attname is tokenized (parsed) using //! white space as a delimeter. The extracted tokens are returned //! in the order of occurence in the vector \p values. // virtual int GetAtt(string varname, string attname, vector &values) const; //! Find the NetCDF ID of a variable virtual int InqVarid(string varname, int &varid) const; //! Return information about a NetCDF attribute virtual int InqAtt(string varname, string attname, nc_type &xtype, size_t &len) const; //! Find a variable's external representation type // virtual int InqVartype(string varname, nc_type &xtype) const; //! Set the fill value virtual int SetFill(int fillmode, int &old_modep); //! End the metadata definition section virtual int EndDef() const; //! Put open netcdf dataset into define mode virtual int ReDef() const; //! Close the currently opened file virtual int Close(); //! Write an array of values to a variable virtual int PutVara(string varname, vector start, vector count, const void *data); virtual int PutVara(string varname, vector start, vector count, const float *data); virtual int PutVara(string varname, vector start, vector count, const double *data); virtual int PutVara(string varname, vector start, vector count, const int *data); virtual int PutVara(string varname, vector start, vector count, const long *data); virtual int PutVara(string varname, vector start, vector count, const unsigned char *data); //! Write an entire variable with one function call virtual int PutVar(string varname, const void *data); virtual int PutVar(string varname, const float *data); virtual int PutVar(string varname, const double *data); virtual int PutVar(string varname, const int *data); virtual int PutVar(string varname, const long *data); virtual int PutVar(string varname, const unsigned char *data); //! Read an array of values from a variable virtual int GetVara(string varname, vector start, vector count, void *data) const; virtual int GetVara(string varname, vector start, vector count, float *data) const; virtual int GetVara(string varname, vector start, vector count, double *data) const; virtual int GetVara(string varname, vector start, vector count, int *data) const; virtual int GetVara(string varname, vector start, vector count, long *data) const; virtual int GetVara(string varname, vector start, vector count, unsigned char *data) const; //! Read an entire variable with one function call virtual int GetVar(string varname, void *data) const; virtual int GetVar(string varname, float *data) const; virtual int GetVar(string varname, double *data) const; virtual int GetVar(string varname, int *data) const; virtual int GetVar(string varname, long *data) const; virtual int GetVar(string varname, unsigned char *data) const; //! Copy a variable from one file to another // virtual int CopyVar(string varname, NetCDFCpp &ncdf_out) const; //! Return the size in bytes of a NetCDF external data type //! static size_t SizeOf(int nctype); //! Return true if file exists and is a valid NetCDF file //! //! Returns true if both the file specified by \p path exists, and //! it can be opened with nc_open(). //! virtual bool ValidFile(string path); //! Returns true if the named dimension is defined //! //! \param[in] dimname A NetCDF dimension name // virtual bool InqDimDefined(string dimname); //! Returns true if the named attribute is defined //! //! \param[in] dimname A NetCDF dimension name // virtual bool InqAttDefined(string varname, string attname); //! Learn the names of the user defined variables present //! //! \param[out] varnames A vector containing the names of all of the //! variables defined in the presently opened NetCDF file. // virtual int InqVarnames(vector &varnames) const; //! Return netCDF ID associated with this object //! int GetNCID() const { return (_ncid); } private: int _ncid; string _path; int _PutVara(string varname, vector start, vector count, const void *data, string func); int _PutVar(string varname, const void *data, string func); int _GetVara(string varname, vector start, vector count, void *data, string func) const; int _GetVar(string varname, void *data, string func) const; }; } // namespace VAPoR #endif // _NetCDFCpp_H_ ================================================ FILE: include/vapor/NetCDFSimple.h ================================================ // // $Id$ // #ifndef _NetCDFSimple_h_ #define _NetCDFSimple_h_ #include #include #include #include namespace VAPoR { // //! \class NetCDFSimple //! \brief NetCDFSimple API interface //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! This class presents a simplified interface for reading netCDF //! data files. //! //! The specification of dimensions and coordinates in this class //! follows the netCDF API convention of ordering from slowest //! varying dimension to fastest varying dimension. For example, if //! 'dims' is a vector of dimensions, then dims[0] is the slowest varying //! dimension, dim[1] is the next slowest, and so on. This ordering is the //! opposite of the ordering used by most of the VAPoR API. // class VDF_API NetCDFSimple : public Wasp::MyBase { public: NetCDFSimple(); virtual ~NetCDFSimple(); //! \class Variable //! \brief NetCDFSimple API interface //! //! A NetCDFSimple data variable // class Variable { public: Variable(); //! Constructor for NetCDFSimple::Variable class //! //! \param[in] varname Name of the netCDF variable //! \param[in] dimnames A vector dimension names, ordered from //! slowest-varying to fastest. //! \param[in] type The netCDF external data type for the variable Variable(string varname, std::vector dimnames, int type); //! Return the variable's name // string GetName() const { return (_name); }; //! Return variable's attribute names //! //! This method returns a vector containing the names of all of the //! attributes associated with this variable // std::vector GetAttNames() const; //! Return variable's dimension names //! //! Returns an ordered list of the variable's netCDF dimension names. //! std::vector GetDimNames() const { return (_dimnames); }; void SetDimNames(const std::vector dimnames) { _dimnames = dimnames; } //! Return the netCDF external data type for an attribute //! //! Returns the nc_type of the named variable attribute. //! \param[in] name Name of the attribute //! //! \retval If an attribute named by \p name does not exist, a //! negative value is returned. // int GetAttType(string name) const; //! Return the netCDF external data type for the variable //! int GetXType() const { return (_type); }; //! Return attribute values for attribute of type float //! //! Return the values of the named attribute converted to type float. //! //! \note Attributes of type int are cast to float //! //! \note All attributes with floating point representation of //! any precision are returned by this method. Attributes that //! do not have floating point internal representations can not //! be returned //! //! \param[in] name Name of the attribute //! \param[out] values A vector of attribute values // void GetAtt(string name, std::vector &values) const; void GetAtt(string name, std::vector &values) const; void GetAtt(string name, string &values) const; //! Set an attribute //! //! Set the floating point attribute, \p name, to the values //! given by \p values // void SetAtt(string name, const std::vector &values) { _flt_atts.push_back(make_pair(name, values)); } void SetAtt(string name, const std::vector &values) { _int_atts.push_back(make_pair(name, values)); } void SetAtt(string name, const string &values) { _str_atts.push_back(make_pair(name, values)); } VDF_API friend std::ostream &operator<<(std::ostream &o, const Variable &var); VDF_API friend bool operator==(const Variable &v1, const Variable &v2) { return ((v1._name == v2._name) && (v1._dimnames == v2._dimnames) && (v1._flt_atts == v2._flt_atts) && (v1._int_atts == v2._int_atts) && (v1._str_atts == v2._str_atts) && (v1._type == v2._type)); } private: string _name; // variable name std::vector _dimnames; // order list of dimension names std::vector>> _flt_atts; std::vector>> _int_atts; std::vector> _str_atts; int _type; // netCDF variable type }; //! Initialize the class instance for a netCDF file //! //! This method initializes (or reinitializes) a class instance with //! the name of a netCDF file //! //! \param[in] path Path to the netCDF file //! //! \retval status A negative int is returned on failure //! virtual int Initialize(string path); //! Open the named variable for reading //! //! This method prepares a netCDF variable //! for subsequent read operations by //! methods of this class. A small, non-negative integer for use in //! subsequent read operations is returned. //! The file descriptor returned by a //! successful call will be the lowest-numbered file descriptor not //! currently open for the process, starting with zero. //! //! \param[in] variable A variable object returned by GetVariables() //! //! \retval status Returns a non-negative file descriptor on success //! //! \sa Read(), GetVariables() //! virtual int OpenRead(const NetCDFSimple::Variable &variable); //! Read an array of values from a variable //! //! The method allows the readying of a hyperslab of data from the //! currently opened variable. //! //! \param[in] start Start vector with one element for each dimension to //! specify a hyperslab //! \param[in] count Count vector with one element for each dimension to //! specify a Hyperslab //! \param[in] fd A currently opened file descriptor returned by OpenRead(). //! \param[out] data A pointer to an area of memory containing sufficent //! space to contain the copied hyperslab. //! //! \retval status A negative int is returned on failure //! //! \sa OpenRead() //! \sa NetCDF documentation for nc_get_vara //! int Read(const size_t start[], const size_t count[], double *data, int fd = 0) const; int Read(const size_t start[], const size_t count[], float *data, int fd = 0) const; int Read(const size_t start[], const size_t count[], int *data, int fd = 0) const; int Read(const size_t start[], const size_t count[], char *data, int fd = 0) const; //! Close the currently opened variable //! //! \param[in] fd A currently opened file descriptor returned by OpenRead(). //! \retval status Returns a non-negative value on success // virtual int Close(int fd = 0); //! Return a vector of the Variables contained in the file //! //! This method returns a vector of Variable objects containing //! the metadata for each variable in the netCDF file //! //! \sa Initialize(), NetCDFSimple::Variable //! const std::vector &GetVariables() const { return (_variables); }; //! Return all dimensions and dimension names defined in the file //! //! This method returns in \p names a vector of all dimension names, //! and in \p dims a vector of all dimension lengths. Thus, for example, //! the lenght of the dimension named by names[i] is given by dims[i] //! //! \params[out] names Vector of dimension names //! \params[out] dims Vector of dimension lengths //! //! \sa Initialize() //! void GetDimensions(std::vector &names, std::vector &dims) const; //! Return the name of the netCDF dimension with a given dimension id //! //! Returns the name of dimension for the netCDF dimension id specified by //! \p id //! //! \param[in] id a valid netCDF dimension ID for the current file //! \retval name Name of the dimension associated with the identifier \p id. //! if \p id is invalid an empty string is returned. //! //! \sa Initialize() // string DimName(int id) const; //! Return the dimension length of the named dimension //! //! Returns the dimension length of the dimension named by //! \p name. If \p name is not recognized as a dimension name //! zero is returned. //! //! \param[in] name a valid netCDF dimension name for the current file //! \retval length Length of the dimension named \p name, or 0 //! if \p name is unknown. //! //! \sa Initialize() // size_t DimLen(string name) const; //! Return the netCDF dimension id for a named dimension //! //! Returns the netCDF dimension id for the named dimension specified by //! \p name //! //! \param[in] name a valid netCDF dimension name for the current file //! \retval id netCDF identifier for the dimension \p name. //! if \p name is invalid a negative int is returned. //! //! \sa Initialize() // int DimId(string name) const; //! Return global attribute names //! //! This method returns a vector of all the global netCDF attributes //! defined in the file //! //! \retval vector A list of global attribute names //! //! \sa Initialize() // std::vector GetAttNames() const; //! Return the netCDF external data type for an attribute //! //! Returns the nc_type of the named global attribute. //! \param[in] name Name of the attribute //! //! \retval If an attribute named by \p name does not exist, a //! negative value is returned. // int GetAttType(string name) const; //! Return global attribute values for attribute of type float //! //! Return the values of the named global attribute converted to type float. //! //! \note Attributes of type int are cast to float //! //! \note All attributes with floating point representation of //! any precision are returned by this method. Attributes that //! do not have floating point internal representations can not //! be returned //! //! \param[in] name Name of the attribute //! \param[out] values A vector of attribute values // void GetAtt(string name, std::vector &values) const; void GetAtt(string name, std::vector &values) const; void GetAtt(string name, string &values) const; //! Determine if a NetCDF nc_type is an int //! //! This static method returns true if \p type is one of the NetCDF's //! \b nc_type: \b NC_BYTE, \b NC_SHORT, \b NC_INT, \b NC_LONG, //! \b NC_UBYTE, \b NC_USHORT, //! \b NC_UINT, \b NC_INT64, or \b NC_UINT64. For all other values //! of \p type //! \b false is returned. //! //! \param[in] type A NetCDF external data type //! \retval bool True if \p type represents an integer data type //! static bool IsNCTypeInt(int type); //! Determine if a NetCDF nc_type is a float //! //! This static method returns true if \p type is one of the NetCDF's //! \b nc_type: \b NC_FLOAT, or \b NC_DOUBLE. For all other values //! of \p type //! \b false is returned. //! //! \param[in] type A NetCDF external data type //! \retval bool True if \p type represents an floating point data type //! static bool IsNCTypeFloat(int type); //! Determine if a NetCDF nc_type is an char //! //! This static method returns true if \p type is one of the NetCDF's //! \b nc_type: \b NC_CHAR. For all other values //! of \p type //! \b false is returned. //! //! \param[in] type A NetCDF external data type //! \retval bool True if \p type represents an char data type //! static bool IsNCTypeText(int type); VDF_API friend std::ostream &operator<<(std::ostream &o, const NetCDFSimple &nc); protected: int _ncid; std::map _ovr_table; // open variable map: fd -> varid string _path; std::vector _dimnames; std::vector _dims; std::vector _unlimited_dimnames; std::vector>> _flt_atts; std::vector>> _int_atts; std::vector> _str_atts; std::vector _variables; int _GetAtts(int ncid, int varid, std::vector>> &flt_atts, std::vector>> &int_atts, std::vector> &str_atts); }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/NonCopyableMixin.h ================================================ #pragma once namespace VAPoR { //! \class NonCopyableMixin //! \ingroup Public_Common //! \brief Mixin class that prevents copying //! \author Stas Jaroszynski //! \version 1.0 //! \date May 2019 //! //! If a class inherits from this class, attempting to copy it will throw //! a compiler error. //! //! This class is used as follows: //! //! class NonCopyableObject : private NonCopyableMixin class NonCopyableMixin { protected: NonCopyableMixin() {} ~NonCopyableMixin() {} private: NonCopyableMixin(const NonCopyableMixin &) = delete; NonCopyableMixin &operator=(const NonCopyableMixin &) = delete; }; }; // namespace VAPoR ================================================ FILE: include/vapor/OSPRay.h ================================================ #pragma once #ifdef BUILD_OSPRAY #include #endif #include #include #include //! \brief OSPRay integration interface and utility functions //! \author Stanislaw Jaroszynski namespace VOSP { RENDER_API int Initialize(int *argc, char **argv); RENDER_API int Shutdown(); RENDER_API std::string Version(); RENDER_API bool IsVersionAtLeast(int major, int minor); #ifdef BUILD_OSPRAY OSPData NewCopiedData(const void *data, OSPDataType type, uint64_t numItems1, uint64_t numItems2 = 1, uint64_t numItems3 = 1); // void LoadTransferFunction(VAPoR::MapperFunction *vtf, OSPTransferFunction otf); OSPTexture OSPDepthFromGLPerspective(float fovy, float aspect, float zNear, float zFar, glm::vec3 cameraDir, glm::vec3 cameraUp, const float *glDepthBuffer, int width, int height); namespace Test { OSPGeometricModel LoadTriangle(glm::vec3 scale = glm::vec3(1.f), const std::string &rendererType = "scivis"); } #endif } // namespace VOSP ================================================ FILE: include/vapor/OpacityMap.h ================================================ //--OpacityMap.h --------------------------------------------------------- // // Copyright (C) 2006 Kenny Gruchalla. All rights reserved. // // Various types of mappings from opacity to data value. // //---------------------------------------------------------------------------- #ifndef OpacityMap_H #define OpacityMap_H #include #include #include #ifdef WIN32 #include #endif namespace VAPoR { class PARAMS_API OpacityMap : public ParamsBase { public: enum Type { CONTROL_POINT, GAUSSIAN, INVERTED_GAUSSIAN, SINE }; //! Create a OpacityMap object from scratch // OpacityMap(ParamsBase::StateSave *ssave); //! Create a OpacityMap object from an existing XmlNode tree // OpacityMap(ParamsBase::StateSave *ssave, XmlNode *node); virtual ~OpacityMap(); void clear(); float opacityDataAtNorm(float nv) const; float opacityData(float value) const; bool inDataBounds(float value) const; void SetType(OpacityMap::Type type); OpacityMap::Type GetType() const { return (OpacityMap::Type)GetValueLong(_typeTag, CONTROL_POINT); } void SetDataBounds(const vector &bounds); vector GetDataBounds() const; double minValue() const; double maxValue() const; void setMinValue(double val); void setMaxValue(double val); bool IsEnabled() { return (GetValueLong(_enabledTag, 0) != 0 ? true : false); } void SetEnabled(bool enabled); double GetMean() const { return GetValueDouble(_meanTag, 0.5); } void SetMean(double mean); double GetSSQ() const { return GetValueDouble(_ssqTag, 0.1); } void SetSSQ(double ssq); double GetFreq() const { return GetValueDouble(_freqTag, 5.0); } void SetFreq(double freq); double GetPhase() const { return GetValueDouble(_phaseTag, 2 * M_PI); } void SetPhase(double phase); int numControlPoints() const { return (int)GetControlPoints().size() / 2; } void addNormControlPoint(float normv, float opacity); // Normalized Coords void addControlPoint(float value, float opacity); // Data Coordinates void deleteControlPoint(int index); void moveControlPoint(int index, float dx, float dy); // Data Coordinates float controlPointOpacity(int index) const; void controlPointOpacity(int index, float opacity); float controlPointValueNormalized(int index) const; float controlPointValue(int index) const; // Data Coordinates void controlPointValueNormalized(int index, float nv); void controlPointValue(int index, float value); // Data Coordinates void setOpaque(); bool isOpaque() const; void SetInterpType(TFInterpolator::type t); TFInterpolator::type GetInterpType() const { return (TFInterpolator::type)GetValueLong(_interpTypeTag, TFInterpolator::linear); } vector GetControlPoints() const; void SetControlPoints(const vector &opacityControlPoints); // Get static string identifier for this params class // static string GetClassType() { return ("OpacityMapParams"); } private: int leftControlIndex(float val) const; double normSSq(double ssq); double denormSSq(double ssq); double normSineFreq(double freq); double denormSineFreq(double freq); double normSinePhase(double phase); double denormSinePhase(double phase); const double _minSSq; const double _maxSSq; const double _minFreq; const double _maxFreq; const double _minPhase; const double _maxPhase; static const string _relMinTag; static const string _relMaxTag; static const string _enabledTag; static const string _meanTag; static const string _ssqTag; static const string _freqTag; static const string _phaseTag; static const string _typeTag; static const string _controlPointsTag; static const string _interpTypeTag; static const string _opacityMapIndexTag; static const string _dataBoundsTag; }; }; // namespace VAPoR #endif // OpacityMap_H ================================================ FILE: include/vapor/OpenMPSupport.h ================================================ #ifndef OPENMPSUPPORT_H #define OPENMPSUPPORT_H #ifdef USE_OMP #include #else #define omp_get_num_threads() (1) #define omp_set_num_threads(x) (void(x)) #define omp_get_thread_num() (0) #endif #endif ================================================ FILE: include/vapor/OptionParser.h ================================================ // // $Id$ // //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: Wed Oct 6 10:49:44 MDT 2004 // // Description: A class for parsing command line options. This // class manages a resource data base of valid command line // options. Valid options may be merged into the data base // at any time and later extracted with their // coresponding values as determined by the command line. // // #ifndef _OptionParser_h_ #define _OptionParser_h_ #include #include #include #include #include #ifdef WIN32 // Silence an annoying and unnecessary compiler warning #pragma warning(disable : 4251) #endif using namespace std; namespace Wasp { // // class COMMON_API OptionParser : public MyBase { public: //! An option description record (odr) // //! A structure for descriping an option //! \param option The name of the option //! \param arg_count Number of arguments expected by the option //! \param value Option's default value //! \param help A C string containing a help message for the option // typedef struct _OptDescRec { const char *option; int arg_count; const char *value; const char *help; } OptDescRec_T; // // structure for returning the value of an option // typedef struct _DPOption { const char *option_name; // the options name // // option type converter // int (*type_conv)(const char *from, void *to); void *offset; // offset of return address int size; // size of option in bytes } Option_T; typedef struct _EnvOpt { const char *option; // option name const char *env_var; // coresponding enviroment var } EnvOpt_T; typedef int Boolean_T; typedef struct Dimension2D_ { int nx, ny; } Dimension2D_T; typedef struct Dimension3D_ { int nx, ny, nz; } Dimension3D_T; // Converter type for CvtToIntRange() // typedef struct IntRange_ { int min, max; } IntRange_T; OptionParser(); ~OptionParser(); //! Append a list of option descriptions // //! Append a list of option descriptions. The input option //! descriptor records are appended to the current list of option //! description records. //! \param[in] odr A null-terminated option descriptor record. //! \sa ParseOptions(), RemoveOptions() // int AppendOptions(const OptDescRec_T *odr); //! Parse a command line argument vector // //! Destrutively parse a command line argument vector against //! the option descriptor records (odr) supplied by previous invocations //! of \b AppendOptions(). Command line arguments that match option //! names in the odr and the input option table are //! \param[in,out] argc A pointer to a count of the number of elements //! in \b argv //! \param[in,out] argv A null-terminated vector of command line arguments //! \param[in,out] opts A null-terminated option table //! \sa ParseOptions(), RemoveOptions() int ParseOptions(int *argc, char **argv, Option_T *opts); int ParseOptions(const EnvOpt_T *envv, Option_T *opts); void RemoveOptions(std::vector options); void PrintOptionHelp(FILE *fp, int linelimit = 80, bool docopyright = true); typedef struct _OptRec { const char *option; // name of option without preceeding '-' const char *value; // current val for the argument const char *default_value; // default val for the argument const char *help; // help string for option int arg_count; // num args expected by option } _OptRec_T; private: vector _optTbl; _OptRec_T *_get_option(const char *name); int _parse_options(const Option_T *opts); friend bool opt_cmp(OptionParser::_OptRec_T *a, OptionParser::_OptRec_T *b); }; COMMON_API int CvtToInt(const char *from, void *to); COMMON_API int CvtToFloat(const char *from, void *to); COMMON_API int CvtToDouble(const char *from, void *to); COMMON_API int CvtToChar(const char *from, void *to); COMMON_API int CvtToBoolean(const char *from, void *to); COMMON_API int CvtToString(const char *from, void *to); COMMON_API int CvtToCPPStr(const char *from, void *to); COMMON_API int CvtToDimension2D(const char *from, void *to); COMMON_API int CvtToDimension3D(const char *from, void *to); // convert a colon delimited ascii string to vector of C++ // STL strings: (vector *) // COMMON_API int CvtToStrVec(const char *from, void *to); // convert a colon delimited ascii string to vector of C++ // STL ints: (vector *) // COMMON_API int CvtToIntVec(const char *from, void *to); // convert a colon delimited ascii string to vector of C++ // STL size_t: (vector *) // COMMON_API int CvtToSize_tVec(const char *from, void *to); // convert a colon delimited ascii string to vector of C++ // STL ints: (vector *) // COMMON_API int CvtToFloatVec(const char *from, void *to); COMMON_API int CvtToDoubleVec(const char *from, void *to); // Convert a colon-delimited pair of integers to a IntRange_T type // COMMON_API int CvtToIntRange(const char *from, void *to); }; // namespace Wasp #endif ================================================ FILE: include/vapor/PNGWriter.h ================================================ #pragma once #include "vapor/ImageWriter.h" namespace VAPoR { class RENDER_API PNGWriter : public ImageWriter { protected: public: PNGWriter(const string &path); ~PNGWriter(){}; static std::vector GetFileExtensions(); int Write(const unsigned char *buffer, const unsigned int width, const unsigned int height); }; } // namespace VAPoR ================================================ FILE: include/vapor/PVTime.h ================================================ // // $Id$ // //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ #ifndef _PVTime_h_ #define _PVTime_h_ #include #include #include #ifndef WIN32 #include #endif #include #ifndef TIME64_T #ifdef WIN32 #define TIME64_T __int64 #else #define TIME64_T int64_t #endif #endif using namespace std; namespace Wasp { COMMON_API TIME64_T MkTime64(struct tm *t); COMMON_API struct tm *LocalTime64_r(const TIME64_T *t, struct tm *p); COMMON_API struct tm *GmTime64_r(const TIME64_T *t, struct tm *p); }; // namespace Wasp #endif // _PVTime_h_ ================================================ FILE: include/vapor/ParamsBase.h ================================================ //************************************************************************ // * // Copyright (C) 2008 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: ParamsBase.h // // Author: John Clyne, modified by Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: March 2008 // // Description: // Defines the ParamsBase class // This is an abstract class for classes that rely on // accessing an XML node for get/set // #ifndef ParamsBase_H #define ParamsBase_H #include "vapor/VAssert.h" #include #include #include #define PARAMS_IMPL_TAG(class, tag) const std::string class::tag = #tag; namespace VAPoR { // //! \class ParamsBase //! \brief Nodes with state in Xml tree representation //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! This is pure abstract base class that may be derived for //! to maintain parameter state information in a manner that //! supports session save/restore and undo/redo operations. All //! session state is maintained in an XML tree that may be //! written to a file and subsequently used to reinitialize ParamsBase //! class objects. //! //! class PARAMS_API ParamsBase : public Wasp::MyBase { public: //! \class StateSave //! \brief State capture class //! //! A class for capturing state changes. A pointer to an //! instance of this class is passed to the ParamsBase constructor. //! Any changes to the ParamsBase are recorded to StateSave by //! calling StateSave::Save() with the effected node and //! a description of the change. It is expected that users of ParamsBase //! will re-implement StateSave to suit their own needs // class StateSave { public: //! Capture current state //! //! If the value of GetSaveState() is true this method is called prior //! to making any changes to the internal state //! virtual void Reinit(const XmlNode *rootNode) {} virtual void Save(const XmlNode *node, string description) {} virtual void BeginGroup(string description) {} virtual void EndGroup() {} virtual void IntermediateChange() {} virtual void SetEnabled(bool onOff) {} virtual bool GetEnabled() const { return (false); } virtual void SetUndoEnabled(bool b) {} virtual bool GetUndoEnabled() const { return false; } }; // NO DEFAULT CONSTRUCTOR // // ParamsBase(); //! Create a ParamsBase object from scratch //! //! \param[in] ssave StateSave class object that will be used to record //! state changes made to this class. //! //! \param[in] classname The string identifier associated with a //! derived class that will be used to create new instances of that //! class via the ParamsFactory factory object. //! ParamsBase(StateSave *ssave, const string &classname); //! Create a ParamsBase object from an existing XmlNode tree //! //! This method will construct a ParamsBase object using an //! existing XML tree. Hence it should NOT do any initialization //! that changes parameter values. // ParamsBase(StateSave *ssave, XmlNode *node); //! Copy constructor. ParamsBase(const ParamsBase &rhs); ParamsBase &operator=(const ParamsBase &rhs); //! Explicit delete the two flavors of move constructor, //! so they ain't called accidentally. ParamsBase(ParamsBase &&) = delete; ParamsBase &operator=(ParamsBase &) = delete; //! Equivalence operator // bool operator==(const ParamsBase &rhs) const { return (_ssave == rhs._ssave && *_node == *(rhs._node)); } bool operator!=(const ParamsBase &rhs) const { return (!(*this == rhs)); }; //! Destroy object //! //! Destroys all resources except possibly the XmlNode and //! its children associated //! with this object. If this objects node is a root node (i.e. has //! no parent) the node is freed. Otherwise it is not. //! virtual ~ParamsBase(); //! Set parent //! //! This method sets the parent of the ParamsBase class to //! \p parent, modifying both this class instance and the parent //! //! \param[in] parent A pointer to a parent ParamsBase class . If //! NULL the class will become parentless // void SetParent(ParamsBase *parent); XmlNode *GetNode() const { return _node; } void BeginGroup(const string &description) { _ssave->BeginGroup(description); } void EndGroup() { _ssave->EndGroup(); } void IntermediateChange() { _ssave->IntermediateChange(); } virtual vector GetValueLongVec(const string tag) const; virtual vector GetValueLongVec(const string tag, const vector &defaultVal) const; virtual long GetValueLong(const string tag, long defaultVal) const; virtual vector GetValueDoubleVec(const string tag) const; virtual vector GetValueDoubleVec(const string tag, const vector &defaultVal) const; virtual double GetValueDouble(const string tag, double defaultVal) const; virtual vector GetValueStringVec(const string tag) const; virtual vector GetValueStringVec(const string tag, const vector &defaultVal) const; virtual string GetValueString(const string tag, string defaultVal) const; virtual void SetValueLongVec(const string &tag, string description, const vector &values); virtual void SetValueLong(const string &tag, string description, long value); virtual void SetValueDoubleVec(const string &tag, string description, const vector &values); virtual void SetValueDouble(const string &tag, string description, double value); virtual void SetValueStringVec(const string &tag, string description, const vector &values); virtual void SetValueString(const string &tag, string description, const string &value); //! //! Method for obtaining the name and/or tag associated with the instance //! string GetName() const { VAssert(_node); return (_node->Tag()); } protected: ParamsBase(StateSave *ssave); //! Delete the named branch. //! //! This method deletes the named child, and all decendents, of the current //! destroying it's contents in the process. The //! named node must be a child of the current node. If the named node //! does not exist the result is a no-op. //! //! \param[in] name The name of the branch // void Remove(const string &name); //! Return the attributes associated with the current branch //! //! \retval map attribute mapping // const map &GetAttributes(); //! Remove (undefine) all parameters //! //! This method deletes any and all paramters contained in the base //! class as well as deleting any tree branches. // void Clear(); protected: StateSave *_ssave; XmlNode * _node; }; ////////////////////////////////////////////////////////////////////////// // // ParamsSeparator Class // ///////////////////////////////////////////////////////////////////////// class PARAMS_API ParamsSeparator : public ParamsBase { public: ParamsSeparator(StateSave *ssave, const string &name); ParamsSeparator(StateSave *ssave, XmlNode *node); ParamsSeparator(ParamsSeparator *parent, const string &name); virtual ~ParamsSeparator() {} bool HasChild(const string &name) { return (GetNode()->HasChild(name)); } }; ////////////////////////////////////////////////////////////////////////// // // ParamsFactory Class // ///////////////////////////////////////////////////////////////////////// class PARAMS_API ParamsFactory { public: static ParamsFactory *Instance() { static ParamsFactory instance; return &instance; } void RegisterFactoryFunction(string name, function classFactoryFunction) { // register the class factory function m_factoryFunctionRegistry[name] = classFactoryFunction; } ParamsBase *(CreateInstance(string classType, ParamsBase::StateSave *, XmlNode *)); vector GetFactoryNames() const; private: map> m_factoryFunctionRegistry; ParamsFactory() {} ParamsFactory(const ParamsFactory &) {} ParamsFactory &operator=(const ParamsFactory &) { return *this; } }; ////////////////////////////////////////////////////////////////////////// // // ParamsRegistrar Class // // Register ParamsBase derived class with: // // static ParamsRegistrar registrar("myclassname"); // // where 'ParamsClass' is a class derived from 'ParamsBase', and // "myclassname" is the name of the class // ///////////////////////////////////////////////////////////////////////// template class ParamsRegistrar { public: ParamsRegistrar(string classType) { // register the class factory function // ParamsFactory::Instance()->RegisterFactoryFunction(classType, [](ParamsBase::StateSave *ssave, XmlNode *node) -> ParamsBase * { if (node) return new T(ssave, node); else return new T(ssave); }); } }; ////////////////////////////////////////////////////////////////////////// // // ParamsContainer Class // ///////////////////////////////////////////////////////////////////////// // // The ParamsContainer class constructs an XML tree as depicted below, // where 'Container Name' is the root of XML tree, and is the name // passed into the constructor as 'myname'; 'Class Name' is the name of // the derived ParamsBase class used to construct new instances of // the derived class; and 'ele name x' is the unique name of the element // contained in the container. // /* |----------------| | Container Name | |----------------| | \|/ |----------------| | Class Name | |----------------| | \ \|/ \ |----------------| \ |----------------| | ele name 1 |....| ele name n | |----------------| |----------------| */ class PARAMS_API ParamsContainer : public Wasp::MyBase { public: ParamsContainer(ParamsBase::StateSave *ssave, const string &myname); ParamsContainer(ParamsBase::StateSave *ssave, XmlNode *node); //! Copy constructor. ParamsContainer(const ParamsContainer &rhs); ParamsContainer &operator=(const ParamsContainer &rhs); //! Destroy object //! //! Destroys all resources except possibly the XmlNode associated //! with this object. If this object's node is a root node (i.e. has //! no parent) the node is freed. Otherwise it is not //! virtual ~ParamsContainer(); //! Set parent //! //! This method sets the parent of the ParamsBase class to //! \p parent, modifying both this class instance and the parent //! //! \param[in] parent A pointer to a parent ParamsBase class . If //! NULL the class will become parentless // void SetParent(ParamsBase *parent) { GetNode()->SetParent(parent->GetNode()); } ParamsBase *Insert(ParamsBase *pb, string name); ParamsBase *Create(string classType, string name); void Remove(string name); void Remove(const ParamsBase *pb) { Remove(GetParamsName(pb)); } ParamsBase *GetParams(string name) const; string GetParamsName(const ParamsBase *pb) const; vector GetNames() const; size_t Size() const { return (_elements.size()); } XmlNode *GetNode() const { return _separator->GetNode(); } private: ParamsBase::StateSave *_ssave; // XmlNode *_node; ParamsSeparator * _separator; map _elements; }; }; // End namespace VAPoR #endif // ParamsBase_H ================================================ FILE: include/vapor/ParamsMgr.h ================================================ //************************************************************************ // * // Copyright (C) 2016 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: ParamsMgr.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: February 2016 // // Description: Defines the ParamsMgr class. // This provides an API for manipulating the Params Objects that are used in VAPOR applications // #ifndef PARAMSMGR_H #define PARAMSMGR_H #include "vapor/VAssert.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace VAPoR { //! //! //! \class ParamsMgr //! \ingroup Public_Params //! \brief A singleton class for managing Params instances //! //! \author Alan Norton //! \version 3.0 //! \date February 2016 //! //! class PARAMS_API ParamsMgr : public MyBase { public: //! ParamsMgr constructor //! //! \param[in] appParamsNames A vector of unique ParamsBase class //! names previously //! registered with ParamsRegistrar(). The ParamsMgr will construct //! these application-defined classes as needed. //! If any of the class names in \p appParamsNames were not //! previously registered via ParamsRegistrar() they will be ignored. //! //! \param[in] appRenderParamsNames A vector of unique RenderParams class //! names previously //! registered with RenParamsRegistrar(). The ParamsMgr will construct //! these application-defined render params classes as needed. //! If any of the class names in \p appRenderParamsNames were not //! previously registered via RenParamsRegistrar() they will be ignored. //! //! \sa ParamsRegistrar() // ParamsMgr(std::vector appParamNames = std::vector(), std::vector appRenderParamNames = std::vector()); //! Destroy object //! virtual ~ParamsMgr(); //! Load the default state //! //! This method resets the entire parameter state to the default values. // virtual void LoadState(); //! Load the parameter state from an XmlNode tree //! //! This method resets the entire parameter state to the state specified //! by the XmlNode tree whose root is \p node. Any unrecognized nodes //! in \p node will be ignored. // virtual void LoadState(const XmlNode *node); //! Load the parameter state from a file //! //! This method resets the entire parameter state to the state specified //! by the file named by \p stateFile. Any unrecognized nodes //! in \p stateFile will be ignored. // virtual int LoadState(string stateFile); //! Add a DataMgr to the ParamsMgr class //! //! This method associates a data set name \p dataSetName with a //! DataMgr \p dataMgr. Methods on this class that take a data set //! name as an argument can not be invoked until the data set name is //! bound to a DataMgr instance. //! void AddDataMgr(string dataSetName, DataMgr *dataMgr); //! Remove a previously created Window instance //! //! \param [in] winName Window name to remove // void RemoveVisualizer(string winName); //! Remove a DataMgr instance previously. //! //! This method removes the association of a DataMgr instance with //! the data set name \p dataSetName, previously made by AddDataMgr() //! void RemoveDataMgr(string dataSetName); //! Return list of all DataMgr names //! //! Return a list of all DataMgr names bound with AddDataMgr() // vector GetDataMgrNames() const; //! Create a new ViewpointParams instances //! //! This method will create a new ViewpointParams instance //! //! \param [in] winName Window name to associate the new RenderParams //! object with. //! //! \retval ptr Returns the name of the newly created object. //! //! \sa RenParamsRegistrar, RenParamsFactory //! GetRenderParams() // string CreateVisualizerParamsInstance(string winName = "__AUTO__"); //! Remove a previously created ViewpointParams instance //! //! \param [in] winName Window name to remove // void RemoveVisualizerParamsInstance(string winName); //! Create a new rendering params instances //! //! This method will create a new instance of an object derived //! from the RenderParams class. The object will be created with //! the RenParamsFactory and its type must have been //! registered with RenParamsRegistrar. The new RenderParams //! instance will be associated with the window named by \p winName. //! //! \param [in] winName Window name to associate the new RenderParams //! object with. //! \param [in] classType Class name used to register the derived RenderParams //! object with. //! \param [in] instName Name to associate with the new object. //! //! \retval ptr Returns a pointer to the newly created object on success, //! and NULL on failure. This method will fail if the data set //! \p dataSetName was not previously bound with AddDataMgr() //! exist, or if \p classType does not refer to a valid RenderParams //! derived class. //! //! \sa RenParamsRegistrar, RenParamsFactory, AddDataMgr(), //! GetRenderParams(), AddDataMgr() //! \sa RemoveRenderParamsInstance() // RenderParams *CreateRenderParamsInstance(string winName, string dataSetName, string classType, string instName); //! Create a render params instance from an existing one //! //! Copies the RenderParams instance \p rp into the hierarchy and //! associates it with the visualizer \p winName and gives it the name //! \p instName. If a RenderParams instance is already associated with //! \p winName and \p instName the existing RenderParams instance is //! destroyed. //! //! \param[in] winName Window name to associate the new RenderParams //! object with. //! \param[in] instName Name to associate with the new object. //! \param[in] rp Pointer to a valid RenderParams instance to insert //! //! \retval pointer Pointer to the newly created RenderParams instance // RenderParams *CreateRenderParamsInstance(string winName, string dataSetName, string instName, const RenderParams *rp); //! Remove a previously created RenderParams instance //! //! This method removes from the session state a previously created //! RenderParams instance. If the identified RenderParams instance //! does not exist this method is a no-op. //! //! \params [in] winName Window name that the RenderParams instance is //! associated with. //! \param [in] classType Class name used to register the derived RenderParams //! object with. //! \param [in] instName Name associated with the object to destroy. //! //! \sa RenParamsRegistrar, RenParamsFactory //! GetRenderParams() //! \sa CreateRenderParamsInstance() // void RemoveRenderParamsInstance(string winName, string dataSetName, string classType, string instName); //! Return a previously created RenderParams instance //! //! This method returns from the session state a previously created //! RenderParams instance. If the identified RenderParams instance //! does not exist this A NULL is returned, but no error is generated. //! //! \params [in] winName Window name that the RenderParams instance is //! associated with. //! \param [in] classType Class name used to register the derived RenderParams //! object with. //! \param [in] instName Name associated with the object to destroy. //! //! \sa RenParamsRegistrar, RenParamsFactory, AddDataMgr(), //! GetRenderParams() //! \sa CreateRenderParamsInstance() //! //! \retval ptr If the identified RenderParams instance exists in the //! session state it is returned, otherwise NULL is returned. The latter //! case does not generate an error // RenderParams *GetRenderParams(string winName, string dataSetName, string classType, string instName) const; void GetRenderParams(string winName, string dataSetName, vector &rParams) const; void GetRenderParams(string winName, vector &rParams) const; void GetRenderParams(vector &rParams) const; //! Return all render param instance names //! //! Return all of the RenderParam instance names associated with //! the visualizer (window) named \p winName, the data set named //! \p dataSetName, and the Params class type \p classType //! //! The returned names are guaranteed to be unique. //! void GetRenderParamNames(string winName, string dataSetName, string classType, vector &instNames) const; void GetRenderParamNames(string winName, string dataSetName, vector &instNames) const; void GetRenderParamNames(string winName, vector &instNames) const; void GetRenderParamNames(vector &instNames) const; vector GetRenderParamNames() const; vector GetRenderParamNamesForDataset(string datasetName) const; //! Lookup window, data set, and class name from a render instance name //! //! This method returns the window name \p winName, data set name //! \p dataSetName, and render params type \p className that are associated //! with the render instance name \p instName. //! //! \retval status True on success, false if \p instName is not a previously //! defined render instance name //! //! \sa CreateRenderParamsInstance // bool RenderParamsLookup(string instName, string &winName, string &dataSetName, string &className) const; bool RenderParamsLookup(RenderParams* inst, string &instName, string &winName, string &dataSetName, string &className) const; //! Returns all defined window (aka visualizer names). //! //! This method will return all defined window names in the session state //! //! \retval names A vector of window names, possibly an empty vector if //! none exist. //! //! \sa CreateRenderParamsInstance() // vector GetVisualizerNames() const; //! Returns renderer types (aka class names) defined for window \p winName //! //! This method returns a list of all RenderParams types associated //! with the window \p winName in the session state //! //! \sa CreateRenderParamsInstance() //! \sa RenParamsRegistrar, RenParamsFactory // vector GetRenderParamsClassNames(string winName) const; //! Returns renderer types (aka class names) defined for window \p winName //! associated with a data set named by \p dataSetName. //! This method returns a list of all RenderParams types associated //! with the window \p winName in the session state //! //! \sa CreateRenderParamsInstance() //! \sa RenParamsRegistrar, RenParamsFactory // vector GetRenderParamsClassNames(string winName, string dataSetName) const; //! Returns available renderer types (aka class names) //! //! This method returns a list of all registered RenderParams types //! (class names) //! //! \sa CreateRenderParamsInstance() //! \sa RenParamsRegistrar, RenParamsFactory // static vector GetRenderParamsClassNamesAvail() { return (RenParamsFactory::Instance()->GetFactoryNames()); } //! Returns renderer instance names defined on window \p winName for //! renderer type \p classname //! //! This method returns the instance names of all RenderParams of //! type \p classType that are associated with the window \p winName //! in the current session state. //! //! \sa CreateRenderParamsInstance() //! \sa RenParamsRegistrar, RenParamsFactory // vector GetRenderParamInstances(string winName, string dataSetName, string classType) const; vector GetRenderParamInstances(string winName, string classType) const; //! Obtain the ViewpointParams that are applicable in a particular Visualizer //! window. //! //! Return the ViewpointParams instance associated with the //! window named by \p winName in the current session state //! //! \retval ptr ViewpointParams instance that is applicable. // ViewpointParams *GetViewpointParams(string winName) const; //! Obtain the RegionParams that are applicable in a particular Visualizer //! window. //! //! Return the RegionParams instance associated with the //! window named by \p winName in the current session state //! //! \retval ptr RegionParams instance that is applicable. // RegionParams *GetRegionParams(string winName) const { return ((RegionParams *)_otherParams->GetParams(RegionParams::GetClassType())); }; //! Obtain the AnnotationParams that are applicable in a particular Visualizer //! window. //! //! Return the AnnotationParams instance associated with the //! window named by \p winName in the current session state //! //! \retval ptr AnnotationParams instance that is applicable. // AnnotationParams *GetAnnotationParams(string winName) const { return ((AnnotationParams *)_otherParams->GetParams(AnnotationParams::GetClassType())); }; //! Obtain the DatasetsParams that are applicable in a particular Visualizer //! window. //! //! \retval ptr DatasetsParams instance that is applicable. // DatasetsParams *GetDatasetsParams() const { return ((DatasetsParams *)_otherParams->GetParams(DatasetsParams::GetClassType())); }; //! Optain any paramers registered by the application //! //! This method returns params that have been registered on the //! ParamsMgr via the constructor //! //! \retval params Pointer to requested params on success, or NULL //! on failure. Fails if \p classType was not registred with //! the constructor or ParamsRegistrar //! //! \sa ParamsMgr() // ParamsBase *GetParams(string classType) const { return (_otherParams->GetParams(classType)); } // template T> T* GetParams() const template T* GetParams() const { return (T*)GetParams(T::GetClassType()); } //! Optain any render paramers registered by the application //! //! This method returns params that have been registered on the //! ParamsMgr via RegisterAppParams() for the data set named //! by \p dataSetName; //! //! \param[in] dataSetName //! \param[in] classType //! //! \retval params Pointer to requested params on success, or NULL //! on failure. Fails if \p classType was not registred with //! the constructor or RenParamsRegistrar //! //! //! \sa ParamsMgr() // RenderParams *GetAppRenderParams(string dataSetName, string classType) { std::map::const_iterator itr; itr = _otherRenParams.find(dataSetName); return (itr != _otherRenParams.cend() ? itr->second->GetParams(classType) : NULL); } //! Optain any render paramers registered by the application for a given data set //! //! This method returns params that have been registered on the //! ParamsMgr via RegisterAppParams() for the data set named //! by \p dataSetName; //! //! \param[in] dataSetName //! \param[out] appRenderParams a vector of application render params associated with \p dataSetName //! //! \sa ParamsMgr() // void GetAppRenderParams(string dataSetName, vector &appRenderParams) const; //! Save current state to a file //! //! Save the current state of the parameter database to an XML file //! //! \param[in] path Path to file // int SaveToFile(string path) const; // const DataMgr *GetDataMgr() const {return (_dataMgr);} //! Begin state save group //! //! Changes in state can be undone (redone) one at a time using //! Undo() and Redo(), or can be grouped to together into a collection. //! This method announces the start of such a collection group. The group //! will be completed when EndSaveStateGroup() is called. //! When a subsequent call //! to Undo() or Redo() is made all of the state changes made within the //! group are undone (redone) at once. Groups may be nested, in //! which case the outermost group prevails. //! //! \param[in] description A descriptive name for the group //! //! \sa EndSaveStateGroup() //! void BeginSaveStateGroup(string description) { _ssave.BeginGroup(description); } //! End state save group //! \sa BeginSaveStateGroup() // void EndSaveStateGroup() { _ssave.EndGroup(); }; //! Call callbacks registered for intermediate changes. These are changes inside of Save State Groups that //! the rendering should still be updated to show. void IntermediateChange() { _ssave.IntermediateChange(); } void SetSaveStateEnabled(bool enabled) { _ssave.SetEnabled(enabled); } bool GetSaveStateEnabled() const { return (_ssave.GetEnabled()); } void PushSaveStateEnabled(bool enabled) { _saveStateEnabledStack.push(GetSaveStateEnabled()); SetSaveStateEnabled(enabled); } void PopSaveStateEnabled() { SetSaveStateEnabled(_saveStateEnabledStack.top()); _saveStateEnabledStack.pop(); } //! Enable/Disable adding params changes to the undo list. //! When enabled, behaves as normal. //! When disabled, params are saved as normal, however the undo list is not updated. //! An example use case is to store a computed value in the params database. void SetSaveStateUndoEnabled(bool enabled) { _ssave.SetUndoEnabled(enabled); } //! Get whether updating the undo list is enabled. bool GetSaveStateUndoEnabled() const { return (_ssave.GetUndoEnabled()); } //! Restore state to previously saved state //! //! \retval status Returns true on success, false if the state is unchanged //! \sa BeginSaveStateGroup() // bool Undo(); //! Restore state to state that existed prior to the last Undo() //! //! \retval status Returns true on success, false if the state is unchanged //! \sa BeginSaveStateGroup() // bool Redo(); void UndoRedoClear(); void ManuallyAddCurrentStateToUndoStack(const string ¬e=""); //! Return description string for event at top of undo stack // string GetTopUndoDesc() const; //! Return description string for event at top of redo stack // string GetTopRedoDesc() const; string GetStateChangeReasonDescription() const { return _ssave.GetStateChangeReasonDescription(); } //! Return number states saved that can be undone with Undo() //! size_t UndoSize() const { return (_ssave.UndoSize()); } size_t RedoSize() const { return (_ssave.RedoSize()); } //! Register a boolean flag to capture state changes //! //! This method registers the address of boolean flag whose value //! will be set whenever the parameter state changes. It is the user's //! responsbility to clear (set to false) the flag. Note, for changes //! grouped tegoer with BeginSaveStateGroup() the flag will not be set //! until after EndSaveStateGroup() is called, and in the case of //! nested groups, not until the last EndSaveStateGroup() invocation. // void RegisterStateChangeFlag(bool *flag) { _ssave.RegisterStateChangeFlag(flag); } //! Register a state change callback //! //! This method is similar to RegisterStateChangeFlag(). However, instead of //! setting a boolean flag, the function specified by \p callback //! will be invoked on state changes // void RegisterStateChangeCB(std::function callback) { _ssave.RegisterStateChangeCB(callback); } //! Intermediate changes are changes inside of Save State Groups that //! the rendering should still be updated to show. void RegisterIntermediateStateChangeCB(std::function callback) { _ssave.RegisterIntermediateStateChangeCB(callback); } //! Reinit state saving //! //! void RebaseStateSave() { _ssave.Rebase(); } const XmlNode *GetXMLRoot() const { return (_rootSeparator->GetNode()); } //! Return true if any state changes made since last call //! //! This method returns a boolean indicating whether any changes //! have been made to the parameter state since the last time //! the method was called. The first time StateChanged() is called //! it will return true; // bool StateChanged() { if (*(_rootSeparator->GetNode()) == _prevState) return (false); _prevState = *(_rootSeparator->GetNode()); return (true); } void TriggerManualStateChangeEvent(const string &reason="", const bool overrideEnabled=false) { _ssave.TriggerManualStateChangeEvent(reason, overrideEnabled); } private: class PMgrStateSave : public ParamsBase::StateSave { public: PMgrStateSave(int stackSize = 100); ~PMgrStateSave(); void Reinit(const XmlNode *rootNode) { _rootNode = rootNode; // Memory leak as this is called before initializing containers in ParamsMgr::_init // emitStateChange(); } void Rebase() { if (_state0) delete _state0; _state0 = _rootNode ? new XmlNode(*_rootNode) : NULL; } void Save(const XmlNode *node, string description); void BeginGroup(string descripion); void EndGroup(); void TriggerManualStateChangeEvent(const string & reason="", const bool overrideEnabled=false); void IntermediateChange(); void SetEnabled(bool onOff) { if (!_groups.empty()) return; // Can't change inside group _enabled = onOff; } bool GetEnabled() const { return (_enabled); } void SetUndoEnabled(bool b); bool GetUndoEnabled() const { return _addToUndoEnabled; } const XmlNode *GetTopUndo(string &description) const; const XmlNode *GetTopRedo(string &description) const; const XmlNode *GetBase() const { return (_state0); } string GetStateChangeReasonDescription() const {return _stateChangeReasonDescription; } bool Undo(); bool Redo(); void Clear(); void ManuallyAddCurrentStateToUndoStack(const string ¬e=""); size_t UndoSize() const { return (_undoStack.size()); } size_t RedoSize() const { return (_redoStack.size()); } void RegisterStateChangeFlag(bool *flag) { _stateChangeFlags.push_back(flag); } void RegisterStateChangeCB(std::function callback) { _stateChangeCBs.push_back(callback); } void RegisterIntermediateStateChangeCB(std::function callback) { _intermediateStateChangeCBs.push_back(callback); } private: bool _enabled; bool _addToUndoEnabled = true; int _stackSize; const XmlNode *_rootNode; const XmlNode *_state0; std::stack _groups; std::deque> _undoStack; std::deque> _redoStack; std::vector _stateChangeFlags; std::vector> _stateChangeCBs; std::vector> _intermediateStateChangeCBs; std::string _stateChangeReasonDescription; void cleanStack(int maxN, std::deque> &s); void emitStateChange(const string &reason); void emitIntermediateStateChange(const string &reason = "Intermediate change"); }; map _dataMgrMap; ParamsSeparator * _rootSeparator; XmlNode _prevState; std::vector _appParamNames; std::vector _appRenderParamNames; // Map of RenParamsContainers referenced by Window Name, then by // data set name, and finally Renderer Name. // map>> _renderParamsMap; // Map of ViewpointParams referenced by Window Name // map _viewpointParamsMap; ParamsContainer * _otherParams; std::map _otherRenParams; PMgrStateSave _ssave; std::stack _saveStateEnabledStack; static const string _rootTag; static const string _globalTag; static const string _renderersTag; static const string _appRenderersTag; static const string _windowsTag; void _init(std::vector appParamNames, XmlNode *node); void _createAppRenParams(string dataSetName); void _destroy(); const map> *getWinMap3(const map>> &m3, string key) const; const map *getWinMap3(const map>> &m3, string key1, string key2) const; const map *getWinMap2(const map> &m2, string key) const; RenParamsContainer *get_ren_container(string winName, string dataSetName, string renderName) const; map> *getWinMap3(map>> &m3, string key) const; map *getWinMap3(map>> &m3, string key1, string key2) const; map *getWinMap2(map> &m2, string key) const; void delete_ren_container(string winName, string dataSetName, string renderName); void delete_ren_containers(string winName, string dataSetName); void delete_ren_containers(string winName); void delete_ren_containers(); void delete_datasets(string dataSetName); RenParamsContainer *make_ren_container(string winName, string dataSetName, string renderName); ViewpointParams *get_vp_params(string winName) const; void delete_vp_params(string winName); ViewpointParams *make_vp_params(string winName); void addDataMgrNew(); void addDataMgrMerge(string dataSetName); bool undoRedoHelper(); RenParamsContainer *createRenderParamsHelper(string winName, string dataSetName, string className, string instName); }; }; // End namespace VAPoR #endif // PARAMSMGR_H ================================================ FILE: include/vapor/Particle.h ================================================ /* * Defines a particle used in flow integration. */ #ifndef PARTICLE_H #define PARTICLE_H #include "vapor/common.h" #include #include namespace flow { enum FLOW_ERROR_CODE // these enum values are available in the flow namespace. { FIELD_ALL_ZERO = 4, MISSING_VAL = 3, NO_ADVECT_HAPPENED = 2, ADVECT_HAPPENED = 1, SUCCESS = 0, OUT_OF_FIELD = -1, NO_FIELD_YET = -2, NO_SEED_PARTICLE_YET = -3, FILE_ERROR = -4, TIME_ERROR = -5, GRID_ERROR = -6, SIZE_MISMATCH = -7, PARAMS_ERROR = -8 }; // Particle is not expected to serve as a base class. class FLOW_API Particle final { public: glm::vec3 location = {0.0f, 0.0f, 0.0f}; float value = 0.0f; double time = 0.0; // Constructors. // This class complies with rule of zero. Particle() = default; Particle(const glm::vec3 &loc, double t, float val = 0.0f); Particle(float x, float y, float z, double t, float val = 0.0f); // // The "property" field allows the user to keep one or more arbitrary values that // are associated with this particle. It's up to the user to keep a record on // what these values at each index stand for. // void AttachProperty(float v); void ClearProperty(); // Remove the property at a certain index. // If the index is out of bound, then nothing is performed void RemoveProperty(size_t i); auto GetPropertyList() const -> const std::forward_list &; // A particle could be set to be at a special state. void SetSpecial(bool isSpecial); bool IsSpecial() const; private: std::forward_list _properties; // Note on the choice of using a forward_list: // Forward_list takes 8 bytes, whereas a vector or list take 24 bytes! // Fun fact: the end() iterator of a forward_list is the nullptr. }; }; // namespace flow #endif ================================================ FILE: include/vapor/ParticleParams.h ================================================ #pragma once #include #include namespace VAPoR { class PARAMS_API ParticleParams : public RenderParams { public: ParticleParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave); ParticleParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, std::string classType); ParticleParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node); virtual ~ParticleParams(); static string GetClassType() { return ("ParticleParams"); } //! \copydoc RenderParams::GetRenderDim() // virtual size_t GetRenderDim() const override { return (3); } virtual string GetActualColorMapVariableName() const override { return GetVariableName(); } private: void _init(); public: //! Show direction/velocity of particles. //! The field variables must be set to the particles velocity vector components //! (this is likely done automatically if using DCP). static const std::string ShowDirectionTag; //! Scale the length of particles velocity vector static const std::string DirectionScaleTag; //! Load every nth particle. Useful for improving performance static const std::string StrideTag; //! Scale the rendered particle size static const std::string RenderRadiusScalarTag; static const std::string RenderRadiusVariableTag; static const std::string RenderRadiusVariableStrengthTag; static const std::string RenderRadiusBaseTag; static const std::string RecalculateRadiusBaseRequestTag; static const std::string RenderLegacyTag; static const std::string LightingEnabledTag; //! Specifies the Phong Ambient lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model). //! Typical values: 0.0 to 1.0. static const std::string PhongAmbientTag; //! Specifies the Phong Diffuse lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model). //! Typical values: 0.0 to 1.0. static const std::string PhongDiffuseTag; //! Specifies the Phong Specular lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model). //! Typical values: 0.0 to 1.0. static const std::string PhongSpecularTag; //! Specifies the Phong Shininess lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model). //! Typical values: 0.0 to 100.0. static const std::string PhongShininessTag; }; }; // namespace VAPoR ================================================ FILE: include/vapor/ParticleRenderer.h ================================================ //************************************************************************ // * // Copyright (C) 2018 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: ParticleRenderer.cpp // // Author: Stas Jaroszynski // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: March 2018 // // Description: // Definition of ParticleRenderer // #ifndef ParticleRENDERER_H #define ParticleRENDERER_H #include #include #include "vapor/VAssert.h" #include #include #include #include namespace VAPoR { class DataMgr; //! \class ParticleRenderer //! \brief Class that draws the Particles (Particles) as specified by IsolineParams //! \author Stas Jaroszynski, Scott Pearse //! \version 1.0 //! \date March 2018 class RENDER_API ParticleRenderer : public Renderer { public: ParticleRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr); virtual ~ParticleRenderer(); static string GetClassType() { return ("Particle"); } //! \copydoc Renderer::_initializeGL() virtual int _initializeGL(); //! \copydoc Renderer::_paintGL() virtual int _paintGL(bool fast); private: struct { size_t ts; int rLevel; int cLevel; std::vector tf_lut; std::vector tf_minMax; VAPoR::CoordType boxMin, boxMax; float radius; bool direction; size_t stride; string varName; string radiusVarName; std::vector fieldVars; } _cacheParams; struct Vertex { glm::vec3 point; float value; }; size_t _particlesCount = 0; unsigned int _VAO = 0; unsigned int _VBO = 0; GLuint _colorMapTexId = 0; GLuint _vertexArrayId = 0; GLuint _vertexBufferId = 0; const GLint _colorMapTexOffset; float _colorMapRange[3]; std::vector _colorMap; void _clearCache() {} bool _particleBaseSizeIsDirty() const; bool _particleCacheIsDirty() const; bool _colormapCacheIsDirty() const; void _resetParticleCache(); void _resetColormapCache(); int _generateParticlesLegacy(Grid*& grid, std::vector& vecGrids); int _getGrids(Grid*& grid, std::vector& vecGrids) const; template void UploadDataBuffer(vector buffer); void _generateTextureData(const Grid* grid, const std::vector& vecGrids); void _computeBaseRadius(); void _renderParticlesLegacy(const Grid* grid, const std::vector& vecGrids) const; int _renderParticlesHelper(); void _prepareColormap(); glm::vec3 _getScales(); }; }; // namespace VAPoR #endif // ParticleRENDERER_H ================================================ FILE: include/vapor/Progress.h ================================================ #pragma once #include #include #include namespace VAPoR { //! \class Progress //! Used for displaying the progress of actions to the user. The actual method //! for displaying the progress can vary based on the callback. //! //! The situations where this should be used is top-level calculations //! that may take longer than a second. This should not be used (although //! it will not break) for non-top level calculations, i.e. in the DC library //! as typically loading data will be part of a higher-level calculation. //! //! The primary use case would be a renderer that has to precompute data, e.g. //! the Flow renderer computing particle advection. class COMMON_API Progress { public: typedef std::function Start_t; typedef std::function Update_t; typedef std::function Finish_t; //! Signifies the beginning of a computation called "name" with "total" elements //! Can be called multiple times to signifiy a series of computations but must //! always end with a Finish static void Start(const std::string &name, long total, bool cancelable = false); //! Same as start but the progress is unknown. Update(0) still needs to be called periodically static void StartIndefinite(const std::string &name, bool cancelable = false); //! Update the progress status. static void Update(long completed); //! If Start was called with cancelled=true, the user will have the option to cancel //! the computation. static inline bool Cancelled() { return _cancelled; } //! Signify the computation was cancelled. static void Finish(); //! This class does not handle actually displaying progress information to //! the user. The interface (e.g. vaporgui) must set callbacks to accomplish this. static void SetHandlers(Start_t start, Update_t update, Finish_t finish); #ifndef NDEBUG //! For testing purposes only. static void Sleep(double s); #endif private: static bool _cancelled; static long _total; static Start_t _start; static Update_t _update; static Finish_t _finish; }; } // namespace VAPoR ================================================ FILE: include/vapor/Proj4API.h ================================================ #ifndef _Proj4API_h_ #define _Proj4API_h_ #include namespace VAPoR { // //! \class Proj4API //! \brief Wrapper for proj4 C API //! //! \author John Clyne //! //! This class provides a convience wrapper for the proj4 Cartographic //! Projections Library http://trac.osgeo.org/proj/ //! class VDF_API Proj4API : public Wasp::MyBase { public: Proj4API(); ~Proj4API(); //! Initialize the class //! //! Initializes the class with source and destination proj4 //! transformation strings. //! //! \param[in] srcdef The source proj4 transformation definition. If //! empty, the string "+proj=latlong" is used. //! \param[in] dstdef The destintation proj4 transformation definition. If //! empty, the string "+proj=latlong" is used. //! //! \retval status Retruns a negative int on failure //! //! \sa pj_init_plus() // int Initialize(string srcdef, string dstdef); //! Transform coordinates //! //! Transforms coordinates based on defintions of the source //! and destination proj4 transformation definitions passed to //! Initialize(). Transformations are performed between //! Geographic coordinates (latitude and longitude) and Cartographic //! coordinates (Cartesian) as specified by the transformation //! definitions. Cartographic coordinates are referred to as the //! Projection Coordinate System (PCS). Default units for the PCS //! are meters on the ground. Geographic coordinates are always //! in degrees. //! //! //! \note As with the proj4 C library the transformations are //! performed in place, modifiying the input values //! //! \param[in,out] x array of longitudes or PCS X values //! \param[in,out] y array of latitudes or PCS Y values //! \param[in] n num elements in x, y, and z //! \param[in] offset Offset between adjacent values in the input and //! output arrays. //! //! \retval status Retruns a negative int on failure //! //! \sa Initialize(), pj_transform() //! int Transform(double *x, double *y, size_t n, int offset = 1) const; int Transform(double *x, double *y, double *z, size_t n, int offset = 1) const; int Transform(float *x, float *y, size_t n, int offset = 1) const; int Transform(float *x, float *y, float *z, size_t n, int offset = 1) const; //! Return true of source projection definition is lat-long //! //! This method returns true iff the source projection definition //! is geographic (i.e. +proj=latlong). If true, subsequent transforms //! expect input values to be in geographic coordinates (i.e. degrees) //! False is returned otherwise //! //! \sa Initialize(), pj_is_latlong() // bool IsLatLonSrc() const; //! Return true of destination projection definition is lat-long //! //! This method returns true iff the destination projection definition //! is geographic (i.e. +proj=latlong). If true, subsequent transforms //! will return output values in geographic coordinates (i.e. degrees) //! False is returned otherwise //! //! \sa Initialize(), pj_is_latlong() // bool IsLatLonDst() const; bool IsGeocentSrc() const; bool IsGeocentDst() const; //! Return the current source projection definition string string GetSrcStr() const; //! Return the current destination projection definition string string GetDstStr() const; int Transform(string srcdef, string dstdef, double *x, double *y, double *z, size_t n, int offset) const; int Transform(string srcdef, string dstdef, float *x, float *y, float *z, size_t n, int offset) const; //! Return the error string generated by the proj4 C API for the //! most recent error //! //! \sa pj_strerrno() string ProjErr() const; //! Clamp the input values to bounds permitted by the source //! projection. If the source projection is not recognized the //! method is a no-op // void Clamp(double *x, double *y, size_t n, int offset) const; //! Return true if the destination projection is cylindrical //! //! Returns true if the destination projection string is either //! cylindrical "eqc", or mercator "merc" // bool IsCylindrical() const; private: void *_pjSrc; void *_pjDst; int _Initialize(string srcdef, string dstdef, void **pjSrc, void **pjDst) const; int _Transform(void *pjSrc, void *pjDst, double *x, double *y, double *z, size_t n, int offset) const; int _Transform(void *pjSrc, void *pjDst, float *x, float *y, float *z, size_t n, int offset) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/Proj4StringParser.h ================================================ #pragma once #include #include #include namespace VAPoR { class RENDER_API Proj4StringParser : Wasp::MyBase { std::string _string; std::map _tokens; static std::pair Proj4ParameterToKeyValuePair(std::string proj); static std::map Proj4StringToParameterMap(std::string proj); public: Proj4StringParser(const std::string &projString); bool HasKey(const std::string &key) const; std::string GetString(const std::string &key, const std::string &defaultValue = "") const; double GetDouble(const std::string &key, const double defaultValue = 0.0) const; static int Proj4EllipseStringToGeoTIFEnum(const std::string &proj); }; } // namespace VAPoR ================================================ FILE: include/vapor/PyEngine.h ================================================ #include #include #include #include #pragma once namespace VAPoR { //! \class PyEngine //! \brief A class for managing derived variables computed with Python //! \author John Clyne //! //! This class provides a means to manage derived variables on the DataMgr //! calculated using Python. It allows the user of this class to define //! derived variables that execute Python scripts and installs the derived //! variable on the DataMgr class. The Python script may operate on //! input variables managed by the DataMgr // class RENDER_API PyEngine : public Wasp::MyBase { public: //! Constructor for PyEngine class //! //! \param[in] dataMgr A pointer to a DataMgr instance upon which derived //! variables created by this class will be managed. // PyEngine(DataMgr *dataMgr) { VAssert(dataMgr != NULL); _dataMgr = dataMgr; } ~PyEngine(); //! Initialize the class //! //! This static initializer must be called to initialize the Python C API //! at least once prior to using //! other PyEngine class methods. //! //! \retval status A negative int is returned on failure and an error //! message will be logged with MyBase::SetErrMsg() // static int Initialize(); //! Add new derived variable(s) to the DataMgr //! //! This method adds one or more derived variables to the DataMgr specified //! by the constructor. Each derived variable is calculated by executing //! the same Python script specified by \p script. I.e. a single Python //! script may compute multiple variables. //! //! \param[in] name A string identifier for the collection of derived variables //! computed by \p script. If a script named \p name already exists it is //! removed with RemoveFunction() and replaced with the new definition. //! //! \param[in] script A Python (NumPy) script that will be invoked each time //! one of the variables listed in \p outputs is accessed. The scope of //! the script will contain NumPy Array (numpy.array) variables named //! in \p inputs. //! //! \param[in] inputs A list of input DataMgr variable names. The named //! DataMgr variables will be made available in the scope of the Python //! script as NumPy Arrays. //! //! \param[in] outputs A list of derived DataMgr variable names. The named //! variables are expected to be computed by \p script as NumPy Arrays //! and will appear as DataMgr derived variables. //! //! \param[in] outMeshes A list of output mesh names, one for each output //! variable listed in \p outputs. The output mesh names must be known //! to the DataMgr. Each output variable created by \p script is expected //! to be sampled by the named mesh. See DataMgr::GetMesh() //! //! \retval status A negative integer is returned on failure and an error //! message is reported with MyBase::SetErrMsg(). AddFunction() will fail //! if any of the output variables named in \p outputs already exist //! in the DataMgr as returned by DataMgr::GetDataVarNames(), or if any of //! the output mesh names in \p outMeshes are not known to the //! DataMgr (see DataMgr::GetMeshNames()) //! //! \note The Python script \p script is executed when one of the output //! variables is read. Depending on the region requested only a subset //! of the DataMgr variable may be provided to \p script as a NumPy //! array. Currently this occurs if all of the input variables named //! by \p inputs and the requested output variable are sampled on the //! same mesh. // int AddFunction(string name, string script, const vector &inputs, const vector &outputs, const vector &outMeshes, bool coordFlag = false); //! Remove a previously defined function //! //! This method removes the function previously created by AddFunction() //! and named by \p name. All of the associated derived variables are //! removed from the DataMgr. The method is a no-op if \p name is not //! an active function. // void RemoveFunction(string name); //! Return a list of all active function names //! //! This method returns a vector of names for all active (not previously //! removed) functions created with AddFunction() //! //! \sa AddFunction(); //! std::vector GetFunctionNames() const; //! Return the script for a named function //! //! This method returns as a string the NumPy script associated with the //! function named by \p name. //! //! \retval script Returns the Python script bound to \p name. Any empty //! string is returned if \p name is not defined. //! //! \sa AddFunction(), RemoveFunction() // string GetFunctionScript(string name) const; bool GetFunctionScript(string name, string &script, std::vector &inputVarNames, std::vector &outputVarNames, std::vector &outputMeshNames, bool &coordFlag) const; //! Return stdout as a string //! //! This method returns as a string any content written to stdout //! by the most recent invocation of the named script \p name // string GetFunctionStdout(string name) const; //! Execute a NumPy script //! //! This static method executes the NumPy script \p script and copies the //! outputs of the Python NumPy Arrays named by \p outputVarNames //! into the regions of memory provided by \p outputVarArrays. The contents //! of the memory referenced by \p inputVarArrays are made available to //! \p script as inputs in the form of NumPy Arrays. //! //! \param[in] script A Python (NumPy) script that is expected to operate on //! the NumPy Arrays listed in \p inputVarNames and store outputs in the //! NumPy arrays listed in \p outputVarNames //! //! \param[in] inputVarNames A list of NumPy Array names that will be made //! available in the scope of the executed Python script, \p script. //! //! \param[in] inputVarDims A list of dimensions for each of the possibly //! multi-dimensional NumPy arrays named by \p inputVarNames //! //! \param[in] inputVarArrays A list of regions of memory for each //! input NumPy Array that will be copied in the Python environment prior //! to executing \p script. The size of the region copy is given by the //! dimensions in \p inputVarDims //! //! \param[in] outputVarNames A list of NumPy Array names that are //! expected to be created within the scope of the Python script \p script //! The required dimesions of each array is given by \p outputVarDims //! //! \param[in] outputVarDims A list of dimensions for each of the possibly //! multi-dimensional NumPy arrays named by \p outputVarNames. //! //! \param[in] outputVarArrays A list of regions of memory for each //! output NumPy Array that will be copied out of the Python environment after //! executing \p script. The size of the region copied is given by the //! dimensions in \p outputVarDims //! static int Calculate(const string &script, vector inputVarNames, vector inputVarDims, vector inputVarArrays, vector outputVarNames, vector outputVarDims, vector outputVarArrays); private: class RENDER_API DerivedPythonVar : public DerivedDataVar { public: DerivedPythonVar(string varName, string units, DC::XType type, string mesh, string time_coord_var, bool hasMissing, std::vector inNames, string script, DataMgr *dataMgr, bool coordFlag); ~DerivedPythonVar() {} int Initialize(); bool GetBaseVarInfo(DC::BaseVar &var) const; std::vector GetInputs() const { return (_inNames); } int GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const; virtual size_t GetNumRefLevels() const; virtual std::vector GetCRatios() const { return (_varInfo.GetCRatios()); } int OpenVariableRead(size_t ts, int level = 0, int lod = 0); int CloseVariable(int fd); int ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region); bool VariableExists(size_t ts, int reflevel, int lod) const; bool GetDataVarInfo(DC::DataVar &cvar) const; //! Return stdout from most recent execution of script //! string GetScriptStdout() const { return (_stdoutString); } private: DC::DataVar _varInfo; std::vector _inNames; string _script; DataMgr * _dataMgr; bool _coordFlag; DC::FileTable _fileTable; DimsType _dims; bool _meshMatchFlag; string _stdoutString; int _readRegionAll(int fd, const DimsType &min, const DimsType &max, float *region); int _readRegionSubset(int fd, const DimsType &min, const DimsType &max, float *region); }; class func_c { public: func_c() {} func_c(const string &name, const string &script, const std::vector &inputVarNames, const std::vector &outputVarNames, const std::vector &outputMeshNames, const std::vector &derivedVars, bool coordFlag) : _name(name), _script(script), _inputVarNames(inputVarNames), _outputVarNames(outputVarNames), _outputMeshNames(outputMeshNames), _derivedVars(derivedVars), _coordFlag(coordFlag) { } string _name; string _script; std::vector _inputVarNames; std::vector _outputVarNames; std::vector _outputMeshNames; std::vector _derivedVars; bool _coordFlag; }; std::map _functions; std::map _functionsStdio; DataMgr * _dataMgr; static bool _isInitialized; PyEngine() : _dataMgr(NULL) {} static void _cleanupDict(PyObject *mainDict, vector keynames); static int _c2python(PyObject *dict, vector inputVarNames, vector inputVarDims, vector inputVarArrays); static int _python2c(PyObject *dict, vector outputVarNames, vector outputVarDims, vector outputVarArrays); bool _validOutputVar(string name) const; int _checkOutVars(const vector &outputVarNames) const; bool _validOutputMesh(string name) const; int _checkOutMeshes(const vector &outputMeshNames) const; string _getTimeCoordVarName(const vector &varNames) const; }; }; // namespace VAPoR ================================================ FILE: include/vapor/PythonDataMgr.h ================================================ #include #pragma once namespace VAPoR { class DCRAM; //! \class PythonDataMgr //! \brief DataMgr for data loaded from python scripts //! \author Stas Jaroszynski class VDF_API PythonDataMgr : public DataMgr { public: PythonDataMgr(string format, size_t mem_size, int nthreads = 0); virtual ~PythonDataMgr(); void AddRegularData(string name, const float *buf, vector dims); DCRAM *GetDC() const; void ClearCache(string varname); }; } ================================================ FILE: include/vapor/QuadTreeRectangle.hpp ================================================ #pragma once #include #include #include #include #include #include #include namespace VAPoR { // Maximum aspect ratio of a rectangle before it is split // const float maxAspectRatio = 2.0; // //! \class QuadTreeRectangle //! \brief This class implements a 2D quad tree space partitioning tree //! that operates on rectangular regions. //! // template class QuadTreeRectangle { public: class rectangle_t { public: rectangle_t() : _left(0.0f), _top(0.0f), _right(0.0f), _bottom(0.0f) {} rectangle_t(T x1, T y1, T x2, T y2) : _left(x1), _top(y1), _right(x2), _bottom(y2) {} // return true iff other intersects us // bool intersects(rectangle_t const &other) const { if (_left > other._right || _top > other._bottom) return (false); if (_right < other._left || _bottom < other._top) return (false); return (true); } // return true iff other is completely contained inside or on boundary // bool contains(rectangle_t const &other) const { return ((_left <= other._left) && (_right >= other._right) && (_top <= other._top) && (_bottom >= other._bottom)); } // return true iff point(x,y) is completely contained inside or on boundary // bool contains(T x, T y) const { return ((_left <= x) && (_right >= x) && (_top <= y) && (_bottom >= y)); } bool touches(rectangle_t const &other) const { return ((_left == other._right) || (_right == other._left) || (_top == other._bottom) || (_bottom == other._top)); } T width() const { return (_right - _left); } T height() const { return (_bottom - _top); } // return the sub-rectangle for the specified quadrant // rectangle_t quadrant(uint32_t n) { T const center_x((_left + _right) / 2); T const center_y((_top + _bottom) / 2); switch (n & 0x03) { case 0: return rectangle_t(_left, _top, center_x, center_y); case 1: return rectangle_t(center_x, _top, _right, center_y); case 2: return rectangle_t(_left, center_y, center_x, _bottom); case 3: return rectangle_t(center_x, center_y, _right, _bottom); } VAssert(0); return *this; // Can't happen since we mask n } // Horizontal aspect ratio // float hAspectRatio() const { if (_bottom == _top) return (std::numeric_limits::quiet_NaN()); return (std::fabs((_right - _left) / (_bottom - _top))); } friend std::ostream &operator<<(std::ostream &os, const rectangle_t &rec) { os << "left-top, right-bottom : " << "(" << rec._left << ", " << rec._top << ") " << "(" << rec._right << ", " << rec._bottom << ")" << std::endl; return (os); } T _left, _top, _right, _bottom; }; //! Construct a QuadTreeRectangle instance for a defined 2D region //! //! This contstructor initiates a 2D quad tree with specified min //! and max bounds. Subsequent insertions into the tree will only //! succeed for regions that intersect the tree bounds //! //! \param[in] left Minimum X coordinate bound. //! \param[in] top Minimum Y coordinate bound. //! \param[in] right Maximum X coordinate bound. Must be greater than //! or equal to \p left. //! \param[in] bottom Maximum Y coordinate bound. Must be greater than //! or equal to \p top. //! \param[in] max_depth The maximum permitted depth of the tree. The //! tree will not be refined beyond \p max_depth levels. //! \param[in] reserve_size A hint indicating the antcipated number of //! nodes in the tree. Accurate estimates will increase performance //! of tree insertions // QuadTreeRectangle(T left, T top, T right, T bottom, size_t max_depth = 12, size_t reserve_size = 1000) { VAssert(left <= right); VAssert(top <= bottom); _nodes.reserve(reserve_size); _nodes.push_back(node_t(left, top, right, bottom)); _rootidx = 0; _maxDepth = max_depth; } //! Construct a QuadTreeRectangle instance for a unit 2D region //! //! Default contructor definining a quad tree covering the region //! (.0, .0) to (1. ,1.) //! QuadTreeRectangle(size_t max_depth = 12, size_t reserve_size = 1000) { _nodes.reserve(reserve_size); _nodes.push_back(node_t(0.0, 0.0, 1.0, 1.0)); _rootidx = 0; _maxDepth = max_depth; } QuadTreeRectangle(const QuadTreeRectangle &rhs) { _nodes.resize(rhs._nodes.size()); for (size_t i = 0; i < rhs._nodes.size(); i++) { _nodes[i] = node_t((rhs._nodes[i])); } _rootidx = rhs._rootidx; _maxDepth = rhs._maxDepth; } QuadTreeRectangle &operator=(const QuadTreeRectangle &rhs) { if (*this == rhs) return *this; _nodes.resize(rhs._nodes.size()); for (size_t i = 0; i < rhs._nodes.size(); i++) { _nodes[i] = node_t((rhs._nodes[i])); } _rootidx = rhs._rootidx; _maxDepth = rhs._maxDepth; return *this; } //! Insert an element into the tree //! //! This method inserts a payload, \p payload, into the tree contained //! in the rectangular region defined by \p left, \p top, \p right, //! \p bottom. If the region to be inserted does not intersect //! the tree bound defined by the contructor method fails and returns //! false. Otherwise, the tree is subdivided as necessary and the defined //! region along with its payload are inserted. The refinement algorithm //! for subdividing the tree operates as follows: The tree nodes that //! intersect the region are subdivided until both the width and height //! of the region to be inserted are larger than the respective //! width and height of the node intersecting the region, or the //! maximum depth of the tree is reached. //! //! \retval status Return true on success, or false if region to be inserted //! does not overlap the region managed by the tree. // bool Insert(const rectangle_t &rectangle, const S &payload) { if (!_nodes[_rootidx].intersects(rectangle)) return (false); float ar = rectangle.hAspectRatio(); if (!(std::isfinite(ar)) || ar == 0.0) return (false); if (ar <= maxAspectRatio && ar >= (1.0 / maxAspectRatio)) { return (node_t::insert(_nodes, _rootidx, rectangle, payload, _maxDepth)); } else if (ar >= maxAspectRatio) { // Horizontal split // bool status = true; size_t n = (size_t)ar; float split_width = (rectangle._right - rectangle._left) / (float)n; float splitLeft = rectangle._left; for (int i = 0; i < n; i++) { float splitRight = splitLeft + split_width; if (i == (n - 1)) splitRight = rectangle._right; status &= node_t::insert(_nodes, _rootidx, rectangle_t(splitLeft, rectangle._top, splitRight, rectangle._bottom), payload, _maxDepth); splitLeft = splitRight; } return (status); } else { // Vertical split // bool status = true; size_t n = (size_t)(1.0 / ar); float split_width = (rectangle._bottom - rectangle._top) / (float)n; float splitTop = rectangle._top; for (int i = 0; i < n; i++) { float splitBottom = splitTop + split_width; if (i == (n - 1)) splitBottom = rectangle._bottom; status &= node_t::insert(_nodes, _rootidx, rectangle_t(rectangle._left, splitTop, rectangle._right, splitBottom), payload, _maxDepth); splitTop = splitBottom; } return (status); } } bool Insert(T left, T top, T right, T bottom, S payload) { return (Insert(rectangle_t(left, top, right, bottom), payload)); } //! Return a list of payloads that intersect a specified point //! //! This method searches the tree for all nodes whose associated regions //! intersect the point (\p x, \p y), and returns any payload found //! at those nodes. //! //! \p param[in] x X coordinate of point //! \p param[in] y Y coordinate of point //! \p payloads[out] A vector of payloads whose regions intersect //! \p x and \p y. //! void GetPayloadContained(T x, T y, std::vector &payloads) const { payloads.clear(); node_t::get_payload_contains(_nodes, _rootidx, x, y, payloads); } //! Return informational statistics about the current tree //! //! This method returns stats about the tree //! //! \param[out] payload_histo Returns a histogram in the form of a vector //! that gives a count of the number of payloads. For example, //! the ith element of \p payload_histo provides the count of nodes //! that contain i number of payloads. //! //! \param[out] level_histo Returns a histogram in the form of a vector //! that gives a count of cells at each level in the tree. // void GetStats(std::vector &payload_histo, std::vector &level_histo) const { payload_histo.clear(); level_histo.clear(); for (size_t i = 0; i < _nodes.size(); i++) { size_t b = _nodes[i].get_payloads().size(); if (b >= payload_histo.size()) { payload_histo.resize(b + 1, 0); } payload_histo[b] += 1; b = _nodes[i].get_level(); if (b >= level_histo.size()) { level_histo.resize(b + 1, 0); } level_histo[b] += 1; } } friend std::ostream &operator<<(std::ostream &os, const QuadTreeRectangle &q) { os << "Num nodes : " << q._nodes.size() << std::endl; const node_t &root = q._nodes[q._rootidx]; root.print(q._nodes, q._rootidx, os); return (os); } private: class node_t { public: node_t(int level = 0) : _level(level), _is_leaf(true), _child0(0), _rectangle(0.0, 0.0, 1.0, 1.0) {} node_t(T left, T top, T right, T bottom, int level = 0) : _level(level), _is_leaf(true), _child0(0), _rectangle(left, top, right, bottom) {} node_t(const rectangle_t &rec, int level = 0) : _level(level), _is_leaf(true), _child0(0), _rectangle(rec) {} rectangle_t & bounds() { return (_rectangle); } rectangle_t const &bounds() const { return (_rectangle); } bool intersects(rectangle_t const &other) const { return (_rectangle.intersects(other)); } bool contains(rectangle_t const &other) const { return (_rectangle.contains(other)); } bool contains(T x, T y) const { return (_rectangle.contains(x, y)); } bool touches(rectangle_t const &other) const { return (_rectangle.touches(other)); } static void subdivide(std::vector &nodes, size_t nidx) { node_t &node = nodes[nidx]; if (!node._is_leaf) return; node._is_leaf = false; node._child0 = nodes.size(); node_t n0(node._rectangle.quadrant(0), node._level + 1); node_t n1(node._rectangle.quadrant(1), node._level + 1); node_t n2(node._rectangle.quadrant(2), node._level + 1); node_t n3(node._rectangle.quadrant(3), node._level + 1); nodes.push_back(n0); nodes.push_back(n1); nodes.push_back(n2); nodes.push_back(n3); } static size_t quadrant(const std::vector &nodes, size_t nidx, uint32_t n) { const node_t &node = nodes[nidx]; switch (n & 0x03) { case 0: return node._child0 + 0; case 1: return node._child0 + 1; case 2: return node._child0 + 2; case 3: return node._child0 + 3; } VAssert(0); return node._child0 + 0; } static size_t quadrant(std::vector &nodes, size_t nidx, uint32_t n) { const node_t &node = nodes[nidx]; VAssert(node._child0 < nodes.size()); switch (n & 0x03) { case 0: return node._child0 + 0; case 1: return node._child0 + 1; case 2: return node._child0 + 2; case 3: return node._child0 + 3; } VAssert(0); return node._child0 + 0; } static bool insert(std::vector &nodes, size_t nidx, const rectangle_t &rec, S payload, size_t maxDepth) { if (!nodes[nidx]._rectangle.intersects(rec)) return (false); // if rec is larger than a quadrant (half the width and height of this // node) there is no point in refining. I.e. stop descending the // tree and store the payload here. // if (nodes[nidx]._rectangle.width() <= rec.width() || nodes[nidx]._rectangle.height() <= rec.height() || nodes[nidx]._level >= maxDepth) { nodes[nidx]._payloads.push_back(payload); return (true); } // This is a no-op if node has already been subdivided // subdivide(nodes, nidx); // Recursively insert in each child node that intersects rec // for (int q = 0; q < 4; q++) { size_t child = node_t::quadrant(nodes, nidx, q); if (nodes[child].intersects(rec)) { bool ok = node_t::insert(nodes, child, rec, payload, maxDepth); VAssert(ok); } } return (true); } static void get_payload_contains(const std::vector &nodes, size_t nidx, T x, T y, std::vector &payloads) { const node_t &node = nodes[nidx]; if (!node._rectangle.contains(x, y)) return; if (node._payloads.size()) { payloads.insert(payloads.end(), node._payloads.begin(), node._payloads.end()); } if (node._is_leaf) return; for (int q = 0; q < 4; q++) { size_t child = node_t::quadrant(nodes, nidx, q); if (nodes[child]._rectangle.contains(x, y)) { node_t::get_payload_contains(nodes, child, x, y, payloads); } } } static void print(const std::vector &nodes, size_t nidx, std::ostream &os) { const node_t &node = nodes[nidx]; for (int i = 0; i < node._level; i++) os << " "; os << node._rectangle; for (int i = 0; i < node._level; i++) os << " "; os << "payload : "; for (int i = 0; i < node._payloads.size(); i++) { os << node._payloads[i] << " "; } os << std::endl; if (!node._is_leaf) { for (int q = 0; q < 4; q++) { size_t childidx = quadrant(nodes, nidx, q); node_t::print(nodes, childidx, os); } } } const std::vector &get_payloads() const { return (_payloads); } size_t get_level() const { return (_level); } private: int _level; bool _is_leaf; size_t _child0; rectangle_t _rectangle; std::vector _payloads; }; std::vector _nodes; size_t _rootidx; size_t _maxDepth; }; }; // namespace VAPoR ================================================ FILE: include/vapor/QuadTreeRectangleP.h ================================================ #pragma once #include #include #pragma once #include #include #include #include using UInt32_tArr2 = std::array; using pType = UInt32_tArr2; namespace VAPoR { // //! \class QuadTreeRectangleP //! \brief This class wraps QuadTreeRectangleP with parallel //! tree construction //! // class QuadTreeRectangleP { public: //! \copydoc QuadTreeRectangle::QuadTreeRectangle() // QuadTreeRectangleP(float left, float top, float right, float bottom, size_t max_depth = 12, size_t reserve_size = 1000); //! \copydoc QuadTreeRectangle::QuadTreeRectangle() // QuadTreeRectangleP(size_t max_depth = 12, size_t reserve_size = 1000); //! \copydoc QuadTreeRectangle::QuadTreeRectangle() // QuadTreeRectangleP(const QuadTreeRectangleP &rhs); //! \copydoc QuadTreeRectangle::QuadTreeRectangle() // QuadTreeRectangleP &operator=(const QuadTreeRectangleP &rhs); ~QuadTreeRectangleP(); //! \copydoc QuadTreeRectangle::Insert() // bool Insert(float left, float top, float right, float bottom, DimsType payload); //! Parallel tree creation //! //! Inserts multiple rectangles into the quad tree in parallel //! //! \sa QuadTreeRectangle::Insert() // bool Insert(std::vector::rectangle_t> rectangles, std::vector payloads); //! Constructs a quadtree from the cells contained in a Grid class //! //! This method iterates over all of the cells found in \p grid and //! constructs a Quadtree. The construction is performed in parallel. //! The topological dimesion of \p grid must be two. //! //! \param[in] grid The grid from which to construct the tree //! \param[in] ncells If non-zero specifies the number of cells to //! insert via iterating over the cells contained in the grid. If zero, //! all of the cells are inserted. //! bool Insert(const Grid *grid, size_t ncells = 0); //! \copydoc QuadTreeRectangle::GetPayloadContained() // void GetPayloadContained(float x, float y, std::vector &payloads) const; //! \copydoc QuadTreeRectangle::GetStats() // void GetStats(std::vector &payload_histo, std::vector &level_histo) const; friend std::ostream &operator<<(std::ostream &os, const QuadTreeRectangleP &q) { for (int i = 0; i < q._qtrs.size(); i++) { os << "Bin " << i << std::endl; os << q._qtrs[i] << std::endl; } return (os); } private: float _left; float _right; std::vector *> _qtrs; }; }; // namespace VAPoR ================================================ FILE: include/vapor/RayCaster.h ================================================ #ifndef RAYCASTER_H #define RAYCASTER_H #include #ifndef WIN32 #include #endif #include #include "vapor/RayCasterParams.h" #include "vapor/GLManager.h" #include namespace VAPoR { class RENDER_API RayCaster : public Renderer { public: RayCaster(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string paramsType, std::string classType, std::string &instName, DataMgr *dataMgr); virtual ~RayCaster(); protected: // C++ stuff // pure virtual functions from Renderer int _initializeGL(); int _paintGL(bool fast); void _clearCache(){}; // Makes RayCaster an abstract class that cannot be instantiated, // and it's up to the subclasses to decide which shader to load. // It returns 0 upon success, and non-zero upon errors. virtual int _load3rdPassShaders() = 0; enum CastingMode { FixedStep = 1, CellTraversal = 2 }; class UserCoordinates { // Note: class UserCoordinates lives completely inside of class RayCaster, // and is solely used by class RayCaster. Thus for simplicity, it has all // of its member variables and methods public. public: // Y // | Z (coming out the screen) // | / // | / // |/ // 0 --------X float * frontFace, *backFace; // user coordinates, size == bx * by * 3 float * rightFace, *leftFace; // user coordinates, size == by * bz * 3 float * topFace, *bottomFace; // user coordinates, size == bx * bz * 3 float * dataField; // data field of this volume unsigned char *missingValueMask; // 0 == is missing value; non-zero == not missing value float * vertCoords; // vertex coordinates in user coordinates float * secondVarData; // values of a second variable unsigned char *secondVarMask; // 0 == is missing value; non-zero == not missing value size_t dims[3]; // num. of samples along each axis. /* Also keep the current meta data */ size_t myCurrentTimeStep; std::string myVariableName; std::string my2ndVarName; int myRefinementLevel, myCompressionLevel; float myGridMin[3], myGridMax[3]; // Keeps the min and max of the current grid. // !!NOT!! the value retrieved from params. // A few flags to indicate if certain data is out of date bool dataFieldUpToDate; bool vertCoordsUpToDate; bool secondVarUpToDate; /* Member functions */ UserCoordinates(); ~UserCoordinates(); // // It returns 0 upon success, and non-zero upon errors. // int GetCurrentGrid(const RayCasterParams *params, DataMgr *dataMgr, StructuredGrid **gridpp) const; void CheckUpToDateStatus(const RayCasterParams *params, const StructuredGrid *grid, DataMgr *dataMgr, bool use2ndVar); // // Update meta data, as well as pointers: 6 faces + dataField + missingValueMask // It returns 0 upon success, and non-zero upon errors: // int UpdateFaceAndData(const RayCasterParams *params, const StructuredGrid *grid, DataMgr *dataMgr); // // Update pointers: xyCoords and zCoords // |-- Note: meta data is updated in UpdateFaceAndData(), but *NOT* here, so // | UpdateFaceAndData() needs to be called priori to UpdateVertCoords(). // |-- It returns 0 upon success, and non-zero upon errors: // int UpdateVertCoords(const RayCasterParams *params, const StructuredGrid *grid, DataMgr *dataMgr); int Update2ndVariable(const RayCasterParams *params, DataMgr *dataMgr); void FillCoordsXYPlane(const StructuredGrid *grid, // Input size_t planeIdx, // Input: which plane to retrieve float * coords); // Output buffer allocated by caller void FillCoordsYZPlane(const StructuredGrid *grid, // Input size_t planeIdx, // Input float * coords); // Output void FillCoordsXZPlane(const StructuredGrid *grid, // Input size_t planeIdx, // Input float * coords); // Output void IterateAGrid(const StructuredGrid *grid, size_t numOfVert, // Length of buffers. float * dataBuf, // Need to be already allocated. unsigned char * maskBuf); // Need to be already allocated. }; // end of class UserCoordinates UserCoordinates _userCoordinates; std::vector _colorMap; float _colorMapRange[3]; // min, max, and diff values. glm::mat4 _currentMV; // model view matrix in use GLint _currentViewport[4]; // current viewport in use bool _isIntel; // OpenGL stuff // textures GLuint _backFaceTextureId; GLuint _frontFaceTextureId; GLuint _volumeTextureId; GLuint _missingValueTextureId; GLuint _colorMapTextureId; GLuint _vertCoordsTextureId; GLuint _depthTextureId; GLuint _2ndVarDataTexId; GLuint _2ndVarMaskTexId; const GLint _backFaceTexOffset; const GLint _frontFaceTexOffset; const GLint _volumeTexOffset; const GLint _colorMapTexOffset; const GLint _missingValueTexOffset; const GLint _vertCoordsTexOffset; const GLint _depthTexOffset; const GLint _2ndVarDataTexOffset; const GLint _2ndVarMaskTexOffset; // buffers and vertex arrays GLuint _frameBufferId; GLuint _vertexArrayId; GLuint _vertexBufferId; // Keeps user coordinates of 6 faces. GLuint _indexBufferId; // Auxiliary indices for efficiently drawing triangle strips. GLuint _vertexAttribId; // Attribute of vertices: (i, j k) logical indices. // shaders ShaderProgram *_1stPassShader; ShaderProgram *_2ndPassShader; ShaderProgram *_3rdPassShader; ShaderProgram *_3rdPassMode1Shader; ShaderProgram *_3rdPassMode2Shader; // // Render the volume surface using triangle strips // This is a subroutine used by _drawVolumeFaces(). // void _renderTriangleStrips(int whichPass, int castingMode) const; void _drawVolumeFaces(int whichPass, int whichCastingMode, const std::vector &cameraCellIdx, const glm::mat4 &inversedMV = glm::mat4(0.0f), bool fast = false) const; void _load3rdPassUniforms(int castingMode, bool fast, bool insideVolume) const; virtual void _3rdPassSpecialHandling(bool fast, int castingMode) const; virtual void _colormapSpecialHandling(); // Cannot be const due to other subroutines. virtual bool _use2ndVariable(const RayCasterParams *params) const; virtual void _update2ndVarTextures(); // // Initialization for 1) framebuffers and 2) textures // It returns 0 upon success, and non-zero upon errors. // int _initializeFramebufferTextures(); int _selectDefaultCastingMethod() const; void _updateViewportWhenNecessary(const GLint *viewport); void _updateColormap(RayCasterParams *params); void _updateDataTextures(); int _updateVertCoordsTexture(const glm::mat4 &MV); void _configure3DTextureNearestInterpolation() const; void _configure3DTextureLinearInterpolation() const; void _configure2DTextureLinearInterpolation() const; void _sleepAWhile() const; #ifndef WIN32 double _getElapsedSeconds(const struct timeval *begin, const struct timeval *end) const; #endif }; // End of class RayCaster }; // End of namespace VAPoR #endif ================================================ FILE: include/vapor/RayCasterParams.h ================================================ #ifndef RAYCASTERPARAMS_H #define RAYCASTERPARAMS_H #include #include namespace VAPoR { class PARAMS_API RayCasterParams : public RenderParams { public: RayCasterParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, std::string classType); RayCasterParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, XmlNode *xmlNode); virtual ~RayCasterParams(); // //! Obtain current MapperFunction for the primary variable. // MapperFunction *GetMapperFunc(); bool GetLighting() const; void SetLighting(bool); std::vector GetLightingCoeffs() const; void SetLightingCoeffs(const std::vector &coeffs); // // Different ray casting methods: 1 == fixed step casting // 2 == prism intersection casting // long GetCastingMode() const; void SetCastingMode(long); long GetSampleRateMultiplier() const; // ComboBox index is held here. Need to translate void SetSampleRateMultiplier(long); // to real multipliers in RayCaster.cpp //! \copydoc RenderParams::GetRenderDim() // virtual size_t GetRenderDim() const override { return (3); } protected: static const std::string _lightingTag; static const std::string _lightingCoeffsTag; static const std::string _castingModeTag; static const std::string _sampleMultiplierTag; }; } // namespace VAPoR #endif ================================================ FILE: include/vapor/RegularGrid.h ================================================ #ifndef _RegularGrid_ #define _RegularGrid_ #include #include #include #include namespace VAPoR { //! \class RegularGrid //! \brief This class implements a 2D or 3D regular grid. //! //! This class implements a 2D or 3D regular grid: a tessellation //! of Euculidean space by rectangles (2D) or parallelpipeds (3D). Each //! grid point can be addressed by an index(i,j,k), where \a i, \p a //! and \a k range from 0 to \a dim - 1, where \a dim is the dimension of the //! \a I, \a J, or \a K axis, respectively. Moreover, each grid point //! has a coordinate in a user-defined coordinate system given by //! (\a i * \a dx, \a j * \a dy, \a k * \a dz) for some real //! numbers \a dx, \a dy, and \a dz representing the grid spacing. //! // class VDF_API RegularGrid : public StructuredGrid { public: //! \copydoc StructuredGrid::StructuredGrid( //! const std::vector&, const std::vector&, //! const std::vector& //! ) //! //! Construct a regular grid sampling a 3D or 2D scalar function. //! //! Adds new parameters: //! //! \param[in] minu A vector provding the user coordinates of the first //! point in the grid. //! \param[in] maxu A vector provding the user coordinates of the last //! point in the grid. All elements of \p maxu must be greater than or //! equal to corresponding elements in \p minu. //! // RegularGrid(const DimsType &dims, const DimsType &bs, const std::vector &blks, const CoordType &minu, const CoordType &maxu); RegularGrid(const std::vector &dims, const std::vector &bs, const std::vector &blks, const std::vector &minu, const std::vector &maxu); RegularGrid() = default; virtual ~RegularGrid() = default; virtual size_t GetGeometryDim() const override { return (_geometryDim); } virtual DimsType GetCoordDimensions(size_t dim) const override; static std::string GetClassType() { return ("Regular"); } std::string GetType() const override { return (GetClassType()); } //! \copydoc Grid::GetBoundingBox() // virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override; //! \copydoc Grid::GetUserCoordinates() // virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override; // For grandparent inheritance of // Grid::GetUserCoordinates(const size_t indices[], double coords[]) // using Grid::GetUserCoordinates; //! \copydoc Grid::GetIndicesCell //! virtual bool GetIndicesCell(const CoordType &coords, DimsType &indices) const override; //! \copydoc Grid::InsideGrid() // virtual bool InsideGrid(const CoordType &coords) const override; class ConstCoordItrRG : public Grid::ConstCoordItrAbstract { public: ConstCoordItrRG(const RegularGrid *rg, bool begin); ConstCoordItrRG(const ConstCoordItrRG &rhs); ConstCoordItrRG(); virtual ~ConstCoordItrRG() {} virtual void next(); virtual void next(const long &offset); virtual ConstCoordType &deref() const { return (_coords); } virtual const void * address() const { return this; }; virtual bool equal(const void *rhs) const { const ConstCoordItrRG *itrptr = static_cast(rhs); return (_index == itrptr->_index); } virtual std::unique_ptr clone() const { return std::unique_ptr(new ConstCoordItrRG(*this)); }; private: DimsType _index; DimsType _dims; CoordType _minu; CoordType _delta; CoordType _coords; }; virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrRG(this, true))); } virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrRG(this, false))); } VDF_API friend std::ostream &operator<<(std::ostream &o, const RegularGrid &rg); protected: virtual float GetValueNearestNeighbor(const CoordType &coords) const override; virtual float GetValueLinear(const CoordType &coords) const override; //! \copydoc Grid::GetUserExtents() // virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override; private: void _regularGrid(const CoordType &minu, const CoordType &maxu); CoordType _minu = {{0.0, 0.0, 0.0}}; CoordType _maxu = {{0.0, 0.0, 0.0}}; size_t _geometryDim; CoordType _delta; // increment between grid points in user coords }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/RenderParams.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: RenderParams.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: July 2014 // // Description: Defines the RendererParams class. // This is an abstract class for all the tabbed panel render params classes. // Supports functionality common to all the tabbed panel render params. // #ifndef RENDERPARAMS_H #define RENDERPARAMS_H #include #include #include #include #include #include #include #include namespace VAPoR { //! \class RenderParams //! \ingroup Public_Params //! \brief A Params subclass for managing parameters used by Renderers //! \author Alan Norton //! \version 3.0 //! \date February 2014 //! class PARAMS_API RenderParams : public ParamsBase { public: //! Standard RenderParams constructor. //! \param[in] name std::string name, can be the tag RenderParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, const string &classname, int maxdim = 3); RenderParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node, int maxdim = 3); RenderParams(const RenderParams &rhs); RenderParams &operator=(const RenderParams &rhs); virtual ~RenderParams(); //! Initialize the class. //! //! Must be called immediately after the constructor: //! //! RenderParams(DataMgr *, ParamsBase::StateSave *, const string &, int maxdim); //! //! The results of //! calling any other methods before calling Initialize() are //! undefined. //! //! Subsequent calls to Initialize() after the first call are a no-op. //! //! \retval returns integer >= 0 on success, otherwise failure // virtual int Initialize(); int ResetUserExtentsToDataExents(string var=""); //! Determine if this params has been enabled for rendering //! //! Default is false. //! //! \retval bool true if enabled virtual bool IsEnabled() const { return ((bool)GetValueLong(_EnabledTag, (int)false)); } //! Enable or disable this params for rendering //! //! This should be executed between start and end capture //! which provides the appropriate undo/redo support //! Accordingly this will not make an entry in the undo/redo queue. //! //! Default is false. //! //! \param[in] bool true to enable, false to disable. virtual void SetEnabled(bool val); //! Specify primary variable name; e.g. used in color mapping or rendering. //! The default is the empty string, which indicates no variable. //! \param[in] string varName. If "0" \p varName will be quietly //! set to the empty string, "". virtual void SetVariableName(string varName); //! Get the primary variable name, e.g. used in color mapping or rendering. //! The default is the empty string, which indicates a no variable. //! \retval string variable name string GetVariableName() const; //! Specify auxiliary variable name; e.g. "Position along Flow" //! The default is a vector of length containing the empty string. //! \param[in] string varNames. If any element is "0" the element //! will be quietly //! set to the empty string, "". virtual void SetAuxVariableNames(vector varName); //! Get the auxiliary variable names, e.g. "position along flow" //! //! The default is a vector of length containing the empty string. //! //! \retval vector variable name vector GetAuxVariableNames() const; //! Determine if auxiliary variable name is used //! \retval bool true if using auxiliary variable bool UseAuxVariable() const { vector names = GetAuxVariableNames(); for (int i = 0; i < names.size(); i++) { if (GetVariableName() == names[i]) return true; } return false; } //! Get the primary variable, or the first valid field variable //! //! Return the first non-empty variable found, first searching //! the name returned by GetVariableName(), and the ordered list //! of variables returned by GetFieldVariableNames(). The empty //! string is returned if no non-empty variable names exist. //! //! \retval string variable name // string GetFirstVariableName() const; //! Specify field variable names; e.g. used in flow integration //! can be 0 or 3 strings //! \param[in] string varNames. If any element is "0" the element //! will be quietly //! set to the empty string, "". // virtual void SetFieldVariableNames(vector varNames); //! Set the X field variable name, e.g. used in flow integration. //! \param[in] std::string varName for X field // void SetXFieldVariableName(std::string varName); //! Set the Y field variable name, e.g. used in flow integration. //! \param[in] std::string varName for Y field // void SetYFieldVariableName(std::string varName); //! Set the Z field variable name, e.g. used in flow integration. //! \param[in] std::string varName for Z field // void SetZFieldVariableName(std::string varName); //! Get the field variable names, e.g. used in flow integration. //! \retval vector variable names. A vector of length 3 //! containing variable names. The default is 3 empty variable names. vector GetFieldVariableNames() const; //! Get the X field variable name, e.g. used in flow integration. //! \retval std::string X field variable name. // std::string GetXFieldVariableName() const; //! Get the Y field variable name, e.g. used in flow integration. //! \retval std::string Y field variable name. // std::string GetYFieldVariableName() const; //! Get the Z field variable name, e.g. used in flow integration. //! \retval std::string Z field variable name. // std::string GetZFieldVariableName() const; //! Get the distribution variable names, e.g. used in flow integration. //! \retval vector variable names vector GetDistribVariableNames() const { return (GetValueStringVec(_distribVariableNamesTag)); } //! Virtual method sets current number of refinements of this Params. //! \param[in] int refinements //! virtual void SetRefinementLevel(int numrefinements); //! Virtual method indicates current number of refinements of this Params. //! \retval integer number of refinements //! virtual int GetRefinementLevel() const; //! virtual method indicates current Compression level. //! \retval integer compression level, 0 is most compressed //! virtual int GetCompressionLevel() const; //! Virtual method sets current Compression level. //! \param[in] val compression level, 0 is most compressed //! virtual void SetCompressionLevel(int val); //! Specify a stretch factor used in displaying histograms in //! mapper functions. //! Can be ignored if there is no mapper function in the params. //! Default value is 1.0. //! //! \param[in] factor positive multiplier that applies to the //! histogram height. void SetHistoStretch(float factor); //! Obtain the stretch factor used in displaying histograms in mapper //! functions. //! //! Default value is 1.0. //! \return multiplier that applies to the histogram height. float GetHistoStretch() const; //! Obtain ColorbarPBase (used to specify Color Bar properties) from RenderParams. virtual ColorbarPbase *GetColorbarPbase() const { return _Colorbar; } //! Set the ColorbarPbase that specifies properties of the Color bar. //! \sa GetColorbarPbase //! By default the ColorbarPbase is a child of the root node of this RenderParams. //! \param[in] pb ColorbarPbase to set. //! \return 0 if successful. virtual void SetColorbarPbase(ColorbarPbase *pb); //! Obtain current MapperFunction //! //! Get a MapperFunction for the variable \p varname. //! If one does not exist it is created. // virtual MapperFunction *GetMapperFunc(string varname); //! Remove the mapper function for the named variable. // virtual void RemoveMapperFunc(string varname); //! Set current MapperFunction //! //! \param[in] varname Name of variable associated with mapping //! \param[in] tf // virtual void SetMapperFunc(string varname, MapperFunction *tf); //! Virtual method to return the Box associated with a Params class. //! By default returns NULL. //! All params classes that use a box to define data extents should reimplement this method. //! Needed to support manipulators. //! \retval Box* returns pointer to the Box associated with this Params. // virtual Box *GetBox() const { return (_Box); } //! Specify the 2D cursor coordinates when associated with this RenderParams //! \param[in] coords void SetCursorCoords(const float coords[2]); //! Obtain the 2D cursor coordinates if associated with this RenderParams //! \return 2D cursor coordinates void GetCursorCoords(float coords[2]) const; //! Specify the variable being used for height //! Overrides method on RenderParams //! \param[in] string varName. If any \p varName is "0" it //! will be quietly //! set to the empty string, "". //! \retval int 0 if successful; virtual void SetHeightVariableName(string varname); //! Determine variable name being used for terrain height (above or below sea level) //! \retval const string& variable name virtual string GetHeightVariableName() const; //! Indicate if a single (constant) color is being used //! \return true if constant single color is used bool UseSingleColor() const; //! Specify the variable being used for color mapping //! \param[in] string varName. If any \p varName is "0" it //! will be quietly //! set to the empty string, "". // virtual void SetColorMapVariableName(string varname); //! Get the color mapping variable name if any //! \retval string variable name //! virtual string GetColorMapVariableName() const; //! Due to legacy code, the "ColorMapVariableName" is not the name of the variable by which //! the renderer is colormapping, but rather the variable it should use if it is not already using its //! primary variable or a constant color. This function should return the name of the variable that //! is currently being used for colormapping. virtual string GetActualColorMapVariableName() const = 0; //! Turn on or off the use of single constant color (versus color map) //! \param[in] val true will enable constant color void SetUseSingleColor(bool val); //! Specify a constant color //! //! Specify a constant color is in rgb values between 0 and 1. //! The constant color is used to color objects when UseSingleColor() //! returns true. //! //! \param[in] const float rgb[3] //! //! \sa GetConstantColor() // void SetConstantColor(const float rgb[3]); void SetConstantColor(vector rgb); //! Get the constant color (in r,g,b) //! //! \param[out] rgb A 3-element array use values are in the range 0.0..1.0 //! //! \sa SetConstantColor(), GetConstantOpacity(), UseSingleColor() // void GetConstantColor(float rgb[3]) const; vector GetConstantColor() const { float rgb[3]; GetConstantColor(rgb); vector v = {rgb[0], rgb[1], rgb[2]}; return (v); } //! Specify a constant opacity. Color is n the between 0 and 1. //! //! \param[in] const float rgb[3] //! \retval 0 if successful //! void SetConstantOpacity(float o); //! Get the constant opacity //! //! \retval opacity //! //! \sa SetConstantColor(), GetConstantOpacity() // float GetConstantOpacity() const; //! Get the current data timestep //! \retval ts current time step // size_t GetCurrentTimestep() const { return (size_t)GetValueLong(_currentTimestepTag, 0); } //! Set the current data timestep being used //! \param[in] ts current time step // void SetCurrentTimestep(size_t ts) { SetValueLong(_currentTimestepTag, "Set timestep", (long)ts); } //! Access the transform used by the renderer // virtual Transform *GetTransform() const { return _transform; } void initializeBypassFlags(); //! Set reasonable default variables //! \param[in] The dimension of the variables being set //! \param[in] Indicates whether we're using color mapped variables virtual void SetDefaultVariables(int dim, bool secondaryColormapVariable); //! Return the renderer's current dimension //! //! For renderers that are only capable of operating on variables of a fixed //! dimensionality (e.g. 2D or 3D) this function will return a constant value: //! the number of dimensions. For renderers that can operate on a variable of //! varying dimension this method returns the current dimensionality. The //! returned value will be between 0 and 3. A value of zero will be //! returned if the current dimensionality cannot be determined. //! //! virtual size_t GetRenderDim() const = 0; //! This should be overriden by params for renderes that support iso values to return true. virtual bool HasIsoValues() const { return false; } virtual vector GetIsoValues(const string &variable) { VAssert(0); return {}; } virtual void SetIsoValues(const string &variable, const vector &values) { VAssert(0); } vector GetIsoValues() { return GetIsoValues(GetVariableName()); } void SetIsoValues(const vector &values) { SetIsoValues(GetVariableName(), values); } //! Return whether a renderer can be oriented - IE, can this renderer be rotated about an origin point? virtual bool GetOrientable() const; //! Return the renderer's 3 axis rotation for creating ArbitrarilyOrientedRegularGrids. //! \retval vector - Slice's rotation on X, Y, and Z axes //! Valid values - -90.0 to 90.0 for each axis component vector GetSlicePlaneRotation() const; //! Return the renderer's 3 axis origin for creating ArbitrarilyOrientedRegularGrids. //! \retval vector - Slice's origin on X, Y, and Z axes, specified in the data's coordinate system //! Valid values - A point within the data domain vector GetSlicePlaneOrigin() const; //! Return the renderer's 3 axis normal for creating ArbitrarilyOrientedRegularGrids. //! \retval vector - Slice's rotation on X, Y, and Z axes, specified in the data's coordinate system //! Valid values - -1.0 to 1.0 for each axis component vector GetSlicePlaneNormal() const; //! Return the renderer's origin value on the X axis for creating ArbitrarilyOrientedRegularGrids. //! \retval double - Slice's origin on the X axis //! Valid values - A point within the data domain's X axis coordinates double GetXSlicePlaneOrigin() const; //! Return the renderer's origin value on the Y axis for creating ArbitrarilyOrientedRegularGrids. //! \retval double - Slice's origin on the Y axis //! Valid values - A point within the data domain's Y axis coordinates double GetYSlicePlaneOrigin() const; //! Return the renderer's origin value on the Z axis for creating ArbitrarilyOrientedRegularGrids. //! \retval double - Slice's origin on the Z axis, specified in the data's coordinate system //! Valid values - A point within the data domain's Z axis coordinates double GetZSlicePlaneOrigin() const; //! Set the renderer's origin value on the X axis for creating ArbitrarilyOrientedRegularGrids. //! \param[in] double - Value to use for the plane origin on the X axis. //! Valid values - A point within the data domain's X axis coordinates void SetXSlicePlaneOrigin(double xOrigin); //! Set the renderer's origin value on the Y axis for creating ArbitrarilyOrientedRegularGrids. //! \param[in] double - Value to use for the plane origin on the Y axis. //! Valid values - A point within the data domain's Y axis coordinates void SetYSlicePlaneOrigin(double yOrigin); //! Set the renderer's origin value on the Z axis for creating ArbitrarilyOrientedRegularGrids. //! \param[in] double - Value to use for the plane origin on the Z axis. //! Valid values - A point within the data domain's Z axis coordinates void SetZSlicePlaneOrigin(double zOrigin); //! Set the values for a quad that encloses an arbitrary user-defined plane //! \param[in] A std::vector of size 4, containing the locations of four vertices. void SetSlicePlaneQuad(const std::vector &quad) { _slicePlaneQuad = quad; } //! Return the values for a quad that encloses an arbitrary user-defined plane //! \retval A std::vector of size 4, containing the locations of four vertices. std::vector GetSlicePlaneQuad() const { return _slicePlaneQuad; } //! Sets whether the renderer is drawn without depth testing (drawn on top of other renderers) void SetDrawInFront(bool); //! Return whether the renderer is drawn without depth testing (drawn on top of other renderers) bool GetDrawInFront() const; protected: DataMgr *_dataMgr; int _maxDim; bool InitBoxFromVariable(size_t ts, string varName); virtual bool GetUseSingleColorDefault() const { return false; } private: void _init(); void _calculateStride(string varName); int _stride; ParamsContainer * _TFs; Box * _Box; ColorbarPbase * _Colorbar; Transform * _transform; bool _classInitialized; // std::vector _slicePlaneQuad; static const string _EnabledTag; static const string _histoScaleTag; static const string _editBoundsTag; static const string _histoBoundsTag; static const string _cursorCoordsTag; static const string _terrainMapTag; static const string _auxVariableNamesTag; static const string _distribVariableNamesTag; static const string _transferFunctionsTag; static const string _stretchFactorsTag; static const string _currentTimestepTag; string _findVarStartingWithLetter(std::vector searchVars, char letter); string _findVarEndingWithLetter(std::vector searchVars, char letter); public: static const string _variableNameTag; static const string _colorMapVariableNameTag; static const string _heightVariableNameTag; static const string _useSingleColorTag; static const string _constantColorTag; static const string _CompressionLevelTag; static const string _RefinementLevelTag; // static const string _fieldVariableNamesTag; static const string _xFieldVariableNameTag; static const string _yFieldVariableNameTag; static const string _zFieldVariableNameTag; static const string _constantOpacityTag; static const string CustomHistogramDataTag; static const string CustomHistogramRangeTag; static const string LightingEnabledTag; static const string UserNameTag; static const string DrawInFrontTag; //! If a renderer supports rotation about a point of origin (IE - Slice and Contour), //! this tag identifies the parameter for the origin's //! location on the X axis. //! \details This tag only applies when 3D data are sliced for contouring or pseudo-coloring slices //! Applies to data of type: double //! Valid values: A point within the data domain's X axis coordinates static const string XSlicePlaneOriginTag; //! If a renderer supports rotation about a point of origin (IE - Slice and Contour), //! this tag identifies the parameter for the origin's //! location on the Y axis. //! \copydetails RenderParams::XSlicePlaneOriginTag() //! Applies to data of type: double //! Valid values: A point within the data domain's Y axis coordinates static const string YSlicePlaneOriginTag; //! If a renderer supports rotation about a point of origin (IE - Slice and Contour), //! this tag identifies the parameter for the origin's //! location on the Z axis. //! \copydetails RenderParams::XSlicePlaneOriginTag() //! Applies to data of type: double //! Valid values: A point within the data domain's Z axis coordinates static const string ZSlicePlaneOriginTag; //! If a renderer supports rotation about a point of origin (IE - Slice and Contour), //! this tag identifies the parameter for the rotation //! about the X axis. //! \copydetails RenderParams::XSlicePlaneOriginTag() //! Applies to data of type: double //! Valid values: -90.0 to 90.0 static const string XSlicePlaneRotationTag; //! If a renderer supports rotation about a point of origin (IE - Slice and Contour), //! this tag identifies the parameter for the rotation //! about the Y axis. //! \copydetails RenderParams::XSlicePlaneOriginTag() //! Applies to data of type: double //! Valid values: -90.0 to 90.0 static const string YSlicePlaneRotationTag; //! If a renderer supports rotation about a point of origin (IE - Slice and Contour), //! this tag identifies the parameter for the rotation //! about the Z axis. //! \copydetails RenderParams::XSlicePlaneOriginTag() //! Applies to data of type: double //! Valid values: -90.0 to 90.0 static const string ZSlicePlaneRotationTag; //! If a renderer samples data points through a plane (IE - Slice and Contour), //! this tag identifies the parameter for how many samples //! to take along that vector. //! \copydetails RenderParams::XSlicePlaneOriginTag() //! Applies to data of type: long //! Valid values: 0 to LONG_MAX static const string SampleRateTag; //! If a renderer can be offset from a point of origin (IE - Slice and Contour), //! this tag identifies the parameter for offsetting the renderer from that point. //! \copydetails RenderParams::XSlicePlaneOriginTag() //! Applies to data of type: double //! Valid values: DBL_MIN to DBL_MAX static const string SliceOffsetTag; //! If a renderer can be oriented orthogonally to a normal vector (IE - Slice and Contour), //! this tag identifies the normal's X component. //! \copydetails RenderParams::XSlicePlaneOriginTag() //! Applies to data of type: double //! Typical values: -1.0 to 1.0 //! Valid values: DBL_MIN to DBL_MAX static const string SlicePlaneNormalXTag; //! If a renderer can be oriented orthogonally to a normal vector (IE - Slice and Contour), //! this tag identifies the normal's Y component. //! \copydetails RenderParams::XSlicePlaneOriginTag() //! Applies to data of type: double //! Typical values: -1.0 to 1.0 //! Valid values: DBL_MIN to DBL_MAX static const string SlicePlaneNormalYTag; //! If a renderer can be oriented orthogonally to a normal vector (IE - Slice and Contour), //! this tag identifies the normal's Z component. //! \copydetails RenderParams::XSlicePlaneOriginTag() //! Applies to data of type: double //! Typical values: -1.0 to 1.0 //! Valid values: DBL_MIN to DBL_MAX static const string SlicePlaneNormalZTag; //! If a renderer can be oriented according to 1) a set of rotationis on the XYZ axes, or //! 2) according to the orthoganality of a specified normal (IE - Slice and Contour), //! this tag determines which method is being used to orient the the renderer. //! \copydetails RenderParams::XSlicePlaneOriginTag() //! Applies to data of type: long //! Valid values: 0 = SlicePlaneOrientationMode::Rotation, 1 = SlicePlaneOrientationMode::Normal static const string SlicePlaneOrientationModeTag; enum class SlicePlaneOrientationMode { Rotation = 0, Normal = 1, }; }; ////////////////////////////////////////////////////////////////////////// // // RenParamsFactory Class // ///////////////////////////////////////////////////////////////////////// class PARAMS_API RenParamsFactory { public: static RenParamsFactory *Instance() { static RenParamsFactory instance; return &instance; } void RegisterFactoryFunction(string name, function classFactoryFunction) { // register the class factory function _factoryFunctionRegistry[name] = classFactoryFunction; } RenderParams *(CreateInstance(string classType, DataMgr *, ParamsBase::StateSave *, XmlNode *)); vector GetFactoryNames() const; private: map> _factoryFunctionRegistry; RenParamsFactory() {} RenParamsFactory(const RenParamsFactory &) {} RenParamsFactory &operator=(const RenParamsFactory &) { return *this; } }; ////////////////////////////////////////////////////////////////////////// // // RenParamsRegistrar Class // // Register RenParamsBase derived class with: // // static RenParamsRegistrar registrar("myclassname"); // // where 'RenParamsClass' is a class derived from 'RenderParams', and // "myclassname" is the name of the class // ///////////////////////////////////////////////////////////////////////// template class RenParamsRegistrar { public: RenParamsRegistrar(string classType) { // register the class factory function // RenParamsFactory::Instance()->RegisterFactoryFunction(classType, [](DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) -> RenderParams * { if (node) return new T(dataMgr, ssave, node); else return new T(dataMgr, ssave); }); } }; ////////////////////////////////////////////////////////////////////////// // // RenParamsContainer Class // ///////////////////////////////////////////////////////////////////////// // // The RenParamsContainer class constructs an XML tree as depicted below, // where 'Container Name' is the root of XML tree, and is the name // passed into the constructor as 'myname'; 'Class Name' is the name of // the derived RenParamBase class used to construct new instances of // the derived class; and 'ele name x' is the unique name of the element // contained in the container. // /* |----------------| | Container Name | |----------------| | \|/ |----------------| | Class Name | |----------------| | \ \|/ \ |----------------| \ |----------------| | ele name 1 |....| ele name n | |----------------| |----------------| */ class PARAMS_API RenParamsContainer : public Wasp::MyBase { public: RenParamsContainer(DataMgr *dataMgr, ParamsBase::StateSave *ssave, const string &myname); RenParamsContainer(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node); //! Copy constructor. RenParamsContainer(const RenParamsContainer &rhs); RenParamsContainer &operator=(const RenParamsContainer &rhs); ~RenParamsContainer(); RenderParams *Insert(const RenderParams *rp, string name); RenderParams *Create(string classType, string name); void Remove(string name); RenderParams *GetParams(string name) const; vector GetNames() const; size_t Size() const { return (_elements.size()); } XmlNode *GetNode() const { return _separator->GetNode(); } ParamsSeparator *GetSeparator() const { return _separator; } string const GetName() const { return (_separator->GetName()); } private: DataMgr * _dataMgr; ParamsBase::StateSave * _ssave; ParamsSeparator * _separator; map _elements; }; }; // End namespace VAPoR #endif // RENDERPARAMS_H ================================================ FILE: include/vapor/Renderer.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // File: Renderer.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: September 2004 // // Description: Defines the Renderer class. // A pure virtual class that is implemented for each renderer. // Methods are called by the visualizer class as needed. // #ifndef RENDERER_H #define RENDERER_H #include #include #include namespace VAPoR { class ShaderProgram; struct GLManager; class MatrixManager; //! \class RendererBase //! \ingroup Public_Render //! \brief A base class for Renderer classes //! \author Alan Norton //! \version 3.0 //! \date July 2015 //! //! RendererBase is a base class of Renderer, for special rendering //! tasks that are not associated with RenderParams instances. //! For example the VizFeatureRenderer has a special role during //! Visualizer OpenGL rendering. RendererBase instances perform rendering //! in a VAPOR Visualizer but are not associated with RenderParams instances. //! class RENDER_API RendererBase : public MyBase { public: RendererBase(const ParamsMgr *pm, string winName, string dataSetName, string paramsType, string classType, string instName, DataMgr *dataMgr); virtual ~RendererBase(); //! Pure virtual method //! Any OpenGL initialization is performed in initializeGL //! It will be called from an OpenGL rendering context. //! Sets _initialized to true if successful. virtual int initializeGL(GLManager *glManager); //! Obtain the Visualizer associated with this Renderer string GetVisualizer() { return _winName; } //! Identify the name of the current renderer //! \return name of renderer string GetMyName() const { return (_instName); }; string GetInstanceName() const { return GetMyName(); } //! Identify the type of the current renderer //! \return type of renderer string GetMyType() const { return (_classType); }; //! Identify the params belonging to the current renderer //! \return params for renderer string GetMyParamsType() const { return (_paramsType); }; //! Identifiy the dataset associated with the current renderer //! \return dataset name string GetMyDatasetName() const { return (_dataSetName); }; //! Return boolean indicating whether initializeGL has been //! successfully called //! bool IsGLInitialized() const { return (_glInitialized); } protected: const ParamsMgr *_paramsMgr; string _winName; string _dataSetName; string _paramsType; string _classType; string _instName; DataMgr * _dataMgr; GLManager *_glManager; //! Pure virtual method //! Any OpenGL initialization is performed in initializeGL //! It will be called from an OpenGL rendering context. virtual int _initializeGL() = 0; public: //! Renderers need to be deleted during the draw loop //! to ensure the correct OpenGL context is bound void FlagForDeletion(); bool IsFlaggedForDeletion() const; DataMgr *GetDataMgr() const { return _dataMgr; } RendererBase() {} private: bool _glInitialized; bool _flaggedForDeletion; }; //! \class Renderer //! \ingroup Public_Render //! \brief A class that performs rendering in a Visualizer //! \author Alan Norton //! \version 3.0 //! \date July 2015 //! //! Renderer class is a pure virtual class that supports //! OpenGL rendering in the VAPOR visualizer window, using a RenderParams instance to describe the rendering. //! All Renderer classes must derive from this class. class RENDER_API Renderer : public RendererBase { public: //! Constructor should be invoked by any derived renderers. //! It is invoked when the user enables a renderer. //! Provides any needed setup of renderer state, but not of OpenGL state. // Renderer(const ParamsMgr *pm, string winName, string dataSetName, string paramsType, string classType, string instName, DataMgr *dataMgr); virtual ~Renderer(); //! Get default z value at the base of the domain. Useful //! for applying a height value to 2D renderers. //! \param[in] dataMgr Current (valid) dataMgr //! \retval default height value for current dataset double GetDefaultZ(DataMgr *dataMgr, size_t ts) const; //! All OpenGL rendering is performed in the paintGL method. //! This invokes _paintGL on the renderer subclass //! \param[in] dataMgr Current (valid) dataMgr //! \retval int zero if successful. virtual int paintGL(bool fast); //! Clear render cache //! //! Called whenever renderer should clear any cached data // void ClearCache() { _clearCache(); }; #ifdef VAPOR3_0_0_ALPHA #endif #ifdef VAPOR3_0_0_ALPHA //! Call setBypass to indicate that the renderer will not work until the state of the params is changed //! This will result in the renderer not being invoked for the specified timestep //! \param[in] int timestep The timestep when the renderer fails void setBypass(int timestep) { if (_currentRenderParams) _currentRenderParams->setBypass(timestep); } //! Partial bypass is currently only used by DVR and Isosurface renderers. //! Indicates a renderer that should be bypassed at //! full resolution but not necessarily at interactive resolution. //! \param[in] timestep Time step that should be bypassed void setPartialBypass(int timestep) { if (_currentRenderParams) _currentRenderParams->setPartialBypass(timestep); } //! SetAllBypass is set to indicate all (or no) timesteps should be bypassed //! Should be set true when render failure is independent of timestep //! Should be set false when state changes and rendering should be reattempted. //! \param[in] val indicates whether it is being turned on or off. void setAllBypass(bool val) { if (_currentRenderParams) _currentRenderParams->setAllBypass(val); } //! doBypass indicates the state of the bypass flag. //! \param[in] timestep indicates the timestep being checked //! \retval bool indicates that the rendering at the timestep should be bypassed. bool doBypass(int timestep) { return (_currentRenderParams && _currentRenderParams->doBypass(timestep)); } //! doAlwaysBypass is used in the presence of partial bypass. //! Indicates that the rendering should be bypassed at any resolution //! \param[in] int timestep Time step //! \retval bool value of flag bool doAlwaysBypass(int timestep) { return (_currentRenderParams && _currentRenderParams->doAlwaysBypass(timestep)); } //! General method to force a renderer to re-obtain its data. //! Default does nothing //! Must be re-implemented if //! there is state or a cache that is retained between renderings. virtual void setAllDataDirty() { return; } #endif #ifdef VAPOR3_0_0_ALPHA //! Set the current ControlExec //! \param[in] ds Current DataStatus instance static void SetControlExec(ControlExec *ce) { _controlExec = ce; } //! @name Internal //! Internal methods not intended for general use //! ///@{ //! Static method invoked during Undo and Redo of Renderer enable or disable. //! This function must be passed in Command::CaptureStart for enable and disable rendering. //! It causes the Undo and Redo operations on enable/disable renderer to actually create //! or destroy the renderer. //! \sa UndoRedoHelpCB_T //! \param[in] isUndo indicates whether an Undo or Redo is being performed //! \param[in] instance indicates the RenderParams instance that is enabled or disabled //! \param[in] beforeP is a copy of the InstanceParams at the start of the Command //! \param[in] afterP is a copy of the InstanceParams at the end of the Command //! \param[in] auxPrev is a copy of auxiliary InstanceParams at the start of the Command, not currently used //! \param[in] afterP is a copy of auxiliary InstanceParams at the end of the Command, not currently used static void UndoRedo(bool isUndo, int instance, Params *beforeP, Params *afterP, Params *auxPrev = 0, Params *auxNext = 0); #endif #ifdef VAPOR3_0_0_ALPHA //! Construct transform of form (x,y)-> (a[0]x+b[0],a[1]y+b[1],const) //! Mapping [-1,1]X[-1,1] into local 3D volume coordinates. //! This is used to map plane coordinates (for various 2D renderers) into User coordinates //! \param[in] orientation is 0 1 or 2 for z, y, or x-axis orientation. //! \param[out] a is linear term of mapping //! \param[out] b is constant term of mapping //! \param[out] constVal is the coordinate along the axis orthogonal to the image of the mapping //! \param[out] mappedDims gives the three axes of the mapped image void buildLocal2DTransform(int dataOrientation, float a[2], float b[2], float *constVal, int mappedDims[3]); #endif #ifdef VAPOR3_0_0_ALPHA //! Obtain the extents of a region that contains a rotated (3D) box associated with a renderer. //! \param[out] regMin Minimum coordinates of containing region. //! \param[out] regMix Maximum coordinates of containing region. void getLocalContainingRegion(float regMin[3], float regMax[3]); #endif //! Render the colorbar for this renderer (if it has one) void renderColorbar(); ///@} //! Obtain the current RenderParams instance //! \retval RenderParams* current render params RenderParams *GetActiveParams() const { return (_paramsMgr->GetRenderParams(_winName, _dataSetName, _paramsType, _instName)); } ViewpointParams *GetViewpointParams() const { return _paramsMgr->GetViewpointParams(_winName); } AnnotationParams *GetAnnotationParams() const { return _paramsMgr->GetAnnotationParams(_winName); } Transform *GetDatasetTransform() const { return GetViewpointParams()->GetTransform(_dataSetName); } void ApplyTransform(MatrixManager *mm) const; static void ApplyTransform(MatrixManager *mm, const Transform *dataset, const Transform *renderer); static void ApplyDatasetTransform(GLManager *gl, const Transform *dataset); protected: Renderer() {} virtual std::string _getColorbarVariableName() const; //! All OpenGL rendering is performed in the pure virtual paintGL method. virtual int _paintGL(bool fast) = 0; //! Enable specified clipping planes during the GL rendering. This //! method clips the scene to the bounding box. See //!! RenderParams::GetBox() //! May be invoked during _paintGL() by classes derived from this class. //! Clipping planes are specified in User coordinates. //! //! \param[in] haloFrac Fraction of bounding box that should be used to //! extend the min and max clippig planes. For example, if a min extent //! is zero, and a max extent is 1.0, and haloFrac is 0.1 then the //! min clipping plane will be set to -0.1 and the max to 1.1 //! //! \sa DisableClippingPlanes void EnableClipToBox(ShaderProgram *shader, float haloFrac = 0.0) const; //! Disable clipping planes. //! If clipping is enabled this method should be called prior to //! returning from _paintGL() // void DisableClippingPlanes(); //! Get clipping planes in the model/user coordinates. //! There are six planes in total that get stored in "planes" //! It is the caller's responsibility to allocate memory for 24 floats. void GetClippingPlanes(float planes[24]) const; //! return true if all of the specified variables exist in the DataMgr //! at the specified timestep, refinement level, and lod. If \p zeroOK //! is true variables named "0" or "" evaluate to true. // virtual bool VariableExists(size_t ts, std::vector &varnames, int level, int lod, bool zeroOK) const; virtual void _clearCache() = 0; static const int _imgHgt; static const int _imgWid; unsigned char * _colorbarTexture; string _fontName; private: size_t _timestep; #ifdef VAPOR3_0_0_ALPHA static ControlExec *_controlExec; #endif }; ////////////////////////////////////////////////////////////////////////// // // RendererFactory Class // ///////////////////////////////////////////////////////////////////////// class RENDER_API RendererFactory { public: static RendererFactory *Instance(); void RegisterFactoryFunction(string myName, string myParamsName, function classFactoryFunction); Renderer *(CreateInstance(const ParamsMgr *pm, string winName, string dataSetName, string classType, string instName, DataMgr *dataMgr)); string GetRenderClassFromParamsClass(string paramsClass) const; string GetParamsClassFromRenderClass(string renderClass) const; std::vector GetFactoryNames() const; private: map> _factoryFunctionRegistry; map _factoryMapRegistry; RendererFactory(); RendererFactory(const RendererFactory &); RendererFactory &operator=(const RendererFactory &); }; ////////////////////////////////////////////////////////////////////////// // // RendererRegistrar Class // // Register RendererBase derived class with: // // static RendererRegistrar // registrar("myclassname", "myparamsclassname"); // // where 'RendererClass' is a class derived from 'Renderer', and // "myclassname" is the name of the class // ///////////////////////////////////////////////////////////////////////// template class RENDER_API RendererRegistrar { public: RendererRegistrar(string classType, string paramsClassType) { // register the class factory function // RendererFactory::Instance()->RegisterFactoryFunction(classType, paramsClassType, [](const ParamsMgr *pm, string winName, string dataSetName, string classType, string instName, DataMgr *dataMgr) -> Renderer * { return new T(pm, winName, dataSetName, instName, dataMgr); }); } }; }; // namespace VAPoR #endif // RENDERER_H ================================================ FILE: include/vapor/ResourcePath.h ================================================ #pragma once #include "vapor/MyBase.h" #include namespace Wasp { COMMON_API std::string GetResourcePath(const std::string &name); COMMON_API std::string GetSharePath(const std::string &name); //! Returns full python installation path //! e.g. /home/lib/python2.7 COMMON_API std::string GetPythonPath(); //! Returns python version //! e.g. 3.6 COMMON_API std::string GetPythonVersion(); //! Returns python home //! e.g. if python if installed in /home/lib/python2.7 //! this will return /home on Linux/Mac but it will return //! /home/lib/python2.7 on Windows COMMON_API std::string GetPythonDir(); //! Register an additional function which returns a path for a given resource. //! This function will be given precidence over the default resource search paths. COMMON_API void RegisterResourceFinder(std::string (*cb)(const std::string &)); }; // namespace Wasp ================================================ FILE: include/vapor/STLUtils.h ================================================ #pragma once #include #include #include #include #include #include #include namespace STLUtils { template bool Contains(const std::vector &toSearch, const T &object) { return std::find(toSearch.cbegin(), toSearch.cend(), object) != toSearch.cend(); } template void AppendTo(std::vector &a, const std::vector &b) { a.insert(a.end(), b.begin(), b.end()); } template std::vector Slice(const std::vector &a, int from, int to = -1) { return std::vector(a.begin() + from, to < 0 ? a.end() : a.begin() + to); } template const std::vector MapKeys(const std::map m) { // const auto keys = std::views::keys(m); // return vector(keys.begin(), keys.end()); vector keys; keys.reserve(m.size()); for (const auto &it : m) keys.push_back(it.first); return keys; } template vector Filter(const std::vector &v, std::function f) { vector v2; std::copy_if(v.begin(), v.end(), std::back_inserter(v2), f); return v2; } template bool BeginsWith(const T &str, const T &match) { return str.size() >= match.size() && equal(match.begin(), match.end(), str.begin()); } COMMON_API bool BeginsWith(const std::string &str, const std::string &match); COMMON_API bool Contains(const std::string &toSearch, const std::string &query); COMMON_API bool ContainsIgnoreCase(const std::string &toSearch, const std::string &query); COMMON_API bool EndsWith(const std::string &str, const std::string &match); COMMON_API std::string ToLower(std::string str); COMMON_API std::vector Split(std::string str, const std::string &delimeter); COMMON_API std::string Join(const std::vector &parts, const std::string &delimeter); COMMON_API std::string ReplaceAll(std::string source, const std::string &oldSegment, const std::string &newSegment); COMMON_API std::string GetCurrentDateTimestamp(); template vector SyncToRemove(const vector &truth, const vector &cache) { vector toRemove; for (const auto &x : cache) if (!STLUtils::Contains(truth, x)) toRemove.push_back(x); return toRemove; } template vector SyncToAdd(const vector &truth, const vector &cache) { vector toAdd; for (const auto &x : truth) if (!STLUtils::Contains(cache, x)) toAdd.push_back(x); return toAdd; } } // namespace STLUtils ================================================ FILE: include/vapor/SetHDF5PluginPath.h ================================================ #pragma once #include #include "vapor/MyBase.h" #include "vapor/ResourcePath.h" namespace VAPoR { void SetHDF5PluginPath() { char *existing = getenv("HDF5_PLUGIN_PATH"); if (existing) { printf("Using custom HDF5_PLUGIN_PATH: '%s'\n", existing); return; } int rc=0; std::string plugins = "HDF5_PLUGIN_PATH=" + Wasp::GetSharePath("plugins"); #ifdef WIN32 rc=_putenv(plugins.c_str()); #else rc = setenv("HDF5_PLUGIN_PATH", Wasp::GetSharePath("plugins").c_str(), 1); #endif if (rc != 0) Wasp::MyBase::SetErrMsg("Unable to set environtment variable s", plugins.c_str()); } }; // namespace VAPoR ================================================ FILE: include/vapor/SettingsParams.h ================================================ //************************************************************************ // * // Copyright (C) 2015 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: SettingsParams.h // // Authors: // Scott Pearse // Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: February 2018 // // Description: Defines the SettingsParams class. // This class supports parameters associted with the // Settings panel, describing the settings settings of the app. // #ifndef SETTINGSPARAMS_H #define SETTINGSPARAMS_H #include #include //! \class SettingsParams //! \ingroup Public_Params //! \brief A class for describing settings at settings. //! \authors Scott Pearse, Alan Norton //! \version 3.0 //! \date February 2018 //! The SettingsParams class controls various features set when the application starts. //! There is only a global SettingsParams, that //! is used throughout the application //! class PARAMS_API SettingsParams : public VAPoR::ParamsBase { public: SettingsParams(VAPoR::ParamsBase::StateSave *ssave, bool loadFromFile = true); SettingsParams(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node); SettingsParams(const SettingsParams &rhs); SettingsParams &operator=(const SettingsParams &rhs); void Init(); ~SettingsParams(); int GetNumThreads() const; void SetNumThreads(int num); long GetCacheMB() const; void SetCacheMB(long val); long GetTextureSize() const; void SetTextureSize(long val); void SetTexSizeEnable(bool val); bool GetTexSizeEnable() const; bool GetAutoStretchEnabled() const; void SetAutoStretchEnabled(bool val); int GetJpegQuality() const; void SetJpegQuality(int quality); bool GetSessionAutoSaveEnabled() const; void SetSessionAutoSaveEnabled(bool enabled); int GetChangesPerAutoSave() const; void SetChangesPerAutoSave(int changes); string GetAutoSaveSessionFile() const; void SetAutoSaveSessionFile(string file); void SetDefaultAutoSaveFile(string file); string GetSessionDir() const; void SetSessionDir(string name); string GetDefaultSessionDir() const; void SetDefaultSessionDir(string dir); string GetMetadataDir() const; void SetMetadataDir(string dir); string GetDefaultMetadataDir() const; void SetDefaultMetadataDir(string dir); string GetTFDir() const; void SetTFDir(string dir); string GetDefaultTFDir() const; void SetDefaultTFDir(string dir); string GetFlowDir() const; void SetFlowDir(string dir); string GetDefaultFlowDir() const; void SetDefaultFlowDir(string dir); string GetPythonDir() const; void SetPythonDir(string dir); string GetDefaultPythonDir() const; void SetDefaultPythonDir(string dir); int GetFontSize() const; void SetFontSize(int size); string GetFontFile() const; void SetFontFile(string file); bool GetDontShowIntelDriverWarning() const; void SetDontShowIntelDriverWarning(bool b); string GetCurrentPrefsPath() const; void SetCurrentPrefsPath(string pth); void Reinit(); const std::string getShortName() { return _shortName; } void SetFidelityDefault3D(long lodDef, long refDef); void SetFidelityDefault2D(long lodDef, long refDef); static string GetClassType() { return (_classType); } int SaveSettings() const; static const string _sessionAutoSaveEnabledTag; std::string GetSettingsPath() const; void SetAutoCheckForUpdates(bool b); bool GetAutoCheckForUpdates() const; void SetAutoCheckForNotices(bool b); bool GetAutoCheckForNotices() const; void SetCasperCheckForVGL(bool b); bool GetCasperCheckForVGL() const; static const string UseAllCoresTag; static const string AutoCheckForUpdatesTag; static const string AutoCheckForNoticesTag; static const string CasperVGLCheck; bool LoadFromSettingsFile(); void FindDefaultSettingsPath(); private: static const string _classType; static const string _shortName; static const string _numThreadsTag; static const string _cacheMBTag; static const string _texSizeTag; static const string _texSizeEnableTag; static const string _currentPrefsPathTag; static const string _sessionDirTag; static const string _defaultSessionDirTag; static const string _metadataDirTag; static const string _defaultMetadataDirTag; static const string _tfDirTag; static const string _defaultTfDirTag; static const string _flowDirTag; static const string _defaultFlowDirTag; static const string _pythonDirTag; static const string _defaultPythonDirTag; static const string _fidelityDefault2DTag; static const string _fidelityDefault3DTag; static const string _autoStretchTag; static const string _jpegQualityTag; static const string _changesPerAutoSaveTag; static const string _autoSaveFileLocationTag; static const string _defaultAutoSaveFileTag; static const string _fontFileTag; static const string _fontSizeTag; static const string _dontShowIntelDriverWarningTag; static const string _settingsNeedsWriteTag; void _swapTildeWithHome(std::string &file) const; string _settingsPath; }; #endif // SETTINGS_H ================================================ FILE: include/vapor/Shader.h ================================================ #pragma once #include #include namespace VAPoR { //! \class Shader //! \ingroup Public_Render //! //! \brief Provides a C++ interface to the OpenGL shader construct //! //! \author Stanislaw Jaroszynski //! \date August, 2018 class RENDER_API Shader : public Wasp::MyBase { unsigned int _id; int _successStatus; bool _compiled; unsigned int _type; std::string _name; public: //! Allocate a new C++ shader and specify the type. An OpenGL shader //! is not allocated until it is compiled //! //! \param[in] type OpenGL shader type enum //! Shader(unsigned int type); ~Shader(); //! \param[in] source GLSL source code //! //! \retval 1 is returned on success //! \retval -1 is returned on failure //! int CompileFromSource(const std::string &source); //! Calls glGetShaderInfoLog std::string GetLog() const; unsigned int GetID() const; unsigned int GetType() const; bool WasCompilationSuccessful() const; }; } // namespace VAPoR ================================================ FILE: include/vapor/ShaderManager.h ================================================ #pragma once #include "vapor/IResourceManager.h" #include "vapor/ShaderProgram.h" #include #include namespace VAPoR { //! \class ShaderManager //! \ingroup Public_Render //! //! \brief Resource management class for shaders //! //! \author Stanislaw Jaroszynski //! \date August, 2018 class RENDER_API ShaderManager : public IResourceManager { std::map> _dependencyModifiedTimes; std::vector _getSourceFilePaths(const std::string &name) const; bool _wasFileModified(const std::string &path) const; static std::string _getNameFromKey(const std::string &key); static std::vector _getDefinesFromKey(const std::string &key); public: ShaderProgram * GetShader(const std::string &name); SmartShaderProgram GetSmartShader(const std::string &name); int LoadResourceByKey(const std::string &key); //! \param[in] path to GLSL source code file //! //! \retval Shader* is returned on success //! \retval nullptr is returned on failure //! static Shader *CompileNewShaderFromFile(const std::string &path, const std::vector &defines = {}); //! Returns an OpenGL shader type enum based on the file extension. //! Valid extensions are .vert, .frag, and .geom //! //! \param[in] path to GLSL source code file //! static unsigned int GetShaderTypeFromPath(const std::string &path); //! Implements the following preprocessor directives: //! - #pragma auto_version //! This sets the GLSL version to the highest available //! //! - #include FileName.glsl //! c-style include without quotes. Path is relative to shader base path //! This will also update line numbers with the #line directive //! //! - #define X //! Each item in the defines list is added to the GLSL code after the #version directive //! //! \param[in] path to GLSL source code file //! \param[in] defines list of definitions to be added to source //! static std::string PreProcessShader(const std::string &path, const std::vector &defines = {}); static std::vector GetShaderDependencies(const std::string &path); }; } // namespace VAPoR ================================================ FILE: include/vapor/ShaderProgram.h ================================================ #pragma once #include #include #include #include #include namespace VAPoR { //! \class ShaderProgram //! \ingroup Public_Render //! //! \brief Provides a C++ interface to the OpenGL shader program construct //! //! \author Stanislaw Jaroszynski //! \date August, 2018 //! //! Automatically manages sampler uniforms and the active gl texture. //! This allows samplers to be set simply like uniforms. class Shader; class Texture; class RENDER_API ShaderProgram : public Wasp::MyBase { unsigned int _id; std::vector _shaders; bool _linked; int _successStatus; std::map _samplerLocations; public: enum class Policy { Strict, Relaxed }; static Policy UniformNotFoundPolicy; ShaderProgram(); ~ShaderProgram(); //! \retval 1 is returned on success //! \retval -1 is returned on failure //! int Link(); void Bind(); bool IsBound() const; static void UnBind(); static int GetBoundProgramID(); void AddShader(Shader *s); //! \param[in] type OpenGL shader type enum //! \param[in] source GLSL source code //! //! \retval 1 is returned on success //! \retval -1 is returned on failure //! int AddShaderFromSource(unsigned int type, const char *source); unsigned int GetID() const; unsigned int WasLinkingSuccessful() const; int GetAttributeLocation(const std::string &name) const; int GetUniformLocation(const std::string &name) const; bool HasUniform(const std::string &name) const; void ComputeSamplerLocations(); template bool SetUniform(const std::string &name, const T &value) const; void SetUniform(int location, const int &value) const; void SetUniform(int location, const float &value) const; void SetUniform(int location, const glm::vec2 &value) const; void SetUniform(int location, const glm::vec3 &value) const; void SetUniform(int location, const glm::vec4 &value) const; void SetUniform(int location, const glm::mat4 &value) const; void SetUniform(int location, const glm::ivec2 &value) const; void SetUniform(int location, const glm::ivec3 &value) const; void SetUniform(int location, const std::vector &value) const; template void SetUniformArray(const std::string &name, int count, const T *values) const; void SetUniformArray(int location, int count, const int *values) const; void SetUniformArray(int location, int count, const float *values) const; void SetUniformArray(int location, int count, const glm::vec3 *values) const; void SetUniformArray(int location, int count, const glm::vec4 *values) const; //! This function behaves just like setting a uniform //! //! \param[in] name uniform name //! \param[in] value an instance of VAPoR::Texture //! //! \retval false if uniform name is not found //! template bool SetSampler(const std::string &name, const T &texture) const; std::string GetLog() const; void PrintUniforms() const; static const char *GLTypeToString(const unsigned int type); static bool IsGLTypeSampler(const unsigned int type); }; //! \class SmartShaderProgram //! \ingroup Public_Render //! //! \brief Provides a C++ interface to the OpenGL shader program construct //! //! \author Stanislaw Jaroszynski //! \date August, 2018 //! //! This class causes shaders to automatically bind when requested from the ShaderManager. //! Once the object becomes out of scope, the shader is unbound. //! Since this class is intended to be used as an object, not a pointer, IsValid replaces //! the usual NULL check class SmartShaderProgram { ShaderProgram *_program; public: SmartShaderProgram(ShaderProgram *program); ~SmartShaderProgram(); ShaderProgram *operator->() { return _program; } bool IsValid() const; friend class ShaderManager; }; } // namespace VAPoR ================================================ FILE: include/vapor/SignificanceMap.h ================================================ // // $Id: SignificanceMap.h,v 1.5 2012/02/28 18:15:58 ypolius Exp $ // #ifndef _SignificanceMap_h_ #define _SignificanceMap_h_ #include #include "vapor/VAssert.h" #include #include // using namespace std; //#include "MyBase.h" #ifndef BITSPERBYTE #define BITSPERBYTE 8 #endif namespace VAPoR { // //! \class SignificanceMap //! \brief Implements a significance map //! \author John Clyne //! \version $Revision: 1.5 $ //! \date $Date: 2012/02/28 18:15:58 $ //! //! This class implements a quick and dirty significance map - a mapping //! indicating which entries in an array are valid and which are not. //! class WASP_API SignificanceMap : public Wasp::MyBase { public: SignificanceMap(); //! //! Significance map constructors for 1D, 2D, 3D, and 4D maps //! //! \param[in] nx Dimension of X axis (fastest varying) //! \param[in] ny Dimension of Y axis (second fastest varying) //! \param[in] nz Dimension of Z axis (third fastest varying) //! \param[in] nt Dimension of Z axis (fourth fastest varying) //! \param[in] dims A vector specifying the number of dimensions and their //! lengths. //! SignificanceMap(size_t nx, size_t ny = 1, size_t nz = 1, size_t nt = 1); SignificanceMap(std::vector dims); // //! Significance map constructors for 1D, 2D, 3D, and 4D maps, using //! a previously created map. I.e. a map returned from GetMap() //! //! \param[in] map An encoded significance map returned by GetMap() //! \param[in] nx Dimension of X axis (fastest varying) //! \param[in] ny Dimension of Y axis (second fastest varying) //! \param[in] nz Dimension of Z axis (third fastest varying) //! \param[in] nt Dimension of Z axis (fourth fastest varying) //! \param[in] dims A vector specifying the number of dimensions and their //! lengths. // SignificanceMap(const unsigned char *map, size_t nx, size_t ny = 1, size_t nz = 1, size_t nt = 1); SignificanceMap(const unsigned char *map, std::vector dims); //! Significance map copy constructor //! SignificanceMap(const SignificanceMap &); ~SignificanceMap(); //! Set the shape (dimension) of a significance map //! //! This method changes the shape (dimension) of a significance map //! //! \param[in] nx Dimension of X axis (fastest varying) //! \param[in] ny Dimension of Y axis (second fastest varying) //! \param[in] nz Dimension of Z axis (third fastest varying) //! \param[in] nt Dimension of Z axis (fourth fastest varying) //! \param[in] dims A vector specifying the number of dimensions and their //! lengths. int Reshape(std::vector dims); int Reshape(size_t nx, size_t ny = 1, size_t nz = 1, size_t nt = 1); //! Return the shape of a significance map //! void GetShape(std::vector &dims) const { dims = _dimsVec; }; //! Mark a map entry as significant. //! //! This method marks a particular coordinate as significant. //! The coordinate parameters, \p x, \p y, \p z, and \p t, must lie within the //! range [0..n-1], where n-1 is the value passed as the coordinates //! dimension to the constructor. No attempt is to prevent duplicate //! entries. If a coordinate is not specified its default value is zero. //! //! \param[in] x X coordinate //! \param[in] y Y coordinate //! \param[in] z Z coordinate //! \param[in] t T coordinate //! \param[in] idx coordinate specified as an offset from a linear array //! //! \retval status a negative value is returned on failure //! int Set(size_t idx); int SetXYZT(size_t x, size_t y = 0, size_t z = 0, size_t t = 0); //! Return true if the indicated entry is significant. Test() returns //! false if the entry is out of range or in range, but not set //! //! \param[in] x X coordinate //! \param[in] y Y coordinate //! \param[in] z Z coordinate //! \param[in] t T coordinate //! \param[in] idx coordinate specified as an offset from a linear array //! bool inline Test(size_t idx) const; bool inline TestXYZT(size_t x, size_t y = 0, size_t z = 0, size_t t = 0) const; //! Mark the indicated entry as insignificant //! //! This method clears the indicated entry (marks it as insignificant) //! //! \retval status a negative value is returned on failure //! int Clear(size_t idx); int ClearXYZT(size_t x, size_t y = 0, size_t z = 0, size_t t = 0); //! Clear entire map //! void Clear(); //! Return the number of significant entries in the map //! size_t GetNumSignificant() const { return (_sigMapVec.size()); }; //! Return coordinates for an ordered entry in the map //! //! Return the coordinates of the ith significant entry in the //! significant map. Note, the mapping between an entry number and //! it's coordinates returned by this function are no longer valid after //! the map is modified (set, cleared, or sorted). If the coordinate pointers, //! x,y,z,t are null, no value is returned for that coordinate. //! //! Valid values for 'i' are in the range [0..GetNumSignificant()-1] //! \retval status a negative value is returned on failure //! // int GetCoordinatesXYZT(size_t i, size_t *x, size_t *y = NULL, size_t *z = NULL, size_t *t = NULL) const; int GetCoordinates(size_t i, size_t *idx) const; //! Restart counters for GetNextEntry() //! //! This method is used to restore internal counters used by the //! GetNextEntry() method //! //! \sa GetMextEntry() // void GetNextEntryRestart(); // //! Return the coordinates for the next signficant entry in the //! significance map. This method may be called iteratively until //! all map entries are turned. The GetNextEntryRestart() method may be used //! to reset the current entry to the first one in the map. A zero //! value is returned if the entry list is exhausted. The coordinates //! are returned in the order that they were set with Set() or SetXYZT(). //! //! \note For sequential processing of map entries it is preferable to //! use this method over the indexed GetEntry() method. //! //! \retval status a negative value is returned on failure //! // int GetNextEntry(size_t *idx); int GetNextEntryXYZT(size_t *x, size_t *y, size_t *z, size_t *t); //! Return size in bytes of an encoded signficance map of given size //! //! This static member method returns the size in bytes of an encoded //! signficance map that would be returned by GetMap() for a //! SignificanceMap of given dimension, \p dims, and number of //! entries, \p num_entries. // static size_t GetMapSize(vector dims, size_t num_entries); //! Return size in bytes of an encoded signficance map of given size //! //! This method returns the size in bytes of an encoded //! signficance map that would be returned by GetMap() after //! the given number of entries, \p num_entries, were stored. //! This method can be used to determine the amount of space //! required to store an encoded signficance map after //! \p num_entries entries have been stored in it. In general, //! this is not the same value for the current significance map. //! //! \param num_entries[in] Number of entries in the signficance map //! //! \sa GetMap() // size_t GetMapSize(size_t num_entries) const; //! Return size in bytes of current encoded signficance map //! //! This method returns the size in bytes of the encoded, //! current signficance map that would be returned by GetMap(). //! //! \sa GetMap() // size_t GetMapSize() const { return (GetMapSize(GetNumSignificant())); }; //! Return the compressed representation of the significance map. The data //! returned are only suitable passing as an argument to the constructor. //! //! \param map[out] Encoded significance map data //! \param maplen[out] Length of \p map in bytes // void GetMap(const unsigned char **map, size_t *maplen); //! Return the compressed representation of the significance map. The data //! returned are only suitable passing as an argument to the constructor. //! //! \param map[out] Encoded significance map data. Caller is //! responsible for allocating memory. The array \p map must be of //! size GetMapSize(). // void GetMap(unsigned char *map); // //! Reinitialize the significance map with the map, \p map , returned from a //! previous call to GetMap. //! //! \param[in] map An encoded significance map returned by GetMap() //! //! \sa GetMap() //! //! \retval status a negative value is returned on failure //! // int SetMap(const unsigned char *map); //! Append a SignificanceMap //! //! This method appends the coordinates in the map, \p smap, to //! this map, creating a new signficance map containing the entries //! from both this signficance map and \p smap. The ordering of the new map //! is as if the GetNextEntry() method of \p smap was called //! iteratively, storing the the returned coordinate with Set(). //! //! The dimensions of \p smap must match those of this map or error //! condition is returned. //! //! \param[in] smap An encoded significance map returned by GetMap() //! //! \retval status a negative value is returned on failure //! // int Append(const SignificanceMap &smap); //! Invert the signficance map //! //! This method inverts the signficance map, making insignficant //! coordinates (those not found in the significance map) into significant //! coordinates. The ordering of the newly created map will be from //! smallest to largest coordinate. //! //! \sa GetNextEntry() // void Invert(); //! Sort map entries //! //! This method sorts the entries of the significance maps so that //! they are stored from smallest to largest. Once sorted, map entries //! returned by GetNextEntry() are guaranteed to be returned from //! smallest to largest //! //! \sa GetNextEntry() // void Sort(); SignificanceMap &operator=(const SignificanceMap &map); friend std::ostream &operator<<(std::ostream &o, const SignificanceMap &sigmap); private: static const int HEADER_SIZE = 64; static const int VDF_VERSION = 2; size_t _nx; size_t _ny; size_t _nz; size_t _nt; // dimensions of map (when # dims < 5) bool _sorted; // true if the map is sorted in ascending order std::vector _dimsVec; // Map dimensions size_t _sigMapSize; // product of dimensions (max coordinate index) std::vector _sigMapVec; // The signficance map int _bits_per_idx; // # bits needed to encode a coordinate unsigned char *_sigMapEncode; // compactly encoded version of _sigMapVec size_t _sigMapEncodeSize; // size of _sigMapEncode in bytes size_t _idxentry; // Counter for sequential access to sig. map int _SignificanceMap(std::vector dims); int _SignificanceMap(const unsigned char *map, std::vector dims); static size_t _GetBitsPerIdx(vector dims); }; bool inline SignificanceMap::Test(size_t idx) const { if (idx > _sigMapSize) return (0); // Invalid coordinate if (_sorted) { return (binary_search(_sigMapVec.begin(), _sigMapVec.end(), idx)); } for (size_t i = 0; i < _sigMapVec.size(); i++) { if (_sigMapVec[i] == idx) return (1); } return (0); } bool inline SignificanceMap::TestXYZT(size_t x, size_t y, size_t z, size_t t) const { size_t idx = (t * _nz * _ny * _nx) + (z * _ny * _nx) + (y * _nx) + x; return (this->Test(idx)); } } // namespace VAPoR #endif ================================================ FILE: include/vapor/SliceParams.h ================================================ #ifndef SLICEPARAMS_H #define SLICEPARAMS_H #include #include namespace VAPoR { //! \class SliceParams //! \brief Class that supports drawing Barbs based on 2D or 3D vector field //! \version 3.0 class PARAMS_API SliceParams : public RenderParams { public: SliceParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave); SliceParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node); virtual ~SliceParams(); virtual int Initialize() override; // Get static string identifier for this params class // static string GetClassType() { return ("SliceParams"); } //! \copydoc RenderParams::GetRenderDim() // virtual size_t GetRenderDim() const override { return (3); } //! \copydoc RenderParams::GetActualColorMapVariableName() virtual string GetActualColorMapVariableName() const override { if (UseSingleColor()) return ""; else return GetVariableName(); } void SetCachedValues(std::vector values); std::vector GetCachedValues() const; bool GetOrientable() const override; private: bool _initialized = false; void _init(); std::vector _cachedValues; }; // End of Class SliceParams }; // namespace VAPoR #endif ================================================ FILE: include/vapor/SliceRenderer.h ================================================ #ifndef SLICERENDERER_H #define SLICERENDERER_H #include #include #include #include #include //#define DEBUG 1 namespace VAPoR { class RENDER_API SliceRenderer : public Renderer { public: SliceRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr); static string GetClassType() { return ("Slice"); } virtual ~SliceRenderer(); protected: virtual int _initializeGL(); virtual int _paintGL(bool fast); private: struct { string varName; string heightVarName; size_t ts; int refinementLevel; int compressionLevel; int textureSampleRate; int orientation; double xRotation; double yRotation; double zRotation; double xOrigin; double yOrigin; double zOrigin; std::vector tf_lut; std::vector tf_minMax; VAPoR::CoordType boxMin, boxMax; VAPoR::CoordType domainMin, domainMax; std::vector sampleLocation; std::vector sliceRotation; std::vector sliceNormal; double sliceOffset; int sliceOrientationMode; } _cacheParams; void _initVAO(); void _initTexCoordVBO(); void _initVertexVBO(); bool _isColormapCacheDirty() const; bool _isDataCacheDirty() const; bool _isBoxCacheDirty() const; void _getExtents(VAPoR::CoordType &min, VAPoR::CoordType &max) const; void _resetColormapCache(); void _resetCache(); void _createDataTexture(std::unique_ptr &dataValues); int _regenerateSlice(); int _getGrid3D(Grid *&grid) const; #ifdef DEBUG void _drawDebugPolygons(); #endif void _configureShader(); void _resetState(); void _initializeState(); bool _initialized; size_t _textureSideSize; GLuint _colorMapTextureID; GLuint _dataValueTextureID; std::vector _windingOrder; std::vector _rectangle3D; GLuint _VAO; GLuint _vertexVBO; GLuint _texCoordVBO; int _colorMapSize; void _clearCache() { _cacheParams.varName.clear(); } }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/SphericalGrid.h ================================================ #ifndef _SphericalGrid_ #define _SphericalGrid_ #include #include #include "RegularGrid.h" #ifdef _WINDOWS #pragma warning(disable : 4251 4100) #endif namespace VAPoR { //! \class SphericalGrid //! //! \brief This class implements a 2D or 3D spherical grid. //! //! This class implements a 2D or 3D spherical grid: a generalization //! of a regular grid where the spacing of grid points along a single dimension //! may vary at each grid point. The spacing along the remaining one (2D case) //! or two (3D case) dimensions is invariant between grid points. For example, //! if K is the spherical dimension than the z coordinate is given by some //! function f(i,j,k): //! //! z = f(i,j,k) //! //! while the remaining x and y coordinates are givey by (i*dx, j*dy) //! for some real dx and dy . //! // class VDF_API SphericalGrid : public RegularGrid { public: //! //! Construct a spherical grid sampling a 3D or 2D scalar function //! //! \param[in] bs A three-element vector specifying the dimensions of //! each block storing the sampled scalar function. //! \param[in] min A three-element vector specifying the ijk index //! of the first point in the grid. The first grid point need not coincide //! with //! block boundaries. I.e. the indecies need not be (0,0,0) //! \param[in] max A three-element vector specifying the ijk index //! of the last point in the grid //! \param[in] extents A six-element vector specifying the user coordinates //! of the first (first three elements) and last (last three elements) of //! the grid points indicated by \p min and \p max, respectively. //! The units are degrees, not radians. //! \param[in] permutation A three-element array indicating the ordering //! of the Longitude, Latitude, and radial dimensions. The array must //! contain some permutation of the set (0,1,2). The permuation (0,1,2) //! indicates that longitude is the fastest varying dimesion, then latitude //! then radius. The permutation (2,1,0) indicates that radius is fastest, //! then latitude, and so on. //! \param[in] periodic A three-element boolean vector indicating //! which i,j,k indecies, respectively, are periodic. //! \param[in] blks An array of blocks containing the sampled function. //! The dimensions of each block //! is given by \p bs. The number of blocks is given by the product //! of the terms: //! //! \code (max[i]/bs[i] - min[i]/bs[i] + 1) \endcode //! //! over i = 0..2. //! //! \param[in] coords An array of blocks with dimension and number the //! same as \p blks specifying the varying dimension grid point coordinates. //! \param[in] varying_dim An enumerant indicating which axis is the //! varying dimension: 0 for I, 1 for J, 2 for K //! SphericalGrid(const size_t bs[3], const size_t min[3], const size_t max[3], const double extents[6], const size_t permutation[3], const bool periodic[3], float **blks); //! //! Construct a spherical grid sampling a 3D or 2D scalar function //! that contains missing values. //! //! This constructor adds a parameter, \p missing_value, that specifies //! the value of missing values in the sampled function. When //! reconstructing the function at arbitrary coordinates special //! consideration is given to grid points with missing values that //! are used in the reconstruction. //! //! \sa GetValue() //! SphericalGrid(const size_t bs[3], const size_t min[3], const size_t max[3], const double extents[6], const size_t permutation[3], const bool periodic[3], float **blks, float missing_value); //! \copydoc RegularGrid::GetValue() //! float GetValue(double x, double y, double z) const; //! \copydoc RegularGrid::GetUserExtents() //! //! Return extents in Cartesian coordinates // virtual void GetUserExtents(double extents[6]) const { for (int i = 0; i < 6; i++) extents[i] = _extentsC[i]; }; //! \copydoc RegularGrid::GetVBoundingBox() //! virtual void GetBoundingBox(const size_t min[3], const size_t max[3], double extents[6]) const; //! \copydoc RegularGrid::GetUserCoordinates() //! int GetUserCoordinates(size_t i, size_t j, size_t k, double *x, double *y, double *z) const; //! \copydoc RegularGrid::GetIJKIndex() //! void GetIJKIndex(double x, double y, double z, size_t *i, size_t *j, size_t *k) const; //! \copydoc RegularGrid::GetIJKIndexFloor() //! void GetIJKIndexFloor(double x, double y, double z, size_t *i, size_t *j, size_t *k) const; //! Return true if the specified point lies inside the grid //! //! This method can be used to determine if a point expressed in //! user coordinates reside inside or outside the grid //! //! \param[in] x coordinate along fastest varying dimension //! \param[in] y coordinate along second fastest varying dimension //! \param[in] z coordinate along third fastest varying dimension //! //! \retval bool True if point is inside the grid //! bool InsideGrid(double x, double y, double z) const; // phi is in range -180 to 180, theta is in range -180/2 to 180/2 // static inline void CartToSph(double x, double y, double z, double *phi, double *theta, double *r); static inline void SphToCart(double phi, double theta, double r, double *x, double *y, double *z); private: double _extentsC[6]; // extents in Cartesian coordinates, ordered x,y,z std::vector _permutation; // permutation vector for coordinate ordering void _GetUserExtents(double extents[6]) const; void _permute(const std::vector &permutation, double result[3], double x, double y, double z) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/StretchedGrid.h ================================================ #ifndef _StretchedGrid_ #define _StretchedGrid_ #include #include #include namespace VAPoR { //! \class StretchedGrid //! //! \brief This class implements a 2D or 3D stretched grid. //! //! This class implements a 2D or 3D stretched grid: a //! specialization of StructuredGrid class where cells are //! quadrilaterals (2D), or cuboids (3D). Hence, stretched grids are //! topologically, but the location of each grid point is expressed //! by functions: //! //! \code //! x = X(i) //! y = Y(j) //! z = Z(k) //! \endcode //! //! // class VDF_API StretchedGrid : public StructuredGrid { public: //! \copydoc StructuredGrid::StructuredGrid() //! //! Construct a regular grid sampling a 3D or 2D scalar function. //! //! This constructor instantiates a stretched grid where the x,y,z //! user coordinates are expressed as follows: //! //! \code //! x = X(i) //! y = Y(j) //! z = Z(k) //! \endcode //! //! The X, Y, and Z user coordinates are specified with \p xcoords, \p xcoords, //! and \p zcoords (if 3D), respectively. //! //! Adds new parameters: //! //! \param[in] xcoords A 1D vector whose size matches that of the I //! dimension of this class, and whose values specify the X user coordinates. //! \param[in] ycoords A 1D vector whose size matches that of the J //! dimension of this class, and whose values specify the Y user coordinates. //! \param[in] zcoords A 1D vector whose size matches that of the K //! dimension of this class, and whose values specify the Z user coordinates. //! //! \sa RegularGrid() // StretchedGrid(const DimsType &dims, const DimsType &bs, const std::vector &blks, const std::vector &xcoords, const std::vector &ycoords, const std::vector &zcoords); StretchedGrid(const std::vector &dims, const std::vector &bs, const std::vector &blks, const std::vector &xcoords, const std::vector &ycoords, const std::vector &zcoords); StretchedGrid() = default; virtual ~StretchedGrid() = default; virtual size_t GetGeometryDim() const override; virtual DimsType GetCoordDimensions(size_t dim) const override; static std::string GetClassType() { return ("Stretched"); } std::string GetType() const override { return (GetClassType()); } // \copydoc GetGrid::GetBoundingBox() // virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override; // \copydoc GetGrid::GetUserCoordinates() // virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override; //! \copydoc Grid::GetIndicesCell //! //! Returns resampling weights if point is found // virtual bool GetIndicesCell(const CoordType &coords, DimsType &indices, double wgts[3]) const; //! \copydoc Grid::GetIndicesCell //! virtual bool GetIndicesCell(const CoordType &coords, DimsType &indices) const override { double dummy[3]; return (GetIndicesCell(coords, indices, dummy)); }; // \copydoc GetGrid::InsideGrid() // virtual bool InsideGrid(const CoordType &coords) const override; //! Returns reference to vector containing X user coordinates //! //! Returns reference to vector passed to constructor //! containing X user coordinates //! const std::vector &GetXCoords() const { return (_xcoords); }; //! Returns reference to vector containing Y user coordinates //! //! Returns reference to vector passed to constructor //! containing Y user coordinates //! const std::vector &GetYCoords() const { return (_ycoords); }; //! Returns reference to vector containing Z user coordinates //! //! Returns reference to vector passed to constructor //! containing Z user coordinates //! const std::vector &GetZCoords() const { return (_zcoords); }; class ConstCoordItrSG : public Grid::ConstCoordItrAbstract { public: ConstCoordItrSG(const StretchedGrid *cg, bool begin); ConstCoordItrSG(const ConstCoordItrSG &rhs); ConstCoordItrSG(); virtual ~ConstCoordItrSG() {} virtual void next(); virtual void next(const long &offset); virtual ConstCoordType &deref() const { return (_coords); } virtual const void * address() const { return this; }; virtual bool equal(const void *rhs) const { const ConstCoordItrSG *itrptr = static_cast(rhs); return (_index == itrptr->_index); } virtual std::unique_ptr clone() const { return std::unique_ptr(new ConstCoordItrSG(*this)); }; private: const StretchedGrid *_sg; DimsType _index; CoordType _coords; }; virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrSG(this, true))); } virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrSG(this, false))); } protected: virtual float GetValueNearestNeighbor(const CoordType &coords) const override; virtual float GetValueLinear(const CoordType &coords) const override; void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override; private: std::vector _xcoords; std::vector _ycoords; std::vector _zcoords; CoordType _minu = {{0.0, 0.0, 0.0}}; CoordType _maxu = {{0.0, 0.0, 0.0}}; void _stretchedGrid(const std::vector &xcoords, const std::vector &ycoords, const std::vector &zcoords); bool _insideGrid(double x, double y, double z, size_t &i, size_t &j, size_t &k, double &xwgt, double &ywgt, double &zwgt) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/StructuredGrid.h ================================================ #ifndef _StructuredGrid_ #define _StructuredGrid_ #include #include #include #include #include #ifdef WIN32 #pragma warning(disable : 4661 4251) // needed for template class #endif namespace VAPoR { //! \class StructuredGrid //! \brief Abstract base class for a 2D or 3D structured grid. //! \author John Clyne //! //! This abstract base class defines a 2D or 3D structured //! grid: a tessellation //! of Euculidean space by quadrilaterals (2D) or hexahdrons (3D). Each //! grid point can be addressed by an index(i,j,k), where \a i, \p j //! and \a k range from 0 to \a dim - 1, where \a dim is the dimension of the //! \a I, \a J, or \a K axis, respectively. Moreover, each grid point //! has a coordinate in a user-defined coordinate system. //! //! The structured grid samples a scalar function at each grid point. The //! scalar function samples are stored as an array decomposed into //! equal-sized blocks. //! //! Because grid samples are repesented internally as arrays, when accessing //! multiple grid points better performance is achieved by using //! unit stride. The \a I axis varies fastest (has unit stride), //! followed by \a J, then \a K. Best performance is achieved //! when using the class iterator: Grid::Iterator. //! //! For methods that allow the specification of grid indecies or coordinates //! as a single parameter tuple (e.g. vector coordinate) the //! first element //! of the tuple corresponds to the \a I axis, etc. //! //! \note Throughout this class grid vertex offsets are specified as //! \a i, \a j, \a k, where \a i, \a j, \a k are integers. User coordinates //! are real values denoted \a x, \a y, \a z, and are given by functions //! \a X(i,j,k), \a Y(i,j,k), \a Z(i,j,k). // class VDF_API StructuredGrid : public Grid { public: //! Construct a structured grid sampling a 3D or 2D scalar function //! //! \copydoc Grid() //! //! The sampled function is represented as a 2D or 3D array, decomposed //! into smaller blocks (tiles in 2D). The dimensions of the array are not //! constrained to coincide with block (tile) boundaries. //! //! The length of parameter vectors \p bs, and \p dim //! must all be either 3 (3D structured grid) or 2 (2D structured grid) //! //! If \p blks is empty a dataless StructuredGrid object is returned. //! Data can not be retrieved from a dataless StructuredGrid. However, //! coordinate access methods may still be invoked. //! StructuredGrid(const std::vector &dims, const std::vector &bs, const std::vector &blks); StructuredGrid(const DimsType &dims, const DimsType &bs, const std::vector &blks); StructuredGrid() = default; virtual ~StructuredGrid() = default; static std::string GetClassType() { return ("Structured"); } std::string GetType() const override { return (GetClassType()); } const DimsType &GetNodeDimensions() const override; const size_t GetNumNodeDimensions() const override; const DimsType &GetCellDimensions() const override { return (_cellDims); }; const size_t GetNumCellDimensions() const override { return GetNumNodeDimensions(); } //! \copydoc Grid::GetCellNodes() //! virtual bool GetCellNodes(const DimsType &cindices, std::vector &nodes) const override; // For grandparent inheritance of // Grid::GetUserCoordinates(const size_t indices[], double coords[]) // using Grid::GetCellNodes; //! \copydoc Grid::GetCellNeighbors() //! virtual bool GetCellNeighbors(const DimsType &cindices, std::vector &cells) const override; //! \copydoc Grid::GetNodeCells() //! virtual bool GetNodeCells(const DimsType &cindices, std::vector &cells) const override; virtual bool GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const override; size_t GetMaxVertexPerFace() const override { return (4); }; size_t GetMaxVertexPerCell() const override { return ((GetTopologyDim() == 3) ? 8 : 4); }; virtual void ClampCoord(const CoordType &coords, CoordType &cCoords) const override; //! \deprecated // virtual void ClampCoord(const double coords[3], double cCoords[3]) const override { Grid::ClampCoord(coords, cCoords); } //! \copydoc Grid::HasInvertedCoordinateSystemHandiness() //! virtual bool HasInvertedCoordinateSystemHandiness() const override; VDF_API friend std::ostream &operator<<(std::ostream &o, const StructuredGrid &sg); protected: private: DimsType _cellDims; void _structuredGrid(const DimsType &dims, const DimsType &bs, const std::vector &blks); }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/TFInterpolator.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: TFInterpolator.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: November 2004 // // Description: Defines the TFInterpolator class: // A class to interpolate transfer function values // Currently only supports linear interpolation // #ifndef TFINTERPOLATOR_H #define TFINTERPOLATOR_H #include #include #include namespace VAPoR { class PARAMS_API TFInterpolator { public: ~TFInterpolator(); // Default is linear enum type { linear, // linearHSV discrete, logarithm, exponential, diverging, linearRGB, linearLAB, linearLCH }; // Determine the interpolated value at intermediate value 0<=r<=1 // where the value at left and right endpoint is known // This method is just a stand-in until we get more sophistication // static float interpolate(type, float leftVal, float rightVal, float r); // Linear interpolation for circular (hue) fcn. values in [0,1). // If it's closer to go around 1, then do so // static float interpCirc(type t, float leftVal, float rightVal, float r); //! Generate the complete diverging color map using the Moreland //! technique from RGB1 to RGB2, placing "white" in the middle. //! The number of points given by the "numColors" variable //! controls the resolution of the color map. //! //! \param[in] RGB1 Start point color for diverging color map. //! \param[in] RGB2 End point color for diverging color map. //! \param[in] Number of colors to generate in the new color map. //! \retval Return status, 1 = success static float *genDivergentMap(float rgb1[3], float rgb2[3], int numColors); // private: //! Interpolation algorithm to generate a single interpolated //! color in a diverging color map. //! //! \param[in] RGB1 Start point color for diverging color map //! \param[in] RGB2 End point color for diverging color map. //! \param[in] The output interpolated RGB value in the divergent map //! \param[in] The interpolation weight of the current color in the color map //! \param[in] Set whether we insert white space between two saturated color control points //! \retval Return status, 1 = success static int divergentInterpolation(float rgb1[3], float rgb2[3], float output[3], float interp, bool corrective = false); //! Interpolation algorithm that applies a corrective white space //! between two saturated color control points //! //! \param[in] RGB1 Start point color for diverging color map //! \param[in] RGB2 End point color for diverging color map. //! \param[in] The output interpolated RGB value in the divergent map //! \param[in] The interpolation weight of the current color in the color map //! \param[in] Set whether we insert white space between two saturated color control points static void correctiveDivergentInterpolation(float rgb1[3], float rgb2[3], float output[3], float interp); //! A function to provide an adjusted hue when interpolating //! to an unsaturated color in Msh space //! \param[in] Input M value to adjust hue to //! \param[in] Input s value to adjust hue to //! \param[in] Input h value to adjust hue to //! \param[in] Second input M value to adjust hue to //! \param[out] Adjusted hue value static float adjustHue(float m1, float s1, float h1, float m2); //! Conversion of Msh to RGB //! \param[in] A 3-tuple color in Msg space //! \param[in] The resultant 3-tuple color in rgb space //! \retval Return status, 1 = success static int msh2srgb(float msh[3], float rgb[3]); //! Conversion of Msh to Lab //! \param[in] A 3-tuple color in Msh space //! \param[in] The resultant 3-tuple color in Lab space //! \retval Return status, 1 = success static int msh2lab(float msh[3], float lab[3]); //! Conversion of Lab to RGB //! \param[in] A 3-tuple color in Lab space //! \param[in] The resultant 3-tuple color in rgb space //! \retval Return status, 1 = success static int lab2srgb(float lab[3], float rgb[3]); //! Conversion from RGB to Msh //! \param[in] A 3-tuple color in rgb space //! \param[in] The resultant 3-tuple color in Msh space //! \retval Return status, 1 = success static int srgb2msh(float rgb[3], float msh[3]); //! Conversion from RGB to Lab //! \param[in] A 3-tuple color in rgb space //! \param[in] The resultant 3-tuple color in Lab space //! \retval Return status, 1 = success static int srgb2lab(float rgb[3], float lab[3]); //! Conversion from Lab to Msh //! \param[in] A 3-tuple color in rgb space //! \param[in] The resultant 3-tuple color in Msh space //! \retval Return status, 1 = success static int lab2msh(float lab[3], float msh[3]); //! Conversion from Lab to Msh //! \param[in] A 3-tuple color in rgb space //! \param[in] The resultant 3-tuple color in xyz space //! \retval Return status, 1 = success static int srgb2xyz(float rgb[3], float xyz[3]); //! Conversion from xyz to rgb //! \param[in] A 3-tuple color in xyz space //! \param[in] The resultant 3-tuple color in rgb space //! \retval Return status, 1 = success static int xyz2srgb(float xyz[3], float rgb[3]); //! Convert an RGB tuple to sRGB //! \param[in] A 3-tuple color in rgb space //! \param[in] The resultant 3-tuple color in sRGB space //! \retval Return status, 1 = success static int rgb2srgb(float rgb[3], float srgb[3]); //! Convert an sRGB tuple to RGB //! \param[in] A 3-tuple color in sRGB space //! \param[in] The resultant 3-tuple color in RGB space //! \retval Return status, 1 = success static int srgb2rgb(float srgb[3], float rgb[3]); static int rgb2hsv(float rgb[3], float hsv[3]); static int hsv2rgb(float hsv[3], float rgb[3]); static float Xn; static float Yn; static float Zn; static float XYZtransferMatrix[9]; static float XYZinverseMatrix[9]; static float *colorMap; }; }; // namespace VAPoR #endif // TFINTERPOLATOR_H ================================================ FILE: include/vapor/TIFWriter.h ================================================ #pragma once #include "vapor/ImageWriter.h" #ifdef WIN32 #include #else #include #endif namespace VAPoR { //! \class TIFWriter //! \ingroup Public_Render //! \brief Writes TIF image files //! \author Stanislaw Jaroszynski class RENDER_API TIFWriter : public ImageWriter { protected: TIFF *tif; int ConfigureWithFormat(Format f); public: static std::vector GetFileExtensions(); TIFWriter(const std::string &path); virtual ~TIFWriter(); virtual int Write(const unsigned char *buffer, const unsigned int width, const unsigned int height); }; } // namespace VAPoR ================================================ FILE: include/vapor/TMSUtils.h ================================================ #pragma once #include #include #include namespace Wasp { namespace TMSUtils { COMMON_API bool IsTMSFile(std::string path); COMMON_API std::string TilePath(std::string file, size_t tileX, size_t tileY, int lod); COMMON_API int GetNumTMSLODs(std::string file); } // namespace TMSUtils } // namespace Wasp ================================================ FILE: include/vapor/TextLabel.h ================================================ #pragma once #include #include namespace VAPoR { struct GLManager; class Font; //! \class TextLabel //! \ingroup Public_Render //! //! \brief Utitlity wrapper for Font class //! //! Creates a 2D label for a point in 2D or 3D space //! //! \author Stanislaw Jaroszynski //! \date August, 2018 class TextLabel { GLManager *_glManager; public: enum Alignment { Left, Center, Right, Top, Bottom }; std::string FontName; unsigned int FontSize; glm::vec4 BackgroundColor; glm::vec4 ForegroundColor; Alignment HorizontalAlignment; Alignment VerticalAlignment; float Padding; TextLabel(GLManager *glManager, const std::string &fontName, unsigned int fontSize); //! Draws a floating text label if a 3D perspective is used or simply text //! if using a pixel coordinate space matrix. Formatting is determined by the //! public variables. //! //! \param[in] position will be transformed according to the current ModelViewProjection matrix //! \param[in] text will be drawn //! void DrawText(const glm::vec3 &position, const std::string &text); void DrawText(const glm::vec2 &position, const std::string &text); Font *GetFont() const; }; } // namespace VAPoR ================================================ FILE: include/vapor/Texture.h ================================================ #pragma once #include namespace VAPoR { class Framebuffer; //! \class Texture //! \ingroup Public_Render //! \brief Wrapper class for an OpenGL texture //! \author Stas Jaroszynski //! \version 1.0 //! \date May 2019 //! //! This class is intended to be used as a member object for a renderer. //! Any use of this class (including the destructor and except the constructor) //! must occur inside the correct OpenGL context. //! class Texture : private NonCopyableMixin { protected: unsigned int _id = 0; unsigned int _width = 0; unsigned int _height = 0; unsigned int _depth = 0; const unsigned int _type; const unsigned int _nDims; public: ~Texture(); int Generate(); int Generate(int filter); void Delete(); bool Initialized() const; void Bind() const; void UnBind() const; int TexImage(int internalFormat, int width, int height, int depth, unsigned int format, unsigned int type, const void *data, int level = 0); static unsigned int GetDimsCount(unsigned int glTextureEnum); protected: Texture(unsigned int type); friend class Framebuffer; }; class Texture1D : public Texture { public: Texture1D(); }; class Texture2D : public Texture { public: Texture2D(); void CopyDepthBuffer(); }; class Texture3D : public Texture { public: Texture3D(); }; class Texture2DArray : public Texture { public: Texture2DArray(); }; }; // namespace VAPoR ================================================ FILE: include/vapor/TrackBall.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: TrackBall.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: July 2004 // // Description: Defines the Trackball class: // This was implemented from Ken Purcell's TrackBall // methods. Additional methods provided to set the TrackBall // based on a viewing frame // /* Copyright (C) 1992 AHPCRC, Univeristy of Minnesota * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program in a file named 'Copying'; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139. */ /* Author: * Ken Chin-Purcell (ken@ahpcrc.umn.edu) * Army High Performance Computing Research Center (AHPCRC) * Univeristy of Minnesota * */ #ifndef TRACKBALL_H #define TRACKBALL_H #include #include /* These vector and quaternion macros complement similar * routines. */ /* The Trackball package gives that nice 3D rotation interface. * A TrackBall class is needed for each rotated scene. */ class RENDER_API Trackball { public: Trackball(); Trackball(float scale[3]); void TrackballSetMatrix(); void TrackballFlip(int axis); void TrackballSpin(); void TrackballStopSpinning(); int TrackballSpinning(); void TrackballSetPosition(double newx, double newy); void TrackballRotate(double newx, double newy); void TrackballPan(double newx, double newy); void TrackballZoom(double newx, double newy); void TrackballCopyTo(Trackball *dst); void TrackballReset(); void GetCenter(double center[3]) const { for (int i = 0; i < 3; i++) center[i] = _center[i]; } bool ReconstructCamera(double position[3], double upVec[3], double viewDir[3]) const; // Note: button is 1,2,3 for left, middle, right void MouseOnTrackball(int eventType, int thisButton, int xcrd, int ycrd, int width, int height); // Initialize the trackball, provide viewer position, direction, upvector, // and the center of rotation (all in trackball coordinate space) // bool setFromFrame(const std::vector &posvec, const std::vector &dirvec, const std::vector &upvec, const std::vector ¢erRot, bool perspective); bool setFromFrame(const double posvec[3], const double dirvec[3], const double upvec[3], const double centerRot[3], bool perspective) { std::vector pos, dir, up, center; for (int i = 0; i < 3; i++) { pos.push_back(posvec[i]); dir.push_back(dirvec[i]); up.push_back(upvec[i]); center.push_back(centerRot[i]); } return setFromFrame(pos, dir, up, center, perspective); } void SetScale(const double scale[3]) { _scale[0] = scale[0]; _scale[1] = scale[1]; _scale[2] = scale[2]; } double GetOrthoSize() const; const double *GetModelViewMatrix() const { return (_modelViewMatrix); } private: void setCenter(const std::vector &newCenter) { _center[0] = newCenter[0]; _center[1] = newCenter[1]; _center[2] = newCenter[2]; } double _qrot[4]; double _qinc[4]; double _trans[3]; double _scale[3]; double _center[3]; double _ballsize; double _lastx, _lasty; bool _perspective; double _modelViewMatrix[16]; }; #endif // TRACKBALL_H ================================================ FILE: include/vapor/Transform.h ================================================ #ifndef TRANSFORM_H #define TRANSFORM_H /* * This class describes a viewpoint */ #include namespace VAPoR { //! \class Transform //! \ingroup Public_Params //! \brief class that indicates location and direction of view //! \author Scott Pearse //! \version 3.0 //! \date October 2017 //! \par //! This class contains all the parameters associated with dataset transforms, //! including the scaling, rotation, and translation of that dataset. //! ddshould be accessed through the TransformParams class. class PARAMS_API Transform : public ParamsBase { public: enum Flags { VIEWPOINT = (1u << 0), RENDERER = (1u << 1) }; Transform(ParamsBase::StateSave *ssave); Transform(ParamsBase::StateSave *ssave, XmlNode *node); virtual ~Transform(); vector GetRotations() const { vector defaultv(3, 0.0); vector rotation = GetValueDoubleVec(_rotationTag, defaultv); return rotation; } void SetRotations(const vector rotation) { SetValueDoubleVec(_rotationTag, "Set rotation transform", rotation); } vector GetTranslations() const { vector defaultv(3, 0.0); vector translation = GetValueDoubleVec(_translationTag, defaultv); return translation; } void SetTranslations(const vector translation) { SetValueDoubleVec(_translationTag, "Set translation transform", translation); } vector GetScales() const { vector defaultv(3, 1.0); vector scale = GetValueDoubleVec(_scaleTag, defaultv); return scale; } void SetScales(const vector scale); vector GetOrigin() const; void SetOrigin(const vector origin); bool IsOriginInitialized() const; void SetOriginInitialized(bool value); static string GetClassType() { return ("Transform"); } private: static const string _translationTag; static const string _rotationTag; static const string _scaleTag; static const string _originTag; static const string _originInitializedTag; }; }; // namespace VAPoR #endif // TRANSFORM_H ================================================ FILE: include/vapor/TwoDDataParams.h ================================================ #ifndef TWODDATAPARAMS_H #define TWODDATAPARAMS_H #include #include namespace VAPoR { //! \class TwoDDataParams //! \brief Class that supports drawing Barbs based on 2D or 3D vector field //! \author Alan Norton //! \version 3.0 class PARAMS_API TwoDDataParams : public RenderParams { public: TwoDDataParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave); TwoDDataParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node); virtual ~TwoDDataParams(); #ifdef VAPOR3_0_0_ALPHA //! \copydoc Params::Validate() virtual void Validate(int type); #endif // Get static string identifier for this params class // static string GetClassType() { return ("TwoDDataParams"); } //! \copydoc RenderParams::GetRenderDim() // virtual size_t GetRenderDim() const override { return (2); } //! \copydoc RenderParams::GetActualColorMapVariableName() virtual string GetActualColorMapVariableName() const override { return GetVariableName(); } private: void _init(); #ifdef VAPOR3_0_0_ALPHA void _validateTF(int type, DataMgr *dataMgr); #endif }; // End of Class TwoDDataParams }; // namespace VAPoR #endif ================================================ FILE: include/vapor/TwoDDataRenderer.h ================================================ //************************************************************************ // * // Copyright (C) 2008 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: TwoDDataRender.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: March 2009 // // Description: Definition of the TwoDDataRenderer class // #ifndef TWODDATARENDERER_H #define TWODDATARENDERER_H #include #include #include #include #include #include #include namespace VAPoR { class RENDER_API TwoDDataRenderer : public TwoDRenderer { public: TwoDDataRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr); virtual ~TwoDDataRenderer(); // Get static string identifier for this render class // static string GetClassType() { return ("TwoDData"); } protected: int _initializeGL(); int _paintGL(bool fast); int GetMesh(DataMgr *dataMgr, GLfloat **verts, GLfloat **normals, GLsizei &nverts, GLsizei &width, GLsizei &height, GLuint **indices, GLsizei &nindices, bool &structuredMesh); const GLvoid *GetTexture(DataMgr *dataMgr, GLsizei &width, GLsizei &height, GLint &internalFormat, GLenum &format, GLenum &type, size_t &texelSize, bool &gridAligned); private: class _grid_state_c { public: _grid_state_c() = default; _grid_state_c(size_t numRefLevels, int refLevel, int lod, string hgtVar, string meshName, size_t ts, vector minExts, vector maxExts) : _numRefLevels(numRefLevels), _refLevel(refLevel), _lod(lod), _hgtVar(hgtVar), _meshName(meshName), _ts(ts), _minExts(minExts), _maxExts(maxExts) { } void clear() { _numRefLevels = 0; _refLevel = _lod = -1; _hgtVar = _meshName = ""; _ts = 0; _minExts.clear(); _maxExts.clear(); } bool operator==(const _grid_state_c &rhs) const { return (_numRefLevels == rhs._numRefLevels && _refLevel == rhs._refLevel && _lod == rhs._lod && _hgtVar == rhs._hgtVar && _meshName == rhs._meshName && _ts == rhs._ts && _minExts == rhs._minExts && _maxExts == rhs._maxExts); } bool operator!=(const _grid_state_c &rhs) const { return (!(*this == rhs)); } private: size_t _numRefLevels; int _refLevel; int _lod; string _hgtVar; string _meshName; size_t _ts; vector _minExts; vector _maxExts; }; class _tex_state_c { public: _tex_state_c() = default; _tex_state_c(int refLevel, int lod, string varname, size_t ts, vector minExts, vector maxExts) : _refLevel(refLevel), _lod(lod), _varname(varname), _ts(ts), _minExts(minExts), _maxExts(maxExts) { } void clear() { _refLevel = _lod = -1; _varname = ""; _ts = 0; _minExts.clear(); _maxExts.clear(); } bool operator==(const _tex_state_c &rhs) const { return (_refLevel == rhs._refLevel && _lod == rhs._lod && _varname == rhs._varname && _ts == rhs._ts && _minExts == rhs._minExts && _maxExts == rhs._maxExts); } bool operator!=(const _tex_state_c &rhs) const { return (!(*this == rhs)); } private: int _refLevel; int _lod; string _varname; size_t _ts; vector _minExts; vector _maxExts; }; _grid_state_c _grid_state; _tex_state_c _tex_state; GLsizei _texWidth; GLsizei _texHeight; size_t _texelSize; SmartBuf _sb_verts; SmartBuf _sb_normals; SmartBuf _sb_indices; SmartBuf _sb_texture; GLsizei _vertsWidth; GLsizei _vertsHeight; GLsizei _nindices; GLsizei _nverts; GLuint _cMapTexID; GLfloat *_colormap; size_t _colormapsize; bool _gridStateDirty() const; void _gridStateClear(); void _gridStateSet(); bool _texStateDirty(DataMgr *dataMgr) const; void _texStateSet(DataMgr *dataMgr); void _texStateClear(); int _getMeshStructured(DataMgr *dataMgr, const StructuredGrid *g, double defaultZ); int _getMeshUnStructured(DataMgr *dataMgr, const Grid *g, double defaultZ); int _getMeshUnStructuredHelper(DataMgr *dataMgr, const Grid *g, double defaultZ); int _getMeshStructuredDisplaced(DataMgr *dataMgr, const StructuredGrid *g, double defaultZ); int _getMeshStructuredPlane(DataMgr *dataMgr, const StructuredGrid *g, double defaultZ); const GLvoid *_getTexture(DataMgr *dataMgr); int _getOrientation(DataMgr *dataMgr, string varname); void _clearCache() { _tex_state.clear(); } }; }; // namespace VAPoR #endif // TWODDATARENDERER_H ================================================ FILE: include/vapor/TwoDRenderer.h ================================================ //---------------- ---------------------------------------------------------- // // Copyright (C) 2016 // University Corporation for Atmospheric Research // All Rights Reserved // //---------------------------------------------------------------------------- #ifndef TWODRENDERER_H #define TWODRENDERER_H #include // Must be included first!!! #include #include #include namespace VAPoR { //! \class TwoDRenderer //! \brief //! \author John Clyne //! \version 3.0 //! \date March 2016 class RENDER_API TwoDRenderer : public Renderer { public: //! Constructor, must invoke Renderer constructor //! \param[in] Visualizer* pointer to the visualizer where this will draw //! \param[in] RenderParams* pointer to the ArrowParams describing //! this renderer TwoDRenderer(const ParamsMgr *pm, string winName, string dataSetName, string paramsType, string classType, string instName, DataMgr *dataMgr); //! Destructor // virtual ~TwoDRenderer(); protected: // Protected pure virual methods // // Return a 2D structured or unstructured mesh // // verts : contains a packed representation of the x,y,z coordinates // of each grid point. Thus size is height * width * sizeof(float) * 3 // // normals : contains surface normal at each vertex. Need not be unit length // Same packing as verts // // nverts : number of vertices and number of normals in verts, and // normals, respectively. A single vertex or normal consists of three // components. Thus if nverts == 1 then verts and normals each contain // one three-component element. // // width : For structured grids contains number of grid points along // fastest varying dimension. For unstructured grids contains *total* // number of grid points // // height : For structured grids contains number of grid points along // second fastest varying dimension. For unstructured grids should be set to // one. // // indices : indexes into verts and normals to generate either triangles // (unstructured mesh) or triangle strips (structured mesh). // Compatible with index argument to GLDrawElements // // nindices : num elements in indices // // structuredMesh : bool, true if structured mesh, false if unstructured // virtual int GetMesh(DataMgr *dataMgr, GLfloat **verts, GLfloat **normals, GLsizei &nverts, GLsizei &width, GLsizei &height, GLuint **indices, GLsizei &nindices, bool &structuredMesh) = 0; // Return data values for mesh returned with GetMesh(). The returned // array may or may not be coincident with the mesh nodes. In the latter // case the array returned is a uniformally 2D sampling of the data // values on the mesh. // // width : For grid aligned data (gridAligned == true) contains number of // data values along // fastest varying dimension. For non-aligned data (gridAligned == false) // contains *total* number of elements // // height : For grid aligned data (gridAligned == true) contains number of // data values along // second fastest varying dimension. For non-aligned data // (gridAligned == false) should be set to one. // // type : Type of data returned by GetTexture(). If gridAligned // is true, type must be GL_FLOAT // // texelSize: Size, in bytes, of a single element returned by GetTexture. // // gridAligned : bool. If true data are coincident with mesh returned by // GetMesh() // virtual const GLvoid *GetTexture(DataMgr *dataMgr, GLsizei &width, GLsizei &height, GLint &internalFormat, GLenum &format, GLenum &type, size_t &texelSize, bool &gridAligned) = 0; virtual void _clearCache() = 0; //! \copydoc Renderer::_initializeGL() virtual int _initializeGL(); //! \copydoc Renderer::_paintGL() virtual int _paintGL(bool fast); //! Compute 2D surface normals at each vertex. //! //! This protected method can be used by derived classes to calculate //! unitized normals from a set of vertices by calculating the gradient //! at each vertex. The normal vectors are determined by looking //! at z-coords of adjacent vertices in both //! x and y. Suppose that dzx is the change in z associated with //! an x-change of dz, and that dzy is the change in z associated with //! a y-change of dy. Let the normal //! vector be (a,b,c). Then a/c is equal to dzx/dx, and b/c is //! equal to dzy/dy. So (a,b,c) is proportional to (dzx*dy, dzy*dx, 1) //! //! \param[in] verts A pointer to a 2D array of surface vertices, dimensioned //! \p w by \p h by 3. Vertices are store as inteleaved //! triplets: vx0, vy0, vz0, vx1, vy1, vz1, ... vxn, vyn, vzn, where //! \b n = \p w * \p h - 1 //! //! \param[in] w Width (length of fastest varying dimension) //! of \p verts in grid points //! \param[in] h Height (length of second fastest varying dimension) //! of \p verts in grid points //! //! \param[out] normals A pointer to a 2D array of the same size as \p verts //! that will contain the computed, unitized surface normals, stored //! in interleaved form. // void ComputeNormals(const GLfloat *verts, GLsizei w, GLsizei h, GLfloat *normals); private: GLuint _textureID; const GLvoid *_texture; GLfloat * _texCoords; GLsizei _texWidth; GLsizei _texHeight; GLint _texInternalFormat; GLenum _texFormat; GLenum _texType; size_t _texelSize; bool _gridAligned; bool _structuredMesh; GLfloat * _verts; GLfloat * _normals; GLuint * _indices; GLsizei _meshWidth; GLsizei _meshHeight; GLsizei _nindices; GLsizei _nverts; SmartBuf _sb_texCoords; GLuint _VAO, _VBO, _dataVBO, _EBO; void _openGLInit(); void _openGLRestore(); void _renderMesh(); void _renderMeshUnAligned(); void _renderMeshAligned(); void _computeTexCoords(GLfloat *tcoords, size_t w, size_t h) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/UDUnitsClass.h ================================================ // // $Id$ // #ifndef _UDUnitsClass_h_ #define _UDUnitsClass_h_ #include #include #include #include #include union ut_unit; struct ut_system; namespace VAPoR { //! \class UDUnits //! //! Provides a C++ wrapper for Unidata's Udunits-2 package: //! http://www.unidata.ucar.edu/software/udunits/udunits-2/udunits2.html //! //! Error handling: most methods in this class return an integer status //! flag, with a negative value indicating error. Error messages for the //! most recent error can be retrieved with GetErrMsg(). //! class VDF_API UDUnits { public: UDUnits(); ~UDUnits(); static std::string GetDatabasePath(); //! Initialize the Udunits-2 data base. Must be called after the //! constructor, prior to any other class methods //! //! \retval status A negative int is returned on failure //! int Initialize(); //! Return true if the string provided by \p unitstr is recognized //! by Udunits-2 as a unit of pressure //! bool IsPressureUnit(std::string unitstr) const; //! Return true if the string provided by \p unitstr is recognized //! by Udunits-2 as a unit of time //! bool IsTimeUnit(std::string unitstr) const; //! Return true if the string provided by \p unitstr is recognized //! by Udunits-2 as a unit of Latitude //! bool IsLatUnit(std::string unitstr) const; //! Return true if the string provided by \p unitstr is recognized //! by Udunits-2 as a unit of Longitude //! bool IsLonUnit(std::string unitstr) const; //! Return true if the string provided by \p unitstr is recognized //! by Udunits-2 as a unit of Longitude or Latitude //! bool IsLatOrLonUnit(std::string unitstr) const; //! Return true if the string provided by \p unitstr is recognized //! by Udunits-2 as a unit of length //! bool IsLengthUnit(std::string unitstr) const; //! Return true if the unit identified by the string contained in \p unitstr //! can be converted into the unit identified by \p unit. Otherwise false //! is returned //! bool AreUnitsConvertible(const ut_unit *unit, std::string unitstr) const; //! Returns true if the string contained in \p unitstr is recognized //! as a valid unit by the Udunits-2 data base //! bool ValidUnit(std::string unitstr) const; //! Convert one unit to another //! //! This method performs conversion between different units, when //! possible (see AreUnitsConvertible()). For example, converting //! meters to feet. The string \p from specifies the unit to convert //! from, and the string \p to specifies the unit to convert to. //! //! \param[in] from A string specifying the source unit //! \param[in] to A string specifying the destination unit //! \param[in] src An array of source unit values //! \param[out] dst An array large enough to store the converted //! unit values. //! \param[in] n The number of elements in \p from //! //! \retval boolean A boolean status is returned indicating whether //! the conversion took place. Conversion will fail if the units are //! not convertible. No error message is generated. //! //! \sa AreUnitsConvertible //! bool Convert(const std::string from, const std::string to, const float *src, float *dst, size_t n) const; bool Convert(const std::string from, const std::string to, const double *src, double *dst, size_t n) const; //! Decode time specified in seconds to year, month, day, hour, minute //! and second. //! //! This method uses Udunits-2 ut_decode_time() function to perform //! time conversion //! void DecodeTime(double seconds, int *year, int *month, int *day, int *hour, int *minute, int *second) const; //! Encode time specified to years, month, day, hour, minute //! and seconds to seconds //! //! This method uses Udunits-2 ut_encode_time() function to perform //! time conversion //! double EncodeTime(int year, int month, int day, int hour, int minute, int second) const; //! Get the most recent error message //! //! This method returns a string containing the most recently occurring //! error message, if any. //! std::string GetErrMsg() const; private: std::map _statmsg; int _status; ut_unit * _pressureUnit; ut_unit * _timeUnit; ut_unit * _latUnit; ut_unit * _lonUnit; ut_unit * _lengthUnit; ut_system * _unitSystem; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/UnstructuredGrid.h ================================================ #ifndef _UnstructuredGrid_ #define _UnstructuredGrid_ #include #include #include #include #include #ifdef WIN32 #pragma warning(disable : 4661 4251) // needed for template class #endif namespace VAPoR { //! \class UnstructuredGrid //! \brief Abstract base class for a 2D or 3D unstructured grid. //! \author John Clyne //! //! This abstract base class defines a 2D or 3D unstructured //! grid. //! //! The unstructured grid samples a scalar function at each grid point. The //! scalar function samples are stored as an array decomposed into //! equal-sized blocks. //! //! Because grid samples are repesented internally as arrays, when accessing //! multiple grid points better performance is achieved by using //! unit stride. The \a I axis varies fastest (has unit stride), //! followed by \a J, then \a K. Best performance is achieved //! when using the class iterator: UnstructuredGrid::Iterator. //! //! For methods that allow the specification of grid indecies or coordinates //! as a single parameter tuple (e.g. vector coordinate) the //! first element //! of the tuple corresponds to the \a I axis, etc. //! //! \note Throughout this class grid vertex offsets are specified as //! \a i, \a j, \a k, where \a i, \a j, \a k are integers. User coordinates //! are real values denoted \a x, \a y, \a z, and are given by functions //! \a X(i,j,k), \a Y(i,j,k), \a Z(i,j,k). // class VDF_API UnstructuredGrid : public Grid { public: enum Location { NODE, CELL, EDGE }; //! //! Construct a unstructured grid sampling a 3D or 2D scalar function //! //! \param[in] vertexDims Dimensions of grid nodes (vertices). //! The product of the //! elements of \p vertexDims gives the total number of nodes in the mesh. //! If the rank of \p vertexDims is greater than one the mesh is assumed to //! be structured along the slower varying dimensions (e.g. a layered mesh) //! //! \param[in] faceDims Dimensions of grid cells. The product of the //! elements of \p cells gives the total number of cells in the mesh. //! If the rank of \p cells is greater than one the mesh is assumed to //! be structured along the slower varying dimensions (e.g. a layered mesh). //! Moreover, the slowest varying dimensions must be one less than the //! corresponding dimension of \p vertexDims. //! //! \param[in] edgeDims Dimensions of grid edges. The product of the //! elements of \p edges gives the total number of edges in the mesh. //! If the rank of \p edges is greater than one the mesh is assumed to //! be structured along the slower varying dimensions (e.g. a layered mesh). //! Moreover, the slowest varying dimensions must be one less than the //! corresponding dimension of \p vertexDims. //! //! \param[in] blks Grid data values. The location of the data values //! (node, cell, edge) is determined by \p location. If the dimensions //! (\p vertexDims, etc) are multi-dimensional the size of \p blks must //! match the size of the slowest varying dimension. Each element of //! \p blks must point to an area of memory of size \b n elements, where //! \b n is the first element of \p vertexDims, \p faceDims, or \p edgeDims //! as indicated by \p location. //! //! \param[in] vertexOnFace An array with dimensions: //! //! \p faceDims[0] * maxVertexPerFace //! that provides for each cell the 1D node IDs of each corner node. //! If the number of corner nodes is less than \p maxVertexPerFace //! the missing node indices will be equal to GetMissingID(); //! The ordering of the nodes is counter-clockwise. //! //! \param[in] faceOnVertex An array with dimensions: //! //! \p vertexDims[0] * maxFacePerVertex //! that provides for each vertex the 1D node IDs of each face //! sharing that vertex. //! If the number of faces is less than \p maxFacePerVertex //! the missing face indices will be equal to GetMissingID(); //! The ordering of the faces is counter-clockwise. //! //! \param[in] faceOnFace An array with dimensions: //! //! \p faceDims[0] * maxVertexPerFace //! that provides for each cell the 1D cell IDs of border cell //! If the number of corner nodes is less than \p maxVertexPerFace //! the missing node indices will be equal to GetMissingID(). If an //! edge is on the mesh boundary the index will be set to the value //! GetBoundaryIndex(). //! The ordering of the neighboring faces is counter-clockwise. //! //! \param[in] location The location of grid data: at the nodes, edge-centered, //! or cell-centered //! //! \param[in] maxVertexPerFace The maxium number of nodes that a face //! may have. //! //! \param[in] nodeOffset The offset from zero for the first element //! in \p vertexOnFace //! //! \param[in] cellOffset The offset from zero for the first element //! in \p faceOnVertex or \p faceOnFace // UnstructuredGrid(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector &blks, size_t topology_dimension, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset ); UnstructuredGrid(const std::vector &vertexDims, const std::vector &faceDims, const std::vector &edgeDims, const std::vector &bs, const std::vector &blks, size_t topology_dimension, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset ); UnstructuredGrid() = default; virtual ~UnstructuredGrid() = default; static std::string GetClassType() { return ("Unstructured"); } std::string GetType() const override { return (GetClassType()); } bool GetCellNodes(const DimsType &cindices, std::vector &nodes) const override; //! \copydoc Grid::GetCellNeighbors() //! virtual bool GetCellNeighbors(const DimsType &cindices, std::vector &cells) const override; //! \copydoc Grid::GetNodeCells() //! virtual bool GetNodeCells(const DimsType &indices, std::vector &cells) const override; size_t GetMaxVertexPerFace() const override { return (_maxVertexPerFace); }; size_t GetMaxVertexPerCell() const override { return ((GetTopologyDim() == 3) ? 2 * GetMaxVertexPerFace() : GetMaxVertexPerFace()); }; //! Return the grid node dimmensions //! const VAPoR::DimsType &GetNodeDimensions() const override; const size_t GetNumNodeDimensions() const override; //! Return the grid cell dimmensions //! const DimsType &GetCellDimensions() const override { return (_faceDims); } virtual const size_t GetNumCellDimensions() const override { return (_nDims); } //! Return the grid edge dimmensions //! const DimsType &GetEdgeDimensions() const { return (_edgeDims); } //! Get missing element ID //! //! Return the value used to indicate termination of a list of element IDs //! size_t GetMissingID() const { return (_missingID); } void SetMissingID(size_t v) { _missingID = v; } //! Get boundary element ID //! //! Return the value used to indicate termination of a list of element IDs //! size_t GetBoundaryID() const { return (_boundaryID); } void SetBoundaryID(size_t v) { _boundaryID = v; } virtual void ClampCoord(const CoordType &coords, CoordType &cCoords) const override { cCoords = coords; } //! \deprecated // virtual void ClampCoord(const double coords[3], double cCoords[3]) const override { Grid::ClampCoord(coords, cCoords); } // A no-op for unstructured grids. Needs to be set in the constuctor :-( // virtual void SetNodeOffset(long offset) override {} virtual void SetCellOffset(long offset) override {} ///////////////////////////////////////////////////////////////////////////// // // Iterators // ///////////////////////////////////////////////////////////////////////////// VDF_API friend std::ostream &operator<<(std::ostream &o, const UnstructuredGrid &sg); protected: const int *_vertexOnFace; const int *_faceOnVertex; const int *_faceOnFace; size_t _maxVertexPerFace; size_t _maxFacePerVertex; Location _location; private: DimsType _vertexDims; DimsType _faceDims; DimsType _edgeDims; size_t _nDims; int _missingID; int _boundaryID; void _unstructuredGrid(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector &blks, size_t topology_dimension, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset ); }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/UnstructuredGrid2D.h ================================================ #ifndef _UnstructuredGrid2D_ #define _UnstructuredGrid2D_ #include #include #include #include #include #include #include #ifdef WIN32 #pragma warning(disable : 4661 4251) // needed for template class #endif namespace VAPoR { //! \class UnstructuredGrid2D //! \brief class for a 2D unstructured grid. //! \author John Clyne //! // class VDF_API UnstructuredGrid2D : public UnstructuredGrid { public: //! Construct a unstructured grid sampling 2D scalar function //! // UnstructuredGrid2D(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug, const UnstructuredGridCoordless &zug, std::shared_ptr qtr); UnstructuredGrid2D(const std::vector &vertexDims, const std::vector &faceDims, const std::vector &edgeDims, const std::vector &bs, const std::vector &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug, const UnstructuredGridCoordless &zug, std::shared_ptr qtr); UnstructuredGrid2D() = default; virtual ~UnstructuredGrid2D() { if (_qtr) _qtr = nullptr; } std::shared_ptr GetQuadTreeRectangle() const { return (_qtr); } virtual DimsType GetCoordDimensions(size_t dim) const override; virtual size_t GetGeometryDim() const override; static std::string GetClassType() { return ("Unstructured2D"); } std::string GetType() const override { return (GetClassType()); } virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override; bool GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const override; virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override; bool GetIndicesCell(const CoordType &coords, DimsType &indices) const override { std::vector lambda; std::vector> nodes; return (GetIndicesCell(coords, indices, nodes, lambda)); } // For grandparent inheritance of // Grid::GetIndicesCell(const double coords[3], size_t indices[3]) // using Grid::GetIndicesCell; //! \copydoc Grid::GetIndicesCell() //! //! \param[out] nodes Indices of vertices of the cell identified by \p indices //! \param[out] lambda Interpolation weights that may be applied to values //! at nodes identified by \p nodes //! bool GetIndicesCell(const CoordType &coords, DimsType &indices, std::vector> &nodes, std::vector &lambda) const; bool InsideGrid(const CoordType &coords) const override; float GetValueNearestNeighbor(const CoordType &coords) const override; float GetValueLinear(const CoordType &coords) const override; ///////////////////////////////////////////////////////////////////////////// // // Iterators // ///////////////////////////////////////////////////////////////////////////// class ConstCoordItrU2D : public Grid::ConstCoordItrAbstract { public: ConstCoordItrU2D(const UnstructuredGrid2D *ug, bool begin); ConstCoordItrU2D(const ConstCoordItrU2D &rhs); ConstCoordItrU2D(); virtual ~ConstCoordItrU2D() {} virtual void next(); virtual void next(const long &offset); virtual ConstCoordType &deref() const { return (_coords); } virtual const void * address() const { return this; }; virtual bool equal(const void *rhs) const { const ConstCoordItrU2D *itrptr = static_cast(rhs); return (_xCoordItr == itrptr->_xCoordItr && _yCoordItr == itrptr->_yCoordItr && _zCoordItr == itrptr->_zCoordItr); } virtual std::unique_ptr clone() const { return std::unique_ptr(new ConstCoordItrU2D(*this)); }; private: size_t _ncoords; ConstIterator _xCoordItr; ConstIterator _yCoordItr; ConstIterator _zCoordItr; CoordType _coords; }; virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrU2D(this, true))); } virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrU2D(this, false))); } VDF_API friend std::ostream &operator<<(std::ostream &o, const UnstructuredGrid2D &sg); protected: virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override; private: UnstructuredGridCoordless _xug; UnstructuredGridCoordless _yug; UnstructuredGridCoordless _zug; std::shared_ptr _qtr; bool _insideGrid(const CoordType &coords, size_t &face, std::vector &nodes, double *lambda, int &nlambda) const; bool _insideGridNodeCentered(const CoordType &coords, size_t &face, std::vector &nodes, double *lambda, int &nlambda) const; bool _insideGridFaceCentered(const CoordType &coords, size_t &face, std::vector &nodes, double *lambda, int &nlambda) const; bool _pointInsideBoundingRectangle(const double pt[], const double verts[], int n) const; bool _insideFace(size_t face, double pt[2], std::vector &node_indices, double *lambda, int &nlambda) const; std::shared_ptr _makeQuadTreeRectangle() const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/UnstructuredGrid3D.h ================================================ #pragma once #include #include #include #include #include #include #ifdef WIN32 #pragma warning(disable : 4661 4251) // needed for template class #endif namespace VAPoR { //! \class UnstructuredGrid3D //! \brief class for a Layered unstructured grid. //! // class VDF_API UnstructuredGrid3D : public UnstructuredGrid { public: //! Construct a unstructured grid sampling Layered scalar function //! // UnstructuredGrid3D(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug, const UnstructuredGridCoordless &zug); UnstructuredGrid3D(const std::vector &vertexDims, const std::vector &faceDims, const std::vector &edgeDims, const std::vector &bs, const std::vector &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug, const UnstructuredGridCoordless &zug); UnstructuredGrid3D() = default; virtual ~UnstructuredGrid3D() = default; virtual DimsType GetCoordDimensions(size_t dim) const override; virtual size_t GetGeometryDim() const override; static std::string GetClassType() { return ("Unstructured3D"); } std::string GetType() const override { return (GetClassType()); } virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override; bool GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const override; virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override; bool GetIndicesCell(const CoordType &coords, DimsType &indices) const override; bool InsideGrid(const CoordType &coords) const override; float GetValueNearestNeighbor(const CoordType &coords) const override; float GetValueLinear(const CoordType &coords) const override; ///////////////////////////////////////////////////////////////////////////// // // Iterators // ///////////////////////////////////////////////////////////////////////////// class ConstCoordItrU3D : public Grid::ConstCoordItrAbstract { public: ConstCoordItrU3D(const UnstructuredGrid3D *ug, bool begin); ConstCoordItrU3D(const ConstCoordItrU3D &rhs); ConstCoordItrU3D(); virtual ~ConstCoordItrU3D() {} virtual void next() override; virtual void next(const long &offset) override; virtual ConstCoordType &deref() const override { return (_coords); } virtual const void * address() const override { return this; }; virtual bool equal(const void *rhs) const override { const ConstCoordItrU3D *itrptr = static_cast(rhs); return (_xCoordItr == itrptr->_xCoordItr && _yCoordItr == itrptr->_yCoordItr && _zCoordItr == itrptr->_zCoordItr); } virtual std::unique_ptr clone() const override { return std::unique_ptr(new ConstCoordItrU3D(*this)); }; private: const UnstructuredGrid3D *_ug; ConstIterator _xCoordItr; ConstIterator _yCoordItr; ConstIterator _zCoordItr; CoordType _coords; }; virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrU3D(this, true))); } virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrU3D(this, false))); } VDF_API friend std::ostream &operator<<(std::ostream &o, const UnstructuredGrid3D &sg); protected: virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override; private: UnstructuredGridCoordless _xug; UnstructuredGridCoordless _yug; UnstructuredGridCoordless _zug; bool _insideGrid(const CoordType &coords, DimsType &cindices, std::vector &nodes2D, std::vector &lambda, float zwgt[2]) const; }; }; // namespace VAPoR ================================================ FILE: include/vapor/UnstructuredGridCoordless.h ================================================ #ifndef _UnstructuredGridCoordless_ #define _UnstructuredGridCoordless_ #include #include #include #include #include #ifdef WIN32 #pragma warning(disable : 4661 4251) // needed for template class #endif namespace VAPoR { //! \class UnstructuredGridCoordless //! \brief class for a 2D unstructured grid. //! \author John Clyne //! // class VDF_API UnstructuredGridCoordless : public UnstructuredGrid { public: //! Construct a unstructured grid sampling 2D scalar function //! // UnstructuredGridCoordless(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector &blks, size_t topology_dimension, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset) : UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, topology_dimension, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset) { } UnstructuredGridCoordless(const std::vector &vertexDims, const std::vector &faceDims, const std::vector &edgeDims, const std::vector &bs, const std::vector &blks, size_t topology_dimension, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset) : UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, topology_dimension, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset) { } UnstructuredGridCoordless() = default; virtual ~UnstructuredGridCoordless() = default; virtual DimsType GetCoordDimensions(size_t dim) const override { return (DimsType{1, 1, 1}); } static std::string GetClassType() { return ("UnstructuredCoordless"); } std::string GetType() const override { return (GetClassType()); } virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override { minu = {0.0, 0.0, 0.0}; maxu = {0.0, 0.0, 0.0}; } bool GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const override { return (false); } virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override {} bool GetIndicesCell(const CoordType &, DimsType &) const override { return (false); } bool InsideGrid(const CoordType &coords) const override { return (false); } float GetValueNearestNeighbor(const CoordType &coords) const override { return (0.0); } float GetValueLinear(const CoordType &coords) const override { return (0.0); } virtual size_t GetGeometryDim() const override { return (0); } ///////////////////////////////////////////////////////////////////////////// // // Iterators // ///////////////////////////////////////////////////////////////////////////// class ConstCoordItrUCoordless : public Grid::ConstCoordItrAbstract { public: ConstCoordItrUCoordless(const UnstructuredGridCoordless *ug, bool begin) {} ConstCoordItrUCoordless(const ConstCoordItrUCoordless &rhs) {} ConstCoordItrUCoordless(); virtual ~ConstCoordItrUCoordless() {} virtual void next() {} virtual void next(const long &offset) {} virtual ConstCoordType &deref() const { return (_coords); } virtual const void * address() const { return this; }; virtual bool equal(const void *rhs) const { return (true); } virtual std::unique_ptr clone() const { return std::unique_ptr(new ConstCoordItrUCoordless(*this)); }; private: CoordType _coords; }; virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrUCoordless(this, true))); } virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrUCoordless(this, false))); } VDF_API friend std::ostream &operator<<(std::ostream &o, const UnstructuredGridCoordless &sg); protected: virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override { minu = {0.0, 0.0, 0.0}; maxu = {0.0, 0.0, 0.0}; } private: }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/UnstructuredGridLayered.h ================================================ #ifndef _UnstructuredGridLayered_ #define _UnstructuredGridLayered_ #include #include #include #include #include #include #ifdef WIN32 #pragma warning(disable : 4661 4251) // needed for template class #endif namespace VAPoR { //! \class UnstructuredGridLayered //! \brief class for a Layered unstructured grid. //! \author John Clyne //! // class VDF_API UnstructuredGridLayered : public UnstructuredGrid { public: //! Construct a unstructured grid sampling Layered scalar function //! // UnstructuredGridLayered(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug, const UnstructuredGridCoordless &zug, std::shared_ptr qtr); UnstructuredGridLayered(const std::vector &vertexDims, const std::vector &faceDims, const std::vector &edgeDims, const std::vector &bs, const std::vector &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug, const UnstructuredGridCoordless &zug, std::shared_ptr qtr); UnstructuredGridLayered() = default; virtual ~UnstructuredGridLayered() = default; std::shared_ptr GetQuadTreeRectangle() const { return (_ug2d.GetQuadTreeRectangle()); } virtual DimsType GetCoordDimensions(size_t dim) const override; virtual size_t GetGeometryDim() const override; static std::string GetClassType() { return ("UnstructuredLayered"); } std::string GetType() const override { return (GetClassType()); } virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override; bool GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const override; virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override; bool GetIndicesCell(const CoordType &coords, DimsType &indices) const override; bool InsideGrid(const CoordType &coords) const override; float GetValueNearestNeighbor(const CoordType &coords) const override; float GetValueLinear(const CoordType &coords) const override; ///////////////////////////////////////////////////////////////////////////// // // Iterators // ///////////////////////////////////////////////////////////////////////////// class ConstCoordItrULayered : public Grid::ConstCoordItrAbstract { public: ConstCoordItrULayered(const UnstructuredGridLayered *ug, bool begin); ConstCoordItrULayered(const ConstCoordItrULayered &rhs); ConstCoordItrULayered(); virtual ~ConstCoordItrULayered() {} virtual void next(); virtual void next(const long &offset); virtual ConstCoordType &deref() const { return (_coords); } virtual const void * address() const { return this; }; virtual bool equal(const void *rhs) const { const ConstCoordItrULayered *itrptr = static_cast(rhs); return (_itr2D == itrptr->_itr2D && _zCoordItr == itrptr->_zCoordItr); } virtual std::unique_ptr clone() const { return std::unique_ptr(new ConstCoordItrULayered(*this)); }; private: const UnstructuredGridLayered * _ug; UnstructuredGrid2D::ConstCoordItr _itr2D; ConstIterator _zCoordItr; CoordType _coords; size_t _nElements2D; size_t _index2D; }; virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrULayered(this, true))); } virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr(new ConstCoordItrULayered(this, false))); } VDF_API friend std::ostream &operator<<(std::ostream &o, const UnstructuredGridLayered &sg); protected: virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override; private: UnstructuredGrid2D _ug2d; UnstructuredGridCoordless _zug; bool _insideGrid(const CoordType &coords, DimsType &cindices, std::vector &nodes2D, std::vector &lambda, float zwgt[2]) const; }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/VAssert.h ================================================ #pragma once #include namespace Wasp { COMMON_API void _VAssertFailed(const char *expr, const char *path, const unsigned int line); } #define VAssert(expr) ((expr) ? (void)0 : Wasp::_VAssertFailed(#expr, __FILE__, __LINE__)) ================================================ FILE: include/vapor/VDC.h ================================================ #include #include #include #include #include #include #ifndef _VDC_H_ #define _VDC_H_ namespace VAPoR { //! //! \class VDC //! \ingroup Public_VDC //! //! \brief Defines API for reading, writing, and appending data to a //! VAPOR Data Collection (Version 3) //! //! \author John Clyne //! \date July, 2014 //! //! This abstract class efines API for reading, writing, and //! appending data to a //! VAPOR Data Collection (Version 3). The VDC class is an abstract virtual //! class, providing a public API, but performing no actual storage //! operations. Derived implementations of the VDC base class are //! required to support the API. //! //! In version 3 of the VDC the metadata (.vdf) file found in VDC version 1 //! and 2 is replaced with a //! "master" file that describes the contents of the entire VDC. The master //! file imposes structure on the organization of the files containing data, //! determining, for example, which data files contain which variables //! and time steps. //! //! Unlike //! the .vdf file, it is intended that the master file will be stored in the //! same scientific data //! file format as the data themselves (though this depends on the //! implementation of the derived class). //! Another important change in version 3 //! is that both the master file and the accompanying data files //! are intended to be accessible using the native file format API. I.e. //! users may operate on files in the VDC using, for example, the //! NetCDF API, or they //! may use the API provided by the VDC class object. The latter is only //! required when reading or writing compressed variables (not all variables //! in a VDC version 3 must be compressed). Thus if NetCDF is chosen //! as the underlying format the NetCDF API may be used directly to read //! and write NetCDF "attributes" and variables (provided the variables //! are not compressed). //! //! Variables in a VDC may have 1, 2, or 3 spatial dimensions, and 0 or 1 //! temporal dimensions. //! //! The VDC is structured in the spirit of the "NetCDF Climate and Forecast //! (CF) Metadata Conventions", version 1.6, 5, December 2011. //! It supports only a subset of the CF functionality (e.g. there is no //! support for "Discrete Sampling Geometries"). Moreover, it is //! more restrictive than the CF in a number of areas. Particular //! items of note include: //! //! \li All dimensions defined in the VDC have a 1D coordinate variable //! associated with them with the same name as the dimension. //! //! \li The API supports variables with 1 to 4 dimensions only. //! //! \li Coordinate variables representing time must be 1D //! //! \li All data variables have a "coordinate" attribute identifying //! the coordinate (or auxilliary coordinate) variables associated with //! each axis //! //! \li To be consistent with VAPOR, when specified in vector form the //! ordering of dimension lengths //! and dimension names is from fastest varying dimension to slowest. //! For example, if //! 'dims' is a vector of dimensions, then dims[0] is the fastest varying //! dimension, dim[1] is the next fastest, and so on. This ordering is the //! opposite of the ordering used by NetCDF. //! //! This class inherits from Wasp::MyBase. Unless otherwise documented //! any method that returns an integer value is returning status. A negative //! value indicates failure. Error messages are logged via //! Wasp::MyBase::SetErrMsg(). Methods that return a boolean do //! not, unless otherwise documented, log an error message upon //! failure (return of false). //! //! \param level //! \parblock //! Grid refinement level for multiresolution variables. //! Compressed variables in the VDC have a multi-resolution //! representation: the sampling grid for multi-resolution variables //! is hierarchical, and the dimension lengths of adjacent levels in the //! hierarchy differ by a factor of two. The \p level parameter is //! used to select a particular depth of the hierarchy. //! //! To provide maximum flexibility as well as compatibility with previous //! versions of the VDC the interpretation of \p level is somewhat //! complex. Both positive and negative values may be used to specify //! the refinement level and have different interpretations. //! //! For positive //! values of \p level, a value of \b 0 indicates the coarsest //! member of the //! grid hierarchy. A value of \b 1 indicates the next grid refinement //! after the coarsest, and so on. Using postive values the finest level //! in the hierarchy is given by GetNumRefLevels() - 1. Values of \p level //! that are greater than GetNumRefLevels() - 1 are treated as if they //! were equal to GetNumRefLevels() - 1. //! //! For negative values of \p level a value of -1 indicates the //! variable's native grid resolution (the finest resolution available). //! A value of -2 indicates the next coarsest member in the hierarchy after //! the finest, and so //! on. Using negative values the coarsest available level in the hierarchy is //! given by negating the value returned by GetNumRefLevels(). Values of //! \p level that are less than the negation of GetNumRefLevels() are //! treated as if they were equal to the negation of the GetNumRefLevels() //! return value. //! \endparblock //! \param lod //! \parblock //! The level-of-detail parameter, \p lod, selects //! the approximation level for a compressed variable. //! The \p lod parameter is similar to the \p level parameter in that it //! provides control over accuracy of a compressed variable. However, instead //! of selecting the grid resolution the \p lod parameter controls //! the compression factor by indexing into the \p cratios vector (see below). //! As with the \p level parameter, both positive and negative values may be //! used to index into \p cratios and //! different interpretations. //! //! For positive //! values of \p lod, a value of \b 0 indicates the //! the first element of \p cratios, a value of \b 1 indicates //! the second element, and so on up to the size of the //! \p cratios vector (See DC::GetCRatios()). //! //! For negative values of \p lod a value of \b -1 indexes the //! last element of \p cratios, a value of \b -2 indexes the //! second to last element, and so on. //! Using negative values the first element of \p cratios - the greatest //! compression rate - is indexed by negating the size of the //! \p cratios vector. //! \endparblock //! \param cratios A monotonically decreasing vector of //! compression ratios. Compressed variables in the VDC are stored //! with a fixed, finite number of compression factors. The \p cratios //! vector is used to specify the available compression factors (ratios). //! A compression factor of 1 indicates no compression (1:1). A value //! of 2 indciates two to one compression (2:1), and so on. The minimum //! valid value of \p cratios is \b 1. The maximum value is determined //! by a number of factors and can be obtained using the CompressionInfo() //! method. //! //! \param wname Name of wavelet used for transforming compressed //! variables between wavelet and physical space. Valid values //! are "bior1.1", "bior1.3", "bior1.5", "bior2.2", "bior2.4", //! "bior2.6", "bior2.8", "bior3.1", "bior3.3", "bior3.5", "bior3.7", //! "bior3.9", "bior4.4" //! //! class VDF_API VDC : public VAPoR::DC { public: //! Read, Write, Append access mode //! enum AccessMode { R, W, A }; //! Class constuctor //! //! VDC(); virtual ~VDC() {} protected: //! Initialize the VDC class //! //! Prepare a VDC for reading or writing/appending. This method prepares //! the master VDC file indicated by \p path for reading or writing. //! The method should be called immediately after the constructor, //! before any other class methods. This method //! exists only because C++ constructors can not return error codes. //! //! \param[in] path A single element vector that specifies the name of file //! that contains, or will //! contain, the VDC master file for this data collection //! \param[in] mode One of \b R, \b W, or \b A, indicating whether \p path //! will be opened for reading, writing, or appending, respectively. //! When \p mode is \b A underlying NetCDF files will be opened //! opened with \em nc_open(path, NC_WRITE)). When \p mode is \b W //! NetCDF files will be created (opened with \em nc_create(path)). //! When \p mode is \b A additional time steps may be added to //! an existing file. //! //! \p bs is a three-element array, with the first element //! specifying the length of the fastest varying spatial dimension (e.g. X) of //! the storage block, the //! second element specifies the length of the next fastest varying //! dimension, etc. If a variable definition defines a variable with \b n //! spatial , where \b n is less than three, only the //! first \b n elements //! of \p bs will be used. For example, if the rank of \b bs is greater than //! two a 2D variable will be stored in //! blocks having dimensions \b bs[0] x \b bs[1]. Time dimensions are //! never blocked. This parameter is ignored unless \p mode is W. //! //! \note The parameter \p mode controls the access to the master //! file indicated by \p path and the variable data files in a somewhat //! unintuitive manner. If \p mode is \b R or \b A the master file \p path //! must already exist. If \p mode is //! \b A or \b W the contents of the VDC master may be changed (written) //! and the //! VDC is put into \b define mode until EndDefine() //! is called. While in \b define mode metadata that will be contained //! in the VDC master file may be changed, but coordinate and data variables //! may not be accessed (read or written). Similarly, when not in define //! mode coordinate //! and data variables may be accessed (read or written), but metadata //! in the VDC master may not be changed. See OpenVariableRead() and //! OpenVariableWrite() for discussion on how \p mode effects reading //! and writing of coordinate and data variables. //! //! \retval status A negative int is returned on failure //! //! \sa EndDefine(); // virtual int initialize(const std::vector &paths, const std::vector &options, AccessMode mode, vector bs); virtual int initialize(const std::vector &paths, const std::vector &options) { return (initialize(paths, options, R, vector())); } public: //! Sets various parameters for storage blocks for subsequent variable //! definitions //! //! This method sets the storage parameters for subsequent variable //! definitions for compressed variables. //! //! Variables whose spatial dimension lengths are less than the coresponding //! dimension of \p bs will be padded to block boundaries. //! //! \p wname set the wavelet family name and //! boundary handling mode //! for subsequent compressed variable definitions. //! Wider wavelets (those requiring //! more filter coefficients) will typically yield higher compression rates, //! but are more computationally expensive and will limit the depth of //! of the grid resolution refinement hierarchy. //! //! Recommended values for \p wname are \e bior1.1, \e bior1.3, \e bior1.5 //! \e bior3.3, \e bior3.5, \e bior3.7, \e bior3.9, \e bior2.2, \e bior2.6, //! \e bior2.6, and \e bior2.8. For odd length filters (e.g. bior1.3) //! //! Finally, \p cratios specifies a vector of compression factors for //! subsequent compressed variable definitions. //! //! \note For compressed variables compression is applied to individual blocks. //! Larger blocks permit deeper grid refinement hierarchies, but may //! result in poor cache performance and slowed disk storage access //! //! \note The wavelet and compression ratio parameters are ignored by variable //! definitions for variables that are not compressed. //! //! //! \param[in] wname A wavelet family name. The default value is "bior4.4". //! \param[in] cratios A vector of compression of integer compression //! factors. //! The default compression ratio vector is: (1, 10, 100, 500) //! //! \retval status A negative int is returned if an invalid parameter //! or parameter combination is specified. //! //! \sa DefineDataVar(), DefineCoordVar(), VDC() // int SetCompressionBlock(string wname, std::vector cratios); //! Retrieve current compression block settings. //! //! \param[out] bs An ordered vector containing the current compression //! block dimensions. //! \param[out] wname The wavelet family name. //! \param[out] cratios A vector of compression of integer compression //! factors. //! //! \sa SetCompressionBlock() // void GetCompressionBlock(std::vector &bs, string &wname, std::vector &cratios) const; //! Set the boundary periodic for subsequent variable definitions //! //! This method specifies an ordered, three-element boolean vector //! indicating the boundary periodicty for a variable's spatial //! dimensions. The ordering is from fastest to slowest varying dimension. //! //! \param[in] periodic A three-element array of booleans. The //! default value of \p periodic is (\b false, \b false, \b false). //! //! \retval status A negative int is returned on error //! void SetPeriodicBoundary(std::vector periodic) { _periodic = periodic; for (int i = _periodic.size(); i < 3; i++) _periodic.push_back(false); } //! Retrieve current boundary periodic settings //! //! \sa SetPeriodicBoundary() // std::vector GetPeriodicBoundary() const { return (_periodic); }; //! Define a dimension in the VDC //! //! This method specifies the name, and length of a dimension. //! A variable in the VDC may have one to four dimensions (one to //! three spatial, and zero or one temporal). Dimensions may be of //! any length //! greater than or equal to one. //! //! This method must be called prior to defining any variables requring //! the defined dimensions. //! //! There are no default dimensions defined. //! //! It is an error to call this method if the VDC master is not currently //! in \b define mode. //! //! \param[in] dimname A string specifying the name of the dimension. //! \param[in] length The dimension length, which must be greater than zero. //! //! \note When the VDC master file is initialized in //! append (\b mode = \b A) //! mode it is an error to redefine an //! existing dimension. New dimensions may, however, be defined. //! //! \retval status A negative int is returned on error //! //! \sa DefineCoordVar(), DefineDataVar(), GetDimension() // int DefineDimension(string dimname, size_t length); //! Define a dimension in the VDC and an associated coordinate variable //! //! This method defines a dimension and a 1D, unitless coordinate variable //! with the same name. //! //! It is an error to call this method if the VDC master is not currently //! in \b define mode. //! //! \param[in] name A string specifying the name of the dimension, and the //! coordinate variable. //! \param[in] length The dimension length, which must be greater than zero. //! \param[in] axis An integer indicating the spatial or temporal //! coordinate axis. Acceptable values are \b 0 (for X or longitude), //! \b 1 (for Y or latitude), \b 2 (for Z or vertical), and \b 3 (for time). //! //! \retval status A negative int is returned on error //! //! \sa DefineCoordVar(), DefineDataVar(), GetDimension() // int DefineDimension(string dimname, size_t length, int axis); protected: //! \copydoc DC:getDimension() // bool getDimension(string dimname, DC::Dimension &dimension) const; //! \copydoc DC:getDimensionNames() // std::vector getDimensionNames() const; //! \copydoc DC:getMeshNames() // std::vector getMeshNames() const; virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const; //! \copydoc DC::GetCoordVarInfo() // bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const; //! \copydoc DC::GetDataVarInfo() // bool getDataVarInfo(string varname, DC::DataVar &datavar) const; //! \copydoc DC::GetAuxVarInfo() // bool getAuxVarInfo(string varname, DC::AuxVar &var) const { return (false); } //! \copydoc DC::GetBaseVarInfo() // bool getBaseVarInfo(string varname, DC::BaseVar &var) const; virtual std::vector getDataVarNames() const; virtual std::vector getAuxVarNames() const { return (vector()); } virtual std::vector getCoordVarNames() const; //! \copydoc DC:GetNumRefLevels() // size_t getNumRefLevels(string varname) const; bool getAtt(string varname, string attname, vector &values) const; bool getAtt(string varname, string attname, vector &values) const; bool getAtt(string varname, string attname, string &values) const; std::vector getAttNames(string varname) const; XType getAttType(string varname, string attname) const; virtual vector getBlockSize() const { return (_bs); } virtual int getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level) const = 0; virtual string getMapProjection(string varname) const; virtual string getMapProjection() const; virtual string getMapProjectionDefault() const { return (getMapProjection()); } virtual int openVariableRead(size_t ts, string varname, int level = 0, int lod = 0) = 0; virtual int closeVariable(int fd) = 0; virtual int readRegion(int fd, const vector &min, const vector &max, float *region) = 0; virtual int readRegion(int fd, const vector &min, const vector &max, double *region) = 0; public: //! Define a coordinate variable //! //! This method provides the definition for a coordinate variable: a //! variable providing spatial or temporal coordinates for a subsequently //! defined data variable. //! //! If the variable's name, \p varname, matches a dimension defined //! with DefineDimension(), only the units and external data type //! may differ from the 1D coordinate variable impliclity defined by //! DefineDimension() //! //! \param[in] varname The name of the coordinate variable. //! \param[in] dimnames An ordered vector specifying the variable's spatial //! dimension names. The dimension names must have previously been defined //! with the DefineDimension() method. //! \param[in] time_dim_name The name of the time varying dimension, if any. //! \param[in] units This parameter specifies a string describing the //! units of measure for the //! variable. The string is compatible with the Unidata udunits2 conversion //! package. If the quantity is unitless an empty string may be specified. //! \param[in] axis An integer indicating the spatial or temporal //! coordinate axis. Acceptable values are \b 0 (for X or longitude), //! \b 1 (for Y or latitude), \b 2 (for Z or vertical), and \b 3 (for time). //! \param[in] type The primitive data type storage format. //! Currently supported values //! are \b FLOAT. This is the type that will be used to store the //! variable on disk //! \param[in] compressed A boolean indicating whether the //! coordinate variable is //! to be wavelet transformed. //! //! It is an error to call this method if the VDC master is not currently //! in \b define mode. //! //! \note Temporal coordinate variables (axis=3) must have exactly one //! dimension. //! //! \note When in append (\b A) mode it is an error to redefine an //! existing variable. //! //! \retval status A negative int is returned on error //! //! \sa DefineDimension(), DefineCoordVar(), SetCompressionBlock() // int DefineCoordVar(string varname, std::vector dimnames, string time_dim_name, string units, int axis, XType type, bool compressed); //! Define a coordinate variable with uniform sampling //! //! This method provides the definition for a uniform coordinate variable. //! A uniformly sampled coordinate variable is a variable //! for which the coordinates along the fastest varying axis //! may be given by i * dx , where //! \em i is an index starting from zero, and \em dx is a real number //! representing the spacing between points. //! //! One-dimensional coordinate variables that have uniform sampling //! should be declared as such using this method rather than the //! more general DefineCoordVar(). //! //! \param[in] varname The name of the coordinate variable. //! \param[in] dimnames An ordered vector specifying the variable's spatial //! dimension names. The dimension names must have previously been defined //! with the DefineDimension() method. //! \param[in] time_dim_name The name of the time varying dimension, if any. //! \param[in] units This parameter specifies a string describing the //! units of measure for the //! variable. The string is compatible with the udunits2 conversion //! package. If the quantity is unitless an empty string may be specified. //! \param[in] axis An integer indicating the spatial or temporal //! coordinate axis. Acceptable values are \b 0 (for X or longitude), //! \b 1 (for Y or latitude), \b 2 (for Z or vertical), and \b 3 (for time). //! \param[in] type The primitive data type storage format. //! Currently supported values //! are \b FLOAT //! \param[in] compressed A boolean indicating whether the //! coordinate variable is //! to be wavelet transformed. //! //! It is an error to call this method if the VDC master is not currently //! in \b define mode. //! //! \note When in append (\b A) mode it is an error to redefine an //! existing variable. //! //! \retval status A negative int is returned on error //! //! \sa DefineDimension(), DefineCoordVar(), SetCompressionBlock() // int DefineCoordVarUniform(string varname, std::vector dimname, string time_dim_name, string units, int axis, XType type, bool compressed); //! Define a data variable //! //! This method defines a data variable in the VDC master file //! //! \param[in] varname The name of the data variable. //! \param[in] dimnames An ordered vector specifying the variables //! dimension names. The dimension names must have previously be defined //! with the DefineDimension() method. //! \param[in] coordvars An ordered vector specifying the coordinate //! variable names providing the coordinates for this variable. The //! coordinate variables must have previously been defined //! with the DefineCoordVar() method. Moreover, the dimension names //! of each coordinate variable must be a subset of those in \p dimnames. //! \param[in] units This parameter specifies a string describing the //! units of measure for the //! variable. The string is compatible with the udunits2 conversion //! package. If the quantity is unitless an empty string may be specified. //! \param[in] type The primitive data type storage format. //! Currently supported values //! are \b FLOAT //! \param[in] compressed A boolean indicating whether the coordinate //! variable is to be wavelet transformed. //! //! It is an error to call this method if the VDC master is not currently //! in \b define mode. //! //! \note When in append (\b A) mode it is an error to redefine an //! existing variable. //! //! \sa DefineDimension(), DefineCoordVar(), SetCompressionBlock() //! int DefineDataVar(string varname, std::vector dimnames, std::vector coordvars, string units, XType type, bool compressed); //! //! Define a compressed or non-compressed data variable with missing data //! //! \copydoc VDC::DefineDataVar( //! string varname, std::vector dimnames, //! std::vector coordvars, //! string units, XType type, bool compressed //! ); //! //! \param[in] missing_value Specifies a value that should be used //! for masked grid locations after a variable is reconstructed. //! //! \param[in] maskvar Specifies the name of a variable //! whose contents indicate the presense or absense of invalid //! entries in the data variable. The contents of the mask array are treated //! as booleans, true values indicating valid data. The rank of of the //! variable may be less than or equal to that of \p varname. The dimensions //! of \p maskvar must match the fastest varying dimensions of \p varname. //! The \p maskvar variable must have been previously defined with //! DefineDataVar(). If \p maskvar is empty, the variable will //! not be compressed. //! //! \sa DefineDimension(), DefineCoordVar(), SetCompressionBlock() //! int DefineDataVar(string varname, std::vector dimnames, std::vector coordvars, string units, XType type, double missing_value, string maskvar); //! Write an attribute //! //! This method write an attribute to the VDC. The attribute can either //! be "global", if \p varname is the empty string, or bound to a variable //! if \p varname indentifies a variable in the VDC. //! //! \param[in] varname The name of a variable already defined in the VDC, //! or the empty string if the attribute is to be global //! \param[in] attname The attributes name //! \param[in] type The primitive data type storage format. //! This is the type that will be used to store the //! attribute on disk //! \param[in] values A vector of floating point attribute values //! //! \retval status A negative int is returned on failure //! //! \sa GetAtt() // int PutAtt(string varname, string attname, XType type, const vector &values); int PutAtt(string varname, string attname, XType type, const vector &values); int PutAtt(string varname, string attname, XType type, const string &values); //! Copy an attribute //! //! This method copies an attribute from the src DC. The attribute can either //! be "global", if \p varname is the empty string, or bound to a variable //! if \p varname indentifies a variable in the src DC. //! //! \param[in] src The source DC from which to copy. //! \param[in] varname The name of the variable the attribute is bound to, //! or the empty string if the attribute is global //! \param[in] attname The attributes name //! //! \retval status A negative int is returned on failure. 0 returned on //! success. //! //! \sa PutAtt() // int CopyAtt(const DC &src, string varname, string attname); //! Copy attributes //! //! This method copies attributes from the src DC. The attributes can either //! be "global", if \p varname is the empty string, or bound to a variable //! if \p varname indentifies a variable in the src DC. All attributes //! associated with \p varname are copied. //! //! \param[in] src The source DC from which to copy. //! \param[in] varname The name of the variable the attribute is bound to, //! or the empty string if the attribute is global //! //! \retval status A negative int is returned on failure. 0 returned on //! success. //! //! \sa PutAtt() // int CopyAtt(const DC &src, string varname); //! Set a map projection string for a data variable //! //! This method sets a properly formatted Proj4 map projection string //! for the data variable indicated by \p varname //! //! \sa GetMapProjection() // virtual int SetMapProjection(string varname, string projstring); //! Set the default Proj4 map projection for georeferenced variables //! //! This method sets the default Proj4 map projection string to be //! used for georeferenced variables. The string set by //! \p projstring is returned by VDC::GetMapProjection() //! virtual int SetMapProjection(string projstring); //! //! When the open mode \b mode is \b A or \b W this method signals the //! class object that metadata defintions have been completed and it //! commits them to the master VDC file. This method also prepares //! the VDC for the reading or writing of variable or coordinate data. //! //! Ignored if \b mode is \b R. //! //! \retval status A negative it is returned if the master file is not //! successfully written for any reason //! //! \note The master file should not be accessed with the native file //! format API (e.g. NetCDF) if the VDC is in define mode (e.g. until //! after EndDefine() is called). //! //! \sa VDC() //! int EndDefine(); //! Return the path name and temporal offset for a variable //! //! Data and coordinate variables in a VDC are in general distributed //! into multiple files. For example, for large variables only a single //! time step //! may be stored per file. //! This method returns the file path name, \p path, of the file //! containing \p varname at time step \p ts. Also returned is the //! integer time offset of the variable within \p path. //! //! \param[in] varname Data or coordinate variable name. //! \param[in] ts Integer offset relative to a variable's temporal dimension //! \param[out] path Path to file containing variable \p varname at //! time step \p ts. //! \param[out] file_ts Temporal offset of variable \p varname in file //! \p path. //! \param[out] max_ts Maximum number of time steps stored in //! \p path //! //! \retval status A negative int is returned if \p varname or //! \p ts are invalid, or if the class object is in define mode. //! virtual int GetPath(string varname, size_t ts, string &path, size_t &file_ts, size_t &max_ts ) const = 0; //! Open the named variable for writing //! //! This method prepares a data or coordinate variable, indicated by a //! variable name and time step pair, for subsequent write operations by //! methods of this class. //! //! The behavior of this method is impacted somewhat by the setting //! of the Initialize() \b mode parameter. Coordinate or data variable //! files may be //! written regardless of the \p mode setting. However, if //! \p mode is \b W the first time a coordinate or data file is written //! it will be created (opened with \em nc_create(path), for example) //! regareless of whether the file previously existed. If \p //! mode is \b A or \b R existing coordinate or data files will be opened //! for appending (e.g. opened with \em nc_open(path, NC_WRITE)). New //! files will be created (opened with \em nc_create(path)). //! //! An error occurs, indicated by a negative return value, if the //! varible identified by the {varname, timestep, lod} tupple //! is not defined. //! //! \param[in] ts Time step of the variable to read. This is the integer //! offset into the variable's temporal dimension. If the variable //! does not have a temporal dimension \p ts is ignored. //! \param[in] varname Name of the variable to read //! \param[in] lod Approximation level of the variable. A value of -1 //! indicates the maximum approximation level defined for the VDC. //! Ignored if the variable is not compressed. //! \retval status Returns a non-negative value on success //! //! \sa GetNumRefLevels(), DC::BaseVar::GetCRatios(), OpenVariableRead() // virtual int OpenVariableWrite(size_t ts, string varname, int lod = -1) = 0; virtual int CloseVariableWrite(int fd) = 0; //! Write all spatial values to the currently opened variable //! //! This method writes, and compresses as necessary, //! the contents of the array contained in //! \p data to the currently opened variable. The number of values //! written from \p data is given by the product of the spatial //! dimensions of the open variable. //! //! \param[in] data An array of data to be written //! \retval status Returns a non-negative value on success //! //! \sa OpenVariableWrite() // virtual int Write(int fd, const float *data) = 0; virtual int Write(int fd, const int *data) = 0; //! Write a single slice of data to the currently opened variable //! //! Compress, and necessary, and write a single slice (2D array) of //! data to the variable //! indicated by the most recent call to OpenVariableWrite(). //! The dimensions of a slices are NX by NY, //! where NX is the dimension of the array along the fastest varying //! spatial dimension, specified //! in grid points, and NY is the length of the second fastest varying //! dimension at the currently opened refinement level. See //! OpenVariableWrite(). //! //! This method should be called exactly NZ times for each opened variable, //! where NZ is the dimension of third, and slowest varying dimension. //! In the case of a 2D variable, NZ is 1. //! //! \param[in] slice A 2D slice of data //! \retval status Returns a non-negative value on success //! //! \sa OpenVariableWrite() //! virtual int WriteSlice(int fd, const float *slice) = 0; virtual int WriteSlice(int fd, const int *slice) = 0; virtual int WriteSlice(int fd, const unsigned char *slice) = 0; //! Write an entire variable in one call //! //! This method writes and entire variable (all time steps, all grid points) //! into a VDC. This is the simplest interface for writing data into //! a VDC. If the variable is split across multiple files PutVar() //! ensures that the data are correctly distributed. //! Any variables currently opened with OpenVariableWrite() are first closed. //! Thus variables need not be opened with OpenVariableWrite() prior to //! calling PutVar(); //! //! It is an error to call this method in \b define mode //! //! \param[in] varname Name of the variable to write //! \param[in] lod Approximation level of the variable. A value of -1 //! indicates the maximum approximation level defined for the VDC. //! Ignored if the variable is not compressed. //! \param[in] data Pointer from where the data will be copied //! //! \retval status A negative int is returned on failure //! //! \sa GetVar() // virtual int PutVar(string varname, int lod, const float *data) = 0; virtual int PutVar(string varname, int lod, const int *data) = 0; //! Write a variable at single time step //! //! This method writes a variable hyperslab consisting of the //! variable's entire spatial dimensions at the time step //! indicated by \p ts. //! Any variables currently opened with OpenVariableWrite() are first closed. //! Thus variables need not be opened with OpenVariableWrite() prior to //! calling PutVar(); //! //! It is an error to call this method in \b define mode //! //! \param[in] ts Time step of the variable to write. This is the integer //! offset into the variable's temporal dimension. If the variable //! does not have a temporal dimension \p ts is ignored. //! \param[in] varname Name of the variable to write //! \param[in] lod Approximation level of the variable. A value of -1 //! indicates the maximum approximation level defined for the VDC. //! Ignored if the variable is not compressed. //! \param[in] data Pointer from where the data will be copied //! //! \retval status A negative int is returned on failure //! //! \sa GetVar() // virtual int PutVar(size_t ts, string varname, int lod, const float *data) = 0; virtual int PutVar(size_t ts, string varname, int lod, const int *data) = 0; //! Copy a variable from another data collection to this data collection //! //! This method copies the variable named \p varname from the data //! collection specified by \b dc to this data collection. The variable //! must have previously been defined in this data collection. //! //! \param[in] dc A reference to a source data collection //! \param[in] varname Name of variable to copy //! \param[in] srclod The level-of-detail used to open \p varname //! in \p dc. //! \param[in] dstlod The level-of-detail used to open \p varname //! in this data collection. //! virtual int CopyVar(DC &dc, string varname, int srclod, int dstlod) = 0; //! Copy a variable from another data collection to this data collection //! at a single time step // virtual int CopyVar(DC &dc, size_t ts, string varname, int srclod, int dstlod) = 0; //! This method computes and returns the depth (number of levels) in a //! a multi-resolution hierarch for a given wavelet, \p wname, //! and decomposition block, \p bs. //! It also computes the maximum compression ratio, \p cratio, possible //! for the //! the specified combination of block size, \p bs, and wavelet, \p wname. //! The maximum compression ratio is \p cratio:1. //! //! \param[in] bs Dimensions of native decomposition block. The rank of //! \p bs may be less than or equal to the rank of \p dims. //! \param[in] wname wavelet name. Empty string if no compression //! is to be performed. //! \param[out] nlevels Number of levels in hierarchy //! \param[out] maxcratio Maximum compression ratio //! //! \retval bool If \p bs, \p wname, or the combination there of is invalid //! false is returned and the values of \p nlevels and \p maxcratio are //! undefined. Upon success true is returned. //! virtual bool CompressionInfo(vector bs, string wname, size_t &nlevels, size_t &maxcratio) const = 0; //! Returns true if indicated data volume is available //! //! Returns true if the variable identified by the timestep, variable //! name, refinement level, and level-of-detail is present in //! the data set. Returns false if //! the variable is not available. //! //! \param[in] ts A valid time step between 0 and GetNumTimesteps()-1 //! \param[in] varname A valid variable name //! \param[in] reflevel Refinement level requested. //! \param[in] lod Compression level of detail requested. //! refinement level contained in the VDC. // virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const = 0; friend std::ostream &operator<<(std::ostream &o, const VDC &vdc); private: string _proj4StringOption; std::vector _newUniformVars; protected: string _master_path; AccessMode _mode; bool _defineMode; std::vector _bs; string _wname; std::vector _cratios; vector _periodic; VAPoR::UDUnits _udunits; std::map _dimsMap; std::map _atts; std::map _coordVars; std::map _dataVars; std::map _meshes; #ifndef DOXYGEN_SKIP_THIS bool _ValidDefineDimension(string name, size_t length) const; bool _ValidDefineCoordVar(string varname, vector dimnames, string time_dim_name, string units, int axis, XType type, bool compressed) const; bool _valid_blocking(const vector &dimensions, const vector &bs, const vector &coordvars) const; bool _valid_mask_var(string varname, vector dimensions, vector bs, bool compressed, string maskvar) const; bool _ValidDefineDataVar(string varname, vector dimnames, vector coordnames, string units, XType type, bool compressed, bool has_missing, string maskvar) const; bool _ValidCompressionBlock(vector bs, string wname, vector cratios) const; bool _valid_dims(const vector &dims0, const vector &bs0, const vector &dims1, const vector &bs1) const; virtual int _WriteMasterMeta() = 0; virtual int _ReadMasterMeta() = 0; void _DefineMesh(string meshname, vector dim_names, vector coord_vars); int _DefineDataVar(string varname, std::vector dimnames, std::vector coordvars, string units, XType type, bool compressed, bool has_missing, double mv, string maskvar); vector _GetCoordVarDimNames(const CoordVar &var, bool &time_varying) const; vector _GetDataVarDimNames(const DataVar &var, bool &time_varying) const; int _DefineImplicitCoordVars(vector dim_names, vector coord_vars_in, vector &coord_vars_out); #endif }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/VDCNetCDF.h ================================================ #include #include #include #include #include "vapor/VDC.h" #include "vapor/WASP.h" #ifndef _VDCNetCDF_H_ #define _VDCNetCDF_H_ namespace VAPoR { //! \class VDCNetCDF //! \ingroup Public_VDC //! //! \brief Implements the VDC //! abstract class, providing storage of VDC data //! in NetCDF files. //! //! \author John Clyne //! \date July, 2014 //! //! Implements the VDC abstract class, providing storage of VDC data //! in NetCDF files. Data (variables) are stored in multiple NetCDF files. //! The distribution of variables to files is described by GetPath(). //! class VDF_API VDCNetCDF : public VAPoR::VDC { public: //! Class constructor //! //! \param[in] numthreads Number of parallel execution threads //! to be run during encoding and decoding of compressed data. A value //! of 0, the default, indicates that the thread count should be //! determined by the environment in a platform-specific manner, for //! example using sysconf(_SC_NPROCESSORS_ONLN) under *nix OSes. //! //! \param[in] master_theshold Variables that are either compressed, or whose //! total number of elements are larger than \p master_theshold, will //! not be stored in the master file. Ignored if the file is open //! for appending or reading. //! //! \param[in] variable_threshold Variables not stored in the master //! file and whose //! total number of elements are larger than \p variable_threshold //! will be stored with one time step per file. Ignored if the file is open //! for appending or reading. // VDCNetCDF(int numthreads = 0, size_t master_theshold = 10 * 1024 * 1024, size_t variable_threshold = 100 * 1024 * 1024); virtual ~VDCNetCDF(); //! \copydoc DC:GetHyperSliceInfo() //! //! Override base class to ensure hyperslices are block aligned //! virtual int GetHyperSliceInfo(string varname, int level, std::vector &dims, size_t &nslice); //! Return path to the data directory //! //! Return the file path to the data directory associated with the //! master file named by \p path. Data files, those NetCDF files //! containing coordinate and data variables, are stored in separate //! files from //! the VDC master file (See VDC::Initialize()). The data files reside //! under the directory returned by this command. //! //! \param[in] path Path to VDC master file //! //! \retval dir : Path to the data directory //! \sa Initialize(), GetPath(), DataDirExists() // static string GetDataDir(string path); //! \copydoc VDC::GetPath() //! //! \par Algorithm //! If the size of a variable (total number of elements) is less than //! GetMasterThreshold() and the variable is not compressed it will //! be stored in the file master file. Otherwise, the variable will //! be stored in either the coordinate variable or data variable //! directory, as appropriate. Variables stored in coordinate or //! data directories are stored one variable per file. If the size //! of the variable is less than GetVariableThreshold() and the //! variable is time varying multiple time steps may be saved in a single //! file. If the variable is compressed each compression level is stored //! in a separate file. //! //! \sa VDCNetCDF::VDCNetCDF(), GetMasterThreshold(), GetVariableThreshold() //! virtual int GetPath(string varname, size_t ts, string &path, size_t &file_ts, size_t &max_ts) const; //! \copydoc VDC::GetDimLensAtLevel() // virtual int getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, vector &bs_at_level) const; //! Return true if a data directory exists for the master file //! named by \p path //! //! \param[in] path Path to VDC master file //! //! \sa Initialize(), GetPath(), GetDataDir(); // static bool DataDirExists(string path); //! Initialize the VDCNetCDF class //! \copydoc VDC::Initialize() //! //! \param[in] chunksizehint : NetCDF chunk size hint. A value of //! zero results in NC_SIZEHINT_DEFAULT being used. // virtual int Initialize(const vector &paths, const vector &options = {}, AccessMode mode = VDC::R, vector bs = {64, 64, 64}, size_t chunksizehint = 0); virtual int Initialize(string path, const vector &options, AccessMode mode, vector bs = {64, 64, 64}, size_t chunksizehint = 0) { std::vector paths; paths.push_back(path); return (Initialize(paths, options, mode, bs, chunksizehint)); } //! Return the master file size threshold //! //! \sa VDCNetCDF::VDCNetCDF(), GetVariableThreshold() // size_t GetMasterThreshold() const { return _master_threshold; }; //! Return the variable size threshold //! //! \sa VDCNetCDF::VDCNetCDF(), GetMasterThreshold() // size_t GetVariableThreshold() const { return _variable_threshold; }; //! \copydoc VDC::OpenVariableWrite() // int OpenVariableWrite(size_t ts, string varname, int lod = -1); int CloseVariableWrite(int fd) { return (closeVariable(fd)); }; //! \copydoc VDC::Write() // int Write(int fd, const float *region) { return (_writeTemplate(fd, region)); } int Write(int fd, const int *region) { return (_writeTemplate(fd, region)); } int WriteSlice(int fd, const float *slice) { return (_writeSliceTemplate(fd, slice)); }; int WriteSlice(int fd, const int *slice) { return (_writeSliceTemplate(fd, slice)); }; int WriteSlice(int fd, const unsigned char *slice) { return (_writeSliceTemplate(fd, slice)); } //! \copydoc VDC::PutVar() // int PutVar(string varname, int lod, const float *data) { return (_putVarTemplate(varname, lod, data)); } int PutVar(string varname, int lod, const int *data) { return (_putVarTemplate(varname, lod, data)); } //! \copydoc VDC::PutVar() // int PutVar(size_t ts, string varname, int lod, const float *data) { return (_putVarTemplate(ts, varname, lod, data)); } int PutVar(size_t ts, string varname, int lod, const int *data) { return (_putVarTemplate(ts, varname, lod, data)); } int CopyVar(DC &dc, string varname, int srclod, int dstlod); int CopyVar(DC &dc, size_t ts, string varname, int srclod, int dstlod); //! \copydoc VDC::CompressionInfo() // bool CompressionInfo(std::vector bs, string wname, size_t &nlevels, size_t &maxcratio) const; //! Enable or disable the NetCDF fill-value mode //! //! Enable or disable the NetCDF fill-value mode //! //! \param[in] fillmode NC_FILL as 0x0 or NC_NOFILL as 0x100 //! //! \retval err: NC_NOERR on success // int SetFill(int fillmode); protected: #ifndef DOXYGEN_SKIP_THIS virtual int _WriteMasterMeta(); virtual int _ReadMasterMeta(); #endif int openVariableRead(size_t ts, string varname, int level = 0, int lod = -1); int closeVariable(int fd); int readRegion(int fd, const std::vector &min, const std::vector &max, float *region); int readRegion(int fd, const std::vector &min, const std::vector &max, double *region); int readRegion(int fd, const std::vector &min, const std::vector &max, int *region); virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const; private: string _version; WASP * _master; // Master NetCDF file class VDCFileObject : public DC::FileTable::FileObject { public: VDCFileObject(size_t ts, string varname, int level, int lod, size_t file_ts, WASP *wasp_data, WASP *wasp_mask, string varname_mask, int level_mask, size_t file_ts_mask, double mv) : FileObject(ts, varname, level, lod), _file_ts(file_ts), _wasp_data(wasp_data), _wasp_mask(wasp_mask), _varname_mask(varname_mask), _level_mask(level_mask), _file_ts_mask(file_ts_mask), _mv(mv) { } size_t GetFileTS() const { return (_file_ts); } WASP * GetWaspData() const { return (_wasp_data); } WASP * GetWaspMask() const { return (_wasp_mask); } string GetVarnameMask() const { return (_varname_mask); } int GetLevelMask() const { return (_level_mask); } size_t GetFileTSMask() const { return (_file_ts_mask); } double GetMissingValue() const { return (_mv); } private: size_t _file_ts; WASP * _wasp_data; WASP * _wasp_mask; string _varname_mask; int _level_mask; size_t _file_ts_mask; double _mv; }; Wasp::SmartBuf _sb_slice_buffer; Wasp::SmartBuf _mask_buffer; size_t _chunksizehint; // NetCDF chunk size hint for file creates size_t _master_threshold; size_t _variable_threshold; int _nthreads; int _WriteMasterDimensions(); int _WriteMasterAttributes(string prefix, const map &atts); int _WriteMasterAttributes(); int _WriteMasterMeshDefs(); int _WriteMasterBaseVarDefs(string prefix, const BaseVar &var); int _WriteMasterCoordVarsDefs(); int _WriteMasterDataVarsDefs(); template int _writeTemplate(int fd, const T *data); template int _writeSliceTemplate(int fd, const T *slice); int _ReadMasterDimensions(); int _ReadMasterAttributes(string prefix, map &atts); int _ReadMasterAttributes(); int _ReadMasterMeshDefs(); int _ReadMasterBaseVarDefs(string prefix, BaseVar &var); int _ReadMasterCoordVarsDefs(); int _ReadMasterDataVarsDefs(); template int _ReadSlice(WASP *file, T *slice); int _PutAtt(WASP *ncdf, string varname, string tag, const Attribute &attr); int _WriteAttributes(WASP *wasp, string varname, const map &atts); int _DefBaseVar(WASP *ncdf, const VDC::BaseVar &var, size_t max_ts); int _DefDataVar(WASP *ncdf, const VDC::DataVar &var, size_t max_ts); int _DefCoordVar(WASP *ncdf, const VDC::CoordVar &var, size_t max_ts); bool _var_in_master(const VDC::BaseVar &var) const; string _get_mask_varname(string varname, double &mv) const; unsigned char *_read_mask_var(WASP *wasp, string varname, string varname_mask, vector start, vector count); WASP *_OpenVariableRead(size_t ts, string varname, int clevel, int lod, size_t &file_ts); int _ReadHelper(vector &start, vector &count) const; template int _putVarTemplate(string varname, int lod, const T *data); template int _putVarTemplate(size_t ts, string varname, int lod, const T *data); int _copyVar0d(DC &dc, size_t ts, const BaseVar &varInfo); template int _copyVarHelper(DC &dc, int fdr, int fdw, vector &buffer_dims, vector &src_hslice_dims, vector &dst_hslice_dims, size_t src_nslice, size_t dst_nslice, T *buffer); template int _readRegionTemplate(int fd, const vector &min, const vector &max, T *region); }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/VDC_c.h ================================================ #ifndef _VDC_C_H_ #define _VDC_C_H_ #define VDC_AccessMode_R 1 #define VDC_AccessMode_W 2 #define VDC_AccessMode_A 3 #define VDC_XType int #define VDC_XType_INVALID -1 #define VDC_XType_FLOAT 1 #define VDC_XType_DOUBLE 2 #define VDC_XType_INT32 3 #define VDC_XType_INT64 4 #define VDC_XType_TEXT 5 #define VDCDimension_Axis_X 0 #define VDCDimension_Axis_Y 1 #define VDCDimension_Axis_Z 2 #define VDCDimension_Axis_T 3 #ifdef __cplusplus #include "vapor/VDC.h" typedef VAPoR::VDCNetCDF VDC; typedef VAPoR::VDC::Dimension VDCDimension; typedef VAPoR::VDC::BaseVar VDCBaseVar; typedef VAPoR::VDC::AuxVar VDCAuxVar; typedef VAPoR::VDC::DataVar VDCDataVar; typedef VAPoR::VDC::CoordVar VDCCoordVar; extern "C" { #else typedef struct VDCNetCDF VDC; typedef struct VDCDimension VDCDimension; typedef struct VDCBaseVar VDCBaseVar; typedef struct VDCAuxVar VDCAuxVar; typedef struct VDCDataVar VDCDataVar; typedef struct VDCCoordVar VDCCoordVar; #endif VDCDimension *VDCDimension_new(); void VDCDimension_delete(VDCDimension *p); void VDCDimension_GetName(const VDCDimension *p, char **name); size_t VDCDimension_GetLength(const VDCDimension *p); int VDCDimension_IsTimeVarying(const VDCDimension *p); VDCBaseVar *VDCBaseVar_new(); void VDCBaseVar_delete(VDCBaseVar *p); void VDCBaseVar_GetName(const VDCBaseVar *p, char **name); void VDCBaseVar_GetUnits(const VDCBaseVar *p, char **units); int VDCBaseVar_GetXType(const VDCBaseVar *p); void VDCBaseVar_GetWName(const VDCBaseVar *p, char **name); void VDCBaseVar_GetCRatios(const VDCBaseVar *p, size_t **ratios, int *count); void VDCBaseVar_GetBS(const VDCBaseVar *p, size_t **bs, int *count); void VDCBaseVar_GetPeriodic(const VDCBaseVar *p, long **periodic, int *count); void VDCBaseVar_GetAttributeNames(const VDCBaseVar *p, char ***names, int *count); // Return names instead of objects int VDCBaseVar_IsCompressed(const VDCBaseVar *p); VDCAuxVar *VDCAuxVar_new(); void VDCAuxVar_delete(VDCAuxVar *p); void VDCAuxVar_GetDimNames(const VDCAuxVar *p, char ***names, int *count); VDCDataVar *VDCDataVar_new(); void VDCDataVar_delete(VDCDataVar *p); void VDCDataVar_GetMeshName(const VDCDataVar *p, char **name); void VDCDataVar_GetTimeCoordVar(const VDCDataVar *p, char **name); // GetSamplingLocation void VDCDataVar_GetMaskvar(const VDCDataVar *p, char **name); int VDCDataVar_GetHasMissing(const VDCDataVar *p); double VDCDataVar_GetMissingValue(const VDCDataVar *p); VDCCoordVar *VDCCoordVar_new(); void VDCCoordVar_delete(VDCCoordVar *p); void VDCCoordVar_GetDimNames(const VDCCoordVar *p, char ***names, int *count); void VDCCoordVar_GetTimeDimName(const VDCCoordVar *p, char **name); int VDCCoordVar_GetAxis(const VDCCoordVar *p); int VDCCoordVar_GetUniform(const VDCCoordVar *p); VDC *VDC_new(); void VDC_delete(VDC *p); int VDC_InitializeDefaultBS(VDC *p, const char *path, int mode); int VDC_Initialize(VDC *p, const char *path, int mode, size_t *bs, int bsCount); int VDC_GetDimension(const VDC *p, const char *dimname, VDCDimension *dimension); void VDC_GetDimensionNames(const VDC *p, char ***names, int *count); int VDC_GetCoordVarInfo(const VDC *p, const char *varname, VDCCoordVar *var); int VDC_GetDataVarInfo(const VDC *p, const char *varname, VDCDataVar *var); int VDC_GetBaseVarInfo(const VDC *p, const char *varname, VDCBaseVar *var); void VDC_GetDataVarNames(const VDC *p, char ***names, int *count); void VDC_GetCoordVarNames(const VDC *p, char ***names, int *count); int VDC_GetNumRefLevels(const VDC *p, const char *varname); int VDC_GetAtt_long(const VDC *p, const char *varname, const char *attname, long **values, int *count); int VDC_GetAtt_double(const VDC *p, const char *varname, const char *attname, double **values, int *count); int VDC_GetAtt_text(const VDC *p, const char *varname, const char *attname, char **text); int VDC_GetAtt_Count(const VDC *p, const char *varname, const char *attname, int *count); void VDC_GetAttNames(const VDC *p, const char *varname, char ***names, int *count); int VDC_GetAttType(const VDC *p, const char *varname, const char *attname); int VDC_VariableExists(const VDC *p, size_t ts, const char *varname, int reflevel, int lod); int VDC_IsTimeVarying(const VDC *p, const char *varname); int VDC_CoordVarExists(const VDC *p, const char *varname); int VDC_GetCRatios(const VDC *p, const char *varname, size_t **ratios, int *count); int VDC_GetCRatiosCount(const VDC *p, const char *varname); int VDC_GetVarDimLens(const VDC *p, const char *varname, int spatial, size_t **lens, int *count); int VDC_GetVarDimNames(const VDC *p, const char *varname, int spatial, char ***names, int *count); int VDC_GetVarCoordVars(const VDC *p, const char *varname, int spatial, char ***names, int *count); int VDC_GetVarDimLensAtLevel(const VDC *p, const char *varname, int level, size_t **lens, int *count); int VDC_OpenVariableRead(VDC *p, size_t ts, const char *varname, int level, int lod); int VDC_CloseVariable(VDC *p, int fd); int VDC_Read(VDC *p, int fd, float *region); int VDC_ReadSlice(VDC *p, int fd, float *slice); int VDC_ReadRegion(VDC *p, int fd, const size_t *min, const size_t *max, const int dims, float *region); int VDC_GetVar(VDC *p, const char *varname, int level, int lod, float *data); int VDC_GetVarAtTimeStep(VDC *p, size_t ts, const char *varname, int level, int lod, float *data); // Write int VDC_SetCompressionBlock(VDC *p, const char *wname, const size_t *cratios, int cratiosCount); int VDC_DefineDimension(VDC *p, const char *dimname, size_t length); int VDC_DefineDimensionWithAxis(VDC *p, const char *dimname, size_t length, int axis); int VDC_DefineDataVar(VDC *p, const char *varname, const char **dimnames, size_t dimnamesCount, const char **coordvars, size_t coordvarCount, const char *units, VDC_XType xtype, int compressed); int VDC_DefineCoordVar(VDC *p, const char *varname, const char **dimnames, size_t dimnamesCount, const char *time_dim_name, const char *units, int axis, VDC_XType xtype, int compressed); int VDC_DefineCoordVarUniform(VDC *p, const char *varname, const char **dimnames, size_t dimnamesCount, const char *time_dim_name, const char *units, int axis, VDC_XType xtype, int compressed); int VDC_PutAtt(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const void *values, size_t count); int VDC_PutAtt_double(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const double *values, size_t count); int VDC_PutAtt_long(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const long *values, size_t count); int VDC_PutAtt_text(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const char *values); int VDC_EndDefine(VDC *p); int VDC_PutVar(VDC *p, const char *varname, int lod, const float *data); int VDC_PutVarAtTimeStep(VDC *p, size_t ts, const char *varname, int lod, const float *data); // Utility const char *VDC_GetErrMsg(); void VDC_FreeStringArray(char ***str, int *count); void VDC_FreeString(char **str); void VDC_FreeLongArray(long **data); void VDC_FreeDoubleArray(double **data); void VDC_FreeSize_tArray(size_t **data); void VDC_ReverseSize_tArray(size_t *data, int count); #ifdef __cplusplus } // extern "C" } #endif #endif ================================================ FILE: include/vapor/VaporField.h ================================================ #ifndef VAPORFIELD_H #define VAPORFIELD_H #include "vapor/Field.h" #include "vapor/Particle.h" #include "vapor/DataMgr.h" #include "vapor/FlowParams.h" #include "vapor/Grid.h" #include "vapor/ptr_cache.hpp" namespace flow { // // Helper class: it is used to identify a specific grid. // class FLOW_API GridKey { private: uint32_t _timestep = std::numeric_limits::max(); // almost impossible value int32_t _refLev = -2; // Impossible value int32_t _compLev = -2; // Impossible value std::string _varName; VAPoR::CoordType _ext_min = {0.0, 0.0, 0.0}; VAPoR::CoordType _ext_max = {0.0, 0.0, 0.0}; public: void Reset(uint32_t, int32_t, int32_t, std::string, VAPoR::CoordType, VAPoR::CoordType); bool emptyVar() const; // == operator to be used in the cache bool operator==(const GridKey &) const; }; // // Helper class: it wraps a grid and a data manager pointer to ensure // the grid is properly destroyed. // class FLOW_API GridWrapper final { private: const VAPoR::Grid *const _gridPtr; VAPoR::DataMgr *const _mgr; // The pointer itself cannot be changed public: GridWrapper(const VAPoR::Grid *gp, VAPoR::DataMgr *mp); // Rule of five GridWrapper(const GridWrapper &) = delete; GridWrapper(const GridWrapper &&) = delete; GridWrapper &operator=(const GridWrapper &) = delete; GridWrapper &operator=(const GridWrapper &&) = delete; ~GridWrapper(); // Access the real pointer const VAPoR::Grid *grid() const; }; // // Note on variable names in a VaporField: // If a variable name is an empty string, then this variable is still valid, // but contains all zero values in it. // class FLOW_API VaporField final : public Field { public: // // Functions from class Field // virtual bool InsideVolumeVelocity(double time, glm::vec3 pos) const override; virtual bool InsideVolumeScalar(double time, glm::vec3 pos) const override; virtual uint32_t GetNumberOfTimesteps() const override; virtual int GetVelocity(double time, glm::vec3 pos, // input glm::vec3 &vel) const override; // output virtual int GetScalar(double time, glm::vec3 pos, // input float &scalar) const override; // output // // Functions for interaction with VAPOR components // void AssignDataManager(VAPoR::DataMgr *dmgr); void UpdateParams(const VAPoR::FlowParams *); void ReleaseLockedGrids(); // Supposed to be invoked at the end of each paintGL event. // // Find one index whose timestamp is just below a given time // I.e., _timestamps[floor] <= time // int LocateTimestamp(double time, // Input size_t &floor) const; // Output // // Returns the intersection domain of 3 velocity variables at a specific time step. // It returns non-zeros upon failure. // int GetVelocityIntersection(size_t ts, glm::vec3 &minxyz, glm::vec3 &maxxyz) const; // // Calculate a reasonable deltaT based on the velocity speed and domain size. // This is used as a one-time operation when getting ready a velocity field. // It'll return 0 on success, and non-zero on error conditions. // int CalcDeltaTFromCurrentTimeStep(double &delT) const; // // It turns that interactions from FlowParams can be expensive. // Let's implement a mechanism to cache information and interact with them less frequently. // Specifically, the following two functions are used to `lock` into (and `unlock` from) // the current set of params from FlowParams, so we don't need to interact with it anymore. // virtual auto LockParams() -> int override; virtual auto UnlockParams() -> int override; private: // // Member variables // std::vector _timestamps; // in ascending order VAPoR::DataMgr * _datamgr = nullptr; const VAPoR::FlowParams *_params = nullptr; using cacheType = VAPoR::ptr_cache; mutable cacheType _recentGrids; mutable std::mutex _grid_operation_mutex; // The following variables are cache states from DataMgr and Params. bool _params_locked = false; uint32_t _c_currentTS = 0; // cached timestep int32_t _c_refLev = -2; // cached ref levels int32_t _c_compLev = -2; // cached ref levels float _c_vel_mult = 0.0f; // cached velocity multiplier VAPoR::CoordType _c_ext_min; // cached extents VAPoR::CoordType _c_ext_max; // cached extents // // Member functions // // Are the following member pointers correctly set? // 1) _datamgr, 2) _params bool _isReady() const; // _getAGrid will use _params to retrieve/generate grids. // In the case of failing to generate a requested grid, nullptr will be returned. // This failure will also be recorded to MyBase. // Note: If a variable name is empty, we then return a ConstantField. const VAPoR::Grid *_getAGrid(uint32_t timestep, const std::string &varName) const; }; }; // namespace flow #endif ================================================ FILE: include/vapor/Version.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: Tue Jul 11 11:59:53 MDT 2006 // // Description: Version information. // //! \class Version //! \brief Return version information //! \author John Clyne //! \date Tue Jul 11 11:59:43 MDT 2006 //! A collection of general purpose utilities - things that //! probably should be in the STL but aren't. //! #ifndef _Version_h_ #define _Version_h_ #include #include #include #include #include using namespace std; namespace Wasp { // class COMMON_API Version : public MyBase { public: //! Return the major version number // static int GetMajor() { return (_majorVersion); } //! Return the minor version number // static int GetMinor() { return (_minorVersion); } //! Return the sub minor version number // static int GetMinorMinor() { return (_minorMinorVersion); } //! Return the sub minor version number // static string GetRC() { return (VERSION_RC); } static string GetBuildType() { return (BUILD_TYPE); } //! Return the canonical version number as a formatted string //! //! Return the canonical version number as a formatted string of //! the form: X.Y.Z, where \p X is the major version number, \p Y //! is the minor version number, and \p Z is the sub minor version number. // static const string &GetVersionString(); //! Return the full version as a formatted string //! //! Return the version as a formatted string of //! the form: MAJOR.MINOR.MICRO.RC.COMMIT // static const string &GetFullVersionString(); //! Return the git hash of the current build // static const string GetBuildHash(); //! Return a string containing the date associated with the version number //! //! This method returns the value of the RCS \p Date keyword. In general, //! this should corespond to the date that the version number was last //! advanced. // static const string &GetDateString() { _dateString.assign(VERSION_DATE); return (_dateString); } //! Parse a version string into it's component major, minor, //! and minorminor numbers // static void Parse(std::string ver, int &major, int &minor, int &minorminor, string &rc); static int Compare(int major, int minor, int minorminor); static int Compare(std::string ver1, std::string ver2); private: static const int _majorVersion; static const int _minorVersion; static const int _minorMinorVersion; static string _formatString; static string _dateString; }; } // namespace Wasp #endif ================================================ FILE: include/vapor/Viewpoint.h ================================================ #ifndef VIEWPOINT_H #define VIEWPOINT_H /* * This class describes a viewpoint */ #include namespace VAPoR { //! \class Viewpoint //! \ingroup Public_Params //! \brief class that indicates location and direction of view //! \author Alan Norton //! \version 3.0 //! \date February 2014 //! \par //! This class contains all the parameters associated with viewpoint, including //! camera position, direction, and rotation center. Most of its methods //! should be accessed through the ViewpointParams class. class PARAMS_API Viewpoint : public ParamsBase { public: Viewpoint(ParamsBase::StateSave *ssave); Viewpoint(ParamsBase::StateSave *ssave, XmlNode *node); virtual ~Viewpoint(); //! Return the current 4x4 model-view matrix // void GetModelViewMatrix(double m[16]) const; void SetModelViewMatrix(const double m[16]); void GetProjectionMatrix(double m[16]) const; void SetProjectionMatrix(const double m[16]); bool ReconstructCamera(const double m[16], double position[3], double upVec[3], double viewDir[3]) const; void SetRotationCenter(const std::vector &v) { VAssert(v.size() == 3); SetValueDoubleVec(_rotationCenterTag, "Camera rotation center", v); } std::vector GetRotationCenter() const { vector defaultv(3, 0.0); return (GetValueDoubleVec(_rotationCenterTag, defaultv)); } static string GetClassType() { return ("Viewpoint"); } private: // ParamsContainer *_VPs; static const string _modelViewMatrixTag; static const string _projectionMatrixTag; static const string _rotationCenterTag; static double _defaultModelViewMatrix[16]; static double _defaultProjectionMatrix[16]; void _init(); }; }; // namespace VAPoR #endif // VIEWPOINT_H ================================================ FILE: include/vapor/ViewpointParams.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: ViewpointParams.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: August 2004 // // Description: Defines the ViewpointParams class // This class contains the parameters associated with viewpoint and lights // #ifndef VIEWPOINTPARAMS_H #define VIEWPOINTPARAMS_H #include #include #include #include #include namespace VAPoR { //! \class ViewpointParams //! \ingroup Public_Params //! \brief A class for describing the viewpoint and lights in a 3D VAPOR scene //! \author Alan Norton //! \version 3.0 //! \date February 2014 //! This class describes the state of viewpoints and //! and the properties of light sources. If the ViewpointParams is shared (i.e. not local), all windows can //! use the same viewpoint and lights. Local viewpoints are //! just applicable in one visualizer. class PARAMS_API ViewpointParams : public ParamsBase { public: ViewpointParams(ParamsBase::StateSave *ssave); ViewpointParams(ParamsBase::StateSave *ssave, XmlNode *node); ViewpointParams(const ViewpointParams &rhs); ViewpointParams &operator=(const ViewpointParams &rhs); virtual ~ViewpointParams(); //! Rescale viewing parameters, e.g. when the scene stretch factors change //! \param[in] vector scaleFac scale factors to be applied, relative to previous scaling. void rescale(vector scaleFac); //! This method tells how many lights are specified and whether //! lighting is on or not (i.e. if there are more than 0 lights). //! Note that only the first (light 0) is used in DVR and Isosurface rendering. //! \retval int number of lights (0,1,2) int getNumLights() const { size_t n = (size_t)GetValueLong(_numLightsTag, _defaultNumLights); if (n > 2) n = 2; return (n); } //! Obtain the current specular exponent. //! This value should be used in setting the material properties //! of all geometry being rendered. //! \retval float Specular exponent double getExponent() const { return (GetValueDouble(_specularExpTag, _defaultSpecularExp)); } //! Set the number of directional light sources //! \param[in] int number of lights (0,1,2) //! \retval 0 on success void setNumLights(size_t nlights) { if (nlights > 2) nlights = 2; SetValueLong(_numLightsTag, "Set number of lights", nlights); } //! get one component of a light direction vector //! \param[in] int lightNum identifies which light source //! \param[in] int dir coordinate of direction vector (0..3) //! \retval double requested component of light direction vector // double getLightDirection(int lightNum, int dir) const; //! Set one component of a light direction vector //! \param[in] int lightNum identifies which light source //! \param[in] int dir coordinate of direction vector (0..3) //! \param[in] double value to be set //! \retval int 0 on success void setLightDirection(int lightNum, int dir, double val); //! Optain the diffuse lighting coefficient of a light source //! \param[in] int light number (0..2) //! \retval double diffuse coefficient double getDiffuseCoeff(int lightNum) const; //! Optain the specular lighting coefficient of a light source //! \param[in] int light number (0..2) //! \retval double specular coefficient double getSpecularCoeff(int lightNum) const; //! Optain the ambient lighting coefficient of the lights //! \retval double ambient coefficient double getAmbientCoeff() const { return GetValueDouble(_ambientCoeffTag, _defaultAmbientCoeff); } //! Set the diffuse lighting coefficient of a light source //! \param[in] int light number (0..2) //! \param[in] double diffuse coefficent //! \retval int 0 if successful void setDiffuseCoeff(int lightNum, double val); //! Set the specular lighting coefficient of a light source //! \param[in] int light number (0..2) //! \param[in] double specular coefficent //! \retval int 0 if successful void setSpecularCoeff(int lightNum, double val); //! Set the specular lighting exponent of all light sources //! \param[in] double specular exponent //! \retval int 0 if successful void setExponent(double val) { SetValueDouble(_specularExpTag, "Set specular lighting", val); } //! Set the ambient lighting coefficient //! \param[in] double ambient coefficient //! \retval int 0 if successful void setAmbientCoeff(double val) { SetValueDouble(_ambientCoeffTag, "Set ambient lighting", val); } //! Set the current viewpoint to another viewpoint //! \param[in] Viewpoint* viewpoint to be set //! \retval int 0 if successful //! \sa Viewpoint void SetCurrentViewpoint(Viewpoint *newVP); //! Set widow width and height //! //! \param[in] width width of window in pixels //! \param[in] height height of window in pixels //! void SetWindowSize(size_t width, size_t height); //! Get widow width and height //! //! \param[out] width width of window in pixels //! \param[out] height height of window in pixels //! void GetWindowSize(size_t &width, size_t &height) const; void SetFOV(float v); double GetFOV() const; void SetOrthoProjectionSize(float f); double GetOrthoProjectionSize() const; enum ProjectionType { Perspective, Orthographic, MapOrthographic }; void SetProjectionType(ProjectionType type); ProjectionType GetProjectionType() const; //! Method to get stretch factors vector GetStretchFactors() const; //! method to set stretch factors //! \param[in] factors 3-vector of stretch factors void SetStretchFactors(vector factors); //! Obtain the current viewpoint //! \sa Viewpoint //! \retval Viewpoint* current viewpoint. virtual Viewpoint *getCurrentViewpoint() const { Viewpoint *v = (Viewpoint *)m_VPs->GetParams(_currentViewTag); VAssert(v != NULL); return (v); } //! Return the current 4x4 model-view matrix // void GetModelViewMatrix(double m[16]) const { getCurrentViewpoint()->GetModelViewMatrix(m); } std::vector GetModelViewMatrix() const { double m[16]; getCurrentViewpoint()->GetModelViewMatrix(m); vector vec(m, m + sizeof(m) / sizeof(m[0])); return (vec); } void SetModelViewMatrix(const double matrix[16]) { getCurrentViewpoint()->SetModelViewMatrix(matrix); } void SetModelViewMatrix(const std::vector mvec) { VAssert(mvec.size() == 16); double m[16]; for (int i = 0; i < mvec.size(); i++) m[i] = mvec[i]; getCurrentViewpoint()->SetModelViewMatrix(m); } void GetProjectionMatrix(double m[16]) const { getCurrentViewpoint()->GetProjectionMatrix(m); } void SetProjectionMatrix(const double m[16]) { getCurrentViewpoint()->SetProjectionMatrix(m); } bool ReconstructCamera(const double m[16], double position[3], double upVec[3], double viewDir[3]) const { return (getCurrentViewpoint()->ReconstructCamera(m, position, upVec, viewDir)); } std::vector GetRotationCenter() const { return (getCurrentViewpoint()->GetRotationCenter()); } void GetRotationCenter(double c[3]) const { vector val = GetRotationCenter(); VAssert(val.size() == 3); for (int i = 0; i < val.size(); i++) c[i] = val[i]; } void SetRotationCenter(vector c) { getCurrentViewpoint()->SetRotationCenter(c); } void SetRotationCenter(const double c[3]) { std::vector vec = {c[0], c[1], c[2]}; SetRotationCenter(vec); } //! Access the transform for a data set //! //! Access the transform for data set \p dataSetName //! //! \retval Returns a new transform if one does not exist // virtual Transform *GetTransform(string dataSetName); //! Return list of transform names. //! //! Return the list of transform names added with AddDatasetTransform() // vector GetTransformNames() const { return (_transforms->GetNames()); } //! Set the current camera position, direction, up vector, and origin from a given xml file //! \retval integer indicating success (0) or failure (-1) int SetCameraFromFile(const std::string &path); //! Save the current camera position, direction, up vector, and origin to an xml file //! \retval integer indicating success (0) or failure (-1) int SaveCameraToFile(const std::string &path); #ifdef VAPOR3_0_0_ALPHA //! Determine the current diameter of the visible scene. //! Calculated as 2*Dist*tan(theta*.5) where theta is the camera angle, //! Dist is the distance from the camera to the rotation center. double GetCurrentViewDiameter(vector stretchFactors) const; #endif #ifndef DOXYGEN_SKIP_THIS static const double *getDefaultLightDirection(int lightNum) { return _defaultLightDirection[lightNum]; } static double getDefaultAmbientCoeff() { return _defaultAmbientCoeff; } static double getDefaultSpecularExp() { return _defaultSpecularExp; } static int getDefaultNumLights() { return _defaultNumLights; } static const double *getDefaultDiffuseCoeff() { return _defaultDiffuseCoeff; } static const double *getDefaultSpecularCoeff() { return _defaultSpecularCoeff; } static void setDefaultLightDirection(int lightNum, double val[3]) { for (int i = 0; i < 3; i++) _defaultLightDirection[lightNum][i] = val[i]; } static void setDefaultSpecularCoeff(double val[3]) { for (int i = 0; i < 3; i++) _defaultSpecularCoeff[i] = val[i]; } static void setDefaultDiffuseCoeff(double val[3]) { for (int i = 0; i < 3; i++) _defaultDiffuseCoeff[i] = val[i]; } static void setDefaultAmbientCoeff(double val) { _defaultAmbientCoeff = val; } static void setDefaultSpecularExp(double val) { _defaultSpecularExp = val; } static void setDefaultNumLights(int val) { _defaultNumLights = val; } // Get static string identifier for this params class // static string GetClassType() { return ("ViewpointParams"); } static const string UseCustomFramebufferTag; static const string CustomFramebufferWidthTag; static const string CustomFramebufferHeightTag; private: ParamsContainer *m_VPs = nullptr; ParamsContainer *_transforms = nullptr; static const string _viewPointsTag; static const string _transformsTag; static const string _currentViewTag; static const string _lightDirectionsTag; static const string _diffuseCoeffTag; static const string _specularCoeffTag; static const string _specularExpTag; static const string _ambientCoeffTag; static const string _numLightsTag; static const string m_windowSizeTag; static const string m_stretchFactorsTag; static const string m_fieldOfView; static const string _orthoProjectionSizeTag; static const string _projectionTypeTag; // defaults: static double _defaultLightDirection[3][4]; static double _defaultDiffuseCoeff[3]; static double _defaultSpecularCoeff[3]; static double _defaultAmbientCoeff; static double _defaultSpecularExp; static int _defaultNumLights; void _init(); #endif // DOXYGEN_SKIP_THIS }; }; // namespace VAPoR #endif // VIEWPOINTPARAMS_H ================================================ FILE: include/vapor/Visualizer.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: Visualizer.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: September 2013 // // Description: Definition of Visualizer class: // A Visualizer object is associated with each visualization window. It contains // information required for rendering, performs // navigation and resize, and defers drawing to the viz window's list of // registered renderers. #pragma once #include #include #include #include #include #include namespace VAPoR { //! \class Visualizer //! \ingroup Public_Render //! \brief A class for performing OpenGL rendering in VAPOR GUI Window //! \author Alan Norton //! \version 3.0 //! \date October 2013 //! //! //! The Visualizer class performs OpenGL rendering for the main VAPOR visualizers. The //! Visualizer class is not a GL Window itself, however it will issue the OpenGL calls to //! perform rendering in a context that is already current. class RENDER_API Visualizer : public MyBase { public: Visualizer(const ParamsMgr *pm, const DataStatus *dataStatus, string winName); ~Visualizer(); //! Method that returns the ViewpointParams that is active in this window. //! \retval ViewpointParams* current active ViewpointParams ViewpointParams *getActiveViewpointParams() const; //! Method that returns the RegionParams that is active in this window. //! \retval RegionParams* current active RegionParams RegionParams *getActiveRegionParams() const; //! Method that returns the AnnotationParams that is active in this window. //! \retval AnnotationParams* current active AnnotationParams AnnotationParams *getActiveAnnotationParams() const; //! Method to initialize GL rendering. Must be called from a GL context. //! \param[in] glManager A pointer to a GLManager int InitializeGL(GLManager *glManager); void syncWithParams(); //! Set/clear a flag indicating that the trackball has changed the viewpoint. //! all the OpenGL rendering is performed in the _paintEvent method. It must be invoked from //! a current OpenGL context. //! \return zero if successful. int paintEvent(bool fast); //! Helper function for paintEvent() to hand off a renderer, call matrix operations, and call paintGL //! \return zero if successful. int renderRenderer(Renderer* renderer, bool fast); //! Issue the OpenGL resize call. Must be called from an OpenGL context. //! \param[in] w Window width in pixels. //! \param[in] h Window height in pixels. int resizeGL(int w, int h); //! Identify the visualizer index associated with this visualizer //! \retval visualizer index; string GetWindowName() const { return _winName; } //! Determine the number of renderers in the renderer list //! \return number of renderers int GetNumRenderers() const { return _renderers.size(); } //! \note A render params instance must have been previously created for //! this renderer. // int CreateRenderer(string dataSetName, string renderType, string renderName); //! Flag a renderer for destruction. //! //! \param[in] hasOpenGLContext If true it is the callers job to ensure that the //! OpenGL Context for the window \p winName is active. In this case the renderer //! is destroyed immediately. If false the renderer is queue'd for later destruction //! when \p winName has an active OpenGL context. // void DestroyRenderer(string renderType, string renderName, bool hasOpenGLContext); //! Flag all rendereres for destruction. //! //! \param[in] hasOpenGLContext If true it is the callers job to ensure that the //! OpenGL Context for the window \p winName is active. In this case the renderer //! is destroyed immediately. If false the renderer is queue'd for later destruction //! when \p winName has an active OpenGL context. // void DestroyAllRenderers(bool hasOpenGLContext); bool HasRenderer(string renderType, string renderName) const; //! Move the renderer to the front of the render queue //! \param[out] Renderer instance that is moved to front void MoveRendererToFront(string renderType, string renderName); void MoveRenderersOfTypeToFront(const std::string &type); //! Determine the approximate size of a pixel in terms of user coordinates, //! at the center of the scene. double getPixelSize() const; //! Turn on or off the image capture enablement. If on, the next _paintEvent will result in capture //! Also saves the capture file name int SetImageCaptureEnabled(bool onOff, string filename) { if (_animationCaptureEnabled) { SetErrMsg("Image capture concurrent with Animation Capture\n"); return -1; } _imageCaptureEnabled = onOff; if (onOff) _captureImageFile = filename; else _captureImageFile = ""; return 0; } //! Turn on or off the animation capture enablement. If on, all paintEvents will result in capture //! until it is turned off int SetAnimationCaptureEnabled(bool onOff, string filename) { if (_imageCaptureEnabled) { SetErrMsg("Image capture concurrent with Animation Capture\n"); return -1; } if (_animationCaptureEnabled == onOff) { SetErrMsg("Animation capture in incorrect state\n"); return -1; } _animationCaptureEnabled = onOff; if (onOff) _captureImageFile = filename; else _captureImageFile = ""; return 0; } //! Draw a text banner at x, y coordinates // void DrawText(string text, int x, int y, int size, float color[3], int type = 0) { _vizFeatures->AddText(text, x, y, size, color, type); } void DrawTextNormalizedCoords(string text, float x, float y, int size, float color[3], int type = 0) { _vizFeatures->AddTextNormalizedCoords(text, x, y, size, color, type); } void ClearText() { _vizFeatures->ClearText(); } //! Force each renderer to empty its cache //! //! This method calls ClearCache on every renderer // void ClearRenderCache(); void ClearRenderCache(const string &inst); private: //! Render all the colorbars enabled in this visualizer. void _renderColorbars(int timeStep); //! Capture a single image to a file. Filename must be *.tif or *.jpg //! Must be called during _paintEvent when captureEnabled has been called. //! Will turn off the captureEnabled switch. //! \param[in] filename //! \return zero if successful int _captureImage(std::string path); void _loadMatricesFromViewpointParams(); //! Definition of OpenGL Vendors enum GLVendorType { UNKNOWN = 0, MESA, NVIDIA, ATI, INTEL }; //! Identify the OpenGL Vendor //! \return OpenGL vendor static GLVendorType GetVendor(); //! Place the OpenGL directional lights specified in the ViewpointParams int _configureLighting(); //! Obtain the image from the gl back buffer //! \param[out] data is array of rgb byte values, 3 bytes per pixel //! \return true if successful bool _getPixelData(unsigned char *data) const; void _deleteFlaggedRenderers(); int _initializeNewRenderers(); void _clearActiveFramebuffer(float r, float g, float b) const; void _applyDatasetTransformsForRenderer(Renderer *r); int _getCurrentTimestep() const; static void _incrementPath(string &s); Renderer *_getRenderer(string type, string instance) const; const ParamsMgr * _paramsMgr; const DataStatus * _dataStatus; string _winName; GLManager * _glManager; AnnotationRenderer *_vizFeatures; bool _insideGLContext; // This is only to make sure we don't call certain functions when they are not supposed to be called. In some situations this variable will be set to true incorrectly. In // those cases there is already some other error so it doesn't matter. bool _imageCaptureEnabled; bool _animationCaptureEnabled; string _captureImageFile; vector _renderers; vector _renderersToDestroy; Framebuffer _framebuffer; unsigned int _screenQuadVAO = 0; unsigned int _screenQuadVBO = 0; }; }; // namespace VAPoR ================================================ FILE: include/vapor/VisualizerGLContextManager.h ================================================ #pragma once #include namespace VAPoR { class RENDER_API VisualizerGLContextManager { public: virtual void Activate(const string &visualizerName) = 0; }; } ================================================ FILE: include/vapor/VolumeAlgorithm.h ================================================ #pragma once #include #include #include #include #include #include namespace VAPoR { struct GLManager; class VolumeAlgorithmFactory; class VolumeRenderer; class VolumeParams; class ViewpointParams; class AnnotationParams; class Transform; //! \class VolumeAlgorithm //! \ingroup Public_Render //! //! \brief Strategy pattern for volume rendering algorithms //! //! \author Stanislaw Jaroszynski //! \date Feburary, 2019 //! //! Instances are created with a Factory pattern class VolumeAlgorithm : private NonCopyableMixin { public: enum class Type { Any, DVR, Iso }; VolumeAlgorithm(GLManager *gl, VolumeRenderer *renderer); virtual ~VolumeAlgorithm() {} virtual void SaveDepthBuffer(bool fast){}; virtual int Render(bool fast) = 0; virtual int LoadData(const Grid *grid) = 0; virtual int LoadSecondaryData(const Grid *grid) = 0; virtual void DeleteSecondaryData() = 0; virtual void GetFinalBlendingMode(int *src, int *dst) = 0; //! On OSX, some shaders can run for a long time without problems //! while others will crash if the run too long. It seems to correlate //! with complexity. Chunked rendering splits the rendering into smaller //! tasks so they won't crash virtual bool RequiresChunkedRendering() = 0; virtual float GuestimateFastModeSpeedupFactor() const { return 1; } virtual int CheckHardwareSupport(const Grid *grid) const { return 0; } static VolumeAlgorithm *NewAlgorithm(const std::string &name, GLManager *gl, VolumeRenderer *renderer); static void Register(VolumeAlgorithmFactory *f); protected: GLManager *_glManager; VolumeParams * GetParams() const; ViewpointParams * GetViewpointParams() const; AnnotationParams *GetAnnotationParams() const; Transform * GetDatasetTransform() const; void GetExtents(glm::vec3 *dataMin, glm::vec3 *dataMax, glm::vec3 *userMin, glm::vec3 *userMax) const; private: static std::map factories; VolumeRenderer * _renderer; }; class VolumeAlgorithmNull : public VolumeAlgorithm { public: VolumeAlgorithmNull(GLManager *gl, VolumeRenderer *renderer) : VolumeAlgorithm(gl, renderer) {} static std::string GetName() { return "NULL"; } static Type GetType() { return Type::Any; } int Render(bool fast) { return 0; } int LoadData(const Grid *grid) { return 0; } int LoadSecondaryData(const Grid *grid) { return 0; } void DeleteSecondaryData() {} bool RequiresChunkedRendering() { return false; } void GetFinalBlendingMode(int *src, int *dst) {} }; class VolumeAlgorithmFactory { public: std::string name; VolumeAlgorithm::Type type; virtual VolumeAlgorithm *Create(GLManager *gl, VolumeRenderer *renderer) = 0; }; template class VolumeAlgorithmRegistrar : public VolumeAlgorithmFactory { public: VolumeAlgorithmRegistrar() { static_assert(std::is_base_of::value, "Register is not derived from VolumeAlgorithm"); name = T::GetName(); type = T::GetType(); VolumeAlgorithm::Register(this); } VolumeAlgorithm *Create(GLManager *gl, VolumeRenderer *renderer) { return new T(gl, renderer); } }; } // namespace VAPoR ================================================ FILE: include/vapor/VolumeCellTraversal.h ================================================ #pragma once #include namespace VAPoR { //! \class VolumeCellTraversal //! \ingroup Public_Render //! //! \brief Curvilinear grid rendering algorithm //! //! \author Stanislaw Jaroszynski //! \date Feburary, 2019 //! //! Renders a curvilinear grid by traversing through the cells. The c++ code //! does the following: //! 1. Loads scalar data //! 2. Loads the coordinates //! 3. Generates a bounding box for every border face //! 4. Groups bounding boxs recursively into a tree, i.e. a bounding box at level n //! would encapsulate the 4 associated bounding boxes at level n-1 //! //! The glsl code does the following: //! 1. Find the initial border face that the ray intersects with by traversing //! the tree built on the CPU //! 2. Loop: //! 3. Find the exit face of the current cell //! 4. Render the ray segment from the entrance to the exit //! 5. Set the current exit face to the new entrance face //! 6. Goto Loop until the ray exits the volume class VolumeCellTraversal : public VolumeRegular { public: VolumeCellTraversal(GLManager *gl, VolumeRenderer *renderer); ~VolumeCellTraversal(); static std::string GetName() { return "Curvilinear"; } static Type GetType() { return Type::DVR; } virtual bool RequiresChunkedRendering() { return true; } virtual int LoadData(const Grid *grid); virtual ShaderProgram *GetShader() const; virtual void SetUniforms(const ShaderProgram *shader) const; virtual float GuestimateFastModeSpeedupFactor() const; virtual int CheckHardwareSupport(const Grid *grid) const; private: Texture3D _coordTexture; Texture2DArray _minTexture; Texture2DArray _maxTexture; Texture2D _BBLevelDimTexture; int _coordDims[3]; int _BBLevels; bool _useHighPrecisionTriangleRoutine; bool _gridHasInvertedCoordinateSystemHandiness; bool _needsHighPrecisionTriangleRoutine(const Grid *grid); static bool _need32BitForCoordinates(const Grid *grid); protected: int _getHeuristicBBLevels() const; virtual std::string _addDefinitionsToShader(std::string shaderName) const; }; //! \class VolumeCellTraversalIso //! \ingroup Public_Render //! //! \brief Curvilinear grid isosurface rendering algorithm //! //! \author Stanislaw Jaroszynski //! \date Feburary, 2019 //! //! Renders isosurfaces by ray tracing. This class is the same as the curvilinear DVR //! except it renders an isosurface class VolumeCellTraversalIso : public VolumeCellTraversal { public: VolumeCellTraversalIso(GLManager *gl, VolumeRenderer *renderer) : VolumeCellTraversal(gl, renderer) {} static std::string GetName() { return "Iso Curvilinear"; } static Type GetType() { return Type::Iso; } virtual ShaderProgram *GetShader() const; virtual void SetUniforms(const ShaderProgram *shader) const; }; } // namespace VAPoR ================================================ FILE: include/vapor/VolumeGLSL.h ================================================ #pragma once #include #include #include namespace VAPoR { //! \class VolumeGLSL //! \ingroup Public_Render //! //! \brief Volume rendering algorithms using GLSL //! //! \author Stanislaw Jaroszynski //! \date July, 2020 class VolumeGLSL : public VolumeAlgorithm { public: VolumeGLSL(GLManager *gl, VolumeRenderer *renderer); ~VolumeGLSL(); virtual void SaveDepthBuffer(bool fast); virtual int Render(bool fast); virtual int LoadData(const Grid *grid); virtual ShaderProgram *GetShader() const = 0; virtual void SetUniforms(const ShaderProgram *shader) const = 0; virtual void GetFinalBlendingMode(int *src, int *dst); private: Texture1D _LUTTexture; Texture1D _LUT2Texture; Texture2D _depthTexture; MapperFunction *_tf = 0, *_tf2 = 0; vector _minDataExtents, _maxDataExtents; vector _constantColor; void _loadTF(); void _loadTF(Texture1D *texture, MapperFunction *tf, MapperFunction **cacheTF); void _getLUTFromTF(const MapperFunction *tf, float *LUT) const; void _setShaderUniforms(const ShaderProgram *shader, const bool fast) const; glm::vec3 _getVolumeScales() const; protected: void _getExtents(glm::vec3 *dataMin, glm::vec3 *dataMax, glm::vec3 *userMin, glm::vec3 *userMax) const; private: bool _usingColorMapData() const; }; } // namespace VAPoR ================================================ FILE: include/vapor/VolumeIsoParams.h ================================================ #pragma once #include #include namespace VAPoR { class PARAMS_API VolumeIsoParams : public VolumeParams { public: VolumeIsoParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave); VolumeIsoParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node); virtual ~VolumeIsoParams(); static string GetClassType() { return ("VolumeIsoParams"); } virtual bool GetDefaultLightingEnabled() const override { return true; } virtual double GetDefaultPhongAmbient() const override { return 0.2; } virtual string GetDefaultAlgorithmName() const override; bool HasIsoValues() const override { return true; } protected: virtual bool GetUseSingleColorDefault() const override { return true; } private: void _init(); }; }; // namespace VAPoR ================================================ FILE: include/vapor/VolumeIsoRenderer.h ================================================ #pragma once #include #include #include using std::string; using std::vector; namespace VAPoR { //! \class VolumeIsoRenderer //! \ingroup Public_Render //! //! \brief Isosurface renderer //! //! \author Stanislaw Jaroszynski //! \date Feburary, 2019 //! //! Since Vapor requires a separate class for each renderer, this //! class is a copy of the VolumeRenderer class but it only gives access //! to the isosurface rendering algorithms class RENDER_API VolumeIsoRenderer : public VolumeRenderer { public: VolumeIsoRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string &instName, DataMgr *dataMgr); ~VolumeIsoRenderer(); static std::string GetClassType() { return ("IsoSurface"); } virtual bool _usingColorMapData() const; virtual void _setShaderUniforms(const ShaderProgram *shader, const bool fast) const; virtual std::string _getDefaultAlgorithmForGrid(const Grid *grid) const; virtual void _getLUTFromTF(const MapperFunction *tf, float *LUT) const; }; }; // namespace VAPoR ================================================ FILE: include/vapor/VolumeOSPRay.h ================================================ #pragma once #include #include #include namespace VAPoR { //! \class VolumeOSPRay //! \ingroup Public_Render //! //! \brief OSPRay volume rendering adapter //! //! \author Stanislaw Jaroszynski //! \date July, 2020 //! #ifdef BUILD_OSPRAY class RENDER_API VolumeOSPRay : public VolumeAlgorithm { public: enum WindingOrder { CCW, CW, INVALID }; VolumeOSPRay(GLManager *gl, VolumeRenderer *renderer); ~VolumeOSPRay(); static std::string GetName(); static Type GetType() { return Type::DVR; } virtual bool RequiresChunkedRendering() { return false; } virtual void SaveDepthBuffer(bool fast); virtual int Render(bool fast); virtual int LoadData(const Grid *grid); virtual int LoadSecondaryData(const Grid *grid) { return 0; } virtual void DeleteSecondaryData() {} virtual ShaderProgram *GetShader() const; virtual void SetUniforms(const ShaderProgram *shader) const; virtual float GuestimateFastModeSpeedupFactor() const; virtual void GetFinalBlendingMode(int *src, int *dst); protected: virtual bool _isIso() const { return false; } private: std::vector _dataDimensions; std::vector _depthData; std::vector _backplateData; Texture2D _ospRenderTexture; Texture2D _ospWriteDepthTexture; struct { glm::vec3 min, max; } _clipBox = {glm::vec3(0), glm::vec3(1)}; float _ospSampleRateScalar; struct { bool usePT; } _cache; OSPRenderer _ospRenderer = nullptr; OSPWorld _ospWorld = nullptr; OSPCamera _ospCamera = nullptr; OSPTransferFunction _ospTF = nullptr; OSPInstance _ospInstance = nullptr; OSPVolumetricModel _ospVolumeModel = nullptr; OSPLight _ospLightAmbient = nullptr; OSPLight _ospLightDistant = nullptr; OSPGeometry _ospIso = nullptr; OSPGeometricModel _ospIsoModel = nullptr; void _setupRenderer(bool fast); void _setupCamera(); void _setupIso(); void _loadTF(); void _applyTransform(); void _copyDepth(); void _copyBackplate(); float _guessSamplingRateScalar(const Grid *grid) const; OSPVolume _loadVolumeRegular(const Grid *grid); OSPVolume _loadVolumeStructured(const Grid *grid); OSPVolume _loadVolumeUnstructured(const Grid *grid); OSPVolume _loadVolumeTest(const Grid *grid); static WindingOrder getWindingOrderRespectToZ(const glm::vec3 &a, const glm::vec3 &b, const glm::vec3 &c); static WindingOrder getWindingOrderTetra(const glm::vec3 &a, const glm::vec3 &b, const glm::vec3 &c, const glm::vec3 &d); static const char * windingOrderToString(WindingOrder o); static bool isQuadCoPlanar(const glm::vec3 &a, const glm::vec3 &b, const glm::vec3 &c, const glm::vec3 &d); }; #else class VolumeOSPRay : public VolumeAlgorithm { public: VolumeOSPRay(GLManager *gl, VolumeRenderer *renderer) : VolumeAlgorithm(gl, renderer) {} static std::string GetName() { return "OSPRay"; } }; #endif //! \class VolumeOSPRayIso //! \ingroup Public_Render //! //! \brief OSPRay isosurface rendering adapter //! //! \author Stanislaw Jaroszynski class RENDER_API VolumeOSPRayIso : public VolumeOSPRay { public: VolumeOSPRayIso(GLManager *gl, VolumeRenderer *renderer) : VolumeOSPRay(gl, renderer) {} static std::string GetName() { return "Iso OSPRay (experimental)"; } static Type GetType() { return Type::Iso; } protected: bool _isIso() const { return true; } }; } // namespace VAPoR ================================================ FILE: include/vapor/VolumeParams.h ================================================ #pragma once #include #include #include namespace VAPoR { class PARAMS_API VolumeParams : public RenderParams { public: enum class Type { Any, DVR, Iso }; VolumeParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave); VolumeParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, std::string classType); VolumeParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node); virtual ~VolumeParams(); virtual string GetDefaultAlgorithmName() const; virtual bool GetDefaultLightingEnabled() const { return true; } virtual double GetDefaultPhongAmbient() const { return 0.6; } virtual double GetDefaultPhongDiffuse() const { return 0.5; } virtual double GetDefaultPhongSpecular() const { return 0.1; } virtual double GetDefaultPhongShininess() const { return 0.2; } static string GetClassType() { return ("VolumeParams"); } //! Get the current raycasting algorithm //! \retval string - Current raycasting algorithm (Regular, Curvilinear, or Ospray) std::string GetAlgorithm() const; //! Set the current raycasting algorithm //! \param[in] string - Raycasting algorithm (Regular, Curvilinear, or Ospray) void SetAlgorithm(std::string algorithm); void SetAlgorithmByUser(std::string algorithm); bool GetAlgorithmWasManuallySetByUser() const; void SetAlgorithmWasManuallySetByUser(bool v); static std::vector GetSamplingRateMultiples(); //! Get the sampling rate multiplier used with the current raycasting algorithm //! \retval long - Sampling rate multiplier long GetSamplingMultiplier() const; //! Set the sampling rate multiplier used with the current raycasting algorithm //! \param[in] long - Sampling rate multiplier void SetSamplingMultiplier(long d); using RenderParams::GetIsoValues; using RenderParams::SetIsoValues; vector GetIsoValues(const string &variable) override; void SetIsoValues(const string &variable, const vector &values) override; //! Enable or disable lighting from the position of the camera //! \param[in] bool - Enable lighting (1/true) or disable lighting (0/false) void SetLightingEnabled(bool v); //! Get the state for whether lighting is enabled or disabled //! \retval bool - State for enabled lighting (1/true) or disabled lighting (0/false) bool GetLightingEnabled() const; //! Set the Phong Ambient lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model) //! \param[in] float - Phong ambient lighting coefficient void SetPhongAmbient(float v); //! Get the Phong Ambient lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model) //! \param[in] float - Phong ambient lighting coefficient float GetPhongAmbient() const; //! Set the Phong Diffuse lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model) //! \param[in] float - Phong diffuse lighting coefficient void SetPhongDiffuse(float v); //! Get the Phong Diffuse lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model) //! \param[in] float - Phong diffuse lighting coefficient float GetPhongDiffuse() const; //! Set the Phong Specular lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model) //! \param[in] float - Phong specular lighting coefficient void SetPhongSpecular(float v); //! Get the Phong Specular lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model) //! \param[in] float - Phong specular lighting coefficient float GetPhongSpecular() const; //! Set the Phong Shininess lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model) //! \param[in] float - Phong shininess lighting coefficient void SetPhongShininess(float v); //! Get the Phong Diffuse lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model) //! \param[in] float - Phong shininess lighting coefficient float GetPhongShininess() const; //! \copydoc RenderParams::GetRenderDim() // virtual size_t GetRenderDim() const override { return (3); } //! \copydoc RenderParams::GetActualColorMapVariableName() virtual string GetActualColorMapVariableName() const override { if (GetAlgorithm() == OSPVolmeAlgorithmName) return GetVariableName(); else if (GetValueLong(UseColormapVariableTag, 0)) return GetColorMapVariableName(); else return GetVariableName(); } static const std::vector GetAlgorithmNames(Type type = Type::Any); static void Register(const std::string &name, Type type = Type::Any); private: void _init(); struct AlgorithmEntry { const std::string name; const Type type; bool operator==(const VolumeParams::AlgorithmEntry &b) { return std::tie(name, type) == std::tie(b.name, b.type); } }; static std::vector _algorithms; static const std::string _algorithmWasManuallySetByUserTag; static const std::string _isoValuesTag; static const std::string _enabledIsoValuesTag; public: static const std::string _algorithmTag; //! If this is enabled, the volume opacity will be controlled by the main variable while the colormapping will be determined by the colormap variable static const std::string UseColormapVariableTag; static const std::string SamplingRateMultiplierTag; //! The VolumeDensityTag applies an opacity factor to the entirety of the volume rendering //! in addition to the opacity applied in the Transfer Function. //! Values range between 0.0 (completely transparent) and 1.0 (completely opaque). static const std::string VolumeDensityTag; static const std::string LightingEnabledTag; static const std::string PhongAmbientTag; static const std::string PhongDiffuseTag; static const std::string PhongSpecularTag; static const std::string PhongShininessTag; static const std::string OSPDensity; static const std::string OSPSampleRateScalar; static const std::string OSPAmbientLightIntensity; static const std::string OSPDirectionalLightIntensity; static const std::string OSPVolmeAlgorithmName; }; }; // namespace VAPoR ================================================ FILE: include/vapor/VolumeRectilinear.h ================================================ #pragma once #include namespace VAPoR { //! \class VolumeRectilinear //! \ingroup Public_Render //! //! \brief Rectilinear grid rendering algorithm //! //! \author Stanislaw Jaroszynski //! class VolumeRectilinear : public VolumeRegular { public: VolumeRectilinear(GLManager *gl, VolumeRenderer *renderer); ~VolumeRectilinear(); static std::string GetName() { return "Rectilinear"; } static Type GetType() { return Type::DVR; } virtual bool RequiresChunkedRendering() { return true; } virtual int LoadData(const Grid *grid); virtual ShaderProgram *GetShader() const; virtual void SetUniforms(const ShaderProgram *shader) const; virtual float GuestimateFastModeSpeedupFactor() const; virtual int CheckHardwareSupport(const Grid *grid) const; private: Texture2DArray _minTexture; Texture2DArray _maxTexture; Texture2D _BBLevelDimTexture; Texture2D _coordLUTTexture; int _coordDims[3]; int _coordSigns[3]; bool _useHighPrecisionTriangleRoutine; bool _gridHasInvertedCoordinateSystemHandiness; protected: virtual std::string _addDefinitionsToShader(std::string shaderName) const; }; //! \class VolumeRectilinearIso //! \ingroup Public_Render //! //! \brief Rectilinear grid isosurface rendering algorithm //! //! \author Stanislaw Jaroszynski //! //! Renders isosurfaces by ray tracing. This class is the same as the rectilinear DVR //! except it renders an isosurface class VolumeRectilinearIso : public VolumeRectilinear { public: VolumeRectilinearIso(GLManager *gl, VolumeRenderer *renderer) : VolumeRectilinear(gl, renderer) {} static std::string GetName() { return "Iso Rectilinear"; } static Type GetType() { return Type::Iso; } virtual ShaderProgram *GetShader() const; virtual void SetUniforms(const ShaderProgram *shader) const; }; } // namespace VAPoR ================================================ FILE: include/vapor/VolumeRegular.h ================================================ #pragma once #include #include namespace VAPoR { //! \class VolumeRegular //! \ingroup Public_Render //! //! \brief Regular grid rendering algorithm //! //! \author Stanislaw Jaroszynski //! \date Feburary, 2019 //! //! Renders a regular grid by ray tracing. The CPU side just loads //! the scalar data and missing values as well as secondary data if needed //! //! The glsl code does a standard sampled ray tracing of the volume. class VolumeRegular : public VolumeGLSL { public: VolumeRegular(GLManager *gl, VolumeRenderer *renderer); ~VolumeRegular(); static std::string GetName() { return "Regular"; } static Type GetType() { return Type::DVR; } virtual bool RequiresChunkedRendering() { return false; } virtual int LoadData(const Grid *grid); virtual int LoadSecondaryData(const Grid *grid); virtual void DeleteSecondaryData(); virtual ShaderProgram *GetShader() const; virtual void SetUniforms(const ShaderProgram *shader) const; virtual float GuestimateFastModeSpeedupFactor() const; virtual int CheckHardwareSupport(const Grid *grid) const; protected: Texture3D _data; Texture3D _missing; bool _hasMissingData; std::vector _dataDimensions; bool _hasSecondData; Texture3D _data2; Texture3D _missing2; bool _hasMissingData2; int _loadDataDirect(const Grid *grid, Texture3D *dataTexture, Texture3D *missingTexture, bool *hasMissingData); virtual std::string _addDefinitionsToShader(std::string shaderName) const; }; //! \class VolumeRegularIso //! \ingroup Public_Render //! //! \brief Regular grid isosurface rendering algorithm //! //! \author Stanislaw Jaroszynski //! \date Feburary, 2019 //! //! Renders isosurfaces by ray tracing. This does the same CPU side tasks //! as the volume renderer but it provides different GLSL code. class VolumeRegularIso : public VolumeRegular { public: VolumeRegularIso(GLManager *gl, VolumeRenderer *renderer) : VolumeRegular(gl, renderer) {} static std::string GetName() { return "Iso Regular"; } static Type GetType() { return Type::Iso; } virtual ShaderProgram *GetShader() const; virtual void SetUniforms(const ShaderProgram *shader) const; }; } // namespace VAPoR ================================================ FILE: include/vapor/VolumeRenderer.h ================================================ #pragma once #include #include #include #include #include namespace VAPoR { class RENDER_API VolumeRenderer : public Renderer { public: VolumeRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string &instName, DataMgr *dataMgr); VolumeRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string paramsType, std::string classType, std::string &instName, DataMgr *dataMgr); ~VolumeRenderer(); static std::string GetClassType() { return ("Volume"); } protected: int _initializeGL(); int _paintGL(bool fast); void _clearCache(){}; virtual std::string _getColorbarVariableName() const; void _drawScreenQuad(); void _drawScreenQuadChuncked(); void _generateChunkedRenderMesh(const float chunks); bool _wasTooSlowForFastRender() const; void _computeNewFramebufferRatio(); bool _shouldUseChunkedRender(bool fast) const; virtual bool _usingColorMapData() const; void _saveOriginalViewport(); void _restoreOriginalViewport(); void _initializeFramebuffer(bool fast); int _renderFramebufferToDisplay(); int _initializeAlgorithm(); int _loadData(); int _loadSecondaryData(); virtual std::string _getDefaultAlgorithmForGrid(const Grid *grid) const; bool _needToSetDefaultAlgorithm() const; unsigned int _VAO = (int)NULL; unsigned int _VBO = (int)NULL; unsigned int _VAOChunked = (int)NULL; unsigned int _VBOChunked = (int)NULL; VolumeAlgorithm *_algorithm = nullptr; Framebuffer _framebuffer; int _nChunks; double _lastRenderTime; bool _lastRenderWasFast; int _originalViewport[4]; int _originalFramebuffer; int _framebufferSize[2]; float _framebufferRatio; float _previousFramebufferRatio; std::vector _dataMinExt; std::vector _dataMaxExt; struct Cache { std::string var = ""; size_t ts = -1; int refinement; int compression; bool useColorMapVar = false; std::string colorMapVar = ""; MapperFunction * tf = nullptr; std::vector constantColor; MapperFunction * tf2 = nullptr; std::string algorithmName = ""; std::vector minExt; std::vector maxExt; int ospMaxCells; int ospTestCellId; bool ospPT; bool osp_force_regular; bool osp_test_volume; bool osp_decompose; bool osp_enable_clipping; bool needsUpdate; } _cache; friend class VolumeAlgorithm; }; }; // namespace VAPoR ================================================ FILE: include/vapor/VolumeResampled.h ================================================ #pragma once #include namespace VAPoR { class VolumeResampled : public VolumeRegular { public: VolumeResampled(GLManager *gl) : VolumeRegular(gl) {} static std::string GetName() { return "Resampled"; } virtual int LoadData(const Grid *grid); }; } // namespace VAPoR ================================================ FILE: include/vapor/VolumeTest.h ================================================ #pragma once #include namespace VAPoR { class VolumeTest : public VolumeRegular { public: VolumeTest(GLManager *gl); ~VolumeTest(); static std::string GetName() { return "Test"; } static Type GetType() { return Type::Any; } virtual int LoadData(const Grid *grid); virtual ShaderProgram *GetShader() const; private: unsigned int xyCoordTexture; unsigned int zCoordTexture; }; } // namespace VAPoR ================================================ FILE: include/vapor/VolumeTest2.h ================================================ #pragma once #include namespace VAPoR { class VolumeTest2 : public VolumeRegular { public: VolumeTest2(GLManager *gl); ~VolumeTest2(); static std::string GetName() { return "Test2"; } static Type GetType() { return Type::Any; } virtual int LoadData(const Grid *grid); virtual ShaderProgram *GetShader() const; private: unsigned int xyCoordTexture; unsigned int zCoordTexture; }; } // namespace VAPoR ================================================ FILE: include/vapor/WASP.h ================================================ #ifndef _WASP_H_ #define _WASP_H_ #include #include #include #include #include #include #include #include namespace VAPoR { //! \class WASP //! \ingroup Public_VDC //! \brief Implements WASP compression conventions for NetCDF //! //! \author John Clyne //! \date July, 2014 //! //! Implements WASP compression conventions for NetCDF by extending //! the NetCDFCPP class. //! //! The WASP conventions establish a policy for compressing, storing, //! and accessing arrays of data in NetCDF. This API provides //! an interface for NetCDF data adhering to the WASP conventions. //! //! Fundamental concepts of the WASP compression conventions include the //! following: //! //! \li \b Blocking Compressed arrays are decomposed into fixed size blocks, //! and each block is compressed individually and atomically. The rank of the //! block may be equal-to, or less-than that of the array. In the latter //! case blocking (and subsequent compression) is only performed on the //! the \em n fastest varying array dimensions, where \em n is the rank of //! the block. //! //! \li \b Transformation Each block is transformed prior to compression //! in an effort to decorrelate (remove redundancy) from the data. The //! transformation process is typically lossless up to floating point //! round off. //! //! \li \b Multi-resolution Some transforms, notably wavelets, exhibit the //! the property of multi-resolution: arrays can be reconstructed from //! transformed coefficients at progressively finer resolution. Resolution //! levels in the WASP API are specified with a \b level parameter, in the //! range 0..max, where 0 is the coarsest resolution possible for a given //! variable, and \em max corresponds to the original resolution of the //! array. The value of \b -1 is an alias for \em max. //! //! \li Progressive access Aka embedded encoding, is the property by //! which compressed data may be progressively refined during decoding by //! transmitting (reading) more of the encoded data. The WASP API supports //! progressive access, but supports a discrete form of refinement: only //! a small, finite set of refinement levels, indicated by a \b lod //! parameter that indexes into an ordered vector of available //! compression ratios. //! //! This class inherits from Wasp::MyBase. Unless otherwise documented //! any method that returns an integer value is returning status. A negative //! value indicates failure. Error messages are logged via //! Wasp::MyBase::SetErrMsg(). In general, methods that return //! boolean values will not record an error message on failure. //! //! \param wname Name of biorthogonal wavelet to use for data //! transformation. If not specified (if \p wname is the empty string) //! no transformation or compression are performed. However, arrays //! are still decomposed into blocks as per the \p bs parameter. //! See VAPoR::WaveFiltBior. //! //! \param bs An ordered list of block dimensions that specifies the //! block decomposition of the variable. The rank of \p bs may be less //! than that of a variable's array dimensions, in which case only //! the \b n fastest varying variable dimensions will be blocked, where //! \b n is the rank of \p bs. //! //! \param cratios A monotonically decreasing vector of //! compression ratios. Each element of \p cratios is in //! the range 1 //! (indicating no compression) to //! \b max, where \b max is the maximum compression supported by the //! specified combination of block size, \p bs, and //! wavelet (See InqCompressionInfo()). If the underlying NetCDF file was //! created with the \b numfiles parameter greater than one then the //! length of \p cratios must exactly match that of \b numfiles. //! //! \param lod An index into the \p cratios vector. A value of -1 //! may be used to index the last element of \p cratios //! //! \param level Array dimensions refinement level for compressed //! variables. A value of 0 indicates //! the coarsest refinement level available, a value of one indicates //! next coarsest, and so on. The finest resolution available is given //! by InqVarNumRefLevels() - 1. If \p level is less than 0 it is interpreted //! do indicate the finest grid resolution. // class WASP_API WASP : public VAPoR::NetCDFCpp { public: //! default constructor //! //! Construct a WASP object //! //! \param[in] nthreads Number of parallel execution threads //! to be run during encoding and decoding of compressed data. A value //! of 0, the default, indicates that the thread count should be //! determined by the environment in a platform-specific manner, for //! example using sysconf(_SC_NPROCESSORS_ONLN) under *nix OSes. //! // WASP(int nthreads = 0); virtual ~WASP(); //! Create a new NetCDF data set with support for WASP conventions //! //! \param[in] path The file base name of the new NetCDF data set //! \param[in] cmode Same as in NetCDFCpp::Create() //! \param[in] initialsz Same as in NetCDFCpp::Create() //! \param[in] bufrsizehintp Same as in NetCDFCpp::Create() //! \param[in] numfiles An integer greater than or equal to one indicating //! whether compressed //! variables should be stored in separate files, one compression level //! (level of detail) per file. A value of one indicates that all //! compression levels for //! compressed variables should be stored in the single file specified by //! \p path. A value greater than one results in the creation of //! \p numfile NetCDF files, each of which will contain a separate //! compression level for any compressed variables. Variables that //! are not compressed will be stored in their entirety in the file //! named by \p path. //! //! \sa NetCDFCpp::Create(), NetCDFCpp::GetPaths() // virtual int Create(string path, int cmode, size_t initialsz, size_t &bufrsizehintp, int numfiles); //! Open an existing NetCDF file //! //! \param[in] path The file base name of the new NetCDF data set //! \param[in] mode Same as in NetCDFCpp::Open() //! //! \sa NetCDFCpp::Open() // virtual int Open(string path, int mode); //! \copydoc NetCDFCpp::SetFill() // virtual int SetFill(int fillmode, int &old_modep); //! \copydoc NetCDFCpp::EndDef() // virtual int EndDef() const; //! Close an open NetCDF file //! //! This method closes any currently opened NetCDF files that were //! opened with Create() or Open(). //! virtual int Close(); //! Return the dimension lengths associated with a variable. //! //! Returns the dimensions of the named variable at the //! multi-resolution level indicated by \p level. If the variable //! does not support multi-resolution (is not compressed with a //! multi-resolution transform) the \p level parameter is ignored, //! the variable's native dimensions will be returned, and the value //! of \p bs will not be undefined. //! //! \param[in] name Name of NetCDF variable //! \param[in] level Grid (dimension) refinement level. A value of 0 indicates //! the coarsest refinement level available, a value of one indicates //! next coarsest, and so on. The finest resolution available is given //! by InqVarNumRefLevels() - 1. If \p level is less than 0 it is interpreted //! do indicate the finest grid resolution. //! //! \param[out] dims Ordered list of variable's \p name dimension lengths //! at the grid hierarchy level indicated by \p level //! \param[out] bs Ordered list of block dimension lengths //! at the grid hierarchy level indicated by \p level //! //! \sa NetCDFCpp::InqVarDims(), InqVarNumRefLevels(), //! InqDimsAtLevel() // virtual int InqVarDimlens(string name, int level, vector &dims, vector &bs) const; //! \copydoc NetCDFCpp::NetCDFCpp() // virtual int InqVarDims(string name, vector &dimnames, vector &dims) const; //! Returns compression paramaters associated with the named variable //! //! This method returns various compression parameters associated //! with a compressed variabled named by \p name. If the variable //! \p name is not compressed \p wname will be empty. If the variable //! is not blocked \p bs will be either empty or all elements //! set to one. //! //! \param[in] name The variable name. //! \param[out] wname The name of the wavelet used to transform the variable. //! \param[out] bs An ordered list of block dimensions that specifies the //! block decomposition of the variable. //! \param[out] cratios The compression ratios available. //! virtual int InqVarCompressionParams(string name, string &wname, vector &bs, vector &cratios) const; //! Return the dimensions of a multi-resolution grid at a specified level in //! the hierarchy //! //! This static method calculates the coarsened dimensions of a //! grid at a specified level in a multiresolution wavelet hierarchy. //! The dimensions of an array are determined by the combination of //! the multi-resolution wavelet used, specified by \p wname, the //! refinement level, \p level, in the multi-resolution hierarchy, //! the rank and dimension of the decomposition block, specified by //! \p bs, and the dimensions of the native (original) grid, \p dims. //! //! \param[in] wname wavelet name //! \param[in] level Grid (dimension) refinement level. A value of 0 indicates //! the coarsest refinement level available, a value of one indicates //! next coarsest, and so on. The finest resolution available is given //! by InqVarNumRefLevels() - 1. If \p level is less than 0 it is interpreted //! do indicate the finest grid resolution. //! \param[in] dims Dimensions of native grid //! \param[in] bs Dimensions of native decomposition block. The rank of //! \p bs may be less than or equal to the rank of \p dims. //! \param[out] dims_at_level Computed grid dimensions at the specified level //! \param[out] bs_at_level Computed block dimensions at the specified level //! //! \sa VarOpenRead() // static int InqDimsAtLevel(string wname, int level, vector dims, vector bs, vector &dims_at_level, vector &bs_at_level); //! Return the number of levels available in a variable's multiresolution //! hierarchy. //! //! Returns the depth of the multi-resolution hierarchy for the variable //! specified by \p name. If the variable //! does not support multi-resolution (is not compressed with a //! multi-resolution transform) value of 1 is returned. //! //! \param[in] name The name of the variable //! //! \retval depth Upon success the number of levels in hierarchy //! are returned. If \p varname does not specify a known variable //! a -1 is returned. // virtual int InqVarNumRefLevels(string name) const; //! Compute the number of levels in a multi-resolution hierarchy //! //! This static method computes and returns the depth (number of levels) in a //! a multi-resolution hierarch for a given wavelet, \p wname, //! and decomposition block, \p bs. //! It also computes the maximum compression ratio, \p cratio, possible //! for the //! the specified combination of block size, \p bs, and wavelet, \p wname. //! The maximum compression ratio is \p cratio:1. //! //! \param[in] wname wavelet name //! \param[in] bs Dimensions of native decomposition block. The rank of //! \p bs may be less than or equal to the rank of \p dims. //! \param[out] nlevels Number of levels in hierarchy //! \param[out] maxcratio Maximum compression ratio //! //! bool status If \p bs, \p wname, or the combination there of is invalid //! false is returned and the values of \p nlevels and \p maxcratio are //! undefined. Upon success true is returned. //! static bool InqCompressionInfo(vector bs, string wname, size_t &nlevels, size_t &maxcratio); //! Define a new compressed variable //! //! \param[in] name Same as NetCDFCpp::DefVar() //! \param[in] xtype Same as NetCDFCpp::DefVar() //! \param[in] dimnames Same as NetCDFCpp::DefVar() //! \param[in] wname Name of biorthogonal wavelet to use for data //! transformation. See VAPoR::WaveFiltBior. If empty, the variable //! will be blocked according to \p bs, but will not be compressed. //! \param[in] bs An ordered list of block dimensions that specifies the //! block decomposition of the variable. //! array's associated dimension. The rank of \p bs may be equal to //! or less than //! that of \p dimnames. In the latter case only the rank(bs) fastest //! varying dimensions of the variable will be blocked. //! The dimension(s) of \p bs[i] need not align with (be integral factors //! of) the dimension lengths //! associated with \p dimnames in which case boundary blocks will be //! padded. If \p bs is empty, or the product of its elements is one, //! the variable will not be blocked or compressed. Hence, the //! \p wname and \p cratio parameters will be ignored. The variable //! will not be defined as a \b WASP variable. See InqVarWASP(). //! \param[in] cratios A monotonically decreasing vector of //! compression ratios. Each element of \p cratios is in //! the range 1 //! (indicating no compression) to //! \b max, where \b max is the maximum compression supported by the //! specified combination of block size, \p bs, and //! wavelet (See InqCompressionInfo()). If the underlying NetCDF file was //! created with \b numfiles parameter greater than one then the //! length of \p cratios must exactly match that of \b numfiles. //! //! \sa NetCDFCpp::DefVar(), Create(), InqCompressionInfo() // virtual int DefVar(string name, int xtype, vector dimnames, string wname, vector bs, vector cratios); //! Define a compressed variable with missing data values //! //! The defined variable may contain missing data values. These //! values will not be transformed and compressed //! //! \copydoc DefVar( //! string name, int xtype, vector dimnames, //! string wname, vector bs, vector cratios //! ) //! //! \param[in] missing_value Value of missing value indicator. //! //! \sa NetCDFCpp::DefVar() //! virtual int DefVar(string name, int xtype, vector dimnames, string wname, vector bs, vector cratios, double missing_value); //! \copydoc NetCDFCpp::DefVar() // Is this needed? virtual int DefVar(string name, int xtype, vector dimnames) { return (NetCDFCpp::DefVar(name, xtype, dimnames)); }; //! \copydoc NetCDFCpp::DefDim() // int DefDim(string name, size_t len) const; //! Inquire whether a named variable is compressed //! //! \param[in] name The name of the variable //! \param[out] compressed A boolean return value indicating whether //! variable \p name is compressed // virtual int InqVarCompressed(string varname, bool &compressed) const; //! Inquire whether a variable is a WASP variable //! //! This method returns true if the variable named by \p varname //! was defined by the WASP API and is either compressed, blocked, or //! both. //! int InqVarWASP(string varname, bool &wasp) const; //! Prepare a variable for writing //! //! Compressed or blocked variables must be opened prior to writing. //! This method initializes the variable named by \p name for writing //! using the PutVara() method. If the variable is defined as compressed //! the \p lod parameter indicates which compression levels will be stored. //! Valid values for \p lod are in the range 0..max, where \p max the size //! of cratios - 1. //! //! Any currently opened variable is first closed with Close() //! //! \param[in] name Name of variable //! \param[in] lod Level-of-detail to save. If not -1, all LOD's from //! 0 to \p lod will subsequently be written. //! //! \note Is \p lod needed? Since cratios can be specified on a per //! variable basis perhaps this is not needed? For single file //! representations it would be better to limit the lod using cratios, //! which will result in a smaller file. //! //! \sa PutVara(), // virtual int OpenVarWrite(string name, int lod); //! Prepare a variable for reading //! //! Compressed or blocked variables must be opened prior to reading. //! This method initializes the variable named by \p name for reading //! using the GetVara() or GetVar() methods. If the variable is //! defined as compressed //! the \p lod parameter indicates which compression levels will used //! during reconstruction of the variable. //! Valid values for \p lod are in the range 0..max, where \p max the size //! of \b cratios - 1. //! If the transform used to compress this variable supports //! multiresolution then the \p level parameter indicates the //! grid hierarchy refinement level for which to reconstruct the data. //! //! Any currently opened variable is first closed with Close() //! //! \param[in] name Name of variable //! \param[in] lod Level-of-detail to read. //! \param[in] level Grid refinement level //! //! \sa GetVara() // virtual int OpenVarRead(string name, int level, int lod); //! Close the currently opened variable //! //! If a variable is opened for writing this method will flush //! all buffers to disk and perform cleanup. If opened for reading //! only cleanup is performed. If no variables are open this method //! is a no-op. // //! virtual int CloseVar(); //! Write an array of values to the currently opened variable //! //! The currently opened variable may or may not be a WASP //! variable (See InqVarWASP()). //! //! The combination of \p start and \p count specify the //! coordinates of a hyperslab to write as described by //! NetCDFCpp::PutVara(). However, for blocked data dimensions //! the values of \p start and \p count must be block aligned //! unless the hyperslab includes the array boundary, in which case //! the hyperslab must be aligned to the boundary. //! //! \param[in] start A vector of block-aligned integers specifying //! the index in the variable where the first of the data values will //! be read. See NetCDFCpp::PutVara() //! \param[in] count A vector of size_t, block-aligned integers //! specifying the edge //! lengths along each dimension of the block of data values to be read. //! See NetCDFCpp::PutVara() //! \param[in] data Same as NetCDFCpp::PutVara() //! //! \sa OpenVarWrite(); // virtual int PutVara(vector start, vector count, const float *data); virtual int PutVar(const float *data); virtual int PutVara(vector start, vector count, const double *data); virtual int PutVar(const double *data); virtual int PutVara(vector start, vector count, const int *data); virtual int PutVar(const int *data); virtual int PutVara(vector start, vector count, const int16_t *data); virtual int PutVar(const int16_t *data); virtual int PutVara(vector start, vector count, const unsigned char *data); virtual int PutVar(const unsigned char *data); //! Write an array of masked values to the currently opened variable //! //! This version of PutVar() handles missing data values whose //! presence is indicated by a boolean mask, \p mask. Missing values //! are replaced with values that perform better when compressed (e.g. the //! average of the field) //! //! \copydoc PutVar( //! vector start, vector count, const float *data //! ) //! //! \param[in] mask a boolean array with the same shape as \p data //! indicting valid and invalid values in \p data. Elements of \p data //! corresponding to false values in \p mask are not preserved when //! written to storage. //! virtual int PutVara(vector start, vector count, const float *data, const unsigned char *mask); virtual int PutVar(const float *data, const unsigned char *mask); virtual int PutVara(vector start, vector count, const double *data, const unsigned char *mask); virtual int PutVar(const double *data, const unsigned char *mask); virtual int PutVara(vector start, vector count, const int *data, const unsigned char *mask); virtual int PutVar(const int *data, const unsigned char *mask); virtual int PutVara(vector start, vector count, const int16_t *data, const unsigned char *mask); virtual int PutVar(const int16_t *data, const unsigned char *mask); virtual int PutVara(vector start, vector count, const unsigned char *data, const unsigned char *mask); virtual int PutVar(const unsigned char *data, const unsigned char *mask); //! Read a hyper-slab of values from the currently opened variable //! //! The currently opened variable may or may not be a WASP //! variable (See InqVarWASP()). //! //! If a compressed variable is being read and the transform //! supports multi-resolution the method InqVarDimlens() //! should be be used to determine the dimensions of the variable //! at the opened refinement level. //! //! \param[in] start A vector of size_t integers specifying the index in //! the variable where the first of the data values will be read. //! The coordinates are specified relative to the dimensions of the //! array at the currently opened refinement level. //! See NetCDFCpp::InqVarDimlens() //! \param[in] count A vector of size_t integers specifying the //! edge lengths along each dimension of the hyperslab of data values to //! be read. //! The coordinates are specified relative to the dimensions of the //! array at the currently opened refinement level. See NetCDFCpp::PutVara() //! \param[out] data Same as NetCDFCpp::PutVara() //! //! \sa InqVarDimlens(), OpenVarRead() // virtual int GetVara(vector start, vector count, float *data); virtual int GetVara(vector start, vector count, double *data); virtual int GetVara(vector start, vector count, int *data); virtual int GetVara(vector start, vector count, int16_t *data); virtual int GetVara(vector start, vector count, unsigned char *data); //! Read a hyper-slab of blocked values from currently opened variable //! //! This method is identical to GetVara() with the exceptions //! that: //! \li The vectors \p start and \p count must be aligned //! with the underlying storage block of the variable. See //! WASP::DefVar() //! //! \li The hyperslab copied to \p data will preserve its underlying //! storage blocking (the data will not be contiguous) //! //! \param[in] start A block-aligned vector of size_t integers specifying //! the index in //! the variable where the first of the data values will be read. //! \param[in] count A block-aligned vector of size_t integers specifying the //! edge lengths along each dimension of the hyperslab of data values to //! be read. //! //! \sa WASP::DefVar() // virtual int GetVaraBlock(vector start, vector count, float *data); virtual int GetVaraBlock(vector start, vector count, double *data); virtual int GetVaraBlock(vector start, vector count, int *data); virtual int GetVaraBlock(vector start, vector count, int16_t *data); virtual int GetVaraBlock(vector start, vector count, unsigned char *data); //! Read an array of values from the currently opened variable //! //! The currently opened variable may or may not be a WASP //! variable (See InqVarWASP()). //! //! The entire variable is read and copied into the array pointed to //! by \p data. The caller is responsible for ensuring that //! adequate space is availble in \p data. //! //! If a compressed variable is being read and the transform //! supports multi-resolution the method InqVarDimlens() //! should be be used to determine the dimensions of the variable //! at the opened refinement level //! //! \param[in] data Same as NetCDFCpp::PutVara() //! //! \sa InqVarDimlens(), OpenVarRead() // virtual int GetVar(float *data); virtual int GetVar(double *data); virtual int GetVar(int *data); virtual int GetVar(int16_t *data); virtual int GetVar(unsigned char *data); //! Copy a variable from one WASP file to another WASP file //! //! Copy a variable from the WASP file associated with this //! object instance to the WASP file associated with \p wasp //! The variable \p varname must be defined in both the source //! and destination files, and must have matching dimensions. //! //! If the source and destination variables are compressed this method //! attempts to copy data verbatim, avoiding decoding and encoding. // virtual int CopyVar(string varname, WASP &wasp); //! Copy a variable from a NetCDF file to a WASP file //! //! Copy a variable from the NetCDF file associated with \p ncdf //! to the WASP file associated with this object instance. //! The variable \p varname must be defined in both the source //! and destination files, and must have matching dimensions. // virtual int CopyVarFrom(string varname, NetCDFCpp &ncdf); //! Copy a variable from a WASP file to a NetCDF file //! //! Copy a variable from the WASP file associated this object instance //! to the WASP file associated with \p ncdf. //! The variable \p varname must be defined in both the source //! and destination files, and must have matching dimensions. // virtual int CopyVarTo(string varname, NetCDFCpp &ncdf); //! Return the NetCDF file paths that would be created from a base //! path. //! //! //! \param[in] path The file base name of the new NetCDF data set //! \param[in] numfiles An integer greater than or equal to one indicating //! the number of files to split a variable into //! \retval vector The path names generated from \p path //! //! \sa Create() // static std::vector GetPaths(string path, int numfiles) { if (numfiles > 1) { return (mkmultipaths(path, numfiles)); } else { std::vector t(1, path); return (t); } } //! NetCDF attribute name specifying Wavelet name static string AttNameWavelet() { return ("WASP.Wavelet"); } //! NetCDF attribute name specifying compression block dimensions static string AttNameBlockSize() { return ("WASP.BlockSize"); } //! NetCDF attribute name specifying number of compression files static string AttNameNumFiles() { return ("WASP.NumFiles"); } //! NetCDF attribute name specifying compression ratios static string AttNameCRatios() { return ("WASP.CRatios"); } //! NetCDF attribute name specifying if this is a WASP file or //! variable static string AttNameWASP() { return ("WASP"); } //! NetCDF attribute name specifying names of uncompressed dimensions static string AttNameDimNames() { return ("WASP.DimNames"); } //! NetCDF attribute name specifying if missing data values are present static string AttNameMissingValue() { return ("WASP.MissingValue"); } //! NetCDF attribute name specifying WASP version number static string AttNameVersion() { return ("WASP.Version"); } private: Wasp::EasyThreads * _et; int _nthreads; vector _ncdfcs; vector _ncdfcptrs; // pointers into _ncdfcs; bool _waspFile; // Is this a WASP file int _numfiles; // Number of NetCDF files int _currentVersion; // Current WASP version number; int _fileVersion; // version number of opened file; Wasp::SmartBuf _blockbuf; // Dynamic storage for blocks Wasp::SmartBuf _coeffbuf; // Dynamic storage wavelet coefficients Wasp::SmartBuf _sigbuf; // Dynamic storage encoded signficance maps bool _open; // compressed variable open for reading or writing? string _open_wname; // wavelet name of opened variable vector _open_bs; // block size of opened variable vector _open_cratios; // compression ratios of opened variable vector _open_udims; // uncompressed dims of opened variable vector _open_dims; // compressed dims of opened variable int _open_lod; // level-of-detail of opened variable int _open_level; // grid refinement level of opened variable bool _open_write; // opened variable open for writing? bool _open_waspvar; // opened variable is a WASP variable? string _open_varname; // name of opened variable nc_type _open_varxtype; // external type of opened variable vector _open_compressors; // Compressor for opened variable int _GetBlockAlignedDims(vector dimnames, vector bs, vector &badimnames, vector &badims) const; int _GetCompressedDims(vector dimnames, string wname, vector bs, vector cratios, int xtype, vector &cdimnames, vector &cdims, vector &encoded_dim_names, vector &encoded_dims) const; int _InqDimlen(string name, size_t &len) const; void _get_encoding_vectors(string wname, vector bs, vector cratios, int xtype, vector &ncoeffs, vector &encoded_dims) const; bool _validate_compression_params(string wname, vector dims, vector bs, vector cratios) const; bool _validate_put_vara_compressed(vector start, vector count, vector bs, vector udims, vector cratios) const; bool _validate_get_vara_compressed(vector start, vector count, vector bs, vector udims, vector cratios, bool unblock) const; int _get_compression_params(string name, vector &bs, vector &cratios, vector &udims, vector &dims, string &wname) const; template int _GetVara(vector start, vector count, bool unblock, T *data, U dummy); template int _GetVara(vector start, vector count, bool unblock_flag, T *data); static void _dims_at_level(vector dims, vector bs, int level, string wname, vector &dims_level, vector &bs_level); static vector mkmultipaths(string path, int n); template int _PutVara(vector start, vector count, const T *data, const unsigned char *mask, U dummy); template int _PutVara(vector start, vector count, const T *data, const unsigned char *mask); template int _CopyHyperSlice(string varname, NetCDFCpp &src_ncdf, NetCDFCpp &dst_ncdf, vector start, vector count, T *buf) const; int _CopyVar(string varname, NetCDFCpp &src_ncdf, NetCDFCpp &dst_ncdf) const; // Determine POD type // int _NetCDFType(float dummy) { return NC_FLOAT; } int _NetCDFType(char dummy) { return NC_BYTE; } int _NetCDFType(double dummy) { return NC_DOUBLE; } int _NetCDFType(unsigned char dummy) { return NC_UBYTE; } int _NetCDFType(int16_t dummy) { return NC_SHORT; } int _NetCDFType(int dummy) { return NC_INT; } int _NetCDFType(long dummy) { return NC_INT64; } }; } // namespace VAPoR namespace Wasp { } #endif // _WASP_H_ ================================================ FILE: include/vapor/WaveCodecIO.h ================================================ // // $Id$ // #ifndef _WaveCodeIO_h_ #define _WaveCodeIO_h_ #include #include #include #include #include #ifdef PARALLEL #include #endif namespace VAPoR { // //! \class WaveCodecIO //! \brief A sub-region reader for VDF files //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! This class provides an API for reading and writing //! VDC2 data. VDC2 data may be accessed with two forms of //! wavelet based progressive //! refinement, : hierarchical or level-of-detail. The former supports //! coarsening and refinement of the sampling grid resolution (the //! dimensions of the sampling grid) at varying //! powers-of-two, and is controled by the \p reflevel parameter. The latter //! allows for arbitrary approximations by restricting the number of //! wavelet basis coefficients used when reconstructing the data from //! their wavelet representation. The level-of-detail is controled with //! the \p lod parameter. // class VDF_API WaveCodecIO : public VDFIOBase, protected Wasp::EasyThreads { public: //! \copydoc VDFIOBase::VDFIOBase(MetadataVDC &) //! //! \param[in] nthreads Number of execution threads that may be used by //! the class for parallel execution. If zero, the system hardware will //! be queried via sysconf to determine the number of processors //! available and this value will be used. // WaveCodecIO(const MetadataVDC &metadata, int nthreads = 0); //! \copydoc VDFIOBase::VDFIOBase(const string &) //! //! \param[in] nthreads Number of execution threads that may be used by //! the class for parallel execution. If zero, the system hardware will //! be queried via sysconf to determine the number of processors //! available and this value will be used. // WaveCodecIO(const string &metafile, int nthreads = 0); #ifdef VAPOR3_0_0_ALPHA WaveCodecIO(const size_t dim[3], const size_t bs[3], int numTransforms, const vector cratios, const string &wname, const string &filebase); WaveCodecIO(const vector &files); #endif virtual ~WaveCodecIO(); //! Open the named variable for reading //! //! This method prepares a data volume (slice), indicated by a //! variable name and time step pair, for subsequent read operations by //! methods of this class. The number of the refinement levels //! parameter, \p reflevel, indicates the resolution of the volume in //! the multiresolution hierarchy. The valid range of values for //! \p reflevel is [0..max_refinement], where \p max_refinement is the //! maximum refinement level of the data set: Metadata::GetNumTransforms(). //! A value of zero indicates the //! coarsest resolution data, a value of \p max_refinement (or -1) indicates //! the //! finest resolution data. //! The level-of-detail parameter, \p lod, selects //! the approximation level. Valid values for \p lod are integers in //! the range 0..GetCRatios().size()-1, or the value -1 may be used //! to select the best approximation available: GetCRatios().size()-1. //! //! An error occurs, indicated by a negative return value, if the //! volume identified by the {varname, timestep, reflevel, lod} tupple //! is not available. Note the availability of a volume can be tested //! with the VariableExists() method. //! //! \param[in] timestep Time step of the variable to read //! \param[in] varname Name of the variable to read //! \param[in] reflevel Refinement level of the variable. A value of -1 //! indicates the maximum refinment level defined for the VDC //! \param[in] lod Approximation level of the variable. A value of -1 //! indicates the maximum approximation level defined for the VDC //! \retval status Returns a non-negative value on success //! //! \sa Metadata::GetVariableNames(), Metadata::GetNumTransforms(), //! GetNumTimeSteps(), GetCRatios() //! virtual int OpenVariableRead(size_t timestep, const char *varname, int reflevel = 0, int lod = 0); //! Open the named variable for writing //! //! Prepare a VDC for writing a data volume (slice). //! The data volume is identified by the specfied time step and //! variable name. The number of resulting approximations for //! the data volume is determined by the Metadata object used to //! initialize the class. Moreover, the number of levels-of-detail actually //! saved to the data collection are determined by \p lod. If //! \p lod is maximum level of detail (or the special value -1, the default) //! all of the wavelet coefficients are saved, and it is possible to //! fully reconstruct the volume later without loss of information (beyond //! floating point round off). //! //! \param[in] timestep Time step of the variable to read //! \param[in] varname Name of the variable to read //! \param[in] lod Level of detail saved. A value of -1 //! indicates the maximum level of detail. //! //! \retval status Returns a non-negative value on success //! \sa Metadata::GetVariableNames(), Metadata::GetNumTransforms() //! virtual int OpenVariableWrite(size_t timestep, const char *varname, int reflevel = -1 /*ignored*/, int lod = -1); //! Close the currently opened variable. //! //! \sa OpenVariableWrite(), OpenVariableRead() // virtual int CloseVariable(); //! Read in and return a subregion from the currently opened //! data volume. //! //! The \p bmin and \p bmax vectors identify the minimum and //! maximum extents, in block coordinates, of the subregion of interest. The //! minimum valid value of 'bmin' is (0,0,0), the maximum valid value of //! \p bmax is (nbx-1,nby-1,nbz-1), where nx, ny, and nz are the //! block dimensions of the volume at the currently opened refinement //! level as retuned by GetDimBlk(). //! The volume //! returned is stored in the memory region pointed to by \p region. It //! is the caller's responsbility to ensure adequate space is available. //! //! \param[in] bmin Minimum region extents in block coordinates //! \param[in] bmax Maximum region extents in block coordinates //! \param[out] region The requested volume subregion //! \param[in] unblock If true, unblock the data before copying to \p region //! //! \retval status Returns a non-negative value on success //! //! \sa OpenVariableRead(), GetBlockSize(), MapVoxToBlk() // virtual int BlockReadRegion(const size_t bmin[3], const size_t bmax[3], float *region, bool unblock = true); //! Read in and return a subregion from the currently opened //! data volume. //! //! This method is similar to BlockReadRegion() with the exception //! that the region bounds are specified in voxel coordinates. //! The \p min and \p max vectors identify the minimum and //! maximum extents, in voxel coordinates, of the subregion of interest. The //! minimum valid value of 'min' is (0,0,0), the maximum valid value of //! \p max is (nx-1,ny-1,nz-1), where nx, ny, and nz are the //! voxel dimensions of the volume at the currently opened refinement //! level as returned by GetDim(). //! //! The volume //! returned is stored in the memory region pointed to by \p region. It //! is the caller's responsbility to ensure adequate space is available. //! //! \param[in] min Minimum region extents in voxel coordinates //! \param[in] max Maximum region extents in voxel coordinates //! \param[out] region The requested volume subregion //! //! \retval status Returns a non-negative value on success //! \sa OpenVariableRead(), GetDim(), MapVoxToBlk() // virtual int ReadRegion(const size_t min[3], const size_t max[3], float *region); virtual int ReadRegion(float *region); //! Read the next volume slice from the currently opened file //! //! Read in and return a slice (2D array) of //! voxels from the currently opened data volume at the current //! refinement level. //! Subsequent calls will read successive slices //! until the entire volume has been read. //! It is the caller's responsibility to ensure that the array pointed //! to by \p slice contains enough space to accomodate //! an NX by NY dimensioned slice, where NX is the dimesion of the //! volume along the X axis, specified //! in **voxels**, and NY is the Y axis dimension, as returned by //! GetDim(). //! //! \note ReadSlice returns 0 if the entire volume has been read. //! //! \param[out] slice The requested volume slice //! //! \retval status Returns a non-negative value on success //! \sa OpenVariableRead(), Metadata::GetDim() //! // virtual int ReadSlice(float *slice); //! Write a volume subregion to the currently opened progressive //! access data volume. //! //! This method is identical to the WriteRegion() method with the exception //! that the region boundaries are defined in block, not voxel, coordinates. //! Secondly, unless the 'block' parameter is set, the internal //! blocking of the data will be preserved. I.e. the data are assumed //! to already be blocked. //! //! The number of voxels contained in \p region must be the product //! over i : //! //! \p (bmax[i] - \p bmin[i] + 1) * bs[i] //! //! where bs[i] is the ith dimension of the block size. //! //! \param[in] bmin Minimum region extents in block coordinates //! \param[in] bmax Maximum region extents in block coordinates //! \param[in] region The volume subregion to write //! \param[in] block If true, block the data before writing/transforming //! //! \retval status Returns a non-negative value on success //! \sa OpenVariableWrite() SetBoundarPadOnOff() // virtual int BlockWriteRegion(const float *region, const size_t bmin[3], const size_t bmax[3], bool block = true); //! Write a volume subregion to the currently opened progressive //! access data volume. //! //! This method is identical to the WriteRegion() method with the exception //! that the region boundaries are defined in block, not voxel, coordinates. //! Secondly, unless the 'block' parameter is set, the internal //! blocking of the data will be preserved. I.e. the data are assumed //! to already be blocked. //! //! The number of voxels contained in \p region must be the product //! over i : //! //! \p (max[i] - \p min[i] + 1) //! //! \param[in] min Minimum region extents in voxel coordinates //! \param[in] max Maximum region extents in voxel coordinates //! \param[in] region The volume subregion to write //! //! \retval status Returns a non-negative value on success //! \sa OpenVariableWrite(), GetBlockSize(), MapVoxToBlk() //! \sa SetBoundarPadOnOff() //! //! \note Unexpected results may be obtained if this method is //! invoked multiple times for adjacent regions if the region //! boundaries do not coincide with block boundaries. //! virtual int WriteRegion(const float *region, const size_t min[3], const size_t max[3]); virtual int WriteRegion(const float *region); //! Write a single slice of voxels to the currently opened variable //! //! Transform and write a single slice (2D array) of voxels to the variable //! indicated by the most recent call to OpenVariableWrite(). //! The dimensions of a slices is NX by NY, //! where NX is the dimesion of the volume along the X axis, specified //! in voxels, and NY is the Y axis dimension. //! //! This method should be called exactly NZ times for each opened variable, //! where NZ is the dimension of the volume in voxels along the Z axis. Each //! invocation should pass a successive slice of volume data. //! //! \param[in] slice A slices of volume data //! \retval status Returns a non-negative value on success //! \sa OpenVariableRead() //! virtual int WriteSlice(const float *slice); //! Toggle padding of data on writes //! //! If true, incomplete data blocks will be padded prior to transformation //! and storage to disk. A block is incomplete iff it is a boundary block //! (a block that contains a volume region boundary) //! and the extents of the region do not coincide with block boundaries //! //! \param[in] pad Boolean indicating whether padding should (true) or should //! not (false) take place //! //! \sa GetBoundaryMode() //! virtual void SetBoundaryPadOnOff(bool pad) { _pad = pad; }; //! Return the data range of the currently opened volume as a two-element array //! //! This method returns the minimum and maximum data values //! of the currently opened variable within the valid domain //! bounds. See GetValidRegion(). //! //! \note The range values returned are valid for the native //! data only. Data approximations produced by level-of-detail or //! through multi-resolution may have values outside of this range. //! //! \retval[out] range A two-element vector containing the current //! minimum and maximum. //! // const float *GetDataRange() const { return (_dataRange); } //! Return the valid region bounds for the currently opened //! variable //! //! This method returns the minimum and maximum valid coordinate //! bounds (in voxels) of the currently opened variable. In general, //! the minimum bounds are (0,0,0) and the maximum bounds are //! (nx-1, ny-1, nz-1), where nx, ny, and nz are the volume dimensions //! returned by GetDim(). However, partial regions (sub-volumes) may be //! written to the VDC as well. //! //! //! \param[in] reflevel Refinement level of the variable //! \param[out] min Minimum coordinate bounds (in voxels) of volume //! \param[out] max Maximum coordinate bounds (in voxels) of volume //! \retval status A non-negative int is returned on success //! void GetValidRegion(size_t min[3], size_t max[3], int reflevel) const; //! Returns true if the indicated data volume exists on disk //! //! Returns true if the variable identified by the timestep, variable //! name, refinement level, and level-of-detail is present on disk. //! Returns 0 if //! the variable is not present. //! \param[in] ts A valid time step from the Metadata object used //! to initialize the class //! \param[in] varname A valid variable name //! \param[in] reflevel Ignored //! \param[in] lod Compression level of detail requested. The coarsest //! approximation level is 0 (zero). A value of -1 indicates the finest //! refinement level contained in the VDC. // virtual int VariableExists(size_t ts, const char *varname, int reflevel = 0, int lod = 0) const; //! Return the maximimum compression ratio possible //! //! This static methods returns the maximum possible compression ratio //! possible for a given combination of blocksize, \p ps, wavele name, //! \p wname, and wavelet boundary handling mode, \p wmode. //! //! \param[in] bs A three-element vector providing the dimensions of //! a block //! \param[in] wavename The name of the wavelet //! \param[in] wmode The wavelet boundary handling mode //! //! \retval ratio A value of zero is returned if the wavename or wmode //! are invalid, otherwise the maximum possible data compression ratio //! is returned. //! //! \sa Metadata::GetCRatios() //! static size_t GetMaxCRatio(const size_t bs[3], string wavename, string wmode); //! \copydoc Metadata::GetNumTransforms() // virtual int GetNumTransforms() const; //! \copydoc Metadata::GetBlockSize(size_t, int) // virtual void GetBlockSize(size_t bs[3], int reflevel) const; #ifdef PARALLEL void SetIOComm(MPI_Comm NewIOComm) { _IO_Comm = NewIOComm; }; #endif void SetCollectiveIO(bool newCollectiveIO) { _collectiveIO = newCollectiveIO; }; friend void *RunBlockReadRegionThread(void *object); friend void *RunBlockWriteRegionThread(void *object); private: #ifdef PARALLEL MPI_Comm _IO_Comm; #endif bool _collectiveIO; double _xformMPI; double _methodTimer; double _methodThreadTimer; double _ioMPI; // // Threaded read object for parallel inverse transforms // (data reconstruction) // class ReadWriteThreadObj { public: ReadWriteThreadObj(WaveCodecIO *wc, int id, float *region, const size_t bmin_p[3], const size_t bmax_p[3], const size_t bdim_p[3], const size_t dim_p[3], const size_t bs_p[3], bool reblock, bool pad); void BlockReadRegionThread(); void BlockWriteRegionThread(); const float *GetDataRange() const { return (_dataRange); } private: WaveCodecIO * _wc; int _id; // thread id float * _region; // destination buffer for read const size_t *_bmin_p; const size_t *_bmax_p; // block coordinates of data const size_t *_bdim_p; const size_t *_dim_p; const size_t *_bs_p; // dimensions of block float _dataRange[2]; bool _reblock; bool _pad; int _FetchBlock(size_t bx, size_t by, size_t bz); int _WriteBlock(size_t bx, size_t by, size_t bz); }; public: int _nthreads; // num execution threads int getNumThread() { return _nthreads; } void EnableBuffering(size_t count[3], size_t divisor, int rank); private: int _next_block; int _threadStatus; size_t _NC_BUF_SIZE; // buffering disabled by default ReadWriteThreadObj ** _rw_thread_objs; vector> _sigmapsThread; // one set for each thread vector _sigmapsizes; // size of each encoded sig map Compressor * _compressor3D; // 3D compressor Compressor * _compressor2DXY; Compressor * _compressor2DXZ; Compressor * _compressor2DYZ; Compressor * _compressor; // compressor for currently opened variable vector _compressorThread3D; vector _compressorThread2DXY; vector _compressorThread2DXZ; vector _compressorThread2DYZ; vector _compressorThread; // current compressor threads vector _ncbufs; VarType_T _vtype; // Type (2d, or 3d) of currently opened variable VarType_T _compressorType; // Type (2d, or 3d) of current _compressor int _lod; // compression level of currently opened file int _reflevel; // current refinement level size_t _validRegMin[3]; // min region bounds of current file size_t _validRegMax[3]; // max region bounds of current file bool _writeMode; // true if opened for writes bool _isOpen; // true if a file is opened size_t _timeStep; // currently opened time step string _varName; // Currently opened variable vector _ncpaths; vector _ncids; vector _nc_sig_vars; // ncdf ids for wave and sig vars vector _nc_wave_vars; float * _cvector; // storage for wavelet coefficients size_t _cvectorsize; // amount of space allocated to _cvector vector _cvectorThread; unsigned char * _svector; // storage for encoded signficance map size_t _svectorsize; // amount of space allocated to _svector vector _svectorThread; float * _block; // storage for a block vector _blockThread; float * _blockReg; // more storage float _dataRange[2]; vector _ncoeffs; // num wave coeff. at each compression level vector _cratios3D; // 3D compression ratios vector _cratios2D; // 2D compression ratios vector _cratios; // compression ratios for currently opened file float *_sliceBuffer; size_t _sliceBufferSize; // size of slice buffer in elements int _sliceCount; // num slices written bool _pad; // Padding enabled? int _OpenVarWrite(const string &basename); int _OpenVarRead(const string &basename); int _WaveCodecIO(int nthreads); int _SetupCompressor(); void _UnpackCoord(VarType_T vtype, const size_t src[3], size_t dst[3], size_t fill) const; void _PackCoord(VarType_T vtype, const size_t src[3], size_t dst[3], size_t fill) const; void _FillPackedCoord(VarType_T vtype, const size_t src[3], size_t dst[3], size_t fill) const; }; }; // namespace VAPoR #endif // _WaveCodeIO_h_ ================================================ FILE: include/vapor/WaveFiltBase.h ================================================ #ifndef _WaveFiltBase_h_ #define _WaveFiltBase_h_ #include namespace VAPoR { // //! \class WaveFiltBase //! \brief A base class for wavelet family filters //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! The WaveFiltBase class is a base class for building classes of //! wavelet families that can be implemented as FIR filters. A wavelet //! family class contains scaling and //! wavelet coefficients that define a particular wavelet. All //! filters are normalized unless IsNormalized returns false. //! class WASP_API WaveFiltBase { public: WaveFiltBase(); virtual ~WaveFiltBase(); //! Return the number of coefficients in both the scaling and //! wavelet FIR filter. //! //! This method returns the number of elements in the arrays //! returned by the classes filter retrieval methods //! //! \retval filter length //! //! \sa GetLowDecomFilCoef(), GetLowReconFilCoef(), GetHighDecomFilCoef() //! GetHighReconFilCoef() //! int GetLength() const { return (_filterLength); }; //! Return scaling (low pass) decompostion filter coefficients const double *GetLowDecomFilCoef() const { return (_lowDecomFilCoef); }; //! Return scaling (low pass) reconstruction filter coefficients const double *GetLowReconFilCoef() const { return (_lowReconFilCoef); }; //! Return wavelet (high pass) decompostion filter coefficients const double *GetHighDecomFilCoef() const { return (_hiDecomFilCoef); }; //! Return wavelet (high pass) decompostion filter coefficients const double *GetHighReconFilCoef() const { return (_hiReconFilCoef); }; //! Returns true if the wavelet is symmetric (or antisymmetric) //! virtual bool issymmetric() const { return (false); }; //! Returns true if the wavelet is an integer transform //! virtual bool isint() const { return (false); }; //! Returns true wavelet transform is normalized //! virtual bool IsNormalized() const { return (true); }; protected: static const int MAX_FILTER_SIZE = 32; // space allocated to filters int _filterLength; // length of filters double * _lowDecomFilCoef; double * _lowReconFilCoef; double * _hiDecomFilCoef; double * _hiReconFilCoef; /*------------------------------------------- * Flipping Operation *-----------------------------------------*/ void wrev(const double *sigIn, double *sigOut, int sigLength) const; /*------------------------------------------- * Quadrature Mirror Filtering Operation *-----------------------------------------*/ void qmf_even(const double *sigIn, double *sigOut, int sigLength) const; /*------------------------------------------- * Flipping and QMF at the same time *-----------------------------------------*/ void qmf_wrev(const double *sigIn, double *sigOut, int sigLength) const; /*------------------------------------------- * Verbatim Copying *-----------------------------------------*/ void verbatim_copy(const double *sigIn, double *sigOut, int sigLength) const; }; } // namespace VAPoR #endif ================================================ FILE: include/vapor/WaveFiltBior.h ================================================ #include #include "WaveFiltBase.h" using namespace std; #ifndef _WaveFiltBior_h_ #define _WaveFiltBior_h_ namespace VAPoR { // //! \class WaveFiltBior //! \brief Biorthogonal spline family FIR filters //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! This class provides FIR filters for the Biorlet family of wavelets //! class WASP_API WaveFiltBior : public WaveFiltBase { public: //! Create a set of Biorthogonal spline filters //! //! \param[in] wavename The Biorlet family wavelet member. Valid values //! are "bior1.1", "bior1.3", "bior1.5", "bior2.2", "bior2.4", //! "bior2.6", "bior2.8", "bior3.1", "bior3.3", "bior3.5", "bior3.7", //! "bior3.9", "bior4.4" //! WaveFiltBior(const string &wavename); virtual ~WaveFiltBior(); //! Returns true if the wavelet is symmetric (or antisymmetric) //! virtual bool issymmetric() const { return (true); }; private: void _analysis_initialize(int member); void _synthesis_initialize(int member); }; } // namespace VAPoR #endif ================================================ FILE: include/vapor/WaveFiltCoif.h ================================================ #include #include using namespace std; #ifndef _WaveFiltCoif_h_ #define _WaveFiltCoif_h_ namespace VAPoR { // //! \class WaveFiltCoif //! \brief Coiflet family FIR filters //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! This class provides FIR filters for the Coiflet family of wavelets //! class WASP_API WaveFiltCoif : public WaveFiltBase { public: //! Create a set of Coiflet filters //! //! \param[in] wavename The Coiflet family wavelet member. Valid values //! are "coif1", "coif2", "coif3", "coif4", and "coif5" //! WaveFiltCoif(const string &wavename); virtual ~WaveFiltCoif(); private: void _analysis_initialize(int member); void _synthesis_initialize(int member); }; } // namespace VAPoR #endif ================================================ FILE: include/vapor/WaveFiltDaub.h ================================================ #include #include using namespace std; #ifndef _WaveFiltDaub_h_ #define _WaveFiltDaub_h_ namespace VAPoR { // //! \class WaveFiltDaub //! \brief Daubechies family FIR filters //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! This class provides FIR filters for the Daubechies family of wavelets //! class WASP_API WaveFiltDaub : public WaveFiltBase { public: //! Create a set of Daubechies filters //! //! \param[in] wavename The Daubechies family wavelet member. Valid values //! are "db", "db", "db", "db", "db5", "db6", "db7", "db8", "db9", and //! "db10" //! WaveFiltDaub(const string &wavename); virtual ~WaveFiltDaub(); private: void _analysis_initialize(int member); void _synthesis_initialize(int member); }; } // namespace VAPoR #endif ================================================ FILE: include/vapor/WaveFiltHaar.h ================================================ #ifndef _WaveFiltHaar_h_ #define _WaveFiltHaar_h_ namespace VAPoR { // //! \class WaveFiltHaar //! \brief Haar FIR filters //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! This class provides FIR filters for the Haar wavelet //! class WASP_API WaveFiltHaar : public WaveFiltBase { public: //! Create a set of Haar wavelet filters //! WaveFiltHaar(); virtual ~WaveFiltHaar(); private: void _analysis_initialize(); void _synthesis_initialize(); }; } // namespace VAPoR #endif ================================================ FILE: include/vapor/WaveFiltInt.h ================================================ #include #include "WaveFiltBase.h" using namespace std; #ifndef _WaveFiltInt #define _WaveFiltInt namespace VAPoR { // //! \class WaveFiltInt //! \brief Integer Biorthogonal spline family FIR filters //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! This class provides FIR filters for the Biorlet family of wavelets //! class WASP_API WaveFiltInt : public WaveFiltBase { public: //! Create a set of Biorthogonal spline filters //! //! \param[in] wavename The Biorlet family wavelet member. Valid values //! are "bior2.2" //! WaveFiltInt(const string &wavename); virtual ~WaveFiltInt(); //! Returns true if the wavelet is symmetric (or antisymmetric) //! virtual bool issymmetric() const { return (true); }; //! Returns true if the wavelet operates only on integers and preserves //! integer values. //! virtual bool isint() const { return (true); }; virtual bool IsNormalized() const { return (false); }; void Analysis(const long *sigIn, size_t sigInLen, long *cA, long *cD, bool oddlow, bool oddhigh) const; void Synthesis(const long *cA, const long *cD, size_t sigInLen, long *sigOut) const; private: string _wavename; void _analysis_initialize(); void _synthesis_initialize(); void _AnalysisCDF5_3(const long *sigIn, size_t sigInLen, long *cA, long *cD) const; void _SynthesisCDF5_3(const long *cA, const long *cD, size_t sigInLen, long *sigOut) const; }; } // namespace VAPoR #endif ================================================ FILE: include/vapor/WireFrameParams.h ================================================ #ifndef WIREFRAMEDATAPARAMS_H #define WIREFRAMEDATAPARAMS_H #include #include namespace VAPoR { //! \class WireFrameParams //! \brief Class that supports drawing Barbs based on 2D or 3D vector field //! \author John Clyne //! \version 3.0 class PARAMS_API WireFrameParams : public RenderParams { public: WireFrameParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave); WireFrameParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node); virtual ~WireFrameParams(); // Get static string identifier for this params class // static string GetClassType() { return ("WireFrameParams"); } //! \copydoc RenderParams::GetRenderDim() // virtual size_t GetRenderDim() const override { return (_dataMgr->GetVarTopologyDim(GetVariableName())); } //! \copydoc RenderParams::GetActualColorMapVariableName() virtual string GetActualColorMapVariableName() const override { return GetVariableName(); } private: void _init(); }; // End of Class WireFrameParams }; // namespace VAPoR #endif ================================================ FILE: include/vapor/WireFrameRenderer.h ================================================ //---------------- ---------------------------------------------------------- // // Copyright (C) 2018 // University Corporation for Atmospheric Research // All Rights Reserved // //---------------------------------------------------------------------------- #ifndef WIREFRAMERENDERER_H #define WIREFRAMERENDERER_H #include // Must be included first!!! #include #include #include #include #include namespace VAPoR { //! \class WireFrameRenderer //! \brief //! \author John Clyne //! \version 3.0 //! \date June 2018 class RENDER_API WireFrameRenderer : public Renderer { public: //! Constructor, must invoke Renderer constructor //! \param[in] Visualizer* pointer to the visualizer where this will draw //! \param[in] RenderParams* pointer to the ArrowParams describing //! this renderer WireFrameRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr); static string GetClassType() { return ("WireFrame"); } //! Destructor // virtual ~WireFrameRenderer(); protected: //! \copydoc Renderer::_initializeGL() virtual int _initializeGL(); //! \copydoc Renderer::_paintGL() virtual int _paintGL(bool fast); private: GLuint _VAO, _VBO, _EBO; unsigned int _nIndices; Texture1D _lutTexture; bool _GPUOutOfMemory; struct VertexData; struct { string varName; string heightVarName; size_t ts; int level; int lod; std::vector boxMin, boxMax; } _cacheParams; // Helper class to keep track of which cell edges have been drawn so // we can avoid duplicate draws. // class DrawList { public: // maxEntries is the maximum number of unique cell nodes. // maxLinesPerVertex is the *expected* max valence (degree) of any // node (vertex). If a node has more than maxLinesPerVertex edges // only the first maxLinesPerVertex edges will be recorded in // DrawList. Hence, queries to edges with DrawList::InList will // return false once maxLinesPerVertex has been exceeded // DrawList(GLuint maxEntries, size_t maxLinesPerVertex) : _drawList(maxEntries * maxLinesPerVertex, (std::numeric_limits::max)()), _maxEntries(maxEntries), _maxLinesPerVertex(maxLinesPerVertex) { } bool InList(GLuint idx0, GLuint idx1) { VAssert(idx0 < _maxEntries); VAssert(idx1 < _maxEntries); if (idx1 < idx0) { std::swap(idx1, idx0); } for (int i = 0; i < _maxLinesPerVertex; i++) { if (_drawList[idx0 * _maxLinesPerVertex + i] == idx1) { return (true); } if (_drawList[idx0 * _maxLinesPerVertex + i] == (std::numeric_limits::max)()) { _drawList[idx0 * _maxLinesPerVertex + i] = idx1; return (false); } } return (false); } private: vector _drawList; const size_t _maxEntries; const size_t _maxLinesPerVertex; }; void _buildCacheVertices(const Grid *grid, const Grid *heightGrid, vector &nodeMap, bool *GPUOutOfMemory) const; size_t _buildCacheConnectivity(const Grid *grid, const vector &nodeMap, bool *GPUOutOfMemory) const; int _buildCache(); bool _isCacheDirty() const; void _saveCacheParams(); void _drawCell(const GLuint *cellNodeIndices, int n, bool layered, const std::vector &nodeMap, GLuint invalidIndex, std::vector &indices, DrawList &drawList) const; void _clearCache() { _cacheParams.varName.clear(); } }; }; // namespace VAPoR #endif ================================================ FILE: include/vapor/XmlNode.h ================================================ // // $Id$ // #ifndef _XmlNode_h_ #define _XmlNode_h_ #include #include #include #include #include #include #ifdef WIN32 #pragma warning(disable : 4251) #endif namespace VAPoR { // //! \class XmlNode //! \brief An Xml tree //! \author John Clyne //! \version $Revision$ //! \date $Date$ //! //! This class manages an XML tree. Each node in the tree //! coresponds to an XML "parent" element. The concept //! of "parent" element is a creation of this class, //! and should be confused with any notions of parent //! in more commonly used XML jargon. A parent element //! is simply one possessing child XML elements //! Non-parent elements - those elements that do not have //! children elements - //! may be thought of as data elements. Typically //! non-parent elements possess XML character data. Parent //! elements may or may not have XML character data //! themselves. //! //! The XmlNode class is derived from the MyBase base //! class. Hence all of the methods make use of MyBase's //! error reporting capability. //! Any method with a return type of int returns a 0 on //! success, and and a negative int on failure, unless otherwise //! docummented. Similary, methods returning pointers return non-NULL on //! success and NULL on failure. Failure in either case triggers //! logging of an error message with MyBase::SetErrMsg() //! class PARAMS_API XmlNode : public Wasp::MyBase { public: //! Constructor for the XmlNode class. //! //! Create's a new Xml node //! //! \param[in] tag Name of Xml node //! \param[in] attrs A list of Xml attribute names and values for this node //! \param[in] numChildrenHint Reserve space for the indicated number of //! children. Children must be created with //! the NewChild() method //! XmlNode(const string &tag, const map &attrs, size_t numChildrenHint = 0); XmlNode(const string &tag, size_t numChildrenHint = 0); XmlNode(); virtual XmlNode *Construct(const string &tag, const map &attrs, size_t numChildrenHint = 0) { return (new XmlNode(tag, attrs, numChildrenHint)); } //! Copy constructor for the XmlNode class. //! //! Create's a new XmlNode node from an existing one. The new //! node will be parentless. //! //! \param[in] node XmlNode instance from which to construct a copy //! XmlNode(const XmlNode &node); virtual XmlNode *Clone() { return new XmlNode(*this); }; //! Destructor //! //! Recursively delete node and chilren, but only if this is the root //! node. Otherwise this method is a no-op //! //! \sa SetParent() // virtual ~XmlNode(); //! Set or get that node's tag (name) //! //! \retval tag A reference to the node's tag // string &Tag() { return (_tag); } string GetTag() const { return (_tag); } void SetTag(string tag) { _tag = tag; } //! Set or get that node's attributes //! //! \retval attrs A reference to the node's attributes // map &Attrs() { return (_attrmap); } // These methods set or get XML character data, possibly formatting // the data in the process. The paramter 'tag' identifies the XML // element tag associated with the character data. The // parameter, 'values', contains the character data itself. The Long and // Double versions of these methods convert a between character streams // and vectors of longs or doubles as appropriate. // //! Set an Xml element of type long //! //! This method defines and sets an Xml element. The Xml character //! data to be associated with this element is the array of longs //! specified by \p values //! //! \param[in] tags Sequence of names of elements as a path to the desired node //! \param[in] values Vector of longs to be converted to character data //! //! \retval status Returns 0 if successful // virtual void SetElementLong(const vector &tags, const vector &values); virtual void SetElementLong(const vector &tags, long value) { vector values(1, value); XmlNode::SetElementLong(tags, values); } //! Set an Xml element of type long //! //! This method defines and sets an Xml element. The Xml character //! data to be associated with this element is the array of longs //! specified by \p values //! //! \param[in] tag Name of the element to define/set //! \param[in] values Vector of longs to be converted to character data //! //! \retval status Returns 0 if successful // virtual void SetElementLong(const string &tag, const vector &values); virtual void SetElementLong(const string &tag, long value) { vector values(1, value); XmlNode::SetElementLong(tag, values); } //! Get an Xml element's data of type long //! //! Return the character data associated with the Xml elemented //! named by \p tag for this node. The data is interpreted and //! returned as a vector of longs. If the element does not exist //! an empty vector is returned. //! //! \param[in] tag Name of element //! \retval vector Vector of longs associated with the named elemented //! virtual const vector &GetElementLong(const string &tag) const; //! Return true if the named element of type long exists //! //! \param[in] tag Name of element //! \retval value at element //! virtual bool HasElementLong(const string &tag) const; //! Set an Xml element of type double //! //! This method defines and sets an Xml element. The Xml character //! data to be associated with this element is the array of doubles //! specified by \p values //! //! \param[in] tag Name of the element to define/set //! \param[in] values Vector of doubles to be converted to character data //! //! \retval status 0 if successful // virtual void SetElementDouble(const string &tag, const vector &values); virtual void SetElementDouble(const string &tag, double value) { vector values(1, value); XmlNode::SetElementDouble(tag, values); } //! Set an Xml element of type double, using a sequence of tags //! //! This method defines and sets an Xml element. The Xml character //! data to be associated with this element is the array of doubles //! specified by \p values //! //! \param[in] tags vector of tags to the specified element //! \param[in] values Vector of doubles to be converted to character data //! //! \retval status 0 if successful // virtual void SetElementDouble(const vector &tags, const vector &values); virtual void SetElementDouble(const vector &tags, double value) { vector values(1, value); XmlNode::SetElementDouble(tags, values); } //! Get an Xml element's data of type double //! //! Return the character data associated with the Xml elemented //! named by \p tag for this node. The data is interpreted and //! returned as a vector of doubles. If the element does not exist //! an empty vector is returned. //! //! \param[in] tag Name of element //! \retval vector Vector of doubles associated with the named elemented //! virtual const vector &GetElementDouble(const string &tag) const; //! Return true if the named element of type double exists //! //! \param[in] tag Name of element //! \retval bool //! virtual bool HasElementDouble(const string &tag) const; //! Set an Xml element of type string //! //! This method defines and sets an Xml element. The Xml character //! data to be associated with this element is the string //! specified by \p values //! //! \param[in] tag Name of the element to define/set //! \param[in] values string to be converted to character data //! //! \retval status Returns a non-negative value on success //! \retval status Returns 0 if successful // virtual void SetElementString(const string &tag, const string &values); //! Get an Xml element's data of type string //! //! Return the character data associated with the Xml elemented //! named by \p tag for this node. The data is interpreted and //! returned as a string. If the element does not exist //! an empty vector is returned. //! //! \param[in] tag Name of element //! \retval string The string associated with the named element //! virtual const string &GetElementString(const string &tag) const; //! Set an Xml element of type string //! //! This method defines and sets an Xml element. The Xml character //! data to be associated with this element is the array of strings //! specified by \p values. The array of strings is first //! translated to a single string of space-separated words (contiguous //! characters) //! //! \param[in] tag Name of the element to define/set //! \param[in] values Vector of strings to be converted to a //! space-separated list of characters //! //! \retval status Returns 0 if successful // virtual void SetElementStringVec(const string &tag, const vector &values); //! Set an Xml element of type string //! //! This method defines and sets an Xml element. The Xml character //! data to be associated with this element is the array of strings //! specified by \p values. The array of strings is first //! translated to a single string of space-separated words (contiguous //! characters) //! //! \param[in] tagpath sequence of tags leading from this to element //! \param[in] values Vector of strings to be converted to a //! space-separated list of characters //! //! \retval status Returns 0 if successful // virtual void SetElementStringVec(const vector &tagpath, const vector &values); //! Get an Xml element's data of type string //! //! Return the character data associated with the Xml elemented //! named by \p tag for this node. The data is interpreted as //! a space-separated list of words (contiguous characters). The //! string vector returned is generated by treating white //! space as delimeters between vector elements. //! If the element does not exist //! an empty vector is returned //! //! \param[in] tag Name of element //! \param[out] vec Vector of strings associated with the named element //! virtual void GetElementStringVec(const string &tag, vector &vec) const; //! Return true if the named element of type string exists //! //! \param[in] tag Name of element //! \retval bool //! virtual bool HasElementString(const string &tag) const; //! Return the number of children nodes this node has //! //! \retval n The number of direct children this node has //! //! \sa NewChild() // //! Add an existing node as a child of the current node. //! //! The new child node will be cloned from \p child and //! appended to the array of child nodes. //! //! \param[in] child is the XmlNode object to be added as a child //! \retval newchild Returns a pointer to the newly created child. This //! is a no-fail method (NULL is never returned). // XmlNode *AddChild(const XmlNode *child); XmlNode *AddChild(const XmlNode &child); virtual int GetNumChildren() const { return (int)(_children.size()); }; //! Create a new child of this node //! //! Create a new child node, named \p tag. The new child node will be //! appended to the array of child nodes. The \p numChildrenHint //! parameter is a hint specifying how many children the new child //! itself may have. //! //! \param[in] tag Name to give the new child node //! \param[in] attrs A list of Xml attribute names and values for this node //! \param[in] numChildrenHint Reserve space for future children of this node //! \retval child Returns the newly created child, or NULL if the child //! could not be created // virtual XmlNode *NewChild(const string &tag, const map &attrs, size_t numChildrenHint = 0); virtual XmlNode *NewChild(const string &tag, size_t numChildrenHint = 0) { map attrs; return (NewChild(tag, attrs, numChildrenHint)); } //! Delete the indicated child node. //! //! Delete the indicated child node, decrementing the total number //! of children by one. Return an error if the child does not //! exist (i.e. if index >= GetNumChildren()) //! //! \param[in] index Index of the child. The first child is zero //! \retval status Returns a non-negative value on success //! \sa GetNumChildren() virtual int DeleteChild(size_t index); virtual int DeleteChild(const string &tag); //! //! Recursively delete all descendants of a node. //! // virtual void DeleteAll(); #ifdef VAPOR3_0_0_ALPHA //! Replace the indicated child node with specified new child node //! //! If indicated child does not exist, return -1, otherwise //! return the index of the replaced child. //! //! \param[in] childNode Pointer to existing child node //! \param[in] newChild Pointer to replacement child node //! \retval status Returns non-negative child index on success virtual int ReplaceChild(XmlNode *childNode, XmlNode *newChild); #endif //! Return the indicated child node. //! //! Return the ith child of this node. The first child node is index=0, //! the last is index=GetNumChildren()-1. Return NULL if the child //! does not exist. //! //! \param[in] index Index of the child. The first child is zero //! \retval child Returns the indicated child, or NULL if the child //! could does not exist. No error is generated on failure. //! \sa GetNumChildren() // virtual XmlNode *GetChild(size_t index) const; //! Return true if the indicated child node exists //! //! \param[in] index Index of the child. The first child is zero //! \retval bool //! virtual bool HasChild(size_t index) const; //! Return the indicated child node. //! //! Return the indicated tagged child node. Return NULL if the child //! does not exist. //! \param[in] tag Name of the child node to return //! \retval child Returns the indicated child, or NULL if the child //! could does not exist. No error is generated on failure. // virtual XmlNode *GetChild(const string &tag) const; //! Return true if the indicated child node exists //! //! \param[in] tag Name of the child node //! \retval bool //! virtual bool HasChild(const string &tag) const; //! Return a pointer to a node with the indicated path if it exists //! //! This method returns a pointer to the node with the path indicated //! by the path vector \p path. If \p absolute is true the search //! begins from the root of the root of the tree. If \p absolute //! is false, the search begins with the children of this node. //! //! \p retval The indicated node is returned on success. If the path //! is not valid NULL is returned, but no error is reported //! virtual XmlNode *GetNode(std::vector path, bool absolute) const; //! Return a pointer to a node with the indicated path if it exists //! //! The path argument \p path is parsed into a vector of strings, with //! the '/' character used as a delimiter. The resulting path vector //! is passed to GetNode(std::vector path, bool absolute). //! If the first character in \p path is '/' then an absolute path //! is assumed. //! //! \sa GetNode(std::vector path, bool absolute) // virtual XmlNode *GetNode(string path) const; //! Return the node's parent //! //! This method returns a pointer to the parent node, or NULL if this //! node is the root of the tree. //! //! \retval node Pointer to parent node or NULL if no parent exists // virtual XmlNode *GetParent() const { return (_parent); } //! Set a node's parent //! //! Set the parent node to \p parent, adding this node to the //! children of \p parent, and removing it from the children of the //! node's current parent. If \p parent already has a child with the //! same name as this node that child is deleted. //! //! \p parent may be NULL in which case the node becomes a root node //! //! \sa IsRoot(); // void SetParent(XmlNode *parent); //! Write the XML tree, rooted at this node, to a file in XML format // friend ostream &operator<<(ostream &s, const XmlNode &node); //! Assignment operator // XmlNode &operator=(const XmlNode &rhs); //! Equivalence operator // bool operator==(const XmlNode &rhs) const; bool operator!=(const XmlNode &rhs) const { return (!(*this == rhs)); }; //! Return boolean indicating if this node is the root of the tree //! //! This method returns true if the node is the root if the tree. I.e. //! true is returned if the node has no parent. Otherwise false is returned. // virtual bool IsRoot() const { return (GetParent() == NULL); } //! Get the path from the root to this node as a vector of tags //! //! This method returns an ordered vector of strings containing all //! of the XmlNode tags from the root to this node. The first string //! in the vector is the root node tag. // virtual std::vector GetPathVec() const; //! Get the path from the root to this node as a delimeter separated string //! //! This method constructs a delimeter separated path from the string //! vector returned by GetPathVec(). The delimiter is a '/' // virtual string GetPath() const; //! Get the root node of the tree //! //! Walks up the tree starting from this node and //! returns the root node of the tree //! virtual XmlNode *GetRoot() const; static const std::vector &GetAllocatedNodes() { return (_allocatedNodes); } // Following is a substitute for exporting the "<<" operator in windows. // I don't know how to export an operator<< ! static ostream &streamOut(ostream &os, const XmlNode &node); static bool IsValidXMLElement(const string &s, int *badIdx=nullptr); static string SanitizeXMLTag(string s); private: static vector _emptyLongVec; // empty elements static vector _emptyDoubleVec; static vector _emptyStringVec; static string _emptyString; static std::vector _allocatedNodes; map> _longmap; // node's long data map> _doublemap; // node's double data map _stringmap; // node's string data map _attrmap; // node's attributes vector _children; // node's children string _tag; // node's tag name size_t _asciiLimit; // length limit beyond which element data are encoded XmlNode *_parent; // Node's parent }; // ostream& VAPoR::operator<< (ostream& os, const XmlNode& node); class PARAMS_API XmlParser : public Wasp::MyBase { public: XmlParser(); ~XmlParser() {} int LoadFromFile(XmlNode *root, string path); int LoadFromFile(XmlNode *root, istream &in); private: enum type { UNKNOWN, PARENT, LONG_DATA, DOUBLE_DATA, STRING_DATA }; XmlNode * _root; type _nodeType; std::stack _nodeStack; string _stringData; void _startElementHandler(string tag, map &myattrs); void _endElementHandler(string tag); void _charDataHandler(string s); bool _isParentElement(string tag, map myattrs) const; bool _isDataElement(string tag, map myattrs, type &dtype) const; friend void _StartElementHandler(void *userData, const char *tag, const char **attrs); friend void _EndElementHandler(void *userData, const char *tag); friend void _CharDataHandler(void *userData, const char *s, int len); }; }; // namespace VAPoR #endif // _XmlNode_h_ ================================================ FILE: include/vapor/common.h ================================================ #ifdef WIN32 #pragma warning(disable : 4018 4244 4267 4305) #ifdef COMMON_EXPORTS #define COMMON_API __declspec(dllexport) #else #define COMMON_API __declspec(dllimport) #endif #ifdef VDF_EXPORTS #define VDF_API __declspec(dllexport) #else #define VDF_API __declspec(dllimport) #endif #ifdef WASP_EXPORTS #define WASP_API __declspec(dllexport) #else #define WASP_API __declspec(dllimport) #endif #ifdef FLOW_EXPORTS #define FLOW_API __declspec(dllexport) #else #define FLOW_API __declspec(dllimport) #endif #ifdef OSGL_EXPORTS #define OSGL_API __declspec(dllexport) #else #define OSGL_API __declspec(dllimport) #endif #ifdef PARAMS_EXPORTS #define PARAMS_API __declspec(dllexport) #else #define PARAMS_API __declspec(dllimport) #endif #ifdef RENDER_EXPORTS #define RENDER_API __declspec(dllexport) #else #define RENDER_API __declspec(dllimport) #endif #ifdef UDUNITS2_EXPORTS #define UDUNITS2_API __declspec(dllexport) #else #define UDUNITS2_API __declspec(dllimport) #endif #ifdef GRIBAPI_EXPORTS #define GRIBAPI_API __declspec(dllexport) #else #define GRIBAPI_API __declspec(dllimport) #endif #ifdef JPEG_EXPORTS // Slightly different definitions for jpeg project: #define JPEG_GLOBAL(type) __declspec(dllexport) type #define JPEG_EXTERN(type) extern __declspec(dllexport) type #else #define JPEG_GLOBAL(type) __declspec(dllimport) type #ifdef __cplusplus #define JPEG_EXTERN(type) extern "C" __declspec(dllimport) type #else #define JPEG_EXTERN(type) extern __declspec(dllimport) type #endif #endif // JPEG_EXPORTS #else // not WIN32, everything is exported #define COMMON_API #define VDF_API #define WASP_API #define FLOW_API #define OSGL_API #define PARAMS_API #define RENDER_API #define GRIBAPI_API #define JPEG_GLOBAL(type) type // Assume all outside projects depending on JPEG are C++ #ifdef JPEG_EXPORTS #define JPEG_EXTERN(type) extern type #else #define JPEG_EXTERN(type) extern "C" type #endif // ifeq JPEG_EXPORTS #endif // end !Win32 #ifndef M_PI #define M_PI 3.1415926535897932384626433832795 #endif ================================================ FILE: include/vapor/converter.h ================================================ /* * Copyright 2008, 2009 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file LICENSE * in the top-level source-directory of the package for copying and * redistribution conditions. */ /* * Public header-file for the Unidata units(3) library. */ #ifndef CV_CONVERTER_H_INCLUDED #define CV_CONVERTER_H_INCLUDED #include #ifdef __cplusplus extern "C" { #endif #include "udunits2.h" typedef union cv_converter cv_converter; /* * Returns the trivial converter (i.e., y = x). * When finished with the converter, the client should pass the converter to * cv_free(). * RETURNS: * The trivial converter. */ UDUNITS2_API cv_converter *cv_get_trivial(void); /* * Returns the reciprocal converter (i.e., y = 1/x). * When finished with the converter, the client should pass the converter to * cv_free(). * RETURNS: * The reciprocal converter. */ UDUNITS2_API cv_converter *cv_get_inverse(void); /* * Returns a scaling converter (i.e., y = ax). * When finished with the converter, the client should pass the converter to * cv_free(). * RETURNS: * The scaling converter. */ UDUNITS2_API cv_converter *cv_get_scale(const double slope); /* * Returns a converter that adds a number to values (i.e., y = x + b). * When finished with the converter, the client should pass the converter to * cv_free(). * ARGUMENTS: * intercept The number to be added. * RETURNS: * NULL Necessary memory couldn't be allocated. * else A converter that adds the given number to values. */ UDUNITS2_API cv_converter *cv_get_offset(const double intercept); /* * Returns a Galilean converter (i.e., y = ax + b). * When finished with the converter, the client should pass the converter to * cv_free(). * ARGUMENTS: * slope The number by which to multiply values. * intercept The number to be added. * RETURNS: * NULL Necessary memory couldn't be allocated. * else A Galilean converter corresponding to the inputs. */ UDUNITS2_API cv_converter *cv_get_galilean(const double slope, const double intercept); /* * Returns a logarithmic converter (i.e., y = log(x) in some base). * When finished with the converter, the client should pass the converter to * cv_free(). * ARGUMENTS: * base The logarithmic base (e.g., 2, M_E, 10). Must be * greater than one. * RETURNS: * NULL "base" is not greater than one or necessary * memory couldn't be allocated. * else A logarithmic converter corresponding to the inputs. */ UDUNITS2_API cv_converter *cv_get_log(const double base); /* * Returns an exponential converter (i.e., y = pow(b, x) in some base "b"). * When finished with the converter, the client should pass the converter to * cv_free(). * * Arguments: * base The desired base. Must be positive. * Returns: * NULL "base" is invalid or necessary memory couldn't be * allocated. * else An exponential converter corresponding to the inputs. */ UDUNITS2_API cv_converter *cv_get_pow(const double base); /* * Returns a converter corresponding to the sequential application of two * other converters. * ARGUMENTS: * first The converter to be applied first. * second The converter to be applied second. * RETURNS: * NULL Either "first" or "second" is NULL or necessary memory couldn't * be allocated. * else A converter corresponding to the sequential application of the * given converters. If one of the input converters is the trivial * converter, then the returned converter will be the other input * converter. */ UDUNITS2_API cv_converter *cv_combine(cv_converter *const first, cv_converter *const second); /* * Frees resources associated with a converter. * ARGUMENTS: * conv The converter to have its resources freed or NULL. */ UDUNITS2_API void cv_free(cv_converter *const conv); /* * Converts a float. * ARGUMENTS: * converter The converter. * value The value to be converted. * RETURNS: * The converted value. */ UDUNITS2_API float cv_convert_float(const cv_converter *converter, const float value); /* * Converts a double. * ARGUMENTS: * converter The converter. * value The value to be converted. * RETURNS: * The converted value. */ UDUNITS2_API double cv_convert_double(const cv_converter *converter, const double value); /* * Converts an array of floats. * ARGUMENTS: * converter The converter. * in The values to be converted. * count The number of values to be converted. * out The output array for the converted values. May * be the same array as "in" or overlap it. * RETURNS: * NULL "out" is NULL. * else A pointer to the output array. */ UDUNITS2_API float *cv_convert_floats(const cv_converter *converter, const float *const in, const size_t count, float *out); /* * Converts an array of doubles. * ARGUMENTS: * converter The converter. * in The values to be converted. * count The number of values to be converted. * out The output array for the converted values. May * be the same array as "in" or overlap it. * RETURNS: * NULL "out" is NULL. * else A pointer to the output array. */ UDUNITS2_API double *cv_convert_doubles(const cv_converter *converter, const double *const in, const size_t count, double *out); /* * Returns a string representation of a converter. * ARGUMENTS: * conv The converter. * buf The buffer into which to write the expression. * max The size of the buffer. * variable The string to be used as the input value for the * converter. * RETURNS * <0 An error was encountered. * else The number of bytes formatted excluding the terminating null. */ UDUNITS2_API int cv_get_expression(const cv_converter *const conv, char *const buf, size_t max, const char *const variable); #ifdef __cplusplus } #endif #endif ================================================ FILE: include/vapor/debug.h ================================================ #ifndef DEBUG_H #define DEBUG_H #ifdef NDEBUG #define dLog(...) #define dBreak() #define dBreakIf(x) #define dBreakCount(x) #define FTRACE(...) #define PERF_TIMER_START #define PERF_TIMER_STOP #define PERF_TIMER_DELTA 1 #else #include #include #include #include #define DLOG_BASENAME_ONLY 1 #ifdef WIN32 #undef DLOG_BASENAME_ONLY #endif #if DLOG_BASENAME_ONLY #include #define dLog_pre() fprintf(stderr, "[%s:%i:%s] ", basename(__FILE__), __LINE__, __func__) #else #define dLog_pre() fprintf(stderr, "[%s:%i:%s] ", __FILE__, __LINE__, __func__) #endif #define dLog(...) \ { \ dLog_pre(); \ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, "\n"); \ } #define dBreak() \ { \ dLog("Breakpoint"); \ raise(SIGTRAP); \ } #define dBreakIf(x) \ { \ if (x) { dBreak(); } \ } #define dBreakCount(x) \ { \ static int count = 0; \ if (++count == (x)) dBreak(); \ } #if WIN32 #define PERF_TIMER_START #define PERF_TIMER_STOP #define PERF_TIMER_DELTA 1 #else #include #define PERF_TIMER_START \ struct timeval PERF_TIMER_T1, PERF_TIMER_T2; \ gettimeofday(&PERF_TIMER_T1, NULL); #define PERF_TIMER_STOP gettimeofday(&PERF_TIMER_T2, NULL); #define PERF_TIMER_DELTA ((PERF_TIMER_T2.tv_usec - PERF_TIMER_T1.tv_usec) / 1000000.0 + (double)(PERF_TIMER_T2.tv_sec - PERF_TIMER_T1.tv_sec)) #endif #ifdef WIN32 #define PRINT_BACKTRACE() #else #include #define PRINT_BACKTRACE(...) \ { \ printf("------------------ %s", __func__); \ printf(__VA_ARGS__); \ printf(" ------------------\n"); \ void **buffer = (void **)malloc(sizeof(void *) * 32); \ int depth = backtrace(buffer, 32); \ fflush(stdout); \ backtrace_symbols_fd(buffer, depth, fileno(stdout)); \ free(buffer); \ } #endif using std::string; using std::vector; #define VDC_LIBTRACE // #define VDC_LIBTRACE_RUNNABLE #ifdef VDC_LIBTRACE #define NARG(...) NARG_(__VA_ARGS__, RSEQ_N()) #define NARG_(...) ARG_N(__VA_ARGS__) #define ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) N #define RSEQ_N() 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 inline void PRINTARG() {} inline void PRINTARG(int x) { printf("%i", x); } inline void PRINTARG(long x) { printf("%li", x); } inline void PRINTARG(size_t x) { printf("%li", x); } inline void PRINTARG(float x) { printf("%g", x); } inline void PRINTARG(double x) { printf("%g", x); } inline void PRINTARG(bool x) { printf("%s", x ? "true" : "false"); } inline void PRINTARG(const std::string x) { printf("\"%s\"", x.c_str()); } inline void PRINTARG(const char *x) { printf("\"%s\"", x); } #ifdef VDC_LIBTRACE_RUNNABLE inline void PRINTARG(const int *i) { printf("(int[]){%i}", *i); } inline void PRINTARG(const float *f) { printf("(float[]){%f}", *f); } inline void PRINTARG(const double *d) { printf("(double[]){%d}", *d); } inline void PRINTARG(const size_t *li) { printf("(size_t[]){%li}", *li); } inline void PRINTARG(const long *li) { printf("(long[]){%li}", *li); } #else inline void PRINTARG(const int *i) { printf("*[%i]", *i); } inline void PRINTARG(const float *f) { printf("*[%f]", *f); } inline void PRINTARG(const double *d) { printf("*[%f]", *d); } inline void PRINTARG(const size_t *li) { printf("*[%li]", *li); } inline void PRINTARG(const long *li) { printf("*[%li]", *li); } #endif inline void PRINTARG(const void *x) { printf("%s", x ? "" : "NULL"); } // void PRINTARG(const VAPoR::VDC::AccessMode x) { printf("VDC::AccessMode::%s", x==VAPoR::VDC::AccessMode::R?"R":x==VAPoR::VDC::AccessMode::W?"W":"A"); } // void PRINTARG(const VAPoR::DC::XType x) // { // switch (x) { // case VAPoR::DC::XType::INVALID: printf("DC::INVALID"); break; // case VAPoR::DC::XType::FLOAT: printf("DC::FLOAT"); break; // case VAPoR::DC::XType::DOUBLE: printf("DC::DOUBLE"); break; // case VAPoR::DC::XType::UINT8: printf("DC::UINT8"); break; // case VAPoR::DC::XType::INT8: printf("DC::INT8"); break; // case VAPoR::DC::XType::INT32: printf("DC::INT32"); break; // case VAPoR::DC::XType::INT64: printf("DC::INT64"); break; // case VAPoR::DC::XType::TEXT: printf("DC::TEXT"); break; // } // } template void PRINTARG(const std::vector v) { #ifdef VDC_LIBTRACE_RUNNABLE if (v.size() == 1) { string t(__PRETTY_FUNCTION__); int s = t.find("[T = ") + strlen("[T = "); int f = t.find("]", s); t = t.substr(s, f - s); printf("vector<%s>(1, ", t.c_str()); } else #endif printf("{"); for (int i = 0; i < v.size(); i++) { PRINTARG(v[i]); if (i != v.size() - 1) printf(", "); } #ifdef VDC_LIBTRACE_RUNNABLE if (v.size() == 1) printf(")"); else #endif printf("}"); } inline std::string classScopeFromPrettyFunc(const std::string &pretty) { size_t args = pretty.find("("); size_t colons = pretty.substr(0, args).rfind("::"); if (colons == std::string::npos) return ""; size_t begin = pretty.substr(0, colons).rfind(" ") + 1; size_t end = colons - begin; return pretty.substr(begin, end) + "::"; } #define _CONCAT(a, b) a##b #define PRINTARGS_1(x, ...) \ { \ PRINTARG(x); \ } #define PRINTARGS_2(x, ...) \ { \ PRINTARG(x); \ printf(", "); \ PRINTARGS_1(__VA_ARGS__); \ } #define PRINTARGS_3(x, ...) \ { \ PRINTARG(x); \ printf(", "); \ PRINTARGS_2(__VA_ARGS__); \ } #define PRINTARGS_4(x, ...) \ { \ PRINTARG(x); \ printf(", "); \ PRINTARGS_3(__VA_ARGS__); \ } #define PRINTARGS_5(x, ...) \ { \ PRINTARG(x); \ printf(", "); \ PRINTARGS_4(__VA_ARGS__); \ } #define PRINTARGS_6(x, ...) \ { \ PRINTARG(x); \ printf(", "); \ PRINTARGS_5(__VA_ARGS__); \ } #define PRINTARGS_7(x, ...) \ { \ PRINTARG(x); \ printf(", "); \ PRINTARGS_6(__VA_ARGS__); \ } #define PRINTARGS_8(x, ...) \ { \ PRINTARG(x); \ printf(", "); \ PRINTARGS_7(__VA_ARGS__); \ } #define PRINTARGS_9(x, ...) \ { \ PRINTARG(x); \ printf(", "); \ PRINTARGS_8(__VA_ARGS__); \ } #define _PRINTARGS(n, ...) \ _CONCAT(PRINTARGS_, n) \ (__VA_ARGS__) #define PRINTARGS(...) _PRINTARGS(NARG(__VA_ARGS__), __VA_ARGS__) #define FTRACE_PRE() printf("%s%s(", classScopeFromPrettyFunc(__PRETTY_FUNCTION__).c_str(), __func__) #define FTRACE(...) \ do { \ FTRACE_PRE(); \ PRINTARGS(__VA_ARGS__); \ printf(");\n"); \ } while (0) #else #define FTRACE(...) #endif #endif #endif ================================================ FILE: include/vapor/direntWin32.h ================================================ /* * dirent.h - dirent API for Microsoft Visual Studio * * Copyright (C) 2006-2012 Toni Ronkko * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * ``Software''), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * $Id: dirent.h,v 1.20 2014/03/19 17:52:23 tronkko Exp $ */ #ifndef DIRENTWin32_H #define DIRENTWin32_H /* * Define architecture flags so we don't need to include windows.h. * Avoiding windows.h makes it simpler to use windows sockets in conjunction * with dirent.h. */ #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86) #define _X86_ #endif #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_AMD64) #define _AMD64_ #endif #include #include #include #include #include #include #include #include #include #include #include /* Indicates that d_type field is available in dirent structure */ #define _DIRENT_HAVE_D_TYPE /* Indicates that d_namlen field is available in dirent structure */ #define _DIRENT_HAVE_D_NAMLEN /* Entries missing from MSVC 6.0 */ #if !defined(FILE_ATTRIBUTE_DEVICE) #define FILE_ATTRIBUTE_DEVICE 0x40 #endif /* File type and permission flags for stat() */ #if !defined(S_IFMT) #define S_IFMT _S_IFMT /* File type mask */ #endif #if !defined(S_IFDIR) #define S_IFDIR _S_IFDIR /* Directory */ #endif #if !defined(S_IFCHR) #define S_IFCHR _S_IFCHR /* Character device */ #endif #if !defined(S_IFFIFO) #define S_IFFIFO _S_IFFIFO /* Pipe */ #endif #if !defined(S_IFREG) #define S_IFREG _S_IFREG /* Regular file */ #endif #if !defined(S_IREAD) #define S_IREAD _S_IREAD /* Read permission */ #endif #if !defined(S_IWRITE) #define S_IWRITE _S_IWRITE /* Write permission */ #endif #if !defined(S_IEXEC) #define S_IEXEC _S_IEXEC /* Execute permission */ #endif #if !defined(S_IFIFO) #define S_IFIFO _S_IFIFO /* Pipe */ #endif #if !defined(S_IFBLK) #define S_IFBLK 0 /* Block device */ #endif #if !defined(S_IFLNK) #define S_IFLNK 0 /* Link */ #endif #if !defined(S_IFSOCK) #define S_IFSOCK 0 /* Socket */ #endif #if defined(_MSC_VER) #define S_IRUSR S_IREAD /* Read user */ #define S_IWUSR S_IWRITE /* Write user */ #define S_IXUSR 0 /* Execute user */ #define S_IRGRP 0 /* Read group */ #define S_IWGRP 0 /* Write group */ #define S_IXGRP 0 /* Execute group */ #define S_IROTH 0 /* Read others */ #define S_IWOTH 0 /* Write others */ #define S_IXOTH 0 /* Execute others */ #endif /* Maximum length of file name */ #if !defined(PATH_MAX) #define PATH_MAX MAX_PATH #endif #if !defined(FILENAME_MAX) #define FILENAME_MAX MAX_PATH #endif #if !defined(NAME_MAX) #define NAME_MAX FILENAME_MAX #endif /* File type flags for d_type */ #define DT_UNKNOWN 0 #define DT_REG S_IFREG #define DT_DIR S_IFDIR #define DT_FIFO S_IFIFO #define DT_SOCK S_IFSOCK #define DT_CHR S_IFCHR #define DT_BLK S_IFBLK #define DT_LNK S_IFLNK /* Macros for converting between st_mode and d_type */ #define IFTODT(mode) ((mode)&S_IFMT) #define DTTOIF(type) (type) /* * File type macros. Note that block devices, sockets and links cannot be * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are * only defined for compatibility. These macros should always return false * on Windows. */ #define S_ISFIFO(mode) (((mode)&S_IFMT) == S_IFIFO) #define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) #define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG) #define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK) #define S_ISSOCK(mode) (((mode)&S_IFMT) == S_IFSOCK) #define S_ISCHR(mode) (((mode)&S_IFMT) == S_IFCHR) #define S_ISBLK(mode) (((mode)&S_IFMT) == S_IFBLK) /* Return the exact length of d_namlen without zero terminator */ #define _D_EXACT_NAMLEN(p) ((p)->d_namlen) /* Return number of bytes needed to store d_namlen */ #define _D_ALLOC_NAMLEN(p) (PATH_MAX) #ifdef __cplusplus extern "C" { #endif /* Wide-character version */ struct _wdirent { long d_ino; /* Always zero */ unsigned short d_reclen; /* Structure size */ size_t d_namlen; /* Length of name without \0 */ int d_type; /* File type */ wchar_t d_name[PATH_MAX]; /* File name */ }; typedef struct _wdirent _wdirent; struct _WDIR { struct _wdirent ent; /* Current directory entry */ WIN32_FIND_DATAW data; /* Private file data */ int cached; /* True if data is valid */ HANDLE handle; /* Win32 search handle */ wchar_t * patt; /* Initial directory name */ }; typedef struct _WDIR _WDIR; static _WDIR * _wopendir(const wchar_t *dirname); static struct _wdirent *_wreaddir(_WDIR *dirp); static int _wclosedir(_WDIR *dirp); static void _wrewinddir(_WDIR *dirp); /* For compatibility with Symbian */ #define wdirent _wdirent #define WDIR _WDIR #define wopendir _wopendir #define wreaddir _wreaddir #define wclosedir _wclosedir #define wrewinddir _wrewinddir /* Multi-byte character versions */ struct dirent { long d_ino; /* Always zero */ unsigned short d_reclen; /* Structure size */ size_t d_namlen; /* Length of name without \0 */ int d_type; /* File type */ char d_name[PATH_MAX]; /* File name */ }; typedef struct dirent dirent; struct DIR { struct dirent ent; struct _WDIR *wdirp; }; typedef struct DIR DIR; static DIR * opendir(const char *dirname); static struct dirent *readdir(DIR *dirp); static int closedir(DIR *dirp); static void rewinddir(DIR *dirp); /* Internal utility functions */ static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp); static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp); static int dirent_mbstowcs_s(size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords, const char *mbstr, size_t count); static int dirent_wcstombs_s(size_t *pReturnValue, char *mbstr, size_t sizeInBytes, const wchar_t *wcstr, size_t count); static void dirent_set_errno(int error); /* * Open directory stream DIRNAME for read and return a pointer to the * internal working area that is used to retrieve individual directory * entries. */ static _WDIR *_wopendir(const wchar_t *dirname) { _WDIR *dirp = NULL; int error; /* Must have directory name */ if (dirname == NULL || dirname[0] == '\0') { dirent_set_errno(ENOENT); return NULL; } /* Allocate new _WDIR structure */ dirp = (_WDIR *)malloc(sizeof(struct _WDIR)); if (dirp != NULL) { DWORD n; /* Reset _WDIR structure */ dirp->handle = INVALID_HANDLE_VALUE; dirp->patt = NULL; dirp->cached = 0; /* Compute the length of full path plus zero terminator */ n = GetFullPathNameW(dirname, 0, NULL, NULL); /* Allocate room for absolute directory name and search pattern */ dirp->patt = (wchar_t *)malloc(sizeof(wchar_t) * n + 16); if (dirp->patt) { /* * Convert relative directory name to an absolute one. This * allows rewinddir() to function correctly even when current * working directory is changed between opendir() and rewinddir(). */ n = GetFullPathNameW(dirname, n, dirp->patt, NULL); if (n > 0) { wchar_t *p; /* Append search pattern \* to the directory name */ p = dirp->patt + n; if (dirp->patt < p) { switch (p[-1]) { case '\\': case '/': case ':': /* Directory ends in path separator, e.g. c:\temp\ */ /*NOP*/; break; default: /* Directory name doesn't end in path separator */ *p++ = '\\'; } } *p++ = '*'; *p = '\0'; /* Open directory stream and retrieve the first entry */ if (dirent_first(dirp)) { /* Directory stream opened successfully */ error = 0; } else { /* Cannot retrieve first entry */ error = 1; dirent_set_errno(ENOENT); } } else { /* Cannot retrieve full path name */ dirent_set_errno(ENOENT); error = 1; } } else { /* Cannot allocate memory for search pattern */ error = 1; } } else { /* Cannot allocate _WDIR structure */ error = 1; } /* Clean up in case of error */ if (error && dirp) { _wclosedir(dirp); dirp = NULL; } return dirp; } /* * Read next directory entry. The directory entry is returned in dirent * structure in the d_name field. Individual directory entries returned by * this function include regular files, sub-directories, pseudo-directories * "." and ".." as well as volume labels, hidden files and system files. */ static struct _wdirent *_wreaddir(_WDIR *dirp) { WIN32_FIND_DATAW *datap; struct _wdirent * entp; /* Read next directory entry */ datap = dirent_next(dirp); if (datap) { size_t n; DWORD attr; /* Pointer to directory entry to return */ entp = &dirp->ent; /* * Copy file name as wide-character string. If the file name is too * long to fit in to the destination buffer, then truncate file name * to PATH_MAX characters and zero-terminate the buffer. */ n = 0; while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) { entp->d_name[n] = datap->cFileName[n]; n++; } dirp->ent.d_name[n] = 0; /* Length of file name excluding zero terminator */ entp->d_namlen = n; /* File type */ attr = datap->dwFileAttributes; if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { entp->d_type = DT_CHR; } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { entp->d_type = DT_DIR; } else { entp->d_type = DT_REG; } /* Reset dummy fields */ entp->d_ino = 0; entp->d_reclen = sizeof(struct _wdirent); } else { /* Last directory entry read */ entp = NULL; } return entp; } /* * Close directory stream opened by opendir() function. This invalidates the * DIR structure as well as any directory entry read previously by * _wreaddir(). */ static int _wclosedir(_WDIR *dirp) { int ok; if (dirp) { /* Release search handle */ if (dirp->handle != INVALID_HANDLE_VALUE) { FindClose(dirp->handle); dirp->handle = INVALID_HANDLE_VALUE; } /* Release search pattern */ if (dirp->patt) { free(dirp->patt); dirp->patt = NULL; } /* Release directory structure */ free(dirp); ok = /*success*/ 0; } else { /* Invalid directory stream */ dirent_set_errno(EBADF); ok = /*failure*/ -1; } return ok; } /* * Rewind directory stream such that _wreaddir() returns the very first * file name again. */ static void _wrewinddir(_WDIR *dirp) { if (dirp) { /* Release existing search handle */ if (dirp->handle != INVALID_HANDLE_VALUE) { FindClose(dirp->handle); } /* Open new search handle */ dirent_first(dirp); } } /* Get first directory entry (internal) */ static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp) { WIN32_FIND_DATAW *datap; /* Open directory and retrieve the first entry */ dirp->handle = FindFirstFileW(dirp->patt, &dirp->data); if (dirp->handle != INVALID_HANDLE_VALUE) { /* a directory entry is now waiting in memory */ datap = &dirp->data; dirp->cached = 1; } else { /* Failed to re-open directory: no directory entry in memory */ dirp->cached = 0; datap = NULL; } return datap; } /* Get next directory entry (internal) */ static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp) { WIN32_FIND_DATAW *p; /* Get next directory entry */ if (dirp->cached != 0) { /* A valid directory entry already in memory */ p = &dirp->data; dirp->cached = 0; } else if (dirp->handle != INVALID_HANDLE_VALUE) { /* Get the next directory entry from stream */ if (FindNextFileW(dirp->handle, &dirp->data) != FALSE) { /* Got a file */ p = &dirp->data; } else { /* The very last entry has been processed or an error occured */ FindClose(dirp->handle); dirp->handle = INVALID_HANDLE_VALUE; p = NULL; } } else { /* End of directory stream reached */ p = NULL; } return p; } /* * Open directory stream using plain old C-string. */ static DIR *opendir(const char *dirname) { struct DIR *dirp; int error; /* Must have directory name */ if (dirname == NULL || dirname[0] == '\0') { dirent_set_errno(ENOENT); return NULL; } /* Allocate memory for DIR structure */ dirp = (DIR *)malloc(sizeof(struct DIR)); if (dirp) { wchar_t wname[PATH_MAX]; size_t n; /* Convert directory name to wide-character string */ error = dirent_mbstowcs_s(&n, wname, PATH_MAX, dirname, PATH_MAX); if (!error) { /* Open directory stream using wide-character name */ dirp->wdirp = _wopendir(wname); if (dirp->wdirp) { /* Directory stream opened */ error = 0; } else { /* Failed to open directory stream */ error = 1; } } else { /* * Cannot convert file name to wide-character string. This * occurs if the string contains invalid multi-byte sequences or * the output buffer is too small to contain the resulting * string. */ error = 1; } } else { /* Cannot allocate DIR structure */ error = 1; } /* Clean up in case of error */ if (error && dirp) { free(dirp); dirp = NULL; } return dirp; } /* * Read next directory entry. * * When working with text consoles, please note that file names returned by * readdir() are represented in the default ANSI code page while any output to * console is typically formatted on another code page. Thus, non-ASCII * characters in file names will not usually display correctly on console. The * problem can be fixed in two ways: (1) change the character set of console * to 1252 using chcp utility and use Lucida Console font, or (2) use * _cprintf function when writing to console. The _cprinf() will re-encode * ANSI strings to the console code page so many non-ASCII characters will * display correcly. */ static struct dirent *readdir(DIR *dirp) { WIN32_FIND_DATAW *datap; struct dirent * entp; /* Read next directory entry */ datap = dirent_next(dirp->wdirp); if (datap) { size_t n; int error; /* Attempt to convert file name to multi-byte string */ error = dirent_wcstombs_s(&n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX); /* * If the file name cannot be represented by a multi-byte string, * then attempt to use old 8+3 file name. This allows traditional * Unix-code to access some file names despite of unicode * characters, although file names may seem unfamiliar to the user. * * Be ware that the code below cannot come up with a short file * name unless the file system provides one. At least * VirtualBox shared folders fail to do this. */ if (error && datap->cAlternateFileName[0] != '\0') { error = dirent_wcstombs_s(&n, dirp->ent.d_name, PATH_MAX, datap->cAlternateFileName, PATH_MAX); } if (!error) { DWORD attr; /* Initialize directory entry for return */ entp = &dirp->ent; /* Length of file name excluding zero terminator */ entp->d_namlen = n - 1; /* File attributes */ attr = datap->dwFileAttributes; if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { entp->d_type = DT_CHR; } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { entp->d_type = DT_DIR; } else { entp->d_type = DT_REG; } /* Reset dummy fields */ entp->d_ino = 0; entp->d_reclen = sizeof(struct dirent); } else { /* * Cannot convert file name to multi-byte string so construct * an errornous directory entry and return that. Note that * we cannot return NULL as that would stop the processing * of directory entries completely. */ entp = &dirp->ent; entp->d_name[0] = '?'; entp->d_name[1] = '\0'; entp->d_namlen = 1; entp->d_type = DT_UNKNOWN; entp->d_ino = 0; entp->d_reclen = 0; } } else { /* No more directory entries */ entp = NULL; } return entp; } /* * Close directory stream. */ static int closedir(DIR *dirp) { int ok; if (dirp) { /* Close wide-character directory stream */ ok = _wclosedir(dirp->wdirp); dirp->wdirp = NULL; /* Release multi-byte character version */ free(dirp); } else { /* Invalid directory stream */ dirent_set_errno(EBADF); ok = /*failure*/ -1; } return ok; } /* * Rewind directory stream to beginning. */ static void rewinddir(DIR *dirp) { /* Rewind wide-character string directory stream */ _wrewinddir(dirp->wdirp); } /* Convert multi-byte string to wide character string */ static int dirent_mbstowcs_s(size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords, const char *mbstr, size_t count) { int error; #if defined(_MSC_VER) && _MSC_VER >= 1400 /* Microsoft Visual Studio 2005 or later */ error = mbstowcs_s(pReturnValue, wcstr, sizeInWords, mbstr, count); #else /* Older Visual Studio or non-Microsoft compiler */ size_t n; /* Convert to wide-character string (or count characters) */ n = mbstowcs(wcstr, mbstr, sizeInWords); if (!wcstr || n < count) { /* Zero-terminate output buffer */ if (wcstr && sizeInWords) { if (n >= sizeInWords) { n = sizeInWords - 1; } wcstr[n] = 0; } /* Length of resuting multi-byte string WITH zero terminator */ if (pReturnValue) { *pReturnValue = n + 1; } /* Success */ error = 0; } else { /* Could not convert string */ error = 1; } #endif return error; } /* Convert wide-character string to multi-byte string */ static int dirent_wcstombs_s(size_t *pReturnValue, char *mbstr, size_t sizeInBytes, /* max size of mbstr */ const wchar_t *wcstr, size_t count) { int error; #if defined(_MSC_VER) && _MSC_VER >= 1400 /* Microsoft Visual Studio 2005 or later */ error = wcstombs_s(pReturnValue, mbstr, sizeInBytes, wcstr, count); #else /* Older Visual Studio or non-Microsoft compiler */ size_t n; /* Convert to multi-byte string (or count the number of bytes needed) */ n = wcstombs(mbstr, wcstr, sizeInBytes); if (!mbstr || n < count) { /* Zero-terminate output buffer */ if (mbstr && sizeInBytes) { if (n >= sizeInBytes) { n = sizeInBytes - 1; } mbstr[n] = '\0'; } /* Lenght of resulting multi-bytes string WITH zero-terminator */ if (pReturnValue) { *pReturnValue = n + 1; } /* Success */ error = 0; } else { /* Cannot convert string */ error = 1; } #endif return error; } /* Set errno variable */ static void dirent_set_errno(int error) { #if defined(_MSC_VER) && _MSC_VER >= 1400 /* Microsoft Visual Studio 2005 and later */ _set_errno(error); #else /* Non-Microsoft compiler or older Microsoft compiler */ errno = error; #endif } #ifdef __cplusplus } #endif #endif /*DIRENT_H*/ ================================================ FILE: include/vapor/errorcodes.h ================================================ //-- errorcodes.h ------------------------------------------------------------ // // Copyright (C) 2004 // University Corporation for Atmospheric Research // All Rights Reserved // //---------------------------------------------------------------------------- // // File: errorcodes.h // // Author: Kenny Gruchalla // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: August 2006 // // Description: VAPoR error codes used for message reporting. // // The high-order bits of the codes are bit masked // providing type information: diagonstic, warning, error, // and fatal. // // For example, if (code & VAPoR::WARNING) then 'code' // is a warning type. // //---------------------------------------------------------------------------- namespace VAPoR { enum errorcodes { // VDF Errors: 0x1 - 0xFF: Handled specially: // The Vaporgui application will not clear // error codes less than 0xfff, until the // error is later detected in the application. // Any errors discovered in the application // must be set with an error code > 0xfff, or // the error will cause methods // in the VDF library to fail. VAPOR_ERROR_VDF = 0x1, VAPOR_ERROR_XML = 0x2, // Diagnostic Codes 0x1001 - 0x1FFF // Currently, diagnostic codes are not used VAPOR_DIAGNOSTIC = 0x1000, // Warning Codes 0x2001 - 0x2FFF VAPOR_WARNING = 0x2000, VAPOR_WARNING_GL_SHADER_LOG = 0x2001, VAPOR_WARNING_FLOW = 0x2100, VAPOR_WARNING_SEEDS = 0x2101, VAPOR_WARNING_FLOW_DATA = 0x2102, VAPOR_WARNING_FLOW_STOP = 0x2103, VAPOR_WARNING_DATA_UNAVAILABLE = 0x2004, VAPOR_WARNING_GL_ERROR = 0x2105, VAPOR_WARNING_TWO_D = 0x2106, // Error Codes 0x4001 - 0x4FFF VAPOR_ERROR = 0x4000, VAPOR_ERROR_GL_RENDERING = 0x4001, VAPOR_ERROR_GL_UNKNOWN_UNIFORM = 0x4002, VAPOR_ERROR_DATA_UNAVAILABLE = 0x4003, VAPOR_ERROR_DATA_TOO_BIG = 0x4004, VAPOR_ERROR_DRIVER_FAILURE = 0x4005, VAPOR_ERROR_GL_VENDOR = 0x4006, VAPOR_ERROR_DVR = 0x4007, VAPOR_ERROR_IMAGE_CAPTURE = 0x4008, VAPOR_ERROR_SPHERICAL = 0x4009, VAPOR_ERROR_STRETCHED = 0x4010, VAPOR_ERROR_PARAMS = 0x4011, VAPOR_ERROR_TWO_D = 0x4012, VAPOR_ERROR_GEOREFERENCE = 0x4013, VAPOR_ERROR_SCRIPTING = 0x4014, VAPOR_ERROR_PARSING = 0x4015, VAPOR_ERROR_VDC_MERGE = 0x4016, VAPOR_ERROR_GL_SHADER = 0x4017, // Flow errors VAPOR_ERROR_FLOW = 0x4100, VAPOR_ERROR_SEEDS = 0x4101, VAPOR_ERROR_INTEGRATION = 0x4102, VAPOR_ERROR_FLOW_DATA = 0x4103, VAPOR_ERROR_FLOW_SAVE = 0x4104, // Fatal Codes 0x8001 - 0x8FFF VAPOR_FATAL = 0x8000 }; }; ================================================ FILE: include/vapor/glutil.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: glutil.h // // Adaptor: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: July 2004 // // Description: Methods to facilitate use of trackball navigation, // adapted from Ken Purcell's code to work in QT window // // Copyright (C) 1992 AHPCRC, Univeristy of Minnesota // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program in a file named 'Copying'; if not, write to // the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139. // // Original Author: // Ken Chin-Purcell (ken@ahpcrc.umn.edu) // Army High Performance Computing Research Center (AHPCRC) // Univeristy of Minnesota // #ifndef _glutil_h_ #define _glutil_h_ #ifdef __APPLE__ #define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED #endif #include #include #include #include #include /* These vector and quaternion macros complement similar * routines. */ #ifdef ArchLinux #define sqrtf(fval) ((float)sqrt((double)(fval))) #define fabsf(fval) ((float)fabs((double)(fval))) #define sinf(fval) ((float)sin((double)(fval))) #define cosf(fval) ((float)cos((double)(fval))) #define tanf(fval) ((float)tan((double)(fval))) #endif //#define vset(a,x,y,z) (a[0] = x, a[1] = y, a[2] = z) //#define Verify(expr,estr) if (!(expr)) BailOut(estr,__FILE__,__LINE__) #define CallocType(type, i) (type *)calloc(i, sizeof(type)) #define YMAXSTEREO 491 #define YOFFSET 532 #ifndef M_PI #define M_PI 3.14159265358979323846 #endif /*extern GLfloat *idmatrix;*/ namespace VAPoR { /* glutil.c */ RENDER_API int __CheckGLError(const char *file, int line, const char *msg = 0); //! Check for any OpenGL errors and return their error codes //! //! This function calls glGetError() to test for any OpenGL errors. //! If no errors are detected the function returns \b true. If one //! or more errors are detected the function returns false and stores //! each of the error codes in the \p status vector // RENDER_API bool oglStatusOK(std::vector &status); RENDER_API void doubleToString(const double val, std::string &result, int digits); //! Decode OpenGL error codes and format them as a string //! //! This function takes a vector of error codes (see oglStatusOK) and //! produces a formatted error string from the list of codes // RENDER_API std::string oglGetErrMsg(std::vector status); //! Returns free RAM in kilobytes //! Returns -1 if not supported RENDER_API int oglGetFreeMemory(); //! Test readyness of OpenGL frame buffer, GL_FRAMEBUFFER //! RENDER_API bool FrameBufferReady(); }; // namespace VAPoR #define CheckGLError() __CheckGLError(__FILE__, __LINE__) #define CheckGLErrorMsg(msg) __CheckGLError(__FILE__, __LINE__, msg) #ifndef NDEBUG #ifdef Darwin #define GL_LEGACY(x) \ { \ } #else #define GL_LEGACY(x) x #endif #include #define GL_ERR_BREAK() \ if (CheckGLError()) ::raise(SIGINT) #else #define GL_LEGACY(x) #define GL_ERR_BREAK() #endif #endif // _glutil_h_ ================================================ FILE: include/vapor/jpegapi.h ================================================ #ifndef JPEGAPI_H #define JPEGAPI_H /* * This header defines the external api to the jpeg library. */ #include namespace VAPoR { RENDER_API int write_JPEG_file(FILE *file, int image_width, int image_height, unsigned char *image_buffer, int quality); RENDER_API int read_JPEG_file(const char *filename, unsigned char **imageBuffer, int *width, int *height); //(void) free_image(unsigned char* imageData); }; // namespace VAPoR #endif // JPEGAPI_H ================================================ FILE: include/vapor/nanoflann.hpp ================================================ /*********************************************************************** * Software License Agreement (BSD License) * * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. * Copyright 2011-2016 Jose Luis Blanco (joseluisblancoc@gmail.com). * All rights reserved. * * THE BSD LICENSE * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************************/ /** \mainpage nanoflann C++ API documentation * nanoflann is a C++ header-only library for building KD-Trees, mostly * optimized for 2D or 3D point clouds. * * nanoflann does not require compiling or installing, just an * #include in your code. * * See: * -
C++ API organized by modules * - Online README * - Doxygen documentation */ #ifndef NANOFLANN_HPP_ #define NANOFLANN_HPP_ #include #include #include #include #include // for fwrite() #define _USE_MATH_DEFINES // Required by MSVC to define M_PI,etc. in #include // for abs() #include // for abs() #include // Avoid conflicting declaration of min/max macros in windows headers #if !defined(NOMINMAX) && (defined(_WIN32) || defined(_WIN32_) || defined(WIN32) || defined(_WIN64)) #define NOMINMAX #ifdef max #undef max #undef min #endif #endif namespace nanoflann { /** @addtogroup nanoflann_grp nanoflann C++ library for ANN * @{ */ /** Library version: 0xMmP (M=Major,m=minor,P=patch) */ #define NANOFLANN_VERSION 0x123 /** @addtogroup result_sets_grp Result set classes * @{ */ template class KNNResultSet { IndexType * indices; DistanceType *dists; CountType capacity; CountType count; public: inline KNNResultSet(CountType capacity_) : indices(0), dists(0), capacity(capacity_), count(0) {} inline void init(IndexType *indices_, DistanceType *dists_) { indices = indices_; dists = dists_; count = 0; if (capacity) dists[capacity - 1] = (std::numeric_limits::max)(); } inline CountType size() const { return count; } inline bool full() const { return count == capacity; } /** * Called during search to add an element matching the criteria. * @return true if the search should be continued, false if the results are sufficient */ inline bool addPoint(DistanceType dist, IndexType index) { CountType i; for (i = count; i > 0; --i) { #ifdef NANOFLANN_FIRST_MATCH // If defined and two points have the same distance, the one with the lowest-index will be returned first. if ((dists[i - 1] > dist) || ((dist == dists[i - 1]) && (indices[i - 1] > index))) { #else if (dists[i - 1] > dist) { #endif if (i < capacity) { dists[i] = dists[i - 1]; indices[i] = indices[i - 1]; } } else break; } if (i < capacity) { dists[i] = dist; indices[i] = index; } if (count < capacity) count++; // tell caller that the search shall continue return true; } inline DistanceType worstDist() const { return dists[capacity - 1]; } }; // namespace nanoflann /** operator "<" for std::sort() */ struct IndexDist_Sorter { /** PairType will be typically: std::pair */ template inline bool operator()(const PairType &p1, const PairType &p2) const { return p1.second < p2.second; } }; /** * A result-set class used when performing a radius based search. */ template class RadiusResultSet { public: const DistanceType radius; std::vector> &m_indices_dists; inline RadiusResultSet(DistanceType radius_, std::vector> &indices_dists) : radius(radius_), m_indices_dists(indices_dists) { init(); } inline void init() { clear(); } inline void clear() { m_indices_dists.clear(); } inline size_t size() const { return m_indices_dists.size(); } inline bool full() const { return true; } /** * Called during search to add an element matching the criteria. * @return true if the search should be continued, false if the results are sufficient */ inline bool addPoint(DistanceType dist, IndexType index) { if (dist < radius) m_indices_dists.push_back(std::make_pair(index, dist)); return true; } inline DistanceType worstDist() const { return radius; } /** * Find the worst result (furtherest neighbor) without copying or sorting * Pre-conditions: size() > 0 */ std::pair worst_item() const { if (m_indices_dists.empty()) throw std::runtime_error("Cannot invoke RadiusResultSet::worst_item() on an empty list of results."); typedef typename std::vector>::const_iterator DistIt; DistIt it = std::max_element(m_indices_dists.begin(), m_indices_dists.end(), IndexDist_Sorter()); return *it; } }; /** @} */ /** @addtogroup loadsave_grp Load/save auxiliary functions * @{ */ template void save_value(FILE *stream, const T &value, size_t count = 1) { fwrite(&value, sizeof(value), count, stream); } template void save_value(FILE *stream, const std::vector &value) { size_t size = value.size(); fwrite(&size, sizeof(size_t), 1, stream); fwrite(&value[0], sizeof(T), size, stream); } template void load_value(FILE *stream, T &value, size_t count = 1) { size_t read_cnt = fread(&value, sizeof(value), count, stream); if (read_cnt != count) { throw std::runtime_error("Cannot read from file"); } } template void load_value(FILE *stream, std::vector &value) { size_t size; size_t read_cnt = fread(&size, sizeof(size_t), 1, stream); if (read_cnt != 1) { throw std::runtime_error("Cannot read from file"); } value.resize(size); read_cnt = fread(&value[0], sizeof(T), size, stream); if (read_cnt != size) { throw std::runtime_error("Cannot read from file"); } } /** @} */ /** @addtogroup metric_grp Metric (distance) classes * @{ */ struct Metric { }; /** Manhattan distance functor (generic version, optimized for high-dimensionality data sets). * Corresponding distance traits: nanoflann::metric_L1 * \tparam T Type of the elements (e.g. double, float, uint8_t) * \tparam _DistanceType Type of distance variables (must be signed) (e.g. float, double, int64_t) */ template struct L1_Adaptor { typedef T ElementType; typedef _DistanceType DistanceType; const DataSource &data_source; L1_Adaptor(const DataSource &_data_source) : data_source(_data_source) {} inline DistanceType evalMetric(const T *a, const size_t b_idx, size_t size, DistanceType worst_dist = -1) const { DistanceType result = DistanceType(); const T * last = a + size; const T * lastgroup = last - 3; size_t d = 0; /* Process 4 items with each loop for efficiency. */ while (a < lastgroup) { const DistanceType diff0 = std::abs(a[0] - data_source.kdtree_get_pt(b_idx, d++)); const DistanceType diff1 = std::abs(a[1] - data_source.kdtree_get_pt(b_idx, d++)); const DistanceType diff2 = std::abs(a[2] - data_source.kdtree_get_pt(b_idx, d++)); const DistanceType diff3 = std::abs(a[3] - data_source.kdtree_get_pt(b_idx, d++)); result += diff0 + diff1 + diff2 + diff3; a += 4; if ((worst_dist > 0) && (result > worst_dist)) { return result; } } /* Process last 0-3 components. Not needed for standard vector lengths. */ while (a < last) { result += std::abs(*a++ - data_source.kdtree_get_pt(b_idx, d++)); } return result; } template inline DistanceType accum_dist(const U a, const V b, int) const { return std::abs(a - b); } }; /** Squared Euclidean distance functor (generic version, optimized for high-dimensionality data sets). * Corresponding distance traits: nanoflann::metric_L2 * \tparam T Type of the elements (e.g. double, float, uint8_t) * \tparam _DistanceType Type of distance variables (must be signed) (e.g. float, double, int64_t) */ template struct L2_Adaptor { typedef T ElementType; typedef _DistanceType DistanceType; const DataSource &data_source; L2_Adaptor(const DataSource &_data_source) : data_source(_data_source) {} inline DistanceType evalMetric(const T *a, const size_t b_idx, size_t size, DistanceType worst_dist = -1) const { DistanceType result = DistanceType(); const T * last = a + size; const T * lastgroup = last - 3; size_t d = 0; /* Process 4 items with each loop for efficiency. */ while (a < lastgroup) { const DistanceType diff0 = a[0] - data_source.kdtree_get_pt(b_idx, d++); const DistanceType diff1 = a[1] - data_source.kdtree_get_pt(b_idx, d++); const DistanceType diff2 = a[2] - data_source.kdtree_get_pt(b_idx, d++); const DistanceType diff3 = a[3] - data_source.kdtree_get_pt(b_idx, d++); result += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3; a += 4; if ((worst_dist > 0) && (result > worst_dist)) { return result; } } /* Process last 0-3 components. Not needed for standard vector lengths. */ while (a < last) { const DistanceType diff0 = *a++ - data_source.kdtree_get_pt(b_idx, d++); result += diff0 * diff0; } return result; } template inline DistanceType accum_dist(const U a, const V b, int) const { return (a - b) * (a - b); } }; /** Squared Euclidean (L2) distance functor (suitable for low-dimensionality datasets, like 2D or 3D point clouds) * Corresponding distance traits: nanoflann::metric_L2_Simple * \tparam T Type of the elements (e.g. double, float, uint8_t) * \tparam _DistanceType Type of distance variables (must be signed) (e.g. float, double, int64_t) */ template struct L2_Simple_Adaptor { typedef T ElementType; typedef _DistanceType DistanceType; const DataSource &data_source; L2_Simple_Adaptor(const DataSource &_data_source) : data_source(_data_source) {} inline DistanceType evalMetric(const T *a, const size_t b_idx, size_t size) const { DistanceType result = DistanceType(); for (size_t i = 0; i < size; ++i) { const DistanceType diff = a[i] - data_source.kdtree_get_pt(b_idx, i); result += diff * diff; } return result; } template inline DistanceType accum_dist(const U a, const V b, int) const { return (a - b) * (a - b); } }; /** SO2 distance functor * Corresponding distance traits: nanoflann::metric_SO2 * \tparam T Type of the elements (e.g. double, float) * \tparam _DistanceType Type of distance variables (must be signed) (e.g. float, double) * orientation is constrained to be in [-pi, pi] */ template struct SO2_Adaptor { typedef T ElementType; typedef _DistanceType DistanceType; const DataSource &data_source; SO2_Adaptor(const DataSource &_data_source) : data_source(_data_source) {} inline DistanceType evalMetric(const T *a, const size_t b_idx, size_t size) const { return accum_dist(a[size - 1], data_source.kdtree_get_pt(b_idx, size - 1), size - 1); } template inline DistanceType accum_dist(const U a, const V b, int) const { DistanceType result = DistanceType(); result = b - a; if (result > M_PI) result -= 2. * M_PI; else if (result < -M_PI) result += 2. * M_PI; return result; } }; /** SO3 distance functor (Uses L2_Simple) * Corresponding distance traits: nanoflann::metric_SO3 * \tparam T Type of the elements (e.g. double, float) * \tparam _DistanceType Type of distance variables (must be signed) (e.g. float, double) */ template struct SO3_Adaptor { typedef T ElementType; typedef _DistanceType DistanceType; L2_Simple_Adaptor distance_L2_Simple; SO3_Adaptor(const DataSource &_data_source) : distance_L2_Simple(_data_source) {} inline DistanceType evalMetric(const T *a, const size_t b_idx, size_t size) const { return distance_L2_Simple.evalMetric(a, b_idx, size); } template inline DistanceType accum_dist(const U a, const V b, int idx) const { return distance_L2_Simple.accum_dist(a, b, idx); } }; /** Metaprogramming helper traits class for the L1 (Manhattan) metric */ struct metric_L1 : public Metric { template struct traits { typedef L1_Adaptor distance_t; }; }; /** Metaprogramming helper traits class for the L2 (Euclidean) metric */ struct metric_L2 : public Metric { template struct traits { typedef L2_Adaptor distance_t; }; }; /** Metaprogramming helper traits class for the L2_simple (Euclidean) metric */ struct metric_L2_Simple : public Metric { template struct traits { typedef L2_Simple_Adaptor distance_t; }; }; /** Metaprogramming helper traits class for the SO3_InnerProdQuat metric */ struct metric_SO2 : public Metric { template struct traits { typedef SO2_Adaptor distance_t; }; }; /** Metaprogramming helper traits class for the SO3_InnerProdQuat metric */ struct metric_SO3 : public Metric { template struct traits { typedef SO3_Adaptor distance_t; }; }; /** @} */ /** @addtogroup param_grp Parameter structs * @{ */ /** Parameters (see README.md) */ struct KDTreeSingleIndexAdaptorParams { KDTreeSingleIndexAdaptorParams(size_t _leaf_max_size = 10) : leaf_max_size(_leaf_max_size) {} size_t leaf_max_size; }; /** Search options for KDTreeSingleIndexAdaptor::findNeighbors() */ struct SearchParams { /** Note: The first argument (checks_IGNORED_) is ignored, but kept for compatibility with the FLANN interface */ SearchParams(int checks_IGNORED_ = 32, float eps_ = 0, bool sorted_ = true) : checks(checks_IGNORED_), eps(eps_), sorted(sorted_) {} int checks; //!< Ignored parameter (Kept for compatibility with the FLANN interface). float eps; //!< search for eps-approximate neighbours (default: 0) bool sorted; //!< only for radius search, require neighbours sorted by distance (default: true) }; /** @} */ /** @addtogroup memalloc_grp Memory allocation * @{ */ /** * Allocates (using C's malloc) a generic type T. * * Params: * count = number of instances to allocate. * Returns: pointer (of type T*) to memory buffer */ template inline T *allocate(size_t count = 1) { T *mem = static_cast(::malloc(sizeof(T) * count)); return mem; } /** * Pooled storage allocator * * The following routines allow for the efficient allocation of storage in * small chunks from a specified pool. Rather than allowing each structure * to be freed individually, an entire pool of storage is freed at once. * This method has two advantages over just using malloc() and free(). First, * it is far more efficient for allocating small objects, as there is * no overhead for remembering all the information needed to free each * object or consolidating fragmented memory. Second, the decision about * how long to keep an object is made at the time of allocation, and there * is no need to track down all the objects to free them. * */ const size_t WORDSIZE = 16; const size_t BLOCKSIZE = 8192; class PooledAllocator { /* We maintain memory alignment to word boundaries by requiring that all allocations be in multiples of the machine wordsize. */ /* Size of machine word in bytes. Must be power of 2. */ /* Minimum number of bytes requested at a time from the system. Must be multiple of WORDSIZE. */ size_t remaining; /* Number of bytes left in current block of storage. */ void * base; /* Pointer to base of current block of storage. */ void * loc; /* Current location in block to next allocate memory. */ void internal_init() { remaining = 0; base = NULL; usedMemory = 0; wastedMemory = 0; } public: size_t usedMemory; size_t wastedMemory; /** Default constructor. Initializes a new pool. */ PooledAllocator() { internal_init(); } /** * Destructor. Frees all the memory allocated in this pool. */ ~PooledAllocator() { free_all(); } /** Frees all allocated memory chunks */ void free_all() { while (base != NULL) { void *prev = *(static_cast(base)); /* Get pointer to prev block. */ ::free(base); base = prev; } internal_init(); } /** * Returns a pointer to a piece of new memory of the given size in bytes * allocated from the pool. */ void *malloc(const size_t req_size) { /* Round size up to a multiple of wordsize. The following expression only works for WORDSIZE that is a power of 2, by masking last bits of incremented size to zero. */ const size_t size = (req_size + (WORDSIZE - 1)) & ~(WORDSIZE - 1); /* Check whether a new block must be allocated. Note that the first word of a block is reserved for a pointer to the previous block. */ if (size > remaining) { wastedMemory += remaining; /* Allocate new storage. */ const size_t blocksize = (size + sizeof(void *) + (WORDSIZE - 1) > BLOCKSIZE) ? size + sizeof(void *) + (WORDSIZE - 1) : BLOCKSIZE; // use the standard C malloc to allocate memory void *m = ::malloc(blocksize); if (!m) { fprintf(stderr, "Failed to allocate memory.\n"); return NULL; } /* Fill first word of new block with pointer to previous block. */ static_cast(m)[0] = base; base = m; size_t shift = 0; // int size_t = (WORDSIZE - ( (((size_t)m) + sizeof(void*)) & (WORDSIZE-1))) & (WORDSIZE-1); remaining = blocksize - sizeof(void *) - shift; loc = (static_cast(m) + sizeof(void *) + shift); } void *rloc = loc; loc = static_cast(loc) + size; remaining -= size; usedMemory += size; return rloc; } /** * Allocates (using this pool) a generic type T. * * Params: * count = number of instances to allocate. * Returns: pointer (of type T*) to memory buffer */ template T *allocate(const size_t count = 1) { T *mem = static_cast(this->malloc(sizeof(T) * count)); return mem; } }; /** @} */ /** @addtogroup nanoflann_metaprog_grp Auxiliary metaprogramming stuff * @{ */ // ---------------- CArray ------------------------- /** A STL container (as wrapper) for arrays of constant size defined at compile time (class imported from the MRPT project) * This code is an adapted version from Boost, modifed for its integration * within MRPT (JLBC, Dec/2009) (Renamed array -> CArray to avoid possible potential conflicts). * See * http://www.josuttis.com/cppcode * for details and the latest version. * See * http://www.boost.org/libs/array for Documentation. * for documentation. * * (C) Copyright Nicolai M. Josuttis 2001. * Permission to copy, use, modify, sell and distribute this software * is granted provided this copyright notice appears in all copies. * This software is provided "as is" without express or implied * warranty, and with no claim as to its suitability for any purpose. * * 29 Jan 2004 - minor fixes (Nico Josuttis) * 04 Dec 2003 - update to synch with library TR1 (Alisdair Meredith) * 23 Aug 2002 - fix for Non-MSVC compilers combined with MSVC libraries. * 05 Aug 2001 - minor update (Nico Josuttis) * 20 Jan 2001 - STLport fix (Beman Dawes) * 29 Sep 2000 - Initial Revision (Nico Josuttis) * * Jan 30, 2004 */ template class CArray { public: T elems[N]; // fixed-size array of elements of type T public: // type definitions typedef T value_type; typedef T * iterator; typedef const T * const_iterator; typedef T & reference; typedef const T & const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; // iterator support inline iterator begin() { return elems; } inline const_iterator begin() const { return elems; } inline iterator end() { return elems + N; } inline const_iterator end() const { return elems + N; } // reverse iterator support #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS) typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; #elif defined(_MSC_VER) && (_MSC_VER == 1300) && defined(BOOST_DINKUMWARE_STDLIB) && (BOOST_DINKUMWARE_STDLIB == 310) // workaround for broken reverse_iterator in VC7 typedef std::reverse_iterator> reverse_iterator; typedef std::reverse_iterator> const_reverse_iterator; #else // workaround for broken reverse_iterator implementations typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; #endif reverse_iterator rbegin() { return reverse_iterator(end()); } const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } // operator[] inline reference operator[](size_type i) { return elems[i]; } inline const_reference operator[](size_type i) const { return elems[i]; } // at() with range check reference at(size_type i) { rangecheck(i); return elems[i]; } const_reference at(size_type i) const { rangecheck(i); return elems[i]; } // front() and back() reference front() { return elems[0]; } const_reference front() const { return elems[0]; } reference back() { return elems[N - 1]; } const_reference back() const { return elems[N - 1]; } // size is constant static inline size_type size() { return N; } static bool empty() { return false; } static size_type max_size() { return N; } enum { static_size = N }; /** This method has no effects in this class, but raises an exception if the expected size does not match */ inline void resize(const size_t nElements) { if (nElements != N) throw std::logic_error("Try to change the size of a CArray."); } // swap (note: linear complexity in N, constant for given instantiation) void swap(CArray &y) { std::swap_ranges(begin(), end(), y.begin()); } // direct access to data (read-only) const T *data() const { return elems; } // use array as C array (direct read/write access to data) T *data() { return elems; } // assignment with type conversion template CArray &operator=(const CArray &rhs) { std::copy(rhs.begin(), rhs.end(), begin()); return *this; } // assign one value to all elements inline void assign(const T &value) { for (size_t i = 0; i < N; i++) elems[i] = value; } // assign (compatible with std::vector's one) (by JLBC for MRPT) void assign(const size_t n, const T &value) { assert(N == n); for (size_t i = 0; i < N; i++) elems[i] = value; } private: // check range (may be private because it is static) static void rangecheck(size_type i) { if (i >= size()) { throw std::out_of_range("CArray<>: index out of range"); } } }; // end of CArray /** Used to declare fixed-size arrays when DIM>0, dynamically-allocated vectors when DIM=-1. * Fixed size version for a generic DIM: */ template struct array_or_vector_selector { typedef CArray container_t; }; /** Dynamic size version */ template struct array_or_vector_selector<-1, T> { typedef std::vector container_t; }; /** @} */ /** kd-tree base-class * * Contains the member functions common to the classes KDTreeSingleIndexAdaptor and KDTreeSingleIndexDynamicAdaptor_. * * \tparam Derived The name of the class which inherits this class. * \tparam DatasetAdaptor The user-provided adaptor (see comments above). * \tparam Distance The distance metric to use, these are all classes derived from nanoflann::Metric * \tparam DIM Dimensionality of data points (e.g. 3 for 3D points) * \tparam IndexType Will be typically size_t or int */ template class KDTreeBaseClass { public: /** Frees the previously-built index. Automatically called within buildIndex(). */ void freeIndex(Derived &obj) { obj.pool.free_all(); obj.root_node = NULL; obj.m_size_at_index_build = 0; } typedef typename Distance::ElementType ElementType; typedef typename Distance::DistanceType DistanceType; /*--------------------- Internal Data Structures --------------------------*/ struct Node { /** Union used because a node can be either a LEAF node or a non-leaf node, so both data fields are never used simultaneously */ union { struct leaf { IndexType left, right; //!< Indices of points in leaf node } lr; struct nonleaf { int divfeat; //!< Dimension used for subdivision. DistanceType divlow, divhigh; //!< The values used for subdivision. } sub; } node_type; Node *child1, *child2; //!< Child nodes (both=NULL mean its a leaf node) }; typedef Node *NodePtr; struct Interval { ElementType low, high; }; /** * Array of indices to vectors in the dataset. */ std::vector vind; NodePtr root_node; size_t m_leaf_max_size; size_t m_size; //!< Number of current points in the dataset size_t m_size_at_index_build; //!< Number of points in the dataset when the index was built int dim; //!< Dimensionality of each data point /** Define "BoundingBox" as a fixed-size or variable-size container depending on "DIM" */ typedef typename array_or_vector_selector::container_t BoundingBox; /** Define "distance_vector_t" as a fixed-size or variable-size container depending on "DIM" */ typedef typename array_or_vector_selector::container_t distance_vector_t; /** The KD-tree used to find neighbours */ BoundingBox root_bbox; /** * Pooled memory allocator. * * Using a pooled memory allocator is more efficient * than allocating memory directly when there is a large * number small of memory allocations. */ PooledAllocator pool; /** Returns number of points in dataset */ size_t size(const Derived &obj) const { return obj.m_size; } /** Returns the length of each point in the dataset */ size_t veclen(const Derived &obj) { return static_cast(DIM > 0 ? DIM : obj.dim); } /// Helper accessor to the dataset points: inline ElementType dataset_get(const Derived &obj, size_t idx, int component) const { return obj.dataset.kdtree_get_pt(idx, component); } /** * Computes the inde memory usage * Returns: memory used by the index */ size_t usedMemory(Derived &obj) { return obj.pool.usedMemory + obj.pool.wastedMemory + obj.dataset.kdtree_get_point_count() * sizeof(IndexType); // pool memory and vind array memory } void computeMinMax(const Derived &obj, IndexType *ind, IndexType count, int element, ElementType &min_elem, ElementType &max_elem) { min_elem = dataset_get(obj, ind[0], element); max_elem = dataset_get(obj, ind[0], element); for (IndexType i = 1; i < count; ++i) { ElementType val = dataset_get(obj, ind[i], element); if (val < min_elem) min_elem = val; if (val > max_elem) max_elem = val; } } /** * Create a tree node that subdivides the list of vecs from vind[first] * to vind[last]. The routine is called recursively on each sublist. * * @param left index of the first vector * @param right index of the last vector */ NodePtr divideTree(Derived &obj, const IndexType left, const IndexType right, BoundingBox &bbox) { NodePtr node = obj.pool.template allocate(); // allocate memory /* If too few exemplars remain, then make this a leaf node. */ if ((right - left) <= static_cast(obj.m_leaf_max_size)) { node->child1 = node->child2 = NULL; /* Mark as leaf node. */ node->node_type.lr.left = left; node->node_type.lr.right = right; // compute bounding-box of leaf points for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) { bbox[i].low = dataset_get(obj, obj.vind[left], i); bbox[i].high = dataset_get(obj, obj.vind[left], i); } for (IndexType k = left + 1; k < right; ++k) { for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) { if (bbox[i].low > dataset_get(obj, obj.vind[k], i)) bbox[i].low = dataset_get(obj, obj.vind[k], i); if (bbox[i].high < dataset_get(obj, obj.vind[k], i)) bbox[i].high = dataset_get(obj, obj.vind[k], i); } } } else { IndexType idx; int cutfeat; DistanceType cutval; middleSplit_(obj, &obj.vind[0] + left, right - left, idx, cutfeat, cutval, bbox); node->node_type.sub.divfeat = cutfeat; BoundingBox left_bbox(bbox); left_bbox[cutfeat].high = cutval; node->child1 = divideTree(obj, left, left + idx, left_bbox); BoundingBox right_bbox(bbox); right_bbox[cutfeat].low = cutval; node->child2 = divideTree(obj, left + idx, right, right_bbox); node->node_type.sub.divlow = left_bbox[cutfeat].high; node->node_type.sub.divhigh = right_bbox[cutfeat].low; for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) { bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low); bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high); } } return node; } void middleSplit_(Derived &obj, IndexType *ind, IndexType count, IndexType &index, int &cutfeat, DistanceType &cutval, const BoundingBox &bbox) { const DistanceType EPS = static_cast(0.00001); ElementType max_span = bbox[0].high - bbox[0].low; for (int i = 1; i < (DIM > 0 ? DIM : obj.dim); ++i) { ElementType span = bbox[i].high - bbox[i].low; if (span > max_span) { max_span = span; } } ElementType max_spread = -1; cutfeat = 0; for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) { ElementType span = bbox[i].high - bbox[i].low; if (span > (1 - EPS) * max_span) { ElementType min_elem, max_elem; computeMinMax(obj, ind, count, i, min_elem, max_elem); ElementType spread = max_elem - min_elem; ; if (spread > max_spread) { cutfeat = i; max_spread = spread; } } } // split in the middle DistanceType split_val = (bbox[cutfeat].low + bbox[cutfeat].high) / 2; ElementType min_elem, max_elem; computeMinMax(obj, ind, count, cutfeat, min_elem, max_elem); if (split_val < min_elem) cutval = min_elem; else if (split_val > max_elem) cutval = max_elem; else cutval = split_val; IndexType lim1, lim2; planeSplit(obj, ind, count, cutfeat, cutval, lim1, lim2); if (lim1 > count / 2) index = lim1; else if (lim2 < count / 2) index = lim2; else index = count / 2; } /** * Subdivide the list of points by a plane perpendicular on axe corresponding * to the 'cutfeat' dimension at 'cutval' position. * * On return: * dataset[ind[0..lim1-1]][cutfeat]cutval */ void planeSplit(Derived &obj, IndexType *ind, const IndexType count, int cutfeat, DistanceType &cutval, IndexType &lim1, IndexType &lim2) { /* Move vector indices for left subtree to front of list. */ IndexType left = 0; IndexType right = count - 1; for (;;) { while (left <= right && dataset_get(obj, ind[left], cutfeat) < cutval) ++left; while (right && left <= right && dataset_get(obj, ind[right], cutfeat) >= cutval) --right; if (left > right || !right) break; // "!right" was added to support unsigned Index types std::swap(ind[left], ind[right]); ++left; --right; } /* If either list is empty, it means that all remaining features * are identical. Split in the middle to maintain a balanced tree. */ lim1 = left; right = count - 1; for (;;) { while (left <= right && dataset_get(obj, ind[left], cutfeat) <= cutval) ++left; while (right && left <= right && dataset_get(obj, ind[right], cutfeat) > cutval) --right; if (left > right || !right) break; // "!right" was added to support unsigned Index types std::swap(ind[left], ind[right]); ++left; --right; } lim2 = left; } DistanceType computeInitialDistances(const Derived &obj, const ElementType *vec, distance_vector_t &dists) const { assert(vec); DistanceType distsq = DistanceType(); for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) { if (vec[i] < obj.root_bbox[i].low) { dists[i] = obj.distance.accum_dist(vec[i], obj.root_bbox[i].low, i); distsq += dists[i]; } if (vec[i] > obj.root_bbox[i].high) { dists[i] = obj.distance.accum_dist(vec[i], obj.root_bbox[i].high, i); distsq += dists[i]; } } return distsq; } void save_tree(Derived &obj, FILE *stream, NodePtr tree) { save_value(stream, *tree); if (tree->child1 != NULL) { save_tree(obj, stream, tree->child1); } if (tree->child2 != NULL) { save_tree(obj, stream, tree->child2); } } void load_tree(Derived &obj, FILE *stream, NodePtr &tree) { tree = obj.pool.template allocate(); load_value(stream, *tree); if (tree->child1 != NULL) { load_tree(obj, stream, tree->child1); } if (tree->child2 != NULL) { load_tree(obj, stream, tree->child2); } } /** Stores the index in a binary file. * IMPORTANT NOTE: The set of data points is NOT stored in the file, so when loading the index object it must be constructed associated to the same source of data points used while building it. * See the example: examples/saveload_example.cpp * \sa loadIndex */ void saveIndex_(Derived &obj, FILE *stream) { save_value(stream, obj.m_size); save_value(stream, obj.dim); save_value(stream, obj.root_bbox); save_value(stream, obj.m_leaf_max_size); save_value(stream, obj.vind); save_tree(obj, stream, obj.root_node); } /** Loads a previous index from a binary file. * IMPORTANT NOTE: The set of data points is NOT stored in the file, so the index object must be constructed associated to the same source of data points used while building the index. * See the example: examples/saveload_example.cpp * \sa loadIndex */ void loadIndex_(Derived &obj, FILE *stream) { load_value(stream, obj.m_size); load_value(stream, obj.dim); load_value(stream, obj.root_bbox); load_value(stream, obj.m_leaf_max_size); load_value(stream, obj.vind); load_tree(obj, stream, obj.root_node); } }; /** @addtogroup kdtrees_grp KD-tree classes and adaptors * @{ */ /** kd-tree static index * * Contains the k-d trees and other information for indexing a set of points * for nearest-neighbor matching. * * The class "DatasetAdaptor" must provide the following interface (can be non-virtual, inlined methods): * * \code * // Must return the number of data poins * inline size_t kdtree_get_point_count() const { ... } * * * // Must return the dim'th component of the idx'th point in the class: * inline T kdtree_get_pt(const size_t idx, int dim) const { ... } * * // Optional bounding-box computation: return false to default to a standard bbox computation loop. * // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again. * // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds) * template * bool kdtree_get_bbox(BBOX &bb) const * { * bb[0].low = ...; bb[0].high = ...; // 0th dimension limits * bb[1].low = ...; bb[1].high = ...; // 1st dimension limits * ... * return true; * } * * \endcode * * \tparam DatasetAdaptor The user-provided adaptor (see comments above). * \tparam Distance The distance metric to use: nanoflann::metric_L1, nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. * \tparam DIM Dimensionality of data points (e.g. 3 for 3D points) * \tparam IndexType Will be typically size_t or int */ template class KDTreeSingleIndexAdaptor : public KDTreeBaseClass, Distance, DatasetAdaptor, DIM, IndexType> { public: /** Deleted copy constructor*/ KDTreeSingleIndexAdaptor(const KDTreeSingleIndexAdaptor &) = delete; /** * The dataset used by this index */ const DatasetAdaptor &dataset; //!< The source of our data const KDTreeSingleIndexAdaptorParams index_params; Distance distance; typedef typename nanoflann::KDTreeBaseClass, Distance, DatasetAdaptor, DIM, IndexType> BaseClassRef; typedef typename BaseClassRef::ElementType ElementType; typedef typename BaseClassRef::DistanceType DistanceType; typedef typename BaseClassRef::Node Node; typedef Node * NodePtr; typedef typename BaseClassRef::Interval Interval; /** Define "BoundingBox" as a fixed-size or variable-size container depending on "DIM" */ typedef typename BaseClassRef::BoundingBox BoundingBox; /** Define "distance_vector_t" as a fixed-size or variable-size container depending on "DIM" */ typedef typename BaseClassRef::distance_vector_t distance_vector_t; /** * KDTree constructor * * Refer to docs in README.md or online in https://github.com/jlblancoc/nanoflann * * The KD-Tree point dimension (the length of each point in the datase, e.g. 3 for 3D points) * is determined by means of: * - The \a DIM template parameter if >0 (highest priority) * - Otherwise, the \a dimensionality parameter of this constructor. * * @param inputData Dataset with the input features * @param params Basically, the maximum leaf node size */ KDTreeSingleIndexAdaptor(const int dimensionality, const DatasetAdaptor &inputData, const KDTreeSingleIndexAdaptorParams ¶ms = KDTreeSingleIndexAdaptorParams()) : dataset(inputData), index_params(params), distance(inputData) { BaseClassRef::root_node = NULL; BaseClassRef::m_size = dataset.kdtree_get_point_count(); BaseClassRef::m_size_at_index_build = BaseClassRef::m_size; BaseClassRef::dim = dimensionality; if (DIM > 0) BaseClassRef::dim = DIM; BaseClassRef::m_leaf_max_size = params.leaf_max_size; // Create a permutable array of indices to the input vectors. init_vind(); } /** * Builds the index */ void buildIndex() { BaseClassRef::m_size = dataset.kdtree_get_point_count(); BaseClassRef::m_size_at_index_build = BaseClassRef::m_size; init_vind(); this->freeIndex(*this); BaseClassRef::m_size_at_index_build = BaseClassRef::m_size; if (BaseClassRef::m_size == 0) return; computeBoundingBox(BaseClassRef::root_bbox); BaseClassRef::root_node = this->divideTree(*this, 0, BaseClassRef::m_size, BaseClassRef::root_bbox); // construct the tree } /** \name Query methods * @{ */ /** * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored inside * the result object. * * Params: * result = the result object in which the indices of the nearest-neighbors are stored * vec = the vector for which to search the nearest neighbors * * \tparam RESULTSET Should be any ResultSet * \return True if the requested neighbors could be found. * \sa knnSearch, radiusSearch */ template bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParams &searchParams) const { assert(vec); if (this->size(*this) == 0) return false; if (!BaseClassRef::root_node) throw std::runtime_error("[nanoflann] findNeighbors() called before building the index."); float epsError = 1 + searchParams.eps; distance_vector_t dists; // fixed or variable-sized container (depending on DIM) dists.assign((DIM > 0 ? DIM : BaseClassRef::dim), 0); // Fill it with zeros. DistanceType distsq = this->computeInitialDistances(*this, vec, dists); searchLevel(result, vec, BaseClassRef::root_node, distsq, dists, epsError); // "count_leaf" parameter removed since was neither used nor returned to the user. return result.full(); } /** * Find the "num_closest" nearest neighbors to the \a query_point[0:dim-1]. Their indices are stored inside * the result object. * \sa radiusSearch, findNeighbors * \note nChecks_IGNORED is ignored but kept for compatibility with the original FLANN interface. * \return Number `N` of valid points in the result set. Only the first `N` entries in `out_indices` and `out_distances_sq` will be valid. * Return may be less than `num_closest` only if the number of elements in the tree is less than `num_closest`. */ size_t knnSearch(const ElementType *query_point, const size_t num_closest, IndexType *out_indices, DistanceType *out_distances_sq, const int /* nChecks_IGNORED */ = 10) const { nanoflann::KNNResultSet resultSet(num_closest); resultSet.init(out_indices, out_distances_sq); this->findNeighbors(resultSet, query_point, nanoflann::SearchParams()); return resultSet.size(); } /** * Find all the neighbors to \a query_point[0:dim-1] within a maximum radius. * The output is given as a vector of pairs, of which the first element is a point index and the second the corresponding distance. * Previous contents of \a IndicesDists are cleared. * * If searchParams.sorted==true, the output list is sorted by ascending distances. * * For a better performance, it is advisable to do a .reserve() on the vector if you have any wild guess about the number of expected matches. * * \sa knnSearch, findNeighbors, radiusSearchCustomCallback * \return The number of points within the given radius (i.e. indices.size() or dists.size() ) */ size_t radiusSearch(const ElementType *query_point, const DistanceType &radius, std::vector> &IndicesDists, const SearchParams &searchParams) const { RadiusResultSet resultSet(radius, IndicesDists); const size_t nFound = radiusSearchCustomCallback(query_point, resultSet, searchParams); if (searchParams.sorted) std::sort(IndicesDists.begin(), IndicesDists.end(), IndexDist_Sorter()); return nFound; } /** * Just like radiusSearch() but with a custom callback class for each point found in the radius of the query. * See the source of RadiusResultSet<> as a start point for your own classes. * \sa radiusSearch */ template size_t radiusSearchCustomCallback(const ElementType *query_point, SEARCH_CALLBACK &resultSet, const SearchParams &searchParams = SearchParams()) const { this->findNeighbors(resultSet, query_point, searchParams); return resultSet.size(); } /** @} */ public: /** Make sure the auxiliary list \a vind has the same size than the current dataset, and re-generate if size has changed. */ void init_vind() { // Create a permutable array of indices to the input vectors. BaseClassRef::m_size = dataset.kdtree_get_point_count(); if (BaseClassRef::vind.size() != BaseClassRef::m_size) BaseClassRef::vind.resize(BaseClassRef::m_size); for (size_t i = 0; i < BaseClassRef::m_size; i++) BaseClassRef::vind[i] = i; } void computeBoundingBox(BoundingBox &bbox) { bbox.resize((DIM > 0 ? DIM : BaseClassRef::dim)); if (dataset.kdtree_get_bbox(bbox)) { // Done! It was implemented in derived class } else { const size_t N = dataset.kdtree_get_point_count(); if (!N) throw std::runtime_error("[nanoflann] computeBoundingBox() called but no data points found."); for (int i = 0; i < (DIM > 0 ? DIM : BaseClassRef::dim); ++i) { bbox[i].low = bbox[i].high = this->dataset_get(*this, 0, i); } for (size_t k = 1; k < N; ++k) { for (int i = 0; i < (DIM > 0 ? DIM : BaseClassRef::dim); ++i) { if (this->dataset_get(*this, k, i) < bbox[i].low) bbox[i].low = this->dataset_get(*this, k, i); if (this->dataset_get(*this, k, i) > bbox[i].high) bbox[i].high = this->dataset_get(*this, k, i); } } } } /** * Performs an exact search in the tree starting from a node. * \tparam RESULTSET Should be any ResultSet * \return true if the search should be continued, false if the results are sufficient */ template bool searchLevel(RESULTSET &result_set, const ElementType *vec, const NodePtr node, DistanceType mindistsq, distance_vector_t &dists, const float epsError) const { /* If this is a leaf node, then do check and return. */ if ((node->child1 == NULL) && (node->child2 == NULL)) { // count_leaf += (node->lr.right-node->lr.left); // Removed since was neither used nor returned to the user. DistanceType worst_dist = result_set.worstDist(); for (IndexType i = node->node_type.lr.left; i < node->node_type.lr.right; ++i) { const IndexType index = BaseClassRef::vind[i]; // reorder... : i; DistanceType dist = distance.evalMetric(vec, index, (DIM > 0 ? DIM : BaseClassRef::dim)); if (dist < worst_dist) { if (!result_set.addPoint(dist, BaseClassRef::vind[i])) { // the resultset doesn't want to receive any more points, we're done searching! return false; } } } return true; } /* Which child branch should be taken first? */ int idx = node->node_type.sub.divfeat; ElementType val = vec[idx]; DistanceType diff1 = val - node->node_type.sub.divlow; DistanceType diff2 = val - node->node_type.sub.divhigh; NodePtr bestChild; NodePtr otherChild; DistanceType cut_dist; if ((diff1 + diff2) < 0) { bestChild = node->child1; otherChild = node->child2; cut_dist = distance.accum_dist(val, node->node_type.sub.divhigh, idx); } else { bestChild = node->child2; otherChild = node->child1; cut_dist = distance.accum_dist(val, node->node_type.sub.divlow, idx); } /* Call recursively to search next level down. */ if (!searchLevel(result_set, vec, bestChild, mindistsq, dists, epsError)) { // the resultset doesn't want to receive any more points, we're done searching! return false; } DistanceType dst = dists[idx]; mindistsq = mindistsq + cut_dist - dst; dists[idx] = cut_dist; if (mindistsq * epsError <= result_set.worstDist()) { if (!searchLevel(result_set, vec, otherChild, mindistsq, dists, epsError)) { // the resultset doesn't want to receive any more points, we're done searching! return false; } } dists[idx] = dst; return true; } public: /** Stores the index in a binary file. * IMPORTANT NOTE: The set of data points is NOT stored in the file, so when loading the index object it must be constructed associated to the same source of data points used while building it. * See the example: examples/saveload_example.cpp * \sa loadIndex */ void saveIndex(FILE *stream) { this->saveIndex_(*this, stream); } /** Loads a previous index from a binary file. * IMPORTANT NOTE: The set of data points is NOT stored in the file, so the index object must be constructed associated to the same source of data points used while building the index. * See the example: examples/saveload_example.cpp * \sa loadIndex */ void loadIndex(FILE *stream) { this->loadIndex_(*this, stream); } }; // class KDTree /** kd-tree dynamic index * * Contains the k-d trees and other information for indexing a set of points * for nearest-neighbor matching. * * The class "DatasetAdaptor" must provide the following interface (can be non-virtual, inlined methods): * * \code * // Must return the number of data poins * inline size_t kdtree_get_point_count() const { ... } * * // Must return the dim'th component of the idx'th point in the class: * inline T kdtree_get_pt(const size_t idx, int dim) const { ... } * * // Optional bounding-box computation: return false to default to a standard bbox computation loop. * // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again. * // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds) * template * bool kdtree_get_bbox(BBOX &bb) const * { * bb[0].low = ...; bb[0].high = ...; // 0th dimension limits * bb[1].low = ...; bb[1].high = ...; // 1st dimension limits * ... * return true; * } * * \endcode * * \tparam DatasetAdaptor The user-provided adaptor (see comments above). * \tparam Distance The distance metric to use: nanoflann::metric_L1, nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. * \tparam DIM Dimensionality of data points (e.g. 3 for 3D points) * \tparam IndexType Will be typically size_t or int */ template class KDTreeSingleIndexDynamicAdaptor_ : public KDTreeBaseClass, Distance, DatasetAdaptor, DIM, IndexType> { public: /** * The dataset used by this index */ const DatasetAdaptor &dataset; //!< The source of our data KDTreeSingleIndexAdaptorParams index_params; std::vector &treeIndex; Distance distance; typedef typename nanoflann::KDTreeBaseClass, Distance, DatasetAdaptor, DIM, IndexType> BaseClassRef; typedef typename BaseClassRef::ElementType ElementType; typedef typename BaseClassRef::DistanceType DistanceType; typedef typename BaseClassRef::Node Node; typedef Node * NodePtr; typedef typename BaseClassRef::Interval Interval; /** Define "BoundingBox" as a fixed-size or variable-size container depending on "DIM" */ typedef typename BaseClassRef::BoundingBox BoundingBox; /** Define "distance_vector_t" as a fixed-size or variable-size container depending on "DIM" */ typedef typename BaseClassRef::distance_vector_t distance_vector_t; /** * KDTree constructor * * Refer to docs in README.md or online in https://github.com/jlblancoc/nanoflann * * The KD-Tree point dimension (the length of each point in the datase, e.g. 3 for 3D points) * is determined by means of: * - The \a DIM template parameter if >0 (highest priority) * - Otherwise, the \a dimensionality parameter of this constructor. * * @param inputData Dataset with the input features * @param params Basically, the maximum leaf node size */ KDTreeSingleIndexDynamicAdaptor_(const int dimensionality, const DatasetAdaptor &inputData, std::vector &treeIndex_, const KDTreeSingleIndexAdaptorParams ¶ms = KDTreeSingleIndexAdaptorParams()) : dataset(inputData), index_params(params), treeIndex(treeIndex_), distance(inputData) { BaseClassRef::root_node = NULL; BaseClassRef::m_size = 0; BaseClassRef::m_size_at_index_build = 0; BaseClassRef::dim = dimensionality; if (DIM > 0) BaseClassRef::dim = DIM; BaseClassRef::m_leaf_max_size = params.leaf_max_size; } /** Assignment operator definiton */ KDTreeSingleIndexDynamicAdaptor_ operator=(const KDTreeSingleIndexDynamicAdaptor_ &rhs) { KDTreeSingleIndexDynamicAdaptor_ tmp(rhs); std::swap(BaseClassRef::vind, tmp.BaseClassRef::vind); std::swap(BaseClassRef::m_leaf_max_size, tmp.BaseClassRef::m_leaf_max_size); std::swap(index_params, tmp.index_params); std::swap(treeIndex, tmp.treeIndex); std::swap(BaseClassRef::m_size, tmp.BaseClassRef::m_size); std::swap(BaseClassRef::m_size_at_index_build, tmp.BaseClassRef::m_size_at_index_build); std::swap(BaseClassRef::root_node, tmp.BaseClassRef::root_node); std::swap(BaseClassRef::root_bbox, tmp.BaseClassRef::root_bbox); std::swap(BaseClassRef::pool, tmp.BaseClassRef::pool); return *this; } /** * Builds the index */ void buildIndex() { BaseClassRef::m_size = BaseClassRef::vind.size(); this->freeIndex(*this); BaseClassRef::m_size_at_index_build = BaseClassRef::m_size; if (BaseClassRef::m_size == 0) return; computeBoundingBox(BaseClassRef::root_bbox); BaseClassRef::root_node = this->divideTree(*this, 0, BaseClassRef::m_size, BaseClassRef::root_bbox); // construct the tree } /** \name Query methods * @{ */ /** * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored inside * the result object. * * Params: * result = the result object in which the indices of the nearest-neighbors are stored * vec = the vector for which to search the nearest neighbors * * \tparam RESULTSET Should be any ResultSet * \return True if the requested neighbors could be found. * \sa knnSearch, radiusSearch */ template bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParams &searchParams) const { assert(vec); if (this->size(*this) == 0) return false; if (!BaseClassRef::root_node) return false; float epsError = 1 + searchParams.eps; distance_vector_t dists; // fixed or variable-sized container (depending on DIM) dists.assign((DIM > 0 ? DIM : BaseClassRef::dim), 0); // Fill it with zeros. DistanceType distsq = this->computeInitialDistances(*this, vec, dists); searchLevel(result, vec, BaseClassRef::root_node, distsq, dists, epsError); // "count_leaf" parameter removed since was neither used nor returned to the user. return result.full(); } /** * Find the "num_closest" nearest neighbors to the \a query_point[0:dim-1]. Their indices are stored inside * the result object. * \sa radiusSearch, findNeighbors * \note nChecks_IGNORED is ignored but kept for compatibility with the original FLANN interface. * \return Number `N` of valid points in the result set. Only the first `N` entries in `out_indices` and `out_distances_sq` will be valid. * Return may be less than `num_closest` only if the number of elements in the tree is less than `num_closest`. */ size_t knnSearch(const ElementType *query_point, const size_t num_closest, IndexType *out_indices, DistanceType *out_distances_sq, const int /* nChecks_IGNORED */ = 10) const { nanoflann::KNNResultSet resultSet(num_closest); resultSet.init(out_indices, out_distances_sq); this->findNeighbors(resultSet, query_point, nanoflann::SearchParams()); return resultSet.size(); } /** * Find all the neighbors to \a query_point[0:dim-1] within a maximum radius. * The output is given as a vector of pairs, of which the first element is a point index and the second the corresponding distance. * Previous contents of \a IndicesDists are cleared. * * If searchParams.sorted==true, the output list is sorted by ascending distances. * * For a better performance, it is advisable to do a .reserve() on the vector if you have any wild guess about the number of expected matches. * * \sa knnSearch, findNeighbors, radiusSearchCustomCallback * \return The number of points within the given radius (i.e. indices.size() or dists.size() ) */ size_t radiusSearch(const ElementType *query_point, const DistanceType &radius, std::vector> &IndicesDists, const SearchParams &searchParams) const { RadiusResultSet resultSet(radius, IndicesDists); const size_t nFound = radiusSearchCustomCallback(query_point, resultSet, searchParams); if (searchParams.sorted) std::sort(IndicesDists.begin(), IndicesDists.end(), IndexDist_Sorter()); return nFound; } /** * Just like radiusSearch() but with a custom callback class for each point found in the radius of the query. * See the source of RadiusResultSet<> as a start point for your own classes. * \sa radiusSearch */ template size_t radiusSearchCustomCallback(const ElementType *query_point, SEARCH_CALLBACK &resultSet, const SearchParams &searchParams = SearchParams()) const { this->findNeighbors(resultSet, query_point, searchParams); return resultSet.size(); } /** @} */ public: void computeBoundingBox(BoundingBox &bbox) { bbox.resize((DIM > 0 ? DIM : BaseClassRef::dim)); if (dataset.kdtree_get_bbox(bbox)) { // Done! It was implemented in derived class } else { const size_t N = BaseClassRef::m_size; if (!N) throw std::runtime_error("[nanoflann] computeBoundingBox() called but no data points found."); for (int i = 0; i < (DIM > 0 ? DIM : BaseClassRef::dim); ++i) { bbox[i].low = bbox[i].high = this->dataset_get(*this, BaseClassRef::vind[0], i); } for (size_t k = 1; k < N; ++k) { for (int i = 0; i < (DIM > 0 ? DIM : BaseClassRef::dim); ++i) { if (this->dataset_get(*this, BaseClassRef::vind[k], i) < bbox[i].low) bbox[i].low = this->dataset_get(*this, BaseClassRef::vind[k], i); if (this->dataset_get(*this, BaseClassRef::vind[k], i) > bbox[i].high) bbox[i].high = this->dataset_get(*this, BaseClassRef::vind[k], i); } } } } /** * Performs an exact search in the tree starting from a node. * \tparam RESULTSET Should be any ResultSet */ template void searchLevel(RESULTSET &result_set, const ElementType *vec, const NodePtr node, DistanceType mindistsq, distance_vector_t &dists, const float epsError) const { /* If this is a leaf node, then do check and return. */ if ((node->child1 == NULL) && (node->child2 == NULL)) { // count_leaf += (node->lr.right-node->lr.left); // Removed since was neither used nor returned to the user. DistanceType worst_dist = result_set.worstDist(); for (IndexType i = node->node_type.lr.left; i < node->node_type.lr.right; ++i) { const IndexType index = BaseClassRef::vind[i]; // reorder... : i; if (treeIndex[index] == -1) continue; DistanceType dist = distance.evalMetric(vec, index, (DIM > 0 ? DIM : BaseClassRef::dim)); if (dist < worst_dist) { result_set.addPoint(dist, BaseClassRef::vind[i]); } } return; } /* Which child branch should be taken first? */ int idx = node->node_type.sub.divfeat; ElementType val = vec[idx]; DistanceType diff1 = val - node->node_type.sub.divlow; DistanceType diff2 = val - node->node_type.sub.divhigh; NodePtr bestChild; NodePtr otherChild; DistanceType cut_dist; if ((diff1 + diff2) < 0) { bestChild = node->child1; otherChild = node->child2; cut_dist = distance.accum_dist(val, node->node_type.sub.divhigh, idx); } else { bestChild = node->child2; otherChild = node->child1; cut_dist = distance.accum_dist(val, node->node_type.sub.divlow, idx); } /* Call recursively to search next level down. */ searchLevel(result_set, vec, bestChild, mindistsq, dists, epsError); DistanceType dst = dists[idx]; mindistsq = mindistsq + cut_dist - dst; dists[idx] = cut_dist; if (mindistsq * epsError <= result_set.worstDist()) { searchLevel(result_set, vec, otherChild, mindistsq, dists, epsError); } dists[idx] = dst; } public: /** Stores the index in a binary file. * IMPORTANT NOTE: The set of data points is NOT stored in the file, so when loading the index object it must be constructed associated to the same source of data points used while building it. * See the example: examples/saveload_example.cpp * \sa loadIndex */ void saveIndex(FILE *stream) { this->saveIndex_(*this, stream); } /** Loads a previous index from a binary file. * IMPORTANT NOTE: The set of data points is NOT stored in the file, so the index object must be constructed associated to the same source of data points used while building the index. * See the example: examples/saveload_example.cpp * \sa loadIndex */ void loadIndex(FILE *stream) { this->loadIndex_(*this, stream); } }; /** kd-tree dynaimic index * * class to create multiple static index and merge their results to behave as single dynamic index as proposed in Logarithmic Approach. * * Example of usage: * examples/dynamic_pointcloud_example.cpp * * \tparam DatasetAdaptor The user-provided adaptor (see comments above). * \tparam Distance The distance metric to use: nanoflann::metric_L1, nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. * \tparam DIM Dimensionality of data points (e.g. 3 for 3D points) * \tparam IndexType Will be typically size_t or int */ template class KDTreeSingleIndexDynamicAdaptor { public: typedef typename Distance::ElementType ElementType; typedef typename Distance::DistanceType DistanceType; protected: size_t m_leaf_max_size; size_t treeCount; size_t pointCount; /** * The dataset used by this index */ const DatasetAdaptor &dataset; //!< The source of our data std::vector treeIndex; //!< treeIndex[idx] is the index of tree in which point at idx is stored. treeIndex[idx]=-1 means that point has been removed. KDTreeSingleIndexAdaptorParams index_params; int dim; //!< Dimensionality of each data point typedef KDTreeSingleIndexDynamicAdaptor_ index_container_t; std::vector index; public: /** Get a const ref to the internal list of indices; the number of indices is adapted dynamically as * the dataset grows in size. */ const std::vector &getAllIndices() const { return index; } private: /** finds position of least significant unset bit */ int First0Bit(IndexType num) { int pos = 0; while (num & 1) { num = num >> 1; pos++; } return pos; } /** Creates multiple empty trees to handle dynamic support */ void init() { typedef KDTreeSingleIndexDynamicAdaptor_ my_kd_tree_t; std::vector index_(treeCount, my_kd_tree_t(dim /*dim*/, dataset, treeIndex, index_params)); index = index_; } public: Distance distance; /** * KDTree constructor * * Refer to docs in README.md or online in https://github.com/jlblancoc/nanoflann * * The KD-Tree point dimension (the length of each point in the datase, e.g. 3 for 3D points) * is determined by means of: * - The \a DIM template parameter if >0 (highest priority) * - Otherwise, the \a dimensionality parameter of this constructor. * * @param inputData Dataset with the input features * @param params Basically, the maximum leaf node size */ KDTreeSingleIndexDynamicAdaptor(const int dimensionality, const DatasetAdaptor &inputData, const KDTreeSingleIndexAdaptorParams ¶ms = KDTreeSingleIndexAdaptorParams(), const size_t maximumPointCount = 1000000000U) : dataset(inputData), index_params(params), distance(inputData) { treeCount = std::log2(maximumPointCount); pointCount = 0U; dim = dimensionality; treeIndex.clear(); if (DIM > 0) dim = DIM; m_leaf_max_size = params.leaf_max_size; init(); int num_initial_points = dataset.kdtree_get_point_count(); if (num_initial_points > 0) { addPoints(0, num_initial_points - 1); } } /** Deleted copy constructor*/ KDTreeSingleIndexDynamicAdaptor(const KDTreeSingleIndexDynamicAdaptor &) = delete; /** Add points to the set, Inserts all points from [start, end] */ void addPoints(IndexType start, IndexType end) { int count = end - start + 1; treeIndex.resize(treeIndex.size() + count); for (IndexType idx = start; idx <= end; idx++) { int pos = First0Bit(pointCount); index[pos].vind.clear(); treeIndex[pointCount] = pos; for (int i = 0; i < pos; i++) { for (int j = 0; j < static_cast(index[i].vind.size()); j++) { index[pos].vind.push_back(index[i].vind[j]); treeIndex[index[i].vind[j]] = pos; } index[i].vind.clear(); index[i].freeIndex(index[i]); } index[pos].vind.push_back(idx); index[pos].buildIndex(); pointCount++; } } /** Remove a point from the set (Lazy Deletion) */ void removePoint(size_t idx) { if (idx >= pointCount) return; treeIndex[idx] = -1; } /** * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored inside * the result object. * * Params: * result = the result object in which the indices of the nearest-neighbors are stored * vec = the vector for which to search the nearest neighbors * * \tparam RESULTSET Should be any ResultSet * \return True if the requested neighbors could be found. * \sa knnSearch, radiusSearch */ template bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParams &searchParams) const { for (size_t i = 0; i < treeCount; i++) { index[i].findNeighbors(result, &vec[0], searchParams); } return result.full(); } }; /** An L2-metric KD-tree adaptor for working with data directly stored in an Eigen Matrix, without duplicating the data storage. * Each row in the matrix represents a point in the state space. * * Example of usage: * \code * Eigen::Matrix mat; * // Fill out "mat"... * * typedef KDTreeEigenMatrixAdaptor< Eigen::Matrix > my_kd_tree_t; * const int max_leaf = 10; * my_kd_tree_t mat_index(mat, max_leaf ); * mat_index.index->buildIndex(); * mat_index.index->... * \endcode * * \tparam DIM If set to >0, it specifies a compile-time fixed dimensionality for the points in the data set, allowing more compiler optimizations. * \tparam Distance The distance metric to use: nanoflann::metric_L1, nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. */ template struct KDTreeEigenMatrixAdaptor { typedef KDTreeEigenMatrixAdaptor self_t; typedef typename MatrixType::Scalar num_t; typedef typename MatrixType::Index IndexType; typedef typename Distance::template traits::distance_t metric_t; typedef KDTreeSingleIndexAdaptor index_t; index_t *index; //! The kd-tree index for the user to call its methods as usual with any other FLANN index. /// Constructor: takes a const ref to the matrix object with the data points KDTreeEigenMatrixAdaptor(const MatrixType &mat, const int leaf_max_size = 10) : m_data_matrix(mat) { const IndexType dims = mat.cols(); index = new index_t(dims, *this /* adaptor */, nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size)); index->buildIndex(); } public: /** Deleted copy constructor */ KDTreeEigenMatrixAdaptor(const self_t &) = delete; ~KDTreeEigenMatrixAdaptor() { delete index; } const MatrixType &m_data_matrix; /** Query for the \a num_closest closest points to a given point (entered as query_point[0:dim-1]). * Note that this is a short-cut method for index->findNeighbors(). * The user can also call index->... methods as desired. * \note nChecks_IGNORED is ignored but kept for compatibility with the original FLANN interface. */ inline void query(const num_t *query_point, const size_t num_closest, IndexType *out_indices, num_t *out_distances_sq, const int /* nChecks_IGNORED */ = 10) const { nanoflann::KNNResultSet resultSet(num_closest); resultSet.init(out_indices, out_distances_sq); index->findNeighbors(resultSet, query_point, nanoflann::SearchParams()); } /** @name Interface expected by KDTreeSingleIndexAdaptor * @{ */ const self_t &derived() const { return *this; } self_t & derived() { return *this; } // Must return the number of data points inline size_t kdtree_get_point_count() const { return m_data_matrix.rows(); } // Returns the dim'th component of the idx'th point in the class: inline num_t kdtree_get_pt(const IndexType idx, int dim) const { return m_data_matrix.coeff(idx, IndexType(dim)); } // Optional bounding-box computation: return false to default to a standard bbox computation loop. // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again. // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds) template bool kdtree_get_bbox(BBOX & /*bb*/) const { return false; } /** @} */ }; // end of KDTreeEigenMatrixAdaptor /** @} */ /** @} */ // end of grouping } // namespace nanoflann #endif /* NANOFLANN_HPP_ */ ================================================ FILE: include/vapor/ptr_cache.hpp ================================================ //----------------------------------------------------------------------------- // This is an implementation of a least-recently-used (LRU) cache that keeps // raw pointers pointing to big structures (e.g., grids, quadtrees). // // This cache has two execution policies: // 1) only insertion counts as `recently used`, and // 2) both insertion and query count as `recently used`. // // Given this design, this cache is expected to keep the ownership of these // structures once they're put in the cache, and all other codes will not // need to manage these structures. In other words, once an object is evicted, // its destructor will be called. // // All structures stored in this cache are const qualified, so once a // structure is put in this cache, there is no more modification to this structure. // // Caveat: A cache keeps things that it is asked to keep, which in this case are pointers. // This implementation guarantees that pointers and the objects that they point to // are not altered while in the cache, and are properly destroyed when evicted. // The cache guarantees nothing more than that. //----------------------------------------------------------------------------- #ifndef PTR_CACHE_H #define PTR_CACHE_H #include // size_t #include // std::pair<> #include #include #include namespace VAPoR { // // Note : 1) Key must support == operator and = operator. // 2) BigObj must be able to be destructed by delete. // template class ptr_cache { public: // // Constructors and Destructor // ptr_cache() = default; ptr_cache(const ptr_cache &) = delete; ptr_cache(const ptr_cache &&) = delete; ptr_cache &operator=(const ptr_cache &) = delete; ptr_cache &operator=(const ptr_cache &&) = delete; ~ptr_cache() { for (auto &p : _element_vector) { if (p.second) delete p.second; } } auto size() const -> size_t { return _element_vector.size(); } // // Major action function. // If the key exists, it returns the pointer associated with the key. // If the key does not exist, it returns a nullptr. // auto query(const Key &key) -> const BigObj * { if (Query) { // Use a guard lock if queries can change ordering. const std::lock_guard lock_gd(_element_vector_mutex); auto it = std::find_if(_element_vector.begin(), _element_vector.end(), [&key](element_type &e) { return e.first == key; }); if (it == _element_vector.end()) // This key does not exist return nullptr; else { // This key does exist std::rotate(_element_vector.begin(), it, it + 1); return _element_vector.front().second; } } else { // Just query, no change whatsoever. auto it = std::find_if(_element_vector.begin(), _element_vector.end(), [&key](element_type &e) { return e.first == key; }); if (it == _element_vector.end()) // This key does not exist return nullptr; else // This key does exist return it->second; } } void insert(const Key &key, const BigObj *ptr) { const std::lock_guard lock_gd(_element_vector_mutex); auto it = std::find_if(_element_vector.begin(), _element_vector.end(), [&key](element_type &e) { return e.first == key; }); if (it == _element_vector.end()) { // This key does not exist --it; // `it` points to the last element now. it->first = key; } if (it->second) // Destroy the old object held here. delete it->second; it->second = ptr; std::rotate(_element_vector.begin(), it, it + 1); } private: using element_type = std::pair; std::mutex _element_vector_mutex; std::array _element_vector; }; } // namespace VAPoR #endif ================================================ FILE: include/vapor/regionparams.h ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: regionparams.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: September 2004 // // Description: Defines the RegionParams class. // This class supports parameters associted with the // region panel, describing the rendering region // #ifndef REGIONPARAMS_H #define REGIONPARAMS_H #include #include namespace VAPoR { //! \class RegionParams //! \ingroup Public_Params //! \brief A class for describing a 3D axis-aligned region in user space. //! \author Alan Norton //! \version 3.0 //! \date February 2014 //! The RegionParams class controls the extents of a 3D box of data for visualization. //! The DVR, Isosurface and Flow renderers use only the data specified by the current RegionParams. //! There is a global RegionParams, that //! is shared by all windows whose region is set to "global". There is also //! a local RegionParams for each window, that users can select whenever there are multiple windows. //! When local settings are used, they only affect one currently active visualizer. //! The RegionParams class also has several methods that are useful in setting up data requests from the DataMgr. //! class PARAMS_API RegionParams : public ParamsBase { public: RegionParams(ParamsBase::StateSave *ssave); RegionParams(ParamsBase::StateSave *ssave, XmlNode *node); RegionParams(const RegionParams &rhs); RegionParams &operator=(const RegionParams &rhs); virtual ~RegionParams(); ///@} //! Method to obtain the current Box defining the region extents //! \retval Box* current Box. virtual Box *GetBox() const { return m_Box; } //! Get the extents extent of the Box, in local coordinates //! \param[out] double[6] extents //! \param[in] int timestep indicates the current timestep, used only with time-varying extents. #ifdef VAPOR3_0_0_ALPHA void getLocalRegionExtents(double exts[6], int timestep) const { GetBox()->GetLocalExtents(exts, timestep); return; } //! Get a center coordinate of the Box, in local coordinates //! \param[in] int coord 0,1,2 for x,y,z //! \param[in] int timestep indicates the current timestep, used only with time-varying extents. //! \retval double value of center for specified coordinate. double getLocalRegionCenter(int indx, int timestep) const { if (indx < 0 || indx > 2) indx = 0; return (0.5 * (getLocalRegionMin(indx, timestep) + getLocalRegionMax(indx, timestep))); } #endif #ifdef VAPOR3_0_0_ALPHA //! Provide a vector of the times, useful for time-varying extents //! \retval const vector vector of times. const vector GetTimes() const { return GetBox()->GetTimes(); } //! Indicate whether or not the extents vary over time //! \retval bool return true if extents are time-varying. bool extentsAreVarying() { return GetBox()->GetTimes().size() > 1; } //! Insert a specific time in the list of time-varying extents. Return false if it's already there //! \param[in] timestep to be inserted //! \retval true if the time was not already in the list. bool insertTime(int timestep); //! Remove a time from the time-varying timesteps. Return false if unsuccessful //! \param[in] timestep to be removed //! \retval false if the time was not already in the list. bool removeTime(int timestep); #endif #ifdef VAPOR3_0_0_ALPHA //! Provide a vector of all the extents for all times //! returns 6 doubles for each time step. //! \retval const vector vector of extents. vector GetAllExtents() const { return GetBox()->GetLocalExtents(); } #endif #ifdef VAPOR3_0_0_ALPHA //! Provide the domain-defining variables //! returns a vector of variable names. //! Note that this is an attribute of the global Region params //! \retval vector domain-defining variables static const vector GetDomainVariables() { ((RegionParams *)_paramsMgr->GetParamsInstance(_regionParamsTag, -1, -1))->GetValueStringVec(_domainVariablesTag); return vec; } //! set the domain-defining variables //! Note that this value is stored in the global Region params //! \param [in] vector names of domain-defining variables //! \retval int 0 if successful static int SetDomainVariables(vector varnames) { if (varnames.size() == 0) return -1; return ((RegionParams *)_paramsMgr->GetParamsInstance(_regionParamsTag, -1, -1))->SetValueStringVec(_domainVariablesTag, "Set Domain-defining variables", varnames); } #endif // Get static string identifier for this params class // static string GetClassType() { return ("RegionParams"); } private: Box *m_Box; static const string _domainVariablesTag; void _init(); void _reconcile(); }; }; // namespace VAPoR #endif // REGIONPARAMS_H ================================================ FILE: include/vapor/udunits2.h ================================================ /* * Copyright 2008, 2009 University Corporation for Atmospheric Research * * This file is part of the UDUNITS-2 package. See the file LICENSE * in the top-level source-directory of the package for copying and * redistribution conditions. */ #ifndef UT_UNITS2_H_INCLUDED #define UT_UNITS2_H_INCLUDED #include "vapor/common.h" #include #include #include "converter.h" typedef struct ut_system ut_system; typedef union ut_unit ut_unit; typedef enum { UT_SUCCESS = 0, /* Success */ UT_BAD_ARG, /* An argument violates the function's contract */ UT_EXISTS, /* Unit, prefix, or identifier already exists */ UT_NO_UNIT, /* No such unit exists */ UT_OS, /* Operating-system error. See "errno". */ UT_NOT_SAME_SYSTEM, /* The units belong to different unit-systems */ UT_MEANINGLESS, /* The operation on the unit(s) is meaningless */ UT_NO_SECOND, /* The unit-system doesn't have a unit named "second" */ UT_VISIT_ERROR, /* An error occurred while visiting a unit */ UT_CANT_FORMAT, /* A unit can't be formatted in the desired manner */ UT_SYNTAX, /* string unit representation contains syntax error */ UT_UNKNOWN, /* string unit representation contains unknown word */ UT_OPEN_ARG, /* Can't open argument-specified unit database */ UT_OPEN_ENV, /* Can't open environment-specified unit database */ UT_OPEN_DEFAULT, /* Can't open installed, default, unit database */ UT_PARSE /* Error parsing unit specification */ } ut_status; typedef enum { UT_ASCII = 0, UT_ISO_8859_1 = 1, UT_LATIN1 = UT_ISO_8859_1, UT_UTF8 = 2 } ut_encoding; #define UT_NAMES 4 #define UT_DEFINITION 8 /* * Data-structure for a visitor to a unit: */ typedef struct { /* * Visits a basic-unit. A basic-unit is a base unit like "meter" or a non- * dimensional but named unit like "radian". * * Arguments: * unit Pointer to the basic-unit. * arg Client pointer passed to ut_accept_visitor(). * Returns: * UT_SUCCESS Success. * else Failure. */ ut_status (*visit_basic)(const ut_unit *unit, void *arg); /* * Visits a product-unit. A product-unit is a product of zero or more * basic-units, each raised to a non-zero power. * * Arguments: * unit Pointer to the product-unit. * count The number of basic-units in the product. May be zero. * basicUnits Pointer to an array of basic-units in the product. * powers Pointer to an array of powers to which the respective * basic-units are raised. * arg Client pointer passed to ut_accept_visitor(). * Returns: * UT_SUCCESS Success. * else Failure. */ ut_status (*visit_product)(const ut_unit *unit, int count, const ut_unit *const *basicUnits, const int *powers, void *arg); /* * Visits a Galilean-unit. A Galilean-unit has an underlying unit and a * non-unity scale factor or a non-zero offset. * * Arguments: * unit Pointer to the Galilean-unit. * scale The scale factor (e.g., 1000 for a kilometer when the * underlying unit is a meter). * underlyingUnit Pointer to the underlying unit. * offset Pointer to the underlying unit. * arg Client pointer passed to ut_accept_visitor(). * Returns: * UT_SUCCESS Success. * else Failure. */ ut_status (*visit_galilean)(const ut_unit *unit, double scale, const ut_unit *underlyingUnit, double offset, void *arg); /* * Visits a timestamp-unit. A timestamp-unit has an underlying unit of time * and an encoded time-origin. * * Arguments: * unit Pointer to the timestamp-unit. * timeUnit Pointer to the underlying unit of time. * origin Encoded origin of the timestamp-unit. * arg Client pointer passed to ut_accept_visitor(). * Returns: * UT_SUCCESS Success. * else Failure. */ ut_status (*visit_timestamp)(const ut_unit *unit, const ut_unit *timeUnit, double origin, void *arg); /* * Visits a logarithmic-unit. A logarithmic-unit has a logarithmic base and * a unit that specifies the reference level. * * Arguments: * unit Pointer to the logarithmic-unit. * base The logarithmic base (e.g., 2, M_E, 10). * reference Pointer to the unit that specifies the reference level. * arg Client pointer passed to ut_accept_visitor(). * Returns: * UT_SUCCESS Success. * else Failure. */ ut_status (*visit_logarithmic)(const ut_unit *unit, double base, const ut_unit *reference, void *arg); } ut_visitor; typedef int (*ut_error_message_handler)(const char *fmt, va_list args); #ifdef __cplusplus extern "C" { #endif /****************************************************************************** * Unit System: ******************************************************************************/ /* * Returns the unit-system corresponding to an XML file. This is the usual way * that a client will obtain a unit-system. * * Arguments: * path The pathname of the XML file or NULL. If NULL, then the * pathname specified by the environment variable UDUNITS2_XML_PATH * is used if set; otherwise, the compile-time pathname of the * installed, default, unit database is used. * Returns: * NULL Failure. "ut_get_status()" will be * UT_OPEN_ARG "path" is non-NULL but file couldn't be * opened. See "errno" for reason. * UT_OPEN_ENV "path" is NULL and environment variable * UDUNITS2_XML_PATH is set but file * couldn't be opened. See "errno" for * reason. * UT_OPEN_DEFAULT "path" is NULL, environment variable * UDUNITS2_XML_PATH is unset, and the * installed, default, unit database * couldn't be opened. See "errno" for * reason. * UT_PARSE Couldn't parse unit database. * UT_OS Operating-system error. See "errno". * else Pointer to the unit-system defined by "path". */ UDUNITS2_API ut_system *ut_read_xml(const char *path); /* * Returns a new unit-system. On success, the unit-system will only contain * the dimensionless unit one. See "ut_get_dimensionless_unit_one()". * * Returns: * NULL Failure. "ut_get_status()" will be: * UT_OS Operating-system error. See "errno". * else Pointer to a new unit system. */ UDUNITS2_API ut_system *ut_new_system(void); /* * Frees a unit-system. All unit-to-identifier and identifier-to-unit mappings * will be removed. * * Arguments: * system Pointer to the unit-system to be freed. Use of "system" * upon return results in undefined behavior. */ UDUNITS2_API void ut_free_system(ut_system *system); /* * Returns the unit-system to which a unit belongs. * * Arguments: * unit Pointer to the unit in question. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * else Pointer to the unit-system to which "unit" belongs. */ UDUNITS2_API ut_system *ut_get_system(const ut_unit *const unit); /* * Returns the dimensionless-unit one of a unit-system. * * Arguments: * system Pointer to the unit-system for which the dimensionless-unit one * will be returned. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "system" is NULL. * else Pointer to the dimensionless-unit one associated with "system". * While not necessary, the pointer may be passed to ut_free() * when the unit is no longer needed by the client. */ UDUNITS2_API ut_unit *ut_get_dimensionless_unit_one(const ut_system *const system); /* * Returns the unit with a given name from a unit-system. Name comparisons * are case-insensitive. * * Arguments: * system Pointer to the unit-system. * name Pointer to the name of the unit to be returned. * Returns: * NULL Failure. "ut_get_status()" will be * UT_SUCCESS "name" doesn't map to a unit of * "system". * UT_BAD_ARG "system" or "name" is NULL. * else Pointer to the unit of the unit-system with the given name. * The pointer should be passed to ut_free() when the unit is * no longer needed. */ UDUNITS2_API ut_unit *ut_get_unit_by_name(const ut_system *const system, const char *const name); /* * Returns the unit with a given symbol from a unit-system. Symbol * comparisons are case-sensitive. * * Arguments: * system Pointer to the unit-system. * symbol Pointer to the symbol associated with the unit to be * returned. * Returns: * NULL Failure. "ut_get_status()" will be * UT_SUCCESS "symbol" doesn't map to a unit of * "system". * UT_BAD_ARG "system" or "symbol" is NULL. * else Pointer to the unit in the unit-system with the given symbol. * The pointer should be passed to ut_free() when the unit is no * longer needed. */ UDUNITS2_API ut_unit *ut_get_unit_by_symbol(const ut_system *const system, const char *const symbol); /* * Sets the "second" unit of a unit-system. This function must be called before * the first call to "ut_offset_by_time()". ut_read_xml() calls this function if the * resulting unit-system contains a unit named "second". * * Arguments: * second Pointer to the "second" unit. * Returns: * UT_BAD_ARG "second" is NULL. * UT_EXISTS The second unit of the unit-system to which "second" * belongs is set to a different unit. * UT_SUCCESS Success. */ UDUNITS2_API ut_status ut_set_second(const ut_unit *const second); /****************************************************************************** * Defining Unit Prefixes: ******************************************************************************/ /* * Adds a name-prefix to a unit-system. A name-prefix is something like "mega" * or "milli". Comparisons between name-prefixes are case-insensitive. * * Arguments: * system Pointer to the unit-system. * name Pointer to the name-prefix (e.g., "mega"). May be freed * upon return. * value The value of the prefix (e.g., 1e6). * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "system" or "name" is NULL, or "value" is 0. * UT_EXISTS "name" already maps to a different value. * UT_OS Operating-system failure. See "errno". */ UDUNITS2_API ut_status ut_add_name_prefix(ut_system *const system, const char *const name, const double value); /* * Adds a symbol-prefix to a unit-system. A symbol-prefix is something like * "M" or "y". Comparisons between symbol-prefixes are case-sensitive. * * Arguments: * system Pointer to the unit-system. * symbol Pointer to the symbol-prefix (e.g., "M"). May be freed * upon return. * value The value of the prefix (e.g., 1e6). * Returns: * UT_SUCCESS Success. * UT_BADSYSTEM "system" or "symbol" is NULL. * UT_BAD_ARG "value" is 0. * UT_EXISTS "symbol" already maps to a different value. * UT_OS Operating-system failure. See "errno". */ UDUNITS2_API ut_status ut_add_symbol_prefix(ut_system *const system, const char *const symbol, const double value); /****************************************************************************** * Defining and Deleting Units: ******************************************************************************/ /* * Adds a base-unit to a unit-system. Clients that use ut_read_xml() should not * normally need to call this function. * * Arguments: * system Pointer to the unit-system to which to add the new base-unit. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "system" or "name" is NULL. * UT_OS Operating-system error. See "errno". * else Pointer to the new base-unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client (the * unit will remain in the unit-system). */ UDUNITS2_API ut_unit *ut_new_base_unit(ut_system *const system); /* * Adds a dimensionless-unit to a unit-system. In the SI system of units, the * derived-unit radian is a dimensionless-unit. Clients that use ut_read_xml() * should not normally need to call this function. * * Arguments: * system Pointer to the unit-system to which to add the new * dimensionless-unit. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "system" is NULL. * UT_OS Operating-system error. See "errno". * else Pointer to the new dimensionless-unit. The pointer should be * passed to ut_free() when the unit is no longer needed by the * client (the unit will remain in the unit-system). */ UDUNITS2_API ut_unit *ut_new_dimensionless_unit(ut_system *const system); /* * Returns a clone of a unit. * * Arguments: * unit Pointer to the unit to be cloned. * Returns: * NULL Failure. ut_get_status() will be * UT_OS Operating-system failure. See "errno". * UT_BAD_ARG "unit" is NULL. * else Pointer to the clone of "unit". The pointer should be * passed to ut_free() when the unit is no longer needed by the * client. */ UDUNITS2_API ut_unit *ut_clone(const ut_unit *unit); /* * Frees resources associated with a unit. This function should be invoked on * all units that are no longer needed by the client. Use of the unit upon * return from this function will result in undefined behavior. * * Arguments: * unit Pointer to the unit to have its resources freed or NULL. */ UDUNITS2_API void ut_free(ut_unit *const unit); /****************************************************************************** * Mapping between Units and Names: ******************************************************************************/ /* * Returns the name in a given encoding to which a unit maps. * * Arguments: * unit Pointer to the unit whose name should be returned. * encoding The desired encoding of the name. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * UT_SUCCESS "unit" doesn't map to a name in * in the given encoding. * else Pointer to the name in the given encoding to which * "unit" maps. */ UDUNITS2_API const char *ut_get_name(const ut_unit *const unit, const ut_encoding encoding); /* * Adds a mapping from a name to a unit. * * Arguments: * name Pointer to the name to be mapped to "unit". May be * freed upon return. * encoding The character encoding of "name". * unit Pointer to the unit to be mapped-to by "name". May be * freed upon return. * Returns: * UT_BAD_ARG "name" or "unit" is NULL. * UT_OS Operating-system error. See "errno". * UT_EXISTS "name" already maps to a different unit. * UT_SUCCESS Success. */ ut_status ut_map_name_to_unit(const char *const name, const ut_encoding encoding, const ut_unit *const unit); /* * Removes a mapping from a name to a unit. After this function, * ut_get_unit_by_name(system,name) will no longer return a unit. * * Arguments: * system The unit-system to which the unit belongs. * name The name of the unit. * encoding The character encoding of "name". * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "system" or "name" is NULL. */ UDUNITS2_API ut_status ut_unmap_name_to_unit(ut_system *system, const char *const name, const ut_encoding encoding); /* * Adds a mapping from a unit to a name. * * Arguments: * unit Pointer to the unit to be mapped to "name". May be * freed upon return. * name Pointer to the name to be mapped-to by "unit". May be * freed upon return. * encoding The encoding of "name". * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "unit" or "name" is NULL, or "name" is not in the * specified encoding. * UT_OS Operating-system error. See "errno". * UT_EXISTS "unit" already maps to a name. */ UDUNITS2_API ut_status ut_map_unit_to_name(const ut_unit *const unit, const char *const name, ut_encoding encoding); /* * Removes a mapping from a unit to a name. * * Arguments: * unit Pointer to the unit. May be freed upon return. * encoding The encoding to be removed. No other encodings will be * removed. * Returns: * UT_BAD_ARG "unit" is NULL. * UT_SUCCESS Success. */ UDUNITS2_API ut_status ut_unmap_unit_to_name(const ut_unit *const unit, ut_encoding encoding); /****************************************************************************** * Mapping between Units and Symbols: ******************************************************************************/ /* * Returns the symbol in a given encoding to which a unit maps. * * Arguments: * unit Pointer to the unit whose symbol should be returned. * encoding The desired encoding of the symbol. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * UT_SUCCESS "unit" doesn't map to a symbol * in the given encoding. * else Pointer to the symbol in the given encoding to which * "unit" maps. */ UDUNITS2_API const char *ut_get_symbol(const ut_unit *const unit, const ut_encoding encoding); /* * Adds a mapping from a symbol to a unit. * * Arguments: * symbol Pointer to the symbol to be mapped to "unit". May be * freed upon return. * ut_encoding The character encoding of "symbol". * unit Pointer to the unit to be mapped-to by "symbol". May * be freed upon return. * Returns: * UT_BAD_ARG "symbol" or "unit" is NULL. * UT_OS Operating-system error. See "errno". * UT_EXISTS "symbol" already maps to a different unit. * UT_SUCCESS Success. */ UDUNITS2_API ut_status ut_map_symbol_to_unit(const char *const symbol, const ut_encoding encoding, const ut_unit *const unit); /* * Removes a mapping from a symbol to a unit. After this function, * ut_get_unit_by_symbol(system,symbol) will no longer return a unit. * * Arguments: * system The unit-system to which the unit belongs. * symbol The symbol of the unit. * encoding The character encoding of "symbol". * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "system" or "symbol" is NULL. */ UDUNITS2_API ut_status ut_unmap_symbol_to_unit(ut_system *system, const char *const symbol, const ut_encoding encoding); /* * Adds a mapping from a unit to a symbol. * * Arguments: * unit Pointer to the unit to be mapped to "symbol". May be * freed upon return. * symbol Pointer to the symbol to be mapped-to by "unit". May * be freed upon return. * encoding The encoding of "symbol". * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "unit" or "symbol" is NULL. * UT_OS Operating-system error. See "errno". * UT_EXISTS "unit" already maps to a symbol. */ UDUNITS2_API ut_status ut_map_unit_to_symbol(const ut_unit *unit, const char *const symbol, ut_encoding encoding); /* * Removes a mapping from a unit to a symbol. * * Arguments: * unit Pointer to the unit to be unmapped to a symbol. May be * freed upon return. * encoding The encoding to be removed. The mappings for "unit" in * other encodings will not be removed. * Returns: * UT_SUCCESS Success. * UT_BAD_ARG "unit" is NULL. */ UDUNITS2_API ut_status ut_unmap_unit_to_symbol(const ut_unit *const unit, ut_encoding encoding); /****************************************************************************** * Getting Information about a Unit: ******************************************************************************/ /* * Indicates if a given unit is dimensionless or not. Note that logarithmic * units are dimensionless by definition. * * Arguments: * unit Pointer to the unit in question. * Returns: * 0 "unit" is dimensionfull or an error occurred. "ut_get_status()" * will be * UT_BAD_ARG "unit" is NULL. * UT_SUCCESS "unit" is dimensionfull. * else "unit" is dimensionless. */ UDUNITS2_API int ut_is_dimensionless(const ut_unit *const unit); /* * Indicates if two units belong to the same unit-system. * * Arguments: * unit1 Pointer to a unit. * unit2 Pointer to another unit. * Returns: * 0 Failure or the units belong to different unit-systems. * "ut_get_status()" will be * UT_BAD_ARG "unit1" or "unit2" is NULL. * UT_SUCCESS The units belong to different * unit-systems. * else The units belong to the same unit-system. */ UDUNITS2_API int ut_same_system(const ut_unit *const unit1, const ut_unit *const unit2); /* * Compares two units. Returns a value less than, equal to, or greater than * zero as the first unit is considered less than, equal to, or greater than * the second unit, respectively. Units from different unit-systems never * compare equal. * * Arguments: * unit1 Pointer to a unit or NULL. * unit2 Pointer to another unit or NULL. * Returns: * <0 The first unit is less than the second unit. * 0 The first and second units are equal or both units are NULL. * >0 The first unit is greater than the second unit. */ UDUNITS2_API int ut_compare(const ut_unit *const unit1, const ut_unit *const unit2); /* * Indicates if numeric values in one unit are convertible to numeric values in * another unit via "ut_get_converter()". In making this determination, * dimensionless units are ignored. * * Arguments: * unit1 Pointer to a unit. * unit2 Pointer to another unit. * Returns: * 0 Failure. "ut_get_status()" will be * UT_BAD_ARG "unit1" or "unit2" is NULL. * UT_NOT_SAME_SYSTEM "unit1" and "unit2" belong to * different unit-sytems. * UT_SUCCESS Conversion between the units is * not possible (e.g., "unit1" is * "meter" and "unit2" is * "kilogram"). * else Numeric values can be converted between the units. */ UDUNITS2_API int ut_are_convertible(const ut_unit *const unit1, const ut_unit *const unit2); /* * Returns a converter of numeric values in one unit to numeric values in * another unit. The returned converter should be passed to cv_free() when it is * no longer needed by the client. * * NOTE: Leap seconds are not taken into account when converting between * timestamp units. * * Arguments: * from Pointer to the unit from which to convert values. * to Pointer to the unit to which to convert values. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "from" or "to" is NULL. * UT_NOT_SAME_SYSTEM "from" and "to" belong to * different unit-systems. * UT_MEANINGLESS Conversion between the units is * not possible. See * "ut_are_convertible()". * else Pointer to the appropriate converter. The pointer * should be passed to cv_free() when no longer needed by * the client. */ UDUNITS2_API cv_converter *ut_get_converter(ut_unit *const from, ut_unit *const to); /****************************************************************************** * Arithmetic Unit Manipulation: ******************************************************************************/ /* * Returns a unit equivalent to another unit scaled by a numeric factor, * e.g., * const ut_unit* meter = ... * const ut_unit* kilometer = ut_scale(1000, meter); * * Arguments: * factor The numeric scale factor. * unit Pointer to the unit to be scaled. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "factor" is 0 or "unit" is NULL. * UT_OS Operating-system error. See * "errno". * else Pointer to the resulting unit. The pointer should be * passed to ut_free() when the unit is no longer needed by * the client. */ UDUNITS2_API ut_unit *ut_scale(const double factor, const ut_unit *const unit); /* * Returns a unit equivalent to another unit offset by a numeric amount, * e.g., * const ut_unit* kelvin = ... * const ut_unit* celsius = ut_offset(kelvin, 273.15); * * Arguments: * unit Pointer to the unit to be offset. * offset The numeric offset. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * UT_OS Operating-system error. See * "errno". * else Pointer to the resulting unit. The pointer should be * passed to ut_free() when the unit is no longer needed by * the client. */ UDUNITS2_API ut_unit *ut_offset(const ut_unit *const unit, const double offset); /* * Returns a unit equivalent to another unit relative to a particular time. * e.g., * const ut_unit* second = ... * const ut_unit* secondsSinceTheEpoch = * ut_offset_by_time(second, ut_encode_time(1970, 1, 1, 0, 0, 0.0)); * * Arguments: * unit Pointer to the time-unit to be made relative to a time-origin. * origin The origin as returned by ut_encode_time(). * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" is NULL. * UT_OS Operating-system error. See "errno". * UT_MEANINGLESS Creation of a timestamp unit based on * "unit" is not meaningful. * UT_NO_SECOND The associated unit-system doesn't * contain a "second" unit. See * ut_set_second(). * else Pointer to the resulting unit. The pointer should be passed * to ut_free() when the unit is no longer needed by the client. */ UDUNITS2_API ut_unit *ut_offset_by_time(const ut_unit *const unit, const double origin); /* * Returns the result of multiplying one unit by another unit. * * Arguments: * unit1 Pointer to a unit. * unit2 Pointer to another unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "unit1" or "unit2" is NULL. * UT_NOT_SAME_SYSTEM "unit1" and "unit2" belong to * different unit-systems. * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed * to ut_free() when the unit is no longer needed by the client. */ UDUNITS2_API ut_unit *ut_multiply(const ut_unit *const unit1, const ut_unit *const unit2); /* * Returns the inverse (i.e., reciprocal) of a unit. This convenience function * is equal to "ut_raise(unit, -1)". * * Arguments: * unit Pointer to the unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "unit" is NULL. * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client. */ UDUNITS2_API ut_unit *ut_invert(const ut_unit *const unit); /* * Returns the result of dividing one unit by another unit. This convenience * function is equivalent to the following sequence: * { * ut_unit* inverse = ut_invert(denom); * ut_multiply(numer, inverse); * ut_free(inverse); * } * * Arguments: * numer Pointer to the numerator (top, dividend) unit. * denom Pointer to the denominator (bottom, divisor) unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "numer" or "denom" is NULL. * UT_NOT_SAME_SYSTEM "unit1" and "unit2" belong to * different unit-systems. * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client. */ UDUNITS2_API ut_unit *ut_divide(const ut_unit *const numer, const ut_unit *const denom); /* * Returns the result of raising a unit to a power. * * Arguments: * unit Pointer to the unit. * power The power by which to raise "unit". Must be greater than or * equal to -255 and less than or equal to 255. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "unit" is NULL or "power" is invalid. * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client. */ UDUNITS2_API ut_unit *ut_raise(const ut_unit *const unit, const int power); /* * Returns the result of taking the root of a unit. * * Arguments: * unit Pointer to the unit. * root The root to take of "unit". Must be greater than or * equal to 1 and less than or equal to 255. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "unit" is NULL, or "root" is invalid. * In particular, all powers of base units * in "unit" must be integral multiples of * "root". * UT_OS Operating-system error. See "errno". * else Pointer to the resulting unit. The pointer should be passed to * ut_free() when the unit is no longer needed by the client. */ UDUNITS2_API ut_unit *ut_root(const ut_unit *const unit, const int root); /* * Returns the logarithmic unit corresponding to a logarithmic base and a * reference level. For example, the following creates a decibel unit with a * one milliwatt reference level: * * const ut_unit* watt = ...; * const ut_unit* milliWatt = ut_scale(0.001, watt); * * if (milliWatt != NULL) { * const ut_unit* bel_1_mW = ut_log(10.0, milliWatt); * * if (bel_1_mW != NULL) { * const ut_unit* decibel_1_mW = ut_scale(0.1, bel_1_mW); * * if (decibel_1_mW != NULL) { * ... * ut_free(decibel_1_mW); * } // "decibel_1_mW" allocated * * ut_free(bel_1_mW); * } // "bel_1_mW" allocated * * ut_free(milliWatt); * } // "milliWatt" allocated * * Arguments: * base The logarithmic base (e.g., 2, M_E, 10). Must be * greater than one. "M_E" is defined in . * reference Pointer to the reference value as a unit. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "base" is invalid or "reference" * is NULL. * UT_OS Operating-system error. See * "errno". * else Pointer to the resulting unit. The pointer should be * passed to ut_free() when the unit is no longer needed by * the client. */ UDUNITS2_API ut_unit *ut_log(const double base, const ut_unit *const reference); /****************************************************************************** * Parsing and Formatting Units: ******************************************************************************/ /* * Returns the binary representation of a unit corresponding to a string * representation. * * Arguments: * system Pointer to the unit-system in which the parsing will * occur. * string The string to be parsed (e.g., "millimeters"). There * should be no leading or trailing whitespace in the * string. See ut_trim(). * encoding The encoding of "string". * Returns: * NULL Failure. "ut_get_status()" will be one of * UT_BAD_ARG "system" or "string" is NULL. * UT_SYNTAX "string" contained a syntax * error. * UT_UNKNOWN "string" contained an unknown * identifier. * UT_OS Operating-system failure. See * "errno". * else Pointer to the unit corresponding to "string". */ UDUNITS2_API ut_unit *ut_parse(const ut_system *const system, const char *const string, const ut_encoding encoding); /* * Removes leading and trailing whitespace from a string. * * Arguments: * string NUL-terminated string. Will be modified if it contains * whitespace.. * encoding The character-encoding of "string". * Returns: * "string", with all leading and trailing whitespace removed. */ UDUNITS2_API char *ut_trim(char *const string, const ut_encoding encoding); /* * Formats a unit. * * Arguments: * unit Pointer to the unit to be formatted. * buf Pointer to the buffer into which to format "unit". * size Size of the buffer in bytes. * opts Formatting options: bitwise-OR of zero or more of the * following: * UT_NAMES Use unit names instead of * symbols * UT_DEFINITION The formatted string should be * the definition of "unit" in * terms of basic-units instead of * stopping any expansion at the * highest level possible. * UT_ASCII The string should be formatted * using the ASCII character set * (default). * UT_LATIN1 The string should be formatted * using the ISO Latin-1 (alias * ISO-8859-1) character set. * UT_UTF8 The string should be formatted * using the UTF-8 character set. * UT_LATIN1 and UT_UTF8 are mutually exclusive: they may * not both be specified. * Returns: * -1 Failure: "ut_get_status()" will be * UT_BAD_ARG "unit" or "buf" is NULL, or both * UT_LATIN1 and UT_UTF8 specified. * UT_CANT_FORMAT "unit" can't be formatted in * the desired manner. * else Success. Number of characters printed in "buf". If * the number is equal to the size of the buffer, then the * buffer is too small to have a terminating NUL character. */ UDUNITS2_API int ut_format(const ut_unit *const unit, char *buf, size_t size, unsigned opts); /* * Accepts a visitor to a unit. * * Arguments: * unit Pointer to the unit to accept the visitor. * visitor Pointer to the visitor of "unit". * arg An arbitrary pointer that will be passed to "visitor". * Returns: * UT_BAD_ARG "unit" or "visitor" is NULL. * UT_VISIT_ERROR A error occurred in "visitor" while visiting "unit". * UT_SUCCESS Success. */ UDUNITS2_API ut_status ut_accept_visitor(const ut_unit *const unit, const ut_visitor *const visitor, void *const arg); /****************************************************************************** * Time Handling: ******************************************************************************/ /* * Encodes a date as a double-precision value. * * Arguments: * year The year. * month The month. * day The day (1 = the first of the month). * Returns: * The date encoded as a scalar value. */ UDUNITS2_API double ut_encode_date(int year, int month, int day); /* * Encodes a time as a double-precision value. * * Arguments: * hours The number of hours (0 = midnight). * minutes The number of minutes. * seconds The number of seconds. * Returns: * The clock-time encoded as a scalar value. */ UDUNITS2_API double ut_encode_clock(int hours, int minutes, double seconds); /* * Encodes a time as a double-precision value. The convenience function is * equivalent to "ut_encode_date(year,month,day) + * ut_encode_clock(hour,minute,second)" * * Arguments: * year The year. * month The month. * day The day. * hour The hour. * minute The minute. * second The second. * Returns: * The time encoded as a scalar value. */ UDUNITS2_API double ut_encode_time(const int year, const int month, const int day, const int hour, const int minute, const double second); /* * Decodes a time from a double-precision value. * * Arguments: * value The value to be decoded. * year Pointer to the variable to be set to the year. * month Pointer to the variable to be set to the month. * day Pointer to the variable to be set to the day. * hour Pointer to the variable to be set to the hour. * minute Pointer to the variable to be set to the minute. * second Pointer to the variable to be set to the second. * resolution Pointer to the variable to be set to the resolution * of the decoded time in seconds. */ UDUNITS2_API void ut_decode_time(double value, int *year, int *month, int *day, int *hour, int *minute, double *second, double *resolution); /****************************************************************************** * Error Handling: ******************************************************************************/ /* * Returns the status of the last operation by the units module. This function * will not change the status. */ UDUNITS2_API ut_status ut_get_status(void); /* * Sets the status of the units module. This function would not normally be * called by the user unless they were doing their own parsing or formatting. * * Arguments: * status The status of the units module. */ UDUNITS2_API void ut_set_status(ut_status status); /* * Handles an error-message. * * Arguments: * fmt The format for the error-message. * ... The arguments for "fmt". * Returns: * <0 An output error was encountered. * else The number of bytes of "fmt" and "arg" written excluding any * terminating NUL. */ UDUNITS2_API int ut_handle_error_message(const char *const fmt, ...); /* * Returns the previously-installed error-message handler and optionally * installs a new handler. The initial handler is "ut_write_to_stderr()". * * Arguments: * handler NULL or pointer to the error-message handler. If NULL, * then the handler is not changed. The * currently-installed handler can be obtained this way. * Returns: * Pointer to the previously-installed error-message handler. */ UDUNITS2_API ut_error_message_handler ut_set_error_message_handler(ut_error_message_handler handler); /* * Writes an error-message to the standard-error stream when received and * appends a newline. This is the initial error-message handler. * * Arguments: * fmt The format for the error-message. * args The arguments of "fmt". * Returns: * <0 A output error was encountered. See "errno". * else The number of bytes of "fmt" and "arg" written excluding any * terminating NUL. */ UDUNITS2_API int ut_write_to_stderr(const char *const fmt, va_list args); /* * Does nothing with an error-message. * * Arguments: * fmt The format for the error-message. * args The arguments of "fmt". * Returns: * 0 Always. */ UDUNITS2_API int ut_ignore(const char *const fmt, va_list args); #ifdef __cplusplus } #endif #endif ================================================ FILE: include/vapor/utils.h ================================================ #include #include #include #include #pragma once namespace Wasp { class COMMON_API SmartBuf { public: SmartBuf() { _buf = NULL; _buf_sz = 0; }; SmartBuf(size_t size) { _buf = new unsigned char[size]; _buf_sz = size; }; SmartBuf(const SmartBuf &rhs) { _buf = new unsigned char[rhs._buf_sz]; _buf_sz = rhs._buf_sz; memcpy(_buf, rhs._buf, rhs._buf_sz); } SmartBuf &operator=(const SmartBuf &rhs) { _buf = new unsigned char[rhs._buf_sz]; _buf_sz = rhs._buf_sz; memcpy(_buf, rhs._buf, rhs._buf_sz); return *this; } ~SmartBuf() { if (_buf) delete[] _buf; }; void * Alloc(size_t size); void * GetBuf() const { return (_buf); } size_t GetBufSize() const { return (_buf_sz); } private: unsigned char *_buf; size_t _buf_sz; }; //! Linearize multi-dimensional coordinates //! //! Convert multi-dimensional coordinates, \p coords, for a space //! with dimensions, \p dims, to a linear offset from the origin //! of dims //! //! \param[in] coords A vector of integer coordinates into a an //! array with dimensions given by \p dims. The minimum coordinate value is //! zero. The maximum coordinate value is \p dims[i] - 1. //! \param[in] dims A vector defining the dimensions of an array. The size //! of \p dims must equal size of \p coords. //! //! \retval offset The offset from the first element of the array to the //! address specified by \p coords // COMMON_API size_t LinearizeCoords(const size_t *coords, const size_t *dims, size_t n); COMMON_API size_t LinearizeCoords(const std::vector &coords, const std::vector &dims); //! Linearize multi-dimensional coordinates //! //! Convert multi-dimensional coordinates, \p coords, for a space //! with minimum and maximum coordinates given by \p min, and \p max, //! respectively. //! //! \param[in] coords A vector of integer coordinates into a an //! array with boundaries defined by \p min and \p max. The minimum //! coordinate value is \p min[i] and the maximum is \p max[i]. //! \param[in] min Minimum valid coordinate value //! \param[in] min Maximum valid coordinate value //! //! \retval offset The offset from the first element of the array to the //! address specified by \p coords COMMON_API size_t LinearizeCoords(const size_t *coords, const size_t *min, const size_t *max, size_t n); COMMON_API size_t LinearizeCoords(const std::vector &coords, const std::vector &min, const std::vector &max); //! Increment a coordinate vector by one //! //! Increments \p counter along the dimension \p dim by one within the //! range of \p min //! to \p max. Overflow is possible, resulting in wraparound and setting //! \p counter back to \p min // COMMON_API void IncrementCoords(const size_t *min, const size_t *max, size_t *counter, size_t n, int dim); COMMON_API std::vector IncrementCoords(const std::vector &min, const std::vector &max, std::vector counter, int dim = 0); //! Return the dimesions of a subregion //! //! return the dimensions of a subregion enclosed by \p min and \p max // COMMON_API std::vector Dims(const std::vector &min, const std::vector &max); //! Return the scalar product of the elements of a vector //! COMMON_API size_t VProduct(const size_t *a, size_t n); COMMON_API size_t VProduct(const std::vector &a); //! Vectorize a coordinate offset. Inverse of VectorizeLinearize //! COMMON_API void VectorizeCoords(size_t offset, const size_t *min, const size_t *max, size_t *coords, size_t n); COMMON_API std::vector VectorizeCoords(size_t offset, const std::vector &min, const std::vector &max); //! Vectorize a coordinate offset. Inverse of VectorizeLinearize //! COMMON_API void VectorizeCoords(size_t offset, const size_t *dims, size_t *coords, size_t n); COMMON_API std::vector VectorizeCoords(size_t offset, const std::vector &dims); // // blocked submatrix Transpose suitable for multithreading // *a : pointer to input matrix // *b : pointer to output matrix // p1,p2: starting index of submatrix (row,col) // m1,m2: size of submatrix (row,col) // s1,s2: size of entire matrix (row,col) // COMMON_API void Transpose(const float *a, float *b, size_t p1, size_t m1, size_t s1, size_t p2, size_t m2, size_t s2); // // blocked matrix Transpose single threaded // *a : pointer to input matrix // *b : pointer to output matrix // s1,s2: size of entire matrix (row,col) // COMMON_API void Transpose(const float *a, float *b, size_t s1, size_t s2); // Perform a binary search in a sorted (increasing or decreasing) 1D // vector of values for the // intervale that contains 'x'. Return the offset 'i' of start of the // interval containing 'x' in 'sorted'. // COMMON_API bool BinarySearchRange(const std::vector &sorted, double x, size_t &i); //! Floating point comparison for near equality. //! //! Perform a floating point comparison to see if two values are nearly equal; //! //! For values close to zero the comparison is made directly againt //! \p abs_th. //! //! For values not close to zero the comparison is made against \p epsilon //! multiplied by the magnitude of \p a + \p b. //! //! See https://stackoverflow.com/questions/4915462/how-should-i-do-floating-point-comparison // // COMMON_API bool NearlyEqual(float a, float b, float epsilon = std::numeric_limits::epsilon(), float abs_th = std::numeric_limits::epsilon()); }; // namespace Wasp ================================================ FILE: include/vapor/vizutil.h ================================================ #ifndef _vizutil_h_ #define _vizutil_h_ namespace VAPoR { //! Decompose a hexahedron into 5 tetrahedra //! //! This function takes as input the indecies of eight vertices defining //! a hexahedron, and decomposes the hexahedron into a sequence of 5 //! tetrahedra. The ordering of the vertices in the input vector //! \p hexahedron must follow the diagram below. //! //! Two possible decompositions are possible, case 1 and case 2. //! //! Case 1 results in 5 tetraheda comprised of the following indecies: //! //! 0,1,5,3; 0,5,6,3; 0,5,4,6; 0,3,6,2; 5,6,3,7; //! //! Case 2 results in 5 tetraheda comprised of the following indecies: //! //! 1,5,4,7; 1,4,2,7; 1,4,0,2; 1,7,2,3; 4,2,7,6 //! //! Case 1 tetraheda are generated if the parity of the 0-vertex is //! even, case 2 if odd. //! //! Conformant meshes are possible when case 1 and case 2 are adjacent. I.e. //! if the input hexahedra are part of a conformant mesh face-adjacent //! hexahedra should have alternating 0-vertex parities. //! //! //! 6*--------*7 //! /| /| //! / | / | //! / | / | //! / 4*----/---*5 //! 2*--------*3 / //! | / | / //! | / | / //! |/ |/ //! 0*--------*1 //! //! //! \param[in] hexahedron A eight-element array containing the unique vertex //! indecies of a hexahedron. //! \param[out] tets A twenty-element array containing the resulting //! vertex indecies of the 5 tetrahedra that the hexahedron is decomposed //! into. // void HexahedronToTets(const int hexahedron[8], int tets[5 * 4]); //! Decompose a quadrilateral into 2 triangles //! //! This function takes as input the indecies of four vertices defining //! a quadrilateral, and decomposes the quad into a sequence of 2 //! triangles. The ordering of the vertices in the input vector //! \p hexahedron must follow the diagram below. //! //! 2*--------*3 //! | | //! | | //! | | //! 0*--------*1 //! //! The decomposition results in 2 triangles comprised of the //! following indecies: //! //! 0,1,3; 0,3,2 //! //! //! \param[in] quad A four-element array containing the unique vertex //! indecies of a quadrilateral. //! \param[out] tets A six-element array containing the resulting //! vertex indecies of the 2 triangles that the quadrilateral is decomposed //! into. // void QuadToTris(const int quad[4], int tris[2 * 3]); //! Return the signed, double-area of a 2D triangle //! //! This function uses determinants to calculate double the signed area of a //! triange with 2D coordinates. Equivalently, this is the 3x3 determinant //! of a matrix whose last row is all ones. The return value is positive //! if the vertices are given in counter-clockwise order, otherwise it //! is negtive. Thus the true area is 1/2 * |A|, where A is the returned //! value. //! //! \param[in] a 2D coordinates of first vertex //! \param[in] b 2D coordinates of second vertex //! \param[in] c 2D coordinates of third vertex //! double SignedTriArea2D(const double a[2], const double b[2], const double c[2]); //! Compute the Barycentric coordinates for a point inside a 2D triangle //! //! \param[in] verts an 6-element array of 2D triagle Cartesian coordinates, //! ordered x1, y1, x2, y2, x3, y3. //! \param[in] pt the 2D Cartesian coordinates //! \param[out] Barycentric coordinates for point \pt. //! //! \retval inside a flag indicating whether the point \p pt //! is inside (or on the edge) of the triangle. I.e. all of the //! Barycentric coordinates //! are positive. bool BarycentricCoordsTri(const double verts[], const double pt[], double lambda[]); //! Compute the Wachspress coordinates for a point inside an irregular, //! convex, n-sided, planar polygon. //! //! This function uses a method adapted from Meyer2005 (Generalized //! Barycentric Coordinates on Irregular Polygons) to compute Wachspress //! (generalized barycentric) coordinates for a point relative to an //! n-sided, 2D, irregular polygon. Wachspress coordinates for a point, p, //! inside a polygon, Q, have the properties that: //! //! The sum of the Wachspress coordinates is exactly 1.0 //! //! The Cartesian coordinates of p are given by the sum of the products of //! Q's vertices with the Wachspress coordinates. //! //! If p is outside of Q at lease one of the Wachspress is negative //! //! \param[in] verts an array of 2D polygon Cartesian coordinates //! describing a possibly irregular, convex polygon. //! \param[in] pt the 2D Cartesian coordinates //! \param[in] n The number of vertices in \p verts. I.e. degree of polygon //! \param[out] Wachspress coordinates for point \pt. The number of //! Wachspress coordinates is given by \p n. //! //! \retval inside a flag indicating whether the point \p pt //! is inside (or on the edge) of Q. I.e. all of the Wachspress coordinates //! are positive. // bool WachspressCoords2D(const double verts[], const double pt[], int n, double lambda[]); //! Test whether a point is inside (or on edge) of a convex polygon //! //! This function returns true of the point \p pt is on an edge or in the //! interior of the 2D polygon defined by the ordered list of vertices //! \p verts. It is the callers responsibility to ensure that the //! polygon is convex, otherwise results are undefined // //! \param[in] verts an array of 2D polygon Cartesian coordinates //! describing a convex polygon. //! \param[in] pt the 2D Cartesian coordinates //! \param[in] n The number of vertices in \p verts. I.e. degree of polygon // bool InsideConvexPolygon(const double verts[], const double pt[], int n); }; // namespace VAPoR #endif ================================================ FILE: lib/CMakeLists.txt ================================================ add_subdirectory (common) add_subdirectory (wasp) export (TARGETS common wasp NAMESPACE VAPOR:: FILE vapor-exports.cmake) if (BUILD_VDC OR BUILD_GUI) add_subdirectory (vdc) export (TARGETS vdc NAMESPACE VAPOR:: APPEND FILE vapor-exports.cmake) endif() if (BUILD_GUI OR BUILD_PYTHON) add_subdirectory(osgl) add_subdirectory (params) add_subdirectory( flow ) add_subdirectory (render) if (NOT WIN32) add_subdirectory (vapi) export (TARGETS vapi NAMESPACE VAPOR:: APPEND FILE vapor-exports.cmake) endif() export (TARGETS render params flow osgl NAMESPACE VAPOR:: APPEND FILE vapor-exports.cmake) endif() ================================================ FILE: lib/common/Base16StringStream.cpp ================================================ #include std::streambuf::int_type Base16StreamBuf::overflow(std::streambuf::int_type c) { if (c != EOF) { _string += "0123456789ABCDEF"[(c & 0xF0) >> 4]; _string += "0123456789ABCDEF"[c & 0x0F]; } return c; } void Base16DecoderStream::Base16Decode(const std::string &in, char *out) { const char map[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15}; for (int i = 0; i < in.size(); i += 2) { out[i / 2] = (map[in[i] - 48] << 4) | (map[in[i + 1] - 48]); } } Base16DecoderStream::Base16DecoderStream(const std::string &s) : std::istream(&_buf), _data(new char[s.size() / 2]), _buf(_data.get(), s.size() / 2) { Base16Decode(s, _data.get()); } ================================================ FILE: lib/common/CFuncs.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #ifdef Darwin #include #endif #include #include #ifdef WIN32 #include "windows.h" #include "Winbase.h" #pragma warning(disable : 4996) #endif namespace { #ifdef WIN32 string Separator = "\\"; #else string Separator = "/"; #endif }; // namespace using namespace Wasp; using namespace std; void Wasp::Splitpath(string path, string &volume, string &dir, string &file, bool nofile) { volume.clear(); dir.clear(); file.clear(); #ifdef WIN32 char drive_buf[_MAX_DRIVE]; char dir_buf[_MAX_DIR]; char fname_buf[_MAX_FNAME]; char ext_buf[_MAX_EXT]; _splitpath(path.c_str(), drive_buf, dir_buf, fname_buf, ext_buf); volume = drive_buf; dir = dir_buf; file = fname_buf; file += ext_buf; #else if (nofile || (path.substr(path.size() - 1, 1) == "/") || (path.substr(path.size() - 2, 2) == "/.") || (path.substr(path.size() - 3, 3) == "/..")) { dir = path; } else { dir = Wasp::FileUtils::Dirname(path); file = Wasp::FileUtils::Basename(path); } #endif } /* bool Wasp::IsAbsPath(string path) { string vol, dir, fname; Splitpath(path, vol, dir, fname, true); return(dir.substr(0,1) == Separator); } */ double Wasp::GetTime() { double t = -1.0; #ifdef WIN32 // Windows does not have a nanosecond time function... SYSTEMTIME sTime; FILETIME fTime; GetSystemTime(&sTime); SystemTimeToFileTime(&sTime, &fTime); // Resulting system time is in 100ns increments __int64 longlongtime = fTime.dwHighDateTime; longlongtime <<= 32; longlongtime += fTime.dwLowDateTime; t = (double)longlongtime; t *= 1.e-7; #endif #ifndef WIN32 struct timespec ts; ts.tv_sec = ts.tv_nsec = 0; #endif #if defined(__linux__) || defined(AIX) clock_gettime(CLOCK_REALTIME, &ts); t = (double)ts.tv_sec + (double)ts.tv_nsec * 1.0e-9; #endif #ifdef Darwin uint64_t tmac = mach_absolute_time(); mach_timebase_info_data_t info = {0, 0}; mach_timebase_info(&info); ts.tv_sec = tmac * 1e-9; ts.tv_nsec = tmac - (ts.tv_sec * 1e9); t = (double)ts.tv_sec + (double)ts.tv_nsec * 1.0e-9; #endif return (t); } int Wasp::MkDirHier(const string &dir) { return FileUtils::MakeDir(dir); } std::string Wasp::GetEnvironmentalVariable(const std::string &name) { const char *env = getenv(name.c_str()); if (env) return string(env); else return ""; } ================================================ FILE: lib/common/CMakeConfig.cpp.in ================================================ #include "vapor/CMakeConfig.h" const int MAJOR = @VERSION_MAJOR@; const int MINOR = @VERSION_MINOR@; const int MICRO = @VERSION_MICRO@; const CMakeConfigStringType VERSION_RC = "@VERSION_RC@"; const CMakeConfigStringType VERSION_DATE = "@VERSION_DATE@"; const CMakeConfigStringType VERSION_COMMIT = "@VERSION_COMMIT@"; const CMakeConfigStringType VERSION_STRING = "@VERSION_STRING@"; const CMakeConfigStringType VERSION_STRING_FULL = "@VERSION_STRING_FULL@"; const CMakeConfigStringType BUILD_TYPE = "@CMAKE_BUILD_TYPE@"; const CMakeConfigStringType SOURCE_DIR = "@PROJECT_SOURCE_DIR@"; const CMakeConfigStringType THIRD_PARTY_DIR = "@THIRD_PARTY_DIR@"; const CMakeConfigStringType PYTHON_VERSION = "@Python_VERSION@"; const CMakeConfigStringType PYTHON_DIR = "@PYTHONDIR@"; const CMakeConfigStringType PYTHON_PATH = "@PYTHONPATH@"; ================================================ FILE: lib/common/CMakeLists.txt ================================================ configure_file (CMakeConfig.cpp.in CMakeConfig.cpp) set (SRC common.cpp MyBase.cpp OptionParser.cpp EasyThreads.cpp CFuncs.cpp Version.cpp PVTime.cpp GetAppPath.cpp utils.cpp FileUtils.cpp ResourcePath.cpp LegacyVectorMath.cpp STLUtils.cpp VAssert.cpp Progress.cpp TMSUtils.cpp Base16StringStream.cpp ${CMAKE_CURRENT_BINARY_DIR}/CMakeConfig.cpp ) set (HEADERS ${PROJECT_SOURCE_DIR}/include/vapor/common.h ${PROJECT_SOURCE_DIR}/include/vapor/MyBase.h ${PROJECT_SOURCE_DIR}/include/vapor/OptionParser.h ${PROJECT_SOURCE_DIR}/include/vapor/EasyThreads.h ${PROJECT_SOURCE_DIR}/include/vapor/CFuncs.h ${PROJECT_SOURCE_DIR}/include/vapor/Version.h ${PROJECT_SOURCE_DIR}/include/vapor/PVTime.h ${PROJECT_SOURCE_DIR}/include/vapor/GetAppPath.h ${PROJECT_SOURCE_DIR}/include/vapor/utils.h ${PROJECT_SOURCE_DIR}/include/vapor/CMakeConfig.h ${PROJECT_SOURCE_DIR}/include/vapor/debug.h ${PROJECT_SOURCE_DIR}/include/vapor/FileUtils.h ${PROJECT_SOURCE_DIR}/include/vapor/ResourcePath.h ${PROJECT_SOURCE_DIR}/include/vapor/LegacyVectorMath.h ${PROJECT_SOURCE_DIR}/include/vapor/STLUtils.h ${PROJECT_SOURCE_DIR}/include/vapor/NonCopyableMixin.h ${PROJECT_SOURCE_DIR}/include/vapor/VAssert.h ${PROJECT_SOURCE_DIR}/include/vapor/Progress.h ${PROJECT_SOURCE_DIR}/include/vapor/TMSUtils.h ${PROJECT_SOURCE_DIR}/include/vapor/Base16StringStream.h ) add_library (common SHARED ${SRC} ${HEADERS}) if (APPLE) find_library (COREFOUNDATION CoreFoundation) target_link_libraries (common ${COREFOUNDATION}) endif() if (CONDA_BUILD AND UNIX AND NOT APPLE) target_link_libraries (common rt) endif() if (NOT WIN32) target_link_libraries (common pthread ${HDF5_LIB}) add_definitions (-DENABLE_THREADS) endif() add_definitions (-DCOMMON_EXPORTS) # This is necessary because we include external header files in our headers target_include_directories (common PUBLIC "${PROJECT_SOURCE_DIR}/include" PUBLIC "${THIRD_PARTY_INC_DIR}" PUBLIC "${THIRD_PARTY_INC_DIR}/freetype2" ) install ( TARGETS common DESTINATION ${INSTALL_LIB_DIR} COMPONENT Libraries ) install ( FILES ${HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR} COMPONENT Libraries ) # Not needed since vapor shares include directory # target_include_directories (common PUBLIC ${VAPOR_SOURCE_DIR}/include) ================================================ FILE: lib/common/EasyThreads.cpp ================================================ #include #include #include #include #include #ifndef WIN32 #include #endif #include //#include using namespace Wasp; #ifdef ENABLE_THREADS #ifdef WIN32 typedef void *(*tfuncp)(void *); DWORD WINAPI runner(void *arg) { void **info = (void **)arg; tfuncp func = (tfuncp)info[0]; // if(info[1]) info[1] = *((void**)info[1]); HANDLE *mutices = (HANDLE *)info[2]; int nthreads = (int)info[3]; // lock one of the notifier mutices for (int i = 0; i < nthreads; i++) { if (WaitForSingleObject(mutices[i], 0) == 0) break; if (i == nthreads - 1) printf("EasyThreads: Failed to lock block mutex!"); } // run the function func(info[1]); delete[] arg; for (int i = 0; i < nthreads; i++) { if (ReleaseMutex(mutices[i]) == TRUE) break; } return 0; } #endif #endif EasyThreads::EasyThreads(int nthreads) { #ifndef WIN32 nthreads_c = 0; threads_c = NULL; block_c = 0; count_c = 0; #else nthreads_c = 0; threads_c = NULL; initialized_c = false; nblocked_c = 0; mutices_c = NULL; bMutices_c = NULL; mutex_c = NULL; bMutex_c = NULL; #endif #ifdef ENABLE_THREADS if (nthreads < 1) nthreads = NProc(); if (char *s = getenv("VAPOR_NTHREADS")) { istringstream ist(s); ist >> nthreads; cout << "VAPOR_NTHREADS = " << nthreads << endl; } #ifndef WIN32 int rc; threads_c = NULL; block_c = 0; count_c = 0; nthreads_c = nthreads; rc = pthread_attr_init(&attr_c); if (rc < 0) { SetErrMsg("pthread_attr_init() : %s", strerror(errno)); return; } rc = pthread_cond_init(&cond_c, NULL); if (rc < 0) { SetErrMsg("pthread_cond_init() : %s", strerror(errno)); return; } rc = pthread_mutex_init(&barrier_lock_c, NULL); if (rc < 0) { SetErrMsg("pthread_mutex_init() : %s", strerror(errno)); return; } rc = pthread_mutex_init(&mutex_lock_c, NULL); if (rc < 0) { SetErrMsg("pthread_mutex_init() : %s", strerror(errno)); return; } pthread_attr_setdetachstate(&attr_c, PTHREAD_CREATE_JOINABLE); if (rc < 0) { SetErrMsg("pthread_attr_setdetachstate() : %s", strerror(errno)); return; } #ifdef __sgi rc = pthread_attr_setscope(&attr_c, PTHREAD_SCOPE_BOUND_NP); #else rc = pthread_attr_setscope(&attr_c, PTHREAD_SCOPE_SYSTEM); #endif if (rc < 0) { SetErrMsg("pthread_attr_setscope() : %s", strerror(errno)); return; } threads_c = new pthread_t[nthreads_c]; #else // WIN32 // make sure we know if initialization failed. initialized_c = false; // initialize basic fields nthreads_c = nthreads; nblocked_c = 0; // initialize threads and mutices threads_c = new HANDLE[nthreads_c]; mutices_c = new HANDLE[nthreads_c]; bMutices_c = new HANDLE[nthreads_c]; for (int i = 0; i < nthreads_c; i++) { // Set up each mutex. If it's NULL, exit without setting initialized if ((mutices_c[i] = CreateMutex(NULL, FALSE, NULL)) == NULL) { SetErrMsg("EasyThreads: Failed to initialize mutices (notifier)!\n"); return; } } for (int i = 0; i < nthreads_c; i++) { // Set up each mutex. If it's NULL, exit without setting initialized if ((bMutices_c[i] = CreateMutex(NULL, FALSE, NULL)) == NULL) { SetErrMsg("EasyThreads: Failed to initialize mutices (blocker)!\n"); return; } } if ((mutex_c = CreateMutex(NULL, FALSE, "main_mutex")) == NULL) { SetErrMsg("EasyThreads: Failed to initialize mutices (main)!\n"); return; } if ((bMutex_c = CreateMutex(NULL, FALSE, "barrier_mutex")) == NULL) { SetErrMsg("EasyThreads: Failed to initialize mutices (barrier)!\n"); return; } // initialization succeeded! initialized_c = true; #endif // OS-switch #endif // ENABLE_THREADS } EasyThreads::~EasyThreads() { #ifdef ENABLE_THREADS #ifndef WIN32 // Mac, Linux pthread_attr_destroy(&attr_c); if (threads_c) delete[] threads_c; threads_c = NULL; #else // Windows // close any mutices for (int i = 0; i < nthreads_c && mutices_c[i] != NULL; i++) { CloseHandle(mutices_c[i]); } for (int i = 0; i < nthreads_c && bMutices_c[i] != NULL; i++) { CloseHandle(bMutices_c[i]); } if (mutex_c != NULL) CloseHandle(mutex_c); if (bMutex_c != NULL) CloseHandle(bMutex_c); // deallocate arrays delete[] threads_c; delete[] bMutices_c; delete[] mutices_c; #endif // OS-switch #endif // ENABLE_THREADS } int EasyThreads::ParRun(void *(*start)(void *), void **arg) { vector argvec; for (int i = 0; i < nthreads_c; i++) argvec.push_back(arg[i]); return (EasyThreads::ParRun(start, argvec)); } int EasyThreads::ParRun(void *(*start)(void *), std::vector argvec) { #ifdef ENABLE_THREADS #ifndef WIN32 int i; int rc; int status = 0; for (i = 0; i < nthreads_c; i++) { rc = pthread_create(&threads_c[i], &attr_c, start, argvec[i]); if (rc < 0) { SetErrMsg("pthread_create() : %s", strerror(errno)); return (-1); } } for (i = 0; i < nthreads_c; i++) { rc = pthread_join(threads_c[i], NULL); if (rc < 0) { SetErrMsg("pthread_join() : %s", strerror(errno)); status = rc; } } return (status); #else // WIN32 if (!initialized_c) return -1; for (int i = 0; i < nthreads_c; i++) { // parse the arguments into a package for the runner void **info = new void *[4]; // TODO: Move to stack info[0] = (void *)start; info[1] = argvec[i]; info[2] = (void *)mutices_c; info[3] = (void *)nthreads_c; // launch the runners if ((threads_c[i] = CreateThread(NULL, 0, runner, (void *)info, 0, NULL)) == NULL) { // if any of them fail, close all of them and return an error code. for (; i >= 0; i--) { if (TerminateThread(threads_c[i], 0) == FALSE) { printf("EasyThreads: Failed to terminate thread after some failed to start!\n"); } } delete[] info; SetErrMsg("EasyThreads: Failed to start threads.\n"); return -1; } } // wait for the threads to finish, and then return success WaitForMultipleObjects(nthreads_c, threads_c, TRUE, INFINITE); return 0; #endif #else return 0; #endif } int EasyThreads::Barrier() { #ifdef ENABLE_THREADS #ifndef WIN32 int local; int rc; if (nthreads_c > 1) { rc = pthread_mutex_lock(&barrier_lock_c); if (rc < 0) { SetErrMsg("pthread_mutex_lock() : %s", strerror(errno)); return (-1); } local = count_c; block_c++; if (block_c == nthreads_c) { block_c = 0; count_c++; rc = pthread_cond_broadcast(&cond_c); if (rc < 0) { SetErrMsg("pthread_cond_broadcast() : %s", strerror(errno)); return (-1); } } while (local == count_c) { rc = pthread_cond_wait(&cond_c, &barrier_lock_c); if (rc < 0) { SetErrMsg("pthread_cond_wait() : %s", strerror(errno)); return (-1); } } rc = pthread_mutex_unlock(&barrier_lock_c); if (rc < 0) { SetErrMsg("pthread_mutex_unlock() : %s", strerror(errno)); return (-1); } } #else // WIN32 // In the windows implementation, the first thread to arrive locks all of the barrier mutices, then lets the other threads in. // The other threads then release their notifier mutices to notify the first thread that they've arrived. // Once the first thread owns all the notifier mutices, it releases the blocker and notifier mutices, and the other threads now each own a blocker mutex. // When the other threads own a blocker mutex, they release it and relock their notifier mutices. int status = 0; if (!initialized_c) return -1; if (nthreads_c == 1) return 0; if (WaitForSingleObject(bMutex_c, INFINITE) != 0) { printf("EasyThreads: Failed to lock barrier mutex!\n"); } nblocked_c++; // printf("NUM: %d\n", nblocked_c); // if we arrived first, set up the wait sequence for the others. if (nblocked_c == 1) { // printf("First thread has arrived at barrier.\n"); if (WaitForMultipleObjects(nthreads_c, bMutices_c, TRUE, 0) != 0) { printf("EasyThreads: Failed to lock blocker mutices in barrier (early)!\n"); status |= 1; } // printf("First thread has locked the blocker mutices.\n"); if (ReleaseMutex(bMutex_c) == 0) { printf("EasyThreads: Failed to release barrier function mutex (early)!\n"); status |= 2; } // printf("First thread has released the barrier function mutex.\n"); if (WaitForMultipleObjects(nthreads_c, mutices_c, TRUE, INFINITE) != 0) { printf("EasyThreads: Failed to lock notifier mutices in barrier (early)!\n"); status |= 4; } // printf("First thread has locked the notifier mutices.\n"); for (int i = 0; i < nthreads_c; i++) { if (ReleaseMutex(mutices_c[i]) == 0) { printf("EasyThreads: Failed to release notifier mutices in barrier (early)!\n"); status |= 8; } } // printf("First thread has unlocked the notifier mutices.\n"); for (int i = 0; i < nthreads_c; i++) { if (ReleaseMutex(bMutices_c[i]) == 0) { printf("EasyThreads: Failed to release blocker mutices in barrier (early)!\n"); status |= 16; } } // printf("First thread has unlocked the blocker mutices.\n"); } else { int n; for (n = 0; n < nthreads_c; n++) { if (ReleaseMutex(mutices_c[n]) != 0) break; if (n == nthreads_c - 1) { printf("EasyThreads: Failed to release notifier mutex (late)!\n"); status |= 32; } } // printf("Thread %d has released its notifier mutex.\n", n); if (ReleaseMutex(bMutex_c) == 0) { printf("EasyThreads: Failed to release barrier function mutex (late)!\n"); status |= 64; } // printf("Thread %d has released the barrier function mutex.\n", n); if (WaitForSingleObject(bMutices_c[n], INFINITE) != 0) { printf("EasyThreads: Failed to lock blocker mutex in barrier (late)!\n"); status |= 128; } // printf("Thread %d has locked its blocker mutex.\n", n); if (ReleaseMutex(bMutices_c[n]) == 0) { printf("EasyThreads: Failed to release blocker mutex in barrier (late)!\n"); status |= 256; } // printf("Thread %d has released its blocker mutex.\n", n); if (WaitForSingleObject(mutices_c[n], 0) != 0) { printf("EasyThreads: Unable to re-lock notifier mutex (late)!\n"); status |= 512; } // printf("Thread %d has locked its notifier mutex.\n", n); } nblocked_c--; return -status; #endif #endif // ENABLE_THREADS return (0); } int EasyThreads::MutexLock() { #ifdef ENABLE_THREADS #ifndef WIN32 if (nthreads_c > 1) { int rc = pthread_mutex_lock(&mutex_lock_c); if (rc < 0) { SetErrMsg("pthread_mutex_lock() : %s", strerror(errno)); return (-1); } } #else // WIN32 if (!initialized_c) return -1; int result = WaitForSingleObject(mutex_c, INFINITE); return result != 0 ? -1 : 0; #endif #endif return (0); } int EasyThreads::MutexUnlock() { #ifdef ENABLE_THREADS #ifndef WIN32 if (nthreads_c > 1) { int rc = pthread_mutex_unlock(&mutex_lock_c); if (rc < 0) { SetErrMsg("pthread_mutex_unlock() : %s", strerror(errno)); return (-1); } } #else if (!initialized_c) return -1; return (int)ReleaseMutex(mutex_c) - 1; #endif #endif return (0); } void EasyThreads::Decompose(int n, int size, int rank, int *offset, int *length) { int remainder = n % size; int chunk = n / size; if (rank < remainder) { *length = chunk + 1; *offset = (chunk + 1) * rank; } else { *length = chunk; *offset = (chunk + 1) * remainder + (rank - remainder) * chunk; } } int EasyThreads::NProc() { #ifdef ENABLE_THREADS #ifndef WIN32 #ifdef __sgi return (sysconf(_SC_NPROC_ONLN)); #else return (sysconf(_SC_NPROCESSORS_ONLN)); #endif #else // WIN32 SYSTEM_INFO info; GetSystemInfo(&info); return info.dwNumberOfProcessors; #endif #else return 1; #endif // ENABLE_THREADS } ================================================ FILE: lib/common/FileUtils.cpp ================================================ #include "vapor/FileUtils.h" #include "vapor/STLUtils.h" #include #include #include #include #ifdef WIN32 #include #include #else #include #include #include #include #endif using namespace Wasp; using FileUtils::FileType; using std::string; #ifdef WIN32 const string FileUtils::Separator = "\\"; #else const string FileUtils::Separator = "/"; #endif string FileUtils::ReadFileToString(const string &path) { FILE *f = fopen(path.c_str(), "r"); if (f) { fseek(f, 0, SEEK_END); long length = ftell(f); rewind(f); char * buf = new char[length + 1]; size_t rv = fread(buf, length, 1, f); fclose(f); if (rv != 1) { delete[] buf; return string(""); } buf[length] = 0; string ret(buf); delete[] buf; return ret; } else { return ""; } } std::string FileUtils::HomeDir() { #ifdef WIN32 return string(getenv("USERPROFILE")); #else if (getenv("HOME")) return string(getenv("HOME")); const struct passwd *pw = getpwuid(getuid()); const char * homeDir = pw->pw_dir; return string(homeDir); #endif } std::string FileUtils::Basename(const std::string &path) { #ifdef WIN32 char fileName[_MAX_FNAME]; char extension[_MAX_EXT]; _splitpath_s(CleanupPath(path).c_str(), NULL, 0, NULL, 0, fileName, _MAX_FNAME, extension, _MAX_EXT); return string(fileName) + string(extension); #else char * copy = strdup(path.c_str()); string ret(basename(copy)); free(copy); return ret; #endif } std::string FileUtils::Dirname(const std::string &path) { #ifdef WIN32 char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; _splitpath_s(CleanupPath(path).c_str(), drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0); return CleanupPath(string(drive) + string(dir)); #else char * copy = strdup(path.c_str()); string ret(dirname(copy)); free(copy); return ret; #endif } std::string FileUtils::Realpath(const std::string &path) { #ifdef WIN32 char real[_MAX_PATH]; if(_fullpath(real, path.c_str(), _MAX_PATH)) return string(real); return path; #else char real[PATH_MAX]; if (realpath(path.c_str(), real)) return string(real); return path; #endif } std::string FileUtils::Relpath(std::string path, std::string to) { path = Realpath(path); to = Realpath(to); if (!IsDirectory(to)) to = Dirname(to); auto common = CommonAncestor({path, to}); auto commonLevels = SplitPath(common).size(); path = JoinPaths(STLUtils::Slice(SplitPath(path), commonLevels)); to = JoinPaths(STLUtils::Slice(SplitPath(to), commonLevels)); for (const auto &_ : SplitPath(to)) { (void)_; path = JoinPaths({"..", path}); } return path; } std::string FileUtils::CommonAncestor(const std::vector &paths_) { if (paths_.empty()) return ""; std::vector> paths; for (const auto &path : paths_) paths.push_back(SplitPath(path)); int min_depth = 100000; for (const auto &path : paths) min_depth = min(min_depth, (int)path.size()); int same_depth = 0; for (int i = 0; i < min_depth; i++) { for (const auto &path: paths) if (path[i] != paths[0][i]) goto stop; same_depth = i+1; } stop: if (same_depth <= 0) return ""; return JoinPaths(std::vector(paths[0].begin(), paths[0].begin() + same_depth)); } std::string FileUtils::Extension(const std::string &path) { string basename = Basename(path); size_t index = basename.rfind("."); if (index == string::npos || index == 0) // dotfile return ""; return basename.substr(index + 1); } std::string FileUtils::RemoveExtension(const std::string &path) { const string extension = Extension(path); if (extension.empty()) return path; return path.substr(0, path.size() - Extension(path).size() - 1); } std::string FileUtils::POSIXPathToWindows(std::string path) { std::replace(path.begin(), path.end(), '/', '\\'); return path; } std::string FileUtils::POSIXPathToCurrentOS(const std::string &path) { #ifdef WIN32 return POSIXPathToWindows(path); #else return path; #endif } std::string FileUtils::CleanupPath(std::string path) { #ifdef WIN32 std::replace(path.begin(), path.end(), '\\', '/'); #endif while (path.length() > 1 && (path.back() == '/' || path.back() == '\\')) path.pop_back(); while (path.find("//") != std::string::npos) path = STLUtils::ReplaceAll(path, "//", "/"); if (path == "") path = ""; return path; } long FileUtils::GetFileModifiedTime(const string &path) { struct STAT64 attrib; STAT64(path.c_str(), &attrib); return attrib.st_mtime; } bool FileUtils::IsPathAbsolute(const std::string &path) { #ifdef WIN32 char dir[_MAX_DIR]; _splitpath_s(path.c_str(), NULL, 0, dir, _MAX_DIR, NULL, 0, NULL, 0); return dir[0] == '/' || dir[0] == '\\'; #else return path[0] == '/'; #endif } bool FileUtils::Exists(const std::string &path) { return FileUtils::GetFileType(path) != FileType::Does_Not_Exist; } bool FileUtils::IsRegularFile(const std::string &path) { return FileUtils::GetFileType(path) == FileType::File; } bool FileUtils::IsDirectory(const std::string &path) { return FileUtils::GetFileType(path) == FileType::Directory; } bool FileUtils::IsSubpath(const std::string &dir, const std::string &path){ return STLUtils::BeginsWith(FileUtils::SplitPath(path), FileUtils::SplitPath(dir)); } #ifndef WIN32 static unsigned long long GetFileInode(const std::string &path) { struct STAT64 s; if (STAT64(path.c_str(), &s) != 0) return 0; return s.st_ino; } #endif bool FileUtils::AreSameFile(const std::string &pathA, const std::string &pathB) { #ifdef WIN32 if (Realpath(pathA) != Realpath(pathB)) return false; if (GetFileType(pathA) != GetFileType(pathB)) return false; if (!IsDirectory(pathA) && GetFileSize(pathA) != GetFileSize(pathB)) return false; if (GetFileModifiedTime(pathA) != GetFileModifiedTime(pathB)) return false; return true; #else return GetFileInode(pathA) == GetFileInode(pathB); #endif } FileType FileUtils::GetFileType(const std::string &path) { struct STAT64 s; if (STAT64(path.c_str(), &s) == 0) { if (s.st_mode & S_IFDIR) return FileType::Directory; else if (s.st_mode & S_IFREG) return FileType::File; else return FileType::Other; } else return FileType::Does_Not_Exist; } long long FileUtils::GetFileSize(const std::string &path) { struct STAT64 s; if (STAT64(path.c_str(), &s) != 0) return -1; return s.st_size; } std::vector FileUtils::ListFiles(const std::string &path) { #ifdef WIN32 WIN32_FIND_DATA find; HANDLE h; vector fileNames; string searchPath = path + "\\*"; h = FindFirstFile(searchPath.c_str(), &find); if (h != INVALID_HANDLE_VALUE) { do { const string name(find.cFileName); if (name == ".") continue; if (name == "..") continue; fileNames.push_back(name); } while (FindNextFile(h, &find)); } FindClose(h); return fileNames; #else DIR *dir = opendir(path.c_str()); if (!dir) return {}; struct dirent *ent; vector fileNames; while ((ent = readdir(dir))) { const string name = ent->d_name; if (name == ".") continue; if (name == "..") continue; fileNames.push_back(name); } closedir(dir); return fileNames; #endif } std::string FileUtils::JoinPaths(const std::vector &paths) { string path; for (auto it = paths.begin(); it != paths.end(); ++it) { if (!it->empty()) { if (!path.empty()) path += Separator; path += *it; } } return CleanupPath(path); } std::vector FileUtils::SplitPath(std::string path) { std::replace(path.begin(), path.end(), '\\', '/'); auto parts = STLUtils::Split(CleanupPath(path), "/"); if (!path.empty() && path[0] == '/') parts[0] = "/"; return STLUtils::Filter(parts, [](const std::string &s) { return !s.empty(); }); } int FileUtils::MakeDir(const std::string &path) { if (IsDirectory(path)) return 0; if (!Exists(Dirname(path))) MakeDir(Dirname(path)); #if WIN32 return _mkdir(path.c_str()); #else return mkdir(path.c_str(), 0755); #endif } const char *FileUtils::LegacyBasename(const char *path) { const char *last; last = strrchr(path, Separator[0]); if (!last) return path; else return last + 1; } ================================================ FILE: lib/common/GetAppPath.cpp ================================================ // // $Id$ // #include #include #include #include #include #include "vapor/CMakeConfig.h" #include "vapor/FileUtils.h" #ifdef Darwin #include #include #include #endif #include #define INCLUDE_DEPRECATED_GET_APP_PATH #include "vapor/GetAppPath.h" #ifdef WIN32 #pragma warning(disable : 4996) #endif using namespace std; using namespace Wasp; #ifdef Darwin string get_path_from_bundle(const string &app) { string path; path.clear(); string bundlename = app + ".app"; // // Get path to document directory from the application "Bundle"; // CFBundleRef mainBundle = CFBundleGetMainBundle(); if (!mainBundle) return ("."); CFURLRef url = CFBundleCopyBundleURL(mainBundle); if (!url) return ("."); const int kBufferLength = 1024; UInt8 buffer[kBufferLength]; char componentStr[kBufferLength]; CFIndex componentLength = CFURLGetBytes(url, buffer, kBufferLength); if (componentLength < 0) return (""); buffer[componentLength] = 0; CFRange range; CFRange rangeIncludingSeparators; range = CFURLGetByteRangeForComponent(url, kCFURLComponentPath, &rangeIncludingSeparators); if (range.location == kCFNotFound) return ("."); strncpy(componentStr, (const char *)&buffer[range.location], range.length); componentStr[range.length] = 0; string s = componentStr; // Spaces are returned as %20. Quick fix below size_t start; while ((start = s.find("%20")) != std::string::npos) s.replace(start, 3, " "); path = s; return (path); } #endif bool pathExists(const string path) { struct STAT64 statbuf; return STAT64(path.c_str(), &statbuf) >= 0; } std::string Wasp::GetAppPath(const string &app, const string &resource, const vector &paths, bool forwardSeparator) { string myResource = resource; #ifndef Darwin if (myResource == "home") { myResource.clear(); } #endif ostringstream oss; oss << "GetAppPath(" << app << ", " << myResource; for (int i = 0; i < paths.size(); i++) { oss << ", " << paths[i]; } oss << ")" << endl; MyBase::SetDiagMsg("%s", oss.str().c_str()); string separator, otherSeparator; if (!forwardSeparator) { separator = "\\"; otherSeparator = "/"; } else { separator = "/"; otherSeparator = "\\"; } string path; path.clear(); string myapp = app; // upper case app name for (string::iterator itr = myapp.begin(); itr != myapp.end(); itr++) { if (islower(*itr)) *itr = toupper(*itr); } string env(myapp); #ifdef WIN32 env.append("3"); #endif env.append("_HOME"); if (!((myResource.compare("lib") == 0) || (myResource.compare("bin") == 0) || (myResource.compare("share") == 0) || (myResource.compare("plugins") == 0) || (myResource.compare("home") == 0) || (myResource.compare("") == 0))) { MyBase::SetDiagMsg("GetAppPath() return : empty (unknown resources)"); return (""); // empty path, invalid resource } char *homestr = getenv(env.c_str()); #ifdef Darwin if (homestr) { string s = homestr; if (s.find(".app") != string::npos) { path.assign(homestr); path.append(separator); homestr = NULL; } } #endif if (homestr) { path.assign(homestr); if (!myResource.empty()) { path.append(separator); path.append(myResource); } } #ifdef Darwin else { if (path.empty()) { path = get_path_from_bundle(myapp); } if (!path.empty()) { path.append("Contents/"); if ((myResource.compare("bin") == 0) || (myResource.compare("") == 0)) { path.append("MacOS"); } else if (myResource.compare("share") == 0) { path.append("share"); } else if (myResource.compare("lib") == 0) { path.append("lib"); } else if (myResource.compare("Frameworks") == 0) { path.append("Frameworks"); } else if (myResource.compare("Resources") == 0) { path.append("Resources"); } else if (myResource.compare("home") == 0) { path.erase(path.size() - 1, 1); } else { // must be plugins path.append("Plugins"); } } } #endif if (!pathExists(path)) { path = ""; } if (path.empty()) { if (myResource.compare("share") == 0) { path.append(SOURCE_DIR); path.append(separator); path.append("share"); } } if (path.empty()) { MyBase::SetDiagMsg("GetAppPath() return : empty (path empty)"); return (path); } // We may need to reverse the slashes in vapor_home bool foundSep = true; while (foundSep) { std::size_t found = path.find(otherSeparator); if (found != std::string::npos) { path.replace(found, 1, separator); } else foundSep = false; } for (int i = 0; i < paths.size(); i++) { path.append(separator); path.append(paths[i]); } if (!pathExists(path)) { MyBase::SetDiagMsg("GetAppPath() return : empty (path does not exist)"); return (""); } MyBase::SetDiagMsg("GetAppPath() return : %s", path.c_str()); return (path); } ================================================ FILE: lib/common/LegacyVectorMath.cpp ================================================ #define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH #include #include "vapor/VAssert.h" #include #include #include using std::string; using std::vector; /* The Identity matrix is useful for intializing transformations. */ namespace { float idmatrix[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, }; double idmatrixd[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, }; }; // namespace namespace VAPoR { void vscale(float *v, float s) { /* Scale the vector v in all directions by s. */ v[0] *= s; v[1] *= s; v[2] *= s; } void vscale(double *v, double s) { /* Scale the vector v in all directions by s. */ v[0] *= s; v[1] *= s; v[2] *= s; } void vscale(vector v, double s) { /* Scale the vector v in all directions by s. */ v[0] *= s; v[1] *= s; v[2] *= s; } // Scale, putting result in another vector // void vmult(const float *v, float s, float *w) { w[0] = s * v[0]; w[1] = s * v[1]; w[2] = s * v[2]; } // Scale, putting result in another vector // void vmult(const double *v, double s, double *w) { w[0] = s * v[0]; w[1] = s * v[1]; w[2] = s * v[2]; } void vhalf(const float *v1, const float *v2, float *half) { /* Return in 'half' the unit vector * half way between v1 and v2. half can be v1 or v2. */ float len; vadd(v2, v1, half); len = vlength(half); if (len > 0) vscale(half, 1 / len); else vcopy(v1, half); } void vcross(const float *v1, const float *v2, float *cross) { /* Vector cross product. */ float temp[3]; temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]); temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]); temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]); vcopy(temp, cross); } void vcross(const double *v1, const double *v2, double *cross) { /* Vector cross product. */ double temp[3]; temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]); temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]); temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]); vcopy(temp, cross); } void vreflect(const float *in, const float *mirror, float *out) { /* Mirror defines a plane across which in is reflected. */ float temp[3]; vcopy(mirror, temp); vscale(temp, vdot(mirror, in)); vsub(temp, in, out); vadd(temp, out, out); } void vtransform(const float *v, float mat[12], float *vt) { /* Vector transform in software... */ float t[3]; t[0] = v[0] * mat[0] + v[1] * mat[1] + v[2] * mat[2] + mat[3]; t[1] = v[0] * mat[4] + v[1] * mat[5] + v[2] * mat[6] + mat[7]; t[2] = v[0] * mat[8] + v[1] * mat[9] + v[2] * mat[10] + mat[11]; vcopy(t, vt); } void vtransform(const float *v, float mat[12], double *vt) { /* Vector transform in software... */ double t[3]; t[0] = v[0] * mat[0] + v[1] * mat[1] + v[2] * mat[2] + mat[3]; t[1] = v[0] * mat[4] + v[1] * mat[5] + v[2] * mat[6] + mat[7]; t[2] = v[0] * mat[8] + v[1] * mat[9] + v[2] * mat[10] + mat[11]; vcopy(t, vt); } void vtransform(const double *v, float mat[12], double *vt) { /* Vector transform in software... */ double t[3]; t[0] = v[0] * mat[0] + v[1] * mat[1] + v[2] * mat[2] + mat[3]; t[1] = v[0] * mat[4] + v[1] * mat[5] + v[2] * mat[6] + mat[7]; t[2] = v[0] * mat[8] + v[1] * mat[9] + v[2] * mat[10] + mat[11]; vcopy(t, vt); } void vtransform(const double *v, double mat[12], double *vt) { /* Vector transform in software... */ double t[3]; t[0] = v[0] * mat[0] + v[1] * mat[1] + v[2] * mat[2] + mat[3]; t[1] = v[0] * mat[4] + v[1] * mat[5] + v[2] * mat[6] + mat[7]; t[2] = v[0] * mat[8] + v[1] * mat[9] + v[2] * mat[10] + mat[11]; vcopy(t, vt); } void vtransform4(const float *v, float *mat, float *vt) { /* Homogeneous coordinates. */ float t[4]; t[0] = v[0] * mat[0] + v[1] * mat[1] + v[2] * mat[2] + mat[3]; t[1] = v[0] * mat[4] + v[1] * mat[5] + v[2] * mat[6] + mat[7]; t[2] = v[0] * mat[8] + v[1] * mat[9] + v[2] * mat[10] + mat[11]; t[3] = v[0] * mat[12] + v[1] * mat[13] + v[2] * mat[14] + mat[15]; qcopy(t, vt); } void vtransform3(const float *v, float *mat, float *vt) { /* 3x3 matrix multiply */ vt[0] = v[0] * mat[0] + v[1] * mat[1] + v[2] * mat[2]; vt[1] = v[0] * mat[3] + v[1] * mat[4] + v[2] * mat[5]; vt[2] = v[0] * mat[6] + v[1] * mat[7] + v[2] * mat[8]; } void vtransform3(const double *v, double *mat, double *vt) { /* 3x3 matrix multiply */ vt[0] = v[0] * mat[0] + v[1] * mat[1] + v[2] * mat[2]; vt[1] = v[0] * mat[3] + v[1] * mat[4] + v[2] * mat[5]; vt[2] = v[0] * mat[6] + v[1] * mat[7] + v[2] * mat[8]; } void vtransform3t(const float *v, float *mat, float *vt) { /* 3x3 matrix multiply, using transpose of matrix */ vt[0] = v[0] * mat[0] + v[1] * mat[3] + v[2] * mat[6]; vt[1] = v[0] * mat[1] + v[1] * mat[4] + v[2] * mat[7]; vt[2] = v[0] * mat[2] + v[1] * mat[5] + v[2] * mat[8]; } // Test whether a planar point is right (or left) of the oriented line from // pt1 to pt2 bool pointOnRight(double *pt1, double *pt2, const double *testPt) { float rhs = pt1[0] * (pt1[1] - pt2[1]) + pt1[1] * (pt2[0] - pt1[0]); float test = (pt2[0] - pt1[0]) * testPt[1] + (pt1[1] - pt2[1]) * testPt[0] - rhs; return (test < 0.f); } void mcopy(float *m1, float *m2) { /* Copy a 4x4 matrix */ int row; for (row = 0; row < 16; row++) m2[row] = m1[row]; } void mcopy(double *m1, double *m2) { /* Copy a 4x4 matrix */ int row; for (row = 0; row < 16; row++) m2[row] = m1[row]; } void mmult(float *m1, float *m2, float *prod) { /* Multiply two 4x4 matricies */ int row, col; float temp[16]; /*for(row = 0 ; row < 4 ; row++) for(col = 0 ; col < 4 ; col++) temp[row + col*4] = (m1[row] * m2[col*4] + m1[row+4] * m2[1+col*4] + m1[row+8] * m2[2+col*4] + m1[row+12] * m2[3+col*4]);*/ /* * Use OpenGL style matrix mult -- Wes. */ for (row = 0; row < 4; row++) for (col = 0; col < 4; col++) temp[row * 4 + col] = (m1[row * 4] * m2[col] + m1[1 + row * 4] * m2[col + 4] + m1[2 + row * 4] * m2[col + 8] + m1[3 + row * 4] * m2[col + 12]); mcopy(temp, prod); } void mmult(double *m1, double *m2, double *prod) { /* Multiply two 4x4 matricies */ int row, col; double temp[16]; /* * Use OpenGL style matrix mult -- Wes. */ for (row = 0; row < 4; row++) for (col = 0; col < 4; col++) temp[row * 4 + col] = (m1[row * 4] * m2[col] + m1[1 + row * 4] * m2[col + 4] + m1[2 + row * 4] * m2[col + 8] + m1[3 + row * 4] * m2[col + 12]); mcopy(temp, prod); } // 4x4 matrix inversion. Fixed (AN 4/07) so that it doesn't try to divide by very small // pivot elements. Returns 0 if not invertible int minvert(const float *mat, float *result) { // Invert a 4x4 matrix int i, j, k; float temp; float m[8][4]; mcopy(idmatrix, result); // mat[i,j] is row j, col i: for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { m[i][j] = mat[i + 4 * j]; m[i + 4][j] = result[i + 4 * j]; } } // Work across by columns (i is col index): for (i = 0; i < 4; i++) { // Find largest entry in the column, below the diagonal: float maxval = 0.f; int pivot = -1; for (int rw = i; rw < 4; rw++) { if (std::abs(m[i][rw]) > maxval) { maxval = std::abs(m[i][rw]); pivot = rw; } } if (pivot < 0) return -1; // otherwise, can't invert! if (pivot != i) { // Swap i and pivot row: for (k = i; k < 8; k++) { temp = m[k][i]; m[k][i] = m[k][pivot]; m[k][pivot] = temp; } } // Divide original row by pivot element, which is now the [i][i] element: for (j = 7; j >= i; j--) m[j][i] /= m[i][i]; // Subtract other rows, to make row i be the only row with nonzero elt in col i: for (j = 0; j < 4; j++) if (i != j) for (k = 7; k >= i; k--) m[k][j] -= m[k][i] * m[i][j]; } // copy back the last 4 columns: for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) result[i + 4 * j] = m[i + 4][j]; return 0; } int minvert(const double *mat, double *result) { // Invert a 4x4 matrix int i, j, k; double temp; double m[8][4]; mcopy(idmatrixd, result); // mat[i,j] is row j, col i: for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { m[i][j] = mat[i + 4 * j]; m[i + 4][j] = result[i + 4 * j]; } } // Work across by columns (i is col index): for (i = 0; i < 4; i++) { // Find largest entry in the column, below the diagonal: double maxval = 0.f; int pivot = -1; for (int rw = i; rw < 4; rw++) { if (std::abs(m[i][rw]) > maxval) { maxval = std::abs(m[i][rw]); pivot = rw; } } if (pivot < 0) return -1; // otherwise, can't invert! if (pivot != i) { // Swap i and pivot row: for (k = i; k < 8; k++) { temp = m[k][i]; m[k][i] = m[k][pivot]; m[k][pivot] = temp; } } // Divide original row by pivot element, which is now the [i][i] element: for (j = 7; j >= i; j--) m[j][i] /= m[i][i]; // Subtract other rows, to make row i be the only row with nonzero elt in col i: for (j = 0; j < 4; j++) if (i != j) for (k = 7; k >= i; k--) m[k][j] -= m[k][i] * m[i][j]; } // copy back the last 4 columns: for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) result[i + 4 * j] = m[i + 4][j]; return 0; } void qnormal(float *q) { /* Normalize a quaternion */ float s; s = 1 / sqrt((double)(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3])); q[0] *= s; q[1] *= s; q[2] *= s; q[3] *= s; } void qinv(const float q1[4], float q2[4]) { // Inverse of quaternion is conjugate/norm-square. 4th coeff is real part! float mag = q1[0] * q1[0] + q1[1] * q1[1] + q1[2] * q1[2] + q1[3] * q1[3]; VAssert(mag > 0.f); for (int i = 0; i < 3; i++) q2[i] = -q1[i] / mag; q2[3] = q1[3] / mag; float reslt[4]; qmult(q1, q2, reslt); } void qmult(const float *q1, const float *q2, float *dest) { /* Multiply two quaternions. Note quaternion real part is 4th coefficient! */ // static int count = 0; float t1[3], t2[3], t3[3]; float tf[4]; vcopy(q1, t1); vscale(t1, q2[3]); vcopy(q2, t2); vscale(t2, q1[3]); vcross(q2, q1, t3); vadd(t1, t2, tf); vadd(t3, tf, tf); tf[3] = q1[3] * q2[3] - vdot(q1, q2); qcopy(tf, dest); // why is this code here? // if (++count >= 97) { // count = 0; // qnormal(dest); //} } void qmult(const double *q1, const double *q2, double *dest) { /* Multiply two quaternions. Note quaternion real part is 4th coefficient! */ // static int count = 0; double t1[3], t2[3], t3[3]; double tf[4]; vcopy(q1, t1); vscale(t1, q2[3]); vcopy(q2, t2); vscale(t2, q1[3]); vcross(q2, q1, t3); vadd(t1, t2, tf); vadd(t3, tf, tf); tf[3] = q1[3] * q2[3] - vdot(q1, q2); qcopy(tf, dest); // why is this code here? // if (++count >= 97) { // count = 0; // qnormal(dest); //} } void qmatrix(const float *q, float *m) { /* Build a rotation matrix, given a quaternion rotation. */ m[0] = 1 - 2 * (q[1] * q[1] + q[2] * q[2]); m[1] = 2 * (q[0] * q[1] - q[2] * q[3]); m[2] = 2 * (q[2] * q[0] + q[1] * q[3]); m[3] = 0; m[4] = 2 * (q[0] * q[1] + q[2] * q[3]); m[5] = 1 - 2 * (q[2] * q[2] + q[0] * q[0]); m[6] = 2 * (q[1] * q[2] - q[0] * q[3]); m[7] = 0; m[8] = 2 * (q[2] * q[0] - q[1] * q[3]); m[9] = 2 * (q[1] * q[2] + q[0] * q[3]); m[10] = 1 - 2 * (q[1] * q[1] + q[0] * q[0]); m[11] = 0; m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; } // This function results in row major matrix. OpenGL uses column major // as well as the rest of the matrix operations void qmatrix(const double *q, double *m) { /* Build a rotation matrix, given a quaternion rotation. */ m[0] = 1 - 2 * (q[1] * q[1] + q[2] * q[2]); m[1] = 2 * (q[0] * q[1] - q[2] * q[3]); m[2] = 2 * (q[2] * q[0] + q[1] * q[3]); m[3] = 0; m[4] = 2 * (q[0] * q[1] + q[2] * q[3]); m[5] = 1 - 2 * (q[2] * q[2] + q[0] * q[0]); m[6] = 2 * (q[1] * q[2] - q[0] * q[3]); m[7] = 0; m[8] = 2 * (q[2] * q[0] - q[1] * q[3]); m[9] = 2 * (q[1] * q[2] + q[0] * q[3]); m[10] = 1 - 2 * (q[1] * q[1] + q[0] * q[0]); m[11] = 0; m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; } /* Convert a 4x4 rotation matrix to a quaternion. q[3] is real part! Code adapted from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion */ #define M_EPSILON 0.00000001 void rotmatrix2q(float *m, float *q) { float trace = m[0] + m[5] + m[10] + 1.0f; if (trace > M_EPSILON) { float s = 0.5f / sqrtf(trace); q[3] = 0.25f / s; q[0] = (m[9] - m[6]) * s; q[1] = (m[2] - m[8]) * s; q[2] = (m[4] - m[1]) * s; } else { if (m[0] > m[5] && m[0] > m[10]) { float s = 2.0f * sqrtf(1.0f + m[0] - m[5] - m[10]); q[0] = 0.25f * s; q[1] = (m[1] + m[4]) / s; q[2] = (m[2] + m[8]) / s; q[3] = (m[6] - m[9]) / s; //???? minus? } else if (m[5] > m[10]) { float s = 2.0f * sqrtf(1.0f + m[5] - m[0] - m[10]); q[0] = (m[1] + m[4]) / s; q[1] = 0.25f * s; q[2] = (m[6] + m[9]) / s; q[3] = (m[2] - m[8]) / s; } else { float s = 2.0f * sqrtf(1.0f + m[10] - m[0] - m[5]); q[0] = (m[2] + m[8]) / s; q[1] = (m[6] + m[9]) / s; q[2] = 0.25f * s; q[3] = (m[1] - m[4]) / s; //?? off by minus?? } } } void rotmatrix2q(double *m, double *q) { double trace = m[0] + m[5] + m[10] + 1.0; if (trace > M_EPSILON) { double s = 0.5 / sqrt(trace); q[3] = 0.25 / s; q[0] = (m[9] - m[6]) * s; q[1] = (m[2] - m[8]) * s; q[2] = (m[4] - m[1]) * s; } else { if (m[0] > m[5] && m[0] > m[10]) { double s = 2.0 * sqrt(1.0 + m[0] - m[5] - m[10]); q[0] = 0.25 * s; q[1] = (m[1] + m[4]) / s; q[2] = (m[2] + m[8]) / s; q[3] = (m[6] - m[9]) / s; //???? minus? } else if (m[5] > m[10]) { double s = 2.0 * sqrt(1.0 + m[5] - m[0] - m[10]); q[0] = (m[1] + m[4]) / s; q[1] = 0.25 * s; q[2] = (m[6] + m[9]) / s; q[3] = (m[2] - m[8]) / s; } else { double s = 2.0 * sqrt(1.0 + m[10] - m[0] - m[5]); q[0] = (m[2] + m[8]) / s; q[1] = (m[6] + m[9]) / s; q[2] = 0.25 * s; q[3] = (m[1] - m[4]) / s; //?? off by minus?? } } } void rvec2q(const float rvec[3], float radians, float q[4]) { double rvec_normal[3]; double d; d = sqrt(rvec[0] * rvec[0] + rvec[1] * rvec[1] + rvec[2] * rvec[2]); if (d != 0.0) { rvec_normal[0] = rvec[0] / d; rvec_normal[1] = rvec[1] / d; rvec_normal[2] = rvec[2] / d; } else { rvec_normal[0] = 0.0; rvec_normal[1] = 0.0; rvec_normal[2] = 1.0; } q[0] = sin(radians / 2.0) * rvec_normal[0]; q[1] = sin(radians / 2.0) * rvec_normal[1]; q[2] = sin(radians / 2.0) * rvec_normal[2]; q[3] = cos(radians / 2.0); } void rvec2q(const double rvec[3], double radians, double q[4]) { double rvec_normal[3]; double d; d = sqrt(rvec[0] * rvec[0] + rvec[1] * rvec[1] + rvec[2] * rvec[2]); if (d != 0.0) { rvec_normal[0] = rvec[0] / d; rvec_normal[1] = rvec[1] / d; rvec_normal[2] = rvec[2] / d; } else { rvec_normal[0] = 0.0; rvec_normal[1] = 0.0; rvec_normal[2] = 1.0; } q[0] = sin(radians / 2.0) * rvec_normal[0]; q[1] = sin(radians / 2.0) * rvec_normal[1]; q[2] = sin(radians / 2.0) * rvec_normal[2]; q[3] = cos(radians / 2.0); } float ProjectToSphere(float r, float x, float y) { /* Project an x,y pair onto a sphere of radius r or a hyperbolic sheet * if we are away from the center of the sphere. * * On sphere, x*x + y*y + z*z = r*r * On hyperbola, sqrt(x*x + y*y) * z = 1/2 r*r * Tangent at z = r / sqrt(2) */ float dd, tt; dd = x * x + y * y; tt = r * r * 0.5; if (dd < tt) return sqrt((double)(r * r - dd)); /* Inside sphere */ else return tt / sqrt((double)dd); /* On hyperbola */ } void CalcRotation(float *q, float newX, float newY, float oldX, float oldY, float ballsize) { /* Given old and new mouse positions (scaled to [-1, 1]), * Find the rotation quaternion q. */ float p1[3], p2[3]; /* 3D mouse points */ float L; /* sin^2(2 * phi) */ /* Check for zero rotation */ if (newX == oldX && newY == oldY) { qzero(q); return; } /* Form two vectors based on input points, find rotation axis */ vset(p1, newX, newY, ProjectToSphere(ballsize, newX, newY)); vset(p2, oldX, oldY, ProjectToSphere(ballsize, oldX, oldY)); vcross(p1, p2, q); /* axis of rotation from p1 and p2 */ L = vdot(q, q) / (vdot(p1, p1) * vdot(p2, p2)); L = sqrt((double)(1 - L)); vnormal(q); /* q' = axis of rotation */ vscale(q, sqrt((double)((1 - L) / 2))); /* q' = q' * sin(phi) */ q[3] = sqrt((double)((1 + L) / 2)); /* qs = qs * cos(phi) */ } void CalcRotation(double *q, double newX, double newY, double oldX, double oldY, double ballsize) { /* Given old and new mouse positions (scaled to [-1, 1]), * Find the rotation quaternion q. */ double p1[3], p2[3]; /* 3D mouse points */ double L; /* sin^2(2 * phi) */ /* Check for zero rotation */ if (newX == oldX && newY == oldY) { qzero(q); return; } /* Form two vectors based on input points, find rotation axis */ vset(p1, newX, newY, ProjectToSphere(ballsize, newX, newY)); vset(p2, oldX, oldY, ProjectToSphere(ballsize, oldX, oldY)); vcross(p1, p2, q); /* axis of rotation from p1 and p2 */ L = vdot(q, q) / (vdot(p1, p1) * vdot(p2, p2)); L = sqrt((double)(1 - L)); vnormal(q); /* q' = axis of rotation */ vscale(q, sqrt((double)((1 - L) / 2))); /* q' = q' * sin(phi) */ q[3] = sqrt((double)((1 + L) / 2)); /* qs = qs * cos(phi) */ } float ScalePoint(long pt, long origin, long size) { /* Scales integer point to the range [-1, 1] */ float x; x = (float)(pt - origin) / (float)size; if (x < 0) x = 0; if (x > 1) x = 1; return 2 * x - 1; } /* Make a translation matrix from a vector: */ void makeTransMatrix(float *trans, float *mtrx) { for (int i = 0; i < 12; i++) mtrx[i] = 0.f; mtrx[0] = 1.f; mtrx[5] = 1.f; mtrx[10] = 1.f; mtrx[15] = 1.f; vcopy(trans, mtrx + 12); } void makeTransMatrix(double *trans, double *mtrx) { for (int i = 0; i < 12; i++) mtrx[i] = 0.; mtrx[0] = 1.; mtrx[5] = 1.; mtrx[10] = 1.; mtrx[15] = 1.; for (int i = 0; i < 3; i++) mtrx[i + 12] = (double)trans[i]; } void makeTransMatrix(const std::vector &trans, double *mtrx) { for (int i = 0; i < 12; i++) mtrx[i] = 0.; mtrx[0] = 1.; mtrx[5] = 1.; mtrx[10] = 1.; mtrx[15] = 1.; for (int i = 0; i < 3; i++) mtrx[i + 12] = trans[i]; } void makeScaleMatrix(const double *scale, double *mtrx) { for (int i = 0; i < 16; i++) mtrx[i] = 0.; mtrx[0] = scale[0]; mtrx[5] = scale[1]; mtrx[10] = scale[2]; mtrx[15] = 1.; } /* * make a modelview matrix from viewer position, direction, and up vector * Vectors must be nonzero * side-effect: will alter input values if not valid. */ void makeModelviewMatrix(float *vpos, float *vdir, float *upvec, float *mtrx) { float vtemp[3]; float left[3] = {-1.f, 0.f, 0.f}; float ydir[3] = {0.f, 1.f, 0.f}; float right[3]; // Normalize the vectors: vnormal(upvec); vnormal(vdir); // Force the up vector to be orthogonal to viewDir vcopy(vdir, vtemp); vscale(vtemp, vdot(vdir, upvec)); // Subtract the component of up in the viewdir direction vsub(upvec, vtemp, upvec); // Make sure it's still valid if (vdot(upvec, upvec) == 0.f) { // First try up = viewdir x left vcross(vdir, left, upvec); if (vdot(upvec, upvec) == 0.f) { // try viewdir x ydir vcross(vdir, ydir, upvec); } } vnormal(upvec); // calculate "right" vector: vcross(vdir, upvec, right); // Construct matrix: float minv[16]; // Fill in bottom row: minv[3] = 0.f; minv[7] = 0.f; minv[11] = 0.f; minv[15] = 1.f; // copy in first 3 elements of columns vcopy(right, minv); vcopy(upvec, minv + 4); // third col is neg of viewdir vcopy(vdir, minv + 8); vscale(minv + 8, -1.f); vcopy(vpos, minv + 12); int rc = minvert(minv, mtrx); VAssert(rc >= 0); // Only catch this in debug mode } /* * make a modelview matrix from viewer position, direction, and up vector * Vectors must be nonzero * side-effect: will alter input values if not valid. */ void makeModelviewMatrixD(double *vpos, double *vdir, double *upvec, double *mtrx) { double vtemp[3]; double left[3] = {-1.f, 0.f, 0.f}; double ydir[3] = {0.f, 1.f, 0.f}; double right[3]; double dupvec[3], dvdir[3], dvpos[3]; for (int i = 0; i < 3; i++) { dupvec[i] = upvec[i]; dvdir[i] = vdir[i]; dvpos[i] = vpos[i]; } // Normalize the vectors: vnormal(dupvec); vnormal(dvdir); // Force the up vector to be orthogonal to viewDir vcopy(dvdir, vtemp); vscale(vtemp, vdot(dvdir, dupvec)); // Subtract the component of up in the viewdir direction vsub(dupvec, vtemp, dupvec); // Make sure it's still valid if (vdot(dupvec, dupvec) == 0.f) { // First try up = viewdir x left vcross(dvdir, left, dupvec); if (vdot(dupvec, dupvec) == 0.f) { // try viewdir x ydir vcross(dvdir, ydir, dupvec); } } vnormal(dupvec); // calculate "right" vector: vcross(dvdir, dupvec, right); // Construct matrix: double minv[16]; // Fill in bottom row: minv[3] = 0.; minv[7] = 0.; minv[11] = 0.; minv[15] = 1.; // copy in first 3 elements of columns vcopy(right, minv); vcopy(dupvec, minv + 4); // third col is neg of viewdir vcopy(dvdir, minv + 8); vscale(minv + 8, -1.); vcopy(dvpos, minv + 12); int rc = minvert(minv, mtrx); VAssert(rc >= 0); // Only catch this in debug mode } /* * make a modelview matrix from viewer position, direction, and up vector * Vectors must be nonzero * side-effect: will alter input values if not valid. */ void makeModelviewMatrixD(const std::vector &vpos, const std::vector &vdir, const std::vector &upvec, double *mtrx) { double vtemp[3]; double left[3] = {-1.f, 0.f, 0.f}; double ydir[3] = {0.f, 1.f, 0.f}; double right[3]; double dupvec[3], dvdir[3], dvpos[3]; for (int i = 0; i < 3; i++) { dupvec[i] = upvec[i]; dvdir[i] = vdir[i]; dvpos[i] = vpos[i]; } // Normalize the vectors: vnormal(dupvec); vnormal(dvdir); // Force the up vector to be orthogonal to viewDir vcopy(dvdir, vtemp); vscale(vtemp, vdot(dvdir, dupvec)); // Subtract the component of up in the viewdir direction vsub(dupvec, vtemp, dupvec); // Make sure it's still valid if (vdot(dupvec, dupvec) == 0.f) { // First try up = viewdir x left vcross(dvdir, left, dupvec); if (vdot(dupvec, dupvec) == 0.f) { // try viewdir x ydir vcross(dvdir, ydir, dupvec); } } vnormal(dupvec); // calculate "right" vector: vcross(dvdir, dupvec, right); // Construct matrix: double minv[16]; // Fill in bottom row: minv[3] = 0.; minv[7] = 0.; minv[11] = 0.; minv[15] = 1.; // copy in first 3 elements of columns vcopy(right, minv); vcopy(dupvec, minv + 4); // third col is neg of viewdir vcopy(dvdir, minv + 8); vscale(minv + 8, -1.); vcopy(dvpos, minv + 12); int rc = minvert(minv, mtrx); VAssert(rc >= 0); // Only catch this in debug mode } void matrix4x4_vec3_mult(const float m[16], const float a[4], float b[4]) { b[0] = m[0] * a[0] + m[4] * a[1] + m[8] * a[2] + m[12] * a[3]; b[1] = m[1] * a[0] + m[5] * a[1] + m[9] * a[2] + m[13] * a[3]; b[2] = m[2] * a[0] + m[6] * a[1] + m[10] * a[2] + m[14] * a[3]; b[3] = m[3] * a[0] + m[7] * a[1] + m[11] * a[2] + m[15] * a[3]; if (b[3] != 0.0 && b[3] != 1.0) { b[0] /= b[3]; b[1] /= b[3]; b[2] /= b[3]; b[3] = 1.0; } } // // Matrix Inversion // Adapted from Richard Carling // from "Graphics Gems", Academic Press, 1990 // #define SMALL_NUMBER 1.e-8 /* * matrix4x4_inverse( original_matrix, inverse_matrix ) * * calculate the inverse of a 4x4 matrix * * -1 * A = ___1__ adjoint A * det A */ int matrix4x4_inverse(const float *in, float *out) { int i, j; double det; double det4x4(const float m[16]); void adjoint(const float *in, float *out); /* calculate the adjoint matrix */ adjoint(in, out); /* calculate the 4x4 determinant * if the determinant is zero, * then the inverse matrix is not unique. */ det = det4x4(in); if (std::abs(det) < SMALL_NUMBER) { // Singular matrix, no inverse! return (-1); } /* scale the adjoint matrix to get the inverse */ for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { out[i * 4 + j] = out[i * 4 + j] / det; } } return (0); } /* * adjoint( original_matrix, inverse_matrix ) * * calculate the adjoint of a 4x4 matrix * * Let a denote the minor determinant of matrix A obtained by * ij * * deleting the ith row and jth column from A. * * i+j * Let b = (-1) a * ij ji * * The matrix B = (b ) is the adjoint of A * ij */ void adjoint(const float *in, float *out) { double a1, a2, a3, a4, b1, b2, b3, b4; double c1, c2, c3, c4, d1, d2, d3, d4; double det3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3); /* assign to individual variable names to aid */ /* selecting correct values */ a1 = in[0 * 4 + 0]; b1 = in[0 * 4 + 1]; c1 = in[0 * 4 + 2]; d1 = in[0 * 4 + 3]; a2 = in[1 * 4 + 0]; b2 = in[1 * 4 + 1]; c2 = in[1 * 4 + 2]; d2 = in[1 * 4 + 3]; a3 = in[2 * 4 + 0]; b3 = in[2 * 4 + 1]; c3 = in[2 * 4 + 2]; d3 = in[2 * 4 + 3]; a4 = in[3 * 4 + 0]; b4 = in[3 * 4 + 1]; c4 = in[3 * 4 + 2]; d4 = in[3 * 4 + 3]; /* row column labeling reversed since we transpose rows & columns */ out[0 * 4 + 0] = det3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4); out[1 * 4 + 0] = -det3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4); out[2 * 4 + 0] = det3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4); out[3 * 4 + 0] = -det3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); out[0 * 4 + 1] = -det3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4); out[1 * 4 + 1] = det3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4); out[2 * 4 + 1] = -det3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4); out[3 * 4 + 1] = det3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4); out[0 * 4 + 2] = det3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4); out[1 * 4 + 2] = -det3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4); out[2 * 4 + 2] = det3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4); out[3 * 4 + 2] = -det3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4); out[0 * 4 + 3] = -det3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3); out[1 * 4 + 3] = det3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3); out[2 * 4 + 3] = -det3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3); out[3 * 4 + 3] = det3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); } /* * double = det4x4( matrix ) * * calculate the determinant of a 4x4 matrix. */ double det4x4(const float m[16]) { double ans; double a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4; double det3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3); /* assign to individual variable names to aid selecting */ /* correct elements */ a1 = m[0 * 4 + 0]; b1 = m[0 * 4 + 1]; c1 = m[0 * 4 + 2]; d1 = m[0 * 4 + 3]; a2 = m[1 * 4 + 0]; b2 = m[1 * 4 + 1]; c2 = m[1 * 4 + 2]; d2 = m[1 * 4 + 3]; a3 = m[2 * 4 + 0]; b3 = m[2 * 4 + 1]; c3 = m[2 * 4 + 2]; d3 = m[2 * 4 + 3]; a4 = m[3 * 4 + 0]; b4 = m[3 * 4 + 1]; c4 = m[3 * 4 + 2]; d4 = m[3 * 4 + 3]; ans = a1 * det3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) - b1 * det3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) + c1 * det3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) - d1 * det3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); return ans; } /* * double = det3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3 ) * * calculate the determinant of a 3x3 matrix * in the form * * | a1, b1, c1 | * | a2, b2, c2 | * | a3, b3, c3 | */ double det3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3) { double ans; double det2x2(double a, double b, double c, double d); ans = a1 * det2x2(b2, b3, c2, c3) - b1 * det2x2(a2, a3, c2, c3) + c1 * det2x2(a2, a3, b2, b3); return ans; } /* * double = det2x2( double a, double b, double c, double d ) * * calculate the determinant of a 2x2 matrix. */ double det2x2(double a, double b, double c, double d) { double ans; ans = a * d - b * c; return ans; } /* * Return true, if n is a power of 2. */ bool powerOf2(size_t n) { return (n & (n - 1)) == 0; } /* * Return the next power of 2 that is equal or larger than n */ size_t nextPowerOf2(size_t n) { if (powerOf2(n)) return n; size_t p; for (int i = 63; i >= 0; i--) { p = n & ((size_t)1 << i); if (p) { p = ((size_t)1 << (i + 1)); break; } } return p; } // Some routines to handle 3x3 rotation matrices, represented as 9 floats, // where the column index increments faster void mmult33(const double *m1, const double *m2, double *result) { for (int row = 0; row < 3; row++) { for (int col = 0; col < 3; col++) { result[row * 3 + col] = (m1[row * 3] * m2[col] + m1[1 + row * 3] * m2[col + 3] + m1[2 + row * 3] * m2[col + 6]); } } } // Same as above, but use the transpose (i.e. inverse for rotations) on the left void mmultt33(const double *m1Trans, const double *m2, double *result) { for (int row = 0; row < 3; row++) { for (int col = 0; col < 3; col++) { result[row * 3 + col] = (m1Trans[row] * m2[col] + m1Trans[3 + row] * m2[col + 3] + m1Trans[6 + row] * m2[col + 6]); } } } // Determine a rotation matrix from (theta, phi, psi) (radians), that is, // find the rotation matrix that first rotates in (x,y) by psi, then takes the vector (0,0,1) // to the vector with direction (theta,phi) by rotating by phi in the (x,z) plane and then // rotating in the (x,y)plane by theta. void getRotationMatrix(double theta, double phi, double psi, double *matrix) { // do the theta-phi rotation first: double mtrx1[9], mtrx2[9]; double cosTheta = cos(theta); double sinTheta = sin(theta); double cosPhi = cos(phi); double sinPhi = sin(phi); double cosPsi = cos(psi); double sinPsi = sin(psi); // specify mtrx1 as an (X,Z) rotation by -phi, followed by an (X,Y) rotation by theta: mtrx1[0] = cosTheta * cosPhi; mtrx1[1] = -sinTheta; mtrx1[2] = cosTheta * sinPhi; // 2nd row: mtrx1[3] = sinTheta * cosPhi; mtrx1[4] = cosTheta; mtrx1[5] = sinTheta * sinPhi; // 3rd row: mtrx1[6] = -sinPhi; mtrx1[7] = 0.f; mtrx1[8] = cosPhi; // mtrx2 is a rotation by psi in the x,y plane: mtrx2[0] = cosPsi; mtrx2[1] = -sinPsi; mtrx2[2] = 0.f; mtrx2[3] = sinPsi; mtrx2[4] = cosPsi; mtrx2[5] = 0.f; mtrx2[6] = 0.f; mtrx2[7] = 0.f; mtrx2[8] = 1.f; mmult33(mtrx1, mtrx2, matrix); } // Determine a rotation matrix about an axis: COMMON_API void getAxisRotation(int axis, double rotation, double *matrix) { for (int col = 0; col < 3; col++) { for (int row = 0; row < 3; row++) { if (row == axis && col == axis) matrix[col + row * 3] = 1.f; else if (row == axis || col == axis) matrix[col + row * 3] = 0.f; else { if (row == col) matrix[col + row * 3] = cos(rotation); else if (row > col) matrix[col + row * 3] = sin(rotation); else matrix[col + row * 3] = -sin(rotation); } } } } // Determine the psi, phi, theta (radians!) from a rotation matrix. // the rotation matrix rotates about the z-axis by psi, // then takes the z-axis to the unit vector with spherical // coordinates theta and phi. void getRotAngles(double *theta, double *phi, double *psi, const double *matrix) { // First find phi and theta by looking at matrix applied to 0,0,1: double vec[3]; double tempPhi, tempTheta; double tempPsi = 0.; double tMatrix1[9], tMatrix2[9]; vec[0] = matrix[2]; vec[1] = matrix[5]; vec[2] = matrix[8]; // float cosPhi = vec[2]; tempPhi = acos(vec[2]); // unique angle between 0 and pi // now project vec[0], vec[1] to x,y plane: double normsq = (vec[0] * vec[0] + vec[1] * vec[1]); if (normsq == 0.) tempTheta = 0.; else { tempTheta = acos(vec[0] / sqrt(normsq)); // If sin(theta)<0 then theta is negative: if (vec[1] < 0) tempTheta = -tempTheta; } // Find the transformation determined by theta, phi: getRotationMatrix(tempTheta, tempPhi, tempPsi, tMatrix1); // Apply the inverse of this to the input matrix: mmultt33(tMatrix1, matrix, tMatrix2); // Now the resulting matrix is a rotation by psi // Cos psi and sin psi are in the first column: if (std::abs(tMatrix2[0]) > 1.f) { if (tMatrix2[0] > 0.f) tMatrix2[0] = 1.f; else tMatrix2[0] = -1.f; } tempPsi = acos(tMatrix2[0]); if (tMatrix2[3] < 0.f) tempPsi = -tempPsi; *theta = tempTheta; *phi = tempPhi; *psi = tempPsi; return; } // Intersect a ray with an axis-aligned box. // Ray is specified by start point and direction vector. // Box is specified by 6 floats (extents) // Return value is number of intersections found, // Results are specified as floats, increasing order, indicating the position R on the ray where // intersection = rayStart+R*rayDir. int rayBoxIntersect(const float rayStart[3], const float rayDir[3], const float boxExts[6], float results[2]) { // Loop over axes of cube. Intersect faces with the ray, then test if it's inside box extents: int numfound = 0; for (int axis = 0; axis < 3; axis++) { // Points along ray are rayStart+t*rayDir. // To intersect face, rayStart+t*rayDir has axis coordinate equal to boxExts[axis] or boxExts[axis+3] // so that t = (boxExts[axis+(0 or 3)] - rayStart[axis])/rayDir[axis]; if (rayDir[axis] == 0.f) continue; // Plane is parallel to ray // check front and back intersections: for (int frontBack = 0; frontBack < 4; frontBack += 3) { float t = (boxExts[axis + frontBack] - rayStart[axis]) / rayDir[axis]; // Check to see if point is within other two box bounds float intersectPoint[3]; for (int j = 0; j < 3; j++) { intersectPoint[j] = rayStart[j] + t * rayDir[j]; } bool pointOK = true; for (int otherCoord = 0; otherCoord < 3; otherCoord++) { if (otherCoord == axis) continue; if (intersectPoint[otherCoord] < boxExts[otherCoord]) { pointOK = false; break; } if (intersectPoint[otherCoord] > boxExts[otherCoord + 3]) { pointOK = false; break; } } if (pointOK) { // Found an intersection! results[numfound++] = t; // order the points in increasing t: if (numfound == 2 && (results[1] < results[0])) { float temp = results[0]; results[0] = results[1]; results[1] = temp; } if (numfound == 2) return numfound; } } } return numfound; } int rayBoxIntersect(const double rayStart[3], const double rayDir[3], const double boxExts[6], double results[2]) { // Loop over axes of cube. Intersect faces with the ray, then test if it's inside box extents: // Return at most two intersections, the max and min along the ray. int numfound = 0; double tempResults[6]; double epsilons[3]; // Error tolerance is size/10^6 for (int i = 0; i < 3; i++) epsilons[i] = (boxExts[i + 3] - boxExts[i]) * 1.e-6; for (int axis = 0; axis < 3; axis++) { if (numfound == 6) break; // Points along ray are rayStart+t*rayDir. // To intersect face, rayStart+t*rayDir has axis coordinate equal to boxExts[axis] or boxExts[axis+3] // so that t = (boxExts[axis+(0 or 3)] - rayStart[axis])/rayDir[axis]; if (rayDir[axis] == 0.) continue; // Plane is parallel to ray // check front and back intersections: for (int frontBack = 0; frontBack < 4; frontBack += 3) { float t = (boxExts[axis + frontBack] - rayStart[axis]) / rayDir[axis]; // Check to see if point is within other two box bounds float intersectPoint[3]; for (int j = 0; j < 3; j++) { intersectPoint[j] = rayStart[j] + t * rayDir[j]; } bool pointOK = true; for (int otherCoord = 0; otherCoord < 3; otherCoord++) { if (otherCoord == axis) continue; if (intersectPoint[otherCoord] < boxExts[otherCoord] - epsilons[otherCoord]) { pointOK = false; break; } if (intersectPoint[otherCoord] > boxExts[otherCoord + 3] + epsilons[otherCoord]) { pointOK = false; break; } } if (pointOK) { // Found an intersection! tempResults[numfound++] = t; } if (numfound == 6) break; } } if (numfound == 0) return 0; // Find the max and min t double mint = DBL_MAX; double maxt = -DBL_MAX; for (int i = 0; i < numfound; i++) { if (tempResults[i] < mint) { mint = tempResults[i]; } if (tempResults[i] > maxt) { maxt = tempResults[i]; } } results[0] = mint; if (numfound == 1) return 1; results[1] = maxt; return 2; } // Project box corners to ray // Ray is specified by start point and direction vector. // Box is specified by 6 doubles (extents) // Results are specified as doubles, increasing order, indicating the position R on the ray where // the corner is projected void rayBoxProject(vector rayStart, vector rayDir, const double boxExts[6], double results[2]) { // For each box corner, // project to line of view double cor[3], wrk[3], dir[3]; double maxProj = -DBL_MAX; double minProj = DBL_MAX; // Make sure rayDir is normalized: for (int i = 0; i < 3; i++) dir[i] = rayDir[i]; vnormal(dir); for (int i = 0; i < 8; i++) { for (int j = 0; j < 3; j++) { cor[j] = ((i >> j) & 1) ? boxExts[j + 3] : boxExts[j]; } vsub(cor, rayStart, wrk); double mdist = vdot(wrk, dir); if (minProj > mdist) { minProj = mdist; } if (maxProj < mdist) { maxProj = mdist; } } results[0] = minProj; results[1] = maxProj; } // Convert a camera view to a quaternion, for linear interpolation of viewpoints. void view2Quat(float vdir[3], float upvec[3], float q[4]) { float vtemp[3]; float left[3] = {-1.f, 0.f, 0.f}; float ydir[3] = {0.f, 1.f, 0.f}; float right[3]; // Normalize the vectors: vnormal(upvec); vnormal(vdir); // Force the up vector to be orthogonal to viewDir vcopy(vdir, vtemp); vscale(vtemp, vdot(vdir, upvec)); // Subtract the component of up in the viewdir direction vsub(upvec, vtemp, upvec); // Make sure it's still valid if (vdot(upvec, upvec) == 0.f) { // First try up = viewdir x left vcross(vdir, left, upvec); if (vdot(upvec, upvec) == 0.f) { // try viewdir x ydir vcross(vdir, ydir, upvec); } } vnormal(upvec); // calculate "right" vector: vcross(vdir, upvec, right); // Construct 4x4 matrix. Just because rotmatrix2q expects 4x4 float minv[16]; // Bottom row, right column not needed. minv[3] = 0.f; minv[7] = 0.f; minv[11] = 0.f; minv[15] = 1.f; // copy in first 3 elements of columns vcopy(right, minv); vcopy(upvec, minv + 4); // third col is neg of viewdir vcopy(vdir, minv + 8); vscale(minv + 8, -1.f); vzero(minv + 12); minv[15] = 1.f; rotmatrix2q(minv, q); } // Convert two camera views to two pure imaginary quaternion, for linear interpolation of viewpoints. // If dot product is negative, the first quaternion is negated, to prevent interpolating the long way around. void views2ImagQuats(float vdir1[3], float upvec1[3], float vdir2[3], float upvec2[3], float q1[3], float q2[3]) { float quat1[4], quat2[4]; view2Quat(vdir1, upvec1, quat1); view2Quat(vdir2, upvec2, quat2); float dotprod = 0.; for (int i = 0; i < 4; i++) dotprod += quat1[i] * quat2[i]; if (dotprod < 0.f) for (int i = 0; i < 4; i++) quat1[i] = -quat1[i]; qnormal(quat2); // force full quaternion to be norm-1 (correct round-off error) qnormal(quat1); float mag = vlength(quat1); // norm of imaginary part float re = acos(quat1[3]); if (mag == 0.f) for (int i = 0; i < 3; i++) q1[i] = 0.f; else for (int i = 0; i < 3; i++) q1[i] = quat1[i] * re / mag; mag = vlength(quat2); // norm of imaginary part re = acos(quat2[3]); if (mag == 0.f) for (int i = 0; i < 3; i++) q2[i] = 0.f; else for (int i = 0; i < 3; i++) q2[i] = quat2[i] * re / mag; return; } // Convert a pure-imaginary quaternion to camera view, for linear interpolation of viewpoints. void imagQuat2View(const float q[3], float vdir[3], float upvec[3]) { float quat[4]; float mtrx[16]; // First, calc exponential of q: float mag = vlength(q); quat[3] = cos(mag); if (mag > 0.f) { float s = sin(mag) / mag; for (int i = 0; i < 3; i++) quat[i] = q[i] * s; } else { for (int i = 0; i < 3; i++) quat[i] = 0.f; } // then convert quat to a matrix qmatrix(quat, mtrx); // extract rows: vcopy(mtrx + 4, upvec); vcopy(mtrx + 8, vdir); vscale(vdir, -1.f); } void quat2View(float quat[4], float vdir[3], float upvec[3]) { float mtrx[16]; // convert quat to a matrix qmatrix(quat, mtrx); // extract rows: vcopy(mtrx + 4, upvec); vcopy(mtrx + 8, vdir); vscale(vdir, -1.f); } // Spherical linear interpolation between two unit quaternions. t is between 0 and 1. void slerp(float quat0[4], float quat1[4], float t, float result[4]) { // Wikipedia: slerp = q0*(q0^-1 * q1)**t float q0inv[4], res1[4], res2[4], V[3]; // make sure they are unit quaternion: qnormal(quat0); qnormal(quat1); // calculate quat0 inv for (int i = 0; i < 3; i++) q0inv[i] = -quat0[i]; q0inv[3] = quat0[3]; qmult(q0inv, quat1, res1); // now take res1 to power t: // First express res1 as cos theta + V sin theta, = exp(theta*V) if (res1[3] > 1.0) res1[3] = 1.0; if (res1[3] < -1.0) res1[3] = -1.0; double theta = acos((double)res1[3]); float sinTheta = sin(theta); if (sinTheta == 0.f) { vzero(V); } else { vcopy(res1, V); vscale(V, 1. / sinTheta); } // Now take to power t, i.e. cos(t*theta)+sin(t*theta)*V res2[3] = cos(t * theta); for (int i = 0; i < 3; i++) res2[i] = V[i] * sin(t * theta); // then multiply on the left by quat0: qmult(quat0, res2, result); } // Logarithm of a unit quaternion void qlog(float quat[4], float quatlog[4]) { // express quat as cos theta + V sin theta, = exp(theta*V) float V[3]; if (quat[3] > 1.0) quat[3] = 1.0; if (quat[3] < -1.0) quat[3] = -1.0; double theta = acos((double)quat[3]); float sinTheta = sin(theta); if (sinTheta == 0.f) { vzero(V); } else { vcopy(quat, V); vscale(V, theta / sinTheta); } vcopy(V, quatlog); quatlog[3] = 0.f; } void squad(float quat1[4], float quat2[4], float s1[4], float s2[4], float t, float result[4]) { float qa[4], qb[4]; slerp(quat1, quat2, t, qa); slerp(s1, s2, t, qb); slerp(qa, qb, 2. * t * (1. - t), result); } void qconj(float quat[4], float conj[4]) { conj[3] = quat[3]; conj[0] = -quat[0]; conj[1] = -quat[1]; conj[2] = -quat[2]; } void doubleToString(const double d, string &s, int digits) { char buf[30]; snprintf(buf, 30, "%-.*G", digits, d); string ss(buf); s = ss; } #define VAPOR3_0_0_ALPHA #ifdef VAPOR3_0_0_ALPHA // Macros #define LINEAR_INDEX(dim, x, y, z) ((x) + (dim[0]) * ((y) + (z) * (dim[1]))) #define sqr(x) ((x) * (x)) void computeGradientData(int dim[3], int numChan, unsigned char *volume, unsigned char *gradient) { for (int z = 0; z < dim[2]; z++) for (int y = 0; y < dim[1]; y++) for (int x = 0; x < dim[0]; x++) { float gradient_temp[3]; // The following code computes the gradient for the volume data. // For volumes with more than one channel, only the first channel // is used to compute the gradient! The voxel index computation is // very inefficient and can be optimized a lot using a simple // incremental computation. // Handle border cases correctly by using forward and backward // differencing for the boundaries. if (x == 0) // forward differencing gradient_temp[0] = ((float)volume[numChan * LINEAR_INDEX(dim, x + 1, y, z)] - (float)volume[numChan * LINEAR_INDEX(dim, x, y, z)]); else if (x == dim[0] - 1) // backward differencing gradient_temp[0] = ((float)volume[numChan * LINEAR_INDEX(dim, x, y, z)] - (float)volume[numChan * LINEAR_INDEX(dim, x - 1, y, z)]); else // central differencing gradient_temp[0] = (((float)volume[numChan * LINEAR_INDEX(dim, x + 1, y, z)] - (float)volume[numChan * LINEAR_INDEX(dim, x - 1, y, z)]) / 2.0); if (y == 0) gradient_temp[1] = ((float)volume[numChan * LINEAR_INDEX(dim, x, y + 1, z)] - (float)volume[numChan * LINEAR_INDEX(dim, x, y, z)]); else if (y == dim[1] - 1) gradient_temp[1] = ((float)volume[numChan * LINEAR_INDEX(dim, x, y, z)] - (float)volume[numChan * LINEAR_INDEX(dim, x, y - 1, z)]); else gradient_temp[1] = (((float)volume[numChan * LINEAR_INDEX(dim, x, y + 1, z)] - (float)volume[numChan * LINEAR_INDEX(dim, x, y - 1, z)]) / 2.0); if (z == 0) gradient_temp[2] = ((float)volume[numChan * LINEAR_INDEX(dim, x, y, z + 1)] - (float)volume[numChan * LINEAR_INDEX(dim, x, y, z)]); else if (z == dim[2] - 1) gradient_temp[2] = ((float)volume[numChan * LINEAR_INDEX(dim, x, y, z)] - (float)volume[numChan * LINEAR_INDEX(dim, x, y, z - 1)]); else gradient_temp[2] = (((float)volume[numChan * LINEAR_INDEX(dim, x, y, z + 1)] - (float)volume[numChan * LINEAR_INDEX(dim, x, y, z - 1)]) / 2.0); // compute the magintude for the gradient double mag = (sqrt(sqr(gradient_temp[0]) + sqr(gradient_temp[1]) + sqr(gradient_temp[2]))); // avoid any divide by zeros! if (mag > 0.01) { gradient_temp[0] /= mag; gradient_temp[1] /= mag; gradient_temp[2] /= mag; } else { gradient_temp[0] = gradient_temp[1] = gradient_temp[2] = 0.0; } // Map the floating point gradient values to the appropriate range // in unsigned byte unsigned long index = 4 * (LINEAR_INDEX(dim, x, y, z)); for (int i = 0; i < 3; i++) { gradient[index + i] = (signed char)floor(gradient_temp[i] * 128.0); } // Set the alpha to be 1.0 gradient[index + 3] = 255; } } #endif }; // namespace VAPoR ================================================ FILE: lib/common/MyBase.cpp ================================================ #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include #include #ifdef WIN32 #pragma warning(disable : 4996) #include "windows.h" #endif #include using namespace Wasp; using namespace std; #ifdef NEW_DEBUG void *operator new(size_t sz) { void *p = malloc(sz); std::cout << "Malloc " << sz << " bytes" << endl; if (!p) { std::cerr << "Malloc " << sz << " bytes failed!!!" << endl; exit(1); } return (p); } void *operator new[](size_t sz) { void *p = malloc(sz); cout << "Malloc " << sz << " bytes" << endl; if (!p) { std::cerr << "Malloc " << sz << " bytes failed!!!" << endl; exit(1); } return (p); } #endif char *MyBase::ErrMsg = NULL; int MyBase::ErrMsgSize = 0; int MyBase::ErrCode = 0; FILE *MyBase::ErrMsgFilePtr = NULL; void (*MyBase::ErrMsgCB)(const char *msg, int err_code) = NULL; char *MyBase::DiagMsg = NULL; int MyBase::DiagMsgSize = 0; #ifdef DEBUG FILE *MyBase::DiagMsgFilePtr = stderr; #else FILE *MyBase::DiagMsgFilePtr = NULL; #endif void (*MyBase::DiagMsgCB)(const char *msg) = NULL; bool MyBase::Enabled = true; MyBase::MyBase() { SetClassName("MyBase"); } void MyBase::_SetErrMsg(char **msgbuf, int *msgbufsz, const char *format, va_list args) { int done = 0; const int alloc_size = 4096; int rc; //#ifdef WIN32 // CHAR szBuf[80]; // DWORD dw = GetLastError(); // sprintf(szBuf, "Reporting error message: GetLastError returned %u\n", dw); // MessageBox(NULL, szBuf, "Error", MB_OK); //#endif if (!*msgbuf) { *msgbuf = new char[alloc_size]; VAssert(*msgbuf != NULL); *msgbufsz = alloc_size; } string formatstr(format); size_t loc; while ((loc = formatstr.find("%M", 0)) != string::npos) { formatstr.replace(loc, 2, strerror(errno), strlen(strerror(errno))); } format = formatstr.c_str(); // Loop until we've successfully buffered the error message, growing // the message buffer as needed // va_list argscopy; while (!done) { va_copy(argscopy, args); #ifdef WIN32 rc = _vsnprintf(*msgbuf, *msgbufsz, format, argscopy); #else rc = vsnprintf(*msgbuf, *msgbufsz, format, argscopy); #endif va_end(argscopy); if (rc < (*msgbufsz - 1)) { done = 1; } else { if (*msgbuf) delete[] * msgbuf; *msgbuf = new char[*msgbufsz + alloc_size]; VAssert(*msgbuf != NULL); *msgbufsz += alloc_size; } } } void MyBase::SetErrMsg(const char *format, ...) { va_list args; // initialize to make valgrind shutup if (!Enabled) return; ErrCode = 1; va_start(args, format); _SetErrMsg(&ErrMsg, &ErrMsgSize, format, args); va_end(args); if (ErrMsgCB) (*ErrMsgCB)(ErrMsg, ErrCode); if (ErrMsgFilePtr) { (void)fprintf(ErrMsgFilePtr, "%s\n", ErrMsg); } } void MyBase::SetErrMsg(int errcode, const char *format, ...) { va_list args; // initialize to make valgrind shutup if (!Enabled) return; ErrCode = errcode; va_start(args, format); _SetErrMsg(&ErrMsg, &ErrMsgSize, format, args); va_end(args); if (ErrMsgCB) (*ErrMsgCB)(ErrMsg, ErrCode); if (ErrMsgFilePtr) { (void)fprintf(ErrMsgFilePtr, "%s\n", ErrMsg); } } void MyBase::SetDiagMsg(const char *format, ...) { va_list args; // initialize to make valgrind shutup va_start(args, format); _SetErrMsg(&DiagMsg, &DiagMsgSize, format, args); va_end(args); if (DiagMsgCB) (*DiagMsgCB)(DiagMsg); if (DiagMsgFilePtr) { (void)fprintf(DiagMsgFilePtr, "%s\n", DiagMsg); } } int Wasp::IsPowerOfTwo(unsigned int x) { if (!x) return 1; while (!(x & 1)) x >>= 1; return (x == 1); } // Find integer log, base 2, of a 32-bit positive integer: int Wasp::ILog2(int n) { int i; for (i = 0; i < 31; i++) { if (n <= (1 << i)) break; } return i; } int Wasp::StrCmpNoCase(const string &s, const string &t) { string::const_iterator sptr = s.begin(); string::const_iterator tptr = t.begin(); while (sptr != s.end() && tptr != t.end()) { if (toupper(*sptr) != toupper(*tptr)) { return (toupper(*sptr) < toupper(*tptr) ? -1 : 1); } *sptr++; *tptr++; } return ((s.size() == t.size()) ? 0 : ((s.size() < t.size()) ? -1 : 1)); } void Wasp::StrRmWhiteSpace(string &s) { string::size_type i; if (s.length() < 1) return; i = 0; while (i < s.length() && isspace(s[i])) i++; if (i > 0) { s.replace(0, i, "", 0); } if (s.length() < 1) return; i = s.length() - 1; while (isspace(s[i])) i--; if (i < (s.length() - 1)) { s.replace(i + 1, s.length() - i + 1, "", 0); } } void Wasp::StrToWordVec(const string &s, vector &v) { string tmp = s; v.clear(); while (!tmp.empty()) { while (!tmp.empty() && isspace(tmp[0])) tmp.erase(0, 1); int index = 0; while (index < tmp.length()) { if (isspace(tmp[index])) if (index == 0 || tmp[index - 1] != '\\') break; index++; } if (index) { string word = tmp.substr(0, index); v.push_back(word); tmp.erase(0, index); } } } std::vector &Wasp::SplitString(const std::string &s, char delim, std::vector &elems) { elems.clear(); stringstream ss(s); string item; while (getline(ss, item, delim)) { if (!item.empty()) elems.push_back(item); } return elems; } namespace { template vector &splitStringTemplate(const std::string &s, char delim, std::vector &elems) { elems.clear(); vector tokens; (void)Wasp::SplitString(s, delim, tokens); for (int i = 0; i < tokens.size(); i++) { stringstream ss(tokens[i]); T elem; ss >> elem; elems.push_back(elem); } return (elems); } }; // namespace std::vector &Wasp::SplitString(const std::string &s, char delim, std::vector &elems) { return (splitStringTemplate(s, delim, elems)); } std::vector &Wasp::SplitString(const std::string &s, char delim, std::vector &elems) { return (splitStringTemplate(s, delim, elems)); } std::vector &Wasp::SplitString(const std::string &s, char delim, std::vector &elems) { return (splitStringTemplate(s, delim, elems)); } std::vector &Wasp::SplitString(const std::string &s, char delim, std::vector &elems) { return (splitStringTemplate(s, delim, elems)); } unsigned long long Wasp::GetBits64(unsigned long long targ, int pos, int n) { return ((targ >> (pos + 1 - n)) & ~(~0ULL << n)); } unsigned long long Wasp::SetBits64(unsigned long long targ, int pos, int n, unsigned long long src) { targ &= ~(~(~0ULL << n) << (pos + 1 - n)); targ |= (src & ~(~0ULL << n)) << (pos + 1 - n); return (targ); } // From Numerical Recipes in C /* Minimal" random number generator of Park and Miller with Bays-Durham shuffle and safeguards. Returns a uniform random deviate between 0.0 and 1.0 (exclusive of the endpoint values). Call with idum a negative integer to initialize; thereafter, do not alter idum between successive deviates in a sequence. RNMX should approximate the largest floating value that is less than 1. */ #define IA 16807 #define IM 2147483647 #define AM (1.0 / IM) #define IQ 127773 #define IR 2836 #define NTAB 32 #define NDIV (1 + (IM - 1) / NTAB) #define EPS 1.2e-7 #define RNMX (1.0 - EPS) double Wasp::ran1(long *idum) { int j; long k; static long iy = 0; static long iv[NTAB]; double temp; if (*idum <= 0 || !iy) { if (-(*idum) < 1) *idum = 1; else *idum = -(*idum); for (j = NTAB + 7; j >= 0; j--) { k = (*idum) / IQ; *idum = IA * (*idum - k * IQ) - IR * k; if (*idum < 0) *idum += IM; if (j < NTAB) iv[j] = *idum; } iy = iv[0]; } k = (*idum) / IQ; *idum = IA * (*idum - k * IQ) - IR * k; if (*idum < 0) *idum += IM; j = iy / NDIV; iy = iv[j]; iv[j] = *idum; if ((temp = AM * iy) > RNMX) return RNMX; else return temp; } ================================================ FILE: lib/common/OptionParser.cpp ================================================ #include #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include #ifdef WIN32 #pragma warning(disable : 4996) #endif using namespace Wasp; namespace Wasp { bool opt_cmp(OptionParser::_OptRec_T *a, OptionParser::_OptRec_T *b) { return (string(a->option) < string(b->option)); }; } // namespace Wasp /* * convert an array of strings into a singe contiguous array of strings */ char *copy_create_arg_string(char **argv, int argc) { char *s, *t; int i, len; /* lenght of new arg string */ for (len = 0, i = 0; i < argc; i++) { len += (int)strlen(argv[i]); len++; /* one for the space */ } s = (char *)malloc(len + 1); VAssert(s != NULL); s = strcpy(s, argv[0]); for (i = 1, t = s; i < argc; i++) { t += strlen(t); *t++ = '\0'; (void)strcpy(t, argv[i]); } return (s); } /* * convert a space seprated string to an array of contiguous strings */ char *fmt_opt_string(char *arg, int n) { int i; char *s; for (i = 1, s = arg; i < n; i++) { while (*s && !isspace(*s)) s++; if (!*s) { return (NULL); } *s++ = '\0'; while (*s && isspace(*s)) s++; } return (arg); } /* ** ** Type converters. The following functions convert string representations ** of data into their primitive data formats. A NULL 'from' value ** should result in a reasonable value. ** */ /* * CvtToInt() * * convert a ascii string to its integer value */ int Wasp::CvtToInt(const char *from, /* the string */ void * to) { int *iptr = (int *)to; if (!from) { *iptr = 0; } else if (sscanf(from, "%d", iptr) != 1) { return (-1); } return (1); } /* * CvtToFloat() * * convert a ascii string to its floating point value */ int Wasp::CvtToFloat(const char *from, /* the string */ void * to) { float *fptr = (float *)to; if (!from) { *fptr = 0.0; } else if (sscanf(from, "%f", fptr) != 1) { return (-1); } return (1); } /* * CvtToDouble() * * convert a ascii string to its floating point value */ int Wasp::CvtToDouble(const char *from, /* the string */ void * to) { double *dptr = (double *)to; if (!from) { *dptr = 0.0; } else if (sscanf(from, "%lf", dptr) != 1) { return (-1); } return (1); } /* * CvtToChar() * * convert a ascii string to a char. */ int Wasp::CvtToChar(const char *from, /* the string */ void * to) { char *cptr = (char *)to; if (!from) { *cptr = '\0'; } else if (sscanf(from, "%c", cptr) != 1) { return (-1); } return (1); } /* * ConvetToBoolean() * * convert a ascii string containing either "true" or "false" to * to TRUE or FALSE */ int Wasp::CvtToBoolean(const char *from, /* the string */ void * to) { OptionParser::Boolean_T *bptr = (OptionParser::Boolean_T *)to; if (!from) { *bptr = 0; } else if (strcmp("true", from) == 0) { *bptr = 1; } else if (strcmp("false", from) == 0) { *bptr = 0; } else { return (-1); } return (1); } /* * CvtToString() * */ int Wasp::CvtToString(const char *from, /* the string */ void * to) { char **sptr = (char **)to; *sptr = (char *)from; return (1); } /* * CvtToCPPStr() * */ int Wasp::CvtToCPPStr(const char *from, /* the string */ void * to) { string *sptr = (string *)to; *sptr = from; return (1); } /* * CvtToDimension2D() * * convert a ascii string to a dimension. */ int Wasp::CvtToDimension2D(const char *from, /* the string */ void * to) { OptionParser::Dimension2D_T *dptr = (OptionParser::Dimension2D_T *)to; if (!from) { dptr->nx = dptr->ny = 0; } else if (!((sscanf(from, "%dx%d", &(dptr->nx), &(dptr->ny)) == 2) || (sscanf(from, "%dX%d", &(dptr->nx), &(dptr->ny)) == 2))) { return (-1); } return (1); } // // CvtToDimension3D() // // convert an ascii string to a 3D dimension. /// int Wasp::CvtToDimension3D(const char *from, /* the string */ void * to) { OptionParser::Dimension3D_T *dptr = (OptionParser::Dimension3D_T *)to; if (!from) { dptr->nx = dptr->ny = dptr->nz = 0; } else if (!((sscanf(from, "%dx%dx%d", &(dptr->nx), &(dptr->ny), &(dptr->nz)) == 3) || (sscanf(from, "%dX%dX%d", &(dptr->nx), &(dptr->ny), &(dptr->nz)) == 3))) { return (-1); } return (1); } // // CvtToStrVec() // // convert a colon delimited ascii string to vector of C++ STL strings // int Wasp::CvtToStrVec(const char *from, /* the string */ void * to) { vector *vptr = (vector *)to; vptr->clear(); (void)SplitString(from, ':', *vptr); return (1); } // // CvtToIntVec() // // convert a colon delimited ascii string to vector of C++ STL ints // int Wasp::CvtToIntVec(const char *from, /* the string */ void * to) { vector *vptr = (vector *)to; vptr->clear(); string s(from); char delim; if (s.find(":") != string::npos) { delim = ':'; } else { delim = 'x'; } (void)SplitString(from, delim, *vptr); return (1); } // // CvtToSize_tVec() // // convert a colon delimited ascii string to vector of C++ STL size_t // int Wasp::CvtToSize_tVec(const char *from, /* the string */ void * to) { vector *vptr = (vector *)to; vptr->clear(); string s(from); char delim; if (s.find(":") != string::npos) { delim = ':'; } else { delim = 'x'; } (void)SplitString(from, delim, *vptr); return (1); } // // CvtToFloatVec() // // convert a colon delimited ascii string to vector of C++ STL float // int Wasp::CvtToFloatVec(const char *from, /* the string */ void * to) { vector *vptr = (vector *)to; vptr->clear(); string s(from); char delim; if (s.find(":") != string::npos) { delim = ':'; } else { delim = 'x'; } (void)SplitString(from, delim, *vptr); return (1); } // // CvtToDoubleVec() // // convert a colon delimited ascii string to vector of C++ STL float // int Wasp::CvtToDoubleVec(const char *from, /* the string */ void * to) { vector *vptr = (vector *)to; vptr->clear(); string s(from); char delim; if (s.find(":") != string::npos) { delim = ':'; } else { delim = 'x'; } (void)SplitString(from, delim, *vptr); return (1); } // // CvtToIntRange() // // convert a colon-delimited string of ints to a min/max pair /// int Wasp::CvtToIntRange(const char *from, /* the string */ void * to) { OptionParser::IntRange_T *dptr = (OptionParser::IntRange_T *)to; if (!from) { dptr->min = dptr->max = 0; } else if (!((sscanf(from, "%d:%d", &(dptr->min), &(dptr->max))) == 2)) { return (-1); } return (1); } OptionParser::OptionParser() { _optTbl.clear(); } OptionParser::~OptionParser() { _OptRec_T *o; for (int i = 0; i < (int)_optTbl.size(); i++) { o = _optTbl[i]; if (o->option) free((void *)o->option); if (o->value) free((void *)o->value); if (o->default_value) free((void *)o->default_value); if (o->help) free((void *)o->help); delete o; } _optTbl.clear(); } /* * AppendOptions * * Add a list of valid application options to the option table. All * options are assumed to begin with a '-' and contain 0 or more arguments. * * The fields of the DPOptDescRec struct are as follows: * * char *option; name of option without preceeding '-' * int arg_count; num args expected by option * char *value; default value for the argument - if 'arg_count' * is zero 'value' is ignored. if 'arg_count' is * greater than 1 'value' is a string of space * separted arguments. * char *help; help string for option * * * on entry * od : option descriptor * optd : Null terminated list of options * * on exit * return : -1 => failure, else OK. */ int OptionParser::AppendOptions(const OptDescRec_T *odr) { int i, j; int num; _OptRec_T *opt_rec; if (!odr[0].option) return (0); /* * make sure there are no duplicate names in the table. This only * compares new entries with old entries. If there are duplicate * entries within the new entries they won't be found. Count * how many options there are as well */ for (j = 0, num = 0; odr[j].option; j++) { for (i = 0; i < (int)_optTbl.size(); i++) { if (strcmp(_optTbl[i]->option, odr[j].option) == 0) { SetErrMsg("Option %s already in option table", odr[j].option); return (-1); /* duplicate entry */ } } num++; } /* * copy all the options into the option table allocating memory * as necessary. */ for (i = 0; i < num; i++) { opt_rec = new _OptRec_T; _optTbl.push_back(opt_rec); char *value = NULL; if (odr[i].arg_count == 0) { value = strdup("false"); } else { if (odr[i].value) value = strdup(odr[i].value); } if (!odr[i].option) { SetErrMsg("Invalid option descriptor"); return (-1); } if (value) { value = fmt_opt_string(value, odr[i].arg_count); if (!value) { SetErrMsg("Arg string invalid: %s", value); return (-1); } } opt_rec->option = strdup(odr[i].option); opt_rec->default_value = value; opt_rec->value = strdup(value); opt_rec->help = strdup(odr[i].help); opt_rec->arg_count = odr[i].arg_count; } return (0); } /* * RemoveOptions * [exported] * * Remove a list of application options from the option table. * Only the 'option' field of the DPOptDescRec struct is referenced, * all other fields are ignored. The options to be freed must have * previously been set with a call to DPLoadOptionTable(). * * * on entry * od : option descriptor * odr : Null terminated list of options * */ void OptionParser::RemoveOptions(vector options) { int j; vector<_OptRec_T *>::iterator itr; /* * look for the option in the option table. */ for (j = 0; j < options.size(); j++) { for (itr = _optTbl.begin(); itr != _optTbl.end(); ++itr) { _OptRec_T *o = *itr; if (options[j].compare(o->option) == 0) { if (o->option) free((void *)o->option); if (o->value) free((void *)o->value); if (o->default_value) free((void *)o->default_value); if (o->help) free((void *)o->help); _optTbl.erase(itr); break; } } } } /* * ParseOption * [exported] * * parse the option table with the command line options. After the * option table is created with DPLoadOptionTable this function may * be called to change values of options in the table. We assume * argv[0] is the program name and we leave it unmolested * * DPErrLog() is invoked on error. * * on entry: * **argv : list of command line args * *argc : num elements in argv * *optds : additional options to merge into the option table * on exit * **argv : contains options not found in the option table * *argc : num elements in argv * return : -1 => failure, else OK */ int OptionParser::ParseOptions(int *argc, char **argv, Option_T *options) { int i; int new_argc = 1; char ** next = argv + 1; _OptRec_T *o; if (!argv) return (1); /* ** Restore default values for options in option table */ for (i = 0; i < (int)_optTbl.size(); i++) { o = _optTbl[i]; if (o->value) free((void *)o->value); o->value = strdup(o->default_value); } /* * look for matches between elements in argv and in the option table */ for (i = 1; i < *argc; i++) { if (*argv[i] == '-') { /* is it an option specifier? */ o = _get_option((char *)(argv[i] + 1)); } else { o = (_OptRec_T *)NULL; /* not a specifier */ } if (o == (_OptRec_T *)-1) { SetErrMsg("Ambiguous option: %s", argv[i]); return (-1); } /* * if no match found leave option in argv along with anything * that follows that is not an option specifier */ if (!o) { /* not found */ *next = argv[i]; new_argc++; next++; while (i + 1 < *argc && *argv[i + 1] != '-') { i++; new_argc++; *next = argv[i]; next++; } continue; } /* * make sure enough args for option */ if ((i + o->arg_count) >= *argc) { SetErrMsg("Option -%s expects %d args", o->option, o->arg_count); return (-1); } /* * Options with no args are a special case. Assign them * a value of true. They are false by default */ if (o->arg_count == 0) { o->value = strdup("true"); continue; } /* * convert the arg list to a single string and stash it * in the option table */ o->value = copy_create_arg_string(&argv[i + 1], o->arg_count); i += o->arg_count; } *argc = new_argc; argv[*argc] = NULL; return (_parse_options(options)); return (0); } /* * DPParseEnvOptions() * * DPParseEnvOptions() is analogous to DPParseOptionTable except that * it takes a list of environment variables and their coresponding * option names instead of an argv list. If a given environment * variable is set its value is used as the argument value for the * option with which it is associated. If the environment variable * is not set the option/environemnt variable pair are ignored. * * on entry * *envv : NUll-terminated list of option/env pairs * *optds : additional options to merge into the option table * * on exit * return : -1 => error, else OK */ int OptionParser::ParseOptions(const EnvOpt_T *envv, Option_T *opts) { const EnvOpt_T *envptr; /* pointer to envv */ char ** argv; /* arg vector created from envv */ int argc; /* size of argv list */ char * arg_string; /* env variable value */ int i; // count the args for (envptr = envv, argc = 0; envptr->option; envptr++, argc += 2) ; argv = new char *[argc + 2]; argv[0] = strdup("place_holder"); /* * look for environment variables. Generate the argument vector, argv */ for (envptr = envv, i = 1; envptr->option; envptr++, i += 2) { if ((arg_string = getenv(envptr->env_var))) { argv[i] = new char[strlen(arg_string + 2)]; argv[i] = strcpy(argv[i], "-"); argv[i] = strcat(argv[i], envptr->option); argv[i + 1] = strdup(arg_string); } } argv[i] = NULL; return (ParseOptions(&argc, argv, opts)); } // // PrintOptionHelp() // // Print help about each option. // // Each option known to the option table is printed, followed by // the string "arg0 arg1 ... argN", where N+1 is the number of arguments // expected by the option, followed by the contents of the 'help' field. // // on entry // *fp : file pointer where output is written. // void OptionParser::PrintOptionHelp(FILE *fp, int linelimit, bool docopyright) { std::sort(_optTbl.begin(), _optTbl.end(), opt_cmp); string h1("OPTION"); string d1("------"); string h2("NUM_ARGS"); string d2("--------"); string h3("DEFAULT"); string d3("-------"); int f1 = h1.size(); int f2 = h2.size(); int f3 = h3.size(); for (int i = 0; i < (int)_optTbl.size(); i++) { string option = _optTbl[i]->option; if (option.size() > f1) f1 = option.size(); string default_value = _optTbl[i]->default_value; if (default_value.size() > f3) f3 = default_value.size(); } f1 += 4; f2 += 4; f3 += 4; ostringstream format; format << " "; format << "%-"; format << f1; format << "."; format << f1; format << "s"; format << "%-"; format << f2; format << "."; format << f2; format << "s"; format << "%-"; format << f3; format << "."; format << f3; format << "s"; fprintf(fp, format.str().c_str(), h1.c_str(), h2.c_str(), h3.c_str()); fprintf(fp, "\n"); fprintf(fp, format.str().c_str(), d1.c_str(), d2.c_str(), d3.c_str()); fprintf(fp, "\n"); string margin(" "); for (int i = 0; i < (int)_optTbl.size(); i++) { _OptRec_T * o = _optTbl[i]; ostringstream arg_count_str; arg_count_str << o->arg_count; string option = "-"; option.append(o->option); string defvalstr(o->default_value); if (!defvalstr.size()) defvalstr = "\"\""; fprintf(fp, format.str().c_str(), option.c_str(), arg_count_str.str().c_str(), defvalstr.c_str()); vector helpvec; string helpstr(o->help); StrToWordVec(helpstr, helpvec); int linecount = linelimit; for (int j = 0; j < helpvec.size(); j++) { if (linecount + helpvec[j].size() < linelimit) { fprintf(fp, "%s ", helpvec[j].c_str()); linecount += helpvec[j].size() + 1; } else { linecount = 0; fprintf(fp, "\n%s%s ", margin.c_str(), helpvec[j].c_str()); linecount += margin.size() + helpvec[j].size() + 1; } } fprintf(fp, "\n"); } #ifdef VAPOR3_0_0_ALPHA for (i = 0; i < (int)_optTbl.size(); i++) { _OptRec_T *o = _optTbl[i]; sprintf(buf, " -%-8.8s", o->option); if (o->arg_count < 4) { for (j = 0; j < o->arg_count; j++) { sprintf(sbf, " arg%d", j); if (strlen(sbf) + strlen(buf) < sizeof(buf)) { (void)strcat(buf, sbf); } else { break; } } } else { sprintf(sbf, " arg0 .. arg%d", o->arg_count - 1); (void)strcat(buf, sbf); } (void)fprintf(fp, buf); for (j = (int)strlen(buf); j < (int)sizeof(buf); j++) { putc(' ', fp); } if (o->help) { (void)fprintf(fp, "%s\n", (char *)o->help); } else { (void)fprintf(fp, "\n"); } } #endif if (!docopyright) return; fprintf(fp, "\nCopyright 2007 The National Center for Atmospheric Research\n"); fprintf(fp, "\nVersion: %s (%s) www.vapor.ucar.edu\n", Version::GetVersionString().c_str(), Version::GetDateString().c_str()); } // // get_option // [internal] // // on entry // *name : name to lookup // on exit // return : if found return command obj ptr. If name is ambiguous // return -1. If not found return NULL. // OptionParser::_OptRec_T *OptionParser::_get_option(const char *name) { _OptRec_T *o; _OptRec_T *found; int nmatches; int i; nmatches = 0; found = NULL; for (i = 0; i < (int)_optTbl.size(); i++) { o = _optTbl[i]; if (strcmp(o->option, name) == 0) { return (o); // exact match } if (strncmp(o->option, name, strlen(name)) == 0) { nmatches++; found = o; }; } if (nmatches > 1) /* ambiguous */ return ((_OptRec_T *)-1); return (found); } // // // _parse_options // // The fields of the Option struct are as follows: // // char *option_name; the options name - used to look the // requested option in the option table. // int (*type_conv)(); option type converter - converts the // string representation of the option // value into a specified format and store // the result at address given by 'offset' // void *offset; offset of return address // int size; size of option in bytes - if there are // multiple arguments for a single option // their destination address is computed // by adding 'size' to 'offset' as // appropriate. // // // on entry // options : Null terminated list of options to be returned // // on exit // options : offset field of options record filled in // return : -1 => failure, else OK // int OptionParser::_parse_options(const Option_T *options) { int i, j; const char *s; int arg_count; _OptRec_T *o; void * offset; for (i = 0; options[i].option_name; i++) { /* * find the option */ o = _get_option(options[i].option_name); if (o == (_OptRec_T *)-1) { SetErrMsg("Ambiguous option: %s", options[i].option_name); return (-1); } if (!o) { // SetErrMsg("Option %s unknown", options[i].option_name); // return(-1); continue; } /* * zero arg_count options really do have a single argument */ arg_count = o->arg_count ? o->arg_count : 1; offset = options[i].offset; for (j = 0, s = o->value; j < arg_count; j++) { if (options[i].type_conv(s, offset) < 0) { SetErrMsg("Type converter for option \"-%s\" " "failed to convert argument \"%s\"", options[i].option_name, s); return (-1); } if (s) s += strlen(s) + 1; offset = (char *)offset + options[i].size; } } return (0); } ================================================ FILE: lib/common/PVTime.cpp ================================================ // // $Id$ // // pivotal_gmtime_r - a replacement for gmtime/localtime/mktime // that works around the 2038 bug on 32-bit // systems. (Version 3) // // Copyright (C) 2005 Paul Sheer // // Redistribution and use in source form, with or without modification, // is permitted provided that the above copyright notice, this list of // conditions, the following disclaimer, and the following char array // are retained. // // Redistribution and use in binary form must reproduce an // // acknowledgment: 'With software provided by http://2038bug.com/' in // the documentation and/or other materials provided with the // distribution, and wherever such acknowledgments are usually // accessible in Your program. // // This software is provided "AS IS" and WITHOUT WARRANTY, either // express or implied, including, without limitation, the warranties of // NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THIS SOFTWARE IS WITH // YOU. Under no circumstances and under no legal theory, whether in // tort (including negligence), contract, or otherwise, shall the // copyright owners be liable for any direct, indirect, special, // incidental, or consequential damages of any character arising as a // result of the use of this software including, without limitation, // damages for loss of goodwill, work stoppage, computer failure or // malfunction, or any and all other commercial damages or losses. This // limitation of liability shall not apply to liability for death or // personal injury resulting from copyright owners' negligence to the // extent applicable law prohibits such limitation. Some jurisdictions // do not allow the exclusion or limitation of incidental or // consequential damages, so this exclusion and limitation may not apply // to You. #include #include #include #include #include "vapor/VAssert.h" #include #include #include using namespace Wasp; // mktime64() is a 64-bit equivalent of mktime(). // localtime64_r() is a 64-bit equivalent of localtime_r(). // gmtime64_r() is a 64-bit equivalent of gmtime_r(). static const int days[4][13] = { {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}, }; #define LEAP_CHECK(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0) #define WRAP(a, b, m) ((a) = ((a) < 0) ? ((b)--, (a) + (m)) : (a)) TIME64_T pivot_time_t(const time_t *now, TIME64_T *_t) { TIME64_T t; t = *_t; if (now && sizeof(time_t) == 4) { time_t _now; _now = *now; if (_now < 1106500000 /* Jan 23 2005 - date of writing */) _now = 2147483647; if ((TIME64_T)t + ((TIME64_T)1 << 31) < (TIME64_T)_now) t += (TIME64_T)1 << 32; } return t; } static struct tm *_gmtime64_r(const time_t *now, TIME64_T *_t, struct tm *p) { int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday, v_tm_tday; int leap; TIME64_T t; long m; t = pivot_time_t(now, _t); v_tm_sec = ((TIME64_T)t % (TIME64_T)60); t /= 60; v_tm_min = ((TIME64_T)t % (TIME64_T)60); t /= 60; v_tm_hour = ((TIME64_T)t % (TIME64_T)24); t /= 24; v_tm_tday = t; WRAP(v_tm_sec, v_tm_min, 60); WRAP(v_tm_min, v_tm_hour, 60); WRAP(v_tm_hour, v_tm_tday, 24); if ((v_tm_wday = (v_tm_tday + 4) % 7) < 0) v_tm_wday += 7; m = (long)v_tm_tday; if (m >= 0) { p->tm_year = 70; leap = LEAP_CHECK(p->tm_year); while (m >= (long)days[leap + 2][12]) { m -= (long)days[leap + 2][12]; p->tm_year++; leap = LEAP_CHECK(p->tm_year); } v_tm_mon = 0; while (m >= (long)days[leap][v_tm_mon]) { m -= (long)days[leap][v_tm_mon]; v_tm_mon++; } } else { p->tm_year = 69; leap = LEAP_CHECK(p->tm_year); while (m < (long)-days[leap + 2][12]) { m += (long)days[leap + 2][12]; p->tm_year--; leap = LEAP_CHECK(p->tm_year); } v_tm_mon = 11; while (m < (long)-days[leap][v_tm_mon]) { m += (long)days[leap][v_tm_mon]; v_tm_mon--; } m += (long)days[leap][v_tm_mon]; } p->tm_mday = (int)m + 1; p->tm_yday = days[leap + 2][v_tm_mon] + m; p->tm_sec = v_tm_sec, p->tm_min = v_tm_min, p->tm_hour = v_tm_hour, p->tm_mon = v_tm_mon, p->tm_wday = v_tm_wday; return p; } static struct tm *_localtime64_r(const time_t *now, TIME64_T *_t, struct tm *p) { TIME64_T tl; time_t t; struct tm tm, tm_localtime, tm_gmtime; _gmtime64_r(now, _t, &tm); if (tm.tm_year > (2037 - 1900)) tm.tm_year = 2037 - 1900; t = MkTime64(&tm); #ifdef WIN32 #pragma warning(disable : 4996) struct tm *tm_localtime_ptr, *tm_gmtime_ptr; tm_localtime_ptr = localtime(&t); tm_localtime = *tm_localtime_ptr; tm_gmtime_ptr = gmtime(&t); tm_gmtime = *tm_gmtime_ptr; #else localtime_r(&t, &tm_localtime); gmtime_r(&t, &tm_gmtime); #endif tl = *_t; tl += (MkTime64(&tm_localtime) - MkTime64(&tm_gmtime)); _gmtime64_r(now, &tl, p); p->tm_isdst = tm_localtime.tm_isdst; return p; } struct tm *Wasp::GmTime64_r(const TIME64_T *_t, struct tm *p) { TIME64_T t; t = *_t; return _gmtime64_r(NULL, &t, p); } TIME64_T Wasp::MkTime64(struct tm *t) { int i, y; long day = 0; TIME64_T r; if (t->tm_year < 70) { y = 69; do { day -= 365 + LEAP_CHECK(y); y--; } while (y >= t->tm_year); } else { y = 70; while (y < t->tm_year) { day += 365 + LEAP_CHECK(y); y++; } } for (i = 0; i < t->tm_mon; i++) day += days[LEAP_CHECK(t->tm_year)][i]; day += t->tm_mday - 1; t->tm_wday = (int)((day + 4) % 7); r = (TIME64_T)day * 86400; r += t->tm_hour * 3600; r += t->tm_min * 60; r += t->tm_sec; return r; } struct tm *Wasp::LocalTime64_r(const TIME64_T *_t, struct tm *p) { TIME64_T tl; tl = *_t; return _localtime64_r(NULL, &tl, p); } ================================================ FILE: lib/common/Progress.cpp ================================================ #include #include using namespace VAPoR; Progress::Start_t Progress::_start = [](const std::string &, long, bool) {}; Progress::Update_t Progress::_update = [](long, bool *) {}; Progress::Finish_t Progress::_finish = []() {}; bool Progress::_cancelled = false; long Progress::_total = 1; void Progress::Start(const std::string &name, long total, bool cancelable) { _start(name, total, cancelable); _cancelled = false; _total = total; } void Progress::StartIndefinite(const std::string &name, bool cancelable) { Progress::Start(name, 0, cancelable); } void Progress::Update(long completed) { if (_total > 100 && completed % (_total / 100) != 0 && completed != 0) return; _update(completed, &_cancelled); } void Progress::Finish() { _finish(); } void Progress::SetHandlers(Start_t start, Update_t update, Finish_t finish) { assert((bool)start); assert((bool)update); assert((bool)finish); _start = start; _update = update; _finish = finish; } #ifndef NDEBUG #ifndef WIN32 #include void Progress::Sleep(double s) { usleep(s * 1e6L); } #endif #endif ================================================ FILE: lib/common/ResourcePath.cpp ================================================ #include #include #include #include #include #include #include #define INCLUDE_DEPRECATED_GET_APP_PATH #include "vapor/GetAppPath.h" #define FORCE_USE_DEV_LIBS 0 #if FORCE_USE_DEV_LIBS #ifndef NDEBUG #error Forced use of development libraries enabled for release build #endif #endif #ifdef Darwin #include string GetMacBundlePath() { CFBundleRef mainBundle = CFBundleGetMainBundle(); CFURLRef resourcesURL = CFBundleCopyBundleURL(mainBundle); CFStringRef str = CFURLCopyFileSystemPath(resourcesURL, kCFURLPOSIXPathStyle); CFRelease(resourcesURL); char path[PATH_MAX]; CFStringGetCString(str, path, PATH_MAX, kCFStringEncodingASCII); CFRelease(str); return string(path); } #endif string CallGetAppPathForResourceName(const string &name) { vector dirs; string getAppPathName; Wasp::SplitString(name, '/', dirs); if (dirs.empty()) { getAppPathName = "home"; } else { getAppPathName = dirs[0]; dirs.erase(dirs.begin()); } return Wasp::GetAppPath("VAPOR", getAppPathName, dirs); } string GetInstalledResourceRoot() { string path; #if defined Darwin path = GetMacBundlePath(); path = Wasp::FileUtils::JoinPaths({path, "Contents"}); #elif defined WIN32 path = string(Wasp::GetEnvironmentalVariable("VAPOR3_HOME")); #else path = string(Wasp::GetEnvironmentalVariable("VAPOR_HOME")); #endif return path; } #define TRY_PATH(p) { \ string path = Wasp::FileUtils::POSIXPathToCurrentOS(p); \ if (Wasp::FileUtils::Exists(path)) {return path;} \ } std::string (*resourceFinderCB)(const std::string &) = nullptr; string GetResourcePathFromCallback(const std::string &name) { if (resourceFinderCB) return resourceFinderCB(name); return ""; } std::string Wasp::GetResourcePath(const std::string &name) { #if FORCE_USE_DEV_LIBS TRY_PATH(FileUtils::JoinPaths({SOURCE_DIR, name})); #else TRY_PATH(GetResourcePathFromCallback(name)); TRY_PATH(FileUtils::JoinPaths({GetInstalledResourceRoot(), name})); TRY_PATH(FileUtils::JoinPaths({SOURCE_DIR, name})); TRY_PATH(FileUtils::JoinPaths({THIRD_PARTY_DIR, name})); TRY_PATH(CallGetAppPathForResourceName(name)); #endif return ""; } std::string Wasp::GetSharePath(const std::string &name) { return GetResourcePath("share/" + name); } #if defined(WIN32) #define PYTHON_MODULE_SUBDIR ("python" + string(PYTHON_VERSION)) #else #define PYTHON_MODULE_SUBDIR ("lib/python" + string(PYTHON_VERSION)) #endif std::string Wasp::GetPythonVersion() { return std::string(PYTHON_VERSION); } std::string Wasp::GetPythonPath() { string path = GetResourcePath(PYTHON_MODULE_SUBDIR); if (!FileUtils::Exists(path)) path = string(PYTHON_PATH); return path; } std::string Wasp::GetPythonDir() { std::string path2; #if defined(__APPLE__) string path = GetResourcePath("Resources"); #else string path = GetResourcePath(""); #endif std::string modulePath = FileUtils::JoinPaths( {path, PYTHON_MODULE_SUBDIR} ); if (!FileUtils::Exists( modulePath )) path = string(PYTHON_DIR); return path; } void Wasp::RegisterResourceFinder(std::string (*cb)(const std::string &)) { assert(resourceFinderCB == nullptr); resourceFinderCB = cb; } ================================================ FILE: lib/common/STLUtils.cpp ================================================ #include #include using std::string; using std::vector; bool STLUtils::Contains(const std::string &toSearch, const std::string &query) { return toSearch.find(query) != string::npos; } bool STLUtils::ContainsIgnoreCase(const std::string &toSearch, const std::string &query) { return Contains(ToLower(toSearch), ToLower(query)); } bool STLUtils::EndsWith(const std::string &str, const std::string &match) { return str.size() >= match.size() && equal(match.begin(), match.end(), str.end() - match.size()); } bool STLUtils::BeginsWith(const std::string &str, const std::string &match) { return STLUtils::BeginsWith(str, match); } std::string STLUtils::ToLower(std::string str) { std::transform(str.begin(), str.end(), str.begin(), ::tolower); return str; } std::vector STLUtils::Split(std::string str, const std::string &delimeter) { size_t index; vector parts; while ((index = str.find(delimeter)) != string::npos) { parts.push_back(str.substr(0, index)); str.erase(0, index + delimeter.length()); } parts.push_back(str); return parts; } std::string STLUtils::Join(const std::vector &parts, const std::string &delimeter) { string whole; auto itr = parts.begin(); if (itr != parts.end()) whole = *itr++; for (; itr != parts.end(); ++itr) whole += delimeter + *itr; return whole; } std::string STLUtils::ReplaceAll(std::string source, const std::string &oldSegment, const std::string &newSegment) { size_t start = 0; size_t index; while ((index = source.find(oldSegment, start)) != string::npos) { source.replace(index, oldSegment.length(), newSegment); start = index + newSegment.length(); } return source; } std::string STLUtils::GetCurrentDateTimestamp() { auto now = std::chrono::system_clock::now(); std::time_t now_c = std::chrono::system_clock::to_time_t(now); std::string timeString = std::ctime(&now_c); timeString.pop_back(); // Remove trailing endline return timeString; } ================================================ FILE: lib/common/TMSUtils.cpp ================================================ #include #include #include #include #include #include using namespace Wasp; //! Returns true if \p path is a Tile Mapping Service master file // bool TMSUtils::IsTMSFile(std::string path) { if (path.rfind(".tms", path.size() - 4) != string::npos) { return true; } return false; } //! Returns the path to the TMS file containing the specified tile // std::string TMSUtils::TilePath(string file, size_t tileX, size_t tileY, int lod) { // If we're given a file instead of a directory, remove the .tms extension // if (file.rfind(".tms", file.size() - 4) != string::npos) { file.erase(file.length() - 4, 4); } size_t tmsTileY = tileY; ostringstream oss; oss << file; oss << "/"; oss << lod; oss << "/"; oss << tileX; oss << "/"; oss << tmsTileY; string base = oss.str(); string path = base + ".tif"; struct stat statbuf; if (stat(path.c_str(), &statbuf) == 0) return (path); path = base + ".tiff"; if (stat(path.c_str(), &statbuf) == 0) return (path); // Tile does not exist // return (""); } //! Returns the number of LODs in the TMS file referened by \p file // int TMSUtils::GetNumTMSLODs(std::string file) { int lod = 0; while (TilePath(file, 0, 0, lod) != "") { lod++; } return lod; } ================================================ FILE: lib/common/VAssert.cpp ================================================ #include #include #include #include #include #include void Wasp::_VAssertFailed(const char *expr, const char *path, const unsigned int line) { char *fileName = strdup(FileUtils::Basename(std::string(path)).c_str()); fprintf(stderr, "VAssert(%s) failed in %s, line %i\n", expr, fileName, line); free(fileName); #ifdef NDEBUG exit(1); #else raise(SIGINT); #endif } ================================================ FILE: lib/common/Version.cpp ================================================ #include #include #include #include #include #include #include #include using namespace Wasp; using namespace std; // // If these aren't defined here, the module won't link! // string Version::_formatString; string Version::_dateString; const int Version::_majorVersion = MAJOR; const int Version::_minorVersion = MINOR; const int Version::_minorMinorVersion = MICRO; const string &Version::GetVersionString() { ostringstream oss; oss << _majorVersion << "." << _minorVersion << "." << _minorMinorVersion; if (GetRC().length()) oss << "." << GetRC(); _formatString = oss.str(); StrRmWhiteSpace(_formatString); return (_formatString); } const string &Version::GetFullVersionString() { ostringstream oss; oss << _majorVersion << "." << _minorVersion << "." << _minorMinorVersion; if (GetRC().length()) oss << "." << GetRC(); oss << "." << GetBuildHash(); _formatString = oss.str(); StrRmWhiteSpace(_formatString); return (_formatString); } const string Version::GetBuildHash() { string hash = string(VERSION_COMMIT); if (hash.empty()) return ""; else return hash; } int Version::Compare(int major, int minor, int minorminor) { if (major != _majorVersion) { return (major > _majorVersion ? -1 : 1); } if (minor != _minorVersion) { return (minor > _minorVersion ? -1 : 1); } if (minorminor != _minorMinorVersion) { return (minorminor > _minorMinorVersion ? -1 : 1); } return (0); } namespace { vector split(string s, string delim) { size_t pos = 0; vector tokens; while ((pos = s.find(delim)) != std::string::npos) { tokens.push_back(s.substr(0, pos)); s.erase(0, pos + delim.length()); } if (!s.empty()) tokens.push_back(s); return (tokens); } }; // namespace void Version::Parse(string s, int &major, int &minor, int &minorminor, string &rc) { StrRmWhiteSpace(s); major = 0; minor = 0; minorminor = 0; rc = ""; vector tokens = split(s, "."); if (tokens.size() > 0) { istringstream ist(tokens[0]); if (!ist.eof()) ist >> major; } if (tokens.size() > 1) { istringstream ist(tokens[1]); if (!ist.eof()) ist >> minor; } if (tokens.size() > 2) { istringstream ist(tokens[2]); if (!ist.eof()) ist >> minorminor; } if (tokens.size() > 3) { rc = tokens[3]; } } int Version::Compare(string v1, string v2) { StrRmWhiteSpace(v1); StrRmWhiteSpace(v2); int major1, minor1, minorminor1; string rc1; int major2, minor2, minorminor2; string rc2; Version::Parse(v1, major1, minor1, minorminor1, rc1); Version::Parse(v2, major2, minor2, minorminor2, rc2); if (major1 < major2) return (-1); else if (major1 > major2) return (1); if (minor1 < minor2) return (-1); else if (minor1 > minor2) return (1); if (minorminor1 < minorminor2) return (-1); else if (minorminor1 > minorminor2) return (1); // // comparison for rc token isn't lexicographical: version strings // without a rc token are greater than version strings with a rc token // if (rc1.length() && rc2.length()) { if (StrCmpNoCase(rc1, rc2) < 0) return (-1); else if (StrCmpNoCase(rc1, rc2) > 0) return (1); } else if (rc1.length() && !rc2.length()) { return (1); } else if (!rc1.length() && rc2.length()) { return (-1); } return (0); } ================================================ FILE: lib/common/common.cpp ================================================ // common.cpp : Defines the entry point for the DLL application. // #ifdef WIN32 #include #include "windows.h" BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } /* // This is an example of an exported variable COMMON_API int ncommon=0; // This is an example of an exported function. COMMON_API int fncommon(void) { return 42; } // This is the constructor of a class that has been exported. // see common.h for the class definition Ccommon::Ccommon() { return; } */ #endif ================================================ FILE: lib/common/utils.cpp ================================================ #include "vapor/VAssert.h" #include #include #include #include #define MAXCOORDS 4 using namespace std; using namespace Wasp; void *SmartBuf::Alloc(size_t size) { if (size <= _buf_sz) return (_buf); if (_buf) delete[] _buf; _buf = new unsigned char[size]; _buf_sz = size; return (_buf); } // convert tuple of multi-dimensional coordinates, 'coord', for a space // with min and max bounds to a linear offset from 'min' // size_t Wasp::LinearizeCoords(const size_t *coords, const size_t *min, const size_t *max, size_t n) { size_t offset = 0; for (size_t i = 0; i < n; i++) { VAssert(coords[i] >= min[i]); VAssert(coords[i] <= max[i]); } size_t factor = 1; for (size_t i = 0; i < n; i++) { offset += factor * (coords[i] - min[i]); factor *= max[i] - min[i] + 1; } return (offset); } size_t Wasp::LinearizeCoords(const std::vector &coords, const std::vector &dims) { VAssert(coords.size() == dims.size()); return (LinearizeCoords(coords.data(), dims.data(), coords.size())); } size_t Wasp::LinearizeCoords(const size_t *coords, const size_t *dims, size_t n) { VAssert(n <= MAXCOORDS); size_t min[MAXCOORDS]; size_t max[MAXCOORDS]; for (size_t i = 0; i < n; i++) { min[i] = 0; max[i] = dims[i] - 1; } size_t returnVal = Wasp::LinearizeCoords(coords, min, max, n); return (returnVal); } size_t Wasp::LinearizeCoords(const std::vector &coords, const std::vector &min, const std::vector &max) { VAssert(coords.size() == min.size()); VAssert(coords.size() == max.size()); return (LinearizeCoords(coords.data(), min.data(), max.data(), coords.size())); } void Wasp::VectorizeCoords(size_t offset, const size_t *min, const size_t *max, size_t *coords, size_t n) { size_t factor = 1; for (size_t i = 0; i < n; i++) { VAssert(min[i] <= max[i]); coords[i] = (offset % (factor * (max[i] - min[i] + 1))) / factor; offset = offset - coords[i] * factor; factor *= (max[i] - min[i] + 1); } VAssert(offset == 0); } std::vector Wasp::VectorizeCoords(size_t offset, const std::vector &min, const std::vector &max) { VAssert(min.size() == max.size()); size_t coords[MAXCOORDS]; VectorizeCoords(offset, min.data(), max.data(), coords, min.size()); std::vector coordsvec(min.size(), 0); for (int i = 0; i < min.size(); i++) coordsvec[i] = coords[i]; return (coordsvec); } void Wasp::VectorizeCoords(size_t offset, const size_t *dims, size_t *coords, size_t n) { VAssert(n <= MAXCOORDS); size_t min[MAXCOORDS]; size_t max[MAXCOORDS]; for (size_t i = 0; i < n; i++) { min[i] = 0; max[i] = dims[i] - 1; } Wasp::VectorizeCoords(offset, min, max, coords, n); } std::vector Wasp::VectorizeCoords(size_t offset, const std::vector &dims) { size_t coords[MAXCOORDS]; VectorizeCoords(offset, dims.data(), coords, dims.size()); std::vector coordsvec(dims.size(), 0); for (int i = 0; i < dims.size(); i++) coordsvec[i] = coords[i]; return (coordsvec); } void Wasp::IncrementCoords(const size_t *min, const size_t *max, size_t *counter, size_t n, int dim) { for (int i = dim; i < n; i++) { if (counter[i] < (max[i])) { counter[i] += 1; break; } counter[i] = min[i]; } } vector Wasp::IncrementCoords(const vector &min, const vector &max, vector counter, int dim) { VAssert(min.size() == max.size()); VAssert(min.size() == counter.size()); IncrementCoords(min.data(), max.data(), counter.data(), min.size(), dim); return (counter); } vector Wasp::Dims(const vector &min, const vector &max) { VAssert(min.size() == max.size()); vector dims; for (int i = 0; i < min.size(); i++) { VAssert(min[i] <= max[i]); dims.push_back(max[i] - min[i] + 1); } return (dims); } size_t Wasp::VProduct(const size_t *a, size_t n) { size_t ntotal = 1; for (size_t i = 0; i < n; i++) ntotal *= a[i]; return (ntotal); } size_t Wasp::VProduct(const std::vector &a) { return (VProduct(a.data(), a.size())); } #define BLOCKSIZE 256 void Wasp::Transpose(const float *a, float *b, size_t p1, size_t m1, size_t s1, size_t p2, size_t m2, size_t s2) { size_t I1, I2; size_t i1, i2; size_t q, r; const size_t block = BLOCKSIZE; for (I2 = p2; I2 < p2 + m2; I2 += block) for (I1 = p1; I1 < p1 + m1; I1 += block) for (i2 = I2; i2 < min(I2 + block, p2 + m2); i2++) for (i1 = I1; i1 < min(I1 + block, p1 + m1); i1++) { q = i2 * s1 + i1; r = i1 * s2 + i2; b[r] = a[q]; } } void Wasp::Transpose(const float *a, float *b, size_t s1, size_t s2) { Wasp::Transpose(a, b, 0, s1, s1, 0, s2, s2); } bool Wasp::BinarySearchRange(const vector &sorted, double x, size_t &i) { i = 0; if (sorted.size() == 1) return (sorted[0] == x); // if sorted in ascending order // if (sorted[0] <= sorted[sorted.size() - 1]) { if (x < sorted[0]) return (false); if (x == sorted[sorted.size() - 1]) { i = sorted.size() - 2; return (true); } vector::const_iterator itr; itr = std::upper_bound(sorted.begin(), sorted.end(), x); if (itr == sorted.end()) { return (false); } if (itr != sorted.begin()) { --itr; } i = itr - sorted.begin(); } else { if (x < sorted[sorted.size() - 1]) return (false); if (x == sorted[sorted.size() - 1]) { i = sorted.size() - 2; return (true); } vector::const_reverse_iterator itr; itr = std::lower_bound(sorted.rbegin(), sorted.rend(), x); if (itr == sorted.rend()) { return (false); } if (itr != sorted.rbegin()) { ++itr; } i = sorted.rend() - itr; } return (true); } #ifdef DEPRECATED // // Remove after release 3.5 // bool Wasp::NearlyEqual(float a, float b, float epsilon) { float absA = std::fabs(a); float absB = std::fabs(b); float diff = std::fabs(a - b); // shortcut, handles infinities // if (a == b) return (true); if (a == 0.0 || b == 0.0 || (absA + absB < std::numeric_limits::min())) { // a or b is zero or both are extremely close to it // relative error is less meaningful here // return (diff < (epsilon * std::numeric_limits::min())); } // use relative error return (diff / min((absA + absB), std::numeric_limits::max()) < epsilon); } #endif bool Wasp::NearlyEqual(float a, float b, float epsilon, float abs_th) { VAssert(std::numeric_limits::epsilon() <= epsilon); VAssert(epsilon < 1.f); if (a == b) return true; auto diff = std::abs(a - b); auto norm = std::min((std::abs(a) + std::abs(b)), std::numeric_limits::max()); return diff < std::max(abs_th, epsilon * norm); } ================================================ FILE: lib/flow/Advection.cpp ================================================ #include #include "vapor/Advection.h" #include #include using namespace flow; // Constructor; Advection::Advection() : _lowerAngle(3.0f), _upperAngle(15.0f) { _lowerAngleCos = glm::cos(glm::radians(_lowerAngle)); _upperAngleCos = glm::cos(glm::radians(_upperAngle)); std::fill(_isPeriodic.begin(), _isPeriodic.end(), false); std::fill(_periodicBounds.begin(), _periodicBounds.end(), glm::vec2(0.0, 0.0)); } void Advection::UseSeedParticles(const std::vector &seeds) { _streams.clear(); _streams.resize(seeds.size()); for (size_t i = 0; i < seeds.size(); i++) _streams[i].push_back(seeds[i]); _separatorCount.assign(seeds.size(), 0); } int Advection::CheckReady() const { for (const auto &s : _streams) { if (s.size() < 1) return NO_SEED_PARTICLE_YET; } return 0; } int Advection::AdvectSteps(Field *velocity, double deltaT, size_t maxSteps, bool fixedStepSize, ADVECTION_METHOD method) { int ready = CheckReady(); if (ready != 0) return ready; bool happened = false; // Observation: user parameters are not gonna change while this function executes. // Action: lock these parameters. if (velocity->LockParams() != 0) return PARAMS_ERROR; // The particle advection process can be parallelized per particle // Each stream represents a trajectory for a single particle #pragma omp parallel for for (size_t streamIdx = 0; streamIdx < _streams.size(); streamIdx++) { auto& s = _streams[streamIdx]; size_t numberOfSteps = s.size() - _separatorCount[streamIdx]; while (numberOfSteps < maxSteps) { auto &past0 = s.back(); if (past0.IsSpecial()) // If the last particle is marked "special," break; // terminate stream immediately. double dt = deltaT; if (!fixedStepSize && s.size() > 2) // When not using fixed step sizes and there are at least 3 particles in the stream, { // none is a separator, we adjust *dt*. const auto &past1 = s[s.size() - 2]; const auto &past2 = s[s.size() - 3]; if ((!past1.IsSpecial()) && (!past2.IsSpecial())) { // We enforce a factor of 20.0f as a limit of how much the step size // can be adjusted by _calcAdjustFactor(). // I.e., the adjusted value can be at most 20X larger or 20X smaller. // The choice of 20.0f is just an empirical value that seems to work well. double mindt = deltaT / 20.0, maxdt = deltaT * 20.0; dt = past0.time - past1.time; // step size used by last integration dt *= _calcAdjustFactor(past2, past1, past0); if (dt > 0) // integrate forward dt = glm::clamp(dt, mindt, maxdt); else // integrate backward dt = glm::clamp(dt, maxdt, mindt); } } Particle p1; int rv = 0; switch (method) { case ADVECTION_METHOD::EULER: rv = _advectEuler(velocity, past0, dt, p1); _printNonZero(rv, __FILE__, __func__, __LINE__); break; case ADVECTION_METHOD::RK4: rv = _advectRK4(velocity, past0, dt, p1); _printNonZero(rv, __FILE__, __func__, __LINE__); break; } if (rv == SUCCESS) { // Bookmark_1 // The new particle *may* be the same as the old particle in case // there's a sink, meaning the velocity is zero. // In that case, we mark p1 as "special" and terminate the current stream. if (p1.location == past0.location) { p1.SetSpecial(true); s.emplace_back(p1); _separatorCount[streamIdx]++; break; } else { happened = true; s.emplace_back(p1); numberOfSteps++; } } else if (rv == MISSING_VAL) { // Bookmark_2 // This is the annoying part: there are multiple possiblities. // 1) past0 is really located at a missing value location; // 2) past0 is inside the volume, but really close to the boundary, // causing RK4 method to fail; // 3) past0 is not at a missing location, but out of the volume. // // Note that we need to detect and deal with each of these possibilities // here instead of using the periodic capabilities of a grid class, // because the advection code needs to have knowledge when a pathline // exits from one side and comes back from another sice, and record // this event by inserting a separator. The separator will later be used // by the rendering code to break a pathline into segments. glm::vec3 vel; bool isMissing = (velocity->GetVelocity(past0.time, past0.location, vel) == MISSING_VAL); bool isInside = velocity->InsideVolumeVelocity(past0.time, past0.location); if (isInside && isMissing) { // Case 1) // We identified a particle at a bad location. // We mark it as special, and terminate the current stream. past0.SetSpecial(true); _separatorCount[streamIdx]++; break; } else if (isInside && (!isMissing)) { // Case 2) // Use Euler advection for this particle. rv = _advectEuler(velocity, past0, dt, p1); assert(rv == 0); s.emplace_back(p1); numberOfSteps++; } else { // Case 3) // We identified a particle that's out of the volume. // We treat it depending on field periodicity. // In case of no periodicity, we mark this particle special and // terminate the current stream. // In case of periodicity enabled, we apply it! if ((!_isPeriodic[0]) && (!_isPeriodic[1]) && (!_isPeriodic[2])) { past0.SetSpecial(true); _separatorCount[streamIdx]++; break; } else { auto loc = past0.location; for (int i = 0; i < 3; i++) { if (_isPeriodic[i]) loc[i] = _applyPeriodic(loc[i], _periodicBounds[i][0], _periodicBounds[i][1]); } // Notice that loc isn't guaranteed to be inside the volume right now, // since periodic ain't enabled for all directions. // As a result, we need to test again if (velocity->InsideVolumeVelocity(past0.time, loc)) { past0.location = loc; Particle separator; separator.SetSpecial(true); auto it = s.end(); --it; s.insert(it, separator); _separatorCount[streamIdx]++; } else { past0.SetSpecial(true); _separatorCount[streamIdx]++; break; } } } } // end (rv == MISSING_VAL) condition else // Advection wasn't successful for other reasons break; } // end loop for particle } // end loop for streams velocity->UnlockParams(); if (happened) return SUCCESS; else return NO_ADVECT_HAPPENED; } int Advection::AdvectTillTime(Field *velocity, double startT, double deltaT, double targetT, bool fixedStepSize, ADVECTION_METHOD method) { int ready = CheckReady(); if (ready != 0) return ready; bool happened = false; size_t streamIdx = 0; size_t maxSteps = 10000; for (auto &s : _streams) // Process one stream at a time { Particle p0 = s.back(); // Start from the last particle in this stream if (p0.time < startT) // Skip this stream if it didn't advance to startT continue; if (p0.IsSpecial()) // Also skip this tream if it was marked special. continue; size_t thisStep = 0; while (p0.time < targetT) { // Check if the particle is inside of the volume. // Wrap it along periodic dimensions if applicable. if (!velocity->InsideVolumeVelocity(p0.time, p0.location)) { bool locChanged = false; auto itr = s.end(); --itr; // pointing to the last element auto loc = itr->location; for (int i = 0; i < 3; i++) { if (_isPeriodic[i]) { loc[i] = _applyPeriodic(loc[i], _periodicBounds[i][0], _periodicBounds[i][1]); locChanged = true; } } if (!locChanged) { // no dimension is periodic, append a separator Particle separator; separator.SetSpecial(true); s.push_back(separator); _separatorCount[streamIdx]++; break; // break the while loop } // See if the new location is inside of the volume if (velocity->InsideVolumeVelocity(itr->time, loc)) { itr->location = loc; p0 = *itr; // p0 is equal to the wrapped particle Particle separator; separator.SetSpecial(true); s.insert(itr, separator); _separatorCount[streamIdx]++; } else { // Still outside, so we terminate the stream! Particle separator; separator.SetSpecial(true); s.push_back(separator); _separatorCount[streamIdx]++; break; // break the while loop } } // Finish the out-of-volume condition double dt = deltaT; if (!fixedStepSize && s.size() > 2) { double mindt = deltaT / 20.0, maxdt = deltaT * 20.0; maxdt = glm::min(maxdt, targetT - p0.time); const auto &past1 = s[s.size() - 2]; const auto &past2 = s[s.size() - 3]; if ((!past1.IsSpecial()) && (!past2.IsSpecial())) { dt = p0.time - past1.time; // step size used by last integration dt *= _calcAdjustFactor(past2, past1, p0); dt = glm::clamp(dt, mindt, maxdt); } } Particle p1; int rv = 0; switch (method) { case ADVECTION_METHOD::EULER: rv = _advectEuler(velocity, p0, dt, p1); _printNonZero(rv, __FILE__, __func__, __LINE__); break; case ADVECTION_METHOD::RK4: rv = _advectRK4(velocity, p0, dt, p1); _printNonZero(rv, __FILE__, __func__, __LINE__); break; } if (rv == SUCCESS) { // Check out Bookmark_1 if (p1.location == p0.location) { p1.SetSpecial(true); s.push_back(p1); _separatorCount[streamIdx]++; break; } else { happened = true; s.push_back(p1); p0 = p1; } } else if (rv == MISSING_VAL) { // Check out Bookmark_2 glm::vec3 vel; bool isMissing = (velocity->GetVelocity(p0.time, p0.location, vel) == MISSING_VAL); bool isInside = velocity->InsideVolumeVelocity(p0.time, p0.location); if (isInside && isMissing) { p1.SetSpecial(true); s.push_back(p1); _separatorCount[streamIdx]++; break; } else if (isInside && (!isMissing)) { rv = _advectEuler(velocity, p0, dt, p1); assert(rv == 0); s.push_back(p1); p0 = p1; } else { auto loc = p0.location; for (int i = 0; i < 3; i++) { if (_isPeriodic[i]) loc[i] = _applyPeriodic(loc[i], _periodicBounds[i][0], _periodicBounds[i][1]); } if (velocity->InsideVolumeVelocity(p0.time, loc)) { p1.SetSpecial(true); auto it = s.end(); --it; s.insert(it, p1); it = s.end(); --it; it->location = loc; _separatorCount[streamIdx]++; } else { p1.SetSpecial(true); s.push_back(p1); _separatorCount[streamIdx]++; break; } } } // finish handling missing value // Another termination criterion: when advecting at least 10,000 steps and // more than 10X more than the previous max num of steps. // if (++thisStep == maxSteps) { thisStep = maxSteps / 10; p1.SetSpecial(true); s.push_back(p1); _separatorCount[streamIdx]++; break; } } // Finish advecting one particle maxSteps = std::max(maxSteps, thisStep * 10); streamIdx++; } // Finish advecting all particles if (happened) return ADVECT_HAPPENED; else return 0; } int Advection::CalculateParticleValues(Field *scalar, bool skipNonZero) { // For steady fields, we calculate values one stream at a time if (scalar->IsSteady) { if (scalar->LockParams() != 0) return PARAMS_ERROR; _valueVarName = scalar->ScalarName; for (auto &s : _streams) { for (auto &p : s) { // Skip this particle if it's a separator if (p.IsSpecial()) continue; // Do not evaluate this particle if its value is non-zero if (skipNonZero && p.value != 0.0f) continue; float value; int rv = scalar->GetScalar(p.time, p.location, value); if (rv == 0) // The end of a stream could be outside of the volume, p.value = value; // so let's only color it when the return value is 0. } } scalar->UnlockParams(); } // For unsteady fields, we calculate values at one timestep at a time else { size_t mostSteps = 0; for (auto &s : _streams) { if (s.size() > mostSteps) mostSteps = s.size(); } _valueVarName = scalar->ScalarName; for (size_t i = 0; i < mostSteps; i++) { for (auto &s : _streams) { if (i < s.size()) { auto &p = s[i]; if (p.IsSpecial()) continue; // Do not evaluate this particle if its value is non-zero if (skipNonZero && p.value != 0.0f) continue; float val; int rv = scalar->GetScalar(p.time, p.location, val); if (rv == 0) p.value = val; } } // end of a stream } // end of all steps } return 0; } int Advection::CalculateParticleIntegratedValues(Field *scalar, const bool skipNonZero, const float distScale, const std::vector &integrateWithinVolumeMin, const std::vector &integrateWithinVolumeMax) { // For steady fields, we calculate values one stream at a time if (scalar->IsSteady) { if (scalar->LockParams() != 0) return PARAMS_ERROR; _valueVarName = scalar->ScalarName; for (auto &s : _streams) { if (s.size() && !s[0].IsSpecial()) s[0].value = 0; for (int i = 1; i < s.size(); i++) { auto &prev = s[i - 1]; auto &p = s[i]; _calculateParticleIntegratedValue(p, prev, scalar, skipNonZero, distScale, integrateWithinVolumeMin, integrateWithinVolumeMax); } } scalar->UnlockParams(); } // For unsteady fields, we calculate values at one timestep at a time else { size_t mostSteps = 0; for (auto &s : _streams) { if (s.size() > mostSteps) mostSteps = s.size(); } _valueVarName = scalar->ScalarName; for (auto &s : _streams) if (s.size() && !s[0].IsSpecial()) s[0].value = 0; for (size_t i = 1; i < mostSteps; i++) { for (auto &s : _streams) { if (i < s.size()) { auto &prev = s[i - 1]; auto &p = s[i]; _calculateParticleIntegratedValue(p, prev, scalar, skipNonZero, distScale, integrateWithinVolumeMin, integrateWithinVolumeMax); } } // end of a stream } // end of all steps } return 0; } void Advection::_calculateParticleIntegratedValue(Particle &p, const Particle &prev, const Field *scalarField, const bool skipNonZero, const float distScale, const std::vector &integrateWithinVolumeMin, const std::vector &integrateWithinVolumeMax) const { // Skip this particle if it is a separator if (p.IsSpecial()) return; if (prev.IsSpecial()) { p.value = 0; return; } // Do not evaluate this particle if its value is non-zero if (skipNonZero && p.value != 0.0f) return; if (!_isParticleInsideVolume(p, integrateWithinVolumeMin, integrateWithinVolumeMax)) { p.value = prev.value; return; } float value; int rv = scalarField->GetScalar(p.time, p.location, value); if (rv != 0) { // If non-0, then outside the volume p.value = prev.value; return; } float dist = glm::distance(prev.location, p.location); p.value = prev.value + value * dist * distScale; } void Advection::SetAllStreamValuesToFinalValue(int realNSamples) { for (auto &s : _streams) { float finalValue = 0; int sampleCount = 0; for (auto &p : s) { if (!p.IsSpecial()) { finalValue = p.value; sampleCount++; } if (sampleCount == realNSamples) break; } int setCount = 0; for (auto &p : s) { if (!p.IsSpecial()) { p.value = finalValue; setCount++; } if (setCount == sampleCount) break; } } } int Advection::CalculateParticleProperties(Field *scalar) { // Test if this scalar property is already calculated. if (std::find(_propertyVarNames.cbegin(), _propertyVarNames.cend(), scalar->ScalarName) != _propertyVarNames.cend()) return 0; // Proceed if there is no current scalar property _propertyVarNames.emplace_back(scalar->ScalarName); // Test if this scalar field is the same as the one used to calculate particle values, // if so, copy over the values. if (scalar->ScalarName == _valueVarName) { for (auto &s : _streams) { for (auto &p : s) { p.AttachProperty(p.value); } } return 0; } // In case this property field is a brand new variable, we do the actual sampling work. if (scalar->IsSteady) { if (scalar->LockParams() != 0) return PARAMS_ERROR; for (auto &s : _streams) { for (auto &p : s) { if (p.IsSpecial()) continue; // At the end of a flow line, a particle might be outside of the volume. // We attach something in that case as well. float val = std::nanf("1"); scalar->GetScalar(p.time, p.location, val); p.AttachProperty(val); } } } else { size_t mostSteps = 0; for (const auto &s : _streams) if (s.size() > mostSteps) mostSteps = s.size(); for (size_t i = 0; i < mostSteps; i++) { for (auto &s : _streams) { if (i < s.size()) { auto &p = s[i]; if (p.IsSpecial()) continue; float value = std::nanf("1"); scalar->GetScalar(p.time, p.location, value); p.AttachProperty(value); } } } } return 0; } void Advection::CalculateParticleHistogram(std::vector &outBounds, std::vector &bins) { std::vector samples; for (const auto &s : _streams) for (const auto &p : s) if (!p.IsSpecial()) samples.push_back(p.value); auto bounds = std::minmax_element(samples.begin(), samples.end()); float minValue = *bounds.first; float maxValue = *bounds.second; float range = maxValue - minValue; int nBins = bins.size(); assert(nBins != 0); std::fill(bins.begin(), bins.end(), 0); for (const auto &s : samples) { bins[std::min(nBins - 1, std::max(0, (int)((nBins - 1) * (s - minValue) / range)))]++; } outBounds.resize(2); outBounds[0] = minValue; outBounds[1] = maxValue; } int Advection::_advectEuler(Field *velocity, const Particle &p0, double dt, Particle &p1) const { glm::vec3 v0; int rv = velocity->GetVelocity(p0.time, p0.location, v0); if (rv != 0) return rv; float dt32 = float(dt); // glm is strict about data types (which is a good thing). p1.location = p0.location + dt32 * v0; p1.time = p0.time + dt; return 0; } int Advection::_advectRK4(Field *velocity, const Particle &p0, double dt, Particle &p1) const { glm::vec3 k1, k2, k3, k4; const double dt_half = dt * 0.5; const float dt32 = float(dt); // glm is strict about data types (which is a good thing). const float dt_half32 = float(dt_half); // glm is strict about data types (which is a good thing). int rv = 0; rv = velocity->GetVelocity(p0.time, p0.location, k1); _printNonZero(rv, __FILE__, __func__, __LINE__); if (rv != 0) return rv; rv = velocity->GetVelocity(p0.time + dt_half, p0.location + dt_half32 * k1, k2); _printNonZero(rv, __FILE__, __func__, __LINE__); if (rv != 0) return rv; rv = velocity->GetVelocity(p0.time + dt_half, p0.location + dt_half32 * k2, k3); _printNonZero(rv, __FILE__, __func__, __LINE__); if (rv != 0) return rv; rv = velocity->GetVelocity(p0.time + dt, p0.location + dt32 * k3, k4); _printNonZero(rv, __FILE__, __func__, __LINE__); if (rv != 0) return rv; p1.location = p0.location + dt32 / 6.0f * (k1 + 2.0f * (k2 + k3) + k4); p1.time = p0.time + dt; return 0; } float Advection::_calcAdjustFactor(const Particle &p2, const Particle &p1, const Particle &p0) const { glm::vec3 p2p1 = p1.location - p2.location; glm::vec3 p1p0 = p0.location - p1.location; float denominator = glm::length(p2p1) * glm::length(p1p0); float cosine; if (denominator < 1e-7) return 1.0f; else cosine = glm::dot(p2p1, p1p0) / denominator; if (cosine > _lowerAngleCos) // Less than "_lowerAngle" degrees return 1.25f; else if (cosine < _upperAngleCos) // More than "_upperAngle" degrees return 0.5f; else return 1.0f; } size_t Advection::GetNumberOfStreams() const { return _streams.size(); } const std::vector &Advection::GetStreamAt(size_t i) const { // Since this function is almost always used together with GetNumberOfStreams(), // I'm offloading the range check to std::vector. return _streams.at(i); } size_t Advection::GetMaxNumOfPart() const { size_t max = 0; size_t idx = 0; for (const auto &s : _streams) { size_t num = s.size() - _separatorCount[idx]; if (num > max) max = num; idx++; } return max; } void Advection::ClearParticleProperties() { _propertyVarNames.clear(); for (auto &stream : _streams) for (auto &part : stream) part.ClearProperty(); } void Advection::RemoveParticleProperty(const std::string &varToRemove) { auto itr = std::find(_propertyVarNames.begin(), _propertyVarNames.end(), varToRemove); // Do nothing if `varToRemove` does not exist if (itr == _propertyVarNames.end()) return; else { auto rmI = std::distance(_propertyVarNames.begin(), itr); _propertyVarNames.erase(itr); for (auto &stream : _streams) for (auto &part : stream) part.RemoveProperty(rmI); } } void Advection::ResetParticleValues() { for (auto &stream : _streams) { std::for_each(stream.begin(), stream.end(), [](Particle &p) { if (!p.IsSpecial()) p.value = 0.0f; }); } } void Advection::SetXPeriodicity(bool isPeri, float min, float max) { _isPeriodic[0] = isPeri; if (isPeri) _periodicBounds[0] = glm::vec2(min, max); else _periodicBounds[0] = glm::vec2(0.0f); } void Advection::SetYPeriodicity(bool isPeri, float min, float max) { _isPeriodic[1] = isPeri; if (isPeri) _periodicBounds[1] = glm::vec2(min, max); else _periodicBounds[1] = glm::vec2(0.0f); } void Advection::SetZPeriodicity(bool isPeri, float min, float max) { _isPeriodic[2] = isPeri; if (isPeri) _periodicBounds[2] = glm::vec2(min, max); else _periodicBounds[2] = glm::vec2(0.0f); } float Advection::_applyPeriodic(float val, float min, float max) const { if (min >= max) // ill params, return val return val; else if (val >= min && val <= max) // nothing needs to change return val; // Let's do some serious work float span = max - min; float pval = val; if (val < min) { while (pval < min) pval += span; return pval; } else // val > max { while (pval > max) pval -= span; return pval; } } void Advection::_printNonZero(int rtn, const char *file, const char *func, int line) const { #ifdef VPRINT if (rtn != 0) { // only print non-zero values printf("Rtn == %d: %s:(%s):%d\n", rtn, file, func, line); } #endif } auto Advection::GetValueVarName() const -> std::string { return _valueVarName; } auto Advection::GetPropertyVarNames() const -> std::vector { return _propertyVarNames; } bool Advection::_isParticleInsideVolume(const Particle &p, const std::vector &min, const std::vector &max) { if (p.location[0] < min[0] || p.location[1] < min[1] || p.location[0] > max[0] || p.location[1] > max[1]) { return false; } if (min.size() > 2 && (p.location[2] < min[2] || p.location[2] > max[2])) { return false; } return true; } ================================================ FILE: lib/flow/AdvectionIO.cpp ================================================ #include "vapor/AdvectionIO.h" #include #include #include #include #include // std::distance #include #include "vapor/Proj4API.h" #include "vapor/UDUnitsClass.h" auto flow::OutputFlowlinesNumSteps(const Advection *adv, const char *filename, size_t numSteps, const std::string &proj4string, bool append) -> int { // First we need the infrastructure for time conversion VAPoR::UDUnits udunits; if (udunits.Initialize() < 0) return PARAMS_ERROR; // Second we need the infrastructure for coordinate conversion bool needGeoConversion = false; VAPoR::Proj4API proj4API; if (!proj4string.empty()) { if (proj4API.Initialize(proj4string, "") < 0) return PARAMS_ERROR; needGeoConversion = true; } // Requesting the file handle std::FILE *f = nullptr; if (append) f = std::fopen(filename, "a"); else f = std::fopen(filename, "w"); if (f == nullptr) return FILE_ERROR; auto propertyNames = adv->GetPropertyVarNames(); // Write the header if (!append) { std::fprintf(f, "%s", "# ID, X-position, Y-position, Z-position"); for (auto &n : propertyNames) std::fprintf(f, ", %s", n.c_str()); std::fprintf(f, "\n"); } // Let's declare variables that will be used repeatedly for geo coordinate conversion float cX = 0.f, cY = 0.f; // converted X, Y coordinates // Write the trajectories for (size_t s_idx = 0; s_idx < adv->GetNumberOfStreams(); s_idx++) { const auto &stream = adv->GetStreamAt(s_idx); size_t step = 0; for (const auto &p : stream) { if (!p.IsSpecial()) { // Let's also convert geo coordinates if needed. cX = p.location.x; cY = p.location.y; if (needGeoConversion) proj4API.Transform(&cX, &cY, 1); std::fprintf(f, "%lu, %f, %f, %f", s_idx, cX, cY, p.location.z); auto props = p.GetPropertyList(); // A quick sanity check assert(std::distance(props.cbegin(), props.cend()) == propertyNames.size()); for (const auto &val : props) std::fprintf(f, ", %f", val); std::fprintf(f, "\n"); // end of one line step++; } if (step > numSteps) // when numSteps + 1 particles are printed. break; } } std::fclose(f); return 0; } auto flow::OutputFlowlinesMaxTime(const Advection *adv, const char *filename, double maxTime, const std::string &proj4string, bool append) -> int { // First we need the infrastructure for time conversion VAPoR::UDUnits udunits; if (udunits.Initialize() < 0) return PARAMS_ERROR; // Second we need the infrastructure for coordinate conversion bool needGeoConversion = false; VAPoR::Proj4API proj4API; if (!proj4string.empty()) { if (proj4API.Initialize(proj4string, "") < 0) return PARAMS_ERROR; needGeoConversion = true; } // Requesting the file handle std::FILE *f = nullptr; if (append) f = std::fopen(filename, "a"); else f = std::fopen(filename, "w"); if (f == nullptr) return FILE_ERROR; auto propertyNames = adv->GetPropertyVarNames(); // Write the header if (!append) { std::fprintf(f, "%s", "# ID, X-position, Y-position, Z-position, Formatted-time, Raw-time"); for (auto &n : propertyNames) std::fprintf(f, ", %s", n.c_str()); std::fprintf(f, "\n"); } // Let's declare variables that will be used repeatedly for time and geo coordinate conversion int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0; float cX = 0.f, cY = 0.f; // converted X, Y coordinates // Write the trajectories for (size_t s_idx = 0; s_idx < adv->GetNumberOfStreams(); s_idx++) { const auto &stream = adv->GetStreamAt(s_idx); for (const auto &p : stream) { if (p.time > maxTime) break; if (!p.IsSpecial()) { // First, convert time. udunits.DecodeTime(p.time, &year, &month, &day, &hour, &minute, &second); // Also convert geo coordinates if needed. cX = p.location.x; cY = p.location.y; if (needGeoConversion) proj4API.Transform(&cX, &cY, 1); std::fprintf(f, "%lu, %f, %f, %f, %.4d-%.2d-%.2d_%.2d:%.2d:%.2d, %f", s_idx, cX, cY, p.location.z, year, month, day, hour, minute, second, p.time); auto props = p.GetPropertyList(); // A quick sanity check assert(std::distance(props.cbegin(), props.cend()) == propertyNames.size()); for (const auto &val : props) std::fprintf(f, ", %f", val); std::fprintf(f, "\n"); // end of one line } } } std::fclose(f); return 0; } auto flow::InputSeedsCSV(const std::string &filename) -> std::vector { std::ifstream ifs(filename); if (!ifs.is_open()) return {}; std::vector newSeeds; for (std::string line; std::getline(ifs, line);) { // remove spaces/tabs in this line line.erase(std::remove_if(line.begin(), line.end(), [](unsigned char c) { return std::isspace(c); }), line.end()); // skip this line if it's empty if (line.empty()) continue; // If leading by a #, then skip it. if (line.front() == '#') continue; // Now try to parse numbers separated by comma std::stringstream ss(line); std::vector valFloat; valFloat.reserve(3); for (std::string tmp; std::getline(ss, tmp, ',');) { try { valFloat.push_back(std::stof(tmp)); } catch (const std::invalid_argument &e) { ifs.close(); return {}; } if (valFloat.size() >= 3) // we parse at most 3 values, and discard the rest of this line. break; } if (valFloat.size() < 3) { // less than 3 values provided in this line ifs.close(); return {}; // Not accepting any seed when encountering a bad line } newSeeds.emplace_back(valFloat[0], valFloat[1], valFloat[2], 0.0); } ifs.close(); // Let's also remove duplicate seeds. auto less = [](const flow::Particle &a, const flow::Particle &b) { if (a.location.x != b.location.x) return (a.location.x < b.location.x); else if (a.location.y != b.location.y) return (a.location.y < b.location.y); else return (a.location.z < b.location.z); }; std::sort(newSeeds.begin(), newSeeds.end(), less); auto equal = [](const flow::Particle &a, const flow::Particle &b) { auto eq = glm::equal(a.location, b.location); return glm::all(eq); }; auto itr = std::unique(newSeeds.begin(), newSeeds.end(), equal); newSeeds.erase(itr, newSeeds.end()); return newSeeds; } ================================================ FILE: lib/flow/CMakeLists.txt ================================================ set (SRC Particle.cpp Advection.cpp Field.cpp VaporField.cpp AdvectionIO.cpp ) set (HEADERS ${PROJECT_SOURCE_DIR}/include/vapor/Advection.h ${PROJECT_SOURCE_DIR}/include/vapor/Particle.h ${PROJECT_SOURCE_DIR}/include/vapor/Field.h ${PROJECT_SOURCE_DIR}/include/vapor/VaporField.h ${PROJECT_SOURCE_DIR}/include/vapor/AdvectionIO.h ${PROJECT_SOURCE_DIR}/include/vapor/ptr_cache.hpp ) add_library (flow SHARED ${SRC} ${HEADERS}) target_link_libraries ( flow PUBLIC vdc params ) add_definitions (-DFLOW_EXPORTS) OpenMPInstall ( TARGETS flow DESTINATION ${INSTALL_LIB_DIR} COMPONENT Libraries ) install ( FILES ${HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR} COMPONENT Libraries ) ================================================ FILE: lib/flow/Field.cpp ================================================ #include #include "vapor/Field.h" using namespace flow; int Field::GetNumOfEmptyVelocityNames() const { return std::count_if(VelocityNames.begin(), VelocityNames.end(), [](const std::string &e) { return e.empty(); }); } ================================================ FILE: lib/flow/Particle.cpp ================================================ #include "vapor/Particle.h" using namespace flow; Particle::Particle(const glm::vec3 &loc, double t, float val) { location = loc; time = t; value = val; } Particle::Particle(float x, float y, float z, double t, float val) { location.x = x; location.y = y; location.z = z; time = t; value = val; } void Particle::AttachProperty(float v) { auto before_itr = _properties.cbefore_begin(); for (auto itr = _properties.cbegin(); itr != _properties.cend(); ++itr) ++before_itr; _properties.insert_after(before_itr, v); } auto Particle::GetPropertyList() const -> const std::forward_list & { return _properties; } void Particle::ClearProperty() { _properties.clear(); } void Particle::RemoveProperty(size_t target_i) { size_t current_i = 0; auto before_it = _properties.cbefore_begin(); for (auto it = _properties.cbegin(); it != _properties.cend(); ++it) { if (current_i == target_i) { _properties.erase_after(before_it); break; } ++current_i; ++before_it; } } void Particle::SetSpecial(bool isSpecial) { // Give both "time" and "value" a nan to indicate the "special state." // Accidental assignment of nan to one of the two variables would not // render a "special state." if (isSpecial) { time = std::nanf("1"); value = std::nanf("1"); } else { time = 0.0f; value = 0.0f; } location = {0.0f, 0.0f, 0.0f}; } bool Particle::IsSpecial() const { return (std::isnan(time) && std::isnan(value)); } ================================================ FILE: lib/flow/VaporField.cpp ================================================ #include "vapor/VaporField.h" #include "vapor/ConstantGrid.h" using namespace flow; // // Class GridKey // void GridKey::Reset(uint32_t ts, int32_t ref, int32_t comp, std::string var, VAPoR::CoordType min, VAPoR::CoordType max) { _timestep = ts; _refLev = ref; _compLev = comp; _varName = std::move(var); _ext_min = min; _ext_max = max; } bool GridKey::operator==(const GridKey &other) const { // String comparison seems to occur most frequently, so put it at the first. if (this->_varName != other._varName) return false; if (this->_timestep != other._timestep) return false; if (this->_refLev != other._refLev) return false; if (this->_compLev != other._compLev) return false; if (this->_ext_min != other._ext_min) return false; if (this->_ext_max != other._ext_max) return false; return true; } bool GridKey::emptyVar() const { return _varName.empty(); } // // Class GridWrapper // GridWrapper::GridWrapper(const VAPoR::Grid *gp, VAPoR::DataMgr *mp) : _gridPtr(gp), _mgr(mp) {} GridWrapper::~GridWrapper() { if (_gridPtr && _mgr) { _mgr->UnlockGrid(_gridPtr); delete _gridPtr; } } const VAPoR::Grid *GridWrapper::grid() const { return _gridPtr; } // // Class VaporField // auto VaporField::LockParams() -> int { if (!_isReady()) return 1; // Retrieve param values and put them in the local cache. _c_currentTS = _params->GetCurrentTimestep(); _c_refLev = _params->GetRefinementLevel(); _c_compLev = _params->GetCompressionLevel(); _c_vel_mult = _params->GetVelocityMultiplier(); _params->GetBox()->GetExtents(_c_ext_min, _c_ext_max); _params_locked = true; return 0; } auto VaporField::UnlockParams() -> int { _c_currentTS = std::numeric_limits::max(); // almost impossible value _c_refLev = -2; // Impossible value _c_compLev = -2; // Impossible value _c_vel_mult = 0.0; _c_ext_min = {0.0, 0.0, 0.0}; _c_ext_max = {0.0, 0.0, 0.0}; _params_locked = false; return 0; } bool VaporField::InsideVolumeVelocity(double time, glm::vec3 pos) const { VAPoR::CoordType coords{pos.x, pos.y, pos.z}; const VAPoR::Grid * grid = nullptr; VAssert(_isReady()); // In case of steady field, we only check a specific time step if (IsSteady) { for (int i = 0; i < 3; i++) { auto currentTS = _c_currentTS; if (!_params_locked) currentTS = _params->GetCurrentTimestep(); else assert(currentTS == _params->GetCurrentTimestep()); grid = _getAGrid(currentTS, VelocityNames[i]); if (grid == nullptr) return false; if (!grid->InsideGrid(coords)) return false; } } else { // In case of unsteady, we check two time steps // First check if the query time is within range if (time < _timestamps.front() || time > _timestamps.back()) return false; // Then locate the 2 time steps size_t floor = 0; int rv = LocateTimestamp(time, floor); if (rv != 0) return false; // Then test if pos is inside of time step "floor" for (auto &v : VelocityNames) { grid = _getAGrid(floor, v); if (grid == nullptr) return false; if (!grid->InsideGrid(coords)) return false; } // If time is larger than _timestamps[floor], we also need to test _timestamps[floor+1] if (time > _timestamps[floor]) { for (auto &v : VelocityNames) { grid = _getAGrid(floor + 1, v); if (grid == nullptr) return false; if (!grid->InsideGrid(coords)) return false; } } } return true; } bool VaporField::InsideVolumeScalar(double time, glm::vec3 pos) const { // When this variable doesn't exist, it doesn't make sense to say if // a position is inside of the volume, so simply return true. if (ScalarName.empty()) return true; VAPoR::CoordType coords{pos.x, pos.y, pos.z}; const VAPoR::Grid * grid = nullptr; VAssert(_isReady()); // In case of steady field, we only check a specific time step if (IsSteady) { auto currentTS = _c_currentTS; if (!_params_locked) currentTS = _params->GetCurrentTimestep(); else assert(currentTS == _params->GetCurrentTimestep()); grid = _getAGrid(currentTS, ScalarName); if (grid == nullptr) return false; return grid->InsideGrid(coords); } else { // In case of unsteady field, we check two time steps // First check if the query time is within range if (time < _timestamps.front() || time > _timestamps.back()) return false; // Then locate the 2 time steps size_t floor = 0; int rv = LocateTimestamp(time, floor); if (rv != 0) return false; // Then test if pos is inside of time step "floor" grid = _getAGrid(floor, ScalarName); if (grid == nullptr) return false; if (!grid->InsideGrid(coords)) return false; // If time is larger than _timestamps[floor], we also need to test _timestamps[floor+1] if (time > _timestamps[floor]) { grid = _getAGrid(floor + 1, ScalarName); if (grid == nullptr) return false; if (!grid->InsideGrid(coords)) return false; } return true; } } int VaporField::GetVelocityIntersection(size_t ts, glm::vec3 &minxyz, glm::vec3 &maxxyz) const { const VAPoR::Grid * grid = nullptr; std::array min[3], max[3]; // For each velocity variables for (int i = 0; i < 3; i++) { grid = _getAGrid(ts, VelocityNames[i]); if (grid == nullptr) { Wasp::MyBase::SetErrMsg("Vector field not available at requested time step!"); return GRID_ERROR; } else grid->GetUserExtents(min[i], max[i]); } minxyz = glm::vec3(min[0][0], min[0][1], min[0][2]); maxxyz = glm::vec3(max[0][0], max[0][1], max[0][2]); for (int i = 1; i < 3; i++) { glm::vec3 xyz(min[i][0], min[i][1], min[i][2]); minxyz = glm::max(minxyz, xyz); xyz = glm::vec3(max[i][0], max[i][1], max[i][2]); maxxyz = glm::min(maxxyz, xyz); } return 0; } int VaporField::GetVelocity(double time, glm::vec3 pos, glm::vec3 &velocity) const { VAPoR::CoordType coords{pos.x, pos.y, pos.z}; const VAPoR::Grid * grid = nullptr; // Retrieve the missing value and velocity multiplier glm::vec3 missingV(0.0f); // stores missing values for 3 velocity variables velocity = glm::vec3(0.0f); if (IsSteady) { for (int i = 0; i < 3; i++) { auto currentTS = _c_currentTS; if (!_params_locked) currentTS = _params->GetCurrentTimestep(); grid = _getAGrid(currentTS, VelocityNames[i]); if (grid == nullptr) return GRID_ERROR; velocity[i] = grid->GetValue(coords); missingV[i] = grid->GetMissingValue(); } auto hasMissing = glm::equal(velocity, missingV); // If missing values are represented using NaN, you cannot compare equality with them! for (int i = 0; i < 3; i++) { if (std::isnan(missingV[i]) && std::isnan(velocity[i])) hasMissing[i] = true; } if (glm::any(hasMissing)) { return MISSING_VAL; } else { float mult = _params_locked ? _c_vel_mult : _params->GetVelocityMultiplier(); velocity *= mult; return SUCCESS; } } // Finish steady case else { // First check if the query time is within range if (time < _timestamps.front() || time > _timestamps.back()) return TIME_ERROR; // Then we locate the floor time step size_t floorTS = 0; int rv = LocateTimestamp(time, floorTS); VAssert(rv == 0); // Find the velocity values at floor time step glm::vec3 floorVelocity(0.f, 0.f, 0.f); glm::vec3 ceilingVelocity(0.f, 0.f, 0.f); for (int i = 0; i < 3; i++) { grid = _getAGrid(floorTS, VelocityNames[i]); if (grid == nullptr) return GRID_ERROR; floorVelocity[i] = grid->GetValue(coords); missingV[i] = grid->GetMissingValue(); } auto hasMissing = glm::equal(floorVelocity, missingV); if (glm::any(hasMissing)) { return MISSING_VAL; } float mult = _params->GetVelocityMultiplier(); if (time == _timestamps[floorTS]) { velocity = floorVelocity * mult; return 0; } else { // Find the velocity values at the ceiling time step, then interpolate. // We need to make sure there aren't duplicate time stamps VAssert(_timestamps[floorTS + 1] > _timestamps[floorTS]); for (int i = 0; i < 3; i++) { grid = _getAGrid(floorTS + 1, VelocityNames[i]); if (grid == nullptr) return GRID_ERROR; ceilingVelocity[i] = grid->GetValue(coords); missingV[i] = grid->GetMissingValue(); } hasMissing = glm::equal(ceilingVelocity, missingV); if (glm::any(hasMissing)) { return MISSING_VAL; } float weight = (time - _timestamps[floorTS]) / (_timestamps[floorTS + 1] - _timestamps[floorTS]); velocity = glm::mix(floorVelocity, ceilingVelocity, weight) * mult; return 0; } } // end of unsteady condition } int VaporField::GetScalar(double time, glm::vec3 pos, float &scalar) const { // When this variable doesn't exist, it doesn't make sense to get a scalar value // from it, so just return that fact. if (ScalarName.empty()) return NO_FIELD_YET; VAPoR::CoordType coords{pos.x, pos.y, pos.z}; const VAPoR::Grid * grid = nullptr; if (IsSteady) { auto currentTS = _c_currentTS; if (!_params_locked) currentTS = _params->GetCurrentTimestep(); grid = _getAGrid(currentTS, ScalarName); if (grid == nullptr) return GRID_ERROR; scalar = grid->GetValue(coords); if (scalar == grid->GetMissingValue()) { return MISSING_VAL; } else return 0; } else { // First check if the query time is within range if (time < _timestamps.front() || time > _timestamps.back()) return TIME_ERROR; // Then we locate the floor time step size_t floorTS = 0; int rv = LocateTimestamp(time, floorTS); VAssert(rv == 0); grid = _getAGrid(floorTS, ScalarName); if (grid == nullptr) return GRID_ERROR; float floorScalar = grid->GetValue(coords); if (floorScalar == grid->GetMissingValue()) { return MISSING_VAL; } if (time == _timestamps[floorTS]) { scalar = floorScalar; return 0; } else { grid = _getAGrid(floorTS + 1, ScalarName); if (grid == nullptr) return GRID_ERROR; float ceilingScalar = grid->GetValue(coords); if (ceilingScalar == grid->GetMissingValue()) { return MISSING_VAL; } else { float weight = (time - _timestamps[floorTS]) / (_timestamps[floorTS + 1] - _timestamps[floorTS]); scalar = glm::mix(floorScalar, ceilingScalar, weight); return 0; } } } // end of unsteady condition } bool VaporField::_isReady() const { if (!_datamgr) return false; if (!_params) return false; return true; } void VaporField::AssignDataManager(VAPoR::DataMgr *dmgr) { _datamgr = dmgr; // Make a copy of the timestamps from the new data manager _timestamps = dmgr->GetTimeCoordinates(); } void VaporField::UpdateParams(const VAPoR::FlowParams *p) { _params = p; IsSteady = p->GetIsSteady(); } int VaporField::LocateTimestamp(double time, size_t &floor) const { if (_timestamps.empty()) return TIME_ERROR; if (_timestamps.size() == 1) { if (_timestamps[0] != time) return TIME_ERROR; else { floor = 0; return 0; } } if (time < _timestamps.front() || time > _timestamps.back()) return TIME_ERROR; else { auto it = std::upper_bound(_timestamps.cbegin(), _timestamps.cend(), time); floor = --it - _timestamps.cbegin(); return 0; } } uint32_t VaporField::GetNumberOfTimesteps() const { return _timestamps.size(); } int VaporField::CalcDeltaTFromCurrentTimeStep(double &delT) const { VAssert(_isReady()); // This function is called only one-time before advection starts, // so don't worry about parameter locking here. const auto currentTS = _params->GetCurrentTimestep(); const auto timestamp = _timestamps.at(currentTS); // Let's find the intersection of 3 velocity components. glm::vec3 minxyz(0.0f), maxxyz(0.0f); int rv = this->GetVelocityIntersection(currentTS, minxyz, maxxyz); if (rv != 0) return rv; // Let's make sure the max is greater than or equal to min const auto invalid = glm::lessThan(maxxyz, minxyz); if (glm::any(invalid)) { Wasp::MyBase::SetErrMsg("One of the selected volume dimension is zero!"); return GRID_ERROR; } // Let's sample some locations along each dimension. const long N = 10; // Num of samples along each axis const long totalSamples = N * N * N; const glm::vec3 numOfSteps(float(N + 1)); const glm::vec3 stepSizes = (maxxyz - minxyz) / numOfSteps; glm::vec3 samples[totalSamples]; long counter = 0; for (long z = 1; z <= N; z++) for (long y = 1; y <= N; y++) for (long x = 1; x <= N; x++) { samples[counter].x = minxyz.x + stepSizes.x * float(x); samples[counter].y = minxyz.y + stepSizes.y * float(y); samples[counter].z = minxyz.z + stepSizes.z * float(z); counter++; } float maxmag = 0.0f; glm::vec3 vel; for (long i = 0; i < totalSamples; i++) { int rv = this->GetVelocity(timestamp, samples[i], vel); // Among possible return values, 0 is good, and MISSING_VAL isn't too bad, // we just need to ignore those values. if (rv == flow::MISSING_VAL) continue; else if (rv != 0) return rv; else { auto mag = glm::length(vel); maxmag = std::max(maxmag, mag); } } // If all sampled locations are missing values or zero values, // we give deltaT an arbitrary value and return a special value. if (maxmag == 0.0 || std::isinf(maxmag)) { delT = glm::distance(minxyz, maxxyz) / 1000.0; return flow::FIELD_ALL_ZERO; } // Let's dictate that using the maximum velocity FROM OUR SAMPLES // a particle needs 1000 steps (in case of unstructured grids) or // twice the domain dimension (in case of structured grids) // to travel the entire space. // Also, no matter what fidelity level we are at with the VDC data set, // we always use the domain dimensions of the full resolution. double desiredNum = 1000.0; // pre-defined value for unstructured grids const auto *grid = _getAGrid(currentTS, VelocityNames[0]); const auto *structuredGrid = dynamic_cast(grid); if (structuredGrid) { auto dims = std::vector(); // -1 indicates that querying the native resolution. _datamgr->GetDimLensAtLevel(VelocityNames[0], -1, dims, currentTS); // `dims` could have 2 or 3 elements, depending on the dimension of the variable. assert(dims.size() == 2 || dims.size() == 3); double numCellsDiagnal = 0.0; if (dims.size() == 3) numCellsDiagnal = std::sqrt(double(dims[0] * dims[0] + dims[1] * dims[1] + dims[2] * dims[2])); else numCellsDiagnal = std::sqrt(double(dims[0] * dims[0] + dims[1] * dims[1])); desiredNum = 2.0 * numCellsDiagnal; } const double actualNum = double(glm::distance(minxyz, maxxyz)) / double(maxmag); delT = actualNum / desiredNum; // Another logic in determing the size of deltaT: // if deltaT will send a particle out of the domain in just one step in any direction, // then we halve deltaT until the particle can go one step inside of the volume. float smallestD = std::numeric_limits::max(); if (!VelocityNames[0].empty()) smallestD = std::min(smallestD, std::abs(minxyz.x - maxxyz.x)); if (!VelocityNames[1].empty()) smallestD = std::min(smallestD, std::abs(minxyz.y - maxxyz.y)); if (!VelocityNames[2].empty()) smallestD = std::min(smallestD, std::abs(minxyz.z - maxxyz.z)); while (maxmag * delT > double(smallestD)) { delT /= 2.0; } // Finally, apply a multiplier to the estimated deltaT. See Github issue 3318: // https://github.com/NCAR/VAPOR/issues/3318 delT *= _params->GetFirstStepSizeMultiplier(); return 0; } const VAPoR::Grid *VaporField::_getAGrid(uint32_t timestep, const std::string &varName) const { GridKey key; if (_params_locked) { // Because in unsteady case, both currentTS and currentTS + 1 will be queried, // so we do a sanity check here. The assertion will be gone in release mode. assert(timestep == _c_currentTS); key.Reset(_c_currentTS, _c_refLev, _c_compLev, varName, _c_ext_min, _c_ext_max); } else { VAPoR::CoordType extMin, extMax; _params->GetBox()->GetExtents(extMin, extMax); int refLevel = _params->GetRefinementLevel(); int compLevel = _params->GetCompressionLevel(); key.Reset(timestep, refLevel, compLevel, varName, extMin, extMax); } // First check if we have the requested grid in our cache. // If it exists, return the grid directly. const auto* wrapper = _recentGrids.query(key); if (wrapper != nullptr) { return wrapper->grid(); } // There's no such grid in our cache! // Let's create a new grid by doing one of the two things, and then put it in the cache. // 1) create it by ourselves if a ConstantGrid is required, or // 2) ask for it from the data manager, // // Note that we use a lock here, so no two threads querying _datamgr simultaneously. const std::lock_guard lock_gd(_grid_operation_mutex); VAPoR::Grid *grid = nullptr; if (key.emptyVar()) { // In case of an empty variable name, we generate a constantGrid with zeros. grid = new VAPoR::ConstantGrid(0.0f, 3); } else { if (_params_locked) { grid = _datamgr->GetVariable(_c_currentTS, varName, _c_refLev, _c_compLev, _c_ext_min, _c_ext_max, true); } else { VAPoR::CoordType extMin, extMax; _params->GetBox()->GetExtents(extMin, extMax); int refLevel = _params->GetRefinementLevel(); int compLevel = _params->GetCompressionLevel(); grid = _datamgr->GetVariable(timestep, varName, refLevel, compLevel, extMin, extMax, true); } } if (grid == nullptr) { Wasp::MyBase::SetErrMsg("Not able to get a grid!"); return nullptr; } // Now we have this grid, but also put it in a GridWrapper so // 1) it will be properly deleted, and // 2) it is stored in our cache, where its ownership is kept. auto dim = _datamgr->GetVarTopologyDim(varName); if (dim == 1) { Wasp::MyBase::SetErrMsg("Variable Dimension Wrong!"); return nullptr; } _recentGrids.insert(key, new GridWrapper(grid, _datamgr)); return grid; } void VaporField::ReleaseLockedGrids() { // Release locked grids by giving the cache a bunch of nullptrs with unique invalid keys. GridKey key; for (int i = 0; i < _recentGrids.size(); i++) { key.Reset(std::numeric_limits::max(), -(i + 2), -(i + 2), "", {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}); _recentGrids.insert(key, nullptr); } } ================================================ FILE: lib/osgl/CMakeCopy.cmake ================================================ cmake_policy(SET CMP0057 NEW) function(COPY_HELPER FILE DESTINATION DEP_LIST) get_filename_component(BASENAME "${FILE}" NAME) if ("${BASENAME}" IN_LIST COPY_EXCLUDE) return() endif() if (IS_DIRECTORY "${FILE}") file(GLOB SUBFILES "${FILE}/*") foreach (SUBFILE ${SUBFILES}) COPY_HELPER("${SUBFILE}" "${DESTINATION}/${BASENAME}" "${DEP_LIST}") endforeach() else() set(OUTFILE "${DESTINATION}/${BASENAME}") add_custom_command( OUTPUT "${OUTFILE}" COMMAND ${CMAKE_COMMAND} -E copy "${FILE}" "${OUTFILE}" MAIN_DEPENDENCY "${FILE}" ) list(APPEND DEP_LIST "${OUTFILE}") # of course this does not work for custom targets # add_dependencies(target ${OUTFILE}) endif() set(DEP_LIST "${DEP_LIST}" PARENT_SCOPE) endfunction() set(COPY_HELPER_TARGET_COUNTER 0) function(COPY FILE DESTINATION) include(CMakeParseArguments) cmake_parse_arguments(PARSE_ARGV 2 "COPY" "" "" "EXCLUDE" ) get_filename_component(FILE "${FILE}" REALPATH) list(APPEND DEP_LIST "") COPY_HELPER("${FILE}" "${DESTINATION}" "${DEP_LIST}") math(EXPR COPY_HELPER_TARGET_COUNTER "${COPY_HELPER_TARGET_COUNTER}+1") set(COPY_HELPER_TARGET_COUNTER ${COPY_HELPER_TARGET_COUNTER} PARENT_SCOPE) add_custom_target( copy_helper_${COPY_HELPER_TARGET_COUNTER} ALL DEPENDS ${DEP_LIST} ) endfunction() ================================================ FILE: lib/osgl/CMakeLists.txt ================================================ set(LIB osgl) include(CMakeCopy.cmake) set(BUILD_MESA_DEFAULT OFF) if (BUILD_PYTHON AND (UNIX AND NOT APPLE)) set(BUILD_MESA_DEFAULT ON) endif() option (BUILD_MESA "Build with OSMesa" ${BUILD_MESA_DEFAULT}) option (SOFTWARE_ONLY "Disable EGL" OFF) if (NOT SOFTWARE_ONLY) if (UNIX AND NOT APPLE) set(BUILD_EGL ON) endif() endif() if (NOT PROJECT_NAME) cmake_minimum_required (VERSION 3.10) project (${LIB}) set (CMAKE_CXX_STANDARD 11) # find_package (OpenGL REQUIRED) # include_directories (${OPENGL_INCLUDE_DIRS}) set(CMAKE_INSTALL_BINDIR bin) set(CMAKE_INSTALL_LIBDIR lib) set(CMAKE_INSTALL_INCLUDEDIR include/vapor) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build." FORCE) endif() else () set(CMAKE_INSTALL_BINDIR ${INSTALL_BIN_DIR}) set(CMAKE_INSTALL_LIBDIR ${INSTALL_LIB_DIR}) set(CMAKE_INSTALL_INCLUDEDIR ${INSTALL_INCLUDE_DIR}) endif () file (GLOB HDRS ./include/vapor/*.h) file (GLOB SRCS ./*.cpp) if (APPLE) file (GLOB OBJC_SRCS ./*.mm) list (APPEND SRCS ${OBJC_SRCS}) endif () list(FILTER SRCS EXCLUDE REGEX "test_[^/]*\\.cpp$") list(FILTER SRCS EXCLUDE REGEX "ext_[^/]*\\.cpp$") list(APPEND SRCS glad/src/egl.c glad/src/gl.c) list(APPEND HDRS glad/include/glad/egl.h glad/include/glad/gl.h) # file(COPY glad/include DESTINATION ${CMAKE_BINARY_DIR}) add_library (${LIB} SHARED ${SRCS} ${HDRS}) # if (NOT SOFTWARE_ONLY) # target_link_libraries (${LIB} ${OPENGL_LIBRARIES}) # endif() target_link_libraries (${LIB} common) if (APPLE) find_library (APPKIT AppKit) target_link_libraries (${LIB} ${APPKIT}) endif () if (UNIX AND NOT APPLE) target_link_libraries (${LIB} rt dl) if (BUILD_EGL) # target_link_libraries(${LIB} EGL) target_compile_definitions(${LIB} PRIVATE BUILD_EGL) endif () if (BUILD_MESA) target_link_libraries (${LIB} OSMesa) target_compile_definitions(${LIB} PRIVATE BUILD_MESA) endif () endif () # if (CONDA_BUILD AND UNIX AND NOT APPLE) # target_link_libraries (${LIB} rt) # endif() if (NOT WIN32) target_compile_options(${LIB} PRIVATE -Wno-deprecated-declarations) endif() # target_compile_options(${LIB} PRIVATE -Wno-unknown-warning-option) # file(COPY ${HDRS} DESTINATION ${CMAKE_BINARY_DIR}/include/vapor) # foreach (HDR ${HDRS}) # copy(${HDR} ${CMAKE_BINARY_DIR}/include/vapor) # Does not work with xcode... # endforeach() # target_include_directories (${LIB} PUBLIC ${CMAKE_BINARY_DIR}/include) target_include_directories (${LIB} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories (${LIB} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/glad/include) if (WIN32) add_definitions (-DOSGL_EXPORTS) add_definitions (-DGLAD_API_CALL_EXPORT_BUILD) endif() install ( TARGETS ${LIB} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Libraries ) install ( FILES ${HDRS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT Libraries ) install ( DIRECTORY glad/include/glad glad/include/KHR glad/include/EGL DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT Libraries ) set (BUILD_OSGL_TESTS OFF) if (NOT WIN32 AND BUILD_OSGL_TESTS) file (GLOB TESTS ./test_*.cpp) foreach (TEST ${TESTS}) get_filename_component(TEST_NAME "${TEST}" NAME_WE) set(TEST_TARGET "${LIB}_${TEST_NAME}") add_executable(${TEST_TARGET} "${TEST}") target_link_libraries(${TEST_TARGET} ${LIB}) target_compile_options(${TEST_TARGET} PRIVATE -Wno-deprecated-declarations) install(TARGETS ${TEST_TARGET} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Libraries) endforeach() endif() ================================================ FILE: lib/osgl/GLContext.cpp ================================================ #include #include String GLContext::GetVersion() { MakeCurrent(); return GLContextProviderUtil::GetGLVersion(); } ================================================ FILE: lib/osgl/GLContextProvider.cpp ================================================ #include #include #include #include #include #include GLContext *GLContextProvider::CreateContext() { #define returnIfSupportedContext(ctxProvider) \ { \ GLContext *ctx = ctxProvider::CreateContext(); \ if (isContextOk(ctx)) \ return ctx; \ else if (ctx) \ delete ctx; \ } #if MacOS returnIfSupportedContext(GLContextProviderMacOS); #endif #if BUILD_EGL returnIfSupportedContext(GLContextProviderNvidia); returnIfSupportedContext(GLContextProviderEGL); #endif #if BUILD_MESA LogWarning("Could not get an OpenGL context from the display manager. Is one running?"); LogWarning("Falling back to software rendering"); returnIfSupportedContext(GLContextProviderMesa); #endif LogWarning("Could not create OpenGL context"); return nullptr; } bool GLContextProvider::isContextOk(GLContext *ctx) { if (ctx == nullptr) return false; ctx->MakeCurrent(); return IsCurrentOpenGLVersionSupported(); } bool GLContextProvider::IsCurrentOpenGLVersionSupported() { int major, minor; GLContextProviderUtil::GetGLVersion(&major, &minor); int version = major * 100 + minor; if (version >= 303) return true; return false; } ================================================ FILE: lib/osgl/GLContextProviderEGL.cpp ================================================ #include #if BUILD_EGL #if !Linux #error EGL only supported on linux #endif #include #include GLContextProviderEGL::GLContextEGL::GLContextEGL(void *display, void *surface, void *context) : _display(display), _surface(surface), _context(context) {} GLContextProviderEGL::GLContextEGL::~GLContextEGL() { eglTerminate(_display); } void GLContextProviderEGL::GLContextEGL::MakeCurrent() { eglMakeCurrent(_display, _surface, _surface, _context); } #ifdef NDEBUG #define REQUIRED_EGL(f) if (f==NULL) { LogWarning("Could not load EGL function %s", #f); return nullptr; } #else #define REQUIRED_EGL(f) printf("EGL function %-25s %s (%p)\n", #f, f?"ok":"FAIL", f) #endif GLContext *GLContextProviderEGL::CreateContext() { if (!gladLoaderLoadEGL(nullptr)) { LogWarning("Could not load EGL"); return nullptr; } REQUIRED_EGL(eglGetDisplay); REQUIRED_EGL(eglGetError); REQUIRED_EGL(eglMakeCurrent); REQUIRED_EGL(eglTerminate); EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); EGLint err = eglGetError(); if (display == nullptr || err != EGL_SUCCESS) { LogWarning("Failed to get a display"); LogWarning("EGL Error: %s", stringifyEGLError(err)); return nullptr; } return createContextForDisplay(display); } GLContext *GLContextProviderEGL::createContextForDisplay(void *display) { if (!gladLoaderLoadEGL(display)) { LogWarning("Could not load EGL"); return nullptr; } REQUIRED_EGL(eglInitialize); REQUIRED_EGL(eglGetError); REQUIRED_EGL(eglChooseConfig); REQUIRED_EGL(eglCreatePbufferSurface); REQUIRED_EGL(eglBindAPI); REQUIRED_EGL(eglCreateContext); REQUIRED_EGL(eglGetProcAddress); EGLint major, minor, err; EGLBoolean ret = eglInitialize(display, &major, &minor); err = eglGetError(); if (ret != EGL_TRUE || err != EGL_SUCCESS) { LogWarning("Failed to initialize EGL"); LogWarning("EGL Error: %s", stringifyEGLError(err)); return nullptr; } LogInfo("EGL Version %i.%i", major, minor); EGLint numConfigs; EGLConfig config; const EGLint configAttribs[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_DEPTH_SIZE, 24, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE}; eglChooseConfig(display, configAttribs, &config, 1, &numConfigs); err = eglGetError(); if (err != EGL_SUCCESS) { LogWarning("Failed to get EGL config"); LogWarning("EGL Error: %s", stringifyEGLError(err)); return nullptr; } const EGLint pbufferAttribs[] = { EGL_WIDTH, 100, EGL_HEIGHT, 100, EGL_NONE, }; EGLSurface surface = eglCreatePbufferSurface(display, config, pbufferAttribs); err = eglGetError(); if (surface == nullptr || err != EGL_SUCCESS) { LogWarning("Failed to create surface"); LogWarning("EGL Error: %s", stringifyEGLError(err)); return nullptr; } eglBindAPI(EGL_OPENGL_API); err = eglGetError(); if (err != EGL_SUCCESS) { LogWarning("Failed to bind OpenGL API"); LogWarning("EGL Error: %s", stringifyEGLError(err)); return nullptr; } EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, NULL); err = eglGetError(); if (context == nullptr || err != EGL_SUCCESS) { LogWarning("Failed to create context"); LogWarning("EGL Error: %s", stringifyEGLError(err)); return nullptr; } GLContextEGL *glContext = new GLContextEGL(display, surface, context); glContext->MakeCurrent(); if (!gladLoadGL((GLADloadfunc)eglGetProcAddress)) { LogWarning("Failed to load GL"); delete glContext; return nullptr; } LogInfo("Created context: %s", glContext->GetVersion().c_str()); return glContext; } const char *GLContextProviderEGL::stringifyEGLError(int e) { switch (e) { case EGL_SUCCESS: return "EGL_SUCCESS"; case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED"; case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT"; case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER"; case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST"; default: return "EGL_UNKNOWN_ERROR"; } } #endif ================================================ FILE: lib/osgl/GLContextProviderMacOS.mm ================================================ #include #include // This include shouldn't be required but Conda's compiler is sporadically improperly configured. #include #include #include // This uses the macOS native libraries which are written in Objective-C. GLContextProviderMacOS::GLContextMacOS::GLContextMacOS(void *ctx) : _ctx(ctx) {} GLContextProviderMacOS::GLContextMacOS::~GLContextMacOS() { NSOpenGLContext *ctx = (NSOpenGLContext *)_ctx; [ctx dealloc]; } void GLContextProviderMacOS::GLContextMacOS::MakeCurrent() { NSOpenGLContext *ctx = (NSOpenGLContext *)_ctx; [ctx makeCurrentContext]; } GLContext *GLContextProviderMacOS::CreateContext() { NSOpenGLPixelFormatAttribute attrs[] = { NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core, // Undocumented 0 }; NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; if (fmt == nil) { LogWarning("Failed to create pixel format\n"); return nullptr; } NSOpenGLContext *ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:nil]; if (ctx == nil) { LogWarning("Failed to create context\n"); [fmt dealloc]; return nullptr; } GLContextMacOS *glContext = new GLContextMacOS(ctx); glContext->MakeCurrent(); if (!gladLoaderLoadGL()) { LogWarning("Failed to load GL"); delete glContext; return nullptr; } LogInfo("Created context: %s", glContext->GetVersion().c_str()); return glContext; } ================================================ FILE: lib/osgl/GLContextProviderMesa.cpp ================================================ #include #if BUILD_MESA #include #include GLContextProviderMesa::GLContextMesa::GLContextMesa(void *ctx) : _ctx(ctx) {} GLContextProviderMesa::GLContextMesa::~GLContextMesa() { OSMesaContext ctx = (OSMesaContext)_ctx; OSMesaDestroyContext(ctx); } void GLContextProviderMesa::GLContextMesa::MakeCurrent() { OSMesaContext ctx = (OSMesaContext)_ctx; bool success = OSMesaMakeCurrent(ctx, _dummyBuffer, GL_UNSIGNED_BYTE, 4, 4); assert(success); } void GLContextProviderMesa::GLContextMesa::DumpParameters() const { #define OSMPP(p) { int v; OSMesaGetIntegerv(p, &v); printf("\t%s = %i", #p, v); } printf("OSMesa Parameters\n"); OSMPP(OSMESA_WIDTH); OSMPP(OSMESA_HEIGHT); OSMPP(OSMESA_FORMAT); OSMPP(OSMESA_TYPE); OSMPP(OSMESA_ROW_LENGTH); OSMPP(OSMESA_Y_UP); #undef OSMPP } GLContext *GLContextProviderMesa::CreateContext() { LogInfo("OSMesa %i.%i.%i", OSMESA_MAJOR_VERSION, OSMESA_MINOR_VERSION, OSMESA_PATCH_VERSION); // Attributes Values // -------------------------------------------------------------------------- // OSMESA_FORMAT OSMESA_RGBA*, OSMESA_BGRA, OSMESA_ARGB, OSMESA_RGB etc. // OSMESA_DEPTH_BITS 0*, 16, 24, 32 // OSMESA_STENCIL_BITS 0*, 8 // OSMESA_ACCUM_BITS 0*, 16 // OSMESA_PROFILE OSMESA_COMPAT_PROFILE*, OSMESA_CORE_PROFILE // OSMESA_CONTEXT_MAJOR_VERSION 1*, 2, 3 // OSMESA_CONTEXT_MINOR_VERSION 0+ // // Note: * = default value // Note: NULL terminated int attrs[] = { OSMESA_FORMAT, OSMESA_RGB, OSMESA_PROFILE, OSMESA_CORE_PROFILE, OSMESA_CONTEXT_MAJOR_VERSION, 3, OSMESA_CONTEXT_MINOR_VERSION, 3, NULL }; OSMesaContext ctx = nullptr; ctx = OSMesaCreateContextAttribs(attrs, NULL); if (!ctx) { LogWarning("OSMesaCreateContextAttribs failed"); OSMesaCreateContextExt(OSMESA_RGB, 0, 0, 0, NULL); } if (!ctx) { LogWarning("OSMesaCreateContextExt failed"); ctx = OSMesaCreateContext(OSMESA_RGB, NULL); } if (!ctx) { LogWarning("Failed to create context"); return nullptr; } GLContextMesa *glContext = new GLContextMesa(ctx); glContext->MakeCurrent(); if (!gladLoadGL((GLADloadfunc)OSMesaGetProcAddress)) { LogWarning("Failed to load GL"); delete glContext; return nullptr; } LogInfo("Created context: %s", glContext->GetVersion().c_str()); return glContext; } #endif ================================================ FILE: lib/osgl/GLContextProviderNvidia.cpp ================================================ #include #include #if BUILD_EGL #if !Linux #error EGL only supported on linux #endif #include #include // Required if using system EGL // #define EGL_EGLEXT_PROTOTYPES // #include GLContext *GLContextProviderNvidia::CreateContext() { if (!gladLoaderLoadEGL(nullptr)) { LogWarning("Could not load EGL"); return nullptr; } const int MAX_DEVICES = 8; EGLDeviceEXT eglDevices[MAX_DEVICES]; String eglDeviceStrings[MAX_DEVICES]; EGLint numDevices; // Required if using system EGL // PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT"); // PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = (PFNEGLQUERYDEVICESTRINGEXTPROC)eglGetProcAddress("eglQueryDeviceStringEXT"); // PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT"); if (eglQueryDevicesEXT == nullptr || eglQueryDeviceStringEXT == nullptr || eglGetPlatformDisplayEXT == nullptr) { LogWarning("Could not load Nvidia EGL extensions"); return nullptr; } eglQueryDevicesEXT(MAX_DEVICES, eglDevices, &numDevices); for (int i = 0; i < numDevices; i++) { const char *str = eglQueryDeviceStringEXT(eglDevices[i], EGL_EXTENSIONS); eglDeviceStrings[i] = String(str); } LogInfo("Found %i EGL devices:", numDevices); for (int i = 0; i < numDevices; i++) Log::Info("\t[%i] = %s", i, eglDeviceStrings[i].c_str()); int nvidiaDeviceId = -1; for (int i = 0; i < numDevices; i++) { if (STLUtils::Contains(STLUtils::ToLower(eglDeviceStrings[i]), "nvidia") || STLUtils::Contains(STLUtils::ToLower(eglDeviceStrings[i]), "egl_nv_") ) { nvidiaDeviceId = i; break; } } if (nvidiaDeviceId >= 0) { LogInfo("Found Nvidia GPU [%i] %s", nvidiaDeviceId, eglDeviceStrings[nvidiaDeviceId].c_str()); } else { LogWarning("Nvidia GPU not found"); return nullptr; } EGLDisplay display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevices[nvidiaDeviceId], 0); EGLint err = eglGetError(); if (display == nullptr || err != EGL_SUCCESS) { LogWarning("Failed to get display from Nvidia GPU"); LogWarning("EGL Error: %s", stringifyEGLError(err)); return nullptr; } return createContextForDisplay(display); } #endif ================================================ FILE: lib/osgl/GLContextProviderUtil.cpp ================================================ #include #include String GLContextProviderUtil::GetGLVersion() { const char *s = (const char *)glGetString(GL_VERSION); assert(s); if (!s) return ""; return String(s); } void GLContextProviderUtil::GetGLVersion(int *major, int *minor) { // Only >=3.0 guarentees glGetIntegerv String version = GetGLVersion(); version = version.substr(0, version.find(" ")); const String majorString = version.substr(0, version.find(".")); *major = std::stoi(majorString); if (majorString.length() < version.length()) { version = version.substr(majorString.length() + 1); const String minorString = version.substr(0, version.find(".")); if (!minorString.empty()) *minor = std::stoi(minorString); else *minor = 0; } } ================================================ FILE: lib/osgl/Log.cpp ================================================ #include #include #include #include #include #ifdef WIN32 #include #endif bool Log::InfoLevelEnabled = true; void Log::printc(const char *format, ...) { va_list args; va_start(args, format); vprintf(format, args); va_end(args); } void Log::fatal() { exit(1); } String Log::AddLocationToFormat(const String &fmt, const char *file, int line) { const char *base = strrchr(file, '/'); base = base ? base + 1 : file; int extraPadding = std::max(4 - (int)std::to_string(line).size(), 0); return "[" + String(base) + ":" + std::to_string(line) + "]" + std::string(extraPadding, ' ') + fmt; } ================================================ FILE: lib/osgl/build.sh ================================================ #!/bin/bash echo build ======================================================================================= echo build ======================================================================================= echo build ======================================================================================= echo build ======================================================================================= echo build ======================================================================================= echo build ======================================================================================= echo build ======================================================================================= echo build ======================================================================================= export echo build ======================================================================================= echo build ======================================================================================= echo build ======================================================================================= mkdir build cd build # Since optimizations are disabled, need to disable fortify source otherwise will get barraged with warnings export CPPFLAGS="`echo $CPPFLAGS|sed 's/-D_FORTIFY_SOURCE=2//g'`" # Ignore extra warnings export CPPFLAGS=" \ $CPPFLAGS \ " # Conda does not properly set CMake flags. This should fix it. export CXXFLAGS="$CPPFLAGS $CXXFLAGS" export CFLAGS="$CPPFLAGS $CFLAGS" cmake .. \ -DCMAKE_INSTALL_PREFIX:PATH="$PREFIX" \ -DCMAKE_INSTALL_LIBDIR=lib \ -DBUILD_SHARED_LIBS=ON \ -DCMAKE_BUILD_TYPE=DEBUG \ ${CMAKE_ARGS} \ -DCMAKE_C_FLAGS_DEBUG="-g -O0" \ -DCMAKE_CXX_FLAGS_DEBUG="-g -O0" \ -DPython_EXECUTABLE="$PYTHON" make -j$(($CPU_COUNT+1)) make install echo build ======================================================================================= echo build ======================================================================================= echo build ======================================================================================= echo build ======================================================================================= echo build ======================================================================================= echo build ======================================================================================= echo build ======================================================================================= echo build ======================================================================================= ================================================ FILE: lib/osgl/glad/include/EGL/eglplatform.h ================================================ #ifndef __eglplatform_h_ #define __eglplatform_h_ /* ** Copyright 2007-2020 The Khronos Group Inc. ** SPDX-License-Identifier: Apache-2.0 */ /* Platform-specific types and definitions for egl.h * * Adopters may modify khrplatform.h and this file to suit their platform. * You are encouraged to submit all modifications to the Khronos group so that * they can be included in future versions of this file. Please submit changes * by filing an issue or pull request on the public Khronos EGL Registry, at * https://www.github.com/KhronosGroup/EGL-Registry/ */ #include /* Macros used in EGL function prototype declarations. * * EGL functions should be prototyped as: * * EGLAPI return-type EGLAPIENTRY eglFunction(arguments); * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments); * * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h */ #ifndef EGLAPI #define EGLAPI KHRONOS_APICALL #endif #ifndef EGLAPIENTRY #define EGLAPIENTRY KHRONOS_APIENTRY #endif #define EGLAPIENTRYP EGLAPIENTRY* /* The types NativeDisplayType, NativeWindowType, and NativePixmapType * are aliases of window-system-dependent types, such as X Display * or * Windows Device Context. They must be defined in platform-specific * code below. The EGL-prefixed versions of Native*Type are the same * types, renamed in EGL 1.3 so all types in the API start with "EGL". * * Khronos STRONGLY RECOMMENDS that you use the default definitions * provided below, since these changes affect both binary and source * portability of applications using EGL running on different EGL * implementations. */ #if defined(EGL_NO_PLATFORM_SPECIFIC_TYPES) typedef void *EGLNativeDisplayType; typedef void *EGLNativePixmapType; typedef void *EGLNativeWindowType; #elif defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 #endif #include typedef HDC EGLNativeDisplayType; typedef HBITMAP EGLNativePixmapType; typedef HWND EGLNativeWindowType; #elif defined(__EMSCRIPTEN__) typedef int EGLNativeDisplayType; typedef int EGLNativePixmapType; typedef int EGLNativeWindowType; #elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */ typedef int EGLNativeDisplayType; typedef void *EGLNativePixmapType; typedef void *EGLNativeWindowType; #elif defined(WL_EGL_PLATFORM) typedef struct wl_display *EGLNativeDisplayType; typedef struct wl_egl_pixmap *EGLNativePixmapType; typedef struct wl_egl_window *EGLNativeWindowType; #elif defined(__GBM__) typedef struct gbm_device *EGLNativeDisplayType; typedef struct gbm_bo *EGLNativePixmapType; typedef void *EGLNativeWindowType; #elif defined(__ANDROID__) || defined(ANDROID) struct ANativeWindow; struct egl_native_pixmap_t; typedef void* EGLNativeDisplayType; typedef struct egl_native_pixmap_t* EGLNativePixmapType; typedef struct ANativeWindow* EGLNativeWindowType; #elif defined(USE_OZONE) typedef intptr_t EGLNativeDisplayType; typedef intptr_t EGLNativePixmapType; typedef intptr_t EGLNativeWindowType; #elif defined(USE_X11) /* X11 (tentative) */ #include #include typedef Display *EGLNativeDisplayType; typedef Pixmap EGLNativePixmapType; typedef Window EGLNativeWindowType; #elif defined(__unix__) typedef void *EGLNativeDisplayType; typedef khronos_uintptr_t EGLNativePixmapType; typedef khronos_uintptr_t EGLNativeWindowType; #elif defined(__APPLE__) typedef int EGLNativeDisplayType; typedef void *EGLNativePixmapType; typedef void *EGLNativeWindowType; #elif defined(__HAIKU__) #include typedef void *EGLNativeDisplayType; typedef khronos_uintptr_t EGLNativePixmapType; typedef khronos_uintptr_t EGLNativeWindowType; #elif defined(__Fuchsia__) typedef void *EGLNativeDisplayType; typedef khronos_uintptr_t EGLNativePixmapType; typedef khronos_uintptr_t EGLNativeWindowType; #else #error "Platform not recognized" #endif /* EGL 1.2 types, renamed for consistency in EGL 1.3 */ typedef EGLNativeDisplayType NativeDisplayType; typedef EGLNativePixmapType NativePixmapType; typedef EGLNativeWindowType NativeWindowType; /* Define EGLint. This must be a signed integral type large enough to contain * all legal attribute names and values passed into and out of EGL, whether * their type is boolean, bitmask, enumerant (symbolic constant), integer, * handle, or other. While in general a 32-bit integer will suffice, if * handles are 64 bit types, then EGLint should be defined as a signed 64-bit * integer type. */ typedef khronos_int32_t EGLint; /* C++ / C typecast macros for special EGL handle values */ #if defined(__cplusplus) #define EGL_CAST(type, value) (static_cast(value)) #else #define EGL_CAST(type, value) ((type) (value)) #endif #endif /* __eglplatform_h */ ================================================ FILE: lib/osgl/glad/include/KHR/khrplatform.h ================================================ #ifndef __khrplatform_h_ #define __khrplatform_h_ /* ** Copyright (c) 2008-2018 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ /* Khronos platform-specific types and definitions. * * The master copy of khrplatform.h is maintained in the Khronos EGL * Registry repository at https://github.com/KhronosGroup/EGL-Registry * The last semantic modification to khrplatform.h was at commit ID: * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 * * Adopters may modify this file to suit their platform. Adopters are * encouraged to submit platform specific modifications to the Khronos * group so that they can be included in future versions of this file. * Please submit changes by filing pull requests or issues on * the EGL Registry repository linked above. * * * See the Implementer's Guidelines for information about where this file * should be located on your system and for more details of its use: * http://www.khronos.org/registry/implementers_guide.pdf * * This file should be included as * #include * by Khronos client API header files that use its types and defines. * * The types in khrplatform.h should only be used to define API-specific types. * * Types defined in khrplatform.h: * khronos_int8_t signed 8 bit * khronos_uint8_t unsigned 8 bit * khronos_int16_t signed 16 bit * khronos_uint16_t unsigned 16 bit * khronos_int32_t signed 32 bit * khronos_uint32_t unsigned 32 bit * khronos_int64_t signed 64 bit * khronos_uint64_t unsigned 64 bit * khronos_intptr_t signed same number of bits as a pointer * khronos_uintptr_t unsigned same number of bits as a pointer * khronos_ssize_t signed size * khronos_usize_t unsigned size * khronos_float_t signed 32 bit floating point * khronos_time_ns_t unsigned 64 bit time in nanoseconds * khronos_utime_nanoseconds_t unsigned time interval or absolute time in * nanoseconds * khronos_stime_nanoseconds_t signed time interval in nanoseconds * khronos_boolean_enum_t enumerated boolean type. This should * only be used as a base type when a client API's boolean type is * an enum. Client APIs which use an integer or other type for * booleans cannot use this as the base type for their boolean. * * Tokens defined in khrplatform.h: * * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. * * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. * * Calling convention macros defined in this file: * KHRONOS_APICALL * KHRONOS_APIENTRY * KHRONOS_APIATTRIBUTES * * These may be used in function prototypes as: * * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( * int arg1, * int arg2) KHRONOS_APIATTRIBUTES; */ #if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) # define KHRONOS_STATIC 1 #endif /*------------------------------------------------------------------------- * Definition of KHRONOS_APICALL *------------------------------------------------------------------------- * This precedes the return type of the function in the function prototype. */ #if defined(KHRONOS_STATIC) /* If the preprocessor constant KHRONOS_STATIC is defined, make the * header compatible with static linking. */ # define KHRONOS_APICALL #elif defined(_WIN32) # define KHRONOS_APICALL __declspec(dllimport) #elif defined (__SYMBIAN32__) # define KHRONOS_APICALL IMPORT_C #elif defined(__ANDROID__) # define KHRONOS_APICALL __attribute__((visibility("default"))) #else # define KHRONOS_APICALL #endif /*------------------------------------------------------------------------- * Definition of KHRONOS_APIENTRY *------------------------------------------------------------------------- * This follows the return type of the function and precedes the function * name in the function prototype. */ #if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) /* Win32 but not WinCE */ # define KHRONOS_APIENTRY __stdcall #else # define KHRONOS_APIENTRY #endif /*------------------------------------------------------------------------- * Definition of KHRONOS_APIATTRIBUTES *------------------------------------------------------------------------- * This follows the closing parenthesis of the function prototype arguments. */ #if defined (__ARMCC_2__) #define KHRONOS_APIATTRIBUTES __softfp #else #define KHRONOS_APIATTRIBUTES #endif /*------------------------------------------------------------------------- * basic type definitions *-----------------------------------------------------------------------*/ #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) /* * Using */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 /* * To support platform where unsigned long cannot be used interchangeably with * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t. * Ideally, we could just use (u)intptr_t everywhere, but this could result in * ABI breakage if khronos_uintptr_t is changed from unsigned long to * unsigned long long or similar (this results in different C++ name mangling). * To avoid changes for existing platforms, we restrict usage of intptr_t to * platforms where the size of a pointer is larger than the size of long. */ #if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__) #if __SIZEOF_POINTER__ > __SIZEOF_LONG__ #define KHRONOS_USE_INTPTR_T #endif #endif #elif defined(__VMS ) || defined(__sgi) /* * Using */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif defined(_WIN32) && !defined(__SCITECH_SNAP__) /* * Win32 */ typedef __int32 khronos_int32_t; typedef unsigned __int32 khronos_uint32_t; typedef __int64 khronos_int64_t; typedef unsigned __int64 khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif defined(__sun__) || defined(__digital__) /* * Sun or Digital */ typedef int khronos_int32_t; typedef unsigned int khronos_uint32_t; #if defined(__arch64__) || defined(_LP64) typedef long int khronos_int64_t; typedef unsigned long int khronos_uint64_t; #else typedef long long int khronos_int64_t; typedef unsigned long long int khronos_uint64_t; #endif /* __arch64__ */ #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif 0 /* * Hypothetical platform with no float or int64 support */ typedef int khronos_int32_t; typedef unsigned int khronos_uint32_t; #define KHRONOS_SUPPORT_INT64 0 #define KHRONOS_SUPPORT_FLOAT 0 #else /* * Generic fallback */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #endif /* * Types that are (so far) the same on all platforms */ typedef signed char khronos_int8_t; typedef unsigned char khronos_uint8_t; typedef signed short int khronos_int16_t; typedef unsigned short int khronos_uint16_t; /* * Types that differ between LLP64 and LP64 architectures - in LLP64, * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears * to be the only LLP64 architecture in current use. */ #ifdef KHRONOS_USE_INTPTR_T typedef intptr_t khronos_intptr_t; typedef uintptr_t khronos_uintptr_t; #elif defined(_WIN64) typedef signed long long int khronos_intptr_t; typedef unsigned long long int khronos_uintptr_t; #else typedef signed long int khronos_intptr_t; typedef unsigned long int khronos_uintptr_t; #endif #if defined(_WIN64) typedef signed long long int khronos_ssize_t; typedef unsigned long long int khronos_usize_t; #else typedef signed long int khronos_ssize_t; typedef unsigned long int khronos_usize_t; #endif #if KHRONOS_SUPPORT_FLOAT /* * Float type */ typedef float khronos_float_t; #endif #if KHRONOS_SUPPORT_INT64 /* Time types * * These types can be used to represent a time interval in nanoseconds or * an absolute Unadjusted System Time. Unadjusted System Time is the number * of nanoseconds since some arbitrary system event (e.g. since the last * time the system booted). The Unadjusted System Time is an unsigned * 64 bit value that wraps back to 0 every 584 years. Time intervals * may be either signed or unsigned. */ typedef khronos_uint64_t khronos_utime_nanoseconds_t; typedef khronos_int64_t khronos_stime_nanoseconds_t; #endif /* * Dummy value used to pad enum types to 32 bits. */ #ifndef KHRONOS_MAX_ENUM #define KHRONOS_MAX_ENUM 0x7FFFFFFF #endif /* * Enumerated boolean type * * Values other than zero should be considered to be true. Therefore * comparisons should not be made against KHRONOS_TRUE. */ typedef enum { KHRONOS_FALSE = 0, KHRONOS_TRUE = 1, KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM } khronos_boolean_enum_t; #endif /* __khrplatform_h_ */ ================================================ FILE: lib/osgl/glad/include/glad/egl.h ================================================ /** * Loader generated by glad 2.0.0-beta on Wed Mar 23 06:44:04 2022 * * Generator: C/C++ * Specification: egl * Extensions: 6 * * APIs: * - egl=1.5 * * Options: * - ALIAS = False * - DEBUG = False * - HEADER_ONLY = False * - LOADER = True * - MX = False * - MX_GLOBAL = False * - ON_DEMAND = False * * Commandline: * --api='egl=1.5' --extensions='EGL_EXT_device_base,EGL_EXT_device_enumeration,EGL_EXT_device_query,EGL_EXT_device_query_name,EGL_EXT_platform_base,EGL_EXT_platform_device' c --loader * * Online: * http://glad.sh/#api=egl%3D1.5&extensions=EGL_EXT_device_base%2CEGL_EXT_device_enumeration%2CEGL_EXT_device_query%2CEGL_EXT_device_query_name%2CEGL_EXT_platform_base%2CEGL_EXT_platform_device&generator=c&options=LOADER * */ #ifndef GLAD_EGL_H_ #define GLAD_EGL_H_ #define GLAD_EGL #define GLAD_OPTION_EGL_LOADER #ifdef __cplusplus extern "C" { #endif #ifndef GLAD_PLATFORM_H_ #define GLAD_PLATFORM_H_ #ifndef GLAD_PLATFORM_WIN32 #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__) #define GLAD_PLATFORM_WIN32 1 #else #define GLAD_PLATFORM_WIN32 0 #endif #endif #ifndef GLAD_PLATFORM_APPLE #ifdef __APPLE__ #define GLAD_PLATFORM_APPLE 1 #else #define GLAD_PLATFORM_APPLE 0 #endif #endif #ifndef GLAD_PLATFORM_EMSCRIPTEN #ifdef __EMSCRIPTEN__ #define GLAD_PLATFORM_EMSCRIPTEN 1 #else #define GLAD_PLATFORM_EMSCRIPTEN 0 #endif #endif #ifndef GLAD_PLATFORM_UWP #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY) #ifdef __has_include #if __has_include() #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 #endif #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 #endif #endif #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY #include #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) #define GLAD_PLATFORM_UWP 1 #endif #endif #ifndef GLAD_PLATFORM_UWP #define GLAD_PLATFORM_UWP 0 #endif #endif #ifdef __GNUC__ #define GLAD_GNUC_EXTENSION __extension__ #else #define GLAD_GNUC_EXTENSION #endif #ifndef GLAD_API_CALL #if defined(GLAD_API_CALL_EXPORT) #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) #if defined(GLAD_API_CALL_EXPORT_BUILD) #if defined(__GNUC__) #define GLAD_API_CALL __attribute__ ((dllexport)) extern #else #define GLAD_API_CALL __declspec(dllexport) extern #endif #else #if defined(__GNUC__) #define GLAD_API_CALL __attribute__ ((dllimport)) extern #else #define GLAD_API_CALL __declspec(dllimport) extern #endif #endif #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD) #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern #else #define GLAD_API_CALL extern #endif #else #define GLAD_API_CALL extern #endif #endif #ifdef APIENTRY #define GLAD_API_PTR APIENTRY #elif GLAD_PLATFORM_WIN32 #define GLAD_API_PTR __stdcall #else #define GLAD_API_PTR #endif #ifndef GLAPI #define GLAPI GLAD_API_CALL #endif #ifndef GLAPIENTRY #define GLAPIENTRY GLAD_API_PTR #endif #define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor) #define GLAD_VERSION_MAJOR(version) (version / 10000) #define GLAD_VERSION_MINOR(version) (version % 10000) #define GLAD_GENERATOR_VERSION "2.0.0-beta" typedef void (*GLADapiproc)(void); typedef GLADapiproc (*GLADloadfunc)(const char *name); typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name); typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...); typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...); #endif /* GLAD_PLATFORM_H_ */ #define EGL_ALPHA_FORMAT 0x3088 #define EGL_ALPHA_FORMAT_NONPRE 0x308B #define EGL_ALPHA_FORMAT_PRE 0x308C #define EGL_ALPHA_MASK_SIZE 0x303E #define EGL_ALPHA_SIZE 0x3021 #define EGL_BACK_BUFFER 0x3084 #define EGL_BAD_ACCESS 0x3002 #define EGL_BAD_ALLOC 0x3003 #define EGL_BAD_ATTRIBUTE 0x3004 #define EGL_BAD_CONFIG 0x3005 #define EGL_BAD_CONTEXT 0x3006 #define EGL_BAD_CURRENT_SURFACE 0x3007 #define EGL_BAD_DEVICE_EXT 0x322B #define EGL_BAD_DISPLAY 0x3008 #define EGL_BAD_MATCH 0x3009 #define EGL_BAD_NATIVE_PIXMAP 0x300A #define EGL_BAD_NATIVE_WINDOW 0x300B #define EGL_BAD_PARAMETER 0x300C #define EGL_BAD_SURFACE 0x300D #define EGL_BIND_TO_TEXTURE_RGB 0x3039 #define EGL_BIND_TO_TEXTURE_RGBA 0x303A #define EGL_BLUE_SIZE 0x3022 #define EGL_BUFFER_DESTROYED 0x3095 #define EGL_BUFFER_PRESERVED 0x3094 #define EGL_BUFFER_SIZE 0x3020 #define EGL_CLIENT_APIS 0x308D #define EGL_CL_EVENT_HANDLE 0x309C #define EGL_COLORSPACE 0x3087 #define EGL_COLORSPACE_LINEAR 0x308A #define EGL_COLORSPACE_sRGB 0x3089 #define EGL_COLOR_BUFFER_TYPE 0x303F #define EGL_CONDITION_SATISFIED 0x30F6 #define EGL_CONFIG_CAVEAT 0x3027 #define EGL_CONFIG_ID 0x3028 #define EGL_CONFORMANT 0x3042 #define EGL_CONTEXT_CLIENT_TYPE 0x3097 #define EGL_CONTEXT_CLIENT_VERSION 0x3098 #define EGL_CONTEXT_LOST 0x300E #define EGL_CONTEXT_MAJOR_VERSION 0x3098 #define EGL_CONTEXT_MINOR_VERSION 0x30FB #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002 #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001 #define EGL_CONTEXT_OPENGL_DEBUG 0x31B0 #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1 #define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD #define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2 #define EGL_CORE_NATIVE_ENGINE 0x305B #define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0) #define EGL_DEPTH_SIZE 0x3025 #define EGL_DEVICE_EXT 0x322C #define EGL_DISPLAY_SCALING 10000 #define EGL_DONT_CARE EGL_CAST(EGLint,-1) #define EGL_DRAW 0x3059 #define EGL_EXTENSIONS 0x3055 #define EGL_FALSE 0 #define EGL_FOREVER 0xFFFFFFFFFFFFFFFF #define EGL_GL_COLORSPACE 0x309D #define EGL_GL_COLORSPACE_LINEAR 0x308A #define EGL_GL_COLORSPACE_SRGB 0x3089 #define EGL_GL_RENDERBUFFER 0x30B9 #define EGL_GL_TEXTURE_2D 0x30B1 #define EGL_GL_TEXTURE_3D 0x30B2 #define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4 #define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6 #define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8 #define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3 #define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5 #define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7 #define EGL_GL_TEXTURE_LEVEL 0x30BC #define EGL_GL_TEXTURE_ZOFFSET 0x30BD #define EGL_GREEN_SIZE 0x3023 #define EGL_HEIGHT 0x3056 #define EGL_HORIZONTAL_RESOLUTION 0x3090 #define EGL_IMAGE_PRESERVED 0x30D2 #define EGL_LARGEST_PBUFFER 0x3058 #define EGL_LEVEL 0x3029 #define EGL_LOSE_CONTEXT_ON_RESET 0x31BF #define EGL_LUMINANCE_BUFFER 0x308F #define EGL_LUMINANCE_SIZE 0x303D #define EGL_MATCH_NATIVE_PIXMAP 0x3041 #define EGL_MAX_PBUFFER_HEIGHT 0x302A #define EGL_MAX_PBUFFER_PIXELS 0x302B #define EGL_MAX_PBUFFER_WIDTH 0x302C #define EGL_MAX_SWAP_INTERVAL 0x303C #define EGL_MIN_SWAP_INTERVAL 0x303B #define EGL_MIPMAP_LEVEL 0x3083 #define EGL_MIPMAP_TEXTURE 0x3082 #define EGL_MULTISAMPLE_RESOLVE 0x3099 #define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B #define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 #define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A #define EGL_NATIVE_RENDERABLE 0x302D #define EGL_NATIVE_VISUAL_ID 0x302E #define EGL_NATIVE_VISUAL_TYPE 0x302F #define EGL_NONE 0x3038 #define EGL_NON_CONFORMANT_CONFIG 0x3051 #define EGL_NOT_INITIALIZED 0x3001 #define EGL_NO_CONTEXT EGL_CAST(EGLContext,0) #define EGL_NO_DEVICE_EXT EGL_CAST(EGLDeviceEXT,0) #define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0) #define EGL_NO_IMAGE EGL_CAST(EGLImage,0) #define EGL_NO_RESET_NOTIFICATION 0x31BE #define EGL_NO_SURFACE EGL_CAST(EGLSurface,0) #define EGL_NO_SYNC EGL_CAST(EGLSync,0) #define EGL_NO_TEXTURE 0x305C #define EGL_OPENGL_API 0x30A2 #define EGL_OPENGL_BIT 0x0008 #define EGL_OPENGL_ES2_BIT 0x0004 #define EGL_OPENGL_ES3_BIT 0x00000040 #define EGL_OPENGL_ES_API 0x30A0 #define EGL_OPENGL_ES_BIT 0x0001 #define EGL_OPENVG_API 0x30A1 #define EGL_OPENVG_BIT 0x0002 #define EGL_OPENVG_IMAGE 0x3096 #define EGL_PBUFFER_BIT 0x0001 #define EGL_PIXEL_ASPECT_RATIO 0x3092 #define EGL_PIXMAP_BIT 0x0002 #define EGL_PLATFORM_DEVICE_EXT 0x313F #define EGL_READ 0x305A #define EGL_RED_SIZE 0x3024 #define EGL_RENDERABLE_TYPE 0x3040 #define EGL_RENDERER_EXT 0x335F #define EGL_RENDER_BUFFER 0x3086 #define EGL_RGB_BUFFER 0x308E #define EGL_SAMPLES 0x3031 #define EGL_SAMPLE_BUFFERS 0x3032 #define EGL_SIGNALED 0x30F2 #define EGL_SINGLE_BUFFER 0x3085 #define EGL_SLOW_CONFIG 0x3050 #define EGL_STENCIL_SIZE 0x3026 #define EGL_SUCCESS 0x3000 #define EGL_SURFACE_TYPE 0x3033 #define EGL_SWAP_BEHAVIOR 0x3093 #define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 #define EGL_SYNC_CL_EVENT 0x30FE #define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF #define EGL_SYNC_CONDITION 0x30F8 #define EGL_SYNC_FENCE 0x30F9 #define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001 #define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0 #define EGL_SYNC_STATUS 0x30F1 #define EGL_SYNC_TYPE 0x30F7 #define EGL_TEXTURE_2D 0x305F #define EGL_TEXTURE_FORMAT 0x3080 #define EGL_TEXTURE_RGB 0x305D #define EGL_TEXTURE_RGBA 0x305E #define EGL_TEXTURE_TARGET 0x3081 #define EGL_TIMEOUT_EXPIRED 0x30F5 #define EGL_TRANSPARENT_BLUE_VALUE 0x3035 #define EGL_TRANSPARENT_GREEN_VALUE 0x3036 #define EGL_TRANSPARENT_RED_VALUE 0x3037 #define EGL_TRANSPARENT_RGB 0x3052 #define EGL_TRANSPARENT_TYPE 0x3034 #define EGL_TRUE 1 #define EGL_UNKNOWN EGL_CAST(EGLint,-1) #define EGL_UNSIGNALED 0x30F3 #define EGL_VENDOR 0x3053 #define EGL_VERSION 0x3054 #define EGL_VERTICAL_RESOLUTION 0x3091 #define EGL_VG_ALPHA_FORMAT 0x3088 #define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B #define EGL_VG_ALPHA_FORMAT_PRE 0x308C #define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 #define EGL_VG_COLORSPACE 0x3087 #define EGL_VG_COLORSPACE_LINEAR 0x308A #define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 #define EGL_VG_COLORSPACE_sRGB 0x3089 #define EGL_WIDTH 0x3057 #define EGL_WINDOW_BIT 0x0004 #include #include struct AHardwareBuffer; struct wl_buffer; struct wl_display; struct wl_resource; typedef unsigned int EGLBoolean; typedef unsigned int EGLenum; typedef intptr_t EGLAttribKHR; typedef intptr_t EGLAttrib; typedef void *EGLClientBuffer; typedef void *EGLConfig; typedef void *EGLContext; typedef void *EGLDeviceEXT; typedef void *EGLDisplay; typedef void *EGLImage; typedef void *EGLImageKHR; typedef void *EGLLabelKHR; typedef void *EGLObjectKHR; typedef void *EGLOutputLayerEXT; typedef void *EGLOutputPortEXT; typedef void *EGLStreamKHR; typedef void *EGLSurface; typedef void *EGLSync; typedef void *EGLSyncKHR; typedef void *EGLSyncNV; typedef void (*__eglMustCastToProperFunctionPointerType)(void); typedef khronos_utime_nanoseconds_t EGLTimeKHR; typedef khronos_utime_nanoseconds_t EGLTime; typedef khronos_utime_nanoseconds_t EGLTimeNV; typedef khronos_utime_nanoseconds_t EGLuint64NV; typedef khronos_uint64_t EGLuint64KHR; typedef khronos_stime_nanoseconds_t EGLnsecsANDROID; typedef int EGLNativeFileDescriptorKHR; typedef khronos_ssize_t EGLsizeiANDROID; typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize); typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize); struct EGLClientPixmapHI { void *pData; EGLint iWidth; EGLint iHeight; EGLint iStride; }; typedef void (GLAD_API_PTR *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message); #define PFNEGLBINDWAYLANDDISPLAYWL PFNEGLBINDWAYLANDDISPLAYWLPROC #define PFNEGLUNBINDWAYLANDDISPLAYWL PFNEGLUNBINDWAYLANDDISPLAYWLPROC #define PFNEGLQUERYWAYLANDBUFFERWL PFNEGLQUERYWAYLANDBUFFERWLPROC #define PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC #define EGL_VERSION_1_0 1 GLAD_API_CALL int GLAD_EGL_VERSION_1_0; #define EGL_VERSION_1_1 1 GLAD_API_CALL int GLAD_EGL_VERSION_1_1; #define EGL_VERSION_1_2 1 GLAD_API_CALL int GLAD_EGL_VERSION_1_2; #define EGL_VERSION_1_3 1 GLAD_API_CALL int GLAD_EGL_VERSION_1_3; #define EGL_VERSION_1_4 1 GLAD_API_CALL int GLAD_EGL_VERSION_1_4; #define EGL_VERSION_1_5 1 GLAD_API_CALL int GLAD_EGL_VERSION_1_5; #define EGL_EXT_device_base 1 GLAD_API_CALL int GLAD_EGL_EXT_device_base; #define EGL_EXT_device_enumeration 1 GLAD_API_CALL int GLAD_EGL_EXT_device_enumeration; #define EGL_EXT_device_query 1 GLAD_API_CALL int GLAD_EGL_EXT_device_query; #define EGL_EXT_device_query_name 1 GLAD_API_CALL int GLAD_EGL_EXT_device_query_name; #define EGL_EXT_platform_base 1 GLAD_API_CALL int GLAD_EGL_EXT_platform_base; #define EGL_EXT_platform_device 1 GLAD_API_CALL int GLAD_EGL_EXT_platform_device; typedef EGLBoolean (GLAD_API_PTR *PFNEGLBINDAPIPROC)(EGLenum api); typedef EGLBoolean (GLAD_API_PTR *PFNEGLBINDTEXIMAGEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint buffer); typedef EGLBoolean (GLAD_API_PTR *PFNEGLCHOOSECONFIGPROC)(EGLDisplay dpy, const EGLint * attrib_list, EGLConfig * configs, EGLint config_size, EGLint * num_config); typedef EGLint (GLAD_API_PTR *PFNEGLCLIENTWAITSYNCPROC)(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout); typedef EGLBoolean (GLAD_API_PTR *PFNEGLCOPYBUFFERSPROC)(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target); typedef EGLContext (GLAD_API_PTR *PFNEGLCREATECONTEXTPROC)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint * attrib_list); typedef EGLImage (GLAD_API_PTR *PFNEGLCREATEIMAGEPROC)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib * attrib_list); typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC)(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint * attrib_list); typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPBUFFERSURFACEPROC)(EGLDisplay dpy, EGLConfig config, const EGLint * attrib_list); typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPIXMAPSURFACEPROC)(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint * attrib_list); typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC)(EGLDisplay dpy, EGLConfig config, void * native_pixmap, const EGLAttrib * attrib_list); typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC)(EGLDisplay dpy, EGLConfig config, void * native_pixmap, const EGLint * attrib_list); typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMWINDOWSURFACEPROC)(EGLDisplay dpy, EGLConfig config, void * native_window, const EGLAttrib * attrib_list); typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)(EGLDisplay dpy, EGLConfig config, void * native_window, const EGLint * attrib_list); typedef EGLSync (GLAD_API_PTR *PFNEGLCREATESYNCPROC)(EGLDisplay dpy, EGLenum type, const EGLAttrib * attrib_list); typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEWINDOWSURFACEPROC)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint * attrib_list); typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx); typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYIMAGEPROC)(EGLDisplay dpy, EGLImage image); typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYSURFACEPROC)(EGLDisplay dpy, EGLSurface surface); typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYSYNCPROC)(EGLDisplay dpy, EGLSync sync); typedef EGLBoolean (GLAD_API_PTR *PFNEGLGETCONFIGATTRIBPROC)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint * value); typedef EGLBoolean (GLAD_API_PTR *PFNEGLGETCONFIGSPROC)(EGLDisplay dpy, EGLConfig * configs, EGLint config_size, EGLint * num_config); typedef EGLContext (GLAD_API_PTR *PFNEGLGETCURRENTCONTEXTPROC)(void); typedef EGLDisplay (GLAD_API_PTR *PFNEGLGETCURRENTDISPLAYPROC)(void); typedef EGLSurface (GLAD_API_PTR *PFNEGLGETCURRENTSURFACEPROC)(EGLint readdraw); typedef EGLDisplay (GLAD_API_PTR *PFNEGLGETDISPLAYPROC)(EGLNativeDisplayType display_id); typedef EGLint (GLAD_API_PTR *PFNEGLGETERRORPROC)(void); typedef EGLDisplay (GLAD_API_PTR *PFNEGLGETPLATFORMDISPLAYPROC)(EGLenum platform, void * native_display, const EGLAttrib * attrib_list); typedef EGLDisplay (GLAD_API_PTR *PFNEGLGETPLATFORMDISPLAYEXTPROC)(EGLenum platform, void * native_display, const EGLint * attrib_list); typedef __eglMustCastToProperFunctionPointerType (GLAD_API_PTR *PFNEGLGETPROCADDRESSPROC)(const char * procname); typedef EGLBoolean (GLAD_API_PTR *PFNEGLGETSYNCATTRIBPROC)(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib * value); typedef EGLBoolean (GLAD_API_PTR *PFNEGLINITIALIZEPROC)(EGLDisplay dpy, EGLint * major, EGLint * minor); typedef EGLBoolean (GLAD_API_PTR *PFNEGLMAKECURRENTPROC)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); typedef EGLenum (GLAD_API_PTR *PFNEGLQUERYAPIPROC)(void); typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint * value); typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYDEVICEATTRIBEXTPROC)(EGLDeviceEXT device, EGLint attribute, EGLAttrib * value); typedef const char * (GLAD_API_PTR *PFNEGLQUERYDEVICESTRINGEXTPROC)(EGLDeviceEXT device, EGLint name); typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYDEVICESEXTPROC)(EGLint max_devices, EGLDeviceEXT * devices, EGLint * num_devices); typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYDISPLAYATTRIBEXTPROC)(EGLDisplay dpy, EGLint attribute, EGLAttrib * value); typedef const char * (GLAD_API_PTR *PFNEGLQUERYSTRINGPROC)(EGLDisplay dpy, EGLint name); typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYSURFACEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint * value); typedef EGLBoolean (GLAD_API_PTR *PFNEGLRELEASETEXIMAGEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint buffer); typedef EGLBoolean (GLAD_API_PTR *PFNEGLRELEASETHREADPROC)(void); typedef EGLBoolean (GLAD_API_PTR *PFNEGLSURFACEATTRIBPROC)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value); typedef EGLBoolean (GLAD_API_PTR *PFNEGLSWAPBUFFERSPROC)(EGLDisplay dpy, EGLSurface surface); typedef EGLBoolean (GLAD_API_PTR *PFNEGLSWAPINTERVALPROC)(EGLDisplay dpy, EGLint interval); typedef EGLBoolean (GLAD_API_PTR *PFNEGLTERMINATEPROC)(EGLDisplay dpy); typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITCLIENTPROC)(void); typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITGLPROC)(void); typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITNATIVEPROC)(EGLint engine); typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITSYNCPROC)(EGLDisplay dpy, EGLSync sync, EGLint flags); GLAD_API_CALL PFNEGLBINDAPIPROC glad_eglBindAPI; #define eglBindAPI glad_eglBindAPI GLAD_API_CALL PFNEGLBINDTEXIMAGEPROC glad_eglBindTexImage; #define eglBindTexImage glad_eglBindTexImage GLAD_API_CALL PFNEGLCHOOSECONFIGPROC glad_eglChooseConfig; #define eglChooseConfig glad_eglChooseConfig GLAD_API_CALL PFNEGLCLIENTWAITSYNCPROC glad_eglClientWaitSync; #define eglClientWaitSync glad_eglClientWaitSync GLAD_API_CALL PFNEGLCOPYBUFFERSPROC glad_eglCopyBuffers; #define eglCopyBuffers glad_eglCopyBuffers GLAD_API_CALL PFNEGLCREATECONTEXTPROC glad_eglCreateContext; #define eglCreateContext glad_eglCreateContext GLAD_API_CALL PFNEGLCREATEIMAGEPROC glad_eglCreateImage; #define eglCreateImage glad_eglCreateImage GLAD_API_CALL PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC glad_eglCreatePbufferFromClientBuffer; #define eglCreatePbufferFromClientBuffer glad_eglCreatePbufferFromClientBuffer GLAD_API_CALL PFNEGLCREATEPBUFFERSURFACEPROC glad_eglCreatePbufferSurface; #define eglCreatePbufferSurface glad_eglCreatePbufferSurface GLAD_API_CALL PFNEGLCREATEPIXMAPSURFACEPROC glad_eglCreatePixmapSurface; #define eglCreatePixmapSurface glad_eglCreatePixmapSurface GLAD_API_CALL PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC glad_eglCreatePlatformPixmapSurface; #define eglCreatePlatformPixmapSurface glad_eglCreatePlatformPixmapSurface GLAD_API_CALL PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC glad_eglCreatePlatformPixmapSurfaceEXT; #define eglCreatePlatformPixmapSurfaceEXT glad_eglCreatePlatformPixmapSurfaceEXT GLAD_API_CALL PFNEGLCREATEPLATFORMWINDOWSURFACEPROC glad_eglCreatePlatformWindowSurface; #define eglCreatePlatformWindowSurface glad_eglCreatePlatformWindowSurface GLAD_API_CALL PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC glad_eglCreatePlatformWindowSurfaceEXT; #define eglCreatePlatformWindowSurfaceEXT glad_eglCreatePlatformWindowSurfaceEXT GLAD_API_CALL PFNEGLCREATESYNCPROC glad_eglCreateSync; #define eglCreateSync glad_eglCreateSync GLAD_API_CALL PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface; #define eglCreateWindowSurface glad_eglCreateWindowSurface GLAD_API_CALL PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext; #define eglDestroyContext glad_eglDestroyContext GLAD_API_CALL PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage; #define eglDestroyImage glad_eglDestroyImage GLAD_API_CALL PFNEGLDESTROYSURFACEPROC glad_eglDestroySurface; #define eglDestroySurface glad_eglDestroySurface GLAD_API_CALL PFNEGLDESTROYSYNCPROC glad_eglDestroySync; #define eglDestroySync glad_eglDestroySync GLAD_API_CALL PFNEGLGETCONFIGATTRIBPROC glad_eglGetConfigAttrib; #define eglGetConfigAttrib glad_eglGetConfigAttrib GLAD_API_CALL PFNEGLGETCONFIGSPROC glad_eglGetConfigs; #define eglGetConfigs glad_eglGetConfigs GLAD_API_CALL PFNEGLGETCURRENTCONTEXTPROC glad_eglGetCurrentContext; #define eglGetCurrentContext glad_eglGetCurrentContext GLAD_API_CALL PFNEGLGETCURRENTDISPLAYPROC glad_eglGetCurrentDisplay; #define eglGetCurrentDisplay glad_eglGetCurrentDisplay GLAD_API_CALL PFNEGLGETCURRENTSURFACEPROC glad_eglGetCurrentSurface; #define eglGetCurrentSurface glad_eglGetCurrentSurface GLAD_API_CALL PFNEGLGETDISPLAYPROC glad_eglGetDisplay; #define eglGetDisplay glad_eglGetDisplay GLAD_API_CALL PFNEGLGETERRORPROC glad_eglGetError; #define eglGetError glad_eglGetError GLAD_API_CALL PFNEGLGETPLATFORMDISPLAYPROC glad_eglGetPlatformDisplay; #define eglGetPlatformDisplay glad_eglGetPlatformDisplay GLAD_API_CALL PFNEGLGETPLATFORMDISPLAYEXTPROC glad_eglGetPlatformDisplayEXT; #define eglGetPlatformDisplayEXT glad_eglGetPlatformDisplayEXT GLAD_API_CALL PFNEGLGETPROCADDRESSPROC glad_eglGetProcAddress; #define eglGetProcAddress glad_eglGetProcAddress GLAD_API_CALL PFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib; #define eglGetSyncAttrib glad_eglGetSyncAttrib GLAD_API_CALL PFNEGLINITIALIZEPROC glad_eglInitialize; #define eglInitialize glad_eglInitialize GLAD_API_CALL PFNEGLMAKECURRENTPROC glad_eglMakeCurrent; #define eglMakeCurrent glad_eglMakeCurrent GLAD_API_CALL PFNEGLQUERYAPIPROC glad_eglQueryAPI; #define eglQueryAPI glad_eglQueryAPI GLAD_API_CALL PFNEGLQUERYCONTEXTPROC glad_eglQueryContext; #define eglQueryContext glad_eglQueryContext GLAD_API_CALL PFNEGLQUERYDEVICEATTRIBEXTPROC glad_eglQueryDeviceAttribEXT; #define eglQueryDeviceAttribEXT glad_eglQueryDeviceAttribEXT GLAD_API_CALL PFNEGLQUERYDEVICESTRINGEXTPROC glad_eglQueryDeviceStringEXT; #define eglQueryDeviceStringEXT glad_eglQueryDeviceStringEXT GLAD_API_CALL PFNEGLQUERYDEVICESEXTPROC glad_eglQueryDevicesEXT; #define eglQueryDevicesEXT glad_eglQueryDevicesEXT GLAD_API_CALL PFNEGLQUERYDISPLAYATTRIBEXTPROC glad_eglQueryDisplayAttribEXT; #define eglQueryDisplayAttribEXT glad_eglQueryDisplayAttribEXT GLAD_API_CALL PFNEGLQUERYSTRINGPROC glad_eglQueryString; #define eglQueryString glad_eglQueryString GLAD_API_CALL PFNEGLQUERYSURFACEPROC glad_eglQuerySurface; #define eglQuerySurface glad_eglQuerySurface GLAD_API_CALL PFNEGLRELEASETEXIMAGEPROC glad_eglReleaseTexImage; #define eglReleaseTexImage glad_eglReleaseTexImage GLAD_API_CALL PFNEGLRELEASETHREADPROC glad_eglReleaseThread; #define eglReleaseThread glad_eglReleaseThread GLAD_API_CALL PFNEGLSURFACEATTRIBPROC glad_eglSurfaceAttrib; #define eglSurfaceAttrib glad_eglSurfaceAttrib GLAD_API_CALL PFNEGLSWAPBUFFERSPROC glad_eglSwapBuffers; #define eglSwapBuffers glad_eglSwapBuffers GLAD_API_CALL PFNEGLSWAPINTERVALPROC glad_eglSwapInterval; #define eglSwapInterval glad_eglSwapInterval GLAD_API_CALL PFNEGLTERMINATEPROC glad_eglTerminate; #define eglTerminate glad_eglTerminate GLAD_API_CALL PFNEGLWAITCLIENTPROC glad_eglWaitClient; #define eglWaitClient glad_eglWaitClient GLAD_API_CALL PFNEGLWAITGLPROC glad_eglWaitGL; #define eglWaitGL glad_eglWaitGL GLAD_API_CALL PFNEGLWAITNATIVEPROC glad_eglWaitNative; #define eglWaitNative glad_eglWaitNative GLAD_API_CALL PFNEGLWAITSYNCPROC glad_eglWaitSync; #define eglWaitSync glad_eglWaitSync GLAD_API_CALL int gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void *userptr); GLAD_API_CALL int gladLoadEGL(EGLDisplay display, GLADloadfunc load); #ifdef GLAD_EGL GLAD_API_CALL int gladLoaderLoadEGL(EGLDisplay display); GLAD_API_CALL void gladLoaderUnloadEGL(void); #endif #ifdef __cplusplus } #endif #endif ================================================ FILE: lib/osgl/glad/include/glad/gl.h ================================================ /** * Loader generated by glad 2.0.0-beta on Wed Mar 23 06:44:05 2022 * * Generator: C/C++ * Specification: gl * Extensions: 0 * * APIs: * - gl:core=4.1 * * Options: * - ALIAS = False * - DEBUG = False * - HEADER_ONLY = False * - LOADER = True * - MX = False * - MX_GLOBAL = False * - ON_DEMAND = False * * Commandline: * --api='gl:core=4.1' --extensions='' c --loader * * Online: * http://glad.sh/#api=gl%3Acore%3D4.1&extensions=&generator=c&options=LOADER * */ #ifndef GLAD_GL_H_ #define GLAD_GL_H_ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif #ifdef __gl_h_ #error OpenGL (gl.h) header already included (API: gl), remove previous include! #endif #define __gl_h_ 1 #ifdef __gl3_h_ #error OpenGL (gl3.h) header already included (API: gl), remove previous include! #endif #define __gl3_h_ 1 #ifdef __glext_h_ #error OpenGL (glext.h) header already included (API: gl), remove previous include! #endif #define __glext_h_ 1 #ifdef __gl3ext_h_ #error OpenGL (gl3ext.h) header already included (API: gl), remove previous include! #endif #define __gl3ext_h_ 1 #ifdef __clang__ #pragma clang diagnostic pop #endif #define GLAD_GL #define GLAD_OPTION_GL_LOADER #ifdef __cplusplus extern "C" { #endif #ifndef GLAD_PLATFORM_H_ #define GLAD_PLATFORM_H_ #ifndef GLAD_PLATFORM_WIN32 #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__) #define GLAD_PLATFORM_WIN32 1 #else #define GLAD_PLATFORM_WIN32 0 #endif #endif #ifndef GLAD_PLATFORM_APPLE #ifdef __APPLE__ #define GLAD_PLATFORM_APPLE 1 #else #define GLAD_PLATFORM_APPLE 0 #endif #endif #ifndef GLAD_PLATFORM_EMSCRIPTEN #ifdef __EMSCRIPTEN__ #define GLAD_PLATFORM_EMSCRIPTEN 1 #else #define GLAD_PLATFORM_EMSCRIPTEN 0 #endif #endif #ifndef GLAD_PLATFORM_UWP #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY) #ifdef __has_include #if __has_include() #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 #endif #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 #endif #endif #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY #include #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) #define GLAD_PLATFORM_UWP 1 #endif #endif #ifndef GLAD_PLATFORM_UWP #define GLAD_PLATFORM_UWP 0 #endif #endif #ifdef __GNUC__ #define GLAD_GNUC_EXTENSION __extension__ #else #define GLAD_GNUC_EXTENSION #endif #ifndef GLAD_API_CALL #if defined(GLAD_API_CALL_EXPORT) #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) #if defined(GLAD_API_CALL_EXPORT_BUILD) #if defined(__GNUC__) #define GLAD_API_CALL __attribute__ ((dllexport)) extern #else #define GLAD_API_CALL __declspec(dllexport) extern #endif #else #if defined(__GNUC__) #define GLAD_API_CALL __attribute__ ((dllimport)) extern #else #define GLAD_API_CALL __declspec(dllimport) extern #endif #endif #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD) #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern #else #define GLAD_API_CALL extern #endif #else #define GLAD_API_CALL extern #endif #endif #ifdef APIENTRY #define GLAD_API_PTR APIENTRY #elif GLAD_PLATFORM_WIN32 #define GLAD_API_PTR __stdcall #else #define GLAD_API_PTR #endif #ifndef GLAPI #define GLAPI GLAD_API_CALL #endif #ifndef GLAPIENTRY #define GLAPIENTRY GLAD_API_PTR #endif #define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor) #define GLAD_VERSION_MAJOR(version) (version / 10000) #define GLAD_VERSION_MINOR(version) (version % 10000) #define GLAD_GENERATOR_VERSION "2.0.0-beta" typedef void (*GLADapiproc)(void); typedef GLADapiproc (*GLADloadfunc)(const char *name); typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name); typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...); typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...); #endif /* GLAD_PLATFORM_H_ */ #define GL_ACTIVE_ATTRIBUTES 0x8B89 #define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_ACTIVE_PROGRAM 0x8259 #define GL_ACTIVE_SUBROUTINES 0x8DE5 #define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 #define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 #define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 #define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 #define GL_ACTIVE_TEXTURE 0x84E0 #define GL_ACTIVE_UNIFORMS 0x8B86 #define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 #define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 #define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #define GL_ALL_SHADER_BITS 0xFFFFFFFF #define GL_ALPHA 0x1906 #define GL_ALREADY_SIGNALED 0x911A #define GL_ALWAYS 0x0207 #define GL_AND 0x1501 #define GL_AND_INVERTED 0x1504 #define GL_AND_REVERSE 0x1502 #define GL_ANY_SAMPLES_PASSED 0x8C2F #define GL_ARRAY_BUFFER 0x8892 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ATTACHED_SHADERS 0x8B85 #define GL_BACK 0x0405 #define GL_BACK_LEFT 0x0402 #define GL_BACK_RIGHT 0x0403 #define GL_BGR 0x80E0 #define GL_BGRA 0x80E1 #define GL_BGRA_INTEGER 0x8D9B #define GL_BGR_INTEGER 0x8D9A #define GL_BLEND 0x0BE2 #define GL_BLEND_COLOR 0x8005 #define GL_BLEND_DST 0x0BE0 #define GL_BLEND_DST_ALPHA 0x80CA #define GL_BLEND_DST_RGB 0x80C8 #define GL_BLEND_EQUATION 0x8009 #define GL_BLEND_EQUATION_ALPHA 0x883D #define GL_BLEND_EQUATION_RGB 0x8009 #define GL_BLEND_SRC 0x0BE1 #define GL_BLEND_SRC_ALPHA 0x80CB #define GL_BLEND_SRC_RGB 0x80C9 #define GL_BLUE 0x1905 #define GL_BLUE_INTEGER 0x8D96 #define GL_BOOL 0x8B56 #define GL_BOOL_VEC2 0x8B57 #define GL_BOOL_VEC3 0x8B58 #define GL_BOOL_VEC4 0x8B59 #define GL_BUFFER_ACCESS 0x88BB #define GL_BUFFER_ACCESS_FLAGS 0x911F #define GL_BUFFER_MAPPED 0x88BC #define GL_BUFFER_MAP_LENGTH 0x9120 #define GL_BUFFER_MAP_OFFSET 0x9121 #define GL_BUFFER_MAP_POINTER 0x88BD #define GL_BUFFER_SIZE 0x8764 #define GL_BUFFER_USAGE 0x8765 #define GL_BYTE 0x1400 #define GL_CCW 0x0901 #define GL_CLAMP_READ_COLOR 0x891C #define GL_CLAMP_TO_BORDER 0x812D #define GL_CLAMP_TO_EDGE 0x812F #define GL_CLEAR 0x1500 #define GL_CLIP_DISTANCE0 0x3000 #define GL_CLIP_DISTANCE1 0x3001 #define GL_CLIP_DISTANCE2 0x3002 #define GL_CLIP_DISTANCE3 0x3003 #define GL_CLIP_DISTANCE4 0x3004 #define GL_CLIP_DISTANCE5 0x3005 #define GL_CLIP_DISTANCE6 0x3006 #define GL_CLIP_DISTANCE7 0x3007 #define GL_COLOR 0x1800 #define GL_COLOR_ATTACHMENT0 0x8CE0 #define GL_COLOR_ATTACHMENT1 0x8CE1 #define GL_COLOR_ATTACHMENT10 0x8CEA #define GL_COLOR_ATTACHMENT11 0x8CEB #define GL_COLOR_ATTACHMENT12 0x8CEC #define GL_COLOR_ATTACHMENT13 0x8CED #define GL_COLOR_ATTACHMENT14 0x8CEE #define GL_COLOR_ATTACHMENT15 0x8CEF #define GL_COLOR_ATTACHMENT16 0x8CF0 #define GL_COLOR_ATTACHMENT17 0x8CF1 #define GL_COLOR_ATTACHMENT18 0x8CF2 #define GL_COLOR_ATTACHMENT19 0x8CF3 #define GL_COLOR_ATTACHMENT2 0x8CE2 #define GL_COLOR_ATTACHMENT20 0x8CF4 #define GL_COLOR_ATTACHMENT21 0x8CF5 #define GL_COLOR_ATTACHMENT22 0x8CF6 #define GL_COLOR_ATTACHMENT23 0x8CF7 #define GL_COLOR_ATTACHMENT24 0x8CF8 #define GL_COLOR_ATTACHMENT25 0x8CF9 #define GL_COLOR_ATTACHMENT26 0x8CFA #define GL_COLOR_ATTACHMENT27 0x8CFB #define GL_COLOR_ATTACHMENT28 0x8CFC #define GL_COLOR_ATTACHMENT29 0x8CFD #define GL_COLOR_ATTACHMENT3 0x8CE3 #define GL_COLOR_ATTACHMENT30 0x8CFE #define GL_COLOR_ATTACHMENT31 0x8CFF #define GL_COLOR_ATTACHMENT4 0x8CE4 #define GL_COLOR_ATTACHMENT5 0x8CE5 #define GL_COLOR_ATTACHMENT6 0x8CE6 #define GL_COLOR_ATTACHMENT7 0x8CE7 #define GL_COLOR_ATTACHMENT8 0x8CE8 #define GL_COLOR_ATTACHMENT9 0x8CE9 #define GL_COLOR_BUFFER_BIT 0x00004000 #define GL_COLOR_CLEAR_VALUE 0x0C22 #define GL_COLOR_LOGIC_OP 0x0BF2 #define GL_COLOR_WRITEMASK 0x0C23 #define GL_COMPARE_REF_TO_TEXTURE 0x884E #define GL_COMPATIBLE_SUBROUTINES 0x8E4B #define GL_COMPILE_STATUS 0x8B81 #define GL_COMPRESSED_RED 0x8225 #define GL_COMPRESSED_RED_RGTC1 0x8DBB #define GL_COMPRESSED_RG 0x8226 #define GL_COMPRESSED_RGB 0x84ED #define GL_COMPRESSED_RGBA 0x84EE #define GL_COMPRESSED_RG_RGTC2 0x8DBD #define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC #define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE #define GL_COMPRESSED_SRGB 0x8C48 #define GL_COMPRESSED_SRGB_ALPHA 0x8C49 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 #define GL_CONDITION_SATISFIED 0x911C #define GL_CONSTANT_ALPHA 0x8003 #define GL_CONSTANT_COLOR 0x8001 #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 #define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 #define GL_CONTEXT_FLAGS 0x821E #define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 #define GL_CONTEXT_PROFILE_MASK 0x9126 #define GL_COPY 0x1503 #define GL_COPY_INVERTED 0x150C #define GL_COPY_READ_BUFFER 0x8F36 #define GL_COPY_WRITE_BUFFER 0x8F37 #define GL_CULL_FACE 0x0B44 #define GL_CULL_FACE_MODE 0x0B45 #define GL_CURRENT_PROGRAM 0x8B8D #define GL_CURRENT_QUERY 0x8865 #define GL_CURRENT_VERTEX_ATTRIB 0x8626 #define GL_CW 0x0900 #define GL_DECR 0x1E03 #define GL_DECR_WRAP 0x8508 #define GL_DELETE_STATUS 0x8B80 #define GL_DEPTH 0x1801 #define GL_DEPTH24_STENCIL8 0x88F0 #define GL_DEPTH32F_STENCIL8 0x8CAD #define GL_DEPTH_ATTACHMENT 0x8D00 #define GL_DEPTH_BUFFER_BIT 0x00000100 #define GL_DEPTH_CLAMP 0x864F #define GL_DEPTH_CLEAR_VALUE 0x0B73 #define GL_DEPTH_COMPONENT 0x1902 #define GL_DEPTH_COMPONENT16 0x81A5 #define GL_DEPTH_COMPONENT24 0x81A6 #define GL_DEPTH_COMPONENT32 0x81A7 #define GL_DEPTH_COMPONENT32F 0x8CAC #define GL_DEPTH_FUNC 0x0B74 #define GL_DEPTH_RANGE 0x0B70 #define GL_DEPTH_STENCIL 0x84F9 #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A #define GL_DEPTH_TEST 0x0B71 #define GL_DEPTH_WRITEMASK 0x0B72 #define GL_DITHER 0x0BD0 #define GL_DONT_CARE 0x1100 #define GL_DOUBLE 0x140A #define GL_DOUBLEBUFFER 0x0C32 #define GL_DOUBLE_MAT2 0x8F46 #define GL_DOUBLE_MAT2x3 0x8F49 #define GL_DOUBLE_MAT2x4 0x8F4A #define GL_DOUBLE_MAT3 0x8F47 #define GL_DOUBLE_MAT3x2 0x8F4B #define GL_DOUBLE_MAT3x4 0x8F4C #define GL_DOUBLE_MAT4 0x8F48 #define GL_DOUBLE_MAT4x2 0x8F4D #define GL_DOUBLE_MAT4x3 0x8F4E #define GL_DOUBLE_VEC2 0x8FFC #define GL_DOUBLE_VEC3 0x8FFD #define GL_DOUBLE_VEC4 0x8FFE #define GL_DRAW_BUFFER 0x0C01 #define GL_DRAW_BUFFER0 0x8825 #define GL_DRAW_BUFFER1 0x8826 #define GL_DRAW_BUFFER10 0x882F #define GL_DRAW_BUFFER11 0x8830 #define GL_DRAW_BUFFER12 0x8831 #define GL_DRAW_BUFFER13 0x8832 #define GL_DRAW_BUFFER14 0x8833 #define GL_DRAW_BUFFER15 0x8834 #define GL_DRAW_BUFFER2 0x8827 #define GL_DRAW_BUFFER3 0x8828 #define GL_DRAW_BUFFER4 0x8829 #define GL_DRAW_BUFFER5 0x882A #define GL_DRAW_BUFFER6 0x882B #define GL_DRAW_BUFFER7 0x882C #define GL_DRAW_BUFFER8 0x882D #define GL_DRAW_BUFFER9 0x882E #define GL_DRAW_FRAMEBUFFER 0x8CA9 #define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 #define GL_DRAW_INDIRECT_BUFFER 0x8F3F #define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 #define GL_DST_ALPHA 0x0304 #define GL_DST_COLOR 0x0306 #define GL_DYNAMIC_COPY 0x88EA #define GL_DYNAMIC_DRAW 0x88E8 #define GL_DYNAMIC_READ 0x88E9 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_EQUAL 0x0202 #define GL_EQUIV 0x1509 #define GL_EXTENSIONS 0x1F03 #define GL_FALSE 0 #define GL_FASTEST 0x1101 #define GL_FILL 0x1B02 #define GL_FIRST_VERTEX_CONVENTION 0x8E4D #define GL_FIXED 0x140C #define GL_FIXED_ONLY 0x891D #define GL_FLOAT 0x1406 #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD #define GL_FLOAT_MAT2 0x8B5A #define GL_FLOAT_MAT2x3 0x8B65 #define GL_FLOAT_MAT2x4 0x8B66 #define GL_FLOAT_MAT3 0x8B5B #define GL_FLOAT_MAT3x2 0x8B67 #define GL_FLOAT_MAT3x4 0x8B68 #define GL_FLOAT_MAT4 0x8B5C #define GL_FLOAT_MAT4x2 0x8B69 #define GL_FLOAT_MAT4x3 0x8B6A #define GL_FLOAT_VEC2 0x8B50 #define GL_FLOAT_VEC3 0x8B51 #define GL_FLOAT_VEC4 0x8B52 #define GL_FRACTIONAL_EVEN 0x8E7C #define GL_FRACTIONAL_ODD 0x8E7B #define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D #define GL_FRAGMENT_SHADER 0x8B30 #define GL_FRAGMENT_SHADER_BIT 0x00000002 #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B #define GL_FRAMEBUFFER 0x8D40 #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 #define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 #define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 #define GL_FRAMEBUFFER_BINDING 0x8CA6 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_DEFAULT 0x8218 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC #define GL_FRAMEBUFFER_SRGB 0x8DB9 #define GL_FRAMEBUFFER_UNDEFINED 0x8219 #define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD #define GL_FRONT 0x0404 #define GL_FRONT_AND_BACK 0x0408 #define GL_FRONT_FACE 0x0B46 #define GL_FRONT_LEFT 0x0400 #define GL_FRONT_RIGHT 0x0401 #define GL_FUNC_ADD 0x8006 #define GL_FUNC_REVERSE_SUBTRACT 0x800B #define GL_FUNC_SUBTRACT 0x800A #define GL_GEOMETRY_INPUT_TYPE 0x8917 #define GL_GEOMETRY_OUTPUT_TYPE 0x8918 #define GL_GEOMETRY_SHADER 0x8DD9 #define GL_GEOMETRY_SHADER_BIT 0x00000004 #define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F #define GL_GEOMETRY_VERTICES_OUT 0x8916 #define GL_GEQUAL 0x0206 #define GL_GREATER 0x0204 #define GL_GREEN 0x1904 #define GL_GREEN_INTEGER 0x8D95 #define GL_HALF_FLOAT 0x140B #define GL_HIGH_FLOAT 0x8DF2 #define GL_HIGH_INT 0x8DF5 #define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B #define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A #define GL_INCR 0x1E02 #define GL_INCR_WRAP 0x8507 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_INT 0x1404 #define GL_INTERLEAVED_ATTRIBS 0x8C8C #define GL_INT_2_10_10_10_REV 0x8D9F #define GL_INT_SAMPLER_1D 0x8DC9 #define GL_INT_SAMPLER_1D_ARRAY 0x8DCE #define GL_INT_SAMPLER_2D 0x8DCA #define GL_INT_SAMPLER_2D_ARRAY 0x8DCF #define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 #define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C #define GL_INT_SAMPLER_2D_RECT 0x8DCD #define GL_INT_SAMPLER_3D 0x8DCB #define GL_INT_SAMPLER_BUFFER 0x8DD0 #define GL_INT_SAMPLER_CUBE 0x8DCC #define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E #define GL_INT_VEC2 0x8B53 #define GL_INT_VEC3 0x8B54 #define GL_INT_VEC4 0x8B55 #define GL_INVALID_ENUM 0x0500 #define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 #define GL_INVALID_INDEX 0xFFFFFFFF #define GL_INVALID_OPERATION 0x0502 #define GL_INVALID_VALUE 0x0501 #define GL_INVERT 0x150A #define GL_ISOLINES 0x8E7A #define GL_KEEP 0x1E00 #define GL_LAST_VERTEX_CONVENTION 0x8E4E #define GL_LAYER_PROVOKING_VERTEX 0x825E #define GL_LEFT 0x0406 #define GL_LEQUAL 0x0203 #define GL_LESS 0x0201 #define GL_LINE 0x1B01 #define GL_LINEAR 0x2601 #define GL_LINEAR_MIPMAP_LINEAR 0x2703 #define GL_LINEAR_MIPMAP_NEAREST 0x2701 #define GL_LINES 0x0001 #define GL_LINES_ADJACENCY 0x000A #define GL_LINE_LOOP 0x0002 #define GL_LINE_SMOOTH 0x0B20 #define GL_LINE_SMOOTH_HINT 0x0C52 #define GL_LINE_STRIP 0x0003 #define GL_LINE_STRIP_ADJACENCY 0x000B #define GL_LINE_WIDTH 0x0B21 #define GL_LINE_WIDTH_GRANULARITY 0x0B23 #define GL_LINE_WIDTH_RANGE 0x0B22 #define GL_LINK_STATUS 0x8B82 #define GL_LOGIC_OP_MODE 0x0BF0 #define GL_LOWER_LEFT 0x8CA1 #define GL_LOW_FLOAT 0x8DF0 #define GL_LOW_INT 0x8DF3 #define GL_MAJOR_VERSION 0x821B #define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 #define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 #define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 #define GL_MAP_READ_BIT 0x0001 #define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 #define GL_MAP_WRITE_BIT 0x0002 #define GL_MAX 0x8008 #define GL_MAX_3D_TEXTURE_SIZE 0x8073 #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF #define GL_MAX_CLIP_DISTANCES 0x0D32 #define GL_MAX_COLOR_ATTACHMENTS 0x8CDF #define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E #define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 #define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 #define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E #define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D #define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E #define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C #define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F #define GL_MAX_DRAW_BUFFERS 0x8824 #define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC #define GL_MAX_ELEMENTS_INDICES 0x80E9 #define GL_MAX_ELEMENTS_VERTICES 0x80E8 #define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 #define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C #define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 #define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD #define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 #define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 #define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 #define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 #define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF #define GL_MAX_INTEGER_SAMPLES 0x9110 #define GL_MAX_PATCH_VERTICES 0x8E7D #define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 #define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F #define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 #define GL_MAX_RENDERBUFFER_SIZE 0x84E8 #define GL_MAX_SAMPLES 0x8D57 #define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 #define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 #define GL_MAX_SUBROUTINES 0x8DE7 #define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 #define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C #define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 #define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 #define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 #define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 #define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F #define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D #define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 #define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 #define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A #define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 #define GL_MAX_TESS_GEN_LEVEL 0x8E7E #define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 #define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B #define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 #define GL_MAX_TEXTURE_LOD_BIAS 0x84FD #define GL_MAX_TEXTURE_SIZE 0x0D33 #define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 #define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 #define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F #define GL_MAX_VARYING_COMPONENTS 0x8B4B #define GL_MAX_VARYING_FLOATS 0x8B4B #define GL_MAX_VARYING_VECTORS 0x8DFC #define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 #define GL_MAX_VERTEX_STREAMS 0x8E71 #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B #define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A #define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB #define GL_MAX_VIEWPORTS 0x825B #define GL_MAX_VIEWPORT_DIMS 0x0D3A #define GL_MEDIUM_FLOAT 0x8DF1 #define GL_MEDIUM_INT 0x8DF4 #define GL_MIN 0x8007 #define GL_MINOR_VERSION 0x821C #define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B #define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 #define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E #define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 #define GL_MIRRORED_REPEAT 0x8370 #define GL_MULTISAMPLE 0x809D #define GL_NAND 0x150E #define GL_NEAREST 0x2600 #define GL_NEAREST_MIPMAP_LINEAR 0x2702 #define GL_NEAREST_MIPMAP_NEAREST 0x2700 #define GL_NEVER 0x0200 #define GL_NICEST 0x1102 #define GL_NONE 0 #define GL_NOOP 0x1505 #define GL_NOR 0x1508 #define GL_NOTEQUAL 0x0205 #define GL_NO_ERROR 0 #define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_NUM_EXTENSIONS 0x821D #define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE #define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 #define GL_OBJECT_TYPE 0x9112 #define GL_ONE 1 #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 #define GL_ONE_MINUS_DST_ALPHA 0x0305 #define GL_ONE_MINUS_DST_COLOR 0x0307 #define GL_ONE_MINUS_SRC1_ALPHA 0x88FB #define GL_ONE_MINUS_SRC1_COLOR 0x88FA #define GL_ONE_MINUS_SRC_ALPHA 0x0303 #define GL_ONE_MINUS_SRC_COLOR 0x0301 #define GL_OR 0x1507 #define GL_OR_INVERTED 0x150D #define GL_OR_REVERSE 0x150B #define GL_OUT_OF_MEMORY 0x0505 #define GL_PACK_ALIGNMENT 0x0D05 #define GL_PACK_IMAGE_HEIGHT 0x806C #define GL_PACK_LSB_FIRST 0x0D01 #define GL_PACK_ROW_LENGTH 0x0D02 #define GL_PACK_SKIP_IMAGES 0x806B #define GL_PACK_SKIP_PIXELS 0x0D04 #define GL_PACK_SKIP_ROWS 0x0D03 #define GL_PACK_SWAP_BYTES 0x0D00 #define GL_PATCHES 0x000E #define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 #define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 #define GL_PATCH_VERTICES 0x8E72 #define GL_PIXEL_PACK_BUFFER 0x88EB #define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED #define GL_PIXEL_UNPACK_BUFFER 0x88EC #define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF #define GL_POINT 0x1B00 #define GL_POINTS 0x0000 #define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 #define GL_POINT_SIZE 0x0B11 #define GL_POINT_SIZE_GRANULARITY 0x0B13 #define GL_POINT_SIZE_RANGE 0x0B12 #define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 #define GL_POLYGON_MODE 0x0B40 #define GL_POLYGON_OFFSET_FACTOR 0x8038 #define GL_POLYGON_OFFSET_FILL 0x8037 #define GL_POLYGON_OFFSET_LINE 0x2A02 #define GL_POLYGON_OFFSET_POINT 0x2A01 #define GL_POLYGON_OFFSET_UNITS 0x2A00 #define GL_POLYGON_SMOOTH 0x0B41 #define GL_POLYGON_SMOOTH_HINT 0x0C53 #define GL_PRIMITIVES_GENERATED 0x8C87 #define GL_PRIMITIVE_RESTART 0x8F9D #define GL_PRIMITIVE_RESTART_INDEX 0x8F9E #define GL_PROGRAM_BINARY_FORMATS 0x87FF #define GL_PROGRAM_BINARY_LENGTH 0x8741 #define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 #define GL_PROGRAM_PIPELINE_BINDING 0x825A #define GL_PROGRAM_POINT_SIZE 0x8642 #define GL_PROGRAM_SEPARABLE 0x8258 #define GL_PROVOKING_VERTEX 0x8E4F #define GL_PROXY_TEXTURE_1D 0x8063 #define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 #define GL_PROXY_TEXTURE_2D 0x8064 #define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B #define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 #define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 #define GL_PROXY_TEXTURE_3D 0x8070 #define GL_PROXY_TEXTURE_CUBE_MAP 0x851B #define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B #define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 #define GL_QUADS 0x0007 #define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C #define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 #define GL_QUERY_BY_REGION_WAIT 0x8E15 #define GL_QUERY_COUNTER_BITS 0x8864 #define GL_QUERY_NO_WAIT 0x8E14 #define GL_QUERY_RESULT 0x8866 #define GL_QUERY_RESULT_AVAILABLE 0x8867 #define GL_QUERY_WAIT 0x8E13 #define GL_R11F_G11F_B10F 0x8C3A #define GL_R16 0x822A #define GL_R16F 0x822D #define GL_R16I 0x8233 #define GL_R16UI 0x8234 #define GL_R16_SNORM 0x8F98 #define GL_R32F 0x822E #define GL_R32I 0x8235 #define GL_R32UI 0x8236 #define GL_R3_G3_B2 0x2A10 #define GL_R8 0x8229 #define GL_R8I 0x8231 #define GL_R8UI 0x8232 #define GL_R8_SNORM 0x8F94 #define GL_RASTERIZER_DISCARD 0x8C89 #define GL_READ_BUFFER 0x0C02 #define GL_READ_FRAMEBUFFER 0x8CA8 #define GL_READ_FRAMEBUFFER_BINDING 0x8CAA #define GL_READ_ONLY 0x88B8 #define GL_READ_WRITE 0x88BA #define GL_RED 0x1903 #define GL_RED_INTEGER 0x8D94 #define GL_RENDERBUFFER 0x8D41 #define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 #define GL_RENDERBUFFER_BINDING 0x8CA7 #define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 #define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 #define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 #define GL_RENDERBUFFER_HEIGHT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 #define GL_RENDERBUFFER_RED_SIZE 0x8D50 #define GL_RENDERBUFFER_SAMPLES 0x8CAB #define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_RENDERBUFFER_WIDTH 0x8D42 #define GL_RENDERER 0x1F01 #define GL_REPEAT 0x2901 #define GL_REPLACE 0x1E01 #define GL_RG 0x8227 #define GL_RG16 0x822C #define GL_RG16F 0x822F #define GL_RG16I 0x8239 #define GL_RG16UI 0x823A #define GL_RG16_SNORM 0x8F99 #define GL_RG32F 0x8230 #define GL_RG32I 0x823B #define GL_RG32UI 0x823C #define GL_RG8 0x822B #define GL_RG8I 0x8237 #define GL_RG8UI 0x8238 #define GL_RG8_SNORM 0x8F95 #define GL_RGB 0x1907 #define GL_RGB10 0x8052 #define GL_RGB10_A2 0x8059 #define GL_RGB10_A2UI 0x906F #define GL_RGB12 0x8053 #define GL_RGB16 0x8054 #define GL_RGB16F 0x881B #define GL_RGB16I 0x8D89 #define GL_RGB16UI 0x8D77 #define GL_RGB16_SNORM 0x8F9A #define GL_RGB32F 0x8815 #define GL_RGB32I 0x8D83 #define GL_RGB32UI 0x8D71 #define GL_RGB4 0x804F #define GL_RGB5 0x8050 #define GL_RGB565 0x8D62 #define GL_RGB5_A1 0x8057 #define GL_RGB8 0x8051 #define GL_RGB8I 0x8D8F #define GL_RGB8UI 0x8D7D #define GL_RGB8_SNORM 0x8F96 #define GL_RGB9_E5 0x8C3D #define GL_RGBA 0x1908 #define GL_RGBA12 0x805A #define GL_RGBA16 0x805B #define GL_RGBA16F 0x881A #define GL_RGBA16I 0x8D88 #define GL_RGBA16UI 0x8D76 #define GL_RGBA16_SNORM 0x8F9B #define GL_RGBA2 0x8055 #define GL_RGBA32F 0x8814 #define GL_RGBA32I 0x8D82 #define GL_RGBA32UI 0x8D70 #define GL_RGBA4 0x8056 #define GL_RGBA8 0x8058 #define GL_RGBA8I 0x8D8E #define GL_RGBA8UI 0x8D7C #define GL_RGBA8_SNORM 0x8F97 #define GL_RGBA_INTEGER 0x8D99 #define GL_RGB_INTEGER 0x8D98 #define GL_RG_INTEGER 0x8228 #define GL_RIGHT 0x0407 #define GL_SAMPLER_1D 0x8B5D #define GL_SAMPLER_1D_ARRAY 0x8DC0 #define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 #define GL_SAMPLER_1D_SHADOW 0x8B61 #define GL_SAMPLER_2D 0x8B5E #define GL_SAMPLER_2D_ARRAY 0x8DC1 #define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 #define GL_SAMPLER_2D_MULTISAMPLE 0x9108 #define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B #define GL_SAMPLER_2D_RECT 0x8B63 #define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 #define GL_SAMPLER_2D_SHADOW 0x8B62 #define GL_SAMPLER_3D 0x8B5F #define GL_SAMPLER_BINDING 0x8919 #define GL_SAMPLER_BUFFER 0x8DC2 #define GL_SAMPLER_CUBE 0x8B60 #define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C #define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D #define GL_SAMPLER_CUBE_SHADOW 0x8DC5 #define GL_SAMPLES 0x80A9 #define GL_SAMPLES_PASSED 0x8914 #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_ALPHA_TO_ONE 0x809F #define GL_SAMPLE_BUFFERS 0x80A8 #define GL_SAMPLE_COVERAGE 0x80A0 #define GL_SAMPLE_COVERAGE_INVERT 0x80AB #define GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GL_SAMPLE_MASK 0x8E51 #define GL_SAMPLE_MASK_VALUE 0x8E52 #define GL_SAMPLE_POSITION 0x8E50 #define GL_SAMPLE_SHADING 0x8C36 #define GL_SCISSOR_BOX 0x0C10 #define GL_SCISSOR_TEST 0x0C11 #define GL_SEPARATE_ATTRIBS 0x8C8D #define GL_SET 0x150F #define GL_SHADER_BINARY_FORMATS 0x8DF8 #define GL_SHADER_COMPILER 0x8DFA #define GL_SHADER_SOURCE_LENGTH 0x8B88 #define GL_SHADER_TYPE 0x8B4F #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #define GL_SHORT 0x1402 #define GL_SIGNALED 0x9119 #define GL_SIGNED_NORMALIZED 0x8F9C #define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 #define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 #define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 #define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 #define GL_SRC1_ALPHA 0x8589 #define GL_SRC1_COLOR 0x88F9 #define GL_SRC_ALPHA 0x0302 #define GL_SRC_ALPHA_SATURATE 0x0308 #define GL_SRC_COLOR 0x0300 #define GL_SRGB 0x8C40 #define GL_SRGB8 0x8C41 #define GL_SRGB8_ALPHA8 0x8C43 #define GL_SRGB_ALPHA 0x8C42 #define GL_STATIC_COPY 0x88E6 #define GL_STATIC_DRAW 0x88E4 #define GL_STATIC_READ 0x88E5 #define GL_STENCIL 0x1802 #define GL_STENCIL_ATTACHMENT 0x8D20 #define GL_STENCIL_BACK_FAIL 0x8801 #define GL_STENCIL_BACK_FUNC 0x8800 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 #define GL_STENCIL_BACK_REF 0x8CA3 #define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 #define GL_STENCIL_BACK_WRITEMASK 0x8CA5 #define GL_STENCIL_BUFFER_BIT 0x00000400 #define GL_STENCIL_CLEAR_VALUE 0x0B91 #define GL_STENCIL_FAIL 0x0B94 #define GL_STENCIL_FUNC 0x0B92 #define GL_STENCIL_INDEX 0x1901 #define GL_STENCIL_INDEX1 0x8D46 #define GL_STENCIL_INDEX16 0x8D49 #define GL_STENCIL_INDEX4 0x8D47 #define GL_STENCIL_INDEX8 0x8D48 #define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 #define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 #define GL_STENCIL_REF 0x0B97 #define GL_STENCIL_TEST 0x0B90 #define GL_STENCIL_VALUE_MASK 0x0B93 #define GL_STENCIL_WRITEMASK 0x0B98 #define GL_STEREO 0x0C33 #define GL_STREAM_COPY 0x88E2 #define GL_STREAM_DRAW 0x88E0 #define GL_STREAM_READ 0x88E1 #define GL_SUBPIXEL_BITS 0x0D50 #define GL_SYNC_CONDITION 0x9113 #define GL_SYNC_FENCE 0x9116 #define GL_SYNC_FLAGS 0x9115 #define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 #define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 #define GL_SYNC_STATUS 0x9114 #define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 #define GL_TESS_CONTROL_SHADER 0x8E88 #define GL_TESS_CONTROL_SHADER_BIT 0x00000008 #define GL_TESS_EVALUATION_SHADER 0x8E87 #define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 #define GL_TESS_GEN_MODE 0x8E76 #define GL_TESS_GEN_POINT_MODE 0x8E79 #define GL_TESS_GEN_SPACING 0x8E77 #define GL_TESS_GEN_VERTEX_ORDER 0x8E78 #define GL_TEXTURE 0x1702 #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE_1D 0x0DE0 #define GL_TEXTURE_1D_ARRAY 0x8C18 #define GL_TEXTURE_2D 0x0DE1 #define GL_TEXTURE_2D_ARRAY 0x8C1A #define GL_TEXTURE_2D_MULTISAMPLE 0x9100 #define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 #define GL_TEXTURE_3D 0x806F #define GL_TEXTURE_ALPHA_SIZE 0x805F #define GL_TEXTURE_ALPHA_TYPE 0x8C13 #define GL_TEXTURE_BASE_LEVEL 0x813C #define GL_TEXTURE_BINDING_1D 0x8068 #define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C #define GL_TEXTURE_BINDING_2D 0x8069 #define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D #define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 #define GL_TEXTURE_BINDING_3D 0x806A #define GL_TEXTURE_BINDING_BUFFER 0x8C2C #define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 #define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A #define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 #define GL_TEXTURE_BLUE_SIZE 0x805E #define GL_TEXTURE_BLUE_TYPE 0x8C12 #define GL_TEXTURE_BORDER_COLOR 0x1004 #define GL_TEXTURE_BUFFER 0x8C2A #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D #define GL_TEXTURE_COMPARE_FUNC 0x884D #define GL_TEXTURE_COMPARE_MODE 0x884C #define GL_TEXTURE_COMPRESSED 0x86A1 #define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 #define GL_TEXTURE_COMPRESSION_HINT 0x84EF #define GL_TEXTURE_CUBE_MAP 0x8513 #define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 #define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F #define GL_TEXTURE_DEPTH 0x8071 #define GL_TEXTURE_DEPTH_SIZE 0x884A #define GL_TEXTURE_DEPTH_TYPE 0x8C16 #define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 #define GL_TEXTURE_GREEN_SIZE 0x805D #define GL_TEXTURE_GREEN_TYPE 0x8C11 #define GL_TEXTURE_HEIGHT 0x1001 #define GL_TEXTURE_INTERNAL_FORMAT 0x1003 #define GL_TEXTURE_LOD_BIAS 0x8501 #define GL_TEXTURE_MAG_FILTER 0x2800 #define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_TEXTURE_MAX_LOD 0x813B #define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_MIN_LOD 0x813A #define GL_TEXTURE_RECTANGLE 0x84F5 #define GL_TEXTURE_RED_SIZE 0x805C #define GL_TEXTURE_RED_TYPE 0x8C10 #define GL_TEXTURE_SAMPLES 0x9106 #define GL_TEXTURE_SHARED_SIZE 0x8C3F #define GL_TEXTURE_STENCIL_SIZE 0x88F1 #define GL_TEXTURE_SWIZZLE_A 0x8E45 #define GL_TEXTURE_SWIZZLE_B 0x8E44 #define GL_TEXTURE_SWIZZLE_G 0x8E43 #define GL_TEXTURE_SWIZZLE_R 0x8E42 #define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 #define GL_TEXTURE_WIDTH 0x1000 #define GL_TEXTURE_WRAP_R 0x8072 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 #define GL_TIMEOUT_EXPIRED 0x911B #define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF #define GL_TIMESTAMP 0x8E28 #define GL_TIME_ELAPSED 0x88BF #define GL_TRANSFORM_FEEDBACK 0x8E22 #define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 #define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F #define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 #define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 #define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 #define GL_TRIANGLES 0x0004 #define GL_TRIANGLES_ADJACENCY 0x000C #define GL_TRIANGLE_FAN 0x0006 #define GL_TRIANGLE_STRIP 0x0005 #define GL_TRIANGLE_STRIP_ADJACENCY 0x000D #define GL_TRUE 1 #define GL_UNDEFINED_VERTEX 0x8260 #define GL_UNIFORM_ARRAY_STRIDE 0x8A3C #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 #define GL_UNIFORM_BLOCK_BINDING 0x8A3F #define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 #define GL_UNIFORM_BLOCK_INDEX 0x8A3A #define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 #define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 #define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 #define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 #define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 #define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 #define GL_UNIFORM_BUFFER 0x8A11 #define GL_UNIFORM_BUFFER_BINDING 0x8A28 #define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 #define GL_UNIFORM_BUFFER_SIZE 0x8A2A #define GL_UNIFORM_BUFFER_START 0x8A29 #define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E #define GL_UNIFORM_MATRIX_STRIDE 0x8A3D #define GL_UNIFORM_NAME_LENGTH 0x8A39 #define GL_UNIFORM_OFFSET 0x8A3B #define GL_UNIFORM_SIZE 0x8A38 #define GL_UNIFORM_TYPE 0x8A37 #define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_UNPACK_IMAGE_HEIGHT 0x806E #define GL_UNPACK_LSB_FIRST 0x0CF1 #define GL_UNPACK_ROW_LENGTH 0x0CF2 #define GL_UNPACK_SKIP_IMAGES 0x806D #define GL_UNPACK_SKIP_PIXELS 0x0CF4 #define GL_UNPACK_SKIP_ROWS 0x0CF3 #define GL_UNPACK_SWAP_BYTES 0x0CF0 #define GL_UNSIGNALED 0x9118 #define GL_UNSIGNED_BYTE 0x1401 #define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 #define GL_UNSIGNED_BYTE_3_3_2 0x8032 #define GL_UNSIGNED_INT 0x1405 #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B #define GL_UNSIGNED_INT_10_10_10_2 0x8036 #define GL_UNSIGNED_INT_24_8 0x84FA #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 #define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E #define GL_UNSIGNED_INT_8_8_8_8 0x8035 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 #define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 #define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 #define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D #define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 #define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 #define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 #define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 #define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F #define GL_UNSIGNED_INT_VEC2 0x8DC6 #define GL_UNSIGNED_INT_VEC3 0x8DC7 #define GL_UNSIGNED_INT_VEC4 0x8DC8 #define GL_UNSIGNED_NORMALIZED 0x8C17 #define GL_UNSIGNED_SHORT 0x1403 #define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 #define GL_UPPER_LEFT 0x8CA2 #define GL_VALIDATE_STATUS 0x8B83 #define GL_VENDOR 0x1F00 #define GL_VERSION 0x1F02 #define GL_VERTEX_ARRAY_BINDING 0x85B5 #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE #define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A #define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 #define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 #define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 #define GL_VERTEX_SHADER 0x8B31 #define GL_VERTEX_SHADER_BIT 0x00000001 #define GL_VIEWPORT 0x0BA2 #define GL_VIEWPORT_BOUNDS_RANGE 0x825D #define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F #define GL_VIEWPORT_SUBPIXEL_BITS 0x825C #define GL_WAIT_FAILED 0x911D #define GL_WRITE_ONLY 0x88B9 #define GL_XOR 0x1506 #define GL_ZERO 0 #include typedef unsigned int GLenum; typedef unsigned char GLboolean; typedef unsigned int GLbitfield; typedef void GLvoid; typedef khronos_int8_t GLbyte; typedef khronos_uint8_t GLubyte; typedef khronos_int16_t GLshort; typedef khronos_uint16_t GLushort; typedef int GLint; typedef unsigned int GLuint; typedef khronos_int32_t GLclampx; typedef int GLsizei; typedef khronos_float_t GLfloat; typedef khronos_float_t GLclampf; typedef double GLdouble; typedef double GLclampd; typedef void *GLeglClientBufferEXT; typedef void *GLeglImageOES; typedef char GLchar; typedef char GLcharARB; #ifdef __APPLE__ typedef void *GLhandleARB; #else typedef unsigned int GLhandleARB; #endif typedef khronos_uint16_t GLhalf; typedef khronos_uint16_t GLhalfARB; typedef khronos_int32_t GLfixed; #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) typedef khronos_intptr_t GLintptr; #else typedef khronos_intptr_t GLintptr; #endif #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) typedef khronos_intptr_t GLintptrARB; #else typedef khronos_intptr_t GLintptrARB; #endif #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) typedef khronos_ssize_t GLsizeiptr; #else typedef khronos_ssize_t GLsizeiptr; #endif #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) typedef khronos_ssize_t GLsizeiptrARB; #else typedef khronos_ssize_t GLsizeiptrARB; #endif typedef khronos_int64_t GLint64; typedef khronos_int64_t GLint64EXT; typedef khronos_uint64_t GLuint64; typedef khronos_uint64_t GLuint64EXT; typedef struct __GLsync *GLsync; struct _cl_context; struct _cl_event; typedef void (GLAD_API_PTR *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); typedef void (GLAD_API_PTR *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); typedef void (GLAD_API_PTR *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); typedef void (GLAD_API_PTR *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); typedef unsigned short GLhalfNV; typedef GLintptr GLvdpauSurfaceNV; typedef void (GLAD_API_PTR *GLVULKANPROCNV)(void); #define GL_VERSION_1_0 1 GLAD_API_CALL int GLAD_GL_VERSION_1_0; #define GL_VERSION_1_1 1 GLAD_API_CALL int GLAD_GL_VERSION_1_1; #define GL_VERSION_1_2 1 GLAD_API_CALL int GLAD_GL_VERSION_1_2; #define GL_VERSION_1_3 1 GLAD_API_CALL int GLAD_GL_VERSION_1_3; #define GL_VERSION_1_4 1 GLAD_API_CALL int GLAD_GL_VERSION_1_4; #define GL_VERSION_1_5 1 GLAD_API_CALL int GLAD_GL_VERSION_1_5; #define GL_VERSION_2_0 1 GLAD_API_CALL int GLAD_GL_VERSION_2_0; #define GL_VERSION_2_1 1 GLAD_API_CALL int GLAD_GL_VERSION_2_1; #define GL_VERSION_3_0 1 GLAD_API_CALL int GLAD_GL_VERSION_3_0; #define GL_VERSION_3_1 1 GLAD_API_CALL int GLAD_GL_VERSION_3_1; #define GL_VERSION_3_2 1 GLAD_API_CALL int GLAD_GL_VERSION_3_2; #define GL_VERSION_3_3 1 GLAD_API_CALL int GLAD_GL_VERSION_3_3; #define GL_VERSION_4_0 1 GLAD_API_CALL int GLAD_GL_VERSION_4_0; #define GL_VERSION_4_1 1 GLAD_API_CALL int GLAD_GL_VERSION_4_1; typedef void (GLAD_API_PTR *PFNGLACTIVESHADERPROGRAMPROC)(GLuint pipeline, GLuint program); typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREPROC)(GLenum texture); typedef void (GLAD_API_PTR *PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); typedef void (GLAD_API_PTR *PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); typedef void (GLAD_API_PTR *PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); typedef void (GLAD_API_PTR *PFNGLBEGINQUERYINDEXEDPROC)(GLenum target, GLuint index, GLuint id); typedef void (GLAD_API_PTR *PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar * name); typedef void (GLAD_API_PTR *PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); typedef void (GLAD_API_PTR *PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); typedef void (GLAD_API_PTR *PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar * name); typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar * name); typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); typedef void (GLAD_API_PTR *PFNGLBINDPROGRAMPIPELINEPROC)(GLuint pipeline); typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); typedef void (GLAD_API_PTR *PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler); typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); typedef void (GLAD_API_PTR *PFNGLBINDTRANSFORMFEEDBACKPROC)(GLenum target, GLuint id); typedef void (GLAD_API_PTR *PFNGLBINDVERTEXARRAYPROC)(GLuint array); typedef void (GLAD_API_PTR *PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONPROC)(GLenum mode); typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEIPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha); typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONIPROC)(GLuint buf, GLenum mode); typedef void (GLAD_API_PTR *PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEIPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); typedef void (GLAD_API_PTR *PFNGLBLENDFUNCIPROC)(GLuint buf, GLenum src, GLenum dst); typedef void (GLAD_API_PTR *PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); typedef void (GLAD_API_PTR *PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void * data, GLenum usage); typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data); typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); typedef void (GLAD_API_PTR *PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); typedef void (GLAD_API_PTR *PFNGLCLEARPROC)(GLbitfield mask); typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint * value); typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHPROC)(GLdouble depth); typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHFPROC)(GLfloat d); typedef void (GLAD_API_PTR *PFNGLCLEARSTENCILPROC)(GLint s); typedef GLenum (GLAD_API_PTR *PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (GLAD_API_PTR *PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); typedef void (GLAD_API_PTR *PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERPROC)(GLuint shader); typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void * data); typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data); typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data); typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void * data); typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data); typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void * data); typedef void (GLAD_API_PTR *PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef GLuint (GLAD_API_PTR *PFNGLCREATEPROGRAMPROC)(void); typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROC)(GLenum type); typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROGRAMVPROC)(GLenum type, GLsizei count, const GLchar *const* strings); typedef void (GLAD_API_PTR *PFNGLCULLFACEPROC)(GLenum mode); typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint * buffers); typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint * framebuffers); typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPROC)(GLuint program); typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPIPELINESPROC)(GLsizei n, const GLuint * pipelines); typedef void (GLAD_API_PTR *PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint * ids); typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint * renderbuffers); typedef void (GLAD_API_PTR *PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint * samplers); typedef void (GLAD_API_PTR *PFNGLDELETESHADERPROC)(GLuint shader); typedef void (GLAD_API_PTR *PFNGLDELETESYNCPROC)(GLsync sync); typedef void (GLAD_API_PTR *PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint * textures); typedef void (GLAD_API_PTR *PFNGLDELETETRANSFORMFEEDBACKSPROC)(GLsizei n, const GLuint * ids); typedef void (GLAD_API_PTR *PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint * arrays); typedef void (GLAD_API_PTR *PFNGLDEPTHFUNCPROC)(GLenum func); typedef void (GLAD_API_PTR *PFNGLDEPTHMASKPROC)(GLboolean flag); typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f); typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEARRAYVPROC)(GLuint first, GLsizei count, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEINDEXEDPROC)(GLuint index, GLdouble n, GLdouble f); typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f); typedef void (GLAD_API_PTR *PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); typedef void (GLAD_API_PTR *PFNGLDISABLEPROC)(GLenum cap); typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); typedef void (GLAD_API_PTR *PFNGLDISABLEIPROC)(GLenum target, GLuint index); typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINDIRECTPROC)(GLenum mode, const void * indirect); typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERPROC)(GLenum buf); typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum * bufs); typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices); typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex); typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void * indirect); typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount); typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex); typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices); typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex); typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKPROC)(GLenum mode, GLuint id); typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)(GLenum mode, GLuint id, GLuint stream); typedef void (GLAD_API_PTR *PFNGLENABLEPROC)(GLenum cap); typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); typedef void (GLAD_API_PTR *PFNGLENABLEIPROC)(GLenum target, GLuint index); typedef void (GLAD_API_PTR *PFNGLENDCONDITIONALRENDERPROC)(void); typedef void (GLAD_API_PTR *PFNGLENDQUERYPROC)(GLenum target); typedef void (GLAD_API_PTR *PFNGLENDQUERYINDEXEDPROC)(GLenum target, GLuint index); typedef void (GLAD_API_PTR *PFNGLENDTRANSFORMFEEDBACKPROC)(void); typedef GLsync (GLAD_API_PTR *PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); typedef void (GLAD_API_PTR *PFNGLFINISHPROC)(void); typedef void (GLAD_API_PTR *PFNGLFLUSHPROC)(void); typedef void (GLAD_API_PTR *PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void (GLAD_API_PTR *PFNGLFRONTFACEPROC)(GLenum mode); typedef void (GLAD_API_PTR *PFNGLGENBUFFERSPROC)(GLsizei n, GLuint * buffers); typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint * framebuffers); typedef void (GLAD_API_PTR *PFNGLGENPROGRAMPIPELINESPROC)(GLsizei n, GLuint * pipelines); typedef void (GLAD_API_PTR *PFNGLGENQUERIESPROC)(GLsizei n, GLuint * ids); typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint * renderbuffers); typedef void (GLAD_API_PTR *PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint * samplers); typedef void (GLAD_API_PTR *PFNGLGENTEXTURESPROC)(GLsizei n, GLuint * textures); typedef void (GLAD_API_PTR *PFNGLGENTRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint * ids); typedef void (GLAD_API_PTR *PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint * arrays); typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPPROC)(GLenum target); typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); typedef void (GLAD_API_PTR *PFNGLGETACTIVESUBROUTINENAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei * length, GLchar * name); typedef void (GLAD_API_PTR *PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei * length, GLchar * name); typedef void (GLAD_API_PTR *PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)(GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint * values); typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei * length, GLchar * uniformBlockName); typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei * length, GLchar * uniformName); typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint * uniformIndices, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei * count, GLuint * shaders); typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar * name); typedef void (GLAD_API_PTR *PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean * data); typedef void (GLAD_API_PTR *PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean * data); typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 * params); typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void ** params); typedef void (GLAD_API_PTR *PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void * data); typedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void * img); typedef void (GLAD_API_PTR *PFNGLGETDOUBLEI_VPROC)(GLenum target, GLuint index, GLdouble * data); typedef void (GLAD_API_PTR *PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble * data); typedef GLenum (GLAD_API_PTR *PFNGLGETERRORPROC)(void); typedef void (GLAD_API_PTR *PFNGLGETFLOATI_VPROC)(GLenum target, GLuint index, GLfloat * data); typedef void (GLAD_API_PTR *PFNGLGETFLOATVPROC)(GLenum pname, GLfloat * data); typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar * name); typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar * name); typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 * data); typedef void (GLAD_API_PTR *PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 * data); typedef void (GLAD_API_PTR *PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint * data); typedef void (GLAD_API_PTR *PFNGLGETINTEGERVPROC)(GLenum pname, GLint * data); typedef void (GLAD_API_PTR *PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat * val); typedef void (GLAD_API_PTR *PFNGLGETPROGRAMBINARYPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLenum * binaryFormat, void * binary); typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog); typedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEINFOLOGPROC)(GLuint pipeline, GLsizei bufSize, GLsizei * length, GLchar * infoLog); typedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEIVPROC)(GLuint pipeline, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETPROGRAMSTAGEIVPROC)(GLuint program, GLenum shadertype, GLenum pname, GLint * values); typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETQUERYINDEXEDIVPROC)(GLenum target, GLuint index, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 * params); typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 * params); typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint * params); typedef void (GLAD_API_PTR *PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint * params); typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat * params); typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog); typedef void (GLAD_API_PTR *PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint * range, GLint * precision); typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * source); typedef void (GLAD_API_PTR *PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint * params); typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGPROC)(GLenum name); typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); typedef GLuint (GLAD_API_PTR *PFNGLGETSUBROUTINEINDEXPROC)(GLuint program, GLenum shadertype, const GLchar * name); typedef GLint (GLAD_API_PTR *PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)(GLuint program, GLenum shadertype, const GLchar * name); typedef void (GLAD_API_PTR *PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei count, GLsizei * length, GLint * values); typedef void (GLAD_API_PTR *PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void * pixels); typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat * params); typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint * params); typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat * params); typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLsizei * size, GLenum * type, GLchar * name); typedef GLuint (GLAD_API_PTR *PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar * uniformBlockName); typedef void (GLAD_API_PTR *PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const* uniformNames, GLuint * uniformIndices); typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar * name); typedef void (GLAD_API_PTR *PFNGLGETUNIFORMSUBROUTINEUIVPROC)(GLenum shadertype, GLint location, GLuint * params); typedef void (GLAD_API_PTR *PFNGLGETUNIFORMDVPROC)(GLuint program, GLint location, GLdouble * params); typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat * params); typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint * params); typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint * params); typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBLDVPROC)(GLuint index, GLenum pname, GLdouble * params); typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void ** pointer); typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble * params); typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat * params); typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLHINTPROC)(GLenum target, GLenum mode); typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERPROC)(GLuint buffer); typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDPROC)(GLenum cap); typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDIPROC)(GLenum target, GLuint index); typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPROC)(GLuint program); typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPIPELINEPROC)(GLuint pipeline); typedef GLboolean (GLAD_API_PTR *PFNGLISQUERYPROC)(GLuint id); typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); typedef GLboolean (GLAD_API_PTR *PFNGLISSAMPLERPROC)(GLuint sampler); typedef GLboolean (GLAD_API_PTR *PFNGLISSHADERPROC)(GLuint shader); typedef GLboolean (GLAD_API_PTR *PFNGLISSYNCPROC)(GLsync sync); typedef GLboolean (GLAD_API_PTR *PFNGLISTEXTUREPROC)(GLuint texture); typedef GLboolean (GLAD_API_PTR *PFNGLISTRANSFORMFEEDBACKPROC)(GLuint id); typedef GLboolean (GLAD_API_PTR *PFNGLISVERTEXARRAYPROC)(GLuint array); typedef void (GLAD_API_PTR *PFNGLLINEWIDTHPROC)(GLfloat width); typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMPROC)(GLuint program); typedef void (GLAD_API_PTR *PFNGLLOGICOPPROC)(GLenum opcode); typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); typedef void (GLAD_API_PTR *PFNGLMINSAMPLESHADINGPROC)(GLfloat value); typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint * first, const GLsizei * count, GLsizei drawcount); typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount); typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount, const GLint * basevertex); typedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERFVPROC)(GLenum pname, const GLfloat * values); typedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERIPROC)(GLenum pname, GLint value); typedef void (GLAD_API_PTR *PFNGLPAUSETRANSFORMFEEDBACKPROC)(void); typedef void (GLAD_API_PTR *PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); typedef void (GLAD_API_PTR *PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat * params); typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint * params); typedef void (GLAD_API_PTR *PFNGLPOINTSIZEPROC)(GLfloat size); typedef void (GLAD_API_PTR *PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); typedef void (GLAD_API_PTR *PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index); typedef void (GLAD_API_PTR *PFNGLPROGRAMBINARYPROC)(GLuint program, GLenum binaryFormat, const void * binary, GLsizei length); typedef void (GLAD_API_PTR *PFNGLPROGRAMPARAMETERIPROC)(GLuint program, GLenum pname, GLint value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1DPROC)(GLuint program, GLint location, GLdouble v0); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FPROC)(GLuint program, GLint location, GLfloat v0); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IPROC)(GLuint program, GLint location, GLint v0); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIPROC)(GLuint program, GLint location, GLuint v0); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IPROC)(GLuint program, GLint location, GLint v0, GLint v1); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLPROVOKINGVERTEXPROC)(GLenum mode); typedef void (GLAD_API_PTR *PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target); typedef void (GLAD_API_PTR *PFNGLREADBUFFERPROC)(GLenum src); typedef void (GLAD_API_PTR *PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels); typedef void (GLAD_API_PTR *PFNGLRELEASESHADERCOMPILERPROC)(void); typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GLAD_API_PTR *PFNGLRESUMETRANSFORMFEEDBACKPROC)(void); typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); typedef void (GLAD_API_PTR *PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint * param); typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint * param); typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param); typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat * param); typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param); typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint * param); typedef void (GLAD_API_PTR *PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GLAD_API_PTR *PFNGLSCISSORARRAYVPROC)(GLuint first, GLsizei count, const GLint * v); typedef void (GLAD_API_PTR *PFNGLSCISSORINDEXEDPROC)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); typedef void (GLAD_API_PTR *PFNGLSCISSORINDEXEDVPROC)(GLuint index, const GLint * v); typedef void (GLAD_API_PTR *PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint * shaders, GLenum binaryFormat, const void * binary, GLsizei length); typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length); typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); typedef void (GLAD_API_PTR *PFNGLSTENCILMASKPROC)(GLuint mask); typedef void (GLAD_API_PTR *PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); typedef void (GLAD_API_PTR *PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); typedef void (GLAD_API_PTR *PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (GLAD_API_PTR *PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer); typedef void (GLAD_API_PTR *PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void * pixels); typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels); typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels); typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint * params); typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint * params); typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat * params); typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint * params); typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void * pixels); typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels); typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels); typedef void (GLAD_API_PTR *PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const* varyings, GLenum bufferMode); typedef void (GLAD_API_PTR *PFNGLUNIFORM1DPROC)(GLint location, GLdouble x); typedef void (GLAD_API_PTR *PFNGLUNIFORM1DVPROC)(GLint location, GLsizei count, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM1IPROC)(GLint location, GLint v0); typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM2DPROC)(GLint location, GLdouble x, GLdouble y); typedef void (GLAD_API_PTR *PFNGLUNIFORM2DVPROC)(GLint location, GLsizei count, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM3DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z); typedef void (GLAD_API_PTR *PFNGLUNIFORM3DVPROC)(GLint location, GLsizei count, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM4DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (GLAD_API_PTR *PFNGLUNIFORM4DVPROC)(GLint location, GLsizei count, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMSUBROUTINESUIVPROC)(GLenum shadertype, GLsizei count, const GLuint * indices); typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFERPROC)(GLenum target); typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMPROC)(GLuint program); typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMSTAGESPROC)(GLuint pipeline, GLbitfield stages, GLuint program); typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPROC)(GLuint program); typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPIPELINEPROC)(GLuint pipeline); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL1DPROC)(GLuint index, GLdouble x); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL1DVPROC)(GLuint index, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL2DPROC)(GLuint index, GLdouble x, GLdouble y); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL2DVPROC)(GLuint index, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL3DVPROC)(GLuint index, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL4DVPROC)(GLuint index, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBLPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer); typedef void (GLAD_API_PTR *PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GLAD_API_PTR *PFNGLVIEWPORTARRAYVPROC)(GLuint first, GLsizei count, const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLVIEWPORTINDEXEDFPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); typedef void (GLAD_API_PTR *PFNGLVIEWPORTINDEXEDFVPROC)(GLuint index, const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); GLAD_API_CALL PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram; #define glActiveShaderProgram glad_glActiveShaderProgram GLAD_API_CALL PFNGLACTIVETEXTUREPROC glad_glActiveTexture; #define glActiveTexture glad_glActiveTexture GLAD_API_CALL PFNGLATTACHSHADERPROC glad_glAttachShader; #define glAttachShader glad_glAttachShader GLAD_API_CALL PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; #define glBeginConditionalRender glad_glBeginConditionalRender GLAD_API_CALL PFNGLBEGINQUERYPROC glad_glBeginQuery; #define glBeginQuery glad_glBeginQuery GLAD_API_CALL PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed; #define glBeginQueryIndexed glad_glBeginQueryIndexed GLAD_API_CALL PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; #define glBeginTransformFeedback glad_glBeginTransformFeedback GLAD_API_CALL PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; #define glBindAttribLocation glad_glBindAttribLocation GLAD_API_CALL PFNGLBINDBUFFERPROC glad_glBindBuffer; #define glBindBuffer glad_glBindBuffer GLAD_API_CALL PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; #define glBindBufferBase glad_glBindBufferBase GLAD_API_CALL PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; #define glBindBufferRange glad_glBindBufferRange GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; #define glBindFragDataLocation glad_glBindFragDataLocation GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed; #define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed GLAD_API_CALL PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; #define glBindFramebuffer glad_glBindFramebuffer GLAD_API_CALL PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline; #define glBindProgramPipeline glad_glBindProgramPipeline GLAD_API_CALL PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; #define glBindRenderbuffer glad_glBindRenderbuffer GLAD_API_CALL PFNGLBINDSAMPLERPROC glad_glBindSampler; #define glBindSampler glad_glBindSampler GLAD_API_CALL PFNGLBINDTEXTUREPROC glad_glBindTexture; #define glBindTexture glad_glBindTexture GLAD_API_CALL PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback; #define glBindTransformFeedback glad_glBindTransformFeedback GLAD_API_CALL PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; #define glBindVertexArray glad_glBindVertexArray GLAD_API_CALL PFNGLBLENDCOLORPROC glad_glBlendColor; #define glBlendColor glad_glBlendColor GLAD_API_CALL PFNGLBLENDEQUATIONPROC glad_glBlendEquation; #define glBlendEquation glad_glBlendEquation GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; #define glBlendEquationSeparate glad_glBlendEquationSeparate GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei; #define glBlendEquationSeparatei glad_glBlendEquationSeparatei GLAD_API_CALL PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi; #define glBlendEquationi glad_glBlendEquationi GLAD_API_CALL PFNGLBLENDFUNCPROC glad_glBlendFunc; #define glBlendFunc glad_glBlendFunc GLAD_API_CALL PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; #define glBlendFuncSeparate glad_glBlendFuncSeparate GLAD_API_CALL PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei; #define glBlendFuncSeparatei glad_glBlendFuncSeparatei GLAD_API_CALL PFNGLBLENDFUNCIPROC glad_glBlendFunci; #define glBlendFunci glad_glBlendFunci GLAD_API_CALL PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; #define glBlitFramebuffer glad_glBlitFramebuffer GLAD_API_CALL PFNGLBUFFERDATAPROC glad_glBufferData; #define glBufferData glad_glBufferData GLAD_API_CALL PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; #define glBufferSubData glad_glBufferSubData GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; #define glCheckFramebufferStatus glad_glCheckFramebufferStatus GLAD_API_CALL PFNGLCLAMPCOLORPROC glad_glClampColor; #define glClampColor glad_glClampColor GLAD_API_CALL PFNGLCLEARPROC glad_glClear; #define glClear glad_glClear GLAD_API_CALL PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; #define glClearBufferfi glad_glClearBufferfi GLAD_API_CALL PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; #define glClearBufferfv glad_glClearBufferfv GLAD_API_CALL PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; #define glClearBufferiv glad_glClearBufferiv GLAD_API_CALL PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; #define glClearBufferuiv glad_glClearBufferuiv GLAD_API_CALL PFNGLCLEARCOLORPROC glad_glClearColor; #define glClearColor glad_glClearColor GLAD_API_CALL PFNGLCLEARDEPTHPROC glad_glClearDepth; #define glClearDepth glad_glClearDepth GLAD_API_CALL PFNGLCLEARDEPTHFPROC glad_glClearDepthf; #define glClearDepthf glad_glClearDepthf GLAD_API_CALL PFNGLCLEARSTENCILPROC glad_glClearStencil; #define glClearStencil glad_glClearStencil GLAD_API_CALL PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; #define glClientWaitSync glad_glClientWaitSync GLAD_API_CALL PFNGLCOLORMASKPROC glad_glColorMask; #define glColorMask glad_glColorMask GLAD_API_CALL PFNGLCOLORMASKIPROC glad_glColorMaski; #define glColorMaski glad_glColorMaski GLAD_API_CALL PFNGLCOMPILESHADERPROC glad_glCompileShader; #define glCompileShader glad_glCompileShader GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; #define glCompressedTexImage1D glad_glCompressedTexImage1D GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; #define glCompressedTexImage2D glad_glCompressedTexImage2D GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; #define glCompressedTexImage3D glad_glCompressedTexImage3D GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; #define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; #define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; #define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D GLAD_API_CALL PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; #define glCopyBufferSubData glad_glCopyBufferSubData GLAD_API_CALL PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; #define glCopyTexImage1D glad_glCopyTexImage1D GLAD_API_CALL PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; #define glCopyTexImage2D glad_glCopyTexImage2D GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; #define glCopyTexSubImage1D glad_glCopyTexSubImage1D GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; #define glCopyTexSubImage2D glad_glCopyTexSubImage2D GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; #define glCopyTexSubImage3D glad_glCopyTexSubImage3D GLAD_API_CALL PFNGLCREATEPROGRAMPROC glad_glCreateProgram; #define glCreateProgram glad_glCreateProgram GLAD_API_CALL PFNGLCREATESHADERPROC glad_glCreateShader; #define glCreateShader glad_glCreateShader GLAD_API_CALL PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv; #define glCreateShaderProgramv glad_glCreateShaderProgramv GLAD_API_CALL PFNGLCULLFACEPROC glad_glCullFace; #define glCullFace glad_glCullFace GLAD_API_CALL PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; #define glDeleteBuffers glad_glDeleteBuffers GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; #define glDeleteFramebuffers glad_glDeleteFramebuffers GLAD_API_CALL PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; #define glDeleteProgram glad_glDeleteProgram GLAD_API_CALL PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines; #define glDeleteProgramPipelines glad_glDeleteProgramPipelines GLAD_API_CALL PFNGLDELETEQUERIESPROC glad_glDeleteQueries; #define glDeleteQueries glad_glDeleteQueries GLAD_API_CALL PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; #define glDeleteRenderbuffers glad_glDeleteRenderbuffers GLAD_API_CALL PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers; #define glDeleteSamplers glad_glDeleteSamplers GLAD_API_CALL PFNGLDELETESHADERPROC glad_glDeleteShader; #define glDeleteShader glad_glDeleteShader GLAD_API_CALL PFNGLDELETESYNCPROC glad_glDeleteSync; #define glDeleteSync glad_glDeleteSync GLAD_API_CALL PFNGLDELETETEXTURESPROC glad_glDeleteTextures; #define glDeleteTextures glad_glDeleteTextures GLAD_API_CALL PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks; #define glDeleteTransformFeedbacks glad_glDeleteTransformFeedbacks GLAD_API_CALL PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; #define glDeleteVertexArrays glad_glDeleteVertexArrays GLAD_API_CALL PFNGLDEPTHFUNCPROC glad_glDepthFunc; #define glDepthFunc glad_glDepthFunc GLAD_API_CALL PFNGLDEPTHMASKPROC glad_glDepthMask; #define glDepthMask glad_glDepthMask GLAD_API_CALL PFNGLDEPTHRANGEPROC glad_glDepthRange; #define glDepthRange glad_glDepthRange GLAD_API_CALL PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv; #define glDepthRangeArrayv glad_glDepthRangeArrayv GLAD_API_CALL PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed; #define glDepthRangeIndexed glad_glDepthRangeIndexed GLAD_API_CALL PFNGLDEPTHRANGEFPROC glad_glDepthRangef; #define glDepthRangef glad_glDepthRangef GLAD_API_CALL PFNGLDETACHSHADERPROC glad_glDetachShader; #define glDetachShader glad_glDetachShader GLAD_API_CALL PFNGLDISABLEPROC glad_glDisable; #define glDisable glad_glDisable GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; #define glDisableVertexAttribArray glad_glDisableVertexAttribArray GLAD_API_CALL PFNGLDISABLEIPROC glad_glDisablei; #define glDisablei glad_glDisablei GLAD_API_CALL PFNGLDRAWARRAYSPROC glad_glDrawArrays; #define glDrawArrays glad_glDrawArrays GLAD_API_CALL PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect; #define glDrawArraysIndirect glad_glDrawArraysIndirect GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; #define glDrawArraysInstanced glad_glDrawArraysInstanced GLAD_API_CALL PFNGLDRAWBUFFERPROC glad_glDrawBuffer; #define glDrawBuffer glad_glDrawBuffer GLAD_API_CALL PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; #define glDrawBuffers glad_glDrawBuffers GLAD_API_CALL PFNGLDRAWELEMENTSPROC glad_glDrawElements; #define glDrawElements glad_glDrawElements GLAD_API_CALL PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; #define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex GLAD_API_CALL PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect; #define glDrawElementsIndirect glad_glDrawElementsIndirect GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; #define glDrawElementsInstanced glad_glDrawElementsInstanced GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; #define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex GLAD_API_CALL PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; #define glDrawRangeElements glad_glDrawRangeElements GLAD_API_CALL PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; #define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback; #define glDrawTransformFeedback glad_glDrawTransformFeedback GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream; #define glDrawTransformFeedbackStream glad_glDrawTransformFeedbackStream GLAD_API_CALL PFNGLENABLEPROC glad_glEnable; #define glEnable glad_glEnable GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; #define glEnableVertexAttribArray glad_glEnableVertexAttribArray GLAD_API_CALL PFNGLENABLEIPROC glad_glEnablei; #define glEnablei glad_glEnablei GLAD_API_CALL PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; #define glEndConditionalRender glad_glEndConditionalRender GLAD_API_CALL PFNGLENDQUERYPROC glad_glEndQuery; #define glEndQuery glad_glEndQuery GLAD_API_CALL PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed; #define glEndQueryIndexed glad_glEndQueryIndexed GLAD_API_CALL PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; #define glEndTransformFeedback glad_glEndTransformFeedback GLAD_API_CALL PFNGLFENCESYNCPROC glad_glFenceSync; #define glFenceSync glad_glFenceSync GLAD_API_CALL PFNGLFINISHPROC glad_glFinish; #define glFinish glad_glFinish GLAD_API_CALL PFNGLFLUSHPROC glad_glFlush; #define glFlush glad_glFlush GLAD_API_CALL PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; #define glFlushMappedBufferRange glad_glFlushMappedBufferRange GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; #define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; #define glFramebufferTexture glad_glFramebufferTexture GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; #define glFramebufferTexture1D glad_glFramebufferTexture1D GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; #define glFramebufferTexture2D glad_glFramebufferTexture2D GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; #define glFramebufferTexture3D glad_glFramebufferTexture3D GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; #define glFramebufferTextureLayer glad_glFramebufferTextureLayer GLAD_API_CALL PFNGLFRONTFACEPROC glad_glFrontFace; #define glFrontFace glad_glFrontFace GLAD_API_CALL PFNGLGENBUFFERSPROC glad_glGenBuffers; #define glGenBuffers glad_glGenBuffers GLAD_API_CALL PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; #define glGenFramebuffers glad_glGenFramebuffers GLAD_API_CALL PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines; #define glGenProgramPipelines glad_glGenProgramPipelines GLAD_API_CALL PFNGLGENQUERIESPROC glad_glGenQueries; #define glGenQueries glad_glGenQueries GLAD_API_CALL PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; #define glGenRenderbuffers glad_glGenRenderbuffers GLAD_API_CALL PFNGLGENSAMPLERSPROC glad_glGenSamplers; #define glGenSamplers glad_glGenSamplers GLAD_API_CALL PFNGLGENTEXTURESPROC glad_glGenTextures; #define glGenTextures glad_glGenTextures GLAD_API_CALL PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks; #define glGenTransformFeedbacks glad_glGenTransformFeedbacks GLAD_API_CALL PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; #define glGenVertexArrays glad_glGenVertexArrays GLAD_API_CALL PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; #define glGenerateMipmap glad_glGenerateMipmap GLAD_API_CALL PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; #define glGetActiveAttrib glad_glGetActiveAttrib GLAD_API_CALL PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName; #define glGetActiveSubroutineName glad_glGetActiveSubroutineName GLAD_API_CALL PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName; #define glGetActiveSubroutineUniformName glad_glGetActiveSubroutineUniformName GLAD_API_CALL PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv; #define glGetActiveSubroutineUniformiv glad_glGetActiveSubroutineUniformiv GLAD_API_CALL PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; #define glGetActiveUniform glad_glGetActiveUniform GLAD_API_CALL PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; #define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName GLAD_API_CALL PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; #define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv GLAD_API_CALL PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; #define glGetActiveUniformName glad_glGetActiveUniformName GLAD_API_CALL PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; #define glGetActiveUniformsiv glad_glGetActiveUniformsiv GLAD_API_CALL PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; #define glGetAttachedShaders glad_glGetAttachedShaders GLAD_API_CALL PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; #define glGetAttribLocation glad_glGetAttribLocation GLAD_API_CALL PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; #define glGetBooleani_v glad_glGetBooleani_v GLAD_API_CALL PFNGLGETBOOLEANVPROC glad_glGetBooleanv; #define glGetBooleanv glad_glGetBooleanv GLAD_API_CALL PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; #define glGetBufferParameteri64v glad_glGetBufferParameteri64v GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; #define glGetBufferParameteriv glad_glGetBufferParameteriv GLAD_API_CALL PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; #define glGetBufferPointerv glad_glGetBufferPointerv GLAD_API_CALL PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; #define glGetBufferSubData glad_glGetBufferSubData GLAD_API_CALL PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; #define glGetCompressedTexImage glad_glGetCompressedTexImage GLAD_API_CALL PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v; #define glGetDoublei_v glad_glGetDoublei_v GLAD_API_CALL PFNGLGETDOUBLEVPROC glad_glGetDoublev; #define glGetDoublev glad_glGetDoublev GLAD_API_CALL PFNGLGETERRORPROC glad_glGetError; #define glGetError glad_glGetError GLAD_API_CALL PFNGLGETFLOATI_VPROC glad_glGetFloati_v; #define glGetFloati_v glad_glGetFloati_v GLAD_API_CALL PFNGLGETFLOATVPROC glad_glGetFloatv; #define glGetFloatv glad_glGetFloatv GLAD_API_CALL PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex; #define glGetFragDataIndex glad_glGetFragDataIndex GLAD_API_CALL PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; #define glGetFragDataLocation glad_glGetFragDataLocation GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; #define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv GLAD_API_CALL PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; #define glGetInteger64i_v glad_glGetInteger64i_v GLAD_API_CALL PFNGLGETINTEGER64VPROC glad_glGetInteger64v; #define glGetInteger64v glad_glGetInteger64v GLAD_API_CALL PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; #define glGetIntegeri_v glad_glGetIntegeri_v GLAD_API_CALL PFNGLGETINTEGERVPROC glad_glGetIntegerv; #define glGetIntegerv glad_glGetIntegerv GLAD_API_CALL PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; #define glGetMultisamplefv glad_glGetMultisamplefv GLAD_API_CALL PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary; #define glGetProgramBinary glad_glGetProgramBinary GLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; #define glGetProgramInfoLog glad_glGetProgramInfoLog GLAD_API_CALL PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog; #define glGetProgramPipelineInfoLog glad_glGetProgramPipelineInfoLog GLAD_API_CALL PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv; #define glGetProgramPipelineiv glad_glGetProgramPipelineiv GLAD_API_CALL PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv; #define glGetProgramStageiv glad_glGetProgramStageiv GLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; #define glGetProgramiv glad_glGetProgramiv GLAD_API_CALL PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv; #define glGetQueryIndexediv glad_glGetQueryIndexediv GLAD_API_CALL PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v; #define glGetQueryObjecti64v glad_glGetQueryObjecti64v GLAD_API_CALL PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; #define glGetQueryObjectiv glad_glGetQueryObjectiv GLAD_API_CALL PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v; #define glGetQueryObjectui64v glad_glGetQueryObjectui64v GLAD_API_CALL PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; #define glGetQueryObjectuiv glad_glGetQueryObjectuiv GLAD_API_CALL PFNGLGETQUERYIVPROC glad_glGetQueryiv; #define glGetQueryiv glad_glGetQueryiv GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; #define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv; #define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv; #define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv GLAD_API_CALL PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv; #define glGetSamplerParameterfv glad_glGetSamplerParameterfv GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv; #define glGetSamplerParameteriv glad_glGetSamplerParameteriv GLAD_API_CALL PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; #define glGetShaderInfoLog glad_glGetShaderInfoLog GLAD_API_CALL PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat; #define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat GLAD_API_CALL PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; #define glGetShaderSource glad_glGetShaderSource GLAD_API_CALL PFNGLGETSHADERIVPROC glad_glGetShaderiv; #define glGetShaderiv glad_glGetShaderiv GLAD_API_CALL PFNGLGETSTRINGPROC glad_glGetString; #define glGetString glad_glGetString GLAD_API_CALL PFNGLGETSTRINGIPROC glad_glGetStringi; #define glGetStringi glad_glGetStringi GLAD_API_CALL PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex; #define glGetSubroutineIndex glad_glGetSubroutineIndex GLAD_API_CALL PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation; #define glGetSubroutineUniformLocation glad_glGetSubroutineUniformLocation GLAD_API_CALL PFNGLGETSYNCIVPROC glad_glGetSynciv; #define glGetSynciv glad_glGetSynciv GLAD_API_CALL PFNGLGETTEXIMAGEPROC glad_glGetTexImage; #define glGetTexImage glad_glGetTexImage GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; #define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; #define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv GLAD_API_CALL PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; #define glGetTexParameterIiv glad_glGetTexParameterIiv GLAD_API_CALL PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; #define glGetTexParameterIuiv glad_glGetTexParameterIuiv GLAD_API_CALL PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; #define glGetTexParameterfv glad_glGetTexParameterfv GLAD_API_CALL PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; #define glGetTexParameteriv glad_glGetTexParameteriv GLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; #define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying GLAD_API_CALL PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; #define glGetUniformBlockIndex glad_glGetUniformBlockIndex GLAD_API_CALL PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; #define glGetUniformIndices glad_glGetUniformIndices GLAD_API_CALL PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; #define glGetUniformLocation glad_glGetUniformLocation GLAD_API_CALL PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv; #define glGetUniformSubroutineuiv glad_glGetUniformSubroutineuiv GLAD_API_CALL PFNGLGETUNIFORMDVPROC glad_glGetUniformdv; #define glGetUniformdv glad_glGetUniformdv GLAD_API_CALL PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; #define glGetUniformfv glad_glGetUniformfv GLAD_API_CALL PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; #define glGetUniformiv glad_glGetUniformiv GLAD_API_CALL PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; #define glGetUniformuiv glad_glGetUniformuiv GLAD_API_CALL PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; #define glGetVertexAttribIiv glad_glGetVertexAttribIiv GLAD_API_CALL PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; #define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv GLAD_API_CALL PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv; #define glGetVertexAttribLdv glad_glGetVertexAttribLdv GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; #define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv GLAD_API_CALL PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; #define glGetVertexAttribdv glad_glGetVertexAttribdv GLAD_API_CALL PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; #define glGetVertexAttribfv glad_glGetVertexAttribfv GLAD_API_CALL PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; #define glGetVertexAttribiv glad_glGetVertexAttribiv GLAD_API_CALL PFNGLHINTPROC glad_glHint; #define glHint glad_glHint GLAD_API_CALL PFNGLISBUFFERPROC glad_glIsBuffer; #define glIsBuffer glad_glIsBuffer GLAD_API_CALL PFNGLISENABLEDPROC glad_glIsEnabled; #define glIsEnabled glad_glIsEnabled GLAD_API_CALL PFNGLISENABLEDIPROC glad_glIsEnabledi; #define glIsEnabledi glad_glIsEnabledi GLAD_API_CALL PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; #define glIsFramebuffer glad_glIsFramebuffer GLAD_API_CALL PFNGLISPROGRAMPROC glad_glIsProgram; #define glIsProgram glad_glIsProgram GLAD_API_CALL PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline; #define glIsProgramPipeline glad_glIsProgramPipeline GLAD_API_CALL PFNGLISQUERYPROC glad_glIsQuery; #define glIsQuery glad_glIsQuery GLAD_API_CALL PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; #define glIsRenderbuffer glad_glIsRenderbuffer GLAD_API_CALL PFNGLISSAMPLERPROC glad_glIsSampler; #define glIsSampler glad_glIsSampler GLAD_API_CALL PFNGLISSHADERPROC glad_glIsShader; #define glIsShader glad_glIsShader GLAD_API_CALL PFNGLISSYNCPROC glad_glIsSync; #define glIsSync glad_glIsSync GLAD_API_CALL PFNGLISTEXTUREPROC glad_glIsTexture; #define glIsTexture glad_glIsTexture GLAD_API_CALL PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback; #define glIsTransformFeedback glad_glIsTransformFeedback GLAD_API_CALL PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; #define glIsVertexArray glad_glIsVertexArray GLAD_API_CALL PFNGLLINEWIDTHPROC glad_glLineWidth; #define glLineWidth glad_glLineWidth GLAD_API_CALL PFNGLLINKPROGRAMPROC glad_glLinkProgram; #define glLinkProgram glad_glLinkProgram GLAD_API_CALL PFNGLLOGICOPPROC glad_glLogicOp; #define glLogicOp glad_glLogicOp GLAD_API_CALL PFNGLMAPBUFFERPROC glad_glMapBuffer; #define glMapBuffer glad_glMapBuffer GLAD_API_CALL PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; #define glMapBufferRange glad_glMapBufferRange GLAD_API_CALL PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading; #define glMinSampleShading glad_glMinSampleShading GLAD_API_CALL PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; #define glMultiDrawArrays glad_glMultiDrawArrays GLAD_API_CALL PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; #define glMultiDrawElements glad_glMultiDrawElements GLAD_API_CALL PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; #define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex GLAD_API_CALL PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv; #define glPatchParameterfv glad_glPatchParameterfv GLAD_API_CALL PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri; #define glPatchParameteri glad_glPatchParameteri GLAD_API_CALL PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback; #define glPauseTransformFeedback glad_glPauseTransformFeedback GLAD_API_CALL PFNGLPIXELSTOREFPROC glad_glPixelStoref; #define glPixelStoref glad_glPixelStoref GLAD_API_CALL PFNGLPIXELSTOREIPROC glad_glPixelStorei; #define glPixelStorei glad_glPixelStorei GLAD_API_CALL PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; #define glPointParameterf glad_glPointParameterf GLAD_API_CALL PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; #define glPointParameterfv glad_glPointParameterfv GLAD_API_CALL PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; #define glPointParameteri glad_glPointParameteri GLAD_API_CALL PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; #define glPointParameteriv glad_glPointParameteriv GLAD_API_CALL PFNGLPOINTSIZEPROC glad_glPointSize; #define glPointSize glad_glPointSize GLAD_API_CALL PFNGLPOLYGONMODEPROC glad_glPolygonMode; #define glPolygonMode glad_glPolygonMode GLAD_API_CALL PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; #define glPolygonOffset glad_glPolygonOffset GLAD_API_CALL PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; #define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex GLAD_API_CALL PFNGLPROGRAMBINARYPROC glad_glProgramBinary; #define glProgramBinary glad_glProgramBinary GLAD_API_CALL PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri; #define glProgramParameteri glad_glProgramParameteri GLAD_API_CALL PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d; #define glProgramUniform1d glad_glProgramUniform1d GLAD_API_CALL PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv; #define glProgramUniform1dv glad_glProgramUniform1dv GLAD_API_CALL PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f; #define glProgramUniform1f glad_glProgramUniform1f GLAD_API_CALL PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv; #define glProgramUniform1fv glad_glProgramUniform1fv GLAD_API_CALL PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i; #define glProgramUniform1i glad_glProgramUniform1i GLAD_API_CALL PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv; #define glProgramUniform1iv glad_glProgramUniform1iv GLAD_API_CALL PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui; #define glProgramUniform1ui glad_glProgramUniform1ui GLAD_API_CALL PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv; #define glProgramUniform1uiv glad_glProgramUniform1uiv GLAD_API_CALL PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d; #define glProgramUniform2d glad_glProgramUniform2d GLAD_API_CALL PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv; #define glProgramUniform2dv glad_glProgramUniform2dv GLAD_API_CALL PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f; #define glProgramUniform2f glad_glProgramUniform2f GLAD_API_CALL PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv; #define glProgramUniform2fv glad_glProgramUniform2fv GLAD_API_CALL PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i; #define glProgramUniform2i glad_glProgramUniform2i GLAD_API_CALL PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv; #define glProgramUniform2iv glad_glProgramUniform2iv GLAD_API_CALL PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui; #define glProgramUniform2ui glad_glProgramUniform2ui GLAD_API_CALL PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv; #define glProgramUniform2uiv glad_glProgramUniform2uiv GLAD_API_CALL PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d; #define glProgramUniform3d glad_glProgramUniform3d GLAD_API_CALL PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv; #define glProgramUniform3dv glad_glProgramUniform3dv GLAD_API_CALL PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f; #define glProgramUniform3f glad_glProgramUniform3f GLAD_API_CALL PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv; #define glProgramUniform3fv glad_glProgramUniform3fv GLAD_API_CALL PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i; #define glProgramUniform3i glad_glProgramUniform3i GLAD_API_CALL PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv; #define glProgramUniform3iv glad_glProgramUniform3iv GLAD_API_CALL PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui; #define glProgramUniform3ui glad_glProgramUniform3ui GLAD_API_CALL PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv; #define glProgramUniform3uiv glad_glProgramUniform3uiv GLAD_API_CALL PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d; #define glProgramUniform4d glad_glProgramUniform4d GLAD_API_CALL PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv; #define glProgramUniform4dv glad_glProgramUniform4dv GLAD_API_CALL PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f; #define glProgramUniform4f glad_glProgramUniform4f GLAD_API_CALL PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv; #define glProgramUniform4fv glad_glProgramUniform4fv GLAD_API_CALL PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i; #define glProgramUniform4i glad_glProgramUniform4i GLAD_API_CALL PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv; #define glProgramUniform4iv glad_glProgramUniform4iv GLAD_API_CALL PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui; #define glProgramUniform4ui glad_glProgramUniform4ui GLAD_API_CALL PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv; #define glProgramUniform4uiv glad_glProgramUniform4uiv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv; #define glProgramUniformMatrix2dv glad_glProgramUniformMatrix2dv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv; #define glProgramUniformMatrix2fv glad_glProgramUniformMatrix2fv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv; #define glProgramUniformMatrix2x3dv glad_glProgramUniformMatrix2x3dv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv; #define glProgramUniformMatrix2x3fv glad_glProgramUniformMatrix2x3fv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv; #define glProgramUniformMatrix2x4dv glad_glProgramUniformMatrix2x4dv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv; #define glProgramUniformMatrix2x4fv glad_glProgramUniformMatrix2x4fv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv; #define glProgramUniformMatrix3dv glad_glProgramUniformMatrix3dv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv; #define glProgramUniformMatrix3fv glad_glProgramUniformMatrix3fv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv; #define glProgramUniformMatrix3x2dv glad_glProgramUniformMatrix3x2dv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv; #define glProgramUniformMatrix3x2fv glad_glProgramUniformMatrix3x2fv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv; #define glProgramUniformMatrix3x4dv glad_glProgramUniformMatrix3x4dv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv; #define glProgramUniformMatrix3x4fv glad_glProgramUniformMatrix3x4fv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv; #define glProgramUniformMatrix4dv glad_glProgramUniformMatrix4dv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv; #define glProgramUniformMatrix4fv glad_glProgramUniformMatrix4fv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv; #define glProgramUniformMatrix4x2dv glad_glProgramUniformMatrix4x2dv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv; #define glProgramUniformMatrix4x2fv glad_glProgramUniformMatrix4x2fv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv; #define glProgramUniformMatrix4x3dv glad_glProgramUniformMatrix4x3dv GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv; #define glProgramUniformMatrix4x3fv glad_glProgramUniformMatrix4x3fv GLAD_API_CALL PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; #define glProvokingVertex glad_glProvokingVertex GLAD_API_CALL PFNGLQUERYCOUNTERPROC glad_glQueryCounter; #define glQueryCounter glad_glQueryCounter GLAD_API_CALL PFNGLREADBUFFERPROC glad_glReadBuffer; #define glReadBuffer glad_glReadBuffer GLAD_API_CALL PFNGLREADPIXELSPROC glad_glReadPixels; #define glReadPixels glad_glReadPixels GLAD_API_CALL PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler; #define glReleaseShaderCompiler glad_glReleaseShaderCompiler GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; #define glRenderbufferStorage glad_glRenderbufferStorage GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; #define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample GLAD_API_CALL PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback; #define glResumeTransformFeedback glad_glResumeTransformFeedback GLAD_API_CALL PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; #define glSampleCoverage glad_glSampleCoverage GLAD_API_CALL PFNGLSAMPLEMASKIPROC glad_glSampleMaski; #define glSampleMaski glad_glSampleMaski GLAD_API_CALL PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv; #define glSamplerParameterIiv glad_glSamplerParameterIiv GLAD_API_CALL PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv; #define glSamplerParameterIuiv glad_glSamplerParameterIuiv GLAD_API_CALL PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf; #define glSamplerParameterf glad_glSamplerParameterf GLAD_API_CALL PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv; #define glSamplerParameterfv glad_glSamplerParameterfv GLAD_API_CALL PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri; #define glSamplerParameteri glad_glSamplerParameteri GLAD_API_CALL PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv; #define glSamplerParameteriv glad_glSamplerParameteriv GLAD_API_CALL PFNGLSCISSORPROC glad_glScissor; #define glScissor glad_glScissor GLAD_API_CALL PFNGLSCISSORARRAYVPROC glad_glScissorArrayv; #define glScissorArrayv glad_glScissorArrayv GLAD_API_CALL PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed; #define glScissorIndexed glad_glScissorIndexed GLAD_API_CALL PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv; #define glScissorIndexedv glad_glScissorIndexedv GLAD_API_CALL PFNGLSHADERBINARYPROC glad_glShaderBinary; #define glShaderBinary glad_glShaderBinary GLAD_API_CALL PFNGLSHADERSOURCEPROC glad_glShaderSource; #define glShaderSource glad_glShaderSource GLAD_API_CALL PFNGLSTENCILFUNCPROC glad_glStencilFunc; #define glStencilFunc glad_glStencilFunc GLAD_API_CALL PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; #define glStencilFuncSeparate glad_glStencilFuncSeparate GLAD_API_CALL PFNGLSTENCILMASKPROC glad_glStencilMask; #define glStencilMask glad_glStencilMask GLAD_API_CALL PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; #define glStencilMaskSeparate glad_glStencilMaskSeparate GLAD_API_CALL PFNGLSTENCILOPPROC glad_glStencilOp; #define glStencilOp glad_glStencilOp GLAD_API_CALL PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; #define glStencilOpSeparate glad_glStencilOpSeparate GLAD_API_CALL PFNGLTEXBUFFERPROC glad_glTexBuffer; #define glTexBuffer glad_glTexBuffer GLAD_API_CALL PFNGLTEXIMAGE1DPROC glad_glTexImage1D; #define glTexImage1D glad_glTexImage1D GLAD_API_CALL PFNGLTEXIMAGE2DPROC glad_glTexImage2D; #define glTexImage2D glad_glTexImage2D GLAD_API_CALL PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; #define glTexImage2DMultisample glad_glTexImage2DMultisample GLAD_API_CALL PFNGLTEXIMAGE3DPROC glad_glTexImage3D; #define glTexImage3D glad_glTexImage3D GLAD_API_CALL PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; #define glTexImage3DMultisample glad_glTexImage3DMultisample GLAD_API_CALL PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; #define glTexParameterIiv glad_glTexParameterIiv GLAD_API_CALL PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; #define glTexParameterIuiv glad_glTexParameterIuiv GLAD_API_CALL PFNGLTEXPARAMETERFPROC glad_glTexParameterf; #define glTexParameterf glad_glTexParameterf GLAD_API_CALL PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; #define glTexParameterfv glad_glTexParameterfv GLAD_API_CALL PFNGLTEXPARAMETERIPROC glad_glTexParameteri; #define glTexParameteri glad_glTexParameteri GLAD_API_CALL PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; #define glTexParameteriv glad_glTexParameteriv GLAD_API_CALL PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; #define glTexSubImage1D glad_glTexSubImage1D GLAD_API_CALL PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; #define glTexSubImage2D glad_glTexSubImage2D GLAD_API_CALL PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; #define glTexSubImage3D glad_glTexSubImage3D GLAD_API_CALL PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; #define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings GLAD_API_CALL PFNGLUNIFORM1DPROC glad_glUniform1d; #define glUniform1d glad_glUniform1d GLAD_API_CALL PFNGLUNIFORM1DVPROC glad_glUniform1dv; #define glUniform1dv glad_glUniform1dv GLAD_API_CALL PFNGLUNIFORM1FPROC glad_glUniform1f; #define glUniform1f glad_glUniform1f GLAD_API_CALL PFNGLUNIFORM1FVPROC glad_glUniform1fv; #define glUniform1fv glad_glUniform1fv GLAD_API_CALL PFNGLUNIFORM1IPROC glad_glUniform1i; #define glUniform1i glad_glUniform1i GLAD_API_CALL PFNGLUNIFORM1IVPROC glad_glUniform1iv; #define glUniform1iv glad_glUniform1iv GLAD_API_CALL PFNGLUNIFORM1UIPROC glad_glUniform1ui; #define glUniform1ui glad_glUniform1ui GLAD_API_CALL PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; #define glUniform1uiv glad_glUniform1uiv GLAD_API_CALL PFNGLUNIFORM2DPROC glad_glUniform2d; #define glUniform2d glad_glUniform2d GLAD_API_CALL PFNGLUNIFORM2DVPROC glad_glUniform2dv; #define glUniform2dv glad_glUniform2dv GLAD_API_CALL PFNGLUNIFORM2FPROC glad_glUniform2f; #define glUniform2f glad_glUniform2f GLAD_API_CALL PFNGLUNIFORM2FVPROC glad_glUniform2fv; #define glUniform2fv glad_glUniform2fv GLAD_API_CALL PFNGLUNIFORM2IPROC glad_glUniform2i; #define glUniform2i glad_glUniform2i GLAD_API_CALL PFNGLUNIFORM2IVPROC glad_glUniform2iv; #define glUniform2iv glad_glUniform2iv GLAD_API_CALL PFNGLUNIFORM2UIPROC glad_glUniform2ui; #define glUniform2ui glad_glUniform2ui GLAD_API_CALL PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; #define glUniform2uiv glad_glUniform2uiv GLAD_API_CALL PFNGLUNIFORM3DPROC glad_glUniform3d; #define glUniform3d glad_glUniform3d GLAD_API_CALL PFNGLUNIFORM3DVPROC glad_glUniform3dv; #define glUniform3dv glad_glUniform3dv GLAD_API_CALL PFNGLUNIFORM3FPROC glad_glUniform3f; #define glUniform3f glad_glUniform3f GLAD_API_CALL PFNGLUNIFORM3FVPROC glad_glUniform3fv; #define glUniform3fv glad_glUniform3fv GLAD_API_CALL PFNGLUNIFORM3IPROC glad_glUniform3i; #define glUniform3i glad_glUniform3i GLAD_API_CALL PFNGLUNIFORM3IVPROC glad_glUniform3iv; #define glUniform3iv glad_glUniform3iv GLAD_API_CALL PFNGLUNIFORM3UIPROC glad_glUniform3ui; #define glUniform3ui glad_glUniform3ui GLAD_API_CALL PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; #define glUniform3uiv glad_glUniform3uiv GLAD_API_CALL PFNGLUNIFORM4DPROC glad_glUniform4d; #define glUniform4d glad_glUniform4d GLAD_API_CALL PFNGLUNIFORM4DVPROC glad_glUniform4dv; #define glUniform4dv glad_glUniform4dv GLAD_API_CALL PFNGLUNIFORM4FPROC glad_glUniform4f; #define glUniform4f glad_glUniform4f GLAD_API_CALL PFNGLUNIFORM4FVPROC glad_glUniform4fv; #define glUniform4fv glad_glUniform4fv GLAD_API_CALL PFNGLUNIFORM4IPROC glad_glUniform4i; #define glUniform4i glad_glUniform4i GLAD_API_CALL PFNGLUNIFORM4IVPROC glad_glUniform4iv; #define glUniform4iv glad_glUniform4iv GLAD_API_CALL PFNGLUNIFORM4UIPROC glad_glUniform4ui; #define glUniform4ui glad_glUniform4ui GLAD_API_CALL PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; #define glUniform4uiv glad_glUniform4uiv GLAD_API_CALL PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; #define glUniformBlockBinding glad_glUniformBlockBinding GLAD_API_CALL PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv; #define glUniformMatrix2dv glad_glUniformMatrix2dv GLAD_API_CALL PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; #define glUniformMatrix2fv glad_glUniformMatrix2fv GLAD_API_CALL PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv; #define glUniformMatrix2x3dv glad_glUniformMatrix2x3dv GLAD_API_CALL PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; #define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv GLAD_API_CALL PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv; #define glUniformMatrix2x4dv glad_glUniformMatrix2x4dv GLAD_API_CALL PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; #define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv GLAD_API_CALL PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv; #define glUniformMatrix3dv glad_glUniformMatrix3dv GLAD_API_CALL PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; #define glUniformMatrix3fv glad_glUniformMatrix3fv GLAD_API_CALL PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv; #define glUniformMatrix3x2dv glad_glUniformMatrix3x2dv GLAD_API_CALL PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; #define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv GLAD_API_CALL PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv; #define glUniformMatrix3x4dv glad_glUniformMatrix3x4dv GLAD_API_CALL PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; #define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv GLAD_API_CALL PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv; #define glUniformMatrix4dv glad_glUniformMatrix4dv GLAD_API_CALL PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; #define glUniformMatrix4fv glad_glUniformMatrix4fv GLAD_API_CALL PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv; #define glUniformMatrix4x2dv glad_glUniformMatrix4x2dv GLAD_API_CALL PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; #define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv GLAD_API_CALL PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv; #define glUniformMatrix4x3dv glad_glUniformMatrix4x3dv GLAD_API_CALL PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; #define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv GLAD_API_CALL PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv; #define glUniformSubroutinesuiv glad_glUniformSubroutinesuiv GLAD_API_CALL PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; #define glUnmapBuffer glad_glUnmapBuffer GLAD_API_CALL PFNGLUSEPROGRAMPROC glad_glUseProgram; #define glUseProgram glad_glUseProgram GLAD_API_CALL PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages; #define glUseProgramStages glad_glUseProgramStages GLAD_API_CALL PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; #define glValidateProgram glad_glValidateProgram GLAD_API_CALL PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline; #define glValidateProgramPipeline glad_glValidateProgramPipeline GLAD_API_CALL PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; #define glVertexAttrib1d glad_glVertexAttrib1d GLAD_API_CALL PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; #define glVertexAttrib1dv glad_glVertexAttrib1dv GLAD_API_CALL PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; #define glVertexAttrib1f glad_glVertexAttrib1f GLAD_API_CALL PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; #define glVertexAttrib1fv glad_glVertexAttrib1fv GLAD_API_CALL PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; #define glVertexAttrib1s glad_glVertexAttrib1s GLAD_API_CALL PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; #define glVertexAttrib1sv glad_glVertexAttrib1sv GLAD_API_CALL PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; #define glVertexAttrib2d glad_glVertexAttrib2d GLAD_API_CALL PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; #define glVertexAttrib2dv glad_glVertexAttrib2dv GLAD_API_CALL PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; #define glVertexAttrib2f glad_glVertexAttrib2f GLAD_API_CALL PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; #define glVertexAttrib2fv glad_glVertexAttrib2fv GLAD_API_CALL PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; #define glVertexAttrib2s glad_glVertexAttrib2s GLAD_API_CALL PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; #define glVertexAttrib2sv glad_glVertexAttrib2sv GLAD_API_CALL PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; #define glVertexAttrib3d glad_glVertexAttrib3d GLAD_API_CALL PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; #define glVertexAttrib3dv glad_glVertexAttrib3dv GLAD_API_CALL PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; #define glVertexAttrib3f glad_glVertexAttrib3f GLAD_API_CALL PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; #define glVertexAttrib3fv glad_glVertexAttrib3fv GLAD_API_CALL PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; #define glVertexAttrib3s glad_glVertexAttrib3s GLAD_API_CALL PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; #define glVertexAttrib3sv glad_glVertexAttrib3sv GLAD_API_CALL PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; #define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv GLAD_API_CALL PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; #define glVertexAttrib4Niv glad_glVertexAttrib4Niv GLAD_API_CALL PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; #define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv GLAD_API_CALL PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; #define glVertexAttrib4Nub glad_glVertexAttrib4Nub GLAD_API_CALL PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; #define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv GLAD_API_CALL PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; #define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv GLAD_API_CALL PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; #define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv GLAD_API_CALL PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; #define glVertexAttrib4bv glad_glVertexAttrib4bv GLAD_API_CALL PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; #define glVertexAttrib4d glad_glVertexAttrib4d GLAD_API_CALL PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; #define glVertexAttrib4dv glad_glVertexAttrib4dv GLAD_API_CALL PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; #define glVertexAttrib4f glad_glVertexAttrib4f GLAD_API_CALL PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; #define glVertexAttrib4fv glad_glVertexAttrib4fv GLAD_API_CALL PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; #define glVertexAttrib4iv glad_glVertexAttrib4iv GLAD_API_CALL PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; #define glVertexAttrib4s glad_glVertexAttrib4s GLAD_API_CALL PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; #define glVertexAttrib4sv glad_glVertexAttrib4sv GLAD_API_CALL PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; #define glVertexAttrib4ubv glad_glVertexAttrib4ubv GLAD_API_CALL PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; #define glVertexAttrib4uiv glad_glVertexAttrib4uiv GLAD_API_CALL PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; #define glVertexAttrib4usv glad_glVertexAttrib4usv GLAD_API_CALL PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor; #define glVertexAttribDivisor glad_glVertexAttribDivisor GLAD_API_CALL PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; #define glVertexAttribI1i glad_glVertexAttribI1i GLAD_API_CALL PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; #define glVertexAttribI1iv glad_glVertexAttribI1iv GLAD_API_CALL PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; #define glVertexAttribI1ui glad_glVertexAttribI1ui GLAD_API_CALL PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; #define glVertexAttribI1uiv glad_glVertexAttribI1uiv GLAD_API_CALL PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; #define glVertexAttribI2i glad_glVertexAttribI2i GLAD_API_CALL PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; #define glVertexAttribI2iv glad_glVertexAttribI2iv GLAD_API_CALL PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; #define glVertexAttribI2ui glad_glVertexAttribI2ui GLAD_API_CALL PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; #define glVertexAttribI2uiv glad_glVertexAttribI2uiv GLAD_API_CALL PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; #define glVertexAttribI3i glad_glVertexAttribI3i GLAD_API_CALL PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; #define glVertexAttribI3iv glad_glVertexAttribI3iv GLAD_API_CALL PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; #define glVertexAttribI3ui glad_glVertexAttribI3ui GLAD_API_CALL PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; #define glVertexAttribI3uiv glad_glVertexAttribI3uiv GLAD_API_CALL PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; #define glVertexAttribI4bv glad_glVertexAttribI4bv GLAD_API_CALL PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; #define glVertexAttribI4i glad_glVertexAttribI4i GLAD_API_CALL PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; #define glVertexAttribI4iv glad_glVertexAttribI4iv GLAD_API_CALL PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; #define glVertexAttribI4sv glad_glVertexAttribI4sv GLAD_API_CALL PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; #define glVertexAttribI4ubv glad_glVertexAttribI4ubv GLAD_API_CALL PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; #define glVertexAttribI4ui glad_glVertexAttribI4ui GLAD_API_CALL PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; #define glVertexAttribI4uiv glad_glVertexAttribI4uiv GLAD_API_CALL PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; #define glVertexAttribI4usv glad_glVertexAttribI4usv GLAD_API_CALL PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; #define glVertexAttribIPointer glad_glVertexAttribIPointer GLAD_API_CALL PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d; #define glVertexAttribL1d glad_glVertexAttribL1d GLAD_API_CALL PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv; #define glVertexAttribL1dv glad_glVertexAttribL1dv GLAD_API_CALL PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d; #define glVertexAttribL2d glad_glVertexAttribL2d GLAD_API_CALL PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv; #define glVertexAttribL2dv glad_glVertexAttribL2dv GLAD_API_CALL PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d; #define glVertexAttribL3d glad_glVertexAttribL3d GLAD_API_CALL PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv; #define glVertexAttribL3dv glad_glVertexAttribL3dv GLAD_API_CALL PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d; #define glVertexAttribL4d glad_glVertexAttribL4d GLAD_API_CALL PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv; #define glVertexAttribL4dv glad_glVertexAttribL4dv GLAD_API_CALL PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer; #define glVertexAttribLPointer glad_glVertexAttribLPointer GLAD_API_CALL PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui; #define glVertexAttribP1ui glad_glVertexAttribP1ui GLAD_API_CALL PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv; #define glVertexAttribP1uiv glad_glVertexAttribP1uiv GLAD_API_CALL PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui; #define glVertexAttribP2ui glad_glVertexAttribP2ui GLAD_API_CALL PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv; #define glVertexAttribP2uiv glad_glVertexAttribP2uiv GLAD_API_CALL PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui; #define glVertexAttribP3ui glad_glVertexAttribP3ui GLAD_API_CALL PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv; #define glVertexAttribP3uiv glad_glVertexAttribP3uiv GLAD_API_CALL PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui; #define glVertexAttribP4ui glad_glVertexAttribP4ui GLAD_API_CALL PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv; #define glVertexAttribP4uiv glad_glVertexAttribP4uiv GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; #define glVertexAttribPointer glad_glVertexAttribPointer GLAD_API_CALL PFNGLVIEWPORTPROC glad_glViewport; #define glViewport glad_glViewport GLAD_API_CALL PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv; #define glViewportArrayv glad_glViewportArrayv GLAD_API_CALL PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf; #define glViewportIndexedf glad_glViewportIndexedf GLAD_API_CALL PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv; #define glViewportIndexedfv glad_glViewportIndexedfv GLAD_API_CALL PFNGLWAITSYNCPROC glad_glWaitSync; #define glWaitSync glad_glWaitSync GLAD_API_CALL int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr); GLAD_API_CALL int gladLoadGL( GLADloadfunc load); #ifdef GLAD_GL GLAD_API_CALL int gladLoaderLoadGL(void); GLAD_API_CALL void gladLoaderUnloadGL(void); #endif #ifdef __cplusplus } #endif #endif ================================================ FILE: lib/osgl/glad/src/egl.c ================================================ #include #include #include #include #ifndef GLAD_IMPL_UTIL_C_ #define GLAD_IMPL_UTIL_C_ #ifdef _MSC_VER #define GLAD_IMPL_UTIL_SSCANF sscanf_s #else #define GLAD_IMPL_UTIL_SSCANF sscanf #endif #endif /* GLAD_IMPL_UTIL_C_ */ #ifdef __cplusplus extern "C" { #endif int GLAD_EGL_VERSION_1_0 = 0; int GLAD_EGL_VERSION_1_1 = 0; int GLAD_EGL_VERSION_1_2 = 0; int GLAD_EGL_VERSION_1_3 = 0; int GLAD_EGL_VERSION_1_4 = 0; int GLAD_EGL_VERSION_1_5 = 0; int GLAD_EGL_EXT_device_base = 0; int GLAD_EGL_EXT_device_enumeration = 0; int GLAD_EGL_EXT_device_query = 0; int GLAD_EGL_EXT_device_query_name = 0; int GLAD_EGL_EXT_platform_base = 0; int GLAD_EGL_EXT_platform_device = 0; PFNEGLBINDAPIPROC glad_eglBindAPI = NULL; PFNEGLBINDTEXIMAGEPROC glad_eglBindTexImage = NULL; PFNEGLCHOOSECONFIGPROC glad_eglChooseConfig = NULL; PFNEGLCLIENTWAITSYNCPROC glad_eglClientWaitSync = NULL; PFNEGLCOPYBUFFERSPROC glad_eglCopyBuffers = NULL; PFNEGLCREATECONTEXTPROC glad_eglCreateContext = NULL; PFNEGLCREATEIMAGEPROC glad_eglCreateImage = NULL; PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC glad_eglCreatePbufferFromClientBuffer = NULL; PFNEGLCREATEPBUFFERSURFACEPROC glad_eglCreatePbufferSurface = NULL; PFNEGLCREATEPIXMAPSURFACEPROC glad_eglCreatePixmapSurface = NULL; PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC glad_eglCreatePlatformPixmapSurface = NULL; PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC glad_eglCreatePlatformPixmapSurfaceEXT = NULL; PFNEGLCREATEPLATFORMWINDOWSURFACEPROC glad_eglCreatePlatformWindowSurface = NULL; PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC glad_eglCreatePlatformWindowSurfaceEXT = NULL; PFNEGLCREATESYNCPROC glad_eglCreateSync = NULL; PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface = NULL; PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext = NULL; PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage = NULL; PFNEGLDESTROYSURFACEPROC glad_eglDestroySurface = NULL; PFNEGLDESTROYSYNCPROC glad_eglDestroySync = NULL; PFNEGLGETCONFIGATTRIBPROC glad_eglGetConfigAttrib = NULL; PFNEGLGETCONFIGSPROC glad_eglGetConfigs = NULL; PFNEGLGETCURRENTCONTEXTPROC glad_eglGetCurrentContext = NULL; PFNEGLGETCURRENTDISPLAYPROC glad_eglGetCurrentDisplay = NULL; PFNEGLGETCURRENTSURFACEPROC glad_eglGetCurrentSurface = NULL; PFNEGLGETDISPLAYPROC glad_eglGetDisplay = NULL; PFNEGLGETERRORPROC glad_eglGetError = NULL; PFNEGLGETPLATFORMDISPLAYPROC glad_eglGetPlatformDisplay = NULL; PFNEGLGETPLATFORMDISPLAYEXTPROC glad_eglGetPlatformDisplayEXT = NULL; PFNEGLGETPROCADDRESSPROC glad_eglGetProcAddress = NULL; PFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib = NULL; PFNEGLINITIALIZEPROC glad_eglInitialize = NULL; PFNEGLMAKECURRENTPROC glad_eglMakeCurrent = NULL; PFNEGLQUERYAPIPROC glad_eglQueryAPI = NULL; PFNEGLQUERYCONTEXTPROC glad_eglQueryContext = NULL; PFNEGLQUERYDEVICEATTRIBEXTPROC glad_eglQueryDeviceAttribEXT = NULL; PFNEGLQUERYDEVICESTRINGEXTPROC glad_eglQueryDeviceStringEXT = NULL; PFNEGLQUERYDEVICESEXTPROC glad_eglQueryDevicesEXT = NULL; PFNEGLQUERYDISPLAYATTRIBEXTPROC glad_eglQueryDisplayAttribEXT = NULL; PFNEGLQUERYSTRINGPROC glad_eglQueryString = NULL; PFNEGLQUERYSURFACEPROC glad_eglQuerySurface = NULL; PFNEGLRELEASETEXIMAGEPROC glad_eglReleaseTexImage = NULL; PFNEGLRELEASETHREADPROC glad_eglReleaseThread = NULL; PFNEGLSURFACEATTRIBPROC glad_eglSurfaceAttrib = NULL; PFNEGLSWAPBUFFERSPROC glad_eglSwapBuffers = NULL; PFNEGLSWAPINTERVALPROC glad_eglSwapInterval = NULL; PFNEGLTERMINATEPROC glad_eglTerminate = NULL; PFNEGLWAITCLIENTPROC glad_eglWaitClient = NULL; PFNEGLWAITGLPROC glad_eglWaitGL = NULL; PFNEGLWAITNATIVEPROC glad_eglWaitNative = NULL; PFNEGLWAITSYNCPROC glad_eglWaitSync = NULL; static void glad_egl_load_EGL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_EGL_VERSION_1_0) return; glad_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) load(userptr, "eglChooseConfig"); glad_eglCopyBuffers = (PFNEGLCOPYBUFFERSPROC) load(userptr, "eglCopyBuffers"); glad_eglCreateContext = (PFNEGLCREATECONTEXTPROC) load(userptr, "eglCreateContext"); glad_eglCreatePbufferSurface = (PFNEGLCREATEPBUFFERSURFACEPROC) load(userptr, "eglCreatePbufferSurface"); glad_eglCreatePixmapSurface = (PFNEGLCREATEPIXMAPSURFACEPROC) load(userptr, "eglCreatePixmapSurface"); glad_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) load(userptr, "eglCreateWindowSurface"); glad_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) load(userptr, "eglDestroyContext"); glad_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) load(userptr, "eglDestroySurface"); glad_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) load(userptr, "eglGetConfigAttrib"); glad_eglGetConfigs = (PFNEGLGETCONFIGSPROC) load(userptr, "eglGetConfigs"); glad_eglGetCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC) load(userptr, "eglGetCurrentDisplay"); glad_eglGetCurrentSurface = (PFNEGLGETCURRENTSURFACEPROC) load(userptr, "eglGetCurrentSurface"); glad_eglGetDisplay = (PFNEGLGETDISPLAYPROC) load(userptr, "eglGetDisplay"); glad_eglGetError = (PFNEGLGETERRORPROC) load(userptr, "eglGetError"); glad_eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC) load(userptr, "eglGetProcAddress"); glad_eglInitialize = (PFNEGLINITIALIZEPROC) load(userptr, "eglInitialize"); glad_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) load(userptr, "eglMakeCurrent"); glad_eglQueryContext = (PFNEGLQUERYCONTEXTPROC) load(userptr, "eglQueryContext"); glad_eglQueryString = (PFNEGLQUERYSTRINGPROC) load(userptr, "eglQueryString"); glad_eglQuerySurface = (PFNEGLQUERYSURFACEPROC) load(userptr, "eglQuerySurface"); glad_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) load(userptr, "eglSwapBuffers"); glad_eglTerminate = (PFNEGLTERMINATEPROC) load(userptr, "eglTerminate"); glad_eglWaitGL = (PFNEGLWAITGLPROC) load(userptr, "eglWaitGL"); glad_eglWaitNative = (PFNEGLWAITNATIVEPROC) load(userptr, "eglWaitNative"); } static void glad_egl_load_EGL_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_EGL_VERSION_1_1) return; glad_eglBindTexImage = (PFNEGLBINDTEXIMAGEPROC) load(userptr, "eglBindTexImage"); glad_eglReleaseTexImage = (PFNEGLRELEASETEXIMAGEPROC) load(userptr, "eglReleaseTexImage"); glad_eglSurfaceAttrib = (PFNEGLSURFACEATTRIBPROC) load(userptr, "eglSurfaceAttrib"); glad_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) load(userptr, "eglSwapInterval"); } static void glad_egl_load_EGL_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_EGL_VERSION_1_2) return; glad_eglBindAPI = (PFNEGLBINDAPIPROC) load(userptr, "eglBindAPI"); glad_eglCreatePbufferFromClientBuffer = (PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC) load(userptr, "eglCreatePbufferFromClientBuffer"); glad_eglQueryAPI = (PFNEGLQUERYAPIPROC) load(userptr, "eglQueryAPI"); glad_eglReleaseThread = (PFNEGLRELEASETHREADPROC) load(userptr, "eglReleaseThread"); glad_eglWaitClient = (PFNEGLWAITCLIENTPROC) load(userptr, "eglWaitClient"); } static void glad_egl_load_EGL_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_EGL_VERSION_1_4) return; glad_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) load(userptr, "eglGetCurrentContext"); } static void glad_egl_load_EGL_VERSION_1_5( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_EGL_VERSION_1_5) return; glad_eglClientWaitSync = (PFNEGLCLIENTWAITSYNCPROC) load(userptr, "eglClientWaitSync"); glad_eglCreateImage = (PFNEGLCREATEIMAGEPROC) load(userptr, "eglCreateImage"); glad_eglCreatePlatformPixmapSurface = (PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC) load(userptr, "eglCreatePlatformPixmapSurface"); glad_eglCreatePlatformWindowSurface = (PFNEGLCREATEPLATFORMWINDOWSURFACEPROC) load(userptr, "eglCreatePlatformWindowSurface"); glad_eglCreateSync = (PFNEGLCREATESYNCPROC) load(userptr, "eglCreateSync"); glad_eglDestroyImage = (PFNEGLDESTROYIMAGEPROC) load(userptr, "eglDestroyImage"); glad_eglDestroySync = (PFNEGLDESTROYSYNCPROC) load(userptr, "eglDestroySync"); glad_eglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYPROC) load(userptr, "eglGetPlatformDisplay"); glad_eglGetSyncAttrib = (PFNEGLGETSYNCATTRIBPROC) load(userptr, "eglGetSyncAttrib"); glad_eglWaitSync = (PFNEGLWAITSYNCPROC) load(userptr, "eglWaitSync"); } static void glad_egl_load_EGL_EXT_device_base( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_EGL_EXT_device_base) return; glad_eglQueryDeviceAttribEXT = (PFNEGLQUERYDEVICEATTRIBEXTPROC) load(userptr, "eglQueryDeviceAttribEXT"); glad_eglQueryDeviceStringEXT = (PFNEGLQUERYDEVICESTRINGEXTPROC) load(userptr, "eglQueryDeviceStringEXT"); glad_eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC) load(userptr, "eglQueryDevicesEXT"); glad_eglQueryDisplayAttribEXT = (PFNEGLQUERYDISPLAYATTRIBEXTPROC) load(userptr, "eglQueryDisplayAttribEXT"); } static void glad_egl_load_EGL_EXT_device_enumeration( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_EGL_EXT_device_enumeration) return; glad_eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC) load(userptr, "eglQueryDevicesEXT"); } static void glad_egl_load_EGL_EXT_device_query( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_EGL_EXT_device_query) return; glad_eglQueryDeviceAttribEXT = (PFNEGLQUERYDEVICEATTRIBEXTPROC) load(userptr, "eglQueryDeviceAttribEXT"); glad_eglQueryDeviceStringEXT = (PFNEGLQUERYDEVICESTRINGEXTPROC) load(userptr, "eglQueryDeviceStringEXT"); glad_eglQueryDisplayAttribEXT = (PFNEGLQUERYDISPLAYATTRIBEXTPROC) load(userptr, "eglQueryDisplayAttribEXT"); } static void glad_egl_load_EGL_EXT_platform_base( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_EGL_EXT_platform_base) return; glad_eglCreatePlatformPixmapSurfaceEXT = (PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC) load(userptr, "eglCreatePlatformPixmapSurfaceEXT"); glad_eglCreatePlatformWindowSurfaceEXT = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) load(userptr, "eglCreatePlatformWindowSurfaceEXT"); glad_eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC) load(userptr, "eglGetPlatformDisplayEXT"); } static int glad_egl_get_extensions(EGLDisplay display, const char **extensions) { *extensions = eglQueryString(display, EGL_EXTENSIONS); return extensions != NULL; } static int glad_egl_has_extension(const char *extensions, const char *ext) { const char *loc; const char *terminator; if(extensions == NULL) { return 0; } while(1) { loc = strstr(extensions, ext); if(loc == NULL) { return 0; } terminator = loc + strlen(ext); if((loc == extensions || *(loc - 1) == ' ') && (*terminator == ' ' || *terminator == '\0')) { return 1; } extensions = terminator; } } static GLADapiproc glad_egl_get_proc_from_userptr(void *userptr, const char *name) { return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); } static int glad_egl_find_extensions_egl(EGLDisplay display) { const char *extensions; if (!glad_egl_get_extensions(display, &extensions)) return 0; GLAD_EGL_EXT_device_base = glad_egl_has_extension(extensions, "EGL_EXT_device_base"); GLAD_EGL_EXT_device_enumeration = glad_egl_has_extension(extensions, "EGL_EXT_device_enumeration"); GLAD_EGL_EXT_device_query = glad_egl_has_extension(extensions, "EGL_EXT_device_query"); GLAD_EGL_EXT_device_query_name = glad_egl_has_extension(extensions, "EGL_EXT_device_query_name"); GLAD_EGL_EXT_platform_base = glad_egl_has_extension(extensions, "EGL_EXT_platform_base"); GLAD_EGL_EXT_platform_device = glad_egl_has_extension(extensions, "EGL_EXT_platform_device"); return 1; } static int glad_egl_find_core_egl(EGLDisplay display) { int major, minor; const char *version; // if (display == NULL) { // display = EGL_NO_DISPLAY; /* this is usually NULL, better safe than sorry */ // } // if (display == EGL_NO_DISPLAY) { // display = eglGetCurrentDisplay(); // } //#ifdef EGL_VERSION_1_4 // if (display == EGL_NO_DISPLAY) { // display = eglGetDisplay(EGL_DEFAULT_DISPLAY); // } //#endif //#ifndef EGL_VERSION_1_5 // if (display == EGL_NO_DISPLAY) { // return 0; // } //#endif // // version = eglQueryString(display, EGL_VERSION); // Modification: this needs to be called with NULL display to work properly version = eglQueryString(EGL_NO_DISPLAY, EGL_VERSION); (void) eglGetError(); if (version == NULL) { major = 1; minor = 0; } else { GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor); } GLAD_EGL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; GLAD_EGL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; GLAD_EGL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; GLAD_EGL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; GLAD_EGL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; GLAD_EGL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; return GLAD_MAKE_VERSION(major, minor); } int gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void* userptr) { int version; eglGetDisplay = (PFNEGLGETDISPLAYPROC) load(userptr, "eglGetDisplay"); eglGetCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC) load(userptr, "eglGetCurrentDisplay"); eglQueryString = (PFNEGLQUERYSTRINGPROC) load(userptr, "eglQueryString"); eglGetError = (PFNEGLGETERRORPROC) load(userptr, "eglGetError"); if (eglGetDisplay == NULL || eglGetCurrentDisplay == NULL || eglQueryString == NULL || eglGetError == NULL) return 0; version = glad_egl_find_core_egl(display); if (!version) return 0; glad_egl_load_EGL_VERSION_1_0(load, userptr); glad_egl_load_EGL_VERSION_1_1(load, userptr); glad_egl_load_EGL_VERSION_1_2(load, userptr); glad_egl_load_EGL_VERSION_1_4(load, userptr); glad_egl_load_EGL_VERSION_1_5(load, userptr); if (!glad_egl_find_extensions_egl(display)) return 0; glad_egl_load_EGL_EXT_device_base(load, userptr); glad_egl_load_EGL_EXT_device_enumeration(load, userptr); glad_egl_load_EGL_EXT_device_query(load, userptr); glad_egl_load_EGL_EXT_platform_base(load, userptr); return version; } int gladLoadEGL(EGLDisplay display, GLADloadfunc load) { return gladLoadEGLUserPtr(display, glad_egl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load); } #ifdef GLAD_EGL #ifndef GLAD_LOADER_LIBRARY_C_ #define GLAD_LOADER_LIBRARY_C_ #include #include #if GLAD_PLATFORM_WIN32 #include #else #include #endif static void* glad_get_dlopen_handle(const char *lib_names[], int length) { void *handle = NULL; int i; for (i = 0; i < length; ++i) { #if GLAD_PLATFORM_WIN32 #if GLAD_PLATFORM_UWP size_t buffer_size = (strlen(lib_names[i]) + 1) * sizeof(WCHAR); LPWSTR buffer = (LPWSTR) malloc(buffer_size); if (buffer != NULL) { int ret = MultiByteToWideChar(CP_ACP, 0, lib_names[i], -1, buffer, buffer_size); if (ret != 0) { handle = (void*) LoadPackagedLibrary(buffer, 0); } free((void*) buffer); } #else handle = (void*) LoadLibraryA(lib_names[i]); #endif #else handle = dlopen(lib_names[i], RTLD_LAZY | RTLD_LOCAL); #endif if (handle != NULL) { return handle; } } return NULL; } static void glad_close_dlopen_handle(void* handle) { if (handle != NULL) { #if GLAD_PLATFORM_WIN32 FreeLibrary((HMODULE) handle); #else dlclose(handle); #endif } } static GLADapiproc glad_dlsym_handle(void* handle, const char *name) { if (handle == NULL) { return NULL; } #if GLAD_PLATFORM_WIN32 return (GLADapiproc) GetProcAddress((HMODULE) handle, name); #else return GLAD_GNUC_EXTENSION (GLADapiproc) dlsym(handle, name); #endif } #endif /* GLAD_LOADER_LIBRARY_C_ */ struct _glad_egl_userptr { void *handle; PFNEGLGETPROCADDRESSPROC get_proc_address_ptr; }; static GLADapiproc glad_egl_get_proc(void *vuserptr, const char* name) { struct _glad_egl_userptr userptr = *(struct _glad_egl_userptr*) vuserptr; GLADapiproc result = NULL; result = glad_dlsym_handle(userptr.handle, name); if (result == NULL) { result = GLAD_GNUC_EXTENSION (GLADapiproc) userptr.get_proc_address_ptr(name); } return result; } static void* _egl_handle = NULL; static void* glad_egl_dlopen_handle(void) { #if GLAD_PLATFORM_APPLE static const char *NAMES[] = {"libEGL.dylib"}; #elif GLAD_PLATFORM_WIN32 static const char *NAMES[] = {"libEGL.dll", "EGL.dll"}; #else static const char *NAMES[] = {"libEGL.so.1", "libEGL.so"}; #endif if (_egl_handle == NULL) { _egl_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0])); } return _egl_handle; } static struct _glad_egl_userptr glad_egl_build_userptr(void *handle) { struct _glad_egl_userptr userptr; userptr.handle = handle; userptr.get_proc_address_ptr = (PFNEGLGETPROCADDRESSPROC) glad_dlsym_handle(handle, "eglGetProcAddress"); return userptr; } int gladLoaderLoadEGL(EGLDisplay display) { int version = 0; void *handle = NULL; int did_load = 0; struct _glad_egl_userptr userptr; did_load = _egl_handle == NULL; handle = glad_egl_dlopen_handle(); if (handle != NULL) { userptr = glad_egl_build_userptr(handle); if (userptr.get_proc_address_ptr != NULL) { version = gladLoadEGLUserPtr(display, glad_egl_get_proc, &userptr); } if (!version && did_load) { gladLoaderUnloadEGL(); } } return version; } void gladLoaderUnloadEGL() { if (_egl_handle != NULL) { glad_close_dlopen_handle(_egl_handle); _egl_handle = NULL; } } #endif /* GLAD_EGL */ #ifdef __cplusplus } #endif ================================================ FILE: lib/osgl/glad/src/gl.c ================================================ #include #include #include #include #ifndef GLAD_IMPL_UTIL_C_ #define GLAD_IMPL_UTIL_C_ #ifdef _MSC_VER #define GLAD_IMPL_UTIL_SSCANF sscanf_s #else #define GLAD_IMPL_UTIL_SSCANF sscanf #endif #endif /* GLAD_IMPL_UTIL_C_ */ #ifdef __cplusplus extern "C" { #endif int GLAD_GL_VERSION_1_0 = 0; int GLAD_GL_VERSION_1_1 = 0; int GLAD_GL_VERSION_1_2 = 0; int GLAD_GL_VERSION_1_3 = 0; int GLAD_GL_VERSION_1_4 = 0; int GLAD_GL_VERSION_1_5 = 0; int GLAD_GL_VERSION_2_0 = 0; int GLAD_GL_VERSION_2_1 = 0; int GLAD_GL_VERSION_3_0 = 0; int GLAD_GL_VERSION_3_1 = 0; int GLAD_GL_VERSION_3_2 = 0; int GLAD_GL_VERSION_3_3 = 0; int GLAD_GL_VERSION_4_0 = 0; int GLAD_GL_VERSION_4_1 = 0; PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram = NULL; PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL; PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL; PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed = NULL; PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL; PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL; PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL; PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL; PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL; PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline = NULL; PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL; PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback = NULL; PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL; PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei = NULL; PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi = NULL; PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei = NULL; PFNGLBLENDFUNCIPROC glad_glBlendFunci = NULL; PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL; PFNGLBUFFERDATAPROC glad_glBufferData = NULL; PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; PFNGLCLAMPCOLORPROC glad_glClampColor = NULL; PFNGLCLEARPROC glad_glClear = NULL; PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL; PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL; PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL; PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL; PFNGLCLEARCOLORPROC glad_glClearColor = NULL; PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL; PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL; PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL; PFNGLCOLORMASKPROC glad_glColorMask = NULL; PFNGLCOLORMASKIPROC glad_glColorMaski = NULL; PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL; PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL; PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL; PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL; PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL; PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL; PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL; PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL; PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; PFNGLCREATESHADERPROC glad_glCreateShader = NULL; PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv = NULL; PFNGLCULLFACEPROC glad_glCullFace = NULL; PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines = NULL; PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL; PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL; PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; PFNGLDELETESYNCPROC glad_glDeleteSync = NULL; PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks = NULL; PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL; PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL; PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv = NULL; PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed = NULL; PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL; PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; PFNGLDISABLEPROC glad_glDisable = NULL; PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; PFNGLDISABLEIPROC glad_glDisablei = NULL; PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect = NULL; PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL; PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL; PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL; PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL; PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect = NULL; PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL; PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL; PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL; PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL; PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback = NULL; PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream = NULL; PFNGLENABLEPROC glad_glEnable = NULL; PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; PFNGLENABLEIPROC glad_glEnablei = NULL; PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL; PFNGLENDQUERYPROC glad_glEndQuery = NULL; PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed = NULL; PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL; PFNGLFENCESYNCPROC glad_glFenceSync = NULL; PFNGLFINISHPROC glad_glFinish = NULL; PFNGLFLUSHPROC glad_glFlush = NULL; PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL; PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL; PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL; PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL; PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL; PFNGLFRONTFACEPROC glad_glFrontFace = NULL; PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines = NULL; PFNGLGENQUERIESPROC glad_glGenQueries = NULL; PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL; PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks = NULL; PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL; PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName = NULL; PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName = NULL; PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv = NULL; PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL; PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL; PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL; PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL; PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL; PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL; PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL; PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL; PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL; PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v = NULL; PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL; PFNGLGETERRORPROC glad_glGetError = NULL; PFNGLGETFLOATI_VPROC glad_glGetFloati_v = NULL; PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL; PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL; PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL; PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL; PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL; PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL; PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary = NULL; PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog = NULL; PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv = NULL; PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv = NULL; PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv = NULL; PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL; PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL; PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL; PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL; PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL; PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL; PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL; PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL; PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL; PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL; PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; PFNGLGETSTRINGPROC glad_glGetString = NULL; PFNGLGETSTRINGIPROC glad_glGetStringi = NULL; PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex = NULL; PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation = NULL; PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL; PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL; PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL; PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL; PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL; PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL; PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL; PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL; PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL; PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv = NULL; PFNGLGETUNIFORMDVPROC glad_glGetUniformdv = NULL; PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL; PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL; PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL; PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv = NULL; PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL; PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; PFNGLHINTPROC glad_glHint = NULL; PFNGLISBUFFERPROC glad_glIsBuffer = NULL; PFNGLISENABLEDPROC glad_glIsEnabled = NULL; PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL; PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; PFNGLISPROGRAMPROC glad_glIsProgram = NULL; PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline = NULL; PFNGLISQUERYPROC glad_glIsQuery = NULL; PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; PFNGLISSAMPLERPROC glad_glIsSampler = NULL; PFNGLISSHADERPROC glad_glIsShader = NULL; PFNGLISSYNCPROC glad_glIsSync = NULL; PFNGLISTEXTUREPROC glad_glIsTexture = NULL; PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback = NULL; PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL; PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; PFNGLLOGICOPPROC glad_glLogicOp = NULL; PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL; PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL; PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading = NULL; PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL; PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL; PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL; PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv = NULL; PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri = NULL; PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback = NULL; PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL; PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL; PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL; PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL; PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL; PFNGLPOINTSIZEPROC glad_glPointSize = NULL; PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL; PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL; PFNGLPROGRAMBINARYPROC glad_glProgramBinary = NULL; PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri = NULL; PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d = NULL; PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv = NULL; PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f = NULL; PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv = NULL; PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i = NULL; PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv = NULL; PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui = NULL; PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv = NULL; PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d = NULL; PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv = NULL; PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f = NULL; PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv = NULL; PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i = NULL; PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv = NULL; PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui = NULL; PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv = NULL; PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d = NULL; PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv = NULL; PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f = NULL; PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv = NULL; PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i = NULL; PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv = NULL; PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui = NULL; PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv = NULL; PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d = NULL; PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv = NULL; PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f = NULL; PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv = NULL; PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i = NULL; PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv = NULL; PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui = NULL; PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv = NULL; PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv = NULL; PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv = NULL; PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv = NULL; PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv = NULL; PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv = NULL; PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv = NULL; PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv = NULL; PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv = NULL; PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv = NULL; PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv = NULL; PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv = NULL; PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv = NULL; PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv = NULL; PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv = NULL; PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv = NULL; PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv = NULL; PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv = NULL; PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv = NULL; PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL; PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL; PFNGLREADBUFFERPROC glad_glReadBuffer = NULL; PFNGLREADPIXELSPROC glad_glReadPixels = NULL; PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL; PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL; PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL; PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL; PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL; PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL; PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL; PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL; PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL; PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL; PFNGLSCISSORPROC glad_glScissor = NULL; PFNGLSCISSORARRAYVPROC glad_glScissorArrayv = NULL; PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed = NULL; PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv = NULL; PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL; PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; PFNGLSTENCILOPPROC glad_glStencilOp = NULL; PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL; PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL; PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL; PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL; PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL; PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL; PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL; PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL; PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL; PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL; PFNGLUNIFORM1DPROC glad_glUniform1d = NULL; PFNGLUNIFORM1DVPROC glad_glUniform1dv = NULL; PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL; PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL; PFNGLUNIFORM2DPROC glad_glUniform2d = NULL; PFNGLUNIFORM2DVPROC glad_glUniform2dv = NULL; PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL; PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL; PFNGLUNIFORM3DPROC glad_glUniform3d = NULL; PFNGLUNIFORM3DVPROC glad_glUniform3dv = NULL; PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL; PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL; PFNGLUNIFORM4DPROC glad_glUniform4d = NULL; PFNGLUNIFORM4DVPROC glad_glUniform4dv = NULL; PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL; PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL; PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL; PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv = NULL; PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv = NULL; PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL; PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv = NULL; PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL; PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv = NULL; PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv = NULL; PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL; PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv = NULL; PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL; PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv = NULL; PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv = NULL; PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL; PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv = NULL; PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL; PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv = NULL; PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL; PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages = NULL; PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline = NULL; PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL; PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL; PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL; PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL; PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL; PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL; PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL; PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL; PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL; PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL; PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL; PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL; PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL; PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL; PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL; PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL; PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL; PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL; PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL; PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL; PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL; PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL; PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL; PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL; PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL; PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL; PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL; PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL; PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL; PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL; PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL; PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL; PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL; PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL; PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL; PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL; PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL; PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL; PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL; PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL; PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL; PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL; PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL; PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL; PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL; PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL; PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL; PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL; PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL; PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL; PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d = NULL; PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv = NULL; PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d = NULL; PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv = NULL; PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d = NULL; PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv = NULL; PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d = NULL; PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv = NULL; PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer = NULL; PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL; PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL; PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL; PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL; PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL; PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL; PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL; PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL; PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; PFNGLVIEWPORTPROC glad_glViewport = NULL; PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv = NULL; PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL; PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL; PFNGLWAITSYNCPROC glad_glWaitSync = NULL; static void glad_gl_load_GL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_1_0) return; glad_glBlendFunc = (PFNGLBLENDFUNCPROC) load(userptr, "glBlendFunc"); glad_glClear = (PFNGLCLEARPROC) load(userptr, "glClear"); glad_glClearColor = (PFNGLCLEARCOLORPROC) load(userptr, "glClearColor"); glad_glClearDepth = (PFNGLCLEARDEPTHPROC) load(userptr, "glClearDepth"); glad_glClearStencil = (PFNGLCLEARSTENCILPROC) load(userptr, "glClearStencil"); glad_glColorMask = (PFNGLCOLORMASKPROC) load(userptr, "glColorMask"); glad_glCullFace = (PFNGLCULLFACEPROC) load(userptr, "glCullFace"); glad_glDepthFunc = (PFNGLDEPTHFUNCPROC) load(userptr, "glDepthFunc"); glad_glDepthMask = (PFNGLDEPTHMASKPROC) load(userptr, "glDepthMask"); glad_glDepthRange = (PFNGLDEPTHRANGEPROC) load(userptr, "glDepthRange"); glad_glDisable = (PFNGLDISABLEPROC) load(userptr, "glDisable"); glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC) load(userptr, "glDrawBuffer"); glad_glEnable = (PFNGLENABLEPROC) load(userptr, "glEnable"); glad_glFinish = (PFNGLFINISHPROC) load(userptr, "glFinish"); glad_glFlush = (PFNGLFLUSHPROC) load(userptr, "glFlush"); glad_glFrontFace = (PFNGLFRONTFACEPROC) load(userptr, "glFrontFace"); glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC) load(userptr, "glGetBooleanv"); glad_glGetDoublev = (PFNGLGETDOUBLEVPROC) load(userptr, "glGetDoublev"); glad_glGetError = (PFNGLGETERRORPROC) load(userptr, "glGetError"); glad_glGetFloatv = (PFNGLGETFLOATVPROC) load(userptr, "glGetFloatv"); glad_glGetIntegerv = (PFNGLGETINTEGERVPROC) load(userptr, "glGetIntegerv"); glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC) load(userptr, "glGetTexImage"); glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC) load(userptr, "glGetTexLevelParameterfv"); glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC) load(userptr, "glGetTexLevelParameteriv"); glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load(userptr, "glGetTexParameterfv"); glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load(userptr, "glGetTexParameteriv"); glad_glHint = (PFNGLHINTPROC) load(userptr, "glHint"); glad_glIsEnabled = (PFNGLISENABLEDPROC) load(userptr, "glIsEnabled"); glad_glLineWidth = (PFNGLLINEWIDTHPROC) load(userptr, "glLineWidth"); glad_glLogicOp = (PFNGLLOGICOPPROC) load(userptr, "glLogicOp"); glad_glPixelStoref = (PFNGLPIXELSTOREFPROC) load(userptr, "glPixelStoref"); glad_glPixelStorei = (PFNGLPIXELSTOREIPROC) load(userptr, "glPixelStorei"); glad_glPointSize = (PFNGLPOINTSIZEPROC) load(userptr, "glPointSize"); glad_glPolygonMode = (PFNGLPOLYGONMODEPROC) load(userptr, "glPolygonMode"); glad_glReadBuffer = (PFNGLREADBUFFERPROC) load(userptr, "glReadBuffer"); glad_glReadPixels = (PFNGLREADPIXELSPROC) load(userptr, "glReadPixels"); glad_glScissor = (PFNGLSCISSORPROC) load(userptr, "glScissor"); glad_glStencilFunc = (PFNGLSTENCILFUNCPROC) load(userptr, "glStencilFunc"); glad_glStencilMask = (PFNGLSTENCILMASKPROC) load(userptr, "glStencilMask"); glad_glStencilOp = (PFNGLSTENCILOPPROC) load(userptr, "glStencilOp"); glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC) load(userptr, "glTexImage1D"); glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC) load(userptr, "glTexImage2D"); glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC) load(userptr, "glTexParameterf"); glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load(userptr, "glTexParameterfv"); glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC) load(userptr, "glTexParameteri"); glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load(userptr, "glTexParameteriv"); glad_glViewport = (PFNGLVIEWPORTPROC) load(userptr, "glViewport"); } static void glad_gl_load_GL_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_1_1) return; glad_glBindTexture = (PFNGLBINDTEXTUREPROC) load(userptr, "glBindTexture"); glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC) load(userptr, "glCopyTexImage1D"); glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load(userptr, "glCopyTexImage2D"); glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC) load(userptr, "glCopyTexSubImage1D"); glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load(userptr, "glCopyTexSubImage2D"); glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC) load(userptr, "glDeleteTextures"); glad_glDrawArrays = (PFNGLDRAWARRAYSPROC) load(userptr, "glDrawArrays"); glad_glDrawElements = (PFNGLDRAWELEMENTSPROC) load(userptr, "glDrawElements"); glad_glGenTextures = (PFNGLGENTEXTURESPROC) load(userptr, "glGenTextures"); glad_glIsTexture = (PFNGLISTEXTUREPROC) load(userptr, "glIsTexture"); glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load(userptr, "glPolygonOffset"); glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC) load(userptr, "glTexSubImage1D"); glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load(userptr, "glTexSubImage2D"); } static void glad_gl_load_GL_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_1_2) return; glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) load(userptr, "glCopyTexSubImage3D"); glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) load(userptr, "glDrawRangeElements"); glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC) load(userptr, "glTexImage3D"); glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) load(userptr, "glTexSubImage3D"); } static void glad_gl_load_GL_VERSION_1_3( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_1_3) return; glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC) load(userptr, "glActiveTexture"); glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC) load(userptr, "glCompressedTexImage1D"); glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load(userptr, "glCompressedTexImage2D"); glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC) load(userptr, "glCompressedTexImage3D"); glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) load(userptr, "glCompressedTexSubImage1D"); glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load(userptr, "glCompressedTexSubImage2D"); glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) load(userptr, "glCompressedTexSubImage3D"); glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC) load(userptr, "glGetCompressedTexImage"); glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load(userptr, "glSampleCoverage"); } static void glad_gl_load_GL_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_1_4) return; glad_glBlendColor = (PFNGLBLENDCOLORPROC) load(userptr, "glBlendColor"); glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC) load(userptr, "glBlendEquation"); glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load(userptr, "glBlendFuncSeparate"); glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC) load(userptr, "glMultiDrawArrays"); glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC) load(userptr, "glMultiDrawElements"); glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC) load(userptr, "glPointParameterf"); glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC) load(userptr, "glPointParameterfv"); glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC) load(userptr, "glPointParameteri"); glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC) load(userptr, "glPointParameteriv"); } static void glad_gl_load_GL_VERSION_1_5( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_1_5) return; glad_glBeginQuery = (PFNGLBEGINQUERYPROC) load(userptr, "glBeginQuery"); glad_glBindBuffer = (PFNGLBINDBUFFERPROC) load(userptr, "glBindBuffer"); glad_glBufferData = (PFNGLBUFFERDATAPROC) load(userptr, "glBufferData"); glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load(userptr, "glBufferSubData"); glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load(userptr, "glDeleteBuffers"); glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC) load(userptr, "glDeleteQueries"); glad_glEndQuery = (PFNGLENDQUERYPROC) load(userptr, "glEndQuery"); glad_glGenBuffers = (PFNGLGENBUFFERSPROC) load(userptr, "glGenBuffers"); glad_glGenQueries = (PFNGLGENQUERIESPROC) load(userptr, "glGenQueries"); glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load(userptr, "glGetBufferParameteriv"); glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC) load(userptr, "glGetBufferPointerv"); glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC) load(userptr, "glGetBufferSubData"); glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC) load(userptr, "glGetQueryObjectiv"); glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC) load(userptr, "glGetQueryObjectuiv"); glad_glGetQueryiv = (PFNGLGETQUERYIVPROC) load(userptr, "glGetQueryiv"); glad_glIsBuffer = (PFNGLISBUFFERPROC) load(userptr, "glIsBuffer"); glad_glIsQuery = (PFNGLISQUERYPROC) load(userptr, "glIsQuery"); glad_glMapBuffer = (PFNGLMAPBUFFERPROC) load(userptr, "glMapBuffer"); glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC) load(userptr, "glUnmapBuffer"); } static void glad_gl_load_GL_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_2_0) return; glad_glAttachShader = (PFNGLATTACHSHADERPROC) load(userptr, "glAttachShader"); glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load(userptr, "glBindAttribLocation"); glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load(userptr, "glBlendEquationSeparate"); glad_glCompileShader = (PFNGLCOMPILESHADERPROC) load(userptr, "glCompileShader"); glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC) load(userptr, "glCreateProgram"); glad_glCreateShader = (PFNGLCREATESHADERPROC) load(userptr, "glCreateShader"); glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load(userptr, "glDeleteProgram"); glad_glDeleteShader = (PFNGLDELETESHADERPROC) load(userptr, "glDeleteShader"); glad_glDetachShader = (PFNGLDETACHSHADERPROC) load(userptr, "glDetachShader"); glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load(userptr, "glDisableVertexAttribArray"); glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC) load(userptr, "glDrawBuffers"); glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load(userptr, "glEnableVertexAttribArray"); glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load(userptr, "glGetActiveAttrib"); glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load(userptr, "glGetActiveUniform"); glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load(userptr, "glGetAttachedShaders"); glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load(userptr, "glGetAttribLocation"); glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load(userptr, "glGetProgramInfoLog"); glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load(userptr, "glGetProgramiv"); glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load(userptr, "glGetShaderInfoLog"); glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load(userptr, "glGetShaderSource"); glad_glGetShaderiv = (PFNGLGETSHADERIVPROC) load(userptr, "glGetShaderiv"); glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load(userptr, "glGetUniformLocation"); glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load(userptr, "glGetUniformfv"); glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load(userptr, "glGetUniformiv"); glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load(userptr, "glGetVertexAttribPointerv"); glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC) load(userptr, "glGetVertexAttribdv"); glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load(userptr, "glGetVertexAttribfv"); glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load(userptr, "glGetVertexAttribiv"); glad_glIsProgram = (PFNGLISPROGRAMPROC) load(userptr, "glIsProgram"); glad_glIsShader = (PFNGLISSHADERPROC) load(userptr, "glIsShader"); glad_glLinkProgram = (PFNGLLINKPROGRAMPROC) load(userptr, "glLinkProgram"); glad_glShaderSource = (PFNGLSHADERSOURCEPROC) load(userptr, "glShaderSource"); glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load(userptr, "glStencilFuncSeparate"); glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load(userptr, "glStencilMaskSeparate"); glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load(userptr, "glStencilOpSeparate"); glad_glUniform1f = (PFNGLUNIFORM1FPROC) load(userptr, "glUniform1f"); glad_glUniform1fv = (PFNGLUNIFORM1FVPROC) load(userptr, "glUniform1fv"); glad_glUniform1i = (PFNGLUNIFORM1IPROC) load(userptr, "glUniform1i"); glad_glUniform1iv = (PFNGLUNIFORM1IVPROC) load(userptr, "glUniform1iv"); glad_glUniform2f = (PFNGLUNIFORM2FPROC) load(userptr, "glUniform2f"); glad_glUniform2fv = (PFNGLUNIFORM2FVPROC) load(userptr, "glUniform2fv"); glad_glUniform2i = (PFNGLUNIFORM2IPROC) load(userptr, "glUniform2i"); glad_glUniform2iv = (PFNGLUNIFORM2IVPROC) load(userptr, "glUniform2iv"); glad_glUniform3f = (PFNGLUNIFORM3FPROC) load(userptr, "glUniform3f"); glad_glUniform3fv = (PFNGLUNIFORM3FVPROC) load(userptr, "glUniform3fv"); glad_glUniform3i = (PFNGLUNIFORM3IPROC) load(userptr, "glUniform3i"); glad_glUniform3iv = (PFNGLUNIFORM3IVPROC) load(userptr, "glUniform3iv"); glad_glUniform4f = (PFNGLUNIFORM4FPROC) load(userptr, "glUniform4f"); glad_glUniform4fv = (PFNGLUNIFORM4FVPROC) load(userptr, "glUniform4fv"); glad_glUniform4i = (PFNGLUNIFORM4IPROC) load(userptr, "glUniform4i"); glad_glUniform4iv = (PFNGLUNIFORM4IVPROC) load(userptr, "glUniform4iv"); glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load(userptr, "glUniformMatrix2fv"); glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load(userptr, "glUniformMatrix3fv"); glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load(userptr, "glUniformMatrix4fv"); glad_glUseProgram = (PFNGLUSEPROGRAMPROC) load(userptr, "glUseProgram"); glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load(userptr, "glValidateProgram"); glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC) load(userptr, "glVertexAttrib1d"); glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC) load(userptr, "glVertexAttrib1dv"); glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load(userptr, "glVertexAttrib1f"); glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load(userptr, "glVertexAttrib1fv"); glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC) load(userptr, "glVertexAttrib1s"); glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC) load(userptr, "glVertexAttrib1sv"); glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC) load(userptr, "glVertexAttrib2d"); glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC) load(userptr, "glVertexAttrib2dv"); glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load(userptr, "glVertexAttrib2f"); glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load(userptr, "glVertexAttrib2fv"); glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC) load(userptr, "glVertexAttrib2s"); glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC) load(userptr, "glVertexAttrib2sv"); glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC) load(userptr, "glVertexAttrib3d"); glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC) load(userptr, "glVertexAttrib3dv"); glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load(userptr, "glVertexAttrib3f"); glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load(userptr, "glVertexAttrib3fv"); glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC) load(userptr, "glVertexAttrib3s"); glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC) load(userptr, "glVertexAttrib3sv"); glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC) load(userptr, "glVertexAttrib4Nbv"); glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC) load(userptr, "glVertexAttrib4Niv"); glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC) load(userptr, "glVertexAttrib4Nsv"); glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC) load(userptr, "glVertexAttrib4Nub"); glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC) load(userptr, "glVertexAttrib4Nubv"); glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC) load(userptr, "glVertexAttrib4Nuiv"); glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC) load(userptr, "glVertexAttrib4Nusv"); glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC) load(userptr, "glVertexAttrib4bv"); glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC) load(userptr, "glVertexAttrib4d"); glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC) load(userptr, "glVertexAttrib4dv"); glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load(userptr, "glVertexAttrib4f"); glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load(userptr, "glVertexAttrib4fv"); glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC) load(userptr, "glVertexAttrib4iv"); glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC) load(userptr, "glVertexAttrib4s"); glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC) load(userptr, "glVertexAttrib4sv"); glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC) load(userptr, "glVertexAttrib4ubv"); glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC) load(userptr, "glVertexAttrib4uiv"); glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC) load(userptr, "glVertexAttrib4usv"); glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load(userptr, "glVertexAttribPointer"); } static void glad_gl_load_GL_VERSION_2_1( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_2_1) return; glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC) load(userptr, "glUniformMatrix2x3fv"); glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC) load(userptr, "glUniformMatrix2x4fv"); glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC) load(userptr, "glUniformMatrix3x2fv"); glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) load(userptr, "glUniformMatrix3x4fv"); glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC) load(userptr, "glUniformMatrix4x2fv"); glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC) load(userptr, "glUniformMatrix4x3fv"); } static void glad_gl_load_GL_VERSION_3_0( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_3_0) return; glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC) load(userptr, "glBeginConditionalRender"); glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) load(userptr, "glBeginTransformFeedback"); glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load(userptr, "glBindBufferBase"); glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load(userptr, "glBindBufferRange"); glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC) load(userptr, "glBindFragDataLocation"); glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, "glBindFramebuffer"); glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, "glBindRenderbuffer"); glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) load(userptr, "glBindVertexArray"); glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) load(userptr, "glBlitFramebuffer"); glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckFramebufferStatus"); glad_glClampColor = (PFNGLCLAMPCOLORPROC) load(userptr, "glClampColor"); glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC) load(userptr, "glClearBufferfi"); glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC) load(userptr, "glClearBufferfv"); glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC) load(userptr, "glClearBufferiv"); glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC) load(userptr, "glClearBufferuiv"); glad_glColorMaski = (PFNGLCOLORMASKIPROC) load(userptr, "glColorMaski"); glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, "glDeleteFramebuffers"); glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, "glDeleteRenderbuffers"); glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) load(userptr, "glDeleteVertexArrays"); glad_glDisablei = (PFNGLDISABLEIPROC) load(userptr, "glDisablei"); glad_glEnablei = (PFNGLENABLEIPROC) load(userptr, "glEnablei"); glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC) load(userptr, "glEndConditionalRender"); glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) load(userptr, "glEndTransformFeedback"); glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) load(userptr, "glFlushMappedBufferRange"); glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glFramebufferRenderbuffer"); glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) load(userptr, "glFramebufferTexture1D"); glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, "glFramebufferTexture2D"); glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) load(userptr, "glFramebufferTexture3D"); glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) load(userptr, "glFramebufferTextureLayer"); glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, "glGenFramebuffers"); glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, "glGenRenderbuffers"); glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) load(userptr, "glGenVertexArrays"); glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, "glGenerateMipmap"); glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC) load(userptr, "glGetBooleani_v"); glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC) load(userptr, "glGetFragDataLocation"); glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetFramebufferAttachmentParameteriv"); glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load(userptr, "glGetIntegeri_v"); glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetRenderbufferParameteriv"); glad_glGetStringi = (PFNGLGETSTRINGIPROC) load(userptr, "glGetStringi"); glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC) load(userptr, "glGetTexParameterIiv"); glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC) load(userptr, "glGetTexParameterIuiv"); glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) load(userptr, "glGetTransformFeedbackVarying"); glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC) load(userptr, "glGetUniformuiv"); glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC) load(userptr, "glGetVertexAttribIiv"); glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC) load(userptr, "glGetVertexAttribIuiv"); glad_glIsEnabledi = (PFNGLISENABLEDIPROC) load(userptr, "glIsEnabledi"); glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, "glIsFramebuffer"); glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, "glIsRenderbuffer"); glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC) load(userptr, "glIsVertexArray"); glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) load(userptr, "glMapBufferRange"); glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage"); glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) load(userptr, "glRenderbufferStorageMultisample"); glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC) load(userptr, "glTexParameterIiv"); glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC) load(userptr, "glTexParameterIuiv"); glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) load(userptr, "glTransformFeedbackVaryings"); glad_glUniform1ui = (PFNGLUNIFORM1UIPROC) load(userptr, "glUniform1ui"); glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC) load(userptr, "glUniform1uiv"); glad_glUniform2ui = (PFNGLUNIFORM2UIPROC) load(userptr, "glUniform2ui"); glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC) load(userptr, "glUniform2uiv"); glad_glUniform3ui = (PFNGLUNIFORM3UIPROC) load(userptr, "glUniform3ui"); glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC) load(userptr, "glUniform3uiv"); glad_glUniform4ui = (PFNGLUNIFORM4UIPROC) load(userptr, "glUniform4ui"); glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC) load(userptr, "glUniform4uiv"); glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC) load(userptr, "glVertexAttribI1i"); glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC) load(userptr, "glVertexAttribI1iv"); glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC) load(userptr, "glVertexAttribI1ui"); glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC) load(userptr, "glVertexAttribI1uiv"); glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC) load(userptr, "glVertexAttribI2i"); glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC) load(userptr, "glVertexAttribI2iv"); glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC) load(userptr, "glVertexAttribI2ui"); glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC) load(userptr, "glVertexAttribI2uiv"); glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC) load(userptr, "glVertexAttribI3i"); glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC) load(userptr, "glVertexAttribI3iv"); glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC) load(userptr, "glVertexAttribI3ui"); glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC) load(userptr, "glVertexAttribI3uiv"); glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC) load(userptr, "glVertexAttribI4bv"); glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC) load(userptr, "glVertexAttribI4i"); glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC) load(userptr, "glVertexAttribI4iv"); glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC) load(userptr, "glVertexAttribI4sv"); glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC) load(userptr, "glVertexAttribI4ubv"); glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC) load(userptr, "glVertexAttribI4ui"); glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC) load(userptr, "glVertexAttribI4uiv"); glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC) load(userptr, "glVertexAttribI4usv"); glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) load(userptr, "glVertexAttribIPointer"); } static void glad_gl_load_GL_VERSION_3_1( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_3_1) return; glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load(userptr, "glBindBufferBase"); glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load(userptr, "glBindBufferRange"); glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC) load(userptr, "glCopyBufferSubData"); glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC) load(userptr, "glDrawArraysInstanced"); glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC) load(userptr, "glDrawElementsInstanced"); glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) load(userptr, "glGetActiveUniformBlockName"); glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC) load(userptr, "glGetActiveUniformBlockiv"); glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC) load(userptr, "glGetActiveUniformName"); glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC) load(userptr, "glGetActiveUniformsiv"); glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load(userptr, "glGetIntegeri_v"); glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC) load(userptr, "glGetUniformBlockIndex"); glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC) load(userptr, "glGetUniformIndices"); glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC) load(userptr, "glPrimitiveRestartIndex"); glad_glTexBuffer = (PFNGLTEXBUFFERPROC) load(userptr, "glTexBuffer"); glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC) load(userptr, "glUniformBlockBinding"); } static void glad_gl_load_GL_VERSION_3_2( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_3_2) return; glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) load(userptr, "glClientWaitSync"); glad_glDeleteSync = (PFNGLDELETESYNCPROC) load(userptr, "glDeleteSync"); glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC) load(userptr, "glDrawElementsBaseVertex"); glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) load(userptr, "glDrawElementsInstancedBaseVertex"); glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) load(userptr, "glDrawRangeElementsBaseVertex"); glad_glFenceSync = (PFNGLFENCESYNCPROC) load(userptr, "glFenceSync"); glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC) load(userptr, "glFramebufferTexture"); glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC) load(userptr, "glGetBufferParameteri64v"); glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC) load(userptr, "glGetInteger64i_v"); glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC) load(userptr, "glGetInteger64v"); glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) load(userptr, "glGetMultisamplefv"); glad_glGetSynciv = (PFNGLGETSYNCIVPROC) load(userptr, "glGetSynciv"); glad_glIsSync = (PFNGLISSYNCPROC) load(userptr, "glIsSync"); glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) load(userptr, "glMultiDrawElementsBaseVertex"); glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC) load(userptr, "glProvokingVertex"); glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC) load(userptr, "glSampleMaski"); glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC) load(userptr, "glTexImage2DMultisample"); glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) load(userptr, "glTexImage3DMultisample"); glad_glWaitSync = (PFNGLWAITSYNCPROC) load(userptr, "glWaitSync"); } static void glad_gl_load_GL_VERSION_3_3( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_3_3) return; glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) load(userptr, "glBindFragDataLocationIndexed"); glad_glBindSampler = (PFNGLBINDSAMPLERPROC) load(userptr, "glBindSampler"); glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC) load(userptr, "glDeleteSamplers"); glad_glGenSamplers = (PFNGLGENSAMPLERSPROC) load(userptr, "glGenSamplers"); glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC) load(userptr, "glGetFragDataIndex"); glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC) load(userptr, "glGetQueryObjecti64v"); glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC) load(userptr, "glGetQueryObjectui64v"); glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC) load(userptr, "glGetSamplerParameterIiv"); glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC) load(userptr, "glGetSamplerParameterIuiv"); glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC) load(userptr, "glGetSamplerParameterfv"); glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC) load(userptr, "glGetSamplerParameteriv"); glad_glIsSampler = (PFNGLISSAMPLERPROC) load(userptr, "glIsSampler"); glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC) load(userptr, "glQueryCounter"); glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC) load(userptr, "glSamplerParameterIiv"); glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC) load(userptr, "glSamplerParameterIuiv"); glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC) load(userptr, "glSamplerParameterf"); glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC) load(userptr, "glSamplerParameterfv"); glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC) load(userptr, "glSamplerParameteri"); glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC) load(userptr, "glSamplerParameteriv"); glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC) load(userptr, "glVertexAttribDivisor"); glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC) load(userptr, "glVertexAttribP1ui"); glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC) load(userptr, "glVertexAttribP1uiv"); glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC) load(userptr, "glVertexAttribP2ui"); glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC) load(userptr, "glVertexAttribP2uiv"); glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC) load(userptr, "glVertexAttribP3ui"); glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC) load(userptr, "glVertexAttribP3uiv"); glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC) load(userptr, "glVertexAttribP4ui"); glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC) load(userptr, "glVertexAttribP4uiv"); } static void glad_gl_load_GL_VERSION_4_0( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_4_0) return; glad_glBeginQueryIndexed = (PFNGLBEGINQUERYINDEXEDPROC) load(userptr, "glBeginQueryIndexed"); glad_glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC) load(userptr, "glBindTransformFeedback"); glad_glBlendEquationSeparatei = (PFNGLBLENDEQUATIONSEPARATEIPROC) load(userptr, "glBlendEquationSeparatei"); glad_glBlendEquationi = (PFNGLBLENDEQUATIONIPROC) load(userptr, "glBlendEquationi"); glad_glBlendFuncSeparatei = (PFNGLBLENDFUNCSEPARATEIPROC) load(userptr, "glBlendFuncSeparatei"); glad_glBlendFunci = (PFNGLBLENDFUNCIPROC) load(userptr, "glBlendFunci"); glad_glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC) load(userptr, "glDeleteTransformFeedbacks"); glad_glDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC) load(userptr, "glDrawArraysIndirect"); glad_glDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC) load(userptr, "glDrawElementsIndirect"); glad_glDrawTransformFeedback = (PFNGLDRAWTRANSFORMFEEDBACKPROC) load(userptr, "glDrawTransformFeedback"); glad_glDrawTransformFeedbackStream = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) load(userptr, "glDrawTransformFeedbackStream"); glad_glEndQueryIndexed = (PFNGLENDQUERYINDEXEDPROC) load(userptr, "glEndQueryIndexed"); glad_glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC) load(userptr, "glGenTransformFeedbacks"); glad_glGetActiveSubroutineName = (PFNGLGETACTIVESUBROUTINENAMEPROC) load(userptr, "glGetActiveSubroutineName"); glad_glGetActiveSubroutineUniformName = (PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) load(userptr, "glGetActiveSubroutineUniformName"); glad_glGetActiveSubroutineUniformiv = (PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) load(userptr, "glGetActiveSubroutineUniformiv"); glad_glGetProgramStageiv = (PFNGLGETPROGRAMSTAGEIVPROC) load(userptr, "glGetProgramStageiv"); glad_glGetQueryIndexediv = (PFNGLGETQUERYINDEXEDIVPROC) load(userptr, "glGetQueryIndexediv"); glad_glGetSubroutineIndex = (PFNGLGETSUBROUTINEINDEXPROC) load(userptr, "glGetSubroutineIndex"); glad_glGetSubroutineUniformLocation = (PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) load(userptr, "glGetSubroutineUniformLocation"); glad_glGetUniformSubroutineuiv = (PFNGLGETUNIFORMSUBROUTINEUIVPROC) load(userptr, "glGetUniformSubroutineuiv"); glad_glGetUniformdv = (PFNGLGETUNIFORMDVPROC) load(userptr, "glGetUniformdv"); glad_glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC) load(userptr, "glIsTransformFeedback"); glad_glMinSampleShading = (PFNGLMINSAMPLESHADINGPROC) load(userptr, "glMinSampleShading"); glad_glPatchParameterfv = (PFNGLPATCHPARAMETERFVPROC) load(userptr, "glPatchParameterfv"); glad_glPatchParameteri = (PFNGLPATCHPARAMETERIPROC) load(userptr, "glPatchParameteri"); glad_glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC) load(userptr, "glPauseTransformFeedback"); glad_glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC) load(userptr, "glResumeTransformFeedback"); glad_glUniform1d = (PFNGLUNIFORM1DPROC) load(userptr, "glUniform1d"); glad_glUniform1dv = (PFNGLUNIFORM1DVPROC) load(userptr, "glUniform1dv"); glad_glUniform2d = (PFNGLUNIFORM2DPROC) load(userptr, "glUniform2d"); glad_glUniform2dv = (PFNGLUNIFORM2DVPROC) load(userptr, "glUniform2dv"); glad_glUniform3d = (PFNGLUNIFORM3DPROC) load(userptr, "glUniform3d"); glad_glUniform3dv = (PFNGLUNIFORM3DVPROC) load(userptr, "glUniform3dv"); glad_glUniform4d = (PFNGLUNIFORM4DPROC) load(userptr, "glUniform4d"); glad_glUniform4dv = (PFNGLUNIFORM4DVPROC) load(userptr, "glUniform4dv"); glad_glUniformMatrix2dv = (PFNGLUNIFORMMATRIX2DVPROC) load(userptr, "glUniformMatrix2dv"); glad_glUniformMatrix2x3dv = (PFNGLUNIFORMMATRIX2X3DVPROC) load(userptr, "glUniformMatrix2x3dv"); glad_glUniformMatrix2x4dv = (PFNGLUNIFORMMATRIX2X4DVPROC) load(userptr, "glUniformMatrix2x4dv"); glad_glUniformMatrix3dv = (PFNGLUNIFORMMATRIX3DVPROC) load(userptr, "glUniformMatrix3dv"); glad_glUniformMatrix3x2dv = (PFNGLUNIFORMMATRIX3X2DVPROC) load(userptr, "glUniformMatrix3x2dv"); glad_glUniformMatrix3x4dv = (PFNGLUNIFORMMATRIX3X4DVPROC) load(userptr, "glUniformMatrix3x4dv"); glad_glUniformMatrix4dv = (PFNGLUNIFORMMATRIX4DVPROC) load(userptr, "glUniformMatrix4dv"); glad_glUniformMatrix4x2dv = (PFNGLUNIFORMMATRIX4X2DVPROC) load(userptr, "glUniformMatrix4x2dv"); glad_glUniformMatrix4x3dv = (PFNGLUNIFORMMATRIX4X3DVPROC) load(userptr, "glUniformMatrix4x3dv"); glad_glUniformSubroutinesuiv = (PFNGLUNIFORMSUBROUTINESUIVPROC) load(userptr, "glUniformSubroutinesuiv"); } static void glad_gl_load_GL_VERSION_4_1( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_4_1) return; glad_glActiveShaderProgram = (PFNGLACTIVESHADERPROGRAMPROC) load(userptr, "glActiveShaderProgram"); glad_glBindProgramPipeline = (PFNGLBINDPROGRAMPIPELINEPROC) load(userptr, "glBindProgramPipeline"); glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC) load(userptr, "glClearDepthf"); glad_glCreateShaderProgramv = (PFNGLCREATESHADERPROGRAMVPROC) load(userptr, "glCreateShaderProgramv"); glad_glDeleteProgramPipelines = (PFNGLDELETEPROGRAMPIPELINESPROC) load(userptr, "glDeleteProgramPipelines"); glad_glDepthRangeArrayv = (PFNGLDEPTHRANGEARRAYVPROC) load(userptr, "glDepthRangeArrayv"); glad_glDepthRangeIndexed = (PFNGLDEPTHRANGEINDEXEDPROC) load(userptr, "glDepthRangeIndexed"); glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC) load(userptr, "glDepthRangef"); glad_glGenProgramPipelines = (PFNGLGENPROGRAMPIPELINESPROC) load(userptr, "glGenProgramPipelines"); glad_glGetDoublei_v = (PFNGLGETDOUBLEI_VPROC) load(userptr, "glGetDoublei_v"); glad_glGetFloati_v = (PFNGLGETFLOATI_VPROC) load(userptr, "glGetFloati_v"); glad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC) load(userptr, "glGetProgramBinary"); glad_glGetProgramPipelineInfoLog = (PFNGLGETPROGRAMPIPELINEINFOLOGPROC) load(userptr, "glGetProgramPipelineInfoLog"); glad_glGetProgramPipelineiv = (PFNGLGETPROGRAMPIPELINEIVPROC) load(userptr, "glGetProgramPipelineiv"); glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC) load(userptr, "glGetShaderPrecisionFormat"); glad_glGetVertexAttribLdv = (PFNGLGETVERTEXATTRIBLDVPROC) load(userptr, "glGetVertexAttribLdv"); glad_glIsProgramPipeline = (PFNGLISPROGRAMPIPELINEPROC) load(userptr, "glIsProgramPipeline"); glad_glProgramBinary = (PFNGLPROGRAMBINARYPROC) load(userptr, "glProgramBinary"); glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC) load(userptr, "glProgramParameteri"); glad_glProgramUniform1d = (PFNGLPROGRAMUNIFORM1DPROC) load(userptr, "glProgramUniform1d"); glad_glProgramUniform1dv = (PFNGLPROGRAMUNIFORM1DVPROC) load(userptr, "glProgramUniform1dv"); glad_glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC) load(userptr, "glProgramUniform1f"); glad_glProgramUniform1fv = (PFNGLPROGRAMUNIFORM1FVPROC) load(userptr, "glProgramUniform1fv"); glad_glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC) load(userptr, "glProgramUniform1i"); glad_glProgramUniform1iv = (PFNGLPROGRAMUNIFORM1IVPROC) load(userptr, "glProgramUniform1iv"); glad_glProgramUniform1ui = (PFNGLPROGRAMUNIFORM1UIPROC) load(userptr, "glProgramUniform1ui"); glad_glProgramUniform1uiv = (PFNGLPROGRAMUNIFORM1UIVPROC) load(userptr, "glProgramUniform1uiv"); glad_glProgramUniform2d = (PFNGLPROGRAMUNIFORM2DPROC) load(userptr, "glProgramUniform2d"); glad_glProgramUniform2dv = (PFNGLPROGRAMUNIFORM2DVPROC) load(userptr, "glProgramUniform2dv"); glad_glProgramUniform2f = (PFNGLPROGRAMUNIFORM2FPROC) load(userptr, "glProgramUniform2f"); glad_glProgramUniform2fv = (PFNGLPROGRAMUNIFORM2FVPROC) load(userptr, "glProgramUniform2fv"); glad_glProgramUniform2i = (PFNGLPROGRAMUNIFORM2IPROC) load(userptr, "glProgramUniform2i"); glad_glProgramUniform2iv = (PFNGLPROGRAMUNIFORM2IVPROC) load(userptr, "glProgramUniform2iv"); glad_glProgramUniform2ui = (PFNGLPROGRAMUNIFORM2UIPROC) load(userptr, "glProgramUniform2ui"); glad_glProgramUniform2uiv = (PFNGLPROGRAMUNIFORM2UIVPROC) load(userptr, "glProgramUniform2uiv"); glad_glProgramUniform3d = (PFNGLPROGRAMUNIFORM3DPROC) load(userptr, "glProgramUniform3d"); glad_glProgramUniform3dv = (PFNGLPROGRAMUNIFORM3DVPROC) load(userptr, "glProgramUniform3dv"); glad_glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC) load(userptr, "glProgramUniform3f"); glad_glProgramUniform3fv = (PFNGLPROGRAMUNIFORM3FVPROC) load(userptr, "glProgramUniform3fv"); glad_glProgramUniform3i = (PFNGLPROGRAMUNIFORM3IPROC) load(userptr, "glProgramUniform3i"); glad_glProgramUniform3iv = (PFNGLPROGRAMUNIFORM3IVPROC) load(userptr, "glProgramUniform3iv"); glad_glProgramUniform3ui = (PFNGLPROGRAMUNIFORM3UIPROC) load(userptr, "glProgramUniform3ui"); glad_glProgramUniform3uiv = (PFNGLPROGRAMUNIFORM3UIVPROC) load(userptr, "glProgramUniform3uiv"); glad_glProgramUniform4d = (PFNGLPROGRAMUNIFORM4DPROC) load(userptr, "glProgramUniform4d"); glad_glProgramUniform4dv = (PFNGLPROGRAMUNIFORM4DVPROC) load(userptr, "glProgramUniform4dv"); glad_glProgramUniform4f = (PFNGLPROGRAMUNIFORM4FPROC) load(userptr, "glProgramUniform4f"); glad_glProgramUniform4fv = (PFNGLPROGRAMUNIFORM4FVPROC) load(userptr, "glProgramUniform4fv"); glad_glProgramUniform4i = (PFNGLPROGRAMUNIFORM4IPROC) load(userptr, "glProgramUniform4i"); glad_glProgramUniform4iv = (PFNGLPROGRAMUNIFORM4IVPROC) load(userptr, "glProgramUniform4iv"); glad_glProgramUniform4ui = (PFNGLPROGRAMUNIFORM4UIPROC) load(userptr, "glProgramUniform4ui"); glad_glProgramUniform4uiv = (PFNGLPROGRAMUNIFORM4UIVPROC) load(userptr, "glProgramUniform4uiv"); glad_glProgramUniformMatrix2dv = (PFNGLPROGRAMUNIFORMMATRIX2DVPROC) load(userptr, "glProgramUniformMatrix2dv"); glad_glProgramUniformMatrix2fv = (PFNGLPROGRAMUNIFORMMATRIX2FVPROC) load(userptr, "glProgramUniformMatrix2fv"); glad_glProgramUniformMatrix2x3dv = (PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) load(userptr, "glProgramUniformMatrix2x3dv"); glad_glProgramUniformMatrix2x3fv = (PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) load(userptr, "glProgramUniformMatrix2x3fv"); glad_glProgramUniformMatrix2x4dv = (PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) load(userptr, "glProgramUniformMatrix2x4dv"); glad_glProgramUniformMatrix2x4fv = (PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) load(userptr, "glProgramUniformMatrix2x4fv"); glad_glProgramUniformMatrix3dv = (PFNGLPROGRAMUNIFORMMATRIX3DVPROC) load(userptr, "glProgramUniformMatrix3dv"); glad_glProgramUniformMatrix3fv = (PFNGLPROGRAMUNIFORMMATRIX3FVPROC) load(userptr, "glProgramUniformMatrix3fv"); glad_glProgramUniformMatrix3x2dv = (PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) load(userptr, "glProgramUniformMatrix3x2dv"); glad_glProgramUniformMatrix3x2fv = (PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) load(userptr, "glProgramUniformMatrix3x2fv"); glad_glProgramUniformMatrix3x4dv = (PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) load(userptr, "glProgramUniformMatrix3x4dv"); glad_glProgramUniformMatrix3x4fv = (PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) load(userptr, "glProgramUniformMatrix3x4fv"); glad_glProgramUniformMatrix4dv = (PFNGLPROGRAMUNIFORMMATRIX4DVPROC) load(userptr, "glProgramUniformMatrix4dv"); glad_glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC) load(userptr, "glProgramUniformMatrix4fv"); glad_glProgramUniformMatrix4x2dv = (PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) load(userptr, "glProgramUniformMatrix4x2dv"); glad_glProgramUniformMatrix4x2fv = (PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) load(userptr, "glProgramUniformMatrix4x2fv"); glad_glProgramUniformMatrix4x3dv = (PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) load(userptr, "glProgramUniformMatrix4x3dv"); glad_glProgramUniformMatrix4x3fv = (PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) load(userptr, "glProgramUniformMatrix4x3fv"); glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC) load(userptr, "glReleaseShaderCompiler"); glad_glScissorArrayv = (PFNGLSCISSORARRAYVPROC) load(userptr, "glScissorArrayv"); glad_glScissorIndexed = (PFNGLSCISSORINDEXEDPROC) load(userptr, "glScissorIndexed"); glad_glScissorIndexedv = (PFNGLSCISSORINDEXEDVPROC) load(userptr, "glScissorIndexedv"); glad_glShaderBinary = (PFNGLSHADERBINARYPROC) load(userptr, "glShaderBinary"); glad_glUseProgramStages = (PFNGLUSEPROGRAMSTAGESPROC) load(userptr, "glUseProgramStages"); glad_glValidateProgramPipeline = (PFNGLVALIDATEPROGRAMPIPELINEPROC) load(userptr, "glValidateProgramPipeline"); glad_glVertexAttribL1d = (PFNGLVERTEXATTRIBL1DPROC) load(userptr, "glVertexAttribL1d"); glad_glVertexAttribL1dv = (PFNGLVERTEXATTRIBL1DVPROC) load(userptr, "glVertexAttribL1dv"); glad_glVertexAttribL2d = (PFNGLVERTEXATTRIBL2DPROC) load(userptr, "glVertexAttribL2d"); glad_glVertexAttribL2dv = (PFNGLVERTEXATTRIBL2DVPROC) load(userptr, "glVertexAttribL2dv"); glad_glVertexAttribL3d = (PFNGLVERTEXATTRIBL3DPROC) load(userptr, "glVertexAttribL3d"); glad_glVertexAttribL3dv = (PFNGLVERTEXATTRIBL3DVPROC) load(userptr, "glVertexAttribL3dv"); glad_glVertexAttribL4d = (PFNGLVERTEXATTRIBL4DPROC) load(userptr, "glVertexAttribL4d"); glad_glVertexAttribL4dv = (PFNGLVERTEXATTRIBL4DVPROC) load(userptr, "glVertexAttribL4dv"); glad_glVertexAttribLPointer = (PFNGLVERTEXATTRIBLPOINTERPROC) load(userptr, "glVertexAttribLPointer"); glad_glViewportArrayv = (PFNGLVIEWPORTARRAYVPROC) load(userptr, "glViewportArrayv"); glad_glViewportIndexedf = (PFNGLVIEWPORTINDEXEDFPROC) load(userptr, "glViewportIndexedf"); glad_glViewportIndexedfv = (PFNGLVIEWPORTINDEXEDFVPROC) load(userptr, "glViewportIndexedfv"); } #if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) #define GLAD_GL_IS_SOME_NEW_VERSION 1 #else #define GLAD_GL_IS_SOME_NEW_VERSION 0 #endif static int glad_gl_get_extensions( int version, const char **out_exts, unsigned int *out_num_exts_i, char ***out_exts_i) { #if GLAD_GL_IS_SOME_NEW_VERSION if(GLAD_VERSION_MAJOR(version) < 3) { #else (void) version; (void) out_num_exts_i; (void) out_exts_i; #endif if (glad_glGetString == NULL) { return 0; } *out_exts = (const char *)glad_glGetString(GL_EXTENSIONS); #if GLAD_GL_IS_SOME_NEW_VERSION } else { unsigned int index = 0; unsigned int num_exts_i = 0; char **exts_i = NULL; if (glad_glGetStringi == NULL || glad_glGetIntegerv == NULL) { return 0; } glad_glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i); if (num_exts_i > 0) { exts_i = (char **) malloc(num_exts_i * (sizeof *exts_i)); } if (exts_i == NULL) { return 0; } for(index = 0; index < num_exts_i; index++) { const char *gl_str_tmp = (const char*) glad_glGetStringi(GL_EXTENSIONS, index); size_t len = strlen(gl_str_tmp) + 1; char *local_str = (char*) malloc(len * sizeof(char)); if(local_str != NULL) { memcpy(local_str, gl_str_tmp, len * sizeof(char)); } exts_i[index] = local_str; } *out_num_exts_i = num_exts_i; *out_exts_i = exts_i; } #endif return 1; } static void glad_gl_free_extensions(char **exts_i, unsigned int num_exts_i) { if (exts_i != NULL) { unsigned int index; for(index = 0; index < num_exts_i; index++) { free((void *) (exts_i[index])); } free((void *)exts_i); exts_i = NULL; } } static int glad_gl_has_extension(int version, const char *exts, unsigned int num_exts_i, char **exts_i, const char *ext) { if(GLAD_VERSION_MAJOR(version) < 3 || !GLAD_GL_IS_SOME_NEW_VERSION) { const char *extensions; const char *loc; const char *terminator; extensions = exts; if(extensions == NULL || ext == NULL) { return 0; } while(1) { loc = strstr(extensions, ext); if(loc == NULL) { return 0; } terminator = loc + strlen(ext); if((loc == extensions || *(loc - 1) == ' ') && (*terminator == ' ' || *terminator == '\0')) { return 1; } extensions = terminator; } } else { unsigned int index; for(index = 0; index < num_exts_i; index++) { const char *e = exts_i[index]; if(strcmp(e, ext) == 0) { return 1; } } } return 0; } static GLADapiproc glad_gl_get_proc_from_userptr(void *userptr, const char* name) { return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); } static int glad_gl_find_extensions_gl( int version) { const char *exts = NULL; unsigned int num_exts_i = 0; char **exts_i = NULL; if (!glad_gl_get_extensions(version, &exts, &num_exts_i, &exts_i)) return 0; (void) glad_gl_has_extension; glad_gl_free_extensions(exts_i, num_exts_i); return 1; } static int glad_gl_find_core_gl(void) { int i; const char* version; const char* prefixes[] = { "OpenGL ES-CM ", "OpenGL ES-CL ", "OpenGL ES ", "OpenGL SC ", NULL }; int major = 0; int minor = 0; version = (const char*) glad_glGetString(GL_VERSION); if (!version) return 0; for (i = 0; prefixes[i]; i++) { const size_t length = strlen(prefixes[i]); if (strncmp(version, prefixes[i], length) == 0) { version += length; break; } } GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor); GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3; GLAD_GL_VERSION_4_0 = (major == 4 && minor >= 0) || major > 4; GLAD_GL_VERSION_4_1 = (major == 4 && minor >= 1) || major > 4; return GLAD_MAKE_VERSION(major, minor); } int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr) { int version; glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); if(glad_glGetString == NULL) return 0; if(glad_glGetString(GL_VERSION) == NULL) return 0; version = glad_gl_find_core_gl(); glad_gl_load_GL_VERSION_1_0(load, userptr); glad_gl_load_GL_VERSION_1_1(load, userptr); glad_gl_load_GL_VERSION_1_2(load, userptr); glad_gl_load_GL_VERSION_1_3(load, userptr); glad_gl_load_GL_VERSION_1_4(load, userptr); glad_gl_load_GL_VERSION_1_5(load, userptr); glad_gl_load_GL_VERSION_2_0(load, userptr); glad_gl_load_GL_VERSION_2_1(load, userptr); glad_gl_load_GL_VERSION_3_0(load, userptr); glad_gl_load_GL_VERSION_3_1(load, userptr); glad_gl_load_GL_VERSION_3_2(load, userptr); glad_gl_load_GL_VERSION_3_3(load, userptr); glad_gl_load_GL_VERSION_4_0(load, userptr); glad_gl_load_GL_VERSION_4_1(load, userptr); if (!glad_gl_find_extensions_gl(version)) return 0; return version; } int gladLoadGL( GLADloadfunc load) { return gladLoadGLUserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load); } #ifdef GLAD_GL #ifndef GLAD_LOADER_LIBRARY_C_ #define GLAD_LOADER_LIBRARY_C_ #include #include #if GLAD_PLATFORM_WIN32 #include #else #include #endif static void* glad_get_dlopen_handle(const char *lib_names[], int length) { void *handle = NULL; int i; for (i = 0; i < length; ++i) { #if GLAD_PLATFORM_WIN32 #if GLAD_PLATFORM_UWP size_t buffer_size = (strlen(lib_names[i]) + 1) * sizeof(WCHAR); LPWSTR buffer = (LPWSTR) malloc(buffer_size); if (buffer != NULL) { int ret = MultiByteToWideChar(CP_ACP, 0, lib_names[i], -1, buffer, buffer_size); if (ret != 0) { handle = (void*) LoadPackagedLibrary(buffer, 0); } free((void*) buffer); } #else handle = (void*) LoadLibraryA(lib_names[i]); #endif #else handle = dlopen(lib_names[i], RTLD_LAZY | RTLD_LOCAL); #endif if (handle != NULL) { return handle; } } return NULL; } static void glad_close_dlopen_handle(void* handle) { if (handle != NULL) { #if GLAD_PLATFORM_WIN32 FreeLibrary((HMODULE) handle); #else dlclose(handle); #endif } } static GLADapiproc glad_dlsym_handle(void* handle, const char *name) { if (handle == NULL) { return NULL; } #if GLAD_PLATFORM_WIN32 return (GLADapiproc) GetProcAddress((HMODULE) handle, name); #else return GLAD_GNUC_EXTENSION (GLADapiproc) dlsym(handle, name); #endif } #endif /* GLAD_LOADER_LIBRARY_C_ */ typedef void* (GLAD_API_PTR *GLADglprocaddrfunc)(const char*); struct _glad_gl_userptr { void *handle; GLADglprocaddrfunc gl_get_proc_address_ptr; }; static GLADapiproc glad_gl_get_proc(void *vuserptr, const char *name) { struct _glad_gl_userptr userptr = *(struct _glad_gl_userptr*) vuserptr; GLADapiproc result = NULL; if(userptr.gl_get_proc_address_ptr != NULL) { result = GLAD_GNUC_EXTENSION (GLADapiproc) userptr.gl_get_proc_address_ptr(name); } if(result == NULL) { result = glad_dlsym_handle(userptr.handle, name); } return result; } static void* _gl_handle = NULL; static void* glad_gl_dlopen_handle(void) { #if GLAD_PLATFORM_APPLE static const char *NAMES[] = { "../Frameworks/OpenGL.framework/OpenGL", "/Library/Frameworks/OpenGL.framework/OpenGL", "/System/Library/Frameworks/OpenGL.framework/OpenGL", "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" }; #elif GLAD_PLATFORM_WIN32 static const char *NAMES[] = {"opengl32.dll"}; #else static const char *NAMES[] = { #if defined(__CYGWIN__) "libGL-1.so", #endif "libGL.so.1", "libGL.so" }; #endif if (_gl_handle == NULL) { _gl_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0])); } return _gl_handle; } static struct _glad_gl_userptr glad_gl_build_userptr(void *handle) { struct _glad_gl_userptr userptr; userptr.handle = handle; #if GLAD_PLATFORM_APPLE || defined(__HAIKU__) userptr.gl_get_proc_address_ptr = NULL; #elif GLAD_PLATFORM_WIN32 userptr.gl_get_proc_address_ptr = (GLADglprocaddrfunc) glad_dlsym_handle(handle, "wglGetProcAddress"); #else userptr.gl_get_proc_address_ptr = (GLADglprocaddrfunc) glad_dlsym_handle(handle, "glXGetProcAddressARB"); #endif return userptr; } int gladLoaderLoadGL(void) { int version = 0; void *handle; int did_load = 0; struct _glad_gl_userptr userptr; did_load = _gl_handle == NULL; handle = glad_gl_dlopen_handle(); if (handle) { userptr = glad_gl_build_userptr(handle); version = gladLoadGLUserPtr(glad_gl_get_proc, &userptr); if (did_load) { gladLoaderUnloadGL(); } } return version; } void gladLoaderUnloadGL(void) { if (_gl_handle != NULL) { glad_close_dlopen_handle(_gl_handle); _gl_handle = NULL; } } #endif /* GLAD_GL */ #ifdef __cplusplus } #endif ================================================ FILE: lib/osgl/include/vapor/GLAD.h ================================================ #pragma once // Differentiate between gl and glad requirements #include ================================================ FILE: lib/osgl/include/vapor/GLContext.h ================================================ #pragma once #include //! \class GLContext //! \ingroup HeadlessGL //! \brief Object that abstracts an OpenGL context since they are differnet in every case. //! \author Stas Jaroszynski class OSGL_API GLContext { public: virtual ~GLContext() {} virtual void MakeCurrent() = 0; String GetVersion(); }; ================================================ FILE: lib/osgl/include/vapor/GLContextProvider.h ================================================ #pragma once #include //! \class GLContextProvider //! \ingroup HeadlessGL //! \brief Interface for creating an OpenGL context. //! \author Stas Jaroszynski class OSGL_API GLContextProvider { public: //! Creates an OpenGL context. The returned pointer is optional for managing //! multiple contexts. static GLContext *CreateContext(); static bool IsCurrentOpenGLVersionSupported(); private: static bool isContextOk(GLContext *ctx); }; ================================================ FILE: lib/osgl/include/vapor/GLContextProviderCommon.h ================================================ #pragma once #include #include #include #include typedef std::string String; using std::vector; #undef MacOS #undef Linux #undef Windows #if __APPLE__ #define MacOS 1 #elif __linux__ #define Linux 1 #elif WIN32 #define Windows 1 #endif #include "Log.h" ================================================ FILE: lib/osgl/include/vapor/GLContextProviderEGL.h ================================================ #pragma once #include //! \class GLContextProviderEGL //! \ingroup HeadlessGL //! \brief Creates an OpenGL context using the EGL library. //! \author Stas Jaroszynski class OSGL_API GLContextProviderEGL { class GLContextEGL : public GLContext { void *_display = nullptr; void *_surface = nullptr; void *_context = nullptr; public: GLContextEGL(void *display, void *surface, void *context); virtual ~GLContextEGL() override; virtual void MakeCurrent() override; }; public: static GLContext *CreateContext(); protected: static GLContext * createContextForDisplay(void *display); static const char *stringifyEGLError(int e); }; ================================================ FILE: lib/osgl/include/vapor/GLContextProviderMacOS.h ================================================ #pragma once #include //! \class GLContextProviderMacOS //! \ingroup HeadlessGL //! \brief Creates an OpenGL context using macOS's libraries. //! \author Stas Jaroszynski class OSGL_API GLContextProviderMacOS { class GLContextMacOS : public GLContext { void *_ctx = nullptr; public: GLContextMacOS(void *ctx); virtual ~GLContextMacOS() override; virtual void MakeCurrent() override; friend class GLContextProviderMacOS; }; public: static GLContext *CreateContext(); }; ================================================ FILE: lib/osgl/include/vapor/GLContextProviderMesa.h ================================================ #pragma once #include //! \class GLContextProviderMesa //! \ingroup HeadlessGL //! \brief Uses OSMesa for headless OpenGL Context creation. //! \author Stas Jaroszynski class OSGL_API GLContextProviderMesa { class GLContextMesa : public GLContext { void *_ctx = nullptr; char _dummyBuffer[4 * 4 * 3]; public: GLContextMesa(void *ctx); virtual ~GLContextMesa() override; virtual void MakeCurrent() override; void DumpParameters() const; }; public: static GLContext *CreateContext(); }; ================================================ FILE: lib/osgl/include/vapor/GLContextProviderNvidia.h ================================================ #pragma once #include //! \class GLContextProviderNvidia //! \ingroup HeadlessGL //! \brief Implements nvidia's API for headless OpenGL Context creation. //! \author Stas Jaroszynski class OSGL_API GLContextProviderNvidia : private GLContextProviderEGL { public: static GLContext *CreateContext(); }; ================================================ FILE: lib/osgl/include/vapor/GLContextProviderUtil.h ================================================ #pragma once #include class OSGL_API GLContextProviderUtil { public: static String GetGLVersion(); static void GetGLVersion(int *major, int *minor); }; ================================================ FILE: lib/osgl/include/vapor/GLInclude.h ================================================ #pragma once //#ifdef __APPLE__ // #define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED // #include //#else // #include //#endif #include "glad/gl.h" ================================================ FILE: lib/osgl/include/vapor/Log.h ================================================ #pragma once #include class OSGL_API Log { template static void print(String fmt, Args... args) { fmt += "\n"; printc(fmt.c_str(), args...); } static void printc(const char *format, ...); static void fatal(); public: static bool InfoLevelEnabled; static String AddLocationToFormat(const String &fmt, const char *file, int line); template static void Fatal(const String &fmt, Args... args) { print(fmt, args...); fatal(); } template static void Message(const String &fmt, Args... args) { print(fmt, args...); } template static void Info(const String &fmt, Args... args) { if (InfoLevelEnabled) print(fmt, args...); } template static void Warning(const String &fmt, Args... args) { print(fmt, args...); } }; #define _Log(type, fmt, ...) Log::type(Log::AddLocationToFormat(fmt, __FILE__, __LINE__), ##__VA_ARGS__) #define LogFatal(fmt, ...) _Log(Fatal, fmt, ##__VA_ARGS__) #define LogMessage(fmt, ...) _Log(Message, fmt, ##__VA_ARGS__) #define LogInfo(fmt, ...) _Log(Info, fmt, ##__VA_ARGS__) #define LogWarning(fmt, ...) _Log(Warning, fmt, ##__VA_ARGS__) ================================================ FILE: lib/osgl/meta.yaml ================================================ package: name: osgl version: "0.01" source: path: /osgl #build: # script: | # echo build ======================================================================================= # echo build ======================================================================================= # echo build ======================================================================================= # echo build ======================================================================================= # echo SRC_DIR=${SRC_DIR} # echo PREFIX=${PREFIX} # cd ${SRC_DIR} # pwd # echo build ======================================================================================= # echo build ======================================================================================= # echo build ======================================================================================= # echo build ======================================================================================= build: skip_compile_pyc: - "*.py" requirements: build: - make - cmake=3.21.3 - cppyy=2.2.0 # missing from vapor website - glm # This does not provide opengl apparently - mesalib - libglu - {{ cdt('mesa-libgl-devel') }} # [linux] - {{ cdt('mesa-libgl') }} # [linux] - {{ cdt('mesa-libegl-devel') }} # [linux] # - mesa-libegl-devel-cos6-x86_64 # - {{ cdt('mesa-dri-drivers') }} # [linux] # - {{ cdt('libselinux') }} # [linux] # - {{ cdt('libxdamage') }} # [linux] # - {{ cdt('libxxf86vm') }} # [linux] # - {{ cdt('libxext') }} # [linux] run: - mesalib ================================================ FILE: lib/osgl/stb_image_write.h ================================================ /* stb_image_write - v1.16 - public domain - http://nothings.org/stb writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 no warranty implied; use at your own risk Before #including, #define STB_IMAGE_WRITE_IMPLEMENTATION in the file that you want to have the implementation. Will probably not work correctly with strict-aliasing optimizations. ABOUT: This header file is a library for writing images to C stdio or a callback. The PNG output is not optimal; it is 20-50% larger than the file written by a decent optimizing implementation; though providing a custom zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. This library is designed for source code compactness and simplicity, not optimal image file size or run-time performance. BUILDING: You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace malloc,realloc,free. You can #define STBIW_MEMMOVE() to replace memmove() You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function for PNG compression (instead of the builtin one), it must have the following signature: unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); The returned data will be freed with STBIW_FREE() (free() by default), so it must be heap allocated with STBIW_MALLOC() (malloc() by default), UNICODE: If compiling for Windows and you wish to use Unicode filenames, compile with #define STBIW_WINDOWS_UTF8 and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert Windows wchar_t filenames to utf8. USAGE: There are five functions, one for each image file format: int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically There are also five equivalent functions that use an arbitrary write function. You are expected to open/close your file-equivalent before and after calling these: int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); where the callback is: void stbi_write_func(void *context, void *data, int size); You can configure it with these global variables: int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode You can define STBI_WRITE_NO_STDIO to disable the file variant of these functions, so the library will not use stdio.h at all. However, this will also disable HDR writing, because it requires stdio for formatted output. Each function returns 0 on failure and non-0 on success. The functions create an image file defined by the parameters. The image is a rectangle of pixels stored from left-to-right, top-to-bottom. Each pixel contains 'comp' channels of data stored interleaved with 8-bits per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. The *data pointer points to the first byte of the top-left-most pixel. For PNG, "stride_in_bytes" is the distance in bytes from the first byte of a row of pixels to the first byte of the next row of pixels. PNG creates output files with the same number of components as the input. The BMP format expands Y to RGB in the file format and does not output alpha. PNG supports writing rectangles of data even when the bytes storing rows of data are not consecutive in memory (e.g. sub-rectangles of a larger image), by supplying the stride between the beginning of adjacent rows. The other formats do not. (Thus you cannot write a native-format BMP through the BMP writer, both because it is in BGR order and because it may have padding at the end of the line.) PNG allows you to set the deflate compression level by setting the global variable 'stbi_write_png_compression_level' (it defaults to 8). HDR expects linear float data. Since the format is always 32-bit rgb(e) data, alpha (if provided) is discarded, and for monochrome data it is replicated across all three channels. TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed data, set the global variable 'stbi_write_tga_with_rle' to 0. JPEG does ignore alpha channels in input data; quality is between 1 and 100. Higher quality looks better but results in a bigger image. JPEG baseline (no JPEG progressive). CREDITS: Sean Barrett - PNG/BMP/TGA Baldur Karlsson - HDR Jean-Sebastien Guay - TGA monochrome Tim Kelsey - misc enhancements Alan Hickman - TGA RLE Emmanuel Julien - initial file IO callback implementation Jon Olick - original jo_jpeg.cpp code Daniel Gibson - integrate JPEG, allow external zlib Aarni Koskela - allow choosing PNG filter bugfixes: github:Chribba Guillaume Chereau github:jry2 github:romigrou Sergio Gonzalez Jonas Karlsson Filip Wasil Thatcher Ulrich github:poppolopoppo Patrick Boettcher github:xeekworx Cap Petschulat Simon Rodriguez Ivan Tikhonov github:ignotion Adam Schackart Andrew Kensler LICENSE See end of file for license information. */ #ifndef INCLUDE_STB_IMAGE_WRITE_H #define INCLUDE_STB_IMAGE_WRITE_H #include // if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' #ifndef STBIWDEF #ifdef STB_IMAGE_WRITE_STATIC #define STBIWDEF static #else #ifdef __cplusplus #define STBIWDEF extern "C" #else #define STBIWDEF extern #endif #endif #endif #ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations STBIWDEF int stbi_write_tga_with_rle; STBIWDEF int stbi_write_png_compression_level; STBIWDEF int stbi_write_force_png_filter; #endif #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); #ifdef STBIW_WINDOWS_UTF8 STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); #endif #endif typedef void stbi_write_func(void *context, void *data, int size); STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); #endif//INCLUDE_STB_IMAGE_WRITE_H #ifdef STB_IMAGE_WRITE_IMPLEMENTATION #ifdef _WIN32 #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif #ifndef _CRT_NONSTDC_NO_DEPRECATE #define _CRT_NONSTDC_NO_DEPRECATE #endif #endif #ifndef STBI_WRITE_NO_STDIO #include #endif // STBI_WRITE_NO_STDIO #include #include #include #include #if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) // ok #elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) // ok #else #error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." #endif #ifndef STBIW_MALLOC #define STBIW_MALLOC(sz) malloc(sz) #define STBIW_REALLOC(p,newsz) realloc(p,newsz) #define STBIW_FREE(p) free(p) #endif #ifndef STBIW_REALLOC_SIZED #define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) #endif #ifndef STBIW_MEMMOVE #define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) #endif #ifndef STBIW_ASSERT #include #define STBIW_ASSERT(x) assert(x) #endif #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) #ifdef STB_IMAGE_WRITE_STATIC static int stbi_write_png_compression_level = 8; static int stbi_write_tga_with_rle = 1; static int stbi_write_force_png_filter = -1; #else int stbi_write_png_compression_level = 8; int stbi_write_tga_with_rle = 1; int stbi_write_force_png_filter = -1; #endif static int stbi__flip_vertically_on_write = 0; STBIWDEF void stbi_flip_vertically_on_write(int flag) { stbi__flip_vertically_on_write = flag; } typedef struct { stbi_write_func *func; void *context; unsigned char buffer[64]; int buf_used; } stbi__write_context; // initialize a callback-based context static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) { s->func = c; s->context = context; } #ifndef STBI_WRITE_NO_STDIO static void stbi__stdio_write(void *context, void *data, int size) { fwrite(data,1,size,(FILE*) context); } #if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) #ifdef __cplusplus #define STBIW_EXTERN extern "C" #else #define STBIW_EXTERN extern #endif STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) { return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); } #endif static FILE *stbiw__fopen(char const *filename, char const *mode) { FILE *f; #if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) wchar_t wMode[64]; wchar_t wFilename[1024]; if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) return 0; if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) return 0; #if defined(_MSC_VER) && _MSC_VER >= 1400 if (0 != _wfopen_s(&f, wFilename, wMode)) f = 0; #else f = _wfopen(wFilename, wMode); #endif #elif defined(_MSC_VER) && _MSC_VER >= 1400 if (0 != fopen_s(&f, filename, mode)) f=0; #else f = fopen(filename, mode); #endif return f; } static int stbi__start_write_file(stbi__write_context *s, const char *filename) { FILE *f = stbiw__fopen(filename, "wb"); stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); return f != NULL; } static void stbi__end_write_file(stbi__write_context *s) { fclose((FILE *)s->context); } #endif // !STBI_WRITE_NO_STDIO typedef unsigned int stbiw_uint32; typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) { while (*fmt) { switch (*fmt++) { case ' ': break; case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); s->func(s->context,&x,1); break; } case '2': { int x = va_arg(v,int); unsigned char b[2]; b[0] = STBIW_UCHAR(x); b[1] = STBIW_UCHAR(x>>8); s->func(s->context,b,2); break; } case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4]; b[0]=STBIW_UCHAR(x); b[1]=STBIW_UCHAR(x>>8); b[2]=STBIW_UCHAR(x>>16); b[3]=STBIW_UCHAR(x>>24); s->func(s->context,b,4); break; } default: STBIW_ASSERT(0); return; } } } static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) { va_list v; va_start(v, fmt); stbiw__writefv(s, fmt, v); va_end(v); } static void stbiw__write_flush(stbi__write_context *s) { if (s->buf_used) { s->func(s->context, &s->buffer, s->buf_used); s->buf_used = 0; } } static void stbiw__putc(stbi__write_context *s, unsigned char c) { s->func(s->context, &c, 1); } static void stbiw__write1(stbi__write_context *s, unsigned char a) { if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) stbiw__write_flush(s); s->buffer[s->buf_used++] = a; } static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) { int n; if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) stbiw__write_flush(s); n = s->buf_used; s->buf_used = n+3; s->buffer[n+0] = a; s->buffer[n+1] = b; s->buffer[n+2] = c; } static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) { unsigned char bg[3] = { 255, 0, 255}, px[3]; int k; if (write_alpha < 0) stbiw__write1(s, d[comp - 1]); switch (comp) { case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case case 1: if (expand_mono) stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp else stbiw__write1(s, d[0]); // monochrome TGA break; case 4: if (!write_alpha) { // composite against pink background for (k = 0; k < 3; ++k) px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); break; } /* FALLTHROUGH */ case 3: stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); break; } if (write_alpha > 0) stbiw__write1(s, d[comp - 1]); } static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) { stbiw_uint32 zero = 0; int i,j, j_end; if (y <= 0) return; if (stbi__flip_vertically_on_write) vdir *= -1; if (vdir < 0) { j_end = -1; j = y-1; } else { j_end = y; j = 0; } for (; j != j_end; j += vdir) { for (i=0; i < x; ++i) { unsigned char *d = (unsigned char *) data + (j*x+i)*comp; stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); } stbiw__write_flush(s); s->func(s->context, &zero, scanline_pad); } } static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) { if (y < 0 || x < 0) { return 0; } else { va_list v; va_start(v, fmt); stbiw__writefv(s, fmt, v); va_end(v); stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); return 1; } } static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) { if (comp != 4) { // write RGB bitmap int pad = (-x*3) & 3; return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, "11 4 22 4" "4 44 22 444444", 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header } else { // RGBA bitmaps need a v4 header // use BI_BITFIELDS mode with 32bpp and alpha mask // (straight BI_RGB with alpha mask doesn't work in most readers) return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0, "11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444", 'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header } } STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) { stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_bmp_core(&s, x, y, comp, data); } #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) { stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_bmp_core(&s, x, y, comp, data); stbi__end_write_file(&s); return r; } else return 0; } #endif //!STBI_WRITE_NO_STDIO static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) { int has_alpha = (comp == 2 || comp == 4); int colorbytes = has_alpha ? comp-1 : comp; int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 if (y < 0 || x < 0) return 0; if (!stbi_write_tga_with_rle) { return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); } else { int i,j,k; int jend, jdir; stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); if (stbi__flip_vertically_on_write) { j = 0; jend = y; jdir = 1; } else { j = y-1; jend = -1; jdir = -1; } for (; j != jend; j += jdir) { unsigned char *row = (unsigned char *) data + j * x * comp; int len; for (i = 0; i < x; i += len) { unsigned char *begin = row + i * comp; int diff = 1; len = 1; if (i < x - 1) { ++len; diff = memcmp(begin, row + (i + 1) * comp, comp); if (diff) { const unsigned char *prev = begin; for (k = i + 2; k < x && len < 128; ++k) { if (memcmp(prev, row + k * comp, comp)) { prev += comp; ++len; } else { --len; break; } } } else { for (k = i + 2; k < x && len < 128; ++k) { if (!memcmp(begin, row + k * comp, comp)) { ++len; } else { break; } } } } if (diff) { unsigned char header = STBIW_UCHAR(len - 1); stbiw__write1(s, header); for (k = 0; k < len; ++k) { stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); } } else { unsigned char header = STBIW_UCHAR(len - 129); stbiw__write1(s, header); stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); } } } stbiw__write_flush(s); } return 1; } STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) { stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_tga_core(&s, x, y, comp, (void *) data); } #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) { stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); stbi__end_write_file(&s); return r; } else return 0; } #endif // ************************************************************************************************* // Radiance RGBE HDR writer // by Baldur Karlsson #define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) #ifndef STBI_WRITE_NO_STDIO static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) { int exponent; float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); if (maxcomp < 1e-32f) { rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; } else { float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; rgbe[0] = (unsigned char)(linear[0] * normalize); rgbe[1] = (unsigned char)(linear[1] * normalize); rgbe[2] = (unsigned char)(linear[2] * normalize); rgbe[3] = (unsigned char)(exponent + 128); } } static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) { unsigned char lengthbyte = STBIW_UCHAR(length+128); STBIW_ASSERT(length+128 <= 255); s->func(s->context, &lengthbyte, 1); s->func(s->context, &databyte, 1); } static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) { unsigned char lengthbyte = STBIW_UCHAR(length); STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code s->func(s->context, &lengthbyte, 1); s->func(s->context, data, length); } static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) { unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; unsigned char rgbe[4]; float linear[3]; int x; scanlineheader[2] = (width&0xff00)>>8; scanlineheader[3] = (width&0x00ff); /* skip RLE for images too small or large */ if (width < 8 || width >= 32768) { for (x=0; x < width; x++) { switch (ncomp) { case 4: /* fallthrough */ case 3: linear[2] = scanline[x*ncomp + 2]; linear[1] = scanline[x*ncomp + 1]; linear[0] = scanline[x*ncomp + 0]; break; default: linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; break; } stbiw__linear_to_rgbe(rgbe, linear); s->func(s->context, rgbe, 4); } } else { int c,r; /* encode into scratch buffer */ for (x=0; x < width; x++) { switch(ncomp) { case 4: /* fallthrough */ case 3: linear[2] = scanline[x*ncomp + 2]; linear[1] = scanline[x*ncomp + 1]; linear[0] = scanline[x*ncomp + 0]; break; default: linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; break; } stbiw__linear_to_rgbe(rgbe, linear); scratch[x + width*0] = rgbe[0]; scratch[x + width*1] = rgbe[1]; scratch[x + width*2] = rgbe[2]; scratch[x + width*3] = rgbe[3]; } s->func(s->context, scanlineheader, 4); /* RLE each component separately */ for (c=0; c < 4; c++) { unsigned char *comp = &scratch[width*c]; x = 0; while (x < width) { // find first run r = x; while (r+2 < width) { if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) break; ++r; } if (r+2 >= width) r = width; // dump up to first run while (x < r) { int len = r-x; if (len > 128) len = 128; stbiw__write_dump_data(s, len, &comp[x]); x += len; } // if there's a run, output it if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd // find next byte after run while (r < width && comp[r] == comp[x]) ++r; // output run up to r while (x < r) { int len = r-x; if (len > 127) len = 127; stbiw__write_run_data(s, len, comp[x]); x += len; } } } } } } static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) { if (y <= 0 || x <= 0 || data == NULL) return 0; else { // Each component is stored separately. Allocate scratch space for full output scanline. unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); int i, len; char buffer[128]; char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; s->func(s->context, header, sizeof(header)-1); #ifdef __STDC_LIB_EXT1__ len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #else len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #endif s->func(s->context, buffer, len); for(i=0; i < y; i++) stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); STBIW_FREE(scratch); return 1; } } STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) { stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_hdr_core(&s, x, y, comp, (float *) data); } STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) { stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); stbi__end_write_file(&s); return r; } else return 0; } #endif // STBI_WRITE_NO_STDIO ////////////////////////////////////////////////////////////////////////////// // // PNG writer // #ifndef STBIW_ZLIB_COMPRESS // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() #define stbiw__sbraw(a) ((int *) (void *) (a) - 2) #define stbiw__sbm(a) stbiw__sbraw(a)[0] #define stbiw__sbn(a) stbiw__sbraw(a)[1] #define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) #define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) #define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) #define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) #define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) #define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) { int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); STBIW_ASSERT(p); if (p) { if (!*arr) ((int *) p)[1] = 0; *arr = (void *) ((int *) p + 2); stbiw__sbm(*arr) = m; } return *arr; } static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) { while (*bitcount >= 8) { stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); *bitbuffer >>= 8; *bitcount -= 8; } return data; } static int stbiw__zlib_bitrev(int code, int codebits) { int res=0; while (codebits--) { res = (res << 1) | (code & 1); code >>= 1; } return res; } static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) { int i; for (i=0; i < limit && i < 258; ++i) if (a[i] != b[i]) break; return i; } static unsigned int stbiw__zhash(unsigned char *data) { stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); hash ^= hash << 3; hash += hash >> 5; hash ^= hash << 4; hash += hash >> 17; hash ^= hash << 25; hash += hash >> 6; return hash; } #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) #define stbiw__zlib_add(code,codebits) \ (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) #define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) // default huffman tables #define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) #define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) #define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) #define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) #define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) #define stbiw__ZHASH 16384 #endif // STBIW_ZLIB_COMPRESS STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) { #ifdef STBIW_ZLIB_COMPRESS // user provided a zlib compress implementation, use that return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); #else // use builtin static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; unsigned int bitbuf=0; int i,j, bitcount=0; unsigned char *out = NULL; unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); if (hash_table == NULL) return NULL; if (quality < 5) quality = 5; stbiw__sbpush(out, 0x78); // DEFLATE 32K window stbiw__sbpush(out, 0x5e); // FLEVEL = 1 stbiw__zlib_add(1,1); // BFINAL = 1 stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman for (i=0; i < stbiw__ZHASH; ++i) hash_table[i] = NULL; i=0; while (i < data_len-3) { // hash next 3 bytes of data to be compressed int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; unsigned char *bestloc = 0; unsigned char **hlist = hash_table[h]; int n = stbiw__sbcount(hlist); for (j=0; j < n; ++j) { if (hlist[j]-data > i-32768) { // if entry lies within window int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); if (d >= best) { best=d; bestloc=hlist[j]; } } } // when hash table entry is too long, delete half the entries if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); stbiw__sbn(hash_table[h]) = quality; } stbiw__sbpush(hash_table[h],data+i); if (bestloc) { // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); hlist = hash_table[h]; n = stbiw__sbcount(hlist); for (j=0; j < n; ++j) { if (hlist[j]-data > i-32767) { int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); if (e > best) { // if next match is better, bail on current match bestloc = NULL; break; } } } } if (bestloc) { int d = (int) (data+i - bestloc); // distance back STBIW_ASSERT(d <= 32767 && best <= 258); for (j=0; best > lengthc[j+1]-1; ++j); stbiw__zlib_huff(j+257); if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); for (j=0; d > distc[j+1]-1; ++j); stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); i += best; } else { stbiw__zlib_huffb(data[i]); ++i; } } // write out final bytes for (;i < data_len; ++i) stbiw__zlib_huffb(data[i]); stbiw__zlib_huff(256); // end of block // pad with 0 bits to byte boundary while (bitcount) stbiw__zlib_add(0,1); for (i=0; i < stbiw__ZHASH; ++i) (void) stbiw__sbfree(hash_table[i]); STBIW_FREE(hash_table); // store uncompressed instead if compression was worse if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) { stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 for (j = 0; j < data_len;) { int blocklen = data_len - j; if (blocklen > 32767) blocklen = 32767; stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8)); stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8)); memcpy(out+stbiw__sbn(out), data+j, blocklen); stbiw__sbn(out) += blocklen; j += blocklen; } } { // compute adler32 on input unsigned int s1=1, s2=0; int blocklen = (int) (data_len % 5552); j=0; while (j < data_len) { for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } s1 %= 65521; s2 %= 65521; j += blocklen; blocklen = 5552; } stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); stbiw__sbpush(out, STBIW_UCHAR(s2)); stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); stbiw__sbpush(out, STBIW_UCHAR(s1)); } *out_len = stbiw__sbn(out); // make returned pointer freeable STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); return (unsigned char *) stbiw__sbraw(out); #endif // STBIW_ZLIB_COMPRESS } static unsigned int stbiw__crc32(unsigned char *buffer, int len) { #ifdef STBIW_CRC32 return STBIW_CRC32(buffer, len); #else static unsigned int crc_table[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; unsigned int crc = ~0u; int i; for (i=0; i < len; ++i) crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; return ~crc; #endif } #define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) static void stbiw__wpcrc(unsigned char **data, int len) { unsigned int crc = stbiw__crc32(*data - len - 4, len+4); stbiw__wp32(*data, crc); } static unsigned char stbiw__paeth(int a, int b, int c) { int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); if (pb <= pc) return STBIW_UCHAR(b); return STBIW_UCHAR(c); } // @OPTIMIZE: provide an option that always forces left-predict or paeth predict static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) { static int mapping[] = { 0,1,2,3,4 }; static int firstmap[] = { 0,1,0,5,6 }; int *mymap = (y != 0) ? mapping : firstmap; int i; int type = mymap[filter_type]; unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; if (type==0) { memcpy(line_buffer, z, width*n); return; } // first loop isn't optimized since it's just one pixel for (i = 0; i < n; ++i) { switch (type) { case 1: line_buffer[i] = z[i]; break; case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; case 5: line_buffer[i] = z[i]; break; case 6: line_buffer[i] = z[i]; break; } } switch (type) { case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; } } STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) { int force_filter = stbi_write_force_png_filter; int ctype[5] = { -1, 0, 4, 2, 6 }; unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; unsigned char *out,*o, *filt, *zlib; signed char *line_buffer; int j,zlen; if (stride_bytes == 0) stride_bytes = x * n; if (force_filter >= 5) { force_filter = -1; } filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } for (j=0; j < y; ++j) { int filter_type; if (force_filter > -1) { filter_type = force_filter; stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); } else { // Estimate the best filter by running through all of them: int best_filter = 0, best_filter_val = 0x7fffffff, est, i; for (filter_type = 0; filter_type < 5; filter_type++) { stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); // Estimate the entropy of the line using this filter; the less, the better. est = 0; for (i = 0; i < x*n; ++i) { est += abs((signed char) line_buffer[i]); } if (est < best_filter_val) { best_filter_val = est; best_filter = filter_type; } } if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); filter_type = best_filter; } } // when we get here, filter_type contains the filter type, and line_buffer contains the data filt[j*(x*n+1)] = (unsigned char) filter_type; STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); } STBIW_FREE(line_buffer); zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); STBIW_FREE(filt); if (!zlib) return 0; // each tag requires 12 bytes of overhead out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); if (!out) return 0; *out_len = 8 + 12+13 + 12+zlen + 12; o=out; STBIW_MEMMOVE(o,sig,8); o+= 8; stbiw__wp32(o, 13); // header length stbiw__wptag(o, "IHDR"); stbiw__wp32(o, x); stbiw__wp32(o, y); *o++ = 8; *o++ = STBIW_UCHAR(ctype[n]); *o++ = 0; *o++ = 0; *o++ = 0; stbiw__wpcrc(&o,13); stbiw__wp32(o, zlen); stbiw__wptag(o, "IDAT"); STBIW_MEMMOVE(o, zlib, zlen); o += zlen; STBIW_FREE(zlib); stbiw__wpcrc(&o, zlen); stbiw__wp32(o,0); stbiw__wptag(o, "IEND"); stbiw__wpcrc(&o,0); STBIW_ASSERT(o == out + *out_len); return out; } #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) { FILE *f; int len; unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); if (png == NULL) return 0; f = stbiw__fopen(filename, "wb"); if (!f) { STBIW_FREE(png); return 0; } fwrite(png, 1, len, f); fclose(f); STBIW_FREE(png); return 1; } #endif STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) { int len; unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); if (png == NULL) return 0; func(context, png, len); STBIW_FREE(png); return 1; } /* *************************************************************************** * * JPEG writer * * This is based on Jon Olick's jo_jpeg.cpp: * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html */ static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { int bitBuf = *bitBufP, bitCnt = *bitCntP; bitCnt += bs[1]; bitBuf |= bs[0] << (24 - bitCnt); while(bitCnt >= 8) { unsigned char c = (bitBuf >> 16) & 255; stbiw__putc(s, c); if(c == 255) { stbiw__putc(s, 0); } bitBuf <<= 8; bitCnt -= 8; } *bitBufP = bitBuf; *bitCntP = bitCnt; } static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; float z1, z2, z3, z4, z5, z11, z13; float tmp0 = d0 + d7; float tmp7 = d0 - d7; float tmp1 = d1 + d6; float tmp6 = d1 - d6; float tmp2 = d2 + d5; float tmp5 = d2 - d5; float tmp3 = d3 + d4; float tmp4 = d3 - d4; // Even part float tmp10 = tmp0 + tmp3; // phase 2 float tmp13 = tmp0 - tmp3; float tmp11 = tmp1 + tmp2; float tmp12 = tmp1 - tmp2; d0 = tmp10 + tmp11; // phase 3 d4 = tmp10 - tmp11; z1 = (tmp12 + tmp13) * 0.707106781f; // c4 d2 = tmp13 + z1; // phase 5 d6 = tmp13 - z1; // Odd part tmp10 = tmp4 + tmp5; // phase 2 tmp11 = tmp5 + tmp6; tmp12 = tmp6 + tmp7; // The rotator is modified from fig 4-8 to avoid extra negations. z5 = (tmp10 - tmp12) * 0.382683433f; // c6 z2 = tmp10 * 0.541196100f + z5; // c2-c6 z4 = tmp12 * 1.306562965f + z5; // c2+c6 z3 = tmp11 * 0.707106781f; // c4 z11 = tmp7 + z3; // phase 5 z13 = tmp7 - z3; *d5p = z13 + z2; // phase 6 *d3p = z13 - z2; *d1p = z11 + z4; *d7p = z11 - z4; *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; } static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { int tmp1 = val < 0 ? -val : val; val = val < 0 ? val-1 : val; bits[1] = 1; while(tmp1 >>= 1) { ++bits[1]; } bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { } // end0pos = first element in reverse order !=0 if(end0pos == 0) { stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); return DU[0]; } for(i = 1; i <= end0pos; ++i) { int startpos = i; int nrzeroes; unsigned short bits[2]; for (; DU[i]==0 && i<=end0pos; ++i) { } nrzeroes = i-startpos; if ( nrzeroes >= 16 ) { int lng = nrzeroes>>4; int nrmarker; for (nrmarker=1; nrmarker <= lng; ++nrmarker) stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); nrzeroes &= 15; } stbiw__jpg_calcBits(DU[i], bits); stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); } if(end0pos != 63) { stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); } return DU[0]; } static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { // Constants that don't pollute global namespace static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; static const unsigned char std_ac_luminance_values[] = { 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa }; static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; static const unsigned char std_ac_chrominance_values[] = { 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa }; // Huffman tables static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; static const unsigned short YAC_HT[256][2] = { {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} }; static const unsigned short UVAC_HT[256][2] = { {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} }; static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; int row, col, i, k, subsample; float fdtbl_Y[64], fdtbl_UV[64]; unsigned char YTable[64], UVTable[64]; if(!data || !width || !height || comp > 4 || comp < 1) { return 0; } quality = quality ? quality : 90; subsample = quality <= 90 ? 1 : 0; quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; quality = quality < 50 ? 5000 / quality : 200 - quality * 2; for(i = 0; i < 64; ++i) { int uvti, yti = (YQT[i]*quality+50)/100; YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); uvti = (UVQT[i]*quality+50)/100; UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); } for(row = 0, k = 0; row < 8; ++row) { for(col = 0; col < 8; ++col, ++k) { fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); } } // Write Headers { static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; s->func(s->context, (void*)head0, sizeof(head0)); s->func(s->context, (void*)YTable, sizeof(YTable)); stbiw__putc(s, 1); s->func(s->context, UVTable, sizeof(UVTable)); s->func(s->context, (void*)head1, sizeof(head1)); s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); stbiw__putc(s, 0x10); // HTYACinfo s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); stbiw__putc(s, 1); // HTUDCinfo s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); stbiw__putc(s, 0x11); // HTUACinfo s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); s->func(s->context, (void*)head2, sizeof(head2)); } // Encode 8x8 macroblocks { static const unsigned short fillBits[] = {0x7F, 7}; int DCY=0, DCU=0, DCV=0; int bitBuf=0, bitCnt=0; // comp == 2 is grey+alpha (alpha is ignored) int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; const unsigned char *dataR = (const unsigned char *)data; const unsigned char *dataG = dataR + ofsG; const unsigned char *dataB = dataR + ofsB; int x, y, pos; if(subsample) { for(y = 0; y < height; y += 16) { for(x = 0; x < width; x += 16) { float Y[256], U[256], V[256]; for(row = y, pos = 0; row < y+16; ++row) { // row >= height => use last input row int clamped_row = (row < height) ? row : height - 1; int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; for(col = x; col < x+16; ++col, ++pos) { // if col >= width => use pixel from last input column int p = base_p + ((col < width) ? col : (width-1))*comp; float r = dataR[p], g = dataG[p], b = dataB[p]; Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; } } DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); // subsample U,V { float subU[64], subV[64]; int yy, xx; for(yy = 0, pos = 0; yy < 8; ++yy) { for(xx = 0; xx < 8; ++xx, ++pos) { int j = yy*32+xx*2; subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; } } DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); } } } } else { for(y = 0; y < height; y += 8) { for(x = 0; x < width; x += 8) { float Y[64], U[64], V[64]; for(row = y, pos = 0; row < y+8; ++row) { // row >= height => use last input row int clamped_row = (row < height) ? row : height - 1; int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; for(col = x; col < x+8; ++col, ++pos) { // if col >= width => use pixel from last input column int p = base_p + ((col < width) ? col : (width-1))*comp; float r = dataR[p], g = dataG[p], b = dataB[p]; Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; } } DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); } } } // Do the bit alignment of the EOI marker stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); } // EOI stbiw__putc(s, 0xFF); stbiw__putc(s, 0xD9); return 1; } STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) { stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); } #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) { stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); stbi__end_write_file(&s); return r; } else return 0; } #endif #endif // STB_IMAGE_WRITE_IMPLEMENTATION /* Revision history 1.16 (2021-07-11) make Deflate code emit uncompressed blocks when it would otherwise expand support writing BMPs with alpha channel 1.15 (2020-07-13) unknown 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels 1.13 1.12 1.11 (2019-08-11) 1.10 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs 1.09 (2018-02-11) fix typo in zlib quality API, improve STB_I_W_STATIC in C++ 1.08 (2018-01-29) add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter 1.07 (2017-07-24) doc fix 1.06 (2017-07-23) writing JPEG (using Jon Olick's code) 1.05 ??? 1.04 (2017-03-03) monochrome BMP expansion 1.03 ??? 1.02 (2016-04-02) avoid allocating large structures on the stack 1.01 (2016-01-16) STBIW_REALLOC_SIZED: support allocators with no realloc support avoid race-condition in crc initialization minor compile issues 1.00 (2015-09-14) installable file IO function 0.99 (2015-09-13) warning fixes; TGA rle support 0.98 (2015-04-08) added STBIW_MALLOC, STBIW_ASSERT etc 0.97 (2015-01-18) fixed HDR asserts, rewrote HDR rle logic 0.96 (2015-01-17) add HDR output fix monochrome BMP 0.95 (2014-08-17) add monochrome TGA output 0.94 (2014-05-31) rename private functions to avoid conflicts with stb_image.h 0.93 (2014-05-27) warning fixes 0.92 (2010-08-01) casts to unsigned char to fix warnings 0.91 (2010-07-17) first public release 0.90 first internal release */ /* ------------------------------------------------------------------------------ This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License Copyright (c) 2017 Sean Barrett Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ ALTERNATIVE B - Public Domain (www.unlicense.org) This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ */ ================================================ FILE: lib/osgl/test_framebuffer_glad.cpp ================================================ #include #include // #include //#include #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" #define GL_SILENCE_DEPRECATION #define GLERRTEST if (glGetError() != GL_NO_ERROR) printf("OPENGL ERROR\n"); int main(int argc, char **argv) { printf("Framebuffer test\n"); auto ctx = GLContextProvider::CreateContext(); assert(ctx); ctx->MakeCurrent(); LogMessage("Context: %s", glGetString(GL_VERSION)); GLuint _colorBuffer; glGenTextures(1, &_colorBuffer); glBindTexture(GL_TEXTURE_2D, _colorBuffer); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 100, 100, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); printf("[%i] About to gen framebuffer\n", __LINE__); GLuint _id; glGenFramebuffers(1, &_id); printf("[%i] Framebuffer generated: %i\n", __LINE__, _id); glBindFramebuffer(GL_FRAMEBUFFER, _id); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _colorBuffer, 0); glBindFramebuffer(GL_FRAMEBUFFER, _id); glViewport(0, 0, 100, 100); glClearColor(1.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glFlush(); unsigned char *pixels[100*100*3]; memset(pixels, 1, 100*100*3); glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(0, 0, 100, 100, GL_RGB, GL_UNSIGNED_BYTE, pixels); stbi_write_png("out-framebuffer-red.png", 100, 100, 3, pixels, 0); GLERRTEST; return 0; } ================================================ FILE: lib/osgl/test_version.cpp ================================================ #include #include int main(int argc, char **argv) { LogMessage("Version Test"); auto ctx = GLContextProvider::CreateContext(); assert(ctx); ctx->MakeCurrent(); LogMessage("Context: %s", glGetString(GL_VERSION)); return 0; } ================================================ FILE: lib/params/AnimationParams.cpp ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: AnimationParams.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: January 2005 // // Description: Implements the AnimationParams class // This is derived from the Params class // It contains all the parameters required for animation // #ifdef WIN32 // Annoying unreferenced formal parameter warning #pragma warning(disable : 4100) #endif #include #include using namespace VAPoR; const string AnimationParams::_maxRateTag = "MaxFrameRate"; const string AnimationParams::_startTimestepTag = "StartTimestep"; const string AnimationParams::_endTimestepTag = "EndTimestep"; const string AnimationParams::_currentTimestepTag = "CurrentTimestep"; const string AnimationParams::_playBackwardsTag = "PlayBackwards"; const string AnimationParams::CaptureStartTag = "CaptureStartTag"; const string AnimationParams::CaptureEndTag = "CaptureEndTag"; const string AnimationParams::CaptureModeTag = "CaptureModeTag"; const string AnimationParams::CaptureTypeTag = "CaptureTypeTag"; const string AnimationParams::CaptureFileNameTag = "CaptureFileNameTag"; const string AnimationParams::CaptureFileDirTag = "CaptureFileDirTag"; const string AnimationParams::CaptureFileTimeTag = "CaptureFileTimeTag"; const string AnimationParams::CaptureTimeSeriesFileNameTag = "CaptureTimeSeriesFileNameTag"; const string AnimationParams::CaptureTimeSeriesTimeTag = "CaptureTimeSeriesTimeTag"; // // Register class with object factory!!! // static ParamsRegistrar registrar(AnimationParams::GetClassType()); //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- AnimationParams::AnimationParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, AnimationParams::GetClassType()) { _init(); } AnimationParams::AnimationParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) { // If node isn't tagged correctly we correct the tag and reinitialize // from scratch; // if (node->GetTag() != AnimationParams::GetClassType()) { node->SetTag(AnimationParams::GetClassType()); _init(); } } //---------------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------------- AnimationParams::~AnimationParams() { MyBase::SetDiagMsg("AnimationParams::~AnimationParams() this=%p", this); } // Reset to initial state // void AnimationParams::_init() { // set everything to default state: SetPlayBackwards(false); SetStartTimestep(0); SetEndTimestep(10000000); SetCurrentTimestep(0); SetMaxFrameRate(10); SetValueLong(AnimationParams::CaptureModeTag, "Set default value for image capture mode", AnimationParams::SingleImage); SetValueLong(AnimationParams::CaptureTypeTag, "Set default value for capture mode image filetype", AnimationParams::TIFF); SetValueLong(AnimationParams::CaptureStartTag, "Set default value for capturing imagery start time", GetStartTimestep()); SetValueLong(AnimationParams::CaptureEndTag, "Set default value for capturing imagery end time", GetEndTimestep()); } ================================================ FILE: lib/params/AnnotationParams.cpp ================================================ //************************************************************************ // * // Copyright (C) 2015 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: AnnotationParams.cpp // // Author: Scott Pearse // Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: June 2015 // // Description: Implements the AnnotationParams class. // This class supports parameters associted with the // visualizer features in the annotation panel // #ifdef WIN32 // Annoying unreferenced formal parameter warning #pragma warning(disable : 4100) #endif #include #include #include #include using namespace VAPoR; const string AnnotationParams::_domainFrameTag = "DomainFrame"; const string AnnotationParams::_domainColorTag = "DomainColor"; const string AnnotationParams::_regionFrameTag = "RegionFrame"; const string AnnotationParams::_regionColorTag = "RegionColor"; const string AnnotationParams::_backgroundColorTag = "BackgroundColor"; const string AnnotationParams::_axisAnnotationEnabledTag = "AxisAnnotationiEnabled"; const string AnnotationParams::_axisColorTag = "AxisColor"; const string AnnotationParams::_axisDigitsTag = "AxisDigits"; const string AnnotationParams::_axisTextHeightTag = "AxisTextHeight"; const string AnnotationParams::_axisFontSizeTag = "AxisFontSize"; const string AnnotationParams::_ticWidthTag = "TicWidths"; const string AnnotationParams::_ticDirsTag = "TicDirections"; const string AnnotationParams::_ticSizeTag = "TicSizes"; const string AnnotationParams::_minTicsTag = "TicMinPositions"; const string AnnotationParams::_maxTicsTag = "TicMaxPositions"; const string AnnotationParams::_numTicsTag = "NumberTics"; const string AnnotationParams::_currentAxisDataMgrTag = "AxisDataMgr"; const string AnnotationParams::_latLonAxesTag = "LatLonAxes"; const string AnnotationParams::_axisOriginTag = "AxisOrigin"; const string AnnotationParams::AxisArrowEnabledTag = "ShowAxisArrows"; const string AnnotationParams::AxisArrowSizeTag = "AxisArrowSize"; const string AnnotationParams::AxisArrowXPosTag = "AxisArrowXPos"; const string AnnotationParams::AxisArrowYPosTag = "AxisArrowYPos"; const string AnnotationParams::_axisAnnotationsTag = "AxisAnnotations"; const string AnnotationParams::_timeLLXTag = "TimeLLX"; const string AnnotationParams::_timeLLYTag = "TimeLLY"; const string AnnotationParams::_timeColorTag = "TimeColor"; const string AnnotationParams::_timeTypeTag = "TimeType"; const string AnnotationParams::_timeSizeTag = "TimeSize"; const string AnnotationParams::_projStringTag = "ProjString"; vector AnnotationParams::_previousStretch; // // Register class with object factory!!! // static ParamsRegistrar registrar(AnnotationParams::GetClassType()); namespace { string defaultAnnotation = "default"; } AnnotationParams::AnnotationParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, AnnotationParams::GetClassType()) { _init(); _axisAnnotations = new ParamsContainer(ssave, _axisAnnotationsTag); _axisAnnotations->SetParent(this); } AnnotationParams::AnnotationParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) { if (node->HasChild(_axisAnnotationsTag)) { _axisAnnotations = new ParamsContainer(ssave, node->GetChild(_axisAnnotationsTag)); } else { _axisAnnotations = new ParamsContainer(ssave, _axisAnnotationsTag); _axisAnnotations->SetParent(this); } } AnnotationParams::AnnotationParams(const AnnotationParams &rhs) : ParamsBase(rhs) { _axisAnnotations = new ParamsContainer(*(rhs._axisAnnotations)); } void AnnotationParams::_init() { SetDomainColor({1.0,1.0,1.0}); SetRegionColor({1.0,0.0,0.0}); SetBackgroundColor({0.118,0.118,0.118}); SetUseRegionFrame(false); SetUseDomainFrame(true); SetValueLong(AxisArrowEnabledTag, "Initializing AxisArrowEnabledTag", 0); SetValueDouble(AxisArrowSizeTag, "Initializing AxisArrowSizeTag", .2); SetValueDouble(AxisArrowXPosTag, "Initializing AxisArrowXPosTag", .05); SetValueDouble(AxisArrowYPosTag, "Initializing AxisArrowYPosTag", .05); SetValueDouble(_timeLLXTag, "Initializing timestep llx coordinate", 0.01); SetValueDouble(_timeLLYTag, "Initializing timestep lly coordinate", 0.01); SetValueLong(_timeSizeTag, "Initializing timestep font size", 24); SetValueDoubleVec(_timeColorTag, "Initializing timestep color", {1., 1., 1.}); SetValueLong(_latLonAxesTag, "Initializing axis annotation enabled default", 0); } void AnnotationParams::_getColor(vector &color, string tag) const { color.clear(); vector defaultv(3, 1.0); color = GetValueDoubleVec(tag, defaultv); for (int i = 0; i < color.size(); i++) { if (color[i] < 0.0) color[i] = 0.0; if (color[i] > 1.0) color[i] = 1.0; } } void AnnotationParams::m_setColor(vector color, string tag, string msg) { VAssert(color.size() == 3); for (int i = 0; i < color.size(); i++) { if (color[i] < 0.0) color[i] = 0.0; if (color[i] > 1.0) color[i] = 1.0; } SetValueDoubleVec(tag, msg, color); } void AnnotationParams::GetDomainColor(double color[3]) const { m_getColor(color, _domainColorTag); } void AnnotationParams::SetDomainColor(vector color) { m_setColor(color, _domainColorTag, "Set domain frame color"); } void AnnotationParams::GetRegionColor(double color[3]) const { m_getColor(color, _regionColorTag); } void AnnotationParams::SetRegionColor(vector color) { m_setColor(color, _regionColorTag, "Set region frame color"); } void AnnotationParams::GetBackgroundColor(double color[3]) const { m_getColor(color, _backgroundColorTag); } void AnnotationParams::SetBackgroundColor(vector color) { m_setColor(color, _backgroundColorTag, "Set background color"); } string AnnotationParams::GetCurrentAxisDataMgrName() const { return GetValueString(_currentAxisDataMgrTag, defaultAnnotation); } void AnnotationParams::SetCurrentAxisDataMgrName(string dmName) { string msg = "Setting current DataMgr w.r.t. axis annotations"; SetValueString(_currentAxisDataMgrTag, msg, dmName); } AxisAnnotation *AnnotationParams::GetAxisAnnotation() { vector names = _axisAnnotations->GetNames(); if (_axisAnnotations->GetParams(defaultAnnotation) == NULL) { AxisAnnotation newAnnotation(_ssave); _axisAnnotations->Insert(&newAnnotation, defaultAnnotation); } AxisAnnotation *aa; aa = (AxisAnnotation *)_axisAnnotations->GetParams(defaultAnnotation); if (!aa->GetAxisAnnotationInitialized()) { aa->Initialize(); } return aa; } void AnnotationParams::SetAxisArrowEnabled(bool enabled) { SetValueLong(AxisArrowEnabledTag, "Set axis arrow to enabled/disabled", (long)enabled); } void AnnotationParams::SetAxisArrowSize(double val) { SetValueDouble(AxisArrowSizeTag, "Set axis arrow size", val); } void AnnotationParams::SetAxisArrowXPos(double val) { SetValueDouble(AxisArrowXPosTag, "Set axis arrow X coordinate", val); } void AnnotationParams::SetAxisArrowYPos(double val) { SetValueDouble(AxisArrowYPosTag, "Set axis arrow Y coordinate", val); } bool AnnotationParams::GetAxisArrowEnabled() const { return (bool)GetValueLong(AxisArrowEnabledTag, false); } double AnnotationParams::GetAxisArrowSize() const { return GetValueDouble(AxisArrowSizeTag, .2); } double AnnotationParams::GetAxisArrowXPos() const { return GetValueDouble(AxisArrowXPosTag, .05); } double AnnotationParams::GetAxisArrowYPos() const { return GetValueDouble(AxisArrowYPosTag, .05); } double AnnotationParams::GetTimeLLX() const { return GetValueDouble(_timeLLXTag, 0.01); } void AnnotationParams::SetTimeLLX(double llx) { SetValueDouble(_timeLLXTag, "Timestep llx coordinate", llx); } double AnnotationParams::GetTimeLLY() const { return GetValueDouble(_timeLLYTag, 0.01); } void AnnotationParams::SetTimeLLY(double lly) { SetValueDouble(_timeLLYTag, "Timestep lly coordinate", lly); } std::vector AnnotationParams::GetTimeColor() const { std::vector defaultv(3, 1.0); std::vector val = GetValueDoubleVec(_timeColorTag, defaultv); return val; } void AnnotationParams::SetTimeColor(vector color) { SetValueDoubleVec(_timeColorTag, "Timestep color", color); } int AnnotationParams::GetTimeType() const { return (int)GetValueLong(_timeTypeTag, 0); } void AnnotationParams::SetTimeType(int type) { SetValueLong(_timeTypeTag, "Timestep annotation type", type); } int AnnotationParams::GetTimeSize() const { return (int)GetValueDouble(_timeSizeTag, 24); } void AnnotationParams::SetTimeSize(int size) { SetValueDouble(_timeSizeTag, "Timestep font size", size); } ================================================ FILE: lib/params/AxisAnnotation.cpp ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: AxisAnnotation.cpp // // Author: Scott Pearse // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: May 2017 // // Description: Implements the AxisAnnotation class // Implements axis annotation ParamsContainer, which stores parameters // for Renderers or DataMgrs to draw axes. // #ifdef WIN32 // Annoying unreferenced formal parameter warning #pragma warning(disable : 4100) #endif #include #include using namespace VAPoR; using namespace Wasp; const string AxisAnnotation::_backgroundColorTag = "BackgroundColor"; const string AxisAnnotation::_annotationEnabledTag = "AxisAnnotation"; const string AxisAnnotation::_colorTag = "AxisColor"; const string AxisAnnotation::_digitsTag = "AxisDigits"; const string AxisAnnotation::_textHeightTag = "AxisTextHeight"; const string AxisAnnotation::_fontSizeTag = "AxisFontSize"; const string AxisAnnotation::_ticWidthTag = "TicWidths"; const string AxisAnnotation::_ticDirsTag = "TicDirections"; const string AxisAnnotation::_ticSizeTag = "TicSizes"; const string AxisAnnotation::_minTicsTag = "TicMinPositions"; const string AxisAnnotation::_maxTicsTag = "TicMaxPositions"; const string AxisAnnotation::_numTicsTag = "NumberTics"; const string AxisAnnotation::_dataMgrTag = "AxisDataMgr"; const string AxisAnnotation::_latLonAxesTag = "LatLonAxes"; const string AxisAnnotation::_originTag = "AxisOrigin"; const string AxisAnnotation::_initializedTag = "AxisAnnotaitonInitialized"; // // Register class with object factory!!! // static ParamsRegistrar registrar(AxisAnnotation::GetClassType()); //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- AxisAnnotation::AxisAnnotation(ParamsBase::StateSave *ssave) : ParamsBase(ssave, AxisAnnotation::GetClassType()) {} AxisAnnotation::AxisAnnotation(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {} //---------------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------------- AxisAnnotation::~AxisAnnotation() { MyBase::SetDiagMsg("AxisAnnotation::~AxisAnnotation() this=%p", this); } void AxisAnnotation::Initialize() { vector minExts(3, 0.0); vector maxExts(3, 1.0); SetMinTics(minExts); SetMaxTics(maxExts); SetAxisOrigin(minExts); SetValueDoubleVec(_backgroundColorTag, "Axis annotation background color", {0.0, 0.0, 0.0}); SetValueDoubleVec(_colorTag, "Axis annotation text color", {1.0, 1.0, 1.0}); SetValueLong(_fontSizeTag, "Axis annotation font size", 24); SetValueLong(_digitsTag, "Set axis num digits", 2); SetTicWidth(1); SetAxisAnnotationInitialized(true); } void AxisAnnotation::SetAxisAnnotationEnabled(bool val) { string msg = "Toggle axis annotation on/off"; SetValueLong(_annotationEnabledTag, msg, (long)val); } bool AxisAnnotation::GetAxisAnnotationEnabled() const { return (0 != GetValueLong(_annotationEnabledTag, (long)false)); } std::vector AxisAnnotation::GetAxisBackgroundColor() const { vector defaultv(4, 0.0); vector val = GetValueDoubleVec(_backgroundColorTag, defaultv); if (val == defaultv) val[3] = 1.f; return val; } void AxisAnnotation::SetAxisBackgroundColor(std::vector color) { string msg = "Axis annotation background color"; if (color.size() == 3) color.push_back(1.f); SetValueDoubleVec(_backgroundColorTag, msg, color); } std::vector AxisAnnotation::GetAxisColor() const { vector defaultv(4, 1.0); vector val = GetValueDoubleVec(_colorTag, defaultv); return val; } void AxisAnnotation::SetAxisColor(std::vector color) { return; string msg = "Axis annotation text color"; SetValueDoubleVec(_colorTag, msg, color); } void AxisAnnotation::SetNumTics(std::vector num) { VAssert(num.size() >= 2); for (int i = 0; i < num.size(); i++) { if (num[i] < 0) num[i] = 0; if (num[i] > 100) num[i] = 100; } SetValueDoubleVec(_numTicsTag, "Set number of axis tics", num); } std::vector AxisAnnotation::GetNumTics() const { vector defaultv = {3, 3, 2}; vector val = GetValueDoubleVec(_numTicsTag, defaultv); for (int i = 0; i < val.size(); i++) { if (val[i] < 0) val[i] = 0; if (val[i] > 100) val[i] = 100; } return (val); } void AxisAnnotation::SetAxisOrigin(vector orig) { VAssert(orig.size() >= 2); SetValueDoubleVec(_originTag, "Set axis val", orig); } vector AxisAnnotation::GetAxisOrigin() const { vector defaultv(3, 0.0); return GetValueDoubleVec(_originTag, defaultv); } void AxisAnnotation::SetMinTics(vector ticMin) { VAssert(ticMin.size() >= 2); SetValueDoubleVec(_minTicsTag, "Set minimum tics", ticMin); } vector AxisAnnotation::GetMinTics() const { vector defaultv(3, 0.0); return GetValueDoubleVec(_minTicsTag, defaultv); } void AxisAnnotation::SetMaxTics(vector ticMax) { VAssert(ticMax.size() >= 2); SetValueDoubleVec(_maxTicsTag, "Set maximum tics", ticMax); } vector AxisAnnotation::GetMaxTics() const { vector defaultv(3, 1.0); vector myVec = GetValueDoubleVec(_maxTicsTag, defaultv); return myVec; } void AxisAnnotation::SetTicSize(vector ticSizes) { VAssert(ticSizes.size() >= 2); SetValueDoubleVec(_ticSizeTag, "Set tic sizes", ticSizes); } vector AxisAnnotation::GetTicSize() const { vector defaultv(3, 0.05); return GetValueDoubleVec(_ticSizeTag, defaultv); } void AxisAnnotation::SetXTicDir(double dir) { std::vector v = GetTicDirs(); v[0] = dir; SetTicDirs(v); } int AxisAnnotation::GetXTicDir() const { return GetTicDirs()[0]; } int AxisAnnotation::GetYTicDir() const { return GetTicDirs()[1]; } int AxisAnnotation::GetZTicDir() const { return GetTicDirs()[2]; } void AxisAnnotation::SetYTicDir(double dir) { std::vector v = GetTicDirs(); v[1] = dir; SetTicDirs(v); } void AxisAnnotation::SetZTicDir(double dir) { std::vector v = GetTicDirs(); v[2] = dir; SetTicDirs(v); } void AxisAnnotation::SetTicDirs(vector ticDirs) { VAssert(ticDirs.size() >= 2); SetValueDoubleVec(_ticDirsTag, "Set tic direction", ticDirs); } vector AxisAnnotation::GetTicDirs() const { vector defaultv(3, 0); defaultv[0] = 1; return GetValueDoubleVec(_ticDirsTag, defaultv); } double AxisAnnotation::GetTicWidth() const { return GetValueDouble(_ticWidthTag, 1.0); } void AxisAnnotation::SetTicWidth(double width) { if (width < 1) width = 1; SetValueDouble(_ticWidthTag, "Set tic width", width); } long AxisAnnotation::GetAxisTextHeight() const { return GetValueLong(_textHeightTag, 10); } void AxisAnnotation::SetAxisTextHeight(long height) { if (height < 1) height = 1; SetValueLong(_textHeightTag, "Set axis text height", height); } long AxisAnnotation::GetAxisDigits() const { return GetValueLong(_digitsTag, 2); } void AxisAnnotation::SetAxisDigits(long numDigits) { if (numDigits < 0) numDigits = 4; SetValueLong(_digitsTag, "Set axis num digits", numDigits); } void AxisAnnotation::SetLatLonAxesEnabled(bool val) { SetValueLong(_latLonAxesTag, "toggle axes lat/lon", (long)val); } bool AxisAnnotation::GetLatLonAxesEnabled() const { return (0 != GetValueLong(_latLonAxesTag, (long)false)); } string AxisAnnotation::GetDataMgrName() const { return GetValueString(_dataMgrTag, ""); } void AxisAnnotation::SetDataMgrName(string dataMgr) { string msg = "Set DataManager currently associated " "with the axis annotations"; SetValueString(_dataMgrTag, msg, dataMgr); } void AxisAnnotation::SetAxisFontSize(int size) { SetValueDouble(_fontSizeTag, "Axis annotation font size", size); } int AxisAnnotation::GetAxisFontSize() const { return (int)GetValueDouble(_fontSizeTag, 16); } void AxisAnnotation::SetAxisAnnotationInitialized(bool val) { string msg = "Axis annotation object initialized"; SetValueDouble(_initializedTag, msg, val); } bool AxisAnnotation::GetAxisAnnotationInitialized() const { return (bool)GetValueDouble(_initializedTag, false); } ================================================ FILE: lib/params/BarbParams.cpp ================================================ #include #include #include #include using namespace Wasp; using namespace VAPoR; #define X 0 #define Y 1 #define Z 2 // // Register class with object factory!!! // static RenParamsRegistrar registrar(BarbParams::GetClassType()); const string BarbParams::_needToRecalculateScalesTag = "NeedToRecalc"; const string BarbParams::_thicknessScaleTag = "LineThickness"; const string BarbParams::_lengthScaleTag = "VectorScale"; const string BarbParams::_xBarbsCountTag = "BarbsCountTag_X"; const string BarbParams::_yBarbsCountTag = "BarbsCountTag_Y"; const string BarbParams::_zBarbsCountTag = "BarbsCountTag_Z"; const string BarbParams::_alignGridTag = "GridAlignedToData"; const string BarbParams::_alignGridStridesTag = "GridAlignedStrides"; const string BarbParams::_varsAre3dTag = "VarsAre3D"; BarbParams::BarbParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, BarbParams::GetClassType()) { SetDiagMsg("BarbParams::BarbParams() this=%p", this); _init(); } BarbParams::BarbParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node) {} BarbParams::~BarbParams() { SetDiagMsg("BarbParams::~BarbParams() this=%p", this); } void BarbParams::SetNeedToRecalculateScales(bool val) { double dval = val ? 1.0 : 0.0; SetValueDouble(_needToRecalculateScalesTag, "Whether or not scales need to be recalculated", dval); } void BarbParams::_init() { SetDiagMsg("BarbParams::_init()"); SetVariableName(""); SetUseSingleColor(false); float rgb[] = {1.f, 1.f, 1.f}; SetConstantColor(rgb); int grid[] = {10, 10, 1}; SetGrid(grid); SetLineThickness(1); SetLengthScale(1); SetValueLong(RenderParams::LightingEnabledTag, "Enable Barb lighting by default", 1); } ================================================ FILE: lib/params/BookmarkParams.cpp ================================================ //************************************************************************ // * // Copyright (C) 2016 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: BookmarkParams.cpp // // Author: Stas Jaroszynski // National Center for Atmospheric Research // PO 3000, Boulder, Colorado #include using namespace VAPoR; const string BookmarkParams::NameTag = "NameTag"; const string BookmarkParams::DataTag = "DataTag"; const string BookmarkParams::IconDataTag = "IconDataTag"; const string BookmarkParams::IconSizeTag = "IconSizeTag"; static ParamsRegistrar registrar(BookmarkParams::GetClassType()); void BookmarkParams::_init() {} BookmarkParams::BookmarkParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, GetClassType()) { _init(); } BookmarkParams::BookmarkParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) { if (node->GetTag() != BookmarkParams::GetClassType()) { node->SetTag(BookmarkParams::GetClassType()); _init(); } } BookmarkParams::BookmarkParams(const BookmarkParams &rhs) : ParamsBase(rhs) {} ================================================ FILE: lib/params/Box.cpp ================================================ //************************************************************************ // * // Copyright (C) 2011 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: Box.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: April 2011 // // Description: Implements the Box class. // Used to control extents and orientation of 2D and 3D data regions. // Supports time-varying extents. // #include #include #include "vapor/VAssert.h" #include #include using namespace std; using namespace VAPoR; using namespace Wasp; const std::string Box::m_anglesTag = "Angles"; const std::string Box::m_extentsTag = "Extents"; const std::string Box::m_planarTag = "Planar"; const std::string Box::m_orientationTag = "Orientation"; // // Register class with object factory!!! // static ParamsRegistrar registrar(Box::GetClassType()); Box::Box(ParamsBase::StateSave *ssave, string name) : ParamsBase(ssave, name) { MyBase::SetDiagMsg("Box::Box() this=%p", this); // Initialize with default box: // SetPlanar(false); vector minExt, maxExt; for (int i = 0; i < 3; i++) minExt.push_back(0.0); for (int i = 0; i < 3; i++) maxExt.push_back(1.0); SetExtents(minExt, maxExt); vector angles; angles.push_back(0.); angles.push_back(0.); angles.push_back(0.); SetAngles(angles); SetOrientation(XYZ); } Box::Box(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {} Box::~Box() { MyBase::SetDiagMsg("Box::~Box() this=%p", this); } void Box::SetExtents(const vector &minExt, const vector &maxExt) { VAssert(minExt.size() == maxExt.size()); vector exts; for (int i = 0; i < minExt.size(); i++) exts.push_back(minExt[i]); for (int i = minExt.size(); i < 3; i++) exts.push_back(0.0); for (int i = 0; i < maxExt.size(); i++) exts.push_back(maxExt[i]); for (int i = maxExt.size(); i < 3; i++) exts.push_back(0.0); SetValueDoubleVec(m_extentsTag, "Set box extents", exts); } void Box::SetExtents(const VAPoR::CoordType &minExt, const VAPoR::CoordType &maxExt) { vector mind(3, 0), maxd(3, 0); for (int i = 0; i < minExt.size(); i++) { mind[i] = minExt[i]; maxd[i] = maxExt[i]; } SetExtents(mind, maxd); } void Box::GetExtents(vector &minExt, vector &maxExt) const { minExt.clear(); maxExt.clear(); minExt.reserve(3); maxExt.reserve(3); vector defaultv; defaultv.reserve(6); for (int i = 0; i < 3; i++) defaultv.push_back(0.0); for (int i = 0; i < 3; i++) defaultv.push_back(1.0); // exts is guaranteed to have the same number of elements as // defaultv // vector exts = GetValueDoubleVec(m_extentsTag, defaultv); int n = IsPlanar() ? 2 : 3; for (int i = 0; i < n; i++) minExt.push_back(exts[i]); for (int i = 0; i < n; i++) maxExt.push_back(exts[i + 3]); } void Box::GetExtents(VAPoR::CoordType &minExt, VAPoR::CoordType &maxExt) const { minExt = {0.0, 0.0, 0.0}; maxExt = {0.0, 0.0, 0.0}; vector defaultv = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // exts is guaranteed to have the same number of elements as // defaultv // vector exts = GetValueDoubleVec(m_extentsTag, defaultv); int n = 3; for (int i = 0; i < n; i++) minExt[i] = exts[i]; for (int i = 0; i < n; i++) maxExt[i] = exts[i + 3]; } void Box::SetPlanar(bool value) { SetValueLong(Box::m_planarTag, "Set box planar value", (long)value); // SetValueLong(m_orientationTag, "", value?XYZ:XY); } bool Box::IsPlanar() const { return GetValueLong(Box::m_planarTag, (long)false); // return GetValueLong(Box::m_orientationTag, XY); } #ifdef VAPOR3_0_0_ALPHA int Box::GetStretchedLocalExtents(double extents[6], int timestep) { double exts[6]; int rc = GetLocalExtents(exts, timestep); if (rc) return rc; vector stretch = _dataStatus->getStretchFactors(); for (int i = 0; i < 6; i++) extents[i] = exts[i] * stretch[i % 3]; return 0; } #endif #ifdef VAPOR3_0_0_ALPHA int Box::SetStretchedLocalExtents(const double extents[6], int timestep) { vector exts; vector stretch = _dataStatus->getStretchFactors(); for (int i = 0; i < 6; i++) exts.push_back((double)(extents[i] / stretch[i % 3])); SetLocalExtents(exts, timestep); } #endif #ifdef VAPOR3_0_0_ALPHA void Box::buildLocalCoordTransform(double transformMatrix[12], double extraThickness, int timestep, double rotation, int axis) const { double theta, phi, psi; if (rotation != 0.) { convertThetaPhiPsi(&theta, &phi, &psi, axis, rotation); } else { vector angles = GetAngles(); theta = angles[0]; phi = angles[1]; psi = angles[2]; } double boxSize[3]; double boxExts[6]; GetLocalExtents(boxExts, timestep); for (int i = 0; i < 3; i++) { boxExts[i] -= extraThickness; boxExts[i + 3] += extraThickness; boxSize[i] = (boxExts[i + 3] - boxExts[i]); } // Get the 3x3 rotation matrix: double rotMatrix[9]; getRotationMatrix(theta * M_PI / 180., phi * M_PI / 180., psi * M_PI / 180., rotMatrix); // then scale according to box: transformMatrix[0] = 0.5 * boxSize[0] * rotMatrix[0]; transformMatrix[1] = 0.5 * boxSize[1] * rotMatrix[1]; transformMatrix[2] = 0.5 * boxSize[2] * rotMatrix[2]; // 2nd row: transformMatrix[4] = 0.5 * boxSize[0] * rotMatrix[3]; transformMatrix[5] = 0.5 * boxSize[1] * rotMatrix[4]; transformMatrix[6] = 0.5 * boxSize[2] * rotMatrix[5]; // 3rd row: transformMatrix[8] = 0.5 * boxSize[0] * rotMatrix[6]; transformMatrix[9] = 0.5 * boxSize[1] * rotMatrix[7]; transformMatrix[10] = 0.5 * boxSize[2] * rotMatrix[8]; // last column, i.e. translation: transformMatrix[3] = .5 * (boxExts[3] + boxExts[0]); transformMatrix[7] = .5 * (boxExts[4] + boxExts[1]); transformMatrix[11] = .5 * (boxExts[5] + boxExts[2]); } // Determine a new value of theta phi and psi when the probe is rotated around either the // x-, y-, or z- axis. axis is 0,1,or 2 1. rotation is in degrees. // newTheta and newPhi are in degrees, with theta between -180 and 180, phi between 0 and 180 // and newPsi between -180 and 180 void Box::convertThetaPhiPsi(double *newTheta, double *newPhi, double *newPsi, int axis, double rotation) const { // First, get original rotation matrix R0(theta, phi, psi) double origMatrix[9], axisRotate[9], newMatrix[9]; vector angles = GetAngles(); getRotationMatrix(angles[0] * M_PI / 180., angles[1] * M_PI / 180., angles[2] * M_PI / 180., origMatrix); // Second, get rotation matrix R1(axis,rotation) getAxisRotation(axis, rotation * M_PI / 180., axisRotate); // New rotation matrix is R1*R0 mmult33(axisRotate, origMatrix, newMatrix); // Calculate newTheta, newPhi, newPsi from R1*R0 getRotAngles(newTheta, newPhi, newPsi, newMatrix); // Convert back to degrees: (*newTheta) *= (180. / M_PI); (*newPhi) *= (180. / M_PI); (*newPsi) *= (180. / M_PI); return; } // Following calculates box corners in user space. Does not use // stretching. void Box::calcLocalBoxCorners(double corners[8][3], float extraThickness, int timestep, double rotation, int axis) const { double transformMatrix[12]; buildLocalCoordTransform(transformMatrix, extraThickness, timestep, rotation, axis); double boxCoord[3]; // Return the corners of the box (in world space) // Go counter-clockwise around the back, then around the front // X increases fastest, then y then z; // Fatten box slightly, in case it is degenerate. This will // prevent us from getting invalid face normals. boxCoord[0] = -1.f; boxCoord[1] = -1.f; boxCoord[2] = -1.f; vtransform(boxCoord, transformMatrix, corners[0]); boxCoord[0] = 1.f; vtransform(boxCoord, transformMatrix, corners[1]); boxCoord[1] = 1.f; vtransform(boxCoord, transformMatrix, corners[3]); boxCoord[0] = -1.f; vtransform(boxCoord, transformMatrix, corners[2]); boxCoord[1] = -1.f; boxCoord[2] = 1.f; vtransform(boxCoord, transformMatrix, corners[4]); boxCoord[0] = 1.f; vtransform(boxCoord, transformMatrix, corners[5]); boxCoord[1] = 1.f; vtransform(boxCoord, transformMatrix, corners[7]); boxCoord[0] = -1.f; vtransform(boxCoord, transformMatrix, corners[6]); } // Find the smallest stretched extents containing the rotated box // Similar to above, using stretched extents void Box::calcRotatedStretchedBoxExtents(vector stretchFactors, double *bigBoxExtents) const { // Determine the smallest axis-aligned cube that contains the probe. This is // obtained by mapping all 8 corners into the space. // It will not necessarily fit inside the unit cube. double corners[8][3]; calcLocalBoxCorners(corners, 0.f, -1); double boxMin[3], boxMax[3]; int crd, cor; // initialize extents, and variables that will be min,max for (crd = 0; crd < 3; crd++) { boxMin[crd] = DBL_MAX; boxMax[crd] = -DBL_MAX; } for (cor = 0; cor < 8; cor++) { // make sure the container includes it: for (crd = 0; crd < 3; crd++) { if (corners[cor][crd] < boxMin[crd]) boxMin[crd] = corners[cor][crd]; if (corners[cor][crd] > boxMax[crd]) boxMax[crd] = corners[cor][crd]; } } for (crd = 0; crd < 3; crd++) { bigBoxExtents[crd] = (boxMin[crd] * stretchFactors[crd]); bigBoxExtents[crd + 3] = (boxMax[crd] * stretchFactors[crd]); } } // Find the smallest extents containing the rotated box void Box::calcRotatedBoxExtents(double *bigBoxExtents) const { // Determine the smallest axis-aligned cube that contains the probe. This is // obtained by mapping all 8 corners into the space. // It will not necessarily fit inside the unit cube. double corners[8][3]; calcLocalBoxCorners(corners, 0.f, -1); double boxMin[3], boxMax[3]; int crd, cor; // initialize extents, and variables that will be min,max for (crd = 0; crd < 3; crd++) { boxMin[crd] = DBL_MAX; boxMax[crd] = -DBL_MAX; } for (cor = 0; cor < 8; cor++) { // make sure the container includes it: for (crd = 0; crd < 3; crd++) { if (corners[cor][crd] < boxMin[crd]) boxMin[crd] = corners[cor][crd]; if (corners[cor][crd] > boxMax[crd]) boxMax[crd] = corners[cor][crd]; } } // Now convert the min,max back into extents for (crd = 0; crd < 3; crd++) { bigBoxExtents[crd] = boxMin[crd]; bigBoxExtents[crd + 3] = boxMax[crd]; } } // Clip the probe to the specified box extents // Return false (and make no change) if the probe rectangle does not have a positive (rectangular) // intersection in the box. bool Box::cropToBox(const double bxExts[6]) { // 0. Initially need a startPoint that is in the box and on the probe center plane. // 1. Check if probe center works. If not call intersectRotatedBox() to get another startPoint (on middle plane) inside box. // 2. Using the new startPoint, construct x-direction line. Find its first two intersections (+ and -) with box. Reset the start point to be the // middle of the resulting line segment. // 3. Construct the y-direction line from the new startPoint. Again find first + and - intersection points. // 4. Take 4 diagonals of x- and y- direction lines, find first box intersection (or corner if box intersection is after corner. // 5. find largest rectangle inside four diagonal points. Use this as the new probe. // Transform the four probe corners to local region double transformMatrix[12]; double prCenter[3]; // original probe center in world coords double startPoint[3]; double pmid[3] = {0., 0., 0.}; double pxp[3] = {1., 0., 0.}; double pyp[3] = {0., 1., 0.}; double psize[2]; double prbexts[4]; // probe extents relative to startPoint, in the 2 probe axis directions. double probeCoords[2] = {0., 0.}; double pendx[3], pendy[3]; double exts[6]; GetLocalExtents(exts); double boxExts[6]; // shrink box slightly, otherwise errors occur with highly stretched domains. for (int i = 0; i < 3; i++) { boxExts[i] = bxExts[i] + (bxExts[i + 3] - bxExts[i]) * 1.e-4; boxExts[i + 3] = bxExts[i + 3] - (bxExts[i + 3] - bxExts[i]) * 1.e-4; } buildLocalCoordTransform(transformMatrix, 0.f, -1); // initially set startPoint to probe center: vtransform(pmid, transformMatrix, startPoint); vcopy(startPoint, prCenter); // Determine probe size in world coords. vtransform(pxp, transformMatrix, pendx); vtransform(pyp, transformMatrix, pendy); vsub(pendx, startPoint, pendx); vsub(pendy, startPoint, pendy); psize[0] = vlength(pendx); psize[1] = vlength(pendy); prbexts[2] = vlength(pendx); prbexts[3] = vlength(pendy); prbexts[0] = -prbexts[2]; prbexts[1] = -prbexts[3]; // Get direction vectors for rotated probe double rotMatrix[9]; const vector &angles = GetAngles(); getRotationMatrix((float)(angles[0] * M_PI / 180.), (float)(angles[1] * M_PI / 180.), (float)(angles[2] * M_PI / 180.), rotMatrix); // determine the probe x- and y- direction vectors double vecx[3] = {1., 0., 0.}; double vecy[3] = {0., 1., 0.}; // Direction vectors: double dir[4][3]; // Intersection parameters double result[4][2]; double edgeDist[4]; // distances from start point to probe edges // Construct 2 rays in x-axis directions vtransform3(vecx, rotMatrix, dir[0]); vtransform3(vecy, rotMatrix, dir[1]); vnormal(dir[0]); vnormal(dir[1]); // also negate: vmult(dir[0], -1.f, dir[2]); vmult(dir[1], -1.f, dir[3]); // Test: is startPoint inside box? bool pointInBox = true; for (int i = 0; i < 3; i++) { if (startPoint[i] < boxExts[i]) { pointInBox = false; break; } if (startPoint[i] > boxExts[i + 3]) { pointInBox = false; break; } } if (!pointInBox) { pointInBox = intersectRotatedBox(boxExts, startPoint, probeCoords); if (!pointInBox) return false; // Modify prbexts to have probe exts relative to new value of startPoint // probeCoords values are along the dir[0] and dir[1] directions, with a value of +1 indicating the probe x-width // Thus the startPoint in world coords is // prCenter + psize[0]*probeCoords[0]*dir[0] + psize[1]*probeCoords[1]*dir[1] // and the probe extents are similarly translated: prbexts[0] = prbexts[0] - probeCoords[0] * psize[0]; prbexts[2] = prbexts[2] - probeCoords[0] * psize[0]; prbexts[1] = prbexts[1] - probeCoords[1] * psize[1]; prbexts[3] = prbexts[3] - probeCoords[1] * psize[1]; } // Shoot rays in axis directions from startPoint. // Intersect each line with the box, get the nearest intersections int numpts; for (int i = 0; i < 4; i += 2) { numpts = rayBoxIntersect(startPoint, dir[i], boxExts, result[i]); // Each ray should have two intersection points with the box if (numpts < 2 || result[i][1] < 0.0) return false; // find the distance from the start point to the second intersection point double interpt[3]; // calculate the intersection point for (int j = 0; j < 3; j++) { interpt[j] = result[i][1] * dir[i][j] + startPoint[j]; } // find the distances from the intersection points to starting point for (int j = 0; j < 3; j++) { interpt[j] = interpt[j] - startPoint[j]; } edgeDist[i] = vlength(interpt); // shorten the distance if it exceeds the probe extent in that direction if (i == 0 && edgeDist[i] > prbexts[2]) edgeDist[i] = prbexts[2]; if (i == 2 && edgeDist[i] > -prbexts[0]) edgeDist[i] = -prbexts[0]; } // Find the midpoint of the line connecting the x intersections double midDist = edgeDist[0] - edgeDist[2]; // Move startPoint to the center for (int i = 0; i < 3; i++) { startPoint[i] = startPoint[i] + dir[0][i] * midDist * 0.5; } // Modify edgeDist so that the new startPoint is the center. edgeDist[0] = edgeDist[2] = 0.5 * (edgeDist[0] + edgeDist[2]); // Now shoot rays in the y directions for (int i = 1; i < 4; i += 2) { numpts = rayBoxIntersect(startPoint, dir[i], boxExts, result[i]); // Each ray should have two intersection points with the box if (numpts < 2 || result[i][1] < 0.0) return false; // find the distance from the start point to the second intersection point double interpt[3]; // calculate the intersection point for (int j = 0; j < 3; j++) { interpt[j] = result[i][1] * dir[i][j] + startPoint[j]; } // find the distances from the intersection points to starting point for (int j = 0; j < 3; j++) { interpt[j] = interpt[j] - startPoint[j]; } edgeDist[i] = vlength(interpt); // Shorten the distance if it exceeds the probe if (i == 1 && edgeDist[i] > prbexts[3]) edgeDist[i] = prbexts[3]; if (i == 3 && edgeDist[i] > -prbexts[1]) edgeDist[i] = -prbexts[1]; } // Now shoot rays in the diagonal directions from startPoint. // First determine the diagonal directions and the distances to the diagonal corners double diagDirs[4][3]; double diagDist[4]; for (int j = 0; j < 4; j++) { // Determine vector from startPoint to corner: for (int i = 0; i < 3; i++) { diagDirs[j][i] = edgeDist[j] * dir[j][i] + edgeDist[(j + 1) % 4] * dir[(j + 1) % 4][i]; } diagDist[j] = vlength(diagDirs[j]); vnormal(diagDirs[j]); } // Now shoot rays in the diagonal directions double diagInterDist[4]; double diagInterPt[4][3]; double component[4][2]; // components of the resulting diagonals along probe x and y axes for (int i = 0; i < 4; i++) { numpts = rayBoxIntersect(startPoint, diagDirs[i], bxExts, result[i]); // Each ray should have two intersection points with the box if (numpts < 2 || result[i][1] < 0.0) return false; // and result[i][1] is the distance along diagonal i to intersection 1 // find the distance from the start point to the second intersection point // calculate the intersection point for (int j = 0; j < 3; j++) { diagInterPt[i][j] = result[i][1] * diagDirs[i][j] + startPoint[j]; } // find the distances from the intersection points to starting point double interVec[3]; for (int j = 0; j < 3; j++) { interVec[j] = diagInterPt[i][j] - startPoint[j]; } diagInterDist[i] = vlength(interVec); // Make sure the diagonal distance does not exceed the distance to the corner double shrinkFactor = 1.; if (diagInterDist[i] > diagDist[i]) { shrinkFactor = diagDist[i] / diagInterDist[i]; } // project in probe directions to get components: component[i][0] = vdot(dir[0], diagDirs[i]) * result[i][1] * shrinkFactor; component[i][1] = vdot(dir[1], diagDirs[i]) * result[i][1] * shrinkFactor; } // Find the x,y extents (relative to startPoint): double pExts[4]; // maxx must be the smaller of the two x displacements: pExts[2] = Min(component[3][0], component[0][0]); // maxx pExts[0] = Max(component[1][0], component[2][0]); // minx pExts[1] = Max(component[2][1], component[3][1]); // miny pExts[3] = Min(component[0][1], component[1][1]); // maxy double wid = pExts[2] - pExts[0]; double ht = pExts[3] - pExts[1]; // New probe center is translated from startPoint by average of extents: // add dir[0]*(pexts[2]+pexts[0])*.5 to move probe x coordinate, similarly for y: // Use dir[] to hold the resulting displacements. double probeCenter[3]; vcopy(startPoint, probeCenter); vmult(dir[0], 0.5 * (pExts[0] + pExts[2]), dir[0]); vmult(dir[1], 0.5 * (pExts[1] + pExts[3]), dir[1]); vadd(startPoint, dir[0], probeCenter); vadd(probeCenter, dir[1], probeCenter); double depth = exts[5] - exts[2]; // apply these as offsets to startPoint, to get probe local extents. // Don't change the z extents. exts[0] = probeCenter[0] - wid * 0.5; exts[1] = probeCenter[1] - ht * 0.5; exts[3] = probeCenter[0] + wid * 0.5; exts[4] = probeCenter[1] + ht * 0.5; exts[2] = probeCenter[2] - depth * 0.5; exts[5] = probeCenter[2] + depth * 0.5; SetLocalExtents(exts); return true; } // Find a point that lies in the probe plane and in a box, if the probe intersects a face of the box. // Return false if there is no such intersection bool Box::intersectRotatedBox(double boxExts[6], double intersectPoint[3], double probeCoords[2]) { // Transform the four probe corners to local region double transformMatrix[12]; double cor[4][3]; // probe corners in local user coords double pcorn[3] = {0., 0., 0.}; // local probe corner coordinates buildLocalCoordTransform(transformMatrix, 0.f, -1); bool cornerInFace[4][6]; for (int i = 0; i < 4; i++) { // make pcorn rotate counter-clockwise around probe pcorn[0] = -1.; pcorn[1] = -1.; if (i > 1) pcorn[1] = 1.; if (i == 1 || i == 2) pcorn[0] = 1.; vtransform(pcorn, transformMatrix, cor[i]); for (int k = 0; k < 3; k++) { // Classify each corner as to whether it is inside or outside the half-space defined by each face // cornerInFace[i][j] is true if the cor[i][j] is inside the half-space if (cor[i][k] <= boxExts[k]) cornerInFace[i][k] = false; else cornerInFace[i][k] = true; if (cor[i][k] >= boxExts[k + 3]) cornerInFace[i][k + 3] = false; else cornerInFace[i][k + 3] = true; } } // initialize probe min & max: double minx = -1., miny = -1.; double maxx = 1., maxy = 1.; // 2. For each box face: for (int face = 0; face < 6; face++) { int faceDim = face % 3; //(x, y, or z-oriented face) int faceDir = face / 3; // either low or high face // Intersect this face with four sides of probe. // A side of probe is determined by line (1-t)*cor[k] + t*cor[(k+1)%4], going from cor[k] to cor[k+1] // for each pair of corners, equation is // (1-t)*cor[k][faceDim] + t*cor[k+1][faceDim] = boxExts[faceDim+faceDir*3] // t*(cor[(k+1)%4][faceDim] - cor[k][faceDim]) = boxExts[faceDim+faceDir*3] - cor[k][faceDim] // i.e.: t = (boxExts[faceDim+faceDir*3] - cor[k][faceDim])/(cor[(k+1)%4][faceDim] - cor[k][faceDim]); int interNum = 0; double interPoint[2][3]; double interT[2]; int interSide[2]; // a. determine either 2 or 0 intersection points between probe boundary and box face, by intersecting all sides of probe with face for (int k = 0; k < 4; k++) { double denom = (cor[(k + 1) % 4][faceDim] - cor[k][faceDim]); if (denom == 0.) continue; double t = (boxExts[faceDim + faceDir * 3] - cor[k][faceDim]) / denom; if (t < 0. || t > 1.) continue; for (int j = 0; j < 3; j++) { interPoint[interNum][j] = (1. - t) * cor[k][j] + t * cor[(k + 1) % 4][j]; } // Replace t with T, going from -1 to +1, increasing with x and y // This simplifies the logic later. if (k > 1) t = 1. - t; // make t increase with x and y interT[interNum] = 2. * t - 1.; // make T go from -1 to 1 instead of 0 to 1 interSide[interNum] = k; interNum++; } VAssert(interNum == 0 || interNum == 2); // Are there two intersections? if (interNum == 2) { // are they on opposite sides? if (interSide[1] - interSide[0] == 2) { // Does it intersect the two horizonal edges? if (interSide[0] == 0) { // is vertex 0 in this half-space? If so use min t-coordinate to cut the probe max x-extents if (cornerInFace[interSide[0]][face]) { double mint = Min(interT[0], interT[1]); if (maxx > mint) maxx = mint; } else { // must be vertex 0 is outside half-space, so use maxt to trim probe min x-extents double maxt = Max(interT[0], interT[1]); if (minx < maxt) minx = maxt; } } else { // It must intersect the two vertical edges, check if vertex 0 is inside half-space VAssert(interSide[0] == 1); if (cornerInFace[interSide[0]][face]) { double mint = Min(interT[0], interT[1]); if (maxy > mint) maxy = mint; } else { // must be vertex 0 is outside half-space, so use max to trim double maxt = Max(interT[0], interT[1]); if (miny < maxt) miny = maxt; } } } else { // The two intersections must cut off a corner of the probe // The possible cases for interSide's are: 0,1 (cuts of vertex 1); 0,3 (cuts off vertex 0); // 1,2 (cuts off vertex 2); 2,3(cuts off vertex 3); each case can exclude or include the corner vertex if (interSide[0] == 0 && interSide[1] == 1) { // new corner is midpoint of line between the two intersection points. double newcorx = 0.5 * (interT[0] + 1.); double newcory = 0.5 * (interT[1] - 1.); if (cornerInFace[interSide[1]][face]) { // if vertex 1 is inside then minx must be at least as large as newcorx, maxy as small as newcory minx = Max(minx, newcorx); maxy = Min(maxy, newcory); } else { // maxx must be as small as newcorx, miny must be as large as newcory maxx = Min(maxx, newcorx); miny = Max(miny, newcory); } } else if (interSide[0] == 0 && interSide[1] == 3) { // new corner is midpoint of line between the two intersection points. double newcorx = 0.5 * (interT[0] - 1.); double newcory = 0.5 * (interT[1] - 1.); if (cornerInFace[interSide[0]][face]) { // if vertex 0 is inside then maxx must be at least as small as newcorx, maxy as small as newcory maxx = Min(maxx, newcorx); maxy = Min(maxy, newcory); } else { // minx must be as large as newcorx, miny must be as large as newcory minx = Max(minx, newcorx); miny = Max(miny, newcory); } } else if (interSide[0] == 1 && interSide[1] == 2) { // new corner is midpoint of line between the two intersection points. double newcory = 0.5 * (interT[0] + 1.); double newcorx = 0.5 * (interT[1] + 1.); if (cornerInFace[interSide[1]][face]) { // if vertex 2 is inside then minx must be at least as large as newcorx, miny as large as newcory minx = Max(minx, newcorx); miny = Max(miny, newcory); } else { // maxx must be as small as newcorx, maxy must be as small as newcory maxx = Min(maxx, newcorx); maxy = Min(maxy, newcory); } } else if (interSide[0] == 2 && interSide[1] == 3) { // new corner is midpoint of line between the two intersection points. double newcorx = 0.5 * (interT[0] - 1.); double newcory = 0.5 * (interT[1] + 1.); if (cornerInFace[interSide[1]][face]) { // if vertex 3 is inside then maxx must be at least as small as newcorx, miny as large as newcory maxx = Min(maxx, newcorx); minx = Max(miny, newcory); } else { // minx must be as large as newcorx, maxy must be as small as newcory minx = Max(minx, newcorx); maxy = Min(maxy, newcory); } } else VAssert(0); } // end of cutting off corner } else { // If no intersections, check if the probe is completely outside slab determined by the face // If any corner is outside, entire probe is outside, so check first corner if (faceDir == 0 && cor[0][faceDim] < boxExts[face]) return false; if (faceDir == 1 && cor[0][faceDim] > boxExts[face]) return false; // OK, entire probe is inside this face } } // finished with all 6 faces. // Use minx, miny, maxx, maxy to find a rectangle in probe and box // 3. rectangle defined as intersection of all limits found // probeCoords uses middle: probeCoords[0] = 0.5 * (minx + maxx); probeCoords[1] = 0.5 * (miny + maxy); // convert minx, miny, maxx, maxy to interpolate between 0 and 1 (instead of -1 and +1) maxx = 0.5 * (maxx + 1.); maxy = 0.5 * (maxy + 1.); minx = 0.5 * (minx + 1.); miny = 0.5 * (miny + 1.); // Determine center of intersection (in world coords) by bilinearly interpolating from corners using minx, maxx, miny,maxy, // then taking average. double newCor[4][3]; for (int k = 0; k < 3; k++) { newCor[0][k] = ((1. - minx) * cor[0][k] + minx * cor[1][k]) * (1. - miny) + miny * ((1. - minx) * cor[3][k] + minx * cor[2][k]); newCor[1][k] = ((1. - maxx) * cor[0][k] + maxx * cor[1][k]) * (1. - miny) + miny * ((1. - maxx) * cor[3][k] + maxx * cor[2][k]); newCor[2][k] = ((1. - maxx) * cor[0][k] + maxx * cor[1][k]) * (1. - maxy) + maxy * ((1. - maxx) * cor[3][k] + maxx * cor[2][k]); newCor[3][k] = ((1. - minx) * cor[0][k] + minx * cor[1][k]) * (1. - maxy) + maxy * ((1. - minx) * cor[3][k] + minx * cor[2][k]); intersectPoint[k] = 0.25 * (newCor[0][k] + newCor[1][k] + newCor[2][k] + newCor[3][k]); } return true; } // Find probe extents that are maximal and fit in box bool Box::fitToBox(const double boxExts[6]) { // Increase the box if it is flat: double modBoxExts[6]; for (int i = 0; i < 3; i++) { modBoxExts[i] = boxExts[i]; modBoxExts[i + 3] = boxExts[i + 3]; if (boxExts[i] >= boxExts[i + 3]) { if (boxExts[i] > 0.f) { modBoxExts[i] = boxExts[i] * 0.99999f; modBoxExts[i + 3] = boxExts[i] * 1.00001f; } else if (boxExts[i] < 0.f) { modBoxExts[i] = boxExts[i] * 1.00001f; modBoxExts[i + 3] = boxExts[i] * 0.99999f; } else { modBoxExts[i] = -1.e-20f; modBoxExts[i + 3] = 1.e-20f; } } } // find a point in the probe that lies in the box. Do this by finding the intersections // of the box with the probe plane and averaging the resulting points: double startPoint[3]; double interceptPoints[6][3]; int numintercept = interceptBox(modBoxExts, interceptPoints); if (numintercept < 3) return false; vzero(startPoint); for (int i = 0; i < numintercept; i++) { for (int j = 0; j < 3; j++) { startPoint[j] += interceptPoints[i][j] * (1.f / (double)numintercept); } } // Expand the probe so that it will exceed the box extents in all dimensions // Begin with the startPoint and intersect horizontal rays with the far edges of the box. double probeCenter[3]; double exts[6]; GetLocalExtents(exts); for (int i = 0; i < 3; i++) probeCenter[i] = 0.5 * (exts[i] + exts[i + 3]); double rotMatrix[9]; const vector &angles = GetAngles(); getRotationMatrix((float)(angles[0] * M_PI / 180.), (float)(angles[1] * M_PI / 180.), (float)(angles[2] * M_PI / 180.), rotMatrix); // determine the probe x- and y- direction vectors double vecx[3] = {1., 0., 0.}; double vecy[3] = {0., 1., 0.}; // Direction vectors: double dir[4][3]; // Intersection parameters double result[4][2]; double edgeDist[4]; // distances from center to probe edges // Construct 4 rays in axis directions vtransform3(vecx, rotMatrix, dir[0]); vtransform3(vecy, rotMatrix, dir[1]); vnormal(dir[0]); vnormal(dir[1]); // also negate: vmult(dir[0], -1.f, dir[2]); vmult(dir[1], -1.f, dir[3]); // Intersect with each line int numpts; for (int i = 0; i < 4; i++) { numpts = rayBoxIntersect(startPoint, dir[i], modBoxExts, result[i]); // Each ray should have two intersection points with the box if (numpts < 2 || result[i][1] < 0.f) return false; } // Use the distance from the probe center to the second intersection point as the new probe size for (int i = 0; i < 4; i++) { double interpt[3]; // calculate the intersection point for (int j = 0; j < 3; j++) { interpt[j] = result[i][1] * dir[i][j] + startPoint[j]; } // find the distance from the intersection point to the probe center for (int j = 0; j < 3; j++) { interpt[j] = interpt[j] - probeCenter[j]; } edgeDist[i] = vlength(interpt); } // Stretch a bit to ensure adequate coverage double wid = 2.1 * Max(edgeDist[0], edgeDist[2]); double ht = 2.1 * Max(edgeDist[1], edgeDist[3]); double depth = abs(exts[5] - exts[2]); exts[0] = probeCenter[0] - 0.5f * wid; exts[3] = probeCenter[0] + 0.5f * wid; exts[1] = probeCenter[1] - 0.5f * ht; exts[4] = probeCenter[1] + 0.5f * ht; exts[2] = probeCenter[2] - 0.5f * depth; exts[5] = probeCenter[2] + 0.5f * depth; SetLocalExtents(exts); bool success = cropToBox(boxExts); // bool success = true; return success; } // Calculate up to six intersections of box edges with probe plane, return the number found. // Up to 6 intersection points are placed in intercept array int Box::interceptBox(const double boxExts[6], double intercept[6][3]) { int numfound = 0; // Get the equation of the probe plane // First, find normal to plane: double rotMatrix[9]; const double vecz[3] = {0., 0., 1.}; const double vec0[3] = {0., 0., 0.}; double probeNormal[3], probeCenter[3]; const vector &angles = GetAngles(); getRotationMatrix((float)(angles[0] * M_PI / 180.), (float)(angles[1] * M_PI / 180.), (float)(angles[2] * M_PI / 180.), rotMatrix); vtransform3(vecz, rotMatrix, probeNormal); double transformMatrix[12]; buildLocalCoordTransform(transformMatrix, 0.01, -1); vtransform(vec0, transformMatrix, probeCenter); vnormal(probeNormal); // The equation of the probe plane is dot(V, probeNormal) = dst: double dst = vdot(probeNormal, probeCenter); // Now intersect the plane with all 6 edges of box. // each edge is defined by two equations of the form // x = boxExts[0] or boxExts[3]; y = boxExts[1] or boxExts[4]; z = boxExts[2] or boxExts[5] for (int edge = 0; edge < 12; edge++) { // edge%3 is the coordinate that varies; // equation holds (edge+1)%3 to low or high value, based on (edge/3)%2 // holds (edge+2) to low or high value based on (edge/6) // Thus equations associated with edge are: // vcoord = edge%3, coord1 is (edge+1)%3, coord2 is (edge+2)%3; // boxExts[vcoord] <= pt[vcoord] <= boxExts[vcoord+3] // pt[coord1] = boxExts[coord1+3*((edge/3)%2)] // pt[coord2] = boxExts[coord2+3*((edge/6))] int vcoord = edge % 3; int coord1 = (edge + 1) % 3; int coord2 = (edge + 2) % 3; double rhs = dst - boxExts[coord1 + 3 * ((edge / 3) % 2)] * probeNormal[coord1] - boxExts[coord2 + 3 * (edge / 6)] * probeNormal[coord2]; // and the equation is V*probeNormal[vcoord] = rhs // Question is whether the other (vcoord) coordinate of the intersection point lies between // boxExts[vcoord] and boxExts[vcoord+3] if (probeNormal[vcoord] == 0.f) continue; if (rhs / probeNormal[vcoord] < boxExts[vcoord]) continue; if (rhs / probeNormal[vcoord] > boxExts[vcoord + 3]) continue; // Intersection found! intercept[numfound][coord1] = boxExts[coord1 + 3 * ((edge / 3) % 2)]; intercept[numfound][coord2] = boxExts[coord2 + 3 * (edge / 6)]; intercept[numfound][vcoord] = rhs / probeNormal[vcoord]; numfound++; if (numfound == 6) return numfound; } return numfound; } void Box::getRotatedVoxelExtents(string varname, float voxdims[2], int numRefinements) { StructuredGrid *rGrid = GetDataMgr()->GetVariable(_dataStatus->getMinTimestep(), varname, numRefinements, 0); VAssert(rGrid); double exts[6], fullSizes[3]; rGrid->GetUserExtents(exts); for (int i = 0; i < 3; i++) fullSizes[i] = exts[i + 3] - exts[i]; double sliceCoord[3]; // Can ignore depth, just mapping center plane sliceCoord[2] = 0.f; double transformMatrix[12]; // Set up to transform from probe into volume: buildLocalCoordTransform(transformMatrix, 0.f, -1); // Get the data dimensions (at this resolution): size_t dataSize[3]; // Start by initializing integer extents rGrid->GetDimensions(dataSize); double cor[4][3]; for (int cornum = 0; cornum < 4; cornum++) { double dataCoord[3]; // coords relative to (-1,1) sliceCoord[1] = -1.f + 2. * (double)(cornum / 2); sliceCoord[0] = -1.f + 2. * (double)(cornum % 2); // Then transform to values in data vtransform(sliceCoord, transformMatrix, dataCoord); // Then get array coords: for (int i = 0; i < 3; i++) { cor[cornum][i] = ((double)dataSize[i]) * (dataCoord[i]) / (fullSizes[i]); } } double vecWid[3], vecHt[3]; vsub(cor[1], cor[0], vecWid); vsub(cor[3], cor[1], vecHt); voxdims[0] = vlength(vecWid); voxdims[1] = vlength(vecHt); return; } void Box::rotateAndRenormalize(int axis, double rotVal) { // Now finalize the rotation double newTheta, newPhi, newPsi; convertThetaPhiPsi(&newTheta, &newPhi, &newPsi, axis, rotVal); double angles[3]; angles[0] = newTheta; angles[1] = newPhi; angles[2] = newPsi; SetAngles(angles); return; } void Box::setBoxToExtents(const double extents[6]) { // First try to fit to extents. If we fail, then move to fit bool success = fitToBox(extents); if (success) return; // Move the box so that it is centered in the extents: double pExts[6]; GetLocalExtents(pExts); for (int i = 0; i < 3; i++) { double psize = pExts[i + 3] - pExts[i]; pExts[i] = 0.5 * (extents[i] + extents[i + 3] - psize); pExts[i + 3] = 0.5 * (extents[i] + extents[i + 3] + psize); } SetLocalExtents(pExts, -1); success = fitToBox(extents); VAssert(success); return; } #endif ================================================ FILE: lib/params/CMakeLists.txt ================================================ set (SRC XmlNode.cpp ParamsBase.cpp ColorMap.cpp OpacityMap.cpp MapperFunction.cpp Box.cpp ColorbarPbase.cpp RenderParams.cpp TwoDDataParams.cpp BarbParams.cpp Viewpoint.cpp Transform.cpp ViewpointParams.cpp regionparams.cpp ParamsMgr.cpp DataStatus.cpp AnnotationParams.cpp HelloParams.cpp ImageParams.cpp TFInterpolator.cpp ContourParams.cpp RayCasterParams.cpp AxisAnnotation.cpp WireFrameParams.cpp SliceParams.cpp DatasetsParams.cpp FlowParams.cpp VolumeParams.cpp VolumeIsoParams.cpp ModelParams.cpp ParticleParams.cpp AnimationParams.cpp MouseModeParams.cpp BookmarkParams.cpp GUIStateParams.cpp SettingsParams.cpp ) set (HEADERS ${PROJECT_SOURCE_DIR}/include/vapor/XmlNode.h ${PROJECT_SOURCE_DIR}/include/vapor/ParamsBase.h ${PROJECT_SOURCE_DIR}/include/vapor/ColorMap.h ${PROJECT_SOURCE_DIR}/include/vapor/OpacityMap.h ${PROJECT_SOURCE_DIR}/include/vapor/MapperFunction.h ${PROJECT_SOURCE_DIR}/include/vapor/Box.h ${PROJECT_SOURCE_DIR}/include/vapor/ColorbarPbase.h ${PROJECT_SOURCE_DIR}/include/vapor/RenderParams.h ${PROJECT_SOURCE_DIR}/include/vapor/TwoDDataParams.h ${PROJECT_SOURCE_DIR}/include/vapor/BarbParams.h ${PROJECT_SOURCE_DIR}/include/vapor/Viewpoint.h ${PROJECT_SOURCE_DIR}/include/vapor/ViewpointParams.h ${PROJECT_SOURCE_DIR}/include/vapor/regionparams.h ${PROJECT_SOURCE_DIR}/include/vapor/ParamsMgr.h ${PROJECT_SOURCE_DIR}/include/vapor/DataStatus.h ${PROJECT_SOURCE_DIR}/include/vapor/AnnotationParams.h ${PROJECT_SOURCE_DIR}/include/vapor/HelloParams.h ${PROJECT_SOURCE_DIR}/include/vapor/ImageParams.h ${PROJECT_SOURCE_DIR}/include/vapor/TFInterpolator.h ${PROJECT_SOURCE_DIR}/include/vapor/ContourParams.h ${PROJECT_SOURCE_DIR}/include/vapor/AxisAnnotation.h ${PROJECT_SOURCE_DIR}/include/vapor/WireFrameParams.h ${PROJECT_SOURCE_DIR}/include/vapor/DatasetsParams.h ${PROJECT_SOURCE_DIR}/include/vapor/SliceParams.h ${PROJECT_SOURCE_DIR}/include/vapor/RayCasterParams.h ${PROJECT_SOURCE_DIR}/include/vapor/FlowParams.h ${PROJECT_SOURCE_DIR}/include/vapor/VolumeParams.h ${PROJECT_SOURCE_DIR}/include/vapor/VolumeIsoParams.h ${PROJECT_SOURCE_DIR}/include/vapor/ModelParams.h ${PROJECT_SOURCE_DIR}/include/vapor/ParticleParams.h ${PROJECT_SOURCE_DIR}/include/vapor/Transform.h ${PROJECT_SOURCE_DIR}/include/vapor/AnimationParams.h ${PROJECT_SOURCE_DIR}/include/vapor/MouseModeParams.h ${PROJECT_SOURCE_DIR}/include/vapor/BookmarkParams.h ${PROJECT_SOURCE_DIR}/include/vapor/GUIStateParams.h ${PROJECT_SOURCE_DIR}/include/vapor/SettingsParams.h ) add_library (params SHARED ${SRC} ${HEADERS}) if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") find_library (AGL AGL) target_link_libraries (params PUBLIC ${AGL}) endif() target_link_libraries (params PUBLIC vdc ${EXPAT}) add_definitions (-DPARAMS_EXPORTS) OpenMPInstall ( TARGETS params DESTINATION ${INSTALL_LIB_DIR} COMPONENT Libraries ) install ( FILES ${HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR} COMPONENT Libraries ) ================================================ FILE: lib/params/ColorMap.cpp ================================================ //--ColorMap.cpp ------------------------------------------------------------ // // Copyright (C) 2006 Kenny Gruchalla. All rights reserved. // // A map from data value to/from color. // //---------------------------------------------------------------------------- #include #include #include #include "vapor/VAssert.h" #include #ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif using namespace std; using namespace VAPoR; using namespace Wasp; //---------------------------------------------------------------------------- // Static member initalization //---------------------------------------------------------------------------- const string ColorMap::_controlPointsTag = "ColorMapControlPoints"; const string ColorMap::_interpTypeTag = "ColorInterpolationType"; const string ColorMap::_useWhitespaceTag = "UseWhitespace"; const string ColorMap::_dataBoundsTag = "DataBounds"; // // Register class with object factory!!! // static ParamsRegistrar registrar(ColorMap::GetClassType()); //============================================================================ // Class ColorMap::Color //============================================================================ //---------------------------------------------------------------------------- // Default constructor (white) //---------------------------------------------------------------------------- ColorMap::Color::Color() : _hue(0.0), _sat(0.0), _val(1.0) {} //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- ColorMap::Color::Color(float h, float s, float v) : _hue(h), _sat(s), _val(v) {} //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- ColorMap::Color::Color(double h, double s, double v) : _hue((float)h), _sat((float)s), _val((float)v) {} //---------------------------------------------------------------------------- // Copy Constructor //---------------------------------------------------------------------------- ColorMap::Color::Color(const Color &c) : _hue(c._hue), _sat(c._sat), _val(c._val) {} //---------------------------------------------------------------------------- // Return the rgb components of the color (0.0 ... 1.0) //---------------------------------------------------------------------------- void ColorMap::Color::toRGB(float *rgb) const { /* * hsv-rgb Conversion function. inputs and outputs between 0 and 1 * copied (with corrections) from Hearn/Baker */ if (_sat == 0.f) // grey { rgb[0] = rgb[1] = rgb[2] = _val; return; } int sector = (int)(_hue * 6.f); float sectCrd = _hue * 6.f - (float)sector; if (sector == 6) { sector = 0; } float a = _val * (1.f - _sat); float b = _val * (1.f - sectCrd * _sat); float c = _val * (1.f - (_sat * (1.f - sectCrd))); switch (sector) { case (0): // red to green, r>g rgb[0] = _val; rgb[1] = c; rgb[2] = a; break; case (1): // red to green, g>r rgb[1] = _val; rgb[2] = a; rgb[0] = b; break; case (2): // green to blue, gr>bl rgb[0] = a; rgb[1] = _val; rgb[2] = c; break; case (3): // green to blue, grred rgb[1] = a; rgb[2] = _val; rgb[0] = c; break; case (5): // blue to red, bl cps; cps.push_back(232.0 / 360.0); cps.push_back(.695); cps.push_back(.757); cps.push_back(0.); cps.push_back(348.0 / 360.0); cps.push_back(.977); cps.push_back(.706); cps.push_back(.99); SetControlPoints(cps); } ColorMap::ColorMap(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {} //---------------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------------- ColorMap::~ColorMap() {} //---------------------------------------------------------------------------- // Clear (& deallocated) the control points //---------------------------------------------------------------------------- void ColorMap::clear() { vector cps; SetControlPoints(cps); } //---------------------------------------------------------------------------- // Return the control point's color //---------------------------------------------------------------------------- ColorMap::Color ColorMap::controlPointColor(int index) const { vector cps = GetControlPoints(); if (index + 4 > cps.size() * 4) return Color(); return Color(cps[4 * index], cps[4 * index + 1], cps[4 * index + 2]); } //---------------------------------------------------------------------------- // Set the control point's color. //---------------------------------------------------------------------------- void ColorMap::controlPointColor(int index, Color color) { vector cps = GetControlPoints(); if (index + 4 > cps.size() * 4) return; // no-op cps[4 * index] = color.hue(); cps[4 * index + 1] = color.sat(); cps[4 * index + 2] = color.val(); SetControlPoints(cps); } float ColorMap::controlPointValueNormalized(int index) const { vector cps = GetControlPoints(); return (float)cps[4 * index + 3]; } //---------------------------------------------------------------------------- // Return the control point's value (in data coordinates). //---------------------------------------------------------------------------- float ColorMap::controlPointValue(int index) const { return (controlPointValueNormalized(index) * (maxValue() - minValue()) + minValue()); } //---------------------------------------------------------------------------- // Set the control point's value (in data coordinates). //---------------------------------------------------------------------------- void ColorMap::controlPointValue(int index, float value) { vector cps = GetControlPoints(); if (index + 4 > cps.size() * 4) return; // no-op float nv = (value - minValue()) / (maxValue() - minValue()); float minVal = 0.0; float maxVal = 1.0; if (index > 0) { minVal = (cps[3]); } if (index < cps.size() / 4 - 1) maxVal = cps[cps.size() - 1]; if (nv < minVal) { nv = minVal; } else if (nv > maxVal) { nv = maxVal; } cps[index * 4 + 3] = nv; SetControlPoints(cps); } //---------------------------------------------------------------------------- // Add a new control point to the colormap. //---------------------------------------------------------------------------- void ColorMap::addControlPointAt(float value) { float nv = (value - minValue()) / (maxValue() - minValue()); addNormControlPointAt(nv); } int ColorMap::addNormControlPointAt(float nv) { Color c = colorNormalized(nv); vector cps = GetControlPoints(); // Find the insertion point: int indx = leftIndex(nv) * 4 + 4; cps.insert(cps.begin() + indx++, c.hue()); cps.insert(cps.begin() + indx++, c.sat()); cps.insert(cps.begin() + indx++, c.val()); cps.insert(cps.begin() + indx, nv); SetControlPoints(cps); return indx / 4; } //---------------------------------------------------------------------------- // Add a new control point to the colormap. //---------------------------------------------------------------------------- void ColorMap::addControlPointAt(float value, Color color) { vector cps = GetControlPoints(); // Find the insertion point: int indx = leftIndex(value) * 4; cps.insert(cps.begin() + indx++, color.hue()); cps.insert(cps.begin() + indx++, color.sat()); cps.insert(cps.begin() + indx++, color.val()); cps.insert(cps.begin() + indx, value); SetControlPoints(cps); } //---------------------------------------------------------------------------- // Add a new control point to the colormap. //---------------------------------------------------------------------------- int ColorMap::addNormControlPoint(float normValue, Color color) { vector cps = GetControlPoints(); // Find the insertion point: int indx = (leftIndex(normValue) + 1) * 4; cps.insert(cps.begin() + indx++, color.hue()); cps.insert(cps.begin() + indx++, color.sat()); cps.insert(cps.begin() + indx++, color.val()); cps.insert(cps.begin() + indx, normValue); SetControlPoints(cps); return indx / 4; } //---------------------------------------------------------------------------- // Delete the control point. //---------------------------------------------------------------------------- void ColorMap::deleteControlPoint(int index) { vector cps = GetControlPoints(); if (index >= 0 && index < cps.size() / 4) { cps.erase(cps.begin() + 4 * index, cps.begin() + 4 * index + 4); SetControlPoints(cps); } } //---------------------------------------------------------------------------- // Move the control point, but not past adjacent control points //---------------------------------------------------------------------------- void ColorMap::move(int index, float delta) { vector cps = GetControlPoints(); if (index > 0 && index < cps.size() / 4 - 1) // don't move first or last control point! { float ndx = delta / (maxValue() - minValue()); float minVal = cps[index * 4 - 1]; // value to the left float maxVal = cps[index * 4 + 7]; // value to the right float value = cps[index * 4 + 3] + ndx; if (value < 0.005) value = 0.005; if (value <= minVal) { value = minVal; } else if (value >= maxVal) { value = maxVal; } cps[index * 4 + 3] = value; SetControlPoints(cps); } } ColorMap::Color ColorMap::getDivergingColor(float ratio, float index) const { vector cps = GetControlPoints(); float hsv1[3] = {(float)cps[4 * index], (float)cps[4 * index + 1], (float)cps[4 * index + 2]}; float hsv2[3] = {(float)cps[4 * index + 4], (float)cps[4 * index + 5], (float)cps[4 * index + 6]}; float rgb1[3], rgb2[3]; float rgbOutput[3], hsvOutput[3]; TFInterpolator::hsv2rgb(hsv1, rgb1); rgb1[0] = rgb1[0] * 255.0; rgb1[1] = rgb1[1] * 255.0; rgb1[2] = rgb1[2] * 255.0; TFInterpolator::hsv2rgb(hsv2, rgb2); rgb2[0] = rgb2[0] * 255.0; rgb2[1] = rgb2[1] * 255.0; rgb2[2] = rgb2[2] * 255.0; if (GetUseWhitespace()) TFInterpolator::correctiveDivergentInterpolation(rgb2, rgb1, rgbOutput, ratio); else TFInterpolator::divergentInterpolation(rgb2, rgb1, rgbOutput, ratio); TFInterpolator::rgb2hsv(rgbOutput, hsvOutput); // Normalize HSV output hsvOutput[0] = hsvOutput[0] / 360.0; hsvOutput[2] = (float)hsvOutput[2] / 255.0; return Color(hsvOutput[0], hsvOutput[1], hsvOutput[2]); } ColorMap::Color ColorMap::color(float value) const { float nv = (value - minValue()) / (maxValue() - minValue()); return colorNormalized(nv); } namespace { void lab2lch(const float lab[3], float lch[3]) { const float l = lab[0]; const float a = lab[1]; const float b = lab[2]; const float c = sqrtf(a * a + b * b); const float h = fmod((atan2f(b, a) / (2 * M_PI) * 360 + 360), 360.f); lch[0] = l; lch[1] = c; lch[2] = h; } void lch2lab(const float lch[3], float lab[3]) { const float l = lch[0]; const float c = lch[1]; float h = lch[2]; h = h / 360.f * 2 * M_PI; lab[0] = l; lab[1] = cosf(h) * c; lab[2] = sinf(h) * c; } template void clamp(T &v, const T min, const T max) { if (v < min) v = min; if (v > max) v = max; } void clamp3(float c[3], const vector &min, const vector &max) { for (int i = 0; i < 3; i++) clamp(c[i], min[i], max[i]); } } // namespace //---------------------------------------------------------------------------- // Interpolate a color at the value (data coordinates) // // Developed by Alan Norton. //---------------------------------------------------------------------------- ColorMap::Color ColorMap::colorNormalized(float nv) const { vector cps = GetControlPoints(); // // Find the bounding control points // int index = leftIndex(nv); if (index < 0) return controlPointColor(0); if (index >= numControlPoints() - 1) return controlPointColor(numControlPoints() - 1); VAssert(index >= 0 && index * 4 + 7 < cps.size()); double leftVal = cps[4 * index + 3]; double rightVal = cps[4 * index + 7]; float ratio = (nv - leftVal) / (rightVal - leftVal); if (ratio > 0.f && ratio < 1.f) { TFInterpolator::type itype = GetInterpType(); if (itype == TFInterpolator::diverging) { ColorMap::Color divergingColor; divergingColor = getDivergingColor(ratio, index); return divergingColor; } else if (itype == TFInterpolator::linear) { float h = TFInterpolator::interpCirc(itype, cps[4 * index], // hue cps[4 * index + 4], ratio); float s = TFInterpolator::interpolate(itype, cps[4 * index + 1], // sat cps[4 * index + 5], ratio); float v = TFInterpolator::interpolate(itype, cps[4 * index + 2], // val cps[4 * index + 6], ratio); return Color(h, s, v); } else if (itype == TFInterpolator::linearRGB) { Color a(cps[4 * index + 0 + 0], cps[4 * index + 1 + 0], cps[4 * index + 2 + 0]); Color b(cps[4 * index + 0 + 4], cps[4 * index + 1 + 4], cps[4 * index + 2 + 4]); float aRGB[3], bRGB[3]; a.toRGB(aRGB); b.toRGB(bRGB); float rgb[3]; for (int i = 0; i < 3; i++) rgb[i] = aRGB[i] + (bRGB[i] - aRGB[i]) * ratio; float hsv[3]; TFInterpolator::rgb2hsv(rgb, hsv); hsv[0] /= 360.f; return Color(hsv[0], hsv[1], hsv[2]); } else if (itype == TFInterpolator::linearLAB) { Color a(cps[4 * index + 0 + 0], cps[4 * index + 1 + 0], cps[4 * index + 2 + 0]); Color b(cps[4 * index + 0 + 4], cps[4 * index + 1 + 4], cps[4 * index + 2 + 4]); float aRGB[3], bRGB[3]; a.toRGB(aRGB); b.toRGB(bRGB); float aSRGB[3], bSRGB[3], rgb[3]; for (int i = 0; i < 3; i++) { aRGB[i] *= 100; bRGB[i] *= 100; } TFInterpolator::rgb2srgb(aRGB, aSRGB); TFInterpolator::rgb2srgb(bRGB, bSRGB); float aLAB[3], bLAB[3], lab[3]; TFInterpolator::srgb2lab(aSRGB, aLAB); TFInterpolator::srgb2lab(bSRGB, bLAB); clamp3(aLAB, {0, -110, -110}, {100, 110, 110}); clamp3(bLAB, {0, -110, -110}, {100, 110, 110}); for (int i = 0; i < 3; i++) lab[i] = aLAB[i] + (bLAB[i] - aLAB[i]) * ratio; float srgb[3]; TFInterpolator::lab2srgb(lab, srgb); TFInterpolator::srgb2rgb(srgb, rgb); for (int i = 0; i < 3; i++) rgb[i] /= 100.f; clamp3(rgb, {0, 0, 0}, {1, 1, 1}); float hsv[3]; TFInterpolator::rgb2hsv(rgb, hsv); hsv[0] /= 360.f; return Color(hsv[0], hsv[1], hsv[2]); } else if (itype == TFInterpolator::linearLCH) { Color a(cps[4 * index + 0 + 0], cps[4 * index + 1 + 0], cps[4 * index + 2 + 0]); Color b(cps[4 * index + 0 + 4], cps[4 * index + 1 + 4], cps[4 * index + 2 + 4]); float aRGB[3], bRGB[3]; a.toRGB(aRGB); b.toRGB(bRGB); float rgb[3]; float hsv[3]; float aSRGB[3], bSRGB[3]; for (int i = 0; i < 3; i++) { aRGB[i] *= 100; bRGB[i] *= 100; } TFInterpolator::rgb2srgb(aRGB, aSRGB); TFInterpolator::rgb2srgb(bRGB, bSRGB); float aLAB[3], bLAB[3]; TFInterpolator::srgb2lab(aSRGB, aLAB); TFInterpolator::srgb2lab(bSRGB, bLAB); clamp3(aLAB, {0, -110, -110}, {100, 110, 110}); clamp3(bLAB, {0, -110, -110}, {100, 110, 110}); float aLCH[3], bLCH[3], lch[3]; lab2lch(aLAB, aLCH); lab2lch(bLAB, bLCH); clamp3(aLCH, {0, 0, 0}, {100, 140, 360}); clamp3(bLCH, {0, 0, 0}, {100, 140, 360}); for (int i = 0; i < 2; i++) lch[i] = aLCH[i] + (bLCH[i] - aLCH[i]) * ratio; float h, ah = aLCH[2], bh = bLCH[2]; if (fabsf(bh - ah) > 180) { if (bh > ah) ah += 360; else bh += 360; } h = ah + (bh - ah) * ratio; lch[2] = h; float lab[3]; lch2lab(lch, lab); clamp3(lab, {0, -110, -110}, {100, 110, 110}); float srgb[3]; TFInterpolator::lab2srgb(lab, srgb); TFInterpolator::srgb2rgb(srgb, rgb); for (int i = 0; i < 3; i++) rgb[i] /= 100.f; clamp3(rgb, {0, 0, 0}, {1, 1, 1}); TFInterpolator::rgb2hsv(rgb, hsv); hsv[0] /= 360.f; return Color(hsv[0], hsv[1], hsv[2]); } else if (itype == TFInterpolator::discrete) { if (ratio < .5) { float h = cps[4 * index]; float s = cps[4 * index + 1]; float v = cps[4 * index + 2]; return Color(h, s, v); } else { float h = cps[4 * index + 4]; float s = cps[4 * index + 5]; float v = cps[4 * index + 6]; return Color(h, s, v); } } } if (ratio >= 1.0) { return Color(cps[4 * index + 4], cps[4 * index + 5], cps[4 * index + 6]); } return Color(cps[4 * index], cps[4 * index + 1], cps[4 * index + 2]); } //---------------------------------------------------------------------------- // binary search , find the index of the largest control point <= val // Requires that control points are increasing. // // Not developed by Alan Norton. //---------------------------------------------------------------------------- int ColorMap::leftIndex(float val) const { int n = numControlPoints(); if (n == 0) return -1; for (int i = 0; i < n; i++) if (controlPointValueNormalized(i) > val) return i - 1; return n - 1; } vector ColorMap::GetControlPoints() const { vector cps = GetValueDoubleVec(_controlPointsTag); while (cps.size() % 4) cps.push_back(0.0); for (int i = 0; i < cps.size(); i += 4) clamp(cps[i], 0.0, 1.0); return (cps); } void ColorMap::SetControlPoints(const vector &controlPoints) { vector mycp = controlPoints; while (mycp.size() % 4) mycp.push_back(0.0); SetValueDoubleVec(_controlPointsTag, "Set color control points", mycp); } void ColorMap::SetInterpType(TFInterpolator::type t) { SetValueLong(_interpTypeTag, "Set Color Interpolation", (long)t); } void ColorMap::SetUseWhitespace(bool enabled) { SetValueLong(_useWhitespaceTag, "Set the use of whitespace for " "diverging colormaps", enabled); } bool ColorMap::GetUseWhitespace() const { return GetValueLong(_useWhitespaceTag, true); } void ColorMap::SetDataBounds(const vector &bounds) { VAssert(bounds.size() == 2); SetValueDoubleVec(_dataBoundsTag, "Set min max map value", bounds); } vector ColorMap::GetDataBounds() const { vector defaultv(2, 0.0); vector bounds = GetValueDoubleVec(_dataBoundsTag, defaultv); if (bounds.size() != 2) bounds = defaultv; return (bounds); } void ColorMap::Reverse() { auto old = GetControlPoints(); vector cps; for (int i = numControlPoints() - 1; i >= 0; i--) { double r = old[i * 4 + 0]; double g = old[i * 4 + 1]; double b = old[i * 4 + 2]; double v = old[i * 4 + 3]; cps.push_back(r); cps.push_back(g); cps.push_back(b); cps.push_back(1.0 - v); } SetControlPoints(cps); } ================================================ FILE: lib/params/ColorbarPbase.cpp ================================================ //************************************************************************ // * // Copyright (C) 2016 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: ColorbarPbase.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: February 2016 // // Description: Implements the ColorbarPbase class. // Used to control parameters of a color bar. // #include #include "vapor/VAssert.h" #include using namespace VAPoR; const string ColorbarPbase::_colorbarBackColorTag = "ColorbarBackgroundColor"; const string ColorbarPbase::_colorbarFrontColorTag = "ColorbarForegroundColor"; const string ColorbarPbase::_colorbarSizeXTag = "ColorbarSize_X"; const string ColorbarPbase::_colorbarSizeYTag = "ColorbarSize_Y"; const string ColorbarPbase::_colorbarPositionXTag = "ColorbarPosition_X"; const string ColorbarPbase::_colorbarPositionYTag = "ColorbarPosition_Y"; const string ColorbarPbase::_colorbarFontSizeTag = "ColorbarFontsize"; const string ColorbarPbase::_colorbarNumDigitsTag = "ColorbarNumDigits"; const string ColorbarPbase::_colorbarTitleTag = "ColorbarTitle"; const string ColorbarPbase::_colorbarNumTicksTag = "ColorbarNumTicks"; const string ColorbarPbase::_colorbarEnabledTag = "ColorbarEnabled"; const string ColorbarPbase::UseScientificNotationTag = "UseScientificNotationTag"; // // Register class with object factory!!! // static ParamsRegistrar registrar(ColorbarPbase::GetClassType()); ColorbarPbase::ColorbarPbase(ParamsBase::StateSave *ssave) : ParamsBase(ssave, ColorbarPbase::GetClassType()) { MyBase::SetDiagMsg("ColorbarPbase::ColorbarPbase() this=%p", this); // Initialize with default values SetCornerPosition(vector(2, 0.03)); SetSize(vector(2, 0.1)); SetTitle(""); SetFontSize(10); SetNumDigits(4); SetNumTicks(6); SetBackgroundColor(vector(3, 1.)); SetForegroundColor(vector(3, 0.)); SetEnabled(false); SetValueLong(UseScientificNotationTag, "", false); } ColorbarPbase::ColorbarPbase(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {} ColorbarPbase::~ColorbarPbase() { MyBase::SetDiagMsg("ColorbarPbase::~ColorbarPbase() this=%p", this); } vector ColorbarPbase::GetCornerPosition() const { vector val(2, 0.0); val[0] = GetValueDouble(_colorbarPositionXTag, 0); val[1] = GetValueDouble(_colorbarPositionYTag, 0); for (int i = 0; i < 2; i++) { if (val[i] < 0.0) val[i] = 0.0; if (val[i] > 1.0) val[i] = 1.0; } return (val); } //! Set the X,Y corner (upper left) coordinates //! Relative to [0,1] //! \param[in] posn = x,y coordinates void ColorbarPbase::SetCornerPosition(vector posn) { vector defaultv(2, 0.0); if (posn.size() != 2) posn = defaultv; for (int i = 0; i < 2; i++) { if (posn[i] < 0.0) posn[i] = 0.0; if (posn[i] > 1.0) posn[i] = 1.0; } BeginGroup("Colorbar_Position"); SetValueDouble(_colorbarPositionXTag, "", posn[0]); SetValueDouble(_colorbarPositionYTag, "", posn[1]); EndGroup(); } //! Get the X,Y size //! Relative to [0,1] //! \retval pair of x,y sizes vector ColorbarPbase::GetSize() const { vector val(2, 0.0); val[0] = GetValueDouble(_colorbarSizeXTag, 0); val[1] = GetValueDouble(_colorbarSizeYTag, 0); for (int i = 0; i < 2; i++) { if (val[i] < 0.0) val[i] = 0.0; if (val[i] > 1.0) val[i] = 1.0; } return (val); } //! Set the X,Y sizes //! Relative to [0,1] //! \param[in] posn = x,y sizes void ColorbarPbase::SetSize(vector sz) { vector defaultv(2, 0.0); if (sz.size() != 2) sz = defaultv; for (int i = 0; i < 2; i++) { if (sz[i] < 0.0) sz[i] = 0.0; if (sz[i] > 1.0) sz[i] = 1.0; } SetValueDouble(_colorbarSizeXTag, "", sz[0]); SetValueDouble(_colorbarSizeYTag, "", sz[1]); } //! Determine colorbar text size //! \return pointsize long ColorbarPbase::GetFontSize() const { float val = (float)GetValueLong(_colorbarFontSizeTag, 10); if (val < 2) val = 2; if (val > 96) val = 96; return (val); } //! Set colorbar text size //! \param[in] val text point size void ColorbarPbase::SetFontSize(long val) { if (val < 2) val = 2; if (val > 96) val = 96; SetValueLong(_colorbarFontSizeTag, "Set colorbar fontsize", val); } //! Determine colorbar num tics //! \return number of tics long ColorbarPbase::GetNumTicks() const { long val = GetValueLong(_colorbarNumTicksTag, 8); if (val < 0) val = 0; if (val > 20) val = 20; return (val); } //! Set colorbar number of tic marks //! \param[in] val number of tics void ColorbarPbase::SetNumTicks(long val) { if (val < 0) val = 0; if (val > 20) val = 20; SetValueLong(_colorbarNumTicksTag, "set num tics", val); } //! Determine colorbar num digits to display //! \return number of digits long ColorbarPbase::GetNumDigits() const { long val = GetValueLong(_colorbarNumDigitsTag, 4); if (val < 0) val = 0; if (val > 8) val = 8; return (val); } //! Set colorbar number of digits //! \param[in] val number of digits void ColorbarPbase::SetNumDigits(long val) { if (val < 0) val = 0; if (val > 8) val = 8; SetValueLong(_colorbarNumDigitsTag, "set num digits", val); } //! Get the background color //! as an rgb triple //! \retval rgb color vector ColorbarPbase::GetBackgroundColor() const { vector defaultv(4, 1.0); vector color = GetValueDoubleVec(_colorbarBackColorTag, defaultv); for (int i = 0; i < color.size(); i++) { if (color[i] < 0.0) color[i] = 0.0; if (color[i] > 1.0) color[i] = 1.0; } return (color); } //! Set the background color as an rgb triple //! \param[in] color = (r,g,b) void ColorbarPbase::SetBackgroundColor(vector color) { VAssert(color.size() == 3 || color.size() == 4); for (int i = 0; i < color.size(); i++) { if (color[i] < 0.0) color[i] = 0.0; if (color[i] > 1.0) color[i] = 1.0; } SetValueDoubleVec(_colorbarBackColorTag, "set colorbar background color", color); } vector ColorbarPbase::GetForegroundColor() const { vector defaultv(3, 0.0); vector color = GetValueDoubleVec(_colorbarFrontColorTag, defaultv); for (int i = 0; i < color.size(); i++) { if (color[i] < 0.0) color[i] = 0.0; if (color[i] > 1.0) color[i] = 1.0; } return (color); } void ColorbarPbase::SetForegroundColor(vector color) { color.resize(3, 0); for (int i = 0; i < color.size(); i++) { if (color[i] < 0.0) color[i] = 0.0; if (color[i] > 1.0) color[i] = 1.0; } SetValueDoubleVec(_colorbarFrontColorTag, "set colorbar background color", color); } void ColorbarPbase::copyTo(ColorbarPbase *target) { target->SetBackgroundColor(GetBackgroundColor()); target->SetForegroundColor(GetForegroundColor()); target->SetSize(GetSize()); target->SetFontSize(GetFontSize()); target->SetNumDigits(GetNumDigits()); target->SetNumTicks(GetNumTicks()); } ================================================ FILE: lib/params/ContourParams.cpp ================================================ #include #include #include namespace VAPoR { // // Register class with object factory!!! // static RenParamsRegistrar registrar(ContourParams::GetClassType()); static ParamsRegistrar registrar2(ContourParams::Contours::GetClassType()); const string ContourParams::_thicknessScaleTag = "LineThickness"; const string ContourParams::_contoursTag = "Contours"; const string ContourParams::_numDigitsTag = "NumDigits"; const string ContourParams::_textDensityTag = "TextDensity"; const string ContourParams::_lineColorTag = "LineColor"; const string ContourParams::_textEnabledTag = "TextEnabled"; const string ContourParams::_lockToTFTag = "LockToTF"; const string ContourParams::Contours::_valuesTag = "Values"; ContourParams::ContourParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, ContourParams::GetClassType(), 3) { SetDiagMsg("ContourParams::ContourParams() this=%p", this); _contours = new ParamsContainer(ssave, _contoursTag); _contours->SetParent(this); _init(); } ContourParams::ContourParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node, 3) { SetDiagMsg("ContourParams::ContourParams() this=%p", this); if (node->HasChild(_contoursTag)) { _contours = new ParamsContainer(ssave, node->GetChild(_contoursTag)); } else { // Node doesn't contain a contours container _contours = new ParamsContainer(ssave, _contoursTag); _contours->SetParent(this); } } ContourParams::ContourParams(const ContourParams &rhs) : RenderParams(rhs) { _contours = new ParamsContainer(*(rhs._contours)); } ContourParams &ContourParams::operator=(const ContourParams &rhs) { if (_contours) delete _contours; ParamsBase::operator=(rhs); _contours = new ParamsContainer(*(rhs._contours)); return (*this); } ContourParams::~ContourParams() { SetDiagMsg("ContourParams::~ContourParams() this=%p", this); if (_contours != NULL) { delete _contours; _contours = NULL; } } vector ContourParams::GetIsoValues(const string &variable) { return GetContourValues(variable); } void ContourParams::SetIsoValues(const string &variable, const vector &values) { SetContourValues(variable, values); } vector ContourParams::GetContourValues(const string &varName) { Contours *c = (Contours *)_contours->GetParams(varName); if (c == NULL) { bool wasEnabled = _ssave->GetEnabled(); _ssave->SetEnabled(false); MakeNewContours(varName); _ssave->SetEnabled(wasEnabled); c = (Contours *)_contours->GetParams(varName); } return c->GetContourValues(); } void ContourParams::SetContourValues(const string &varName, const vector &vals) { Contours *c = (Contours *)_contours->GetParams(varName); if (c == NULL) { MakeNewContours(varName); c = (Contours *)_contours->GetParams(varName); } c->SetContourValues(vals); } ContourParams::Contours *ContourParams::GetCurrentContours() { string varName = GetVariableName(); ContourParams::Contours *c = (ContourParams::Contours *)_contours->GetParams(varName); if (c == NULL) { MakeNewContours(varName); c = (ContourParams::Contours *)_contours->GetParams(varName); } return c; } void ContourParams::MakeNewContours(string varName) { Contours newContours(_ssave); MapperFunction *mf = GetMapperFunc(varName); VAssert(mf); vector minMax = mf->getMinMaxMapValue(); int numContours = newContours.GetContourValues().size(); double spacing = (minMax[1] - minMax[0]) / (numContours - 1); GenerateContourValues(minMax[0], spacing, numContours, &newContours); _contours->Insert(&newContours, varName); } void ContourParams::GenerateContourValues(double start, double spacing, int num, Contours *c) { if (!c) c = GetCurrentContours(); vector vals; for (int i = 0; i < num; i++) vals.push_back(start + i * spacing); c->SetContourValues(vals); } // Set everything to default values void ContourParams::_init() { SetDiagMsg("ContourParams::_init()"); float rgb[] = {1., 1., 1.}; SetConstantColor(rgb); GetBox()->SetPlanar(true); GetBox()->SetOrientation(VAPoR::Box::XY); SetDefaultVariables(2, true); } int ContourParams::GetContourCount() { Contours * c = GetCurrentContours(); vector vals = c->GetContourValues(); return vals.size(); } double ContourParams::GetContourMin() { Contours * c = GetCurrentContours(); vector vals = c->GetContourValues(); return vals[0]; } double ContourParams::GetContourMax() { Contours * c = GetCurrentContours(); vector vals = c->GetContourValues(); return vals[vals.size() - 1]; } double ContourParams::GetContourSpacing() { Contours * c = GetCurrentContours(); vector vals = c->GetContourValues(); if (vals.size() < 2) return 1; else return vals[1] - vals[0]; } void ContourParams::SetContourCount(int num) { GenerateContourValues(GetContourMin(), GetContourSpacing(), num); } void ContourParams::SetContourMin(double val) { GenerateContourValues(val, GetContourSpacing(), GetContourCount()); } void ContourParams::SetContourSpacing(double val) { GenerateContourValues(GetContourMin(), val, GetContourCount()); } void ContourParams::GetLineColor(int lineNum, float color[3]) { if (UseSingleColor()) { GetConstantColor(color); } else { string varName = GetVariableName(); MapperFunction *tf = 0; tf = (MapperFunction *)GetMapperFunc(varName); VAssert(tf); vector vals = GetContourValues(varName); double val = vals[lineNum]; tf->rgbValue(val, color); } } void ContourParams::SetLockToTF(bool lock) { string l = "false"; if (lock) { l = "true"; } SetValueString(_lockToTFTag, "Lock settings to TF", l); } bool ContourParams::GetLockToTF() const { if (GetValueString(_lockToTFTag, "false") == "false") { return false; } else { return true; } } bool ContourParams::GetTextEnabled() const { if (GetValueString(_textEnabledTag, "false") == "false") { return false; } else { return true; } } void ContourParams::SetTFLock(bool lock) { string l = "false"; if (lock) l = "true"; SetValueString(_lockToTFTag, "Lock contours to transfer function" " bounds", l); } bool ContourParams::GetTFLock() { string l = GetValueString(_lockToTFTag, "false"); if (l == "false") return false; return true; } ContourParams::Contours::Contours(ParamsBase::StateSave *ssave) : ParamsBase(ssave, Contours::GetClassType()) {} ContourParams::Contours::Contours(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {} ContourParams::Contours::~Contours() { MyBase::SetDiagMsg("Contours::~Contours() this=%p", this); } }; // end namespace VAPoR ================================================ FILE: lib/params/DataStatus.cpp ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: DataStatus.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: February 2006 // // Description: Implements the DataStatus class // #ifdef WIN32 #pragma warning(disable : 4251 4100) #endif #include #include "vapor/VAssert.h" #include #include #include #include #include #include #include #include #include using namespace VAPoR; using namespace Wasp; namespace { void print_extents(string header, const CoordType &minExts, const CoordType &maxExts) { #ifdef DEBUG VAssert(minExts.size() == maxExts.size()); cout << endl; cout << header << endl; for (int i = 0; i < minExts.size(); i++) { cout << "\t" << minExts[i] << " " << maxExts[i] << endl; } cout << endl; #endif } }; // namespace // Default constructor // Whether or not it exists on disk, what's its max and min // What resolutions are available. // DataStatus::DataStatus(size_t cacheSize, int nThreads) { _cacheSize = cacheSize; _nThreads = nThreads; _dataMgrs.clear(); _timeCoords.clear(); _timeCoordsFormatted.clear(); _timeMap.clear(); reset_time(); } int DataStatus::Open(const std::vector &files, const std::vector &options, string name, string format) { VAssert(!name.empty()); vector myOptions = options; Close(name); DataMgr *dataMgr; if (format == "ram") dataMgr = new PythonDataMgr(format, _cacheSize, _nThreads); else dataMgr = new DataMgr(format, _cacheSize, _nThreads); // Ensure all data managers use the same proj4 string. Note, it's // possible that 'options' will already have a -proj4 string argument. // The one we add here will take precedence because it is last in // the list. This is a bit of a hack. To ensure that a -proj argument // already present in the 'options' parameter is honored the dataMgr // map should be empty. I.e. the first open data mgr. // if (_dataMgrs.size()) { map::iterator itr = _dataMgrs.begin(); DataMgr * dm0 = itr->second; myOptions.push_back("-proj4"); myOptions.push_back(dm0->GetMapProjection()); } int rc = dataMgr->Initialize(files, myOptions); if (rc < 0) { delete dataMgr; return (-1); } _dataMgrs[name] = dataMgr; reset_time(); return (0); } void DataStatus::Close(string name) { if (name.empty()) name = "DataSet1"; map::iterator itr; if ((itr = _dataMgrs.find(name)) != _dataMgrs.end()) { if (itr->second) delete itr->second; _dataMgrs.erase(itr); } reset_time(); } // const DataMgr *DataStatus::GetDataMgr(string name) const DataMgr *DataStatus::GetDataMgr(string name) const { if (name.empty()) name = "DataSet1"; map::const_iterator itr; itr = _dataMgrs.find(name); if (itr == _dataMgrs.end()) return (NULL); return (itr->second); } vector DataStatus::GetDataMgrNames() const { vector names; map::const_iterator itr; for (itr = _dataMgrs.begin(); itr != _dataMgrs.end(); ++itr) { names.push_back(itr->first); } return (names); } void DataStatus::_getExtents(size_t ts, const map> &varMap, CoordType &minExts, CoordType &maxExts) const { minExts = {0.0, 0.0, 0.0}; maxExts = {0.0, 0.0, 0.0}; if (varMap.empty()) return; vector tmpMinExts(3, std::numeric_limits::max()); vector tmpMaxExts(3, std::numeric_limits::lowest()); map>::const_iterator itr; for (itr = varMap.begin(); itr != varMap.end(); ++itr) { string dataSetName = itr->first; DataMgr *dataMgr = GetDataMgr(dataSetName); if (!dataMgr) continue; size_t local_ts = MapGlobalToLocalTimeStep(dataSetName, ts); const vector &variables = itr->second; for (auto it = variables.begin(); it != variables.end(); ++it) { const var_info_t &var = *it; CoordType minVExts, maxVExts; vector axes; bool status = DataMgrUtils::GetExtents(dataMgr, local_ts, var.varnames, var.refLevel, var.compLevel, minVExts, maxVExts, axes); if (!status) continue; if (axes.size() == 2) { bool has3D = !dataMgr->GetDataVarNames(3).empty(); if (has3D) { double z = DataMgrUtils::Get2DRendererDefaultZ(dataMgr, ts, var.refLevel, var.compLevel); minVExts[2] = z; maxVExts[2] = z; axes.push_back(2); } } print_extents(dataSetName, minVExts, maxVExts); for (int i = 0; i < axes.size(); i++) { int axis = axes[i]; if (minVExts[i] < tmpMinExts[axis]) { tmpMinExts[axis] = minVExts[i]; } if (maxVExts[i] > tmpMaxExts[axis]) { tmpMaxExts[axis] = maxVExts[i]; } } } } // tmp{Min,Max}Exts are always 3D vectors. If all variables are 2D // and live in same plane the returned {min,max}Exts should have // size of 2. // for (int i = 0; i < tmpMinExts.size(); i++) { if (tmpMinExts[i] != std::numeric_limits::max()) { minExts[i] = tmpMinExts[i]; maxExts[i] = tmpMaxExts[i]; } } print_extents("Dataset union", minExts, maxExts); return; } map> DataStatus::_getFirstVar(string dataSetName, size_t &ts) const { map> defaultVars; DataMgr *dataMgr = GetDataMgr(dataSetName); for (int dim = 3; dim > 1; dim--) { string varname; bool ok = DataMgrUtils::GetFirstExistingVariable(dataMgr, 0, 0, dim, varname, ts); if (ok) { var_info_t var; var.varnames = vector(1, varname); var.refLevel = 0; var.compLevel = 0; defaultVars[dataSetName] = vector(1, var); break; } } return (defaultVars); } void DataStatus::GetActiveExtents(const ParamsMgr *paramsMgr, string winName, string dataSetName, size_t ts, CoordType &minExts, CoordType &maxExts) const { map> varMap; vector rParams; paramsMgr->GetRenderParams(winName, dataSetName, rParams); vector variables; for (int j = 0; j < rParams.size(); j++) { if (!rParams[j]->IsEnabled()) continue; string varname = rParams[j]->GetVariableName(); var_info_t var; var.refLevel = rParams[j]->GetRefinementLevel(); var.compLevel = rParams[j]->GetCompressionLevel(); if (!varname.empty()) { var.varnames.push_back(varname); variables.push_back(var); } vector fvarnames = rParams[j]->GetFieldVariableNames(); for (int k = 0; k < fvarnames.size(); k++) { if (!fvarnames[k].empty()) { var.varnames.push_back(fvarnames[k]); variables.push_back(var); } } vector auxVarNames = rParams[j]->GetAuxVariableNames(); for (int k = 0; k < auxVarNames.size(); k++) { if (!auxVarNames[k].empty()) var.varnames.push_back(auxVarNames[k]); variables.push_back(var); } } if (variables.size()) { varMap[dataSetName] = variables; } else { // If we didn't find any enabled variable use the first variables // found in each data set // varMap = _getFirstVar(dataSetName, ts); } _getExtents(ts, varMap, minExts, maxExts); } void DataStatus::GetActiveExtents(const ParamsMgr *paramsMgr, string winName, size_t ts, CoordType &minExts, CoordType &maxExts) const { for (int i = 0; i < minExts.size(); i++) { minExts[i] = std::numeric_limits::max(); maxExts[i] = std::numeric_limits::lowest(); } vector dataSetNames = GetDataMgrNames(); for (int i = 0; i < dataSetNames.size(); i++) { CoordType minWExts, maxWExts; GetActiveExtents(paramsMgr, winName, dataSetNames[i], ts, minWExts, maxWExts); for (int j = 0; j < minWExts.size(); j++) { if (minWExts[j] < minExts[j]) { minExts[j] = minWExts[j]; } if (maxWExts[j] > maxExts[j]) { maxExts[j] = maxWExts[j]; } } } } void DataStatus::GetActiveExtents(const ParamsMgr *paramsMgr, size_t ts, CoordType &minExts, CoordType &maxExts) const { for (int i = 0; i < minExts.size(); i++) { minExts[i] = std::numeric_limits::max(); maxExts[i] = std::numeric_limits::lowest(); } vector winNames = paramsMgr->GetVisualizerNames(); for (int i = 0; i < winNames.size(); i++) { CoordType minWExts, maxWExts; GetActiveExtents(paramsMgr, winNames[i], ts, minWExts, maxWExts); for (int j = 0; j < minWExts.size(); j++) { if (minWExts[j] < minExts[j]) { minExts[j] = minWExts[j]; } if (maxWExts[j] > maxExts[j]) { maxExts[j] = maxWExts[j]; } } } } size_t DataStatus::MapGlobalToLocalTimeStep(string dataSetName, size_t ts) const { map>::const_iterator itr; itr = _timeMap.find(dataSetName); if (itr == _timeMap.end()) return (0); const vector &ref = itr->second; if (ts >= ref.size()) { ts = ref.size() - 1; } return (ref[ts]); } void DataStatus::MapLocalToGlobalTimeRange(string dataSetName, size_t local_ts, size_t &min_ts, size_t &max_ts) const { min_ts = max_ts = 0; map>::const_iterator itr; itr = _timeMap.find(dataSetName); if (itr == _timeMap.end()) return; const vector & ref = itr->second; vector::const_iterator itr1; vector::const_reverse_iterator itr2; itr1 = find(ref.begin(), ref.end(), local_ts); if (itr1 == ref.end()) return; itr2 = find(ref.rbegin(), ref.rend(), local_ts); if (itr2 == ref.rend()) return; min_ts = itr1 - ref.begin(); max_ts = ref.rend() - itr2 - 1; } string DataStatus::GetMapProjection() const { if (_dataMgrs.empty()) return (""); map::const_iterator itr = _dataMgrs.begin(); DataMgr * dm0 = itr->second; return (dm0->GetMapProjection()); } string DataStatus::GetMapProjectionDefault(string dataSetName) const { DataMgr *dataMgr = GetDataMgr(dataSetName); if (!dataMgr) return (""); return (dataMgr->GetMapProjectionDefault()); } namespace { int find_nearest(const vector &timeCoords, double time) { if (!timeCoords.size()) return (-1); if (time <= timeCoords[0]) return (0); if (time >= timeCoords[timeCoords.size() - 1]) return (timeCoords.size() - 1); // If we get to here there must be at least two elements in timeCoords // VAssert(timeCoords.size() >= 2); for (int i = 0; i < timeCoords.size() - 1; i++) { if (time >= timeCoords[i] && time <= timeCoords[i + 1]) { VAssert(timeCoords[i] != timeCoords[i + 1]); double s = (time - timeCoords[i]) / (timeCoords[i + 1] - timeCoords[i]); if (s <= 0.5) { return (i); } else { return (i + 1); } } } VAssert(0); return -1; } }; // namespace void DataStatus::reset_time_helper() { _timeCoordsFormatted = vector(_timeCoords.size(), ""); UDUnits udunits; int rc = udunits.Initialize(); if (rc < 0) return; char buf[80]; for (int i = 0; i < _timeCoords.size(); i++) { int year, month, day, hour, minute, second; udunits.DecodeTime(_timeCoords[i], &year, &month, &day, &hour, &minute, &second); snprintf(buf, 80, "%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d", year, month, day, hour, minute, second); _timeCoordsFormatted[i] = string(buf); } } void DataStatus::reset_time() { _timeCoords.clear(); _timeMap.clear(); if (_dataMgrs.size() == 0) return; // First construct global list of time coordinates // map::const_iterator itr; for (itr = _dataMgrs.begin(); itr != _dataMgrs.end(); ++itr) { DataMgr *dataMgr = itr->second; vector t = dataMgr->GetTimeCoordinates(); _timeCoords.insert(_timeCoords.end(), t.begin(), t.end()); } sort(_timeCoords.begin(), _timeCoords.end()); // This is a NOP as it is used incorrectly and has been since 2017 so disabling for now // unique(_timeCoords.begin(), _timeCoords.end()); for (itr = _dataMgrs.begin(); itr != _dataMgrs.end(); ++itr) { string dataSetName = itr->first; DataMgr *dataMgr = itr->second; vector timeSteps; vector t = dataMgr->GetTimeCoordinates(); for (int i = 0; i < _timeCoords.size(); i++) { int idx = find_nearest(t, _timeCoords[i]); timeSteps.push_back(idx); } _timeMap[dataSetName] = timeSteps; } reset_time_helper(); } DataStatus::~DataStatus() {} #ifdef VAPOR3_0_0_ALPHA // Map corners of box to voxels. void DataStatus::mapBoxToVox(Box *box, string varname, int refLevel, int lod, int timestep, size_t voxExts[6]) { double userExts[6]; box->GetUserExtents(userExts, (size_t)timestep); vector minexts, maxexts; for (int i = 0; i < 3; i++) { minexts.push_back(userExts[i]); maxexts.push_back(userExts[i + 3]); } bool errEnabled = MyBase::EnableErrMsg(false); StructuredGrid *rg = dataMgr->GetVariable(timestep, varname, refLevel, lod, minexts, maxexts); MyBase::EnableErrMsg(errEnabled); if (rg) { rg->GetIJKIndex(minexts[0], minexts[1], minexts[2], voxExts, voxExts + 1, voxExts + 2); rg->GetIJKIndex(maxexts[0], maxexts[1], maxexts[2], voxExts + 3, voxExts + 4, voxExts + 5); } else { for (int i = 0; i < 6; i++) voxExts[i] = 0; } //(Note: this can be expensive with layered data) return; } #endif ================================================ FILE: lib/params/DatasetsParams.cpp ================================================ #include #include #include namespace VAPoR { // // Register class with object factory!!! // static ParamsRegistrar registrar(DatasetsParams::GetClassType()); static ParamsRegistrar registrar1(DatasetParams::GetClassType()); static ParamsRegistrar registrar2(DatasetParams::ScriptParams::GetClassType()); const string DatasetsParams::_datasetsTag = "Datasets"; const string DatasetParams::_datasetTag = "Dataset"; const string DatasetParams::_scriptsTag = "Scripts"; const string DatasetParams::ScriptParams::_scriptTag = "Script"; const string DatasetParams::ScriptParams::_inputVarNamesTag = "InputVarNames"; const string DatasetParams::ScriptParams::_outputVarNamesTag = "OutputVarNames"; const string DatasetParams::ScriptParams::_outputVarMeshesTag = "OutputVarMeshes"; const string DatasetParams::ScriptParams::_coordFlagTag = "CoordFlag"; // DatasetsParams class: A collection of data sets // DatasetsParams::DatasetsParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, DatasetsParams::GetClassType()) { SetDiagMsg("DatasetsParams::DatasetsParams() this=%p", this); _datasets = new ParamsContainer(ssave, _datasetsTag); _datasets->SetParent(this); } DatasetsParams::DatasetsParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) { SetDiagMsg("DatasetsParams::DatasetsParams() this=%p", this); if (node->HasChild(_datasetsTag)) { _datasets = new ParamsContainer(ssave, node->GetChild(_datasetsTag)); } else { // Node doesn't contain a contours container _datasets = new ParamsContainer(ssave, _datasetsTag); _datasets->SetParent(this); } } DatasetsParams::DatasetsParams(const DatasetsParams &rhs) : ParamsBase(rhs) { _datasets = new ParamsContainer(*(rhs._datasets)); } DatasetsParams &DatasetsParams::operator=(const DatasetsParams &rhs) { if (_datasets) delete _datasets; ParamsBase::operator=(rhs); _datasets = new ParamsContainer(*(rhs._datasets)); return (*this); } DatasetsParams::~DatasetsParams() { SetDiagMsg("DatasetsParams::~DatasetsParams() this=%p", this); if (_datasets != NULL) { delete _datasets; _datasets = NULL; } } void DatasetsParams::SetScript(string datasetName, string name, string script, const vector &inputVarNames, const vector &outputVarNames, const vector &outputVarMeshes, bool coordFlag) { DatasetParams *s = (DatasetParams *)_datasets->GetParams(datasetName); if (s == NULL) { DatasetParams sParams(_ssave); _datasets->Insert(&sParams, datasetName); s = (DatasetParams *)_datasets->GetParams(datasetName); VAssert(s); } s->SetScript(name, script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag); } bool DatasetsParams::GetScript(string datasetName, string name, string &script, vector &inputVarNames, vector &outputVarNames, vector &outputVarMeshes, bool &coordFlag) const { script.clear(); inputVarNames.clear(); outputVarNames.clear(); outputVarMeshes.clear(); DatasetParams *s = (DatasetParams *)_datasets->GetParams(datasetName); if (s == NULL) return (false); s->GetScript(name, script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag); return (true); } void DatasetsParams::RemoveScript(string datasetName, string scriptName) { DatasetParams *s = (DatasetParams *)_datasets->GetParams(datasetName); if (s == NULL) return; s->RemoveScript(scriptName); } vector DatasetsParams::GetScriptNames(string datasetName) const { DatasetParams *s = (DatasetParams *)_datasets->GetParams(datasetName); if (s == NULL) return (vector()); return (s->GetScriptNames()); } // DatasetParams class: A single data set // DatasetParams::DatasetParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, DatasetParams::GetClassType()) { SetDiagMsg("DatasetParams::DatasetParams() this=%p", this); _scripts = new ParamsContainer(ssave, _scriptsTag); _scripts->SetParent(this); } DatasetParams::DatasetParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) { SetDiagMsg("DatasetParams::DatasetParams() this=%p", this); // If node isn't tagged correctly we correct the tag and reinitialize // from scratch; // if (node->GetTag() != DatasetParams::GetClassType()) { node->SetTag(DatasetParams::GetClassType()); } if (node->HasChild(_scriptsTag)) { _scripts = new ParamsContainer(ssave, node->GetChild(_scriptsTag)); } else { // Node doesn't contain a contours container _scripts = new ParamsContainer(ssave, _scriptsTag); _scripts->SetParent(this); } } DatasetParams::DatasetParams(const DatasetParams &rhs) : ParamsBase(rhs) { _scripts = new ParamsContainer(*(rhs._scripts)); } DatasetParams &DatasetParams::operator=(const DatasetParams &rhs) { if (_scripts) delete _scripts; ParamsBase::operator=(rhs); _scripts = new ParamsContainer(*(rhs._scripts)); return (*this); } DatasetParams::~DatasetParams() { SetDiagMsg("DatasetParams::~DatasetParams() this=%p", this); if (_scripts != NULL) { delete _scripts; _scripts = NULL; } } void DatasetParams::SetScript(string name, string script, const vector &inputVarNames, const vector &outputVarNames, const vector &outputVarMeshes, bool coordFlag) { ScriptParams *s = (ScriptParams *)_scripts->GetParams(name); if (s == NULL) { ScriptParams sParams(_ssave); _scripts->Insert(&sParams, name); s = (ScriptParams *)_scripts->GetParams(name); VAssert(s); } s->SetScript(script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag); } bool DatasetParams::GetScript(string name, string &script, vector &inputVarNames, vector &outputVarNames, vector &outputVarMeshes, bool &coordFlag) const { script.clear(); inputVarNames.clear(); outputVarNames.clear(); outputVarMeshes.clear(); ScriptParams *s = (ScriptParams *)_scripts->GetParams(name); if (s == NULL) return (false); s->GetScript(script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag); return (true); } }; // end namespace VAPoR ================================================ FILE: lib/params/FlowParams.cpp ================================================ #include "vapor/FlowParams.h" #include #include using namespace VAPoR; const std::string FlowParams::RenderTypeTag = "RenderTypeTag"; const std::string FlowParams::RenderRadiusBaseTag = "RenderRadiusBaseTag"; const std::string FlowParams::RenderRadiusScalarTag = "RenderRadiusScalarTag"; const std::string FlowParams::RenderGeom3DTag = "RenderGeom3DTag"; const std::string FlowParams::RenderLightAtCameraTag = "RenderLightAtCameraTag"; const std::string FlowParams::RenderShowStreamDirTag = "RenderShowStreamDirTag"; const std::string FlowParams::RenderGlyphTypeTag = "RenderGlyphTypeTag"; const std::string FlowParams::RenderGlyphStrideTag = "RenderGlyphStrideTag"; const std::string FlowParams::RenderGlyphOnlyLeadingTag = "RenderGlyphOnlyLeadingTag"; const std::string FlowParams::RenderDensityFalloffTag = "RenderDensityFalloffTag"; const std::string FlowParams::RenderDensityToneMappingTag = "RenderDensityToneMappingTag"; const std::string FlowParams::RenderFadeTailTag = "RenderFadeTailTag"; const std::string FlowParams::RenderFadeTailStartTag = "RenderFadeTailStartTag"; const std::string FlowParams::RenderFadeTailStopTag = "RenderFadeTailStopTag"; const std::string FlowParams::RenderFadeTailLengthTag = "RenderFadeTailLengthTag"; const std::string FlowParams::PhongAmbientTag = "PhongAmbientTag"; const std::string FlowParams::PhongDiffuseTag = "PhongDiffuseTag"; const std::string FlowParams::PhongSpecularTag = "PhongSpecularTag"; const std::string FlowParams::PhongShininessTag = "PhongShininessTag"; const std::string FlowParams::_isSteadyTag = "IsSteadyTag"; const std::string FlowParams::_velocityMultiplierTag = "VelocityMultiplierTag"; const std::string FlowParams::_firstStepSizeMultiplierTag = "FirstStepSizeMultiplierTag"; const std::string FlowParams::_fixedAdvectionStepTag= "FixedAdvectionStepTag"; const std::string FlowParams::_fixedAdvectionStepSizeTag= "FixedAdvectionStepSizeTag"; const std::string FlowParams::_steadyNumOfStepsTag = "SteadyNumOfStepsTag"; const std::string FlowParams::_seedGenModeTag = "SeedGenModeTag"; const std::string FlowParams::_seedInputFilenameTag = "SeedInputFilenameTag"; const std::string FlowParams::_flowlineOutputFilenameTag = "FlowlineOutputFilenameTag"; const std::string FlowParams::_flowOutputMoreVariablesTag = "FlowOutputMoreVariablesTag"; const std::string FlowParams::_flowDirectionTag = "FlowDirectionTag"; const std::string FlowParams::_needFlowlineOutputTag = "NeedFlowlineOutputTag"; const std::string FlowParams::_xPeriodicTag = "PeriodicTag_X"; const std::string FlowParams::_yPeriodicTag = "PeriodicTag_Y"; const std::string FlowParams::_zPeriodicTag = "PeriodicTag_Z"; const std::string FlowParams::_rakeTag = "RakeTag"; const std::string FlowParams::_doIntegrationTag = "DoIntegrationTag"; const std::string FlowParams::_integrationScalarTag = "IntegrationScalarTag"; const std::string FlowParams::_integrationSetAllToFinalValueTag = "IntegrationSetAllToFinalValueTag"; const std::string FlowParams::_integrationBoxTag = "IntegrationBoxTag"; const std::string FlowParams::_rakeBiasVariable = "RakeBiasVariable"; const std::string FlowParams::_rakeBiasStrength = "RakeBiasStrength"; const std::string FlowParams::_pastNumOfTimeSteps = "PastNumOfTimeSteps"; const std::string FlowParams::_seedInjInterval = "SeedInjInterval"; const std::string FlowParams::_xGridNumOfSeedsTag = "GridNumOfSeeds_X"; const std::string FlowParams::_yGridNumOfSeedsTag = "GridNumOfSeeds_Y"; const std::string FlowParams::_zGridNumOfSeedsTag = "GridNumOfSeeds_Z"; const std::string FlowParams::_randomNumOfSeedsTag = "RandomNumOfSeeds"; static RenParamsRegistrar registrar(FlowParams::GetClassType()); // Constructor FlowParams::FlowParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave) : RenderParams(dataManager, stateSave, FlowParams::GetClassType(), 3 /* max dim */) { SetVariableName(""); SetDiagMsg("FlowParams::FlowParams() this=%p", this); SetValueLong(RenderTypeTag, "", RenderTypeStream); SetValueDouble(RenderRadiusBaseTag, "", -1); SetValueDouble(RenderRadiusScalarTag, "", 1); SetValueLong(RenderGeom3DTag, "", false); SetValueLong(RenderLightAtCameraTag, "", true); SetValueLong(RenderShowStreamDirTag, "", false); SetValueLong(RenderGlyphTypeTag, "", GlpyhTypeSphere); SetValueLong(RenderGlyphStrideTag, "", 5); SetValueLong(RenderGlyphOnlyLeadingTag, "", false); SetValueDouble(RenderDensityFalloffTag, "", 1); SetValueDouble(RenderDensityToneMappingTag, "", 1); SetValueLong(RenderFadeTailTag, "", false); SetValueLong(RenderFadeTailStartTag, "", 10); SetValueLong(RenderFadeTailLengthTag, "", 10); SetValueLong(RenderFadeTailStopTag, "", 0); SetValueDouble(PhongAmbientTag, "", 0.4); SetValueDouble(PhongDiffuseTag, "", 0.8); SetValueDouble(PhongSpecularTag, "", 0); SetValueDouble(PhongShininessTag, "", 2); // Give the random bias variable the same as color mapping variable. auto colorvar = GetColorMapVariableName(); SetValueString(_rakeBiasVariable, "which variable to bias with", colorvar); } FlowParams::FlowParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, XmlNode *node) : RenderParams(dataManager, stateSave, node, 3 /* max dim */) { _initialized = true; SetDiagMsg("FlowParams::FlowParams() this=%p", this); } // Destructor FlowParams::~FlowParams() { SetDiagMsg("FlowParams::~FlowParams() this=%p", this); if (_fakeRakeBox) delete _fakeRakeBox; if (_fakeIntegrationBox) delete _fakeIntegrationBox; } int FlowParams::Initialize() { int rc = RenderParams::Initialize(); if (rc < 0) return (rc); if (_initialized) return 0; // At this point the base class is initialized, and the _Box is // properly initialized // to be the extents of the domain. Let's use that information to // initialize the rake! // std::vector minext, maxext; auto box = RenderParams::GetBox(); box->GetExtents(minext, maxext); std::vector floats(minext.size() * 2); for (int i = 0; i < minext.size(); i++) { floats[i * 2] = minext[i]; floats[i * 2 + 1] = maxext[i]; } this->SetRake(floats); this->SetIntegrationVolume(floats); vector rake; rake.push_back(minext[0]); rake.push_back(maxext[0]); rake.push_back(minext[1]); rake.push_back(maxext[1]); if (minext.size() == 3) { rake.push_back(minext[2]); rake.push_back(maxext[2]); } SetRake(rake); SetIntegrationVolume(rake); SetFlowDirection((int)FlowDir::FORWARD); SetSteadyNumOfSteps(100); SetVelocityMultiplier(1.0); SetFirstStepSizeMultiplier(1.0); SetUseFixedAdvectionSteps(false); SetFixedAdvectionStepSize(0.0); SetPeriodic(vector(3, false)); SetGridNumOfSeeds({5, 5, 1}); SetRandomNumOfSeeds(50); SetFlowlineOutputFilename(Wasp::FileUtils::HomeDir() + "/VaporFlow.txt"); SetSeedInputFilename(Wasp::GetSharePath("examples/listOfSeeds.txt")); SetIsSteady(true); SetPastNumOfTimeSteps(std::max(_dataMgr->GetNumTimeSteps() - 1, 1)); SetValueLong(_doIntegrationTag, "", false); SetValueDouble(_integrationScalarTag, "", 1.f); SetValueLong(_integrationSetAllToFinalValueTag, "", false); return (0); } void FlowParams::SetDefaultVariables(int dim, bool secondaryColormapVariable) { RenderParams::SetDefaultVariables(dim, secondaryColormapVariable); std::vector varnames = _dataMgr->GetDataVarNames(dim); if (varnames.size()) SetRakeBiasVariable(varnames[0]); } void FlowParams::SetIsSteady(bool steady) { SetValueLong(_isSteadyTag, "are we using steady advection", long(steady)); } bool FlowParams::GetIsSteady() const { long rv = GetValueLong(_isSteadyTag, long(true)); return bool(rv); } void FlowParams::SetNeedFlowlineOutput(bool need) { SetValueLong(_needFlowlineOutputTag, "need to do an output of the flow lines", long(need)); } bool FlowParams::GetNeedFlowlineOutput() const { long rv = GetValueLong(_needFlowlineOutputTag, long(false)); return bool(rv); } double FlowParams::GetVelocityMultiplier() const { return GetValueDouble(_velocityMultiplierTag, 1.0); } double FlowParams::GetFirstStepSizeMultiplier() const { return GetValueDouble(_firstStepSizeMultiplierTag, 1.0); } bool FlowParams::GetUseFixedAdvectionSteps() const { return GetValueLong(_fixedAdvectionStepTag, 0); } double FlowParams::GetFixedAdvectionStepSize() const { return GetValueDouble(_fixedAdvectionStepSizeTag, 0.0); } void FlowParams::SetVelocityMultiplier(double coeff) { SetValueDouble(_velocityMultiplierTag, "Field Scale Factor", coeff); } void FlowParams::SetFirstStepSizeMultiplier(double coeff) { SetValueDouble(_firstStepSizeMultiplierTag, "first step size multiplier", coeff); } void FlowParams::SetUseFixedAdvectionSteps(bool fixed) { SetValueLong(_fixedAdvectionStepTag, "Use Fixed Advection Steps", long(fixed)); } void FlowParams::SetFixedAdvectionStepSize(double step) { SetValueDouble(_fixedAdvectionStepSizeTag, "Fixed Advection Step Size", step); } long FlowParams::GetSteadyNumOfSteps() const { return GetValueLong(_steadyNumOfStepsTag, 100); } void FlowParams::SetSteadyNumOfSteps(long i) { SetValueLong(_steadyNumOfStepsTag, "num of steps for a steady integration", i); } int FlowParams::GetSeedGenMode() const { return GetValueLong(_seedGenModeTag, (int)FlowSeedMode::UNIFORM); } void FlowParams::SetSeedGenMode(int i) { SetValueLong(_seedGenModeTag, "", i); } std::string FlowParams::GetSeedInputFilename() const { return GetValueString(_seedInputFilenameTag, ""); } void FlowParams::SetSeedInputFilename(const std::string &name) { SetValueString(_seedInputFilenameTag, "filename for input seeding list", name); } std::string FlowParams::GetFlowlineOutputFilename() const { return GetValueString(_flowlineOutputFilenameTag, ""); } void FlowParams::SetFlowlineOutputFilename(const std::string &name) { SetValueString(_flowlineOutputFilenameTag, "filename for output flow lines", name); } std::vector FlowParams::GetFlowOutputMoreVariables() const { return GetValueStringVec(_flowOutputMoreVariablesTag); } void FlowParams::SetFlowOutputMoreVariables(std::vector vars) { SetValueStringVec(_flowOutputMoreVariablesTag, "", vars); } int FlowParams::GetFlowDirection() const { return GetValueLong(_flowDirectionTag, (int)FlowDir::FORWARD); } void FlowParams::SetFlowDirection(int i) { VAssert(i == (int)FlowDir::FORWARD || i == (int)FlowDir::BACKWARD || i == (int)FlowDir::BI_DIR); SetValueLong(_flowDirectionTag, "", i); } std::vector FlowParams::GetPeriodic() const { vector sav; sav.push_back(GetValueLong(_xPeriodicTag, false)); sav.push_back(GetValueLong(_yPeriodicTag, false)); if (GetRenderDim() == 3) sav.push_back(GetValueLong(_zPeriodicTag, false)); return sav; } void FlowParams::SetPeriodic(const std::vector &bools) { VAssert(bools.size() == 3 || bools.size() == 2); SetValueLong(_xPeriodicTag, "", bools[0]); SetValueLong(_yPeriodicTag, "", bools[1]); if (bools.size() == 3) SetValueLong(_zPeriodicTag, "", bools[2]); } void FakeRakeBox::Initialize(string tag) { _tag = tag; vector flowBox = parent->GetValueDoubleVec(tag); if (flowBox.size() != 4 && flowBox.size() != 6) { vector min, max; parent->GetBox()->GetExtents(min, max); SetExtents(min, max); flowBox = parent->GetValueDoubleVec(tag); } vector min, max; min.push_back(flowBox[0]); max.push_back(flowBox[1]); min.push_back(flowBox[2]); max.push_back(flowBox[3]); if (flowBox.size() == 6) { min.push_back(flowBox[4]); max.push_back(flowBox[5]); } Box::SetExtents(min, max); } void FakeRakeBox::SetExtents(const vector &min, const vector &max) { VAssert(parent); vector rake; rake.push_back(min[0]); rake.push_back(max[0]); rake.push_back(min[1]); rake.push_back(max[1]); if (min.size() == 3) { rake.push_back(min[2]); rake.push_back(max[2]); } BeginGroup("Set fake region"); parent->SetValueDoubleVec(_tag, "", rake); Initialize(_tag); EndGroup(); } Box *FlowParams::GetRakeBox() { if (!_fakeRakeBox) { _fakeRakeBox = new FakeRakeBox(&_fakeRakeStateSave); _fakeRakeBox->parent = this; } Box *extBox = GetBox(); _fakeRakeBox->SetPlanar(extBox->IsPlanar()); _fakeRakeBox->SetOrientation(extBox->GetOrientation()); _fakeRakeBox->Initialize(_rakeTag); return _fakeRakeBox; } Box *FlowParams::GetIntegrationBox() { if (!_fakeIntegrationBox) { _fakeIntegrationBox = new FakeRakeBox(&_fakeRakeStateSave); _fakeIntegrationBox->parent = this; } Box *extBox = GetBox(); _fakeIntegrationBox->SetPlanar(extBox->IsPlanar()); _fakeIntegrationBox->SetOrientation(extBox->GetOrientation()); _fakeIntegrationBox->Initialize(_integrationBoxTag); return _fakeIntegrationBox; } std::vector FlowParams::GetRake() const { auto doubles = GetValueDoubleVec(_rakeTag); vector ret; int dim = GetRenderDim(); for (int i = 0; i < dim * 2; i++) { if (i < doubles.size()) ret.push_back(doubles[i]); else ret.push_back(5); } return ret; } void FlowParams::SetRake(const std::vector &rake) { const auto rakesize = rake.size(); VAssert(rakesize == 4 || rakesize == 6); std::vector doubles(rakesize); std::copy(rake.cbegin(), rake.cend(), doubles.begin()); SetValueDoubleVec(_rakeTag, "rake boundaries", doubles); } void FlowParams::SetIntegrationVolume(const std::vector &rake) { const auto rakesize = rake.size(); VAssert(rakesize == 4 || rakesize == 6); std::vector doubles(rakesize); std::copy(rake.cbegin(), rake.cend(), doubles.begin()); SetValueDoubleVec(_integrationBoxTag, "", doubles); } std::vector FlowParams::GetGridNumOfSeeds() const { vector sav(3); sav[0] = GetValueLong(_xGridNumOfSeedsTag, 5); sav[1] = GetValueLong(_yGridNumOfSeedsTag, 5); sav[2] = GetValueLong(_zGridNumOfSeedsTag, 5); vector ret; int dims = GetRenderDim(); for (int i = 0; i < dims; i++) ret.push_back(sav[i]); return ret; } void FlowParams::SetGridNumOfSeeds(const std::vector &num) { VAssert(num.size() == 3 || num.size() == 2); SetValueLong(_xGridNumOfSeedsTag, "", num[0]); SetValueLong(_yGridNumOfSeedsTag, "", num[1]); if (num.size() == 3) SetValueLong(_zGridNumOfSeedsTag, "", num[2]); } long FlowParams::GetRandomNumOfSeeds() const { return GetValueLong(_randomNumOfSeedsTag, 50); } void FlowParams::SetRandomNumOfSeeds(long num) { VAssert(num >= 0); SetValueLong(_randomNumOfSeedsTag, "random num of seeds", num); } std::string FlowParams::GetRakeBiasVariable() const { std::string empty; return GetValueString(_rakeBiasVariable, empty); } void FlowParams::SetRakeBiasVariable(const std::string &varname) { SetValueString(_rakeBiasVariable, "which variable to bias with", varname); } long FlowParams::GetRakeBiasStrength() const { return (GetValueLong(_rakeBiasStrength, 0)); } void FlowParams::SetRakeBiasStrength(long strength) { SetValueLong(_rakeBiasStrength, "bias strength", strength); } int FlowParams::GetPastNumOfTimeSteps() const { // return -1 as an obvious invalid value. Valid values are greater than 0 return int(GetValueLong(_pastNumOfTimeSteps, -1)); } void FlowParams::SetPastNumOfTimeSteps(int val) { SetValueLong(_pastNumOfTimeSteps, "how many past time steps to render", val); } int FlowParams::GetSeedInjInterval() const { // return -1 as an obvious invalid value. // 0 means no repeated seed injection // 1 means every time step, 2 means every other time step, etc. return int(GetValueLong(_seedInjInterval, -1)); } void FlowParams::SetSeedInjInterval(int val) { SetValueLong(_seedInjInterval, "What's the interval of injecting seeds into an unsteady flow advection", val); } double FlowParams::_getRakeCenter(int dim) { Box *rakeBox = GetRakeBox(); if (rakeBox == nullptr) return 0.; VAPoR::CoordType minExt, maxExt; rakeBox->GetExtents(minExt, maxExt); return (maxExt[dim] + minExt[dim]) / 2.; } void FlowParams::_setRakeCenter(int dim, double center) { Box *rakeBox = GetRakeBox(); if (rakeBox == nullptr) return; VAPoR::CoordType minExt, maxExt; rakeBox->GetExtents(minExt, maxExt); double length = (maxExt[dim] - minExt[dim]) / 2.; maxExt[dim] = center + length; minExt[dim] = center - length; rakeBox->SetExtents(minExt, maxExt); } double FlowParams::GetXRakeCenter() { return _getRakeCenter(0); } void FlowParams::SetXRakeCenter(double center) { _setRakeCenter(0, center); } double FlowParams::GetYRakeCenter() { return _getRakeCenter(1); } void FlowParams::SetYRakeCenter(double center) { _setRakeCenter(1, center); } double FlowParams::GetZRakeCenter() { return _getRakeCenter(2); } void FlowParams::SetZRakeCenter(double center) { _setRakeCenter(2, center); } ================================================ FILE: lib/params/GUIStateParams.cpp ================================================ //************************************************************************ // * // Copyright (C) 2016 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: GUIStateParams.cpp // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: August 2016 // #ifdef WIN32 // Annoying unreferenced formal parameter warning #pragma warning(disable : 4100) #endif #include #include #include #include #include #include #include using namespace VAPoR; const string GUIStateParams::m_activeVisualizer = "ActiveVisualizer"; const string GUIStateParams::m_pathParamsTag = "PathParamsTag"; const string GUIStateParams::m_sessionFileTag = "SessionFileTag"; const string GUIStateParams::m_imagePathTag = "ImagePathTag"; const string GUIStateParams::m_imageSavePathTag = "ImageSavePathTag"; const string GUIStateParams::m_pythonPathTag = "PythonPathTag"; const string GUIStateParams::m_flowPathTag = "FlowPathTag"; const string GUIStateParams::m_tfPathTag = "TFPathTag"; const string GUIStateParams::m_statsDatasetNameTag = "StatsDatasetNameTag"; const string GUIStateParams::m_plotDatasetNameTag = "PlotDatasetNameTag"; const string GUIStateParams::m_proj4StringTag = "Proj4StringTag"; const string GUIStateParams::m_openDataSetsTag = "OpenDataSetsTag"; const string GUIStateParams::_flowDimensionalityTag = "_flowDimensionalityTag"; const string GUIStateParams::BookmarksTag = "BookmarksTag"; const string GUIStateParams::MovingDomainTrackCameraTag = "MovingDomainTrackCameraTag"; const string GUIStateParams::MovingDomainTrackRenderRegionsTag = "MovingDomainTrackRenderRegionsTag"; const string GUIStateParams::ImportDataTypeTag = "ImportDataTypeTag"; const string GUIStateParams::SessionNewTag = "SessionNewTag"; const string GUIStateParams::DataSetParam::m_dataSetPathsTag = "DataSetPathsTag"; const string GUIStateParams::DataSetParam::m_dataSetRelativePathsTag = "DataSetRelativePathsTag"; const string GUIStateParams::DataSetParam::m_dataSetFormatTag = "DataSetFormatTag"; // // Register class with object factory!!! // static ParamsRegistrar registrar(GUIStateParams::GetClassType()); static ParamsRegistrar registrar_dsp(GUIStateParams::DataSetParam::GetClassType()); //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- GUIStateParams::GUIStateParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, GetClassType()) { _init(); m_activeRenderer = new ActiveRenderer(ssave); m_activeRenderer->GetNode()->SetParent(GetNode()); m_mouseModeParams = new MouseModeParams(ssave); m_mouseModeParams->GetNode()->SetParent(GetNode()); // Create a Params container for multiple opacity maps // m_openDataSets = new ParamsContainer(ssave, m_openDataSetsTag); m_openDataSets->SetParent(this); _bookmarks = new ParamsContainer(ssave, BookmarksTag); _bookmarks->SetParent(this); } GUIStateParams::GUIStateParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) { // If node isn't tagged correctly we correct the tag and reinitialize // from scratch; // if (node->GetTag() != GUIStateParams::GetClassType()) { node->SetTag(GUIStateParams::GetClassType()); _init(); } if (node->HasChild(MouseModeParams::GetClassType())) { m_mouseModeParams = new MouseModeParams(ssave, node->GetChild(MouseModeParams::GetClassType())); } else { m_mouseModeParams = new MouseModeParams(ssave); m_mouseModeParams->GetNode()->SetParent(GetNode()); } if (node->HasChild(ActiveRenderer::GetClassType())) { m_activeRenderer = new ActiveRenderer(ssave, node->GetChild(ActiveRenderer::GetClassType())); } else { m_activeRenderer = new ActiveRenderer(ssave); m_activeRenderer->GetNode()->SetParent(GetNode()); } if (node->HasChild(m_openDataSetsTag)) { m_openDataSets = new ParamsContainer(ssave, node->GetChild(m_openDataSetsTag)); } else { // Node doesn't contain a opacity map // m_openDataSets = new ParamsContainer(ssave, m_openDataSetsTag); m_openDataSets->SetParent(this); } if (node->HasChild(BookmarksTag)) { _bookmarks = new ParamsContainer(ssave, node->GetChild(BookmarksTag)); } else { _bookmarks = new ParamsContainer(ssave, BookmarksTag); _bookmarks->SetParent(this); } } GUIStateParams::GUIStateParams(const GUIStateParams &rhs) : ParamsBase(rhs) { m_mouseModeParams = new MouseModeParams(*(rhs.m_mouseModeParams)); m_activeRenderer = new ActiveRenderer(*(rhs.m_activeRenderer)); _bookmarks = new ParamsContainer(*(rhs._bookmarks)); } GUIStateParams &GUIStateParams::operator=(const GUIStateParams &rhs) { m_mouseModeParams = new MouseModeParams(*(rhs.m_mouseModeParams)); m_activeRenderer = new ActiveRenderer(*(rhs.m_activeRenderer)); _bookmarks = new ParamsContainer(*(rhs._bookmarks)); return (*this); } //---------------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------------- GUIStateParams::~GUIStateParams() {} //---------------------------------------------------------------------------- // Getters and Setters //---------------------------------------------------------------------------- string GUIStateParams::GetActiveVizName() const { string defaultv; return (GetValueString(m_activeVisualizer, defaultv)); } void GUIStateParams::SetActiveVizName(string vizWin) { bool e = _ssave->GetUndoEnabled(); _ssave->SetUndoEnabled(false); SetValueString(m_activeVisualizer, "Set active visualizer window", vizWin); _ssave->SetUndoEnabled(e); } //! Get active renderer class and instance name for a visualizer // void GUIStateParams::GetActiveRenderer(string vizWin, string &renderType, string &renderInst) const { m_activeRenderer->GetActiveRenderer(vizWin, renderType, renderInst); } string GUIStateParams::GetActiveRendererInst() const { string renderType, renderInst; GetActiveRenderer(GetActiveVizName(), renderType, renderInst); return renderInst; } //! Set active renderer class and instance name for a visualizer // void GUIStateParams::SetActiveRenderer(string vizWin, string renderType, string renderInst) { bool e = _ssave->GetUndoEnabled(); _ssave->SetUndoEnabled(false); BeginGroup("Set active " + renderInst); SetValueString("Active_Dataset", "", ""); m_activeRenderer->SetActiveRenderer(vizWin, renderType, renderInst); EndGroup(); _ssave->SetUndoEnabled(e); } string GUIStateParams::GetActiveDataset() const { string name = GetValueString("Active_Dataset", ""); if (!STLUtils::Contains(GetOpenDataSetNames(), name)) return ""; return name; } void GUIStateParams::SetActiveDataset(std::string name) { assert(STLUtils::Contains(GetOpenDataSetNames(), name)); bool e = _ssave->GetUndoEnabled(); _ssave->SetUndoEnabled(false); BeginGroup("Set active dataset"); SetActiveRenderer(GetActiveVizName(), "", ""); SetValueString("Active_Dataset", "", name); EndGroup(); _ssave->SetUndoEnabled(e); } string GUIStateParams::GetCurrentSessionFile() const { return (GetValueString(m_sessionFileTag, "")); } void GUIStateParams::SetCurrentSessionFile(string path) { SetValueString(m_sessionFileTag, "Set current session file path", path); } //! method identifies the current session file //! \retval session file path string GUIStateParams::GetCurrentImagePath() const { return (GetValueString(m_imagePathTag, Wasp::FileUtils::HomeDir())); } //! method sets the current session path //! \param[in] path string void GUIStateParams::SetCurrentImagePath(string path) { SetValueString(m_imagePathTag, "Set current image path", path); } //! method identifies the current session file //! \retval session file path string GUIStateParams::GetCurrentImageSavePath() const { return (GetValueString(m_imageSavePathTag, Wasp::FileUtils::HomeDir())); } //! method sets the current session path //! \param[in] path string void GUIStateParams::SetCurrentImageSavePath(string path) { SetValueString(m_imageSavePathTag, "Set current image path", path); } //! method identifies the current session file //! \retval session file path string GUIStateParams::GetCurrentTFPath() { return (GetValueString(m_tfPathTag, Wasp::FileUtils::HomeDir())); } //! method sets the current session path //! \param[in] path string void GUIStateParams::SetCurrentTFPath(string path) { SetValueString(m_tfPathTag, "Set current tf path", path); } //! method identifies the current session file //! \retval session file path string GUIStateParams::GetCurrentPythonPath() const { return (GetValueString(m_pythonPathTag, Wasp::FileUtils::HomeDir())); } //! method sets the current session path //! \param[in] path string void GUIStateParams::SetCurrentPythonPath(string path) { SetValueString(m_pythonPathTag, "Set current python path", path); } //! method identifies the current session file //! \retval session file path string GUIStateParams::GetCurrentFlowPath() const { return (GetValueString(m_flowPathTag, Wasp::FileUtils::HomeDir())); } //! method sets the current session path //! \param[in] path string void GUIStateParams::SetCurrentFlowPath(string path) { SetValueString(m_flowPathTag, "Set current flow path", path); } MouseModeParams *GUIStateParams::GetMouseModeParams() const { return (m_mouseModeParams); } //---------------------------------------------------------------------------- // Funcs //---------------------------------------------------------------------------- vector GUIStateParams::GetOpenDataSetPaths(string dataSetName) const { DataSetParam *dsParams = (DataSetParam *)m_openDataSets->GetParams(dataSetName); if (!dsParams) { return (vector()); } vector paths = dsParams->GetPaths(); if (paths.empty()) paths.push_back(""); return (paths); } vector GUIStateParams::GetOpenDataSetRelativePaths(string dataSetName) const { DataSetParam *dsParams = (DataSetParam *)m_openDataSets->GetParams(dataSetName); if (!dsParams) { return (vector()); } return dsParams->GetRelativePaths(); } string GUIStateParams::GetOpenDataSetFormat(string dataSetName) const { DataSetParam *dsParams = (DataSetParam *)m_openDataSets->GetParams(dataSetName); if (!dsParams) { return (""); } return (dsParams->GetFormat()); } void GUIStateParams::InsertOpenDataSet(string dataSetName, string format, const vector &paths, const vector &relPaths) { m_openDataSets->Remove(dataSetName); DataSetParam dsParam(_ssave); dsParam.SetPaths(paths); dsParam.SetFormat(format); if (relPaths.size() == paths.size()) dsParam.SetRelativePaths(relPaths); m_openDataSets->Insert(&dsParam, dataSetName); } void GUIStateParams::AddBookmark(BookmarkParams *bookmark) { _bookmarks->Insert(bookmark, "i_" + std::to_string(_bookmarks->Size())); } BookmarkParams *GUIStateParams::CreateBookmark() { return (BookmarkParams *)_bookmarks->Create(BookmarkParams::GetClassType(), "i_" + std::to_string(_bookmarks->Size())); } void GUIStateParams::SetBookmarks(const vector &all) { ClearBookmarks(); for (auto b : all) AddBookmark(b); } void GUIStateParams::DeleteBookmark(int i) { auto b = GetBookmark(i); if (b) _bookmarks->Remove(b); } void GUIStateParams::ClearBookmarks() { auto names = _bookmarks->GetNames(); for (auto &name : names) _bookmarks->Remove(name); } vector GUIStateParams::GetBookmarks() const { vector ret; auto names = _bookmarks->GetNames(); for (auto &name : names) ret.push_back((BookmarkParams *)_bookmarks->GetParams(name)); return ret; } int GUIStateParams::GetNumBookmarks() const { return _bookmarks->Size(); } BookmarkParams *GUIStateParams::GetBookmark(int i) const { assert(i >= 0 && i < _bookmarks->Size()); if (i < 0 && i >= _bookmarks->Size()) return NULL; return (BookmarkParams *)_bookmarks->GetParams(_bookmarks->GetNames()[i]); } void GUIStateParams::_init() { SetActiveVizName(""); SetValueLong(MovingDomainTrackCameraTag, "", true); SetValueLong(MovingDomainTrackRenderRegionsTag, "", true); SetValueString(ImportDataTypeTag, "Default dataset to import", "WRF-ARW") ; SetValueLong(SessionNewTag, "Open dataset as a new session", true); } void GUIStateParams::ActiveRenderer::SetActiveRenderer(string vizWin, string renderType, string renderInst) { std::vector v; v.push_back(renderType); v.push_back(renderInst); bool e = _ssave->GetUndoEnabled(); _ssave->SetUndoEnabled(false); SetValueStringVec(vizWin, "Set active render type and instance", v); _ssave->SetUndoEnabled(e); } void GUIStateParams::ActiveRenderer::GetActiveRenderer(string vizWin, string &renderType, string &renderInst) const { std::vector defaultv(2, ""); std::vector v = GetValueStringVec(vizWin, defaultv); renderType = v[0]; renderInst = v[1]; } std::string GUIStateParams::GetStatsDatasetName() const { return GetValueString(m_statsDatasetNameTag, ""); } void GUIStateParams::SetStatsDatasetName(std::string &name) { SetValueString(m_statsDatasetNameTag, "Name of the active data set in Statistics", name); } std::string GUIStateParams::GetPlotDatasetName() const { return GetValueString(m_plotDatasetNameTag, ""); } void GUIStateParams::SetPlotDatasetName(std::string &name) { SetValueString(m_plotDatasetNameTag, "Name of the active data set in Plot", name); } string GUIStateParams::ActiveTab() const { return GetValueString("ActiveTabTag", ""); } void GUIStateParams::SetActiveTab(const string &t) { bool e = _ssave->GetUndoEnabled(); _ssave->SetUndoEnabled(false); SetValueString("ActiveTabTag", "", t); _ssave->SetUndoEnabled(e); } int GUIStateParams::GetFlowDimensionality() const { return GetValueLong(_flowDimensionalityTag, -1); } void GUIStateParams::SetFlowDimensionality(int nDims) { if (nDims > 3) nDims = 3; else if (nDims < 2) nDims = 2; SetValueLong(_flowDimensionalityTag, _flowDimensionalityTag, nDims); } ================================================ FILE: lib/params/HelloParams.cpp ================================================ #include #include using namespace Wasp; using namespace VAPoR; // Provide values for all the tags const string HelloParams::m_lineThicknessTag = "LineThickness"; const string HelloParams::m_point1Tag = "Point1"; const string HelloParams::m_point2Tag = "Point2"; // // Register class with object factory!!! // static RenParamsRegistrar registrar(HelloParams::GetClassType()); HelloParams::HelloParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, HelloParams::GetClassType()) { // restart provides default values even with no data mgr _init(); } HelloParams::HelloParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node) {} HelloParams::~HelloParams() {} // Set everything to default values. // Data Manager is absent. void HelloParams::_init() { SetLineThickness(1.0); vector pt1; vector pt2; GetBox()->GetExtents(pt1, pt2); SetPoint1(pt1); SetPoint2(pt2); } ================================================ FILE: lib/params/ImageParams.cpp ================================================ #include #include #include using namespace VAPoR; const std::string ImageParams::_fileNameTag = "FileName"; const std::string ImageParams::_isGeoRefTag = "IsGeoRefTag"; const std::string ImageParams::_ignoreTransparencyTag = "IgnoreTransparency"; const std::string ImageParams::_opacityTag = "Opacity"; const std::string ImageParams::_orientationTag = "Orientation"; const std::string ImageParams::_TMSLODTag = "TMSLevelOfDetail"; const std::string ImageParams::_numTMSLODTag = "numTMSLevelOfDetail"; // // Register class with object factory // static RenParamsRegistrar registrar(ImageParams::GetClassType()); ImageParams::ImageParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave) : RenderParams(dataManager, stateSave, ImageParams::GetClassType(), 2) { SetVariableName(""); SetFieldVariableNames(vector()); SetDiagMsg("ImageParams::ImageParams() this=%p", this); } ImageParams::ImageParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, XmlNode *node) : RenderParams(dataManager, stateSave, node, 2) { _initialized = true; } ImageParams::~ImageParams() { SetDiagMsg("ImageParams::~ImageParams() this=%p", this); } int ImageParams::Initialize() { int rc = RenderParams::Initialize(); if (rc < 0) return (rc); if (_initialized) return 0; // RenderParams will initialize the Box class based on the dimensionality // of the variable's supported by a particular renderer. The image renderer // is unique in that it operates on 2D variables if they exist. If they // don't we'll use any 3D variables to set up the Box correctly // for (int ndim = 2; ndim < 4; ndim++) { size_t ts; string varname; if (DataMgrUtils::GetFirstExistingVariable(_dataMgr, 0, 0, ndim, varname, ts)) { if (InitBoxFromVariable(ts, varname)) break; } } // The image renderer behaves like a 2D renderer, but it doesn't operate // on any data variables. Make sure the box is planar. // GetBox()->SetOrientation(VAPoR::Box::XY); GetBox()->SetPlanar(true); SetImagePath(Wasp::GetSharePath("images/NaturalEarth.tms")); SetIsGeoRef(true); SetIgnoreTransparency(false); _initialized = true; return (0); } std::string ImageParams::GetImagePath() const { std::string defaultImage = Wasp::GetSharePath("images/NaturalEarth.tms"); return GetValueString(_fileNameTag, defaultImage); } ================================================ FILE: lib/params/MapperFunction.cpp ================================================ //************************************************************************ // * // Copyright (C) 2005 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: MapperFunction.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: August 2005 // // Description: Implements the MapperFunction class // Provides separate mapping of color and opacity with separate domain // bounds. // // #ifdef WIN32 #pragma warning(disable : 4251 4100) #endif #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include using namespace VAPoR; using namespace Wasp; const string MapperFunction::_dataBoundsTag = "DataBounds"; const string MapperFunction::_opacityCompositionTag = "OpacityComposition"; const string MapperFunction::_opacityScaleTag = "OpacityScale"; const string MapperFunction::_opacityMapsTag = "OpacityMaps"; const string MapperFunction::_opacityMapTag = "OpacityMap"; const string MapperFunction::_autoUpdateHistoTag = "AutoUpdateHisto"; const string MapperFunction::_secondaryVarMapperTag = "SecondaryVarMapper"; const string MapperFunction::CustomMappingSliderRangeTag = "CustomMappingSliderRange"; const string MapperFunction::IsUsingCustomMappingSliderRangeTag = "IsUsingCustomMappingSliderRange"; // // Register class with object factory!!! // static ParamsRegistrar registrar(MapperFunction::GetClassType()); //---------------------------------------------------------------------------- // Constructor for empty, default Mapper function //---------------------------------------------------------------------------- MapperFunction::MapperFunction(ParamsBase::StateSave *ssave) : ParamsBase(ssave, MapperFunction::GetClassType()), _numEntries(256) { m_colorMap = NULL; m_opacityMaps = NULL; setOpacityScale(1.0); setOpacityComposition(ADDITION); m_colorMap = new ColorMap(ssave); m_colorMap->SetParent(this); // Create a Params container for multiple opacity maps // m_opacityMaps = new ParamsContainer(ssave, _opacityMapsTag); m_opacityMaps->SetParent(this); // Populate container with a single default opacity map // OpacityMap opacityMap(ssave); m_opacityMaps->Insert(&opacityMap, _make_omap_name(0)); setMinMaxMapValue(1., -1.); } MapperFunction::MapperFunction(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node), _numEntries(256) { m_colorMap = NULL; m_opacityMaps = NULL; if (node->HasChild(ColorMap::GetClassType())) { m_colorMap = new ColorMap(ssave, node->GetChild(ColorMap::GetClassType())); } else { // Node doesn't contain a colormap // m_colorMap = new ColorMap(ssave); m_colorMap->SetParent(this); } if (node->HasChild(_opacityMapsTag)) { m_opacityMaps = new ParamsContainer(ssave, node->GetChild(_opacityMapsTag)); } else { // Node doesn't contain a opacity map // m_opacityMaps = new ParamsContainer(ssave, _opacityMapsTag); m_opacityMaps->SetParent(this); // Populate container with a single default opacity map // OpacityMap opacityMap(ssave); m_opacityMaps->Insert(&opacityMap, _make_omap_name(0)); } } MapperFunction::MapperFunction(const MapperFunction &rhs) : ParamsBase(rhs), _numEntries(256) { m_colorMap = NULL; m_opacityMaps = NULL; m_colorMap = new ColorMap(*(rhs.m_colorMap)); m_colorMap->SetParent(this); m_opacityMaps = new ParamsContainer(*(rhs.m_opacityMaps)); m_opacityMaps->SetParent(this); } MapperFunction &MapperFunction::operator=(const MapperFunction &rhs) { if (m_colorMap) delete m_colorMap; if (m_opacityMaps) delete m_opacityMaps; ParamsBase::operator=(rhs); m_colorMap = NULL; m_opacityMaps = NULL; m_colorMap = new ColorMap(rhs._ssave, rhs.m_colorMap->GetNode()); m_colorMap->SetParent(this); m_opacityMaps = new ParamsContainer(rhs._ssave, rhs.m_opacityMaps->GetNode()); m_opacityMaps->SetParent(this); return (*this); } //---------------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------------- MapperFunction::~MapperFunction() { MyBase::SetDiagMsg("MapperFunction::~MapperFunction()"); if (m_colorMap) delete m_colorMap; if (m_opacityMaps) delete m_opacityMaps; } //---------------------------------------------------------------------------- // Create a mapper function by parsing a file. //---------------------------------------------------------------------------- int MapperFunction::LoadFromFile(string path) { XmlParser xmlparser; XmlNode *node = new XmlNode(); int rc = xmlparser.LoadFromFile(node, path); if (rc < 0) { MyBase::SetErrMsg("Failed to read file %s : %M", path.c_str()); return (-1); } // Create a new MapperFunction from the XmlNode tree // XmlNode * parent = this->GetNode()->GetParent(); MapperFunction *newTF = new MapperFunction(_ssave, node); // Assign (copy) new TF to this object // *this = *newTF; this->GetNode()->SetParent(parent); // Delete the new tree // delete newTF; _ssave->Save(_node, "Load transfer function from file"); return (0); } int MapperFunction::LoadColormapFromFile(string path) { MapperFunction temp = *this; int rc = temp.LoadFromFile(path); if (rc < 0) return rc; *m_colorMap = *temp.GetColorMap(); m_colorMap->SetParent(this); // Apparently the colormap stores its own copy of the mapping range. // This could be solved differently but the fact that this // is a valid solution is amusing. setMinMaxMapValue(getMinMapValue(), getMaxMapValue()); return rc; } //---------------------------------------------------------------------------- // Save the mapper function to a file. //---------------------------------------------------------------------------- int MapperFunction::SaveToFile(string path) { ofstream out(path); if (!out) { MyBase::SetErrMsg("Failed to open file %s : %M", path.c_str()); return (-1); } XmlNode *node = GetNode(); out << *node; if (out.bad()) { MyBase::SetErrMsg("Failed to write file %s : %M", path.c_str()); return (-1); } out.close(); return (0); } //---------------------------------------------------------------------------- // Calculate the opacity given the data value //---------------------------------------------------------------------------- float MapperFunction::getOpacityValueData(float value) const { int count = 0; // // Using the square of the opacity scaling factor gives // better control over low opacity values. // But this correction will be made in the GUI // float opacScale = getOpacityScale(); float opacity = 0.0; if (getOpacityComposition() == MULTIPLICATION) { opacity = 1.0; } for (int i = 0; i < getNumOpacityMaps(); i++) { OpacityMap *omap = GetOpacityMap(i); // if (omap->IsEnabled() && omap->inDataBounds(value)) { if (omap->IsEnabled()) { // Bounds handling was buggy and bounded opacity maps are no longer used if (getOpacityComposition() == ADDITION) { opacity += omap->opacityData(value); } else // _compType == MULTIPLICATION { opacity *= omap->opacityData(value); } count++; if (opacity * opacScale > 1.0) { return 1.0; } } } if (count) return opacity * opacScale; return 0.0; } //---------------------------------------------------------------------------- // Calculate the color given the data value //---------------------------------------------------------------------------- void MapperFunction::hsvValue(float value, float *h, float *s, float *v) const { ColorMap *cmap = GetColorMap(); if (cmap) { ColorMap::Color color = cmap->color(value); *h = color.hue(); *s = color.sat(); *v = color.val(); } } //---------------------------------------------------------------------------- // Populate at a RGBA lookup table //---------------------------------------------------------------------------- void MapperFunction::makeLut(float *clut) const { float step = (getMaxMapValue() - getMinMapValue()) / float(_numEntries - 1); for (int i = 0; i < _numEntries; i++) { float v = getMinMapValue() + i * step; m_colorMap->color(v).toRGB(&clut[4 * i]); clut[4 * i + 3] = getOpacityValueData(v); } } //---------------------------------------------------------------------------- // Populate at a RGBA lookup table with std::vector input //---------------------------------------------------------------------------- void MapperFunction::makeLut(std::vector &clut) const { float *cluta = new float[4 * _numEntries]; makeLut(cluta); clut.assign(cluta, cluta + 4 * _numEntries); delete[] cluta; } std::vector MapperFunction::makeLut() const { vector v; makeLut(v); return v; } //! Set both minimum and maximum mapping (histo) values //! \param[in] val1 minimum value //! \param[in] val2 maximum value void MapperFunction::setMinMaxMapValue(float val1, float val2) { if (val1 > val2) val2 = val1; vector bnds; bnds.push_back(val1); bnds.push_back(val2); SetValueDoubleVec(_dataBoundsTag, "Set min max map value", bnds); // Need to set the bounds of color and opacity maps // ColorMap *cmap = GetColorMap(); if (cmap) cmap->SetDataBounds(bnds); for (int i = 0; i < getNumOpacityMaps(); i++) { GetOpacityMap(i)->SetDataBounds(bnds); } } vector MapperFunction::getMinMaxMapValue() const { vector defaultv(2, 0.0); vector bounds = GetValueDoubleVec(_dataBoundsTag, defaultv); if (bounds.size() != 2) bounds = defaultv; return (bounds); } vector MapperFunction::GetCustomMappingSliderRange() const { vector defaultv(2, 0); return GetValueDoubleVec(CustomMappingSliderRangeTag, defaultv); } bool MapperFunction::IsUsingCustomMappingSliderRange() const { return GetValueLong(IsUsingCustomMappingSliderRangeTag, false); } void MapperFunction::SetCustomMappingSliderRange(const vector &range) { return SetValueDoubleVec(CustomMappingSliderRangeTag, CustomMappingSliderRangeTag, range); } void MapperFunction::SetUsingCustomMappingSliderRange(bool b) { SetValueLong(IsUsingCustomMappingSliderRangeTag, IsUsingCustomMappingSliderRangeTag, b); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- OpacityMap *MapperFunction::createOpacityMap(OpacityMap::Type type) { int index = m_opacityMaps->Size(); OpacityMap opacityMap(_ssave); opacityMap.SetType(type); m_opacityMaps->Insert(&opacityMap, _make_omap_name(index)); return ((OpacityMap *)m_opacityMaps->GetParams(_make_omap_name(index))); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- void MapperFunction::DeleteOpacityMap(const OpacityMap *omap) { m_opacityMaps->Remove(omap); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- OpacityMap *MapperFunction::GetOpacityMap(int index) const { if (index >= m_opacityMaps->Size()) return (NULL); return ((OpacityMap *)m_opacityMaps->GetParams(_make_omap_name(index))); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // Reset to starting values //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // Static utility function to map and quantize a float //---------------------------------------------------------------------------- int MapperFunction::mapPosition(float x, float minValue, float maxValue, int hSize) { double psn = (0.5 + ((((double)x - (double)minValue) * hSize) / ((double)maxValue - (double)minValue))); // constrain to integer size limit if (psn < -1000000000.f) psn = -1000000000.f; if (psn > 1000000000.f) psn = 1000000000.f; return (int)psn; } //---------------------------------------------------------------------------- // hsv-rgb Conversion function. inputs and outputs between 0 and 1 // copied (with corrections) from Hearn/Baker //---------------------------------------------------------------------------- void MapperFunction::hsvToRgb(float *hsv, float *rgb) { if (hsv[1] == 0.f) { // grey rgb[0] = rgb[1] = rgb[2] = hsv[2]; return; } int sector = (int)(hsv[0] * 6.f); float sectCrd = hsv[0] * 6.f - (float)sector; if (sector == 6) sector = 0; float a = hsv[2] * (1.f - hsv[1]); float b = hsv[2] * (1.f - sectCrd * hsv[1]); float c = hsv[2] * (1.f - (hsv[1] * (1.f - sectCrd))); switch (sector) { case (0): // red to green, r>g rgb[0] = hsv[2]; rgb[1] = c; rgb[2] = a; break; case (1): // red to green, g>r rgb[1] = hsv[2]; rgb[2] = a; rgb[0] = b; break; case (2): // green to blue, gr>bl rgb[0] = a; rgb[1] = hsv[2]; rgb[2] = c; break; case (3): // green to blue, grred rgb[1] = a; rgb[2] = hsv[2]; rgb[0] = c; break; case (5): // blue to red, bl MapperFunction::rgbToHsv(vector rgb) { assert(rgb.size() == 3); vector hsv; rgb.resize(3, 0); hsv.resize(3, 0); rgbToHsv(rgb.data(), hsv.data()); return hsv; } //---------------------------------------------------------------------------- // Set the opacity function to 1. //---------------------------------------------------------------------------- void MapperFunction::setOpaque() { for (int i = 0; i < getNumOpacityMaps(); i++) { GetOpacityMap(i)->setOpaque(); } } bool MapperFunction::isOpaque() const { for (int i = 0; i < getNumOpacityMaps(); i++) { if (GetOpacityMap(i)->isOpaque()) return false; } return true; } string MapperFunction::_make_omap_name(int index) const { stringstream ss; ss << MapperFunction::_opacityMapTag; ss << "_"; ss << index; return (ss.str()); } ================================================ FILE: lib/params/ModelParams.cpp ================================================ #include #include #include using namespace Wasp; using namespace VAPoR; const std::string ModelParams::FileTag = "FileTag"; // // Register class with object factory!!! // static RenParamsRegistrar registrar(ModelParams::GetClassType()); ModelParams::ModelParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, ModelParams::GetClassType(), 3) { SetDiagMsg("ModelParams::ModelParams() this=%p", this); _init(); } ModelParams::ModelParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, std::string classType) : RenderParams(dataMgr, ssave, classType, 3) { SetDiagMsg("ModelParams::ModelParams() this=%p", this); _init(); } ModelParams::ModelParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node, 3) {} ModelParams::~ModelParams() { SetDiagMsg("ModelParams::~ModelParams() this=%p", this); } // Set everything to default values void ModelParams::_init() { SetDiagMsg("ModelParams::_init()"); } ================================================ FILE: lib/params/MouseModeParams.cpp ================================================ //************************************************************************ // * // Copyright (C) 2014 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: MouseModeParams.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: April 2014 // // Description: Implements the MouseModeParams class. // This class supports parameters associted with the // mouse mode // #ifdef WIN32 // Annoying unreferenced formal parameter warning #pragma warning(disable : 4100) #endif #include #include #include "../../apps/vaporgui/images/wheel.xpm" #include "../../apps/vaporgui/images/cube.xpm" #include const std::string MouseModeParams::_currentMouseModeTag = "CurrentMouseModeTag"; using namespace VAPoR; MouseModeParams::MouseModeParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, MouseModeParams::GetClassType()) { _setUpDefault(); _init(); } MouseModeParams::MouseModeParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) { _setUpDefault(); // If node isn't tagged correctly we correct the tag and reinitialize // from scratch; // if (node->GetTag() != MouseModeParams::GetClassType()) { node->SetTag(MouseModeParams::GetClassType()); _init(); } } MouseModeParams::~MouseModeParams() {} // Reset region settings to initial state void MouseModeParams::_init() { // Set to navigation mode SetCurrentMouseMode(GetNavigateModeName()); } //! Static method called at startup to register all the built-in mouse modes void MouseModeParams::_setUpDefault() { _modes.push_back({GetNavigateModeName(), wheel}); _modes.push_back({GetRegionModeName(), cube}); // RegisterMouseMode("Barb rake", 1, arrowrake ); // RegisterMouseMode("Contours", 3, isoline); // RegisterMouseMode(Params::GetClassType(),1, "Flow rake",rake ); // RegisterMouseMode(Params::GetClassType(),3,"Probe", probe); // RegisterMouseMode("2D Data", 2, twoDData); // RegisterMouseMode("Image", 2, twoDImage); } void MouseModeParams::SetCurrentMouseMode(string t) { // Make sure mode is registered. If not, use default // auto itr = _modes.cbegin(); for (; itr != _modes.cend(); ++itr) if (itr->name == t) break; if (itr == _modes.cend()) t = GetNavigateModeName(); SetValueString(_currentMouseModeTag, "Set mouse mode", t); } ================================================ FILE: lib/params/OpacityMap.cpp ================================================ //--OpacityMap.cpp ------------------------------------------------------- // // Copyright (C) 2006 Kenny Gruchalla. All rights reserved. // // Various types of mappings from opacity to data value. // //---------------------------------------------------------------------------- #include #include #include #include #include #include #ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif #ifndef M_PI #define M_PI 3.1415926535897932384626433832795 #endif #ifndef M_E #define M_E 2.71828182845904523536 #endif using namespace std; using namespace VAPoR; using namespace Wasp; //---------------------------------------------------------------------------- // Static member initalization //---------------------------------------------------------------------------- const string OpacityMap::_relMinTag = "RelMinValue"; const string OpacityMap::_relMaxTag = "RelMaxValue"; const string OpacityMap::_enabledTag = "Enabled"; const string OpacityMap::_meanTag = "Mean"; const string OpacityMap::_ssqTag = "SSq"; const string OpacityMap::_freqTag = "Freq"; const string OpacityMap::_phaseTag = "Phase"; const string OpacityMap::_typeTag = "Type"; const string OpacityMap::_controlPointsTag = "OpacityMapControlPoints"; const string OpacityMap::_interpTypeTag = "OpacityInterpolation"; const string OpacityMap::_opacityMapIndexTag = "OpacityMapIndex"; const string OpacityMap::_dataBoundsTag = "DataBounds"; // // Register class with object factory!!! // static ParamsRegistrar registrar(OpacityMap::GetClassType()); //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- OpacityMap::OpacityMap(ParamsBase::StateSave *ssave) : ParamsBase(ssave, OpacityMap::GetClassType()), _minSSq(0.0001), _maxSSq(1.0), _minFreq(1.0), _maxFreq(30.0), _minPhase(0.0), _maxPhase(2 * M_PI) { SetInterpType(TFInterpolator::linear); SetType(CONTROL_POINT); SetEnabled(true); SetMean(0.5); SetSSQ(0.1); SetFreq(5.0); SetPhase(2. * M_PI); vector bounds(2, 0.0); SetDataBounds(bounds); setMinValue(bounds[0]); setMaxValue(bounds[1]); vector cps; for (int i = 0; i < 4; i++) { cps.push_back(1.f); cps.push_back((double)i / 3.); // cps.push_back((double)i/3.); // cps.push_back((double)i/3.); } SetControlPoints(cps); } OpacityMap::OpacityMap(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node), _minSSq(0.0001), _maxSSq(1.0), _minFreq(1.0), _maxFreq(30.0), _minPhase(0.0), _maxPhase(2 * M_PI) {} //---------------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------------- OpacityMap::~OpacityMap() {} //---------------------------------------------------------------------------- // Clear the control points //---------------------------------------------------------------------------- void OpacityMap::clear() { vector cps; SetControlPoints(cps); } //---------------------------------------------------------------------------- // Add a new control point to the opacity map. //---------------------------------------------------------------------------- void OpacityMap::addNormControlPoint(float normVal, float opacity) { vector cps = GetControlPoints(); // cps.insert position is before where new element goes, so must add 2 int index = leftControlIndex(normVal) * 2 + 2; cps.insert(cps.begin() + index++, opacity); cps.insert(cps.begin() + index, normVal); SetControlPoints(cps); } //---------------------------------------------------------------------------- // Add a new control point to the opacity map. //---------------------------------------------------------------------------- void OpacityMap::addControlPoint(float value, float opacity) { float normVal = (value - minValue()) / (maxValue() - minValue()); addNormControlPoint(normVal, opacity); } //---------------------------------------------------------------------------- // Delete the control point. //---------------------------------------------------------------------------- void OpacityMap::deleteControlPoint(int index) { vector cps = GetControlPoints(); if (index >= 0 && index < cps.size() / 2 - 1 && cps.size() > 2) { cps.erase(cps.begin() + 2 * index, cps.begin() + 2 * index + 2); SetControlPoints(cps); } } //---------------------------------------------------------------------------- // Move the control point. //---------------------------------------------------------------------------- void OpacityMap::moveControlPoint(int index, float dx, float dy) { vector cps = GetControlPoints(); if (index >= 0 && index <= cps.size() / 2 - 1) { float minVal = 0.0; float maxVal = 1.0; float ndx = dx / (maxValue() - minValue()); if (index != 0) { minVal = cps[2 * index - 1]; } if (index < cps.size() / 2 - 1) { maxVal = cps[2 * index + 3]; } float value = cps[2 * index + 1] + ndx; if (value < minVal) { value = minVal; } else if (value > maxVal) { value = maxVal; } cps[2 * index + 1] = value; float opacity = cps[2 * index] + dy; if (opacity < 0.0) { opacity = 0.0; } else if (opacity > 1.0) { opacity = 1.0; } cps[2 * index] = opacity; } SetControlPoints(cps); } //---------------------------------------------------------------------------- // Return the control point's opacity. //---------------------------------------------------------------------------- float OpacityMap::controlPointOpacity(int index) const { if (index < 0) { return 0.0; } vector cps = GetControlPoints(); if (index > cps.size() / 2 - 1) { return 1.0; } return cps[2 * index]; } //---------------------------------------------------------------------------- // Set the control point's opacity. //---------------------------------------------------------------------------- void OpacityMap::controlPointOpacity(int index, float opacity) { vector cps = GetControlPoints(); if (index < 0 || 2 * index >= cps.size()) return; if (opacity < 0.0) opacity = 0.; else if (opacity > 1.0) opacity = 1.; cps[index * 2] = opacity; SetControlPoints(cps); } float OpacityMap::controlPointValue(int index) const { return (controlPointValueNormalized(index) * (maxValue() - minValue()) + minValue()); } //---------------------------------------------------------------------------- // Return the control point's value (in data coordinates). //---------------------------------------------------------------------------- float OpacityMap::controlPointValueNormalized(int index) const { if (index < 0) { return minValue(); } vector cps = GetControlPoints(); if (2 * index + 1 >= cps.size()) { return maxValue(); } float norm = cps[2 * index + 1]; return norm; } void OpacityMap::controlPointValue(int index, float value) { float nv = (value - minValue()) / (maxValue() - minValue()); controlPointValueNormalized(index, nv); } //---------------------------------------------------------------------------- // Set the control point's value (in data coordinates). //---------------------------------------------------------------------------- void OpacityMap::controlPointValueNormalized(int index, float nv) { vector cps = GetControlPoints(); if (index < 0 || index * 2 >= cps.size()) { return; } float minVal = 0.0; float maxVal = 1.0; if (index > 0) { minVal = cps[2 * index - 1]; } if (index * 2 + 3 < cps.size()) { maxVal = cps[2 * index + 3]; } if (nv < minVal) { nv = minVal; } else if (nv > maxVal) { nv = maxVal; } cps[2 * index + 1] = nv; } //---------------------------------------------------------------------------- // Set the mean value (normalized coordinates) for the gaussian function //---------------------------------------------------------------------------- void OpacityMap::SetMean(double mean) { SetValueDouble(_meanTag, "Set opacity mean", mean); } //---------------------------------------------------------------------------- // Set the sigma squared value (normalized coordinates) for the gaussian // function //---------------------------------------------------------------------------- void OpacityMap::SetSSQ(double ssq) { SetValueDouble(_ssqTag, "Set Opac SSQ", ssq); } //---------------------------------------------------------------------------- // Set the frequency (normalized coordinates) of the sine function //---------------------------------------------------------------------------- void OpacityMap::SetFreq(double freq) { SetValueDouble(_freqTag, "Set Opac Freq", freq); } //---------------------------------------------------------------------------- // Set the phase (normalized coordinates) of the sine function //---------------------------------------------------------------------------- void OpacityMap::SetPhase(double p) { SetValueDouble(_phaseTag, "Set Opac Phase", denormSinePhase(p)); } float OpacityMap::opacityData(float value) const { float nv = (value - minValue()) / (maxValue() - minValue()); return opacityDataAtNorm(nv); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- float OpacityMap::opacityDataAtNorm(float nv) const { vector cps = GetControlPoints(); if (nv < 0.0) { nv = 0; } if (nv > 1.0) { nv = 1.0; } OpacityMap::Type _type = GetType(); switch (_type) { case CONTROL_POINT: { // // Find the bounding control points // int index = leftControlIndex(nv); if (numControlPoints() == 1) return controlPointOpacity(index); double val0 = cps[2 * index + 1]; double val1 = cps[2 * index + 3]; float ratio = (nv - val0) / (val1 - val0); if (ratio > 0. && ratio < 1.) { float o = TFInterpolator::interpolate(GetInterpType(), cps[2 * index], cps[2 * index + 2], ratio); return o; } if (ratio >= 1.0) { return cps[2 * index + 2]; } return cps[2 * index]; } case GAUSSIAN: { return pow(M_E, -((nv - GetMean()) * (nv - GetMean())) / (2.0 * GetSSQ())); } case INVERTED_GAUSSIAN: { return 1.0 - pow(M_E, -((nv - GetMean()) * (nv - GetMean())) / (2.0 * GetSSQ())); } case SINE: { return (0.5 + sin(GetFreq() * M_PI * nv + GetPhase()) / 2); } } return 0.0; } //---------------------------------------------------------------------------- // Determine if the opacity map bounds the value. //---------------------------------------------------------------------------- bool OpacityMap::inDataBounds(float value) const { return (value >= minValue() && value <= maxValue()); } void OpacityMap::SetDataBounds(const vector &bounds) { VAssert(bounds.size() == 2); SetValueDoubleVec(_dataBoundsTag, "Set min max map value", bounds); } vector OpacityMap::GetDataBounds() const { vector defaultv(2, 0.0); vector bounds = GetValueDoubleVec(_dataBoundsTag, defaultv); if (bounds.size() != 2) bounds = defaultv; return (bounds); } //---------------------------------------------------------------------------- // binary search , find the index of the largest control point <= val // Requires that control points are increasing. // // Developed by Alan Norton. //---------------------------------------------------------------------------- int OpacityMap::leftControlIndex(float normval) const { vector cps = GetControlPoints(); int left = 0; int right = cps.size() / 2 - 1; // // Iterate, keeping left to the left of ctrl point // while (right - left > 1) { int mid = left + (right - left) / 2; if (cps[mid * 2 + 1] > normval) { right = mid; } else { left = mid; } } return left; } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- double OpacityMap::normSSq(double ssq) { return (ssq - _minSSq) / (_maxSSq - _minSSq); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- double OpacityMap::denormSSq(double ssq) { return _minSSq + (ssq * (_maxSSq - _minSSq)); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- double OpacityMap::normSineFreq(double freq) { return (freq - _minFreq) / (_maxFreq - _minFreq); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- double OpacityMap::denormSineFreq(double freq) { return _minFreq + (freq * (_maxFreq - _minFreq)); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- double OpacityMap::normSinePhase(double phase) { return (phase - _minPhase) / (_maxPhase - _minPhase); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- double OpacityMap::denormSinePhase(double phase) { return _minPhase + (phase * (_maxPhase - _minPhase)); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- void OpacityMap::setOpaque() { vector cps = GetControlPoints(); for (int i = 0; i < cps.size() / 2; i++) { cps[2 * i] = 1.; } SetControlPoints(cps); } bool OpacityMap::isOpaque() const { vector cps = GetControlPoints(); for (int i = 0; i < cps.size(); i += 2) { if (cps[i] < 1.0) return false; } return true; } void OpacityMap::SetEnabled(bool val) { SetValueLong(_enabledTag, "Change opacity map enabled", (long)val); } vector OpacityMap::GetControlPoints() const { vector cps = GetValueDoubleVec(_controlPointsTag); while (cps.size() % 2) cps.push_back(0.0); return (cps); } void OpacityMap::SetControlPoints(const vector &controlPoints) { vector mycp = controlPoints; while (mycp.size() % 2) mycp.push_back(0.0); SetValueDoubleVec(_controlPointsTag, "Set opacity control points", mycp); } void OpacityMap::SetInterpType(TFInterpolator::type t) { SetValueLong(_interpTypeTag, "Set Opacity Interpolation", (long)t); } void OpacityMap::SetType(OpacityMap::Type t) { SetValueLong(_typeTag, "Set Opacity Map Type", (long)t); } //---------------------------------------------------------------------------- // Set the minimum value of the opacity map (in data coordinates). // // The minimum value is stored as normalized coordinates in the parameter // space. Therefore, the opacity map will change relative to any changes in // the parameter space. //---------------------------------------------------------------------------- void OpacityMap::setMinValue(double val) { vector minmaxmap = GetDataBounds(); if (val > minmaxmap[1]) val = minmaxmap[1]; if (val < minmaxmap[0]) val = minmaxmap[0]; // change to relative max if (minmaxmap[1] > minmaxmap[0]) val = (val - minmaxmap[0]) / (minmaxmap[1] - minmaxmap[0]); else val = 0.; SetValueDouble(_relMinTag, "Set Opacity min", val); } //---------------------------------------------------------------------------- // Set the minimum value of the opacity map (in data coordinates). // // The minimum value is stored as normalized coordinates in the parameter // space. Therefore, the opacity map will change relative to any changes in // the parameter space. //---------------------------------------------------------------------------- void OpacityMap::setMaxValue(double val) { vector minmaxmap = GetDataBounds(); if (val < minmaxmap[0]) val = minmaxmap[0]; if (val > minmaxmap[1]) val = minmaxmap[1]; // change to relative max if (minmaxmap[1] > minmaxmap[0]) val = (val - minmaxmap[0]) / (minmaxmap[1] - minmaxmap[0]); else val = 1.; SetValueDouble(_relMaxTag, "Set Opacity max", val); } double OpacityMap::minValue() const { vector minmaxmap = GetDataBounds(); double relmin = GetValueDouble(_relMinTag, 0.0); return (minmaxmap[0] + relmin * (minmaxmap[1] - minmaxmap[0])); } double OpacityMap::maxValue() const { vector minmaxmap = GetDataBounds(); double relmax = GetValueDouble(_relMaxTag, 1.0); return (minmaxmap[0] + relmax * (minmaxmap[1] - minmaxmap[0])); } ================================================ FILE: lib/params/ParamsBase.cpp ================================================ //************************************************************************ // * // Copyright (C) 2008 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: ParamsBase.cpp // // Author: John Clyne with modifications by Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: March 2008 // // Description: Implements the ParamsBase class // This is abstract class for classes that use a ParamNode // to support get/set functionality, and to support dirty bits // It is a base class for Params, MapperFunction and other classes // that retain their state in xml nodes // #include #include "vapor/VAssert.h" #include #include #include #include using namespace VAPoR; namespace { void string_replace(vector &v, string olds, string news) { for (int i = 0; i < v.size(); i++) { if (v[i] == olds) { v[i] = news; } } } }; // namespace ParamsBase::ParamsBase(StateSave *ssave, const string &classname) { VAssert(ssave != NULL); _ssave = ssave; _node = NULL; map attrs; _node = new XmlNode(classname, attrs); } ParamsBase::ParamsBase(StateSave *ssave, XmlNode *node) { VAssert(ssave != NULL); VAssert(node != NULL); _ssave = ssave; _node = node; } ParamsBase::ParamsBase(const ParamsBase &rhs) { _ssave = rhs._ssave; _node = NULL; _node = new XmlNode(*(rhs._node)); } ParamsBase::ParamsBase(StateSave *ssave) { VAssert(ssave != NULL); _ssave = ssave; _node = NULL; } ParamsBase &ParamsBase::operator=(const ParamsBase &rhs) { MyBase::operator=(rhs); if (_node) { _node->SetParent(NULL); delete _node; } _ssave = rhs._ssave; _node = NULL; _node = new XmlNode(*(rhs._node)); return (*this); } ParamsBase::~ParamsBase() { // Only delete the Xml tree if this is the root node // if (_node && _node->IsRoot()) { delete _node; } _node = NULL; _ssave = NULL; } void ParamsBase::SetParent(ParamsBase *parent) { GetNode()->SetParent(parent ? parent->GetNode() : NULL); _ssave->Save(GetNode(), "Set parent node"); } vector ParamsBase::GetValueLongVec(const string tag) const { vector empty; if (!_node->HasElementLong(tag)) return (empty); return (_node->GetElementLong(tag)); } vector ParamsBase::GetValueLongVec(const string tag, const vector &defaultVal) const { if (!_node->HasElementLong(tag)) return (defaultVal); vector v = _node->GetElementLong(tag); if (v.size() < defaultVal.size()) { for (int i = v.size(); i < defaultVal.size(); i++) { v.push_back(defaultVal[i]); } } else if (v.size() > defaultVal.size()) { while (v.size() > defaultVal.size()) { v.pop_back(); } } return (v); } long ParamsBase::GetValueLong(const string tag, long defaultVal) const { vector defaultValVec(1, defaultVal); vector v = ParamsBase::GetValueLongVec(tag, defaultValVec); if (!v.size()) return (defaultVal); return (v[0]); } vector ParamsBase::GetValueDoubleVec(const string tag) const { vector empty; VAssert(_node); bool test = _node->HasElementDouble(tag); if (!test) return (empty); // if (! _node->HasElementDouble(tag)) return(empty); return (_node->GetElementDouble(tag)); } vector ParamsBase::GetValueDoubleVec(const string tag, const vector &defaultVal) const { if (!_node->HasElementDouble(tag)) return (defaultVal); vector v = _node->GetElementDouble(tag); if (v.size() < defaultVal.size()) { for (int i = v.size(); i < defaultVal.size(); i++) { v.push_back(defaultVal[i]); } } else if (v.size() > defaultVal.size()) { while (v.size() > defaultVal.size()) { v.pop_back(); } } return (v); } double ParamsBase::GetValueDouble(const string tag, double defaultVal) const { vector defaultValVec(1, defaultVal); vector v = ParamsBase::GetValueDoubleVec(tag, defaultValVec); if (!v.size()) return (defaultVal); return (v[0]); } vector ParamsBase::GetValueStringVec(const string tag) const { vector empty; if (!_node->HasElementString(tag)) return (empty); vector v; _node->GetElementStringVec(tag, v); string_replace(v, "NULL", ""); return (v); } vector ParamsBase::GetValueStringVec(const string tag, const vector &defaultVal) const { if (!_node->HasElementString(tag)) return (defaultVal); vector v; _node->GetElementStringVec(tag, v); string_replace(v, "NULL", ""); if (v.size() < defaultVal.size()) { for (int i = v.size(); i < defaultVal.size(); i++) { v.push_back(defaultVal[i]); } } else if (v.size() > defaultVal.size()) { while (v.size() > defaultVal.size()) { v.pop_back(); } } return (v); } string ParamsBase::GetValueString(const string tag, string defaultVal) const { if (!_node->HasElementString(tag)) return (defaultVal); string v = _node->GetElementString(tag); v = STLUtils::ReplaceAll(v, "\\ ", " "); if (v == "NULL") { v = ""; } return (v); } void ParamsBase::SetValueLong(const string &tag, string description, long value) { vector values(1, value); ParamsBase::SetValueLongVec(tag, description, values); } void ParamsBase::SetValueLongVec(const string &tag, string description, const vector &values) { vector current = GetValueLongVec(tag); if (current == values) return; _node->SetElementLong(tag, values); _ssave->Save(_node, description); } void ParamsBase::SetValueDouble(const string &tag, string description, double value) { vector values(1, value); ParamsBase::SetValueDoubleVec(tag, description, values); } void ParamsBase::SetValueDoubleVec(const string &tag, string description, const vector &values) { vector current = GetValueDoubleVec(tag); if (current == values) return; _node->SetElementDouble(tag, values); _ssave->Save(_node, description); } void ParamsBase::SetValueString(const string &tag, string description, const string &value) { vector values(1, value); ParamsBase::SetValueStringVec(tag, description, values); } void ParamsBase::SetValueStringVec(const string &tag, string description, const vector &values) { vector current = GetValueStringVec(tag); if (current == values) return; // Replace empty strings with a token // vector my_values = values; string_replace(my_values, "", "NULL"); _node->SetElementStringVec(tag, my_values); _ssave->Save(_node, description); } ////////////////////////////////////////////////////////////////////////// // // ParamsSeparator Class // ///////////////////////////////////////////////////////////////////////// ParamsSeparator::ParamsSeparator(StateSave *ssave, const string &name) : ParamsBase(ssave, name) {} ParamsSeparator::ParamsSeparator(StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {} ParamsSeparator::ParamsSeparator(ParamsSeparator *parent, const string &name) : ParamsBase(parent->_ssave) { if (parent->GetNode()->HasChild(name)) { _node = parent->GetNode()->GetChild(name); VAssert(_node); } else { _node = parent->GetNode()->NewChild(name); parent->_ssave->Save(parent->GetNode(), "New params"); } } ////////////////////////////////////////////////////////////////////////// // // ParamsFactory Class // ///////////////////////////////////////////////////////////////////////// ParamsBase *ParamsFactory::CreateInstance(string className, ParamsBase::StateSave *ssave, XmlNode *node) { ParamsBase *instance = NULL; // find className in the registry and call factory method. // auto it = m_factoryFunctionRegistry.find(className); if (it != m_factoryFunctionRegistry.end()) instance = it->second(ssave, node); if (instance != NULL) return instance; else return NULL; } vector ParamsFactory::GetFactoryNames() const { vector names; map>::const_iterator itr; for (itr = m_factoryFunctionRegistry.begin(); itr != m_factoryFunctionRegistry.end(); ++itr) { names.push_back(itr->first); } return (names); } ////////////////////////////////////////////////////////////////////////// // // ParamsContainer Class // ///////////////////////////////////////////////////////////////////////// ParamsContainer::ParamsContainer(ParamsBase::StateSave *ssave, const string &name) { VAssert(ssave != NULL); _ssave = ssave; _separator = NULL; _elements.clear(); _separator = new ParamsSeparator(ssave, name); } ParamsContainer::ParamsContainer(ParamsBase::StateSave *ssave, XmlNode *node) { VAssert(ssave != NULL); VAssert(node != NULL); _ssave = ssave; _separator = new ParamsSeparator(ssave, node); _elements.clear(); for (int i = 0; i < node->GetNumChildren(); i++) { XmlNode *eleNameNode = node->GetChild(i); if (!eleNameNode->HasChild(0)) continue; // bad node XmlNode *eleNode = eleNameNode->GetChild(0); string eleName = eleNameNode->GetTag(); string classname = eleNode->GetTag(); ParamsBase *pB = ParamsFactory::Instance()->CreateInstance(classname, ssave, eleNode); if (pB == NULL) { SetDiagMsg("ParamsContainer::ParamsContainer() unrecognized class: %s", classname.c_str()); continue; } _elements[eleName] = pB; } } ParamsContainer::ParamsContainer(const ParamsContainer &rhs) { _ssave = rhs._ssave; _separator = NULL; _elements.clear(); _ssave->BeginGroup("Params container"); _separator = new ParamsSeparator(*(rhs._separator)); _separator->SetParent(NULL); vector names = rhs.GetNames(); for (int i = 0; i < names.size(); i++) { // Make copy of ParamsBase // ParamsBase *rhspb = rhs.GetParams(names[i]); XmlNode * node = new XmlNode(*(rhspb->GetNode())); string classname = rhspb->GetName(); ParamsBase *mypb = ParamsFactory::Instance()->CreateInstance(classname, _ssave, node); mypb->SetParent(_separator); _elements[names[i]] = mypb; } _ssave->EndGroup(); } ParamsContainer &ParamsContainer::operator=(const ParamsContainer &rhs) { VAssert(_separator); vector mynames = GetNames(); for (int i = 0; i < mynames.size(); i++) { Remove(mynames[i]); } _elements.clear(); _ssave->BeginGroup("Params container"); _separator = rhs._separator; _ssave = rhs._ssave; vector names = rhs.GetNames(); for (int i = 0; i < names.size(); i++) { XmlNode *eleNameNode = _separator->GetNode()->GetChild(names[i]); VAssert(eleNameNode); ParamsSeparator mySep(_ssave, eleNameNode); XmlNode *eleNode = eleNameNode->GetChild(0); string eleName = eleNameNode->GetTag(); string classname = eleNode->GetTag(); ParamsBase *mypb = ParamsFactory::Instance()->CreateInstance(classname, _ssave, eleNode); mypb->SetParent(&mySep); _elements[names[i]] = mypb; } _ssave->EndGroup(); return (*this); } ParamsContainer::~ParamsContainer() { map::iterator itr; for (itr = _elements.begin(); itr != _elements.end(); ++itr) { if (itr->second) delete itr->second; } if (_separator) delete _separator; } ParamsBase *ParamsContainer::Insert(ParamsBase *pb, string name) { VAssert(pb != NULL); if (name.empty()) { name = "NULL"; } map::iterator itr = _elements.find(name); if (itr != _elements.end()) { delete itr->second; } _ssave->BeginGroup("Params container"); // Create a separator node // ParamsSeparator mySep(_ssave, name); mySep.SetParent(_separator); // Create element name node // string classname = pb->GetName(); XmlNode * node = new XmlNode(*(pb->GetNode())); ParamsBase *mypb = ParamsFactory::Instance()->CreateInstance(classname, _ssave, node); VAssert(mypb != NULL); mypb->SetParent(&mySep); _elements[name] = mypb; _ssave->EndGroup(); return (mypb); } ParamsBase *ParamsContainer::Create(string className, string name) { VAssert(!className.empty()); VAssert(!name.empty()); map::iterator itr = _elements.find(name); if (itr != _elements.end()) { delete itr->second; } _ssave->BeginGroup("Params container"); // Create a separator node // ParamsSeparator mySep(_ssave, name); mySep.SetParent(_separator); // Create the desired class // ParamsBase *mypb = ParamsFactory::Instance()->CreateInstance(className, _ssave, NULL); VAssert(mypb != NULL); mypb->SetParent(&mySep); _elements[name] = mypb; _ssave->EndGroup(); return (mypb); } void ParamsContainer::Remove(string name) { map::iterator itr = _elements.find(name); if (itr == _elements.end()) return; ParamsBase *mypb = itr->second; // Set parent to root so Xml representation will be deleted // mypb->SetParent(NULL); delete mypb; _elements.erase(itr); _ssave->Save(_separator->GetNode(), "Delete params"); } ParamsBase *ParamsContainer::GetParams(string name) const { if (name.empty()) { name = "NULL"; } map::const_iterator itr = _elements.find(name); if (itr != _elements.end()) return (itr->second); return (NULL); } string ParamsContainer::GetParamsName(const ParamsBase *pb) const { map::const_iterator itr; for (itr = _elements.begin(); itr != _elements.end(); ++itr) { if (itr->second == pb) return (itr->first); } return (""); } vector ParamsContainer::GetNames() const { map::const_iterator itr; vector names; for (itr = _elements.begin(); itr != _elements.end(); ++itr) { names.push_back(itr->first); } return (names); } ================================================ FILE: lib/params/ParamsMgr.cpp ================================================ //************************************************************************ // * // Copyright (C) 2016 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: paramsmgr.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: October 2004 // // Description: Implements the ParamsMgr class // This manages the collection of Params classes that are active in VAPOR // #include #include #include #include #include #include #include #include using namespace VAPoR; //---------------------------------------------------------------------------- // Static member initialization. //---------------------------------------------------------------------------- const string ParamsMgr::_rootTag = "VAPOR"; const string ParamsMgr::_globalTag = "Global"; const string ParamsMgr::_windowsTag = "Windows"; const string ParamsMgr::_renderersTag = "Renderers"; const string ParamsMgr::_appRenderersTag = "AppRenderers"; void ParamsMgr::_init(vector appParams, XmlNode *node) { _renderParamsMap.clear(); if (node) { if (node->GetTag() != _rootTag) { node->SetTag(_rootTag); } _rootSeparator = new ParamsSeparator(&_ssave, node); } else { _rootSeparator = new ParamsSeparator(&_ssave, _rootTag); node = _rootSeparator->GetNode(); } // State save class needs root node of state tree // _ssave.Reinit(node); XmlNode *child = node->GetChild(_globalTag); if (child) { _otherParams = new ParamsContainer(&_ssave, child); } else { _otherParams = new ParamsContainer(&_ssave, _globalTag); _otherParams->SetParent(_rootSeparator); } if (!_otherParams->GetParams(RegionParams::GetClassType())) { _otherParams->Create(RegionParams::GetClassType(), RegionParams::GetClassType()); } if (!_otherParams->GetParams(AnnotationParams::GetClassType())) { _otherParams->Create(AnnotationParams::GetClassType(), AnnotationParams::GetClassType()); } if (!_otherParams->GetParams(DatasetsParams::GetClassType())) { _otherParams->Create(DatasetsParams::GetClassType(), DatasetsParams::GetClassType()); } // Deal with any Params registered by the application // for (int i = 0; i < appParams.size(); i++) { if (!_otherParams->GetParams(appParams[i])) { _otherParams->Create(appParams[i], appParams[i]); } } } ParamsMgr::ParamsMgr(std::vector appParamNames, std::vector appRenderParamNames) { _appParamNames = appParamNames; _appRenderParamNames = appRenderParamNames; _dataMgrMap.clear(); _ssave.SetEnabled(false); _init(appParamNames, NULL); _ssave.SetEnabled(true); } void ParamsMgr::_destroy() { // Delete all of the render containers // delete_ren_containers(); // Now delete all of the viewpoint params // map::iterator vpitr; for (vpitr = _viewpointParamsMap.begin(); vpitr != _viewpointParamsMap.end(); ++vpitr) { if (vpitr->second) delete vpitr->second; } _viewpointParamsMap.clear(); if (_otherParams) delete _otherParams; map::iterator itr; for (itr = _otherRenParams.begin(); itr != _otherRenParams.end(); ++itr) { if (itr->second) delete itr->second; } _otherRenParams.clear(); if (_rootSeparator) delete _rootSeparator; } ParamsMgr::~ParamsMgr() { _destroy(); } void ParamsMgr::LoadState() { // Don't know if this is necessary but previous code would always wrap call BeginSaveStateGroup("Load state"); _destroy(); _init(_appParamNames, NULL); // If data loaded set up data dependent parameters from default state. // if (_dataMgrMap.size()) { addDataMgrNew(); } EndSaveStateGroup(); } void ParamsMgr::LoadState(const XmlNode *node) { _destroy(); XmlNode *mynode = new XmlNode(*node); _init(_appParamNames, mynode); ParamsSeparator *windowsSep = new ParamsSeparator(_rootSeparator, _windowsTag); XmlNode *winNode = windowsSep->GetNode(); for (int i = 0; i < winNode->GetNumChildren(); i++) { string winName = winNode->GetChild(i)->GetTag(); (void)make_vp_params(winName); } delete windowsSep; // If data loaded set up data dependent parameters from new state. // vector dataSetNames = GetDataMgrNames(); for (auto dataSetName : dataSetNames) { map::const_iterator itr = _dataMgrMap.find(dataSetName); if (itr != _dataMgrMap.end()) addDataMgrMerge(itr->first); } } int ParamsMgr::LoadState(string stateFile) { BeginSaveStateGroup("Load state"); XmlParser parser; XmlNode node; int rc = parser.LoadFromFile(&node, stateFile); if (rc < 0) { SetErrMsg("Invalid session file : %s", stateFile.c_str()); EndSaveStateGroup(); return (-1); } LoadState(&node); EndSaveStateGroup(); return (0); } void ParamsMgr::addDataMgrNew() { // Delete all of the renderer containers // delete_ren_containers(); } void ParamsMgr::addDataMgrMerge(string dataSetName) { ParamsSeparator *windowsSep = new ParamsSeparator(_rootSeparator, _windowsTag); XmlNode *winSepNode = windowsSep->GetNode(); for (int i = 0; i < winSepNode->GetNumChildren(); i++) { XmlNode *winNode = winSepNode->GetChild(i); string winName = winNode->GetTag(); if (winNode->HasChild(_renderersTag)) { XmlNode *renderersNode = winNode->GetChild(_renderersTag); for (int j = 0; j < renderersNode->GetNumChildren(); j++) { XmlNode *dataSepNode = renderersNode->GetChild(j); string s = dataSepNode->GetTag(); if (s != dataSetName) continue; for (int k = 0; k < dataSepNode->GetNumChildren(); k++) { (void)make_ren_container(winName, dataSetName, dataSepNode->GetChild(k)->GetTag()); } } } } delete windowsSep; _createAppRenParams(dataSetName); } void ParamsMgr::_createAppRenParams(string dataSetName) { // Deal with any application render Params registered by the application // ParamsSeparator *appRenParamsSep = new ParamsSeparator(_rootSeparator, _appRenderersTag); // Delete any existing container for this data set // map::const_iterator itr; itr = _otherRenParams.find(dataSetName); RenParamsContainer *rpc = itr == _otherRenParams.end() ? NULL : itr->second; if (rpc) delete rpc; if (appRenParamsSep->HasChild(dataSetName)) { XmlNode *node = appRenParamsSep->GetNode()->GetChild(dataSetName); VAssert(node); rpc = new RenParamsContainer(_dataMgrMap[dataSetName], &_ssave, node); } else { rpc = new RenParamsContainer(_dataMgrMap[dataSetName], &_ssave, dataSetName); rpc->GetSeparator()->SetParent(appRenParamsSep); } delete appRenParamsSep; // Now add any application render params to the container for this // data set // for (int i = 0; i < _appRenderParamNames.size(); i++) { if (!rpc->GetParams(_appRenderParamNames[i])) { rpc->Create(_appRenderParamNames[i], _appRenderParamNames[i]); } } _otherRenParams[dataSetName] = rpc; } void ParamsMgr::AddDataMgr(string dataSetName, DataMgr *dataMgr) { _dataMgrMap[dataSetName] = dataMgr; // If state already exist use it. Otherwise, create new, default // state // if (_rootSeparator->HasChild(_windowsTag)) { addDataMgrMerge(dataSetName); } else { addDataMgrNew(); } ParamsSeparator windowsSep(_rootSeparator, _windowsTag); XmlNode * winSepNode = windowsSep.GetNode(); for (int i = 0; i < winSepNode->GetNumChildren(); i++) { string winName = winSepNode->GetChild(i)->GetTag(); // Instantiating ParamsSeparator classes will add child nodes to the // XML tree as a side effect // ParamsSeparator windowSep(&windowsSep, winName); ParamsSeparator renderSep(&windowSep, _renderersTag); ParamsSeparator dataSep(&renderSep, dataSetName); } } void ParamsMgr::RemoveVisualizer(string winName) { if (!_rootSeparator->HasChild(_windowsTag)) return; ParamsSeparator windowsSep(_rootSeparator, _windowsTag); if (!windowsSep.HasChild(winName)) return; _ssave.BeginGroup("ParamsMgr::RemoveVisualizer"); delete_ren_containers(winName); RemoveVisualizerParamsInstance(winName); ParamsSeparator windowSep(ParamsSeparator(&windowsSep, winName)); // Set parent to root so Xml representation will be deleted // windowSep.SetParent(NULL); _ssave.EndGroup(); } void ParamsMgr::RemoveDataMgr(string dataSetName) { map::iterator itr; itr = _dataMgrMap.find(dataSetName); if (itr == _dataMgrMap.end()) return; _dataMgrMap.erase(itr); delete_datasets(dataSetName); } vector ParamsMgr::GetDataMgrNames() const { vector dataMgrNames; ParamsSeparator windowsSep(_rootSeparator, _windowsTag); XmlNode *winSepNode = windowsSep.GetNode(); for (int i = 0; i < winSepNode->GetNumChildren(); i++) { XmlNode *winNode = winSepNode->GetChild(i); string winName = winNode->GetTag(); if (winNode->HasChild(_renderersTag)) { XmlNode *renderersNode = winNode->GetChild(_renderersTag); for (int j = 0; j < renderersNode->GetNumChildren(); j++) { XmlNode *dataSepNode = renderersNode->GetChild(j); string s = dataSepNode->GetTag(); dataMgrNames.push_back(s); } } } sort(dataMgrNames.begin(), dataMgrNames.end()); dataMgrNames.erase(unique(dataMgrNames.begin(), dataMgrNames.end()), dataMgrNames.end()); return (dataMgrNames); } // Legacy moved from VizWinMgr static string make_viz_name(vector currentNames) { int index = 0; bool found = false; string name; while (!found) { std::stringstream out; out << index; name = "Visualizer_No._" + out.str(); found = true; for (int i = 0; i < currentNames.size(); i++) { if (currentNames[i] == name) found = false; } index++; } return (name); } string ParamsMgr::CreateVisualizerParamsInstance(string winName) { const auto previousVisualizerNames = GetVisualizerNames(); if (winName == "__AUTO__") winName = make_viz_name(previousVisualizerNames); _ssave.BeginGroup("CreateVisualizerParamsInstance"); ViewpointParams *vpParams = get_vp_params(winName); if (!vpParams) { vpParams = make_vp_params(winName); } VAssert(vpParams != NULL); // TODO initialize viewpoint params // This shouldn't be done here but this was previously accomplished by spaghetti // involving the qt event system and there currently isn't a good place to put it. if (previousVisualizerNames.size() >= 1) { auto pvp = get_vp_params(previousVisualizerNames[0]); vpParams->SetModelViewMatrix(pvp->GetModelViewMatrix()); vpParams->SetRotationCenter(pvp->GetRotationCenter()); for (auto name : pvp->GetTransformNames()) { auto nt = vpParams->GetTransform(name); auto pt = pvp->GetTransform(name); nt->SetTranslations(pt->GetTranslations()); nt->SetScales(pt->GetScales()); nt->SetRotations(pt->GetRotations()); nt->SetOrigin(pt->GetOrigin()); nt->SetOriginInitialized(pt->IsOriginInitialized()); } } _ssave.EndGroup(); return winName; } void ParamsMgr::RemoveVisualizerParamsInstance(string winName) { _ssave.BeginGroup("RemoveVisualizerParamsInstance"); map::const_iterator itr; itr = _viewpointParamsMap.find(winName); if (itr == _viewpointParamsMap.end()) return; ViewpointParams *vParams = itr->second; // Set parent to root so Xml representation will be deleted // vParams->SetParent(NULL); delete vParams; _viewpointParamsMap.erase(itr); _ssave.EndGroup(); } RenParamsContainer *ParamsMgr::createRenderParamsHelper(string winName, string dataSetName, string className, string instName) { map::const_iterator itr; itr = _dataMgrMap.find(dataSetName); if (itr == _dataMgrMap.end()) { SetErrMsg("Invalid state : no data set"); return (NULL); } vector instNames; GetRenderParamNames(instNames); if (find(instNames.begin(), instNames.end(), instName) != instNames.end()) { string myWinName, myDataSetName, myClassName; (void)RenderParamsLookup(instName, myWinName, myDataSetName, myClassName); if (!(myWinName == winName) && (myDataSetName == dataSetName) && (myClassName == className)) { SetErrMsg("Non-unique render instance name : %s", instName.c_str()); return (NULL); } } // Create ViewpointParams if we don't have one // ViewpointParams *vpParams = get_vp_params(winName); if (!vpParams) { CreateVisualizerParamsInstance(winName); vpParams = get_vp_params(winName); } VAssert(vpParams != NULL); RenParamsContainer *container = get_ren_container(winName, dataSetName, className); if (!container) { container = make_ren_container(winName, dataSetName, className); } VAssert(container != NULL); return (container); } RenderParams *ParamsMgr::CreateRenderParamsInstance(string winName, string dataSetName, string className, string instName) { _ssave.BeginGroup("CreateRenderParamsInstance"); RenParamsContainer *container = createRenderParamsHelper(winName, dataSetName, className, instName); if (!container) { _ssave.EndGroup(); return (NULL); } RenderParams *rp = container->GetParams(instName); if (!rp) { rp = container->Create(className, instName); } _ssave.EndGroup(); if (!rp) { SetErrMsg("Invalid derived RenderParams class name %s", className.c_str()); return (NULL); } return (rp); } RenderParams *ParamsMgr::CreateRenderParamsInstance(string winName, string dataSetName, string instName, const RenderParams *rp) { VAssert(rp); _ssave.BeginGroup("CreateRenderParamsInstance"); string className = rp->GetName(); RenParamsContainer *container = createRenderParamsHelper(winName, dataSetName, className, instName); if (!container) { _ssave.EndGroup(); return (NULL); } RenderParams *newRP = container->Insert(rp, instName); _ssave.EndGroup(); if (!newRP) { SetErrMsg("Invalid derived RenderParams class name %s", className.c_str()); return (NULL); } return (newRP); } void ParamsMgr::RemoveRenderParamsInstance(string winName, string dataSetName, string className, string instName) { RenParamsContainer *container = get_ren_container(winName, dataSetName, className); if (!container) return; container->Remove(instName); } RenderParams *ParamsMgr::GetRenderParams(string winName, string dataSetName, string className, string instName) const { RenParamsContainer *container = get_ren_container(winName, dataSetName, className); if (!container) { return (NULL); } return (container->GetParams(instName)); } void ParamsMgr::GetRenderParams(string winName, string dataSetName, vector &rParams) const { rParams.clear(); const map *m1Ptr; m1Ptr = getWinMap3(_renderParamsMap, winName, dataSetName); if (!m1Ptr) return; // m1Ptr[className] // const map & ref = *m1Ptr; map::const_iterator itr; for (itr = ref.begin(); itr != ref.end(); ++itr) { RenParamsContainer *rpc = itr->second; vector names = rpc->GetNames(); for (int i = 0; i < names.size(); i++) { rParams.push_back(rpc->GetParams(names[i])); } } } void ParamsMgr::GetRenderParams(string winName, vector &rParams) const { rParams.clear(); const map> *m2Ptr; m2Ptr = getWinMap3(_renderParamsMap, winName); if (!m2Ptr) return; // m2Ptr[dataSetName][className] // const map> & ref = *m2Ptr; map>::const_iterator itr; for (itr = ref.begin(); itr != ref.end(); ++itr) { vector tmp; GetRenderParams(winName, itr->first, tmp); rParams.insert(rParams.end(), tmp.begin(), tmp.end()); } } void ParamsMgr::GetRenderParams(vector &rParams) const { rParams.clear(); map>>::const_iterator itr; for (itr = _renderParamsMap.begin(); itr != _renderParamsMap.end(); ++itr) { vector tmp; GetRenderParams(itr->first, tmp); rParams.insert(rParams.end(), tmp.begin(), tmp.end()); } } void ParamsMgr::GetRenderParamNames(string winName, string dataSetName, string className, vector &instNames) const { instNames.clear(); RenParamsContainer *container = get_ren_container(winName, dataSetName, className); if (!container) return; instNames = container->GetNames(); // Sanity check. Names should always be unique! // sort(instNames.begin(), instNames.end()); instNames.erase(unique(instNames.begin(), instNames.end()), instNames.end()); } void ParamsMgr::GetRenderParamNames(string winName, string dataSetName, vector &instNames) const { instNames.clear(); const map *m1Ptr; m1Ptr = getWinMap3(_renderParamsMap, winName, dataSetName); if (!m1Ptr) return; // m1Ptr[className] // const map & ref = *m1Ptr; map::const_iterator itr; for (itr = ref.begin(); itr != ref.end(); ++itr) { vector tmp; GetRenderParamNames(winName, dataSetName, itr->first, tmp); instNames.insert(instNames.end(), tmp.begin(), tmp.end()); } sort(instNames.begin(), instNames.end()); instNames.erase(unique(instNames.begin(), instNames.end()), instNames.end()); } void ParamsMgr::GetRenderParamNames(string winName, vector &instNames) const { instNames.clear(); const map> *m2Ptr; m2Ptr = getWinMap3(_renderParamsMap, winName); if (!m2Ptr) return; // m2Ptr[dataSetName][className] // const map> & ref = *m2Ptr; map>::const_iterator itr; for (itr = ref.begin(); itr != ref.end(); ++itr) { vector tmp; GetRenderParamNames(winName, itr->first, tmp); instNames.insert(instNames.end(), tmp.begin(), tmp.end()); } sort(instNames.begin(), instNames.end()); instNames.erase(unique(instNames.begin(), instNames.end()), instNames.end()); } void ParamsMgr::GetRenderParamNames(vector &instNames) const { instNames.clear(); map>>::const_iterator itr; for (itr = _renderParamsMap.begin(); itr != _renderParamsMap.end(); ++itr) { vector tmp; GetRenderParamNames(itr->first, tmp); instNames.insert(instNames.end(), tmp.begin(), tmp.end()); } sort(instNames.begin(), instNames.end()); instNames.erase(unique(instNames.begin(), instNames.end()), instNames.end()); } vector ParamsMgr::GetRenderParamNames() const { vector ret; GetRenderParamNames(ret); return ret; } vector ParamsMgr::GetRenderParamNamesForDataset(string datasetName) const { vector names, t; for (const auto &viz : GetVisualizerNames()) { GetRenderParamNames(viz, datasetName, t); STLUtils::AppendTo(names, t); } return names; } bool ParamsMgr::RenderParamsLookup(string instName, string &winName, string &dataSetName, string &className) const { winName.clear(); dataSetName.clear(); className.clear(); // Exhaustively search through _renderParamsMap looking for an // occurrence of instName // map>>::const_iterator itr1; for (itr1 = _renderParamsMap.begin(); itr1 != _renderParamsMap.end(); ++itr1) { map>::const_iterator itr2; for (itr2 = itr1->second.begin(); itr2 != itr1->second.end(); ++itr2) { map::const_iterator itr3; for (itr3 = itr2->second.begin(); itr3 != itr2->second.end(); ++itr3) { const RenParamsContainer &ref = *(itr3->second); vector instNames = ref.GetNames(); if (find(instNames.begin(), instNames.end(), instName) != instNames.end()) { winName = itr1->first; dataSetName = itr2->first; className = itr3->first; return (true); } } } } return (false); } bool ParamsMgr::RenderParamsLookup(RenderParams *inst, string &instName, string &winName, string &dataSetName, string &className) const { winName.clear(); dataSetName.clear(); className.clear(); map>>::const_iterator itr1; for (itr1 = _renderParamsMap.begin(); itr1 != _renderParamsMap.end(); ++itr1) { map>::const_iterator itr2; for (itr2 = itr1->second.begin(); itr2 != itr1->second.end(); ++itr2) { map::const_iterator itr3; for (itr3 = itr2->second.begin(); itr3 != itr2->second.end(); ++itr3) { const RenParamsContainer &ref = *(itr3->second); vector instNames = ref.GetNames(); for (const auto & name : instNames) { if (ref.GetParams(name) == inst) { instName = name; winName = itr1->first; dataSetName = itr2->first; className = itr3->first; return (true); } } } } } return (false); } vector ParamsMgr::GetVisualizerNames() const { vector vizNames; map::const_iterator itr; for (itr = _viewpointParamsMap.begin(); itr != _viewpointParamsMap.end(); ++itr) { vizNames.push_back(itr->first); } return (vizNames); } // m2[b][c] <- m3[a][b][c] // const map> *ParamsMgr::getWinMap3(const map>> &m3, string key) const { // map[a][b][c] // map>>::const_iterator itr; itr = m3.find(key); if (itr == m3.end()) return (NULL); return (&(itr->second)); } // m1[c] <- m3[a][b][c] // const map *ParamsMgr::getWinMap3(const map>> &m3, string key1, string key2) const { const map> *m2Ptr; m2Ptr = getWinMap3(m3, key1); if (!m2Ptr) return (NULL); const map *m1Ptr; m1Ptr = getWinMap2(*m2Ptr, key2); return (m1Ptr); } // m1[c] <- m2[b][c] // const map *ParamsMgr::getWinMap2(const map> &m2, string key) const { // map[b][c] // map>::const_iterator itr; itr = m2.find(key); if (itr == m2.end()) return (NULL); return (&(itr->second)); } // m2[b][c] <- m3[a][b][c] // map> *ParamsMgr::getWinMap3(map>> &m3, string key) const { // map[a][b][c] // map>>::iterator itr; itr = m3.find(key); if (itr == m3.end()) return (NULL); return (&(itr->second)); } // m1[c] <- m3[a][b][c] // map *ParamsMgr::getWinMap3(map>> &m3, string key1, string key2) const { map> *m2Ptr; m2Ptr = getWinMap3(m3, key1); if (!m2Ptr) return (NULL); map *m1Ptr; m1Ptr = getWinMap2(*m2Ptr, key2); return (m1Ptr); } // m1[c] <- m2[b][c] // map *ParamsMgr::getWinMap2(map> &m2, string key) const { // map[b][c] // map>::iterator itr; itr = m2.find(key); if (itr == m2.end()) return (NULL); return (&(itr->second)); } vector ParamsMgr::GetRenderParamsClassNames(string winName, string dataSetName) const { vector rClassNames; // _renderParamsMap[winName][dataSetName][className] // const map *m1Ptr; m1Ptr = getWinMap3(_renderParamsMap, winName, dataSetName); if (!m1Ptr) return (rClassNames); // m1Ptr[className] // const map &ref = *m1Ptr; map::const_iterator itr; for (itr = ref.begin(); itr != ref.end(); ++itr) { rClassNames.push_back(itr->first); } // remove duplicates // sort(rClassNames.begin(), rClassNames.end()); rClassNames.erase(unique(rClassNames.begin(), rClassNames.end()), rClassNames.end()); return (rClassNames); } vector ParamsMgr::GetRenderParamsClassNames(string winName) const { vector rClassNames; // _renderParamsMap[winName][dataSetName][className] // const map> *m2Ptr; m2Ptr = getWinMap3(_renderParamsMap, winName); if (!m2Ptr) return (rClassNames); // m2Ptr[dataSetName][className] // const map> &ref = *m2Ptr; map>::const_iterator itr; for (itr = ref.begin(); itr != ref.end(); ++itr) { string dataSetName = itr->first; vector tmpV = GetRenderParamsClassNames(winName, dataSetName); rClassNames.insert(rClassNames.end(), tmpV.begin(), tmpV.end()); } // remove duplicates // sort(rClassNames.begin(), rClassNames.end()); rClassNames.erase(unique(rClassNames.begin(), rClassNames.end()), rClassNames.end()); return (rClassNames); } vector ParamsMgr::GetRenderParamInstances(string winName, string dataSetName, string className) const { vector instances; RenParamsContainer *rpc = get_ren_container(winName, dataSetName, className); if (rpc) { vector names = rpc->GetNames(); instances.insert(instances.end(), names.begin(), names.end()); } // Sanity check. Names should always be unique! // sort(instances.begin(), instances.end()); instances.erase(unique(instances.begin(), instances.end()), instances.end()); return (instances); } vector ParamsMgr::GetRenderParamInstances(string winName, string className) const { vector instances; const map> *m2Ptr; m2Ptr = getWinMap3(_renderParamsMap, winName); if (!m2Ptr) return (instances); const map> & ref = *m2Ptr; map>::const_iterator itr; for (itr = ref.begin(); itr != ref.end(); ++itr) { string dataSetName = itr->first; RenParamsContainer *rpc = get_ren_container(winName, dataSetName, className); if (rpc) { vector names = rpc->GetNames(); instances.insert(instances.end(), names.begin(), names.end()); } } // Sanity check. Names should always be unique! // sort(instances.begin(), instances.end()); instances.erase(unique(instances.begin(), instances.end()), instances.end()); return (instances); } ViewpointParams *ParamsMgr::GetViewpointParams(string winName) const { return (get_vp_params(winName)); } #ifdef VAPOR3_0_0_ALPHA void ParamsMgr::InsertRenderParamsInstance(RenderParams *rp, string winName, string instName) { string className = rp->GetName(); RenParamsContainer *container = get_ren_container(winName, className); if (!container) { container = make_ren_container(className, winName); } VAssert(container != NULL); container->Insert(rp, instName); } #endif RenParamsContainer *ParamsMgr::get_ren_container(string winName, string dataSetName, string renderName) const { // map[winName][dataSetName][renderName] // const map *m1Ptr; m1Ptr = getWinMap3(_renderParamsMap, winName, dataSetName); if (!m1Ptr) return (NULL); // m1Ptr[className] // const map &ref = *m1Ptr; map::const_iterator itr; itr = ref.find(renderName); if (itr == ref.end()) return (NULL); return (itr->second); } void ParamsMgr::delete_ren_container(string winName, string dataSetName, string renderName) { // _renderParamsMap[winName][dataSetName][renderName] -> ref[renderName] // map *m1Ptr; m1Ptr = getWinMap3(_renderParamsMap, winName, dataSetName); if (!m1Ptr) return; // *m1Ptr[renderName] == ref[renderName] // map &ref = *m1Ptr; map::iterator itr; itr = ref.find(renderName); if (itr == ref.end()) return; RenParamsContainer *rpc = itr->second; ref.erase(renderName); if (!rpc) return; // Set parent to root so Xml representation will be deleted // rpc->GetNode()->SetParent(NULL); delete rpc; } void ParamsMgr::delete_ren_containers(string winName, string dataSetName) { // _renderParamsMap[winName][dataSetName][renderName] -> // ref1[dataSetName][renderName] // map> *m2Ptr; m2Ptr = getWinMap3(_renderParamsMap, winName); if (!m2Ptr) return; map> &ref1 = *m2Ptr; map>::iterator itr1; itr1 = ref1.find(dataSetName); if (itr1 == ref1.end()) return; // ref1[dataSetName][renderName] -> ref2[renderName] // map & ref2 = itr1->second; map::iterator itr2; while ((itr2 = ref2.begin()) != ref2.end()) { delete_ren_container(winName, dataSetName, itr2->first); } ref1.erase(dataSetName); } void ParamsMgr::delete_ren_containers(string winName) { // _renderParamsMap[winName][dataSetName][renderName] -> // ref1[dataSetName][renderName] // map> *m2Ptr; m2Ptr = getWinMap3(_renderParamsMap, winName); if (!m2Ptr) return; map> & ref = *m2Ptr; map>::iterator itr; while ((itr = ref.begin()) != ref.end()) { delete_ren_containers(winName, itr->first); } _renderParamsMap.erase(winName); } void ParamsMgr::delete_ren_containers() { // For each window name delete all of the windows render containers // map>>::iterator itr; while ((itr = _renderParamsMap.begin()) != _renderParamsMap.end()) { delete_ren_containers(itr->first); } } void ParamsMgr::delete_datasets(string dataSetName) { ParamsSeparator windowsSep(_rootSeparator, _windowsTag); XmlNode *winSepNode = windowsSep.GetNode(); for (int i = 0; i < winSepNode->GetNumChildren(); i++) { XmlNode *winNode = winSepNode->GetChild(i); string winName = winNode->GetTag(); delete_ren_containers(winName, dataSetName); XmlNode *renderersNode = winNode->GetChild(_renderersTag); for (int j = 0; j < renderersNode->GetNumChildren(); j++) { XmlNode *dataSepNode = renderersNode->GetChild(j); string s = dataSepNode->GetTag(); if (s == dataSetName) { dataSepNode->SetParent(NULL); break; } } } } RenParamsContainer *ParamsMgr::make_ren_container(string winName, string dataSetName, string renderName) { ParamsSeparator *windowsSep = new ParamsSeparator(_rootSeparator, _windowsTag); ParamsSeparator *windowSep = new ParamsSeparator(windowsSep, winName); ParamsSeparator *renderSep = new ParamsSeparator(windowSep, _renderersTag); ParamsSeparator *dataSep = new ParamsSeparator(renderSep, dataSetName); // Delete any existing occurences with the same name // RenParamsContainer *rpc = get_ren_container(winName, dataSetName, renderName); if (rpc) delete rpc; if (dataSep->HasChild(renderName)) { XmlNode *node = dataSep->GetNode()->GetChild(renderName); VAssert(node); rpc = new RenParamsContainer(_dataMgrMap[dataSetName], &_ssave, node); } else { rpc = new RenParamsContainer(_dataMgrMap[dataSetName], &_ssave, renderName); rpc->GetSeparator()->SetParent(dataSep); } _renderParamsMap[winName][dataSetName][renderName] = rpc; delete dataSep; delete renderSep; delete windowSep; delete windowsSep; return (rpc); } ViewpointParams *ParamsMgr::get_vp_params(string winName) const { map::const_iterator itr; itr = _viewpointParamsMap.find(winName); if (itr == _viewpointParamsMap.end()) return (NULL); return (itr->second); } ViewpointParams *ParamsMgr::make_vp_params(string winName) { ParamsSeparator *windowsSep = new ParamsSeparator(_rootSeparator, _windowsTag); ParamsSeparator *windowSep = new ParamsSeparator(windowsSep, winName); // Delete any existing occurences with the same name // ViewpointParams *vpParams = get_vp_params(winName); if (vpParams) delete vpParams; if (windowSep->HasChild(ViewpointParams::GetClassType())) { XmlNode *node = windowSep->GetNode()->GetChild(ViewpointParams::GetClassType()); VAssert(node); vpParams = new ViewpointParams(&_ssave, node); } else { vpParams = new ViewpointParams(&_ssave); vpParams->SetParent(windowSep); } _viewpointParamsMap[winName] = vpParams; delete windowsSep; delete windowSep; return (vpParams); } #ifdef VAPOR3_0_0_ALPHA //---------------------------------------------------------------------------- // Create a transfer function by parsing a file. //---------------------------------------------------------------------------- int ParamsMgr::loadFromFile(string path) { XmlParser xmlparser; XmlNode *node = GetNode(); int rc = xmlparser.LoadFromFile(node, path); if (rc < 0) { MyBase::SetErrMsg("Failed to read file %s : %M", path.c_str()); return (-1); } return (0); } #endif void ParamsMgr::GetAppRenderParams(string dataSetName, vector &appRenderParams) const { appRenderParams.clear(); std::map::const_iterator itr; itr = _otherRenParams.find(dataSetName); if (itr == _otherRenParams.cend()) return; vector v = itr->second->GetNames(); for (int i = 0; i < v.size(); i++) { if (itr->second->GetParams(v[i])) { appRenderParams.push_back(itr->second->GetParams(v[i])); } } } //---------------------------------------------------------------------------- // Save the transfer function to a file. //---------------------------------------------------------------------------- int ParamsMgr::SaveToFile(string path) const { ofstream out(path); if (!out) { MyBase::SetErrMsg("Failed to open file %s : %M", path.c_str()); return (-1); } out << *(_rootSeparator->GetNode()); if (out.bad()) { MyBase::SetErrMsg("Failed to write file %s : %M", path.c_str()); return (-1); } out.close(); return (0); } bool ParamsMgr::undoRedoHelper() { string description; // Get top of **undo** stack // const XmlNode *newNode = _ssave.GetTopUndo(description); if (!newNode) { newNode = _ssave.GetBase(); } if (!newNode) return (false); // nothing to undo - shouldnt get here // Need to disable state saving so the undo itself doesn't trigger // saving of intermediate state // bool saveState = GetSaveStateEnabled(); SetSaveStateEnabled(false); // Load the new Xml tree (which destroys the old one) // LoadState(newNode); // Restore state saving // SetSaveStateEnabled(saveState); return (true); } bool ParamsMgr::Undo() { bool status = _ssave.Undo(); if (!status) return (status); return (undoRedoHelper()); } bool ParamsMgr::Redo() { bool status = _ssave.Redo(); if (!status) return (status); return (undoRedoHelper()); } void ParamsMgr::UndoRedoClear() { _ssave.Clear(); RebaseStateSave(); } void ParamsMgr::ManuallyAddCurrentStateToUndoStack(const string ¬e) { _ssave.ManuallyAddCurrentStateToUndoStack(note); } string ParamsMgr::GetTopUndoDesc() const { string s; _ssave.GetTopUndo(s); return (s); } string ParamsMgr::GetTopRedoDesc() const { string s; _ssave.GetTopRedo(s); return (s); } ParamsMgr::PMgrStateSave::PMgrStateSave(int stackSize) : StateSave() { _enabled = true; _stackSize = stackSize; _rootNode = NULL; _state0 = NULL; _undoStack.clear(); _redoStack.clear(); } ParamsMgr::PMgrStateSave::~PMgrStateSave() { cleanStack(0, _undoStack); cleanStack(0, _redoStack); if (_state0) delete _state0; } void ParamsMgr::PMgrStateSave::Save(const XmlNode *node, string description) { VAssert(_rootNode); VAssert(node); if (!GetEnabled()) { return; } // Only save state if the node is a branch of the tree rooted at // the node named by _rootTag // vector pathvec = node->GetPathVec(); if ((!pathvec.size()) || (pathvec[0] != _rootTag)) { return; } if (GetUndoEnabled()) { const XmlNode *topNode = NULL; string s; topNode = GetTopUndo(s); if (topNode && (*topNode == *_rootNode)) { // Don't save tree if no changes return; } } if (!_groups.empty()) { return; } if (!_state0) { _state0 = new XmlNode(*_rootNode); } // Delete oldest elements if needed // cleanStack(_stackSize, _undoStack); // It not inside a group push this element onto the stack // if (GetUndoEnabled()) { _undoStack.push_back(make_pair(description, new XmlNode(*_rootNode))); } //#define DEBUG #ifdef DEBUG cout << "ParamsMgr::PMgrStateSave::Save() : saving node " << node->GetTag() << " : " << description << endl; #endif // Clear redo stack // cleanStack(0, _redoStack); emitStateChange(description); } void ParamsMgr::PMgrStateSave::BeginGroup(string description) { VAssert(_rootNode); VAssert(!description.empty()); if (!GetEnabled()) return; _groups.push(description); } void ParamsMgr::PMgrStateSave::EndGroup() { VAssert(_rootNode); if (!GetEnabled()) return; assert(_groups.size()); if (!_groups.size()) return; // BeginGroup() not called string desc = _groups.top(); _groups.pop(); // Don't do anything until _groups is empty // if (_groups.size()) return; if (GetUndoEnabled()) { const XmlNode *topNode = NULL; string s; topNode = GetTopUndo(s); if (topNode && (*topNode == *_rootNode)) { // Don't save tree if no changes // return; } } if (!_state0) { _state0 = new XmlNode(*_rootNode); } #ifdef DEBUG cout << "ParamsMgr::PMgrStateSave::EndGroup() : saving " << " : " << desc << endl; #endif // Delete oldest elements if needed // cleanStack(_stackSize, _undoStack); // Clear redo stack // cleanStack(0, _redoStack); if (GetUndoEnabled()) _undoStack.push_back(make_pair(desc, new XmlNode(*_rootNode))); emitStateChange(desc); } void ParamsMgr::PMgrStateSave::TriggerManualStateChangeEvent(const string &reason, const bool overrideEnabled) { if (!GetEnabled() && !overrideEnabled) return; emitStateChange("Manually triggered" + (reason.empty() ? "" : (": " + reason))); } void ParamsMgr::PMgrStateSave::IntermediateChange() { emitIntermediateStateChange(); } void ParamsMgr::PMgrStateSave::SetUndoEnabled(bool b) { if (!_groups.empty()) { return; // Can't change inside group } _addToUndoEnabled = b; } const XmlNode *ParamsMgr::PMgrStateSave::GetTopUndo(string &description) const { VAssert(_rootNode); description.clear(); if (!_undoStack.size()) return (NULL); const pair &p1 = _undoStack.back(); description = p1.first; return (p1.second); } const XmlNode *ParamsMgr::PMgrStateSave::GetTopRedo(string &description) const { VAssert(_rootNode); description.clear(); if (!_redoStack.size()) return (NULL); const pair &p1 = _redoStack.back(); description = p1.first; return (p1.second); } bool ParamsMgr::PMgrStateSave::Undo() { VAssert(_rootNode); if (!_undoStack.size()) return (false); pair &p1 = _undoStack.back(); // Delete oldest elements if needed // cleanStack(_stackSize, _redoStack); _redoStack.push_back(p1); _undoStack.pop_back(); if (GetEnabled()) emitStateChange("Undo " + p1.first); return (true); } bool ParamsMgr::PMgrStateSave::Redo() { VAssert(_rootNode); if (!_redoStack.size()) return (false); pair &p1 = _redoStack.back(); // Delete oldest elements if needed // cleanStack(_stackSize, _undoStack); _undoStack.push_back(p1); _redoStack.pop_back(); if (GetEnabled()) emitStateChange("Redo " + p1.first); return (true); } void ParamsMgr::PMgrStateSave::Clear() { VAssert(_rootNode); cleanStack(0, _undoStack); cleanStack(0, _redoStack); // while (_groups.size()) _groups.pop(); } void ParamsMgr::PMgrStateSave::ManuallyAddCurrentStateToUndoStack(const string ¬e) { // Delete oldest elements if needed cleanStack(_stackSize, _undoStack); // Clear redo stack cleanStack(0, _redoStack); assert(GetUndoEnabled()); _undoStack.push_back(make_pair(note, new XmlNode(*_rootNode))); } void ParamsMgr::PMgrStateSave::cleanStack(int maxN, std::deque> &s) { // Delete oldest elements if needed // while (s.size() > maxN) { pair &p1 = s.front(); if (p1.second) { delete p1.second; } s.pop_front(); } } void ParamsMgr::PMgrStateSave::emitStateChange(const string &reason) { _stateChangeReasonDescription = reason; // Trigger state change flags and CBs // for (int i = 0; i < _stateChangeFlags.size(); i++) { *(_stateChangeFlags[i]) = true; } for (int i = 0; i < _stateChangeCBs.size(); i++) { _stateChangeCBs[i](); } } void ParamsMgr::PMgrStateSave::emitIntermediateStateChange(const string &reason) { _stateChangeReasonDescription = reason; for (auto func : _intermediateStateChangeCBs) func(); } ================================================ FILE: lib/params/ParticleParams.cpp ================================================ #include #include #include #include using namespace Wasp; using namespace VAPoR; static RenParamsRegistrar registrar(ParticleParams::GetClassType()); const std::string ParticleParams::ShowDirectionTag = "ShowDirectionTag"; const std::string ParticleParams::DirectionScaleTag = "DirectionScaleTag"; const std::string ParticleParams::StrideTag = "StrideTag"; const std::string ParticleParams::RenderRadiusScalarTag = "RenderRadiusScalarTag"; PARAMS_IMPL_TAG(ParticleParams, RenderRadiusVariableTag); PARAMS_IMPL_TAG(ParticleParams, RenderRadiusVariableStrengthTag); PARAMS_IMPL_TAG(ParticleParams, RecalculateRadiusBaseRequestTag); const std::string ParticleParams::LightingEnabledTag = "LightingEnabledTag"; const std::string ParticleParams::RenderRadiusBaseTag = "RenderRadiusBaseTag"; const std::string ParticleParams::RenderLegacyTag = "RenderLegacyTag"; const std::string ParticleParams::PhongAmbientTag = "PhongAmbientTag"; const std::string ParticleParams::PhongDiffuseTag = "PhongDiffuseTag"; const std::string ParticleParams::PhongSpecularTag = "PhongSpecularTag"; const std::string ParticleParams::PhongShininessTag = "PhongShininessTag"; ParticleParams::ParticleParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, ParticleParams::GetClassType(), 3) { SetDiagMsg("ParticleParams::ParticleParams() this=%p", this); _init(); } ParticleParams::ParticleParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, std::string classType) : RenderParams(dataMgr, ssave, classType, 3) { SetDiagMsg("ParticleParams::ParticleParams() this=%p", this); _init(); } ParticleParams::ParticleParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node, 3) {} ParticleParams::~ParticleParams() { SetDiagMsg("ParticleParams::~ParticleParams() this=%p", this); } // Set everything to default values void ParticleParams::_init() { SetDiagMsg("ParticleParams::_init()"); SetValueLong(ShowDirectionTag, "", false); SetValueDouble(DirectionScaleTag, "", 1); SetValueLong(StrideTag, "", 1); SetValueDouble(RenderRadiusScalarTag, "", 8.); SetValueDouble(RenderRadiusVariableStrengthTag, "", 1.); SetValueDouble(RenderRadiusBaseTag, "", -1); SetValueLong(RenderLegacyTag, "", false); SetValueLong(LightingEnabledTag, "", true); SetValueDouble(PhongAmbientTag, "", .4); SetValueDouble(PhongDiffuseTag, "", .8); SetValueDouble(PhongSpecularTag, "", 0.); SetValueDouble(PhongShininessTag, "", 0.5); RenderParams::SetDefaultVariables(3, true); } ================================================ FILE: lib/params/RayCasterParams.cpp ================================================ #include "vapor/RayCasterParams.h" using namespace VAPoR; const std::string RayCasterParams::_lightingTag = "LightingTag"; const std::string RayCasterParams::_lightingCoeffsTag = "LightingCoeffTag"; const std::string RayCasterParams::_castingModeTag = "CastingModeTag"; const std::string RayCasterParams::_sampleMultiplierTag = "SampleMultiplierTag"; RayCasterParams::RayCasterParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, std::string classType) : RenderParams(dataManager, stateSave, classType, 3 /* max dim */) { SetFieldVariableNames(vector()); SetDiagMsg("RayCasterParams::RayCasterParams() this=%p", this); } // Constructor RayCasterParams::RayCasterParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, XmlNode *node) : RenderParams(dataManager, stateSave, node, 3 /* max dim */) { SetDiagMsg("RayCasterParams::RayCasterParams() this=%p", this); } // Destructor RayCasterParams::~RayCasterParams() { SetDiagMsg("RayCasterParams::~RayCasterParams() this=%p", this); } MapperFunction *RayCasterParams::GetMapperFunc() { return RenderParams::GetMapperFunc(GetVariableName()); } void RayCasterParams::SetLighting(bool lightingOn) { SetValueLong(_lightingTag, "Apply lighting or not", (long int)lightingOn); } bool RayCasterParams::GetLighting() const { long l = GetValueLong(_lightingTag, 1); return (bool)l; } std::vector RayCasterParams::GetLightingCoeffs() const { std::vector defaultVec(4); defaultVec[0] = 0.2; defaultVec[1] = 0.5; defaultVec[2] = 0.25; defaultVec[3] = 8.0; return GetValueDoubleVec(_lightingCoeffsTag, defaultVec); } void RayCasterParams::SetLightingCoeffs(const std::vector &coeffs) { SetValueDoubleVec(_lightingCoeffsTag, "Coefficients for lighting effects", coeffs); } long RayCasterParams::GetCastingMode() const { return GetValueLong(_castingModeTag, 0); // 0 means it's not set by the user yet. } void RayCasterParams::SetCastingMode(long mode) { if (mode == 1 || mode == 2) // currently supported casting modes SetValueLong(_castingModeTag, "Which ray casting mode", mode); else // put mode 1 here SetValueLong(_castingModeTag, "Which ray casting mode", 1); } long RayCasterParams::GetSampleRateMultiplier() const { return GetValueLong(_sampleMultiplierTag, 0); } void RayCasterParams::SetSampleRateMultiplier(long val) { if (val >= 0 && val < 7) SetValueLong(_sampleMultiplierTag, "How to adjust the sample rate", val); else SetValueLong(_sampleMultiplierTag, "How to adjust the sample rate", 0); } ================================================ FILE: lib/params/RenderParams.cpp ================================================ //************************************************************************ // * // Copyright (C) 2014 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: RenderParams.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: July 2014 // // Description: Implements the RenderParams class. // This is an abstract class for all the tabbed panel rendering params classes. // Supports functionality common to all the tabbed panel render params. // #include #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include using namespace VAPoR; const string RenderParams::_EnabledTag = "Enabled"; const string RenderParams::_histoScaleTag = "HistoScale"; const string RenderParams::_editBoundsTag = "EditBounds"; const string RenderParams::_histoBoundsTag = "HistoBounds"; const string RenderParams::_cursorCoordsTag = "CursorCoords"; const string RenderParams::_heightVariableNameTag = "HeightVariable"; const string RenderParams::_colorMapVariableNameTag = "ColorMapVariable"; const string RenderParams::_xFieldVariableNameTag = "FieldVariableName_X"; const string RenderParams::_yFieldVariableNameTag = "FieldVariableName_Y"; const string RenderParams::_zFieldVariableNameTag = "FieldVariableName_Z"; const string RenderParams::_auxVariableNamesTag = "AuxVariableNames"; const string RenderParams::_distribVariableNamesTag = "DistributionVariableNames"; const string RenderParams::_variableNameTag = "VariableName"; const string RenderParams::_useSingleColorTag = "UseSingleColor"; const string RenderParams::_constantColorTag = "ConstantColor"; const string RenderParams::_constantOpacityTag = "ConstantOpacity"; const string RenderParams::CustomHistogramDataTag = "CustomHistogramData"; const string RenderParams::CustomHistogramRangeTag = "CustomHistogramRange"; const string RenderParams::_CompressionLevelTag = "CompressionLevel"; const string RenderParams::_RefinementLevelTag = "RefinementLevel"; const string RenderParams::_transferFunctionsTag = "MapperFunctions"; const string RenderParams::_stretchFactorsTag = "StretchFactors"; const string RenderParams::_currentTimestepTag = "CurrentTimestep"; const string RenderParams::XSlicePlaneOriginTag = "XSlicePlaneOrigin"; const string RenderParams::YSlicePlaneOriginTag = "YSlicePlaneOrigin"; const string RenderParams::ZSlicePlaneOriginTag = "ZSlicePlaneOrigin"; const string RenderParams::XSlicePlaneRotationTag = "XSlicePlaneRotation"; const string RenderParams::YSlicePlaneRotationTag = "YSlicePlaneRotation"; const string RenderParams::ZSlicePlaneRotationTag = "ZSlicePlaneRotation"; const string RenderParams::SampleRateTag = "SampleRate"; const string RenderParams::SliceOffsetTag = "SliceOffsetTag"; const string RenderParams::SlicePlaneNormalXTag = "SlicePlaneNormalXTag"; const string RenderParams::SlicePlaneNormalYTag = "SlicePlaneNormalYTag"; const string RenderParams::SlicePlaneNormalZTag = "SlicePlaneNormalZTag"; const string RenderParams::SlicePlaneOrientationModeTag = "SlicePlaneOrientationModeTag"; const string RenderParams::LightingEnabledTag = "LightingEnabled"; const string RenderParams::UserNameTag = "UserNameTag"; const string RenderParams::DrawInFrontTag = "DrawInFrontTag"; #define REQUIRED_SAMPLE_SIZE 1000000 namespace { vector string_replace(vector v, string olds, string news) { for (int i = 0; i < v.size(); i++) { if (v[i] == olds) v[i] = news; } return (v); } string string_replace(string s, string olds, string news) { if (s == olds) s = news; return (s); } }; // namespace void RenderParams::SetDefaultVariables(int dim = 3, bool secondaryColormapVariable = false) { // Find the first variable in the data collection of // the requested dimesion that exists and make it the default. // string varname; size_t ts; bool ok = false; for (int i = dim; i > 1; i--) { if (ok = DataMgrUtils::GetFirstExistingVariable(_dataMgr, 0, 0, i, varname, ts)) break; } if (!ok) varname = ""; SetVariableName(varname); SetColorMapVariableName(varname); // Now set the rest of the variable name fields. It's not important // that these exist or not // vector varnames; varnames = _dataMgr->GetDataVarNames(dim); // Try to find U, V, and W vector variables vector fieldVarNames(3, ""); fieldVarNames[0] = _findVarStartingWithLetter(varnames, 'u'); fieldVarNames[1] = _findVarStartingWithLetter(varnames, 'v'); if (dim == 3) { fieldVarNames[2] = _findVarStartingWithLetter(varnames, 'w'); SetHeightVariableName(""); } // If we can't find U or V, look for variables that correspond with the X, Y, and Z dimensions such as bx, by, and bz if (fieldVarNames[0] == "" || fieldVarNames[1] == "") { fieldVarNames[0] = _findVarEndingWithLetter(varnames, 'x'); fieldVarNames[1] = _findVarEndingWithLetter(varnames, 'y'); if (dim == 3) fieldVarNames[2] = _findVarEndingWithLetter(varnames, 'z'); } SetFieldVariableNames(fieldVarNames); string colorVar = varname; if (secondaryColormapVariable) colorVar = _findVarStartingWithLetter(varnames, 't'); if (!colorVar.empty()) SetColorMapVariableName(colorVar); } void RenderParams::_init() { SetEnabled(true); SetDefaultVariables(_maxDim); SetRefinementLevel(0); SetCompressionLevel(0); SetHistoStretch(1.0); float rgb[] = {1.0, 1.0, 1.0}; SetConstantColor(rgb); SetConstantOpacity(1.0); SetDrawInFront(false); } int RenderParams::Initialize() { if (_classInitialized) return (0); // // Initialize box with bounds of a single variable. First check // variable returned by GetVariableName(). If not available, // look for others // string varname = GetVariableName(); size_t ts = GetCurrentTimestep(); size_t tsInit = ts; int ndim = _maxDim; bool foundVar = false; if (!varname.empty()) { for (size_t ts = 0; ts < _dataMgr->GetNumTimeSteps() && !foundVar; ts++) { if (!_dataMgr->VariableExists(ts, varname, 0, 0)) { foundVar = true; } } } if (!foundVar) { // Probably should have a _minDim here.. // varname.clear(); for (; ndim > 0; ndim--) { bool ok = DataMgrUtils::GetFirstExistingVariable(_dataMgr, 0, 0, ndim, varname, ts); if (ok) { foundVar = true; if (_dataMgr->VariableExists(tsInit, varname, 0, 0)) { ts = tsInit; break; } } } } if (!foundVar) return (0); (void)InitBoxFromVariable(ts, varname); _classInitialized = true; return (0); } int RenderParams::ResetUserExtentsToDataExents(string var) { if (var.empty()) var = GetVariableName(); CoordType minExt, maxExt; int rc = _dataMgr->GetVariableExtents(GetCurrentTimestep(), var, 0, 0, minExt, maxExt); if (rc < 0) return (-1); VAssert(minExt.size() == maxExt.size() && (minExt.size() == 2 || minExt.size() == 3)); bool planar = _dataMgr->GetNumDimensions(var) == 2; if (planar) { _Box->SetOrientation(VAPoR::Box::XY); } else { _Box->SetOrientation(VAPoR::Box::XYZ); } _Box->SetExtents(minExt, maxExt); _Box->SetPlanar(planar); vector origin(minExt.size()); for (int i = 0; i < minExt.size(); i++) { origin[i] = minExt[i] + (maxExt[i] - minExt[i]) * 0.5; } _transform->SetOrigin(origin); return 0; } RenderParams::RenderParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, const string &classname, int maxdim) : ParamsBase(ssave, classname) { _classInitialized = false; _dataMgr = dataMgr; _maxDim = maxdim; _stride = 1; // Initialize DataMgr dependent parameters // _init(); _TFs = new ParamsContainer(ssave, _transferFunctionsTag); _TFs->SetParent(this); _Box = new Box(ssave); _Box->SetParent(this); _Colorbar = new ColorbarPbase(ssave); _Colorbar->SetParent(this); _transform = new Transform(ssave); _transform->SetParent(this); } RenderParams::RenderParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node, int maxdim) : ParamsBase(ssave, node) { _classInitialized = true; _dataMgr = dataMgr; _maxDim = maxdim; _stride = 1; // Reconcile DataMgr dependent parameters // if (node->HasChild(_transferFunctionsTag)) { _TFs = new ParamsContainer(ssave, node->GetChild(_transferFunctionsTag)); } else { // Node doesn't contain a transfer function container // _TFs = new ParamsContainer(ssave, _transferFunctionsTag); _TFs->SetParent(this); } if (node->HasChild(Box::GetClassType())) { _Box = new Box(ssave, node->GetChild(Box::GetClassType())); } else { // Node doesn't contain a Box // _Box = new Box(ssave); _Box->SetParent(this); } if (node->HasChild(ColorbarPbase::GetClassType())) { _Colorbar = new ColorbarPbase(ssave, node->GetChild(ColorbarPbase::GetClassType())); } else { // Node doesn't contain a ColorbarPbase // _Colorbar = new ColorbarPbase(ssave); _Colorbar->SetParent(this); } if (node->HasChild(Transform::GetClassType())) { _transform = new Transform(ssave, node->GetChild(Transform::GetClassType())); } else { // Node doesn't contain a Transform // _transform = new Transform(ssave); _transform->SetParent(this); } } RenderParams::RenderParams(const RenderParams &rhs) : ParamsBase(rhs) { _dataMgr = rhs._dataMgr; _TFs = new ParamsContainer(*(rhs._TFs)); _Box = new Box(*(rhs._Box)); _Colorbar = new ColorbarPbase(*(rhs._Colorbar)); _transform = new Transform(*(rhs._transform)); } RenderParams &RenderParams::operator=(const RenderParams &rhs) { if (_TFs) delete _TFs; if (_Box) delete _Box; if (_Colorbar) delete _Colorbar; if (_transform) delete _transform; ParamsBase::operator=(rhs); _dataMgr = rhs._dataMgr; _TFs = new ParamsContainer(*(rhs._TFs)); _Box = new Box(*(rhs._Box)); _Colorbar = new ColorbarPbase(*(rhs._Colorbar)); _transform = new Transform(*(rhs._transform)); return (*this); } RenderParams::~RenderParams() { if (_TFs) delete _TFs; if (_Box) delete _Box; if (_Colorbar) delete _Colorbar; if (_transform) delete _transform; } void RenderParams::SetEnabled(bool val) { SetValueLong(_EnabledTag, "enable/disable renderer", val); } void RenderParams::SetVariableName(string varname) { varname = string_replace(varname, "", "NULL"); varname = string_replace(varname, "", "NULL"); SetValueString(_variableNameTag, "Specify variable name", varname); } string RenderParams::GetVariableName() const { string varname = GetValueString(_variableNameTag, ""); varname = string_replace(varname, "NULL", ""); return (varname); } int RenderParams::GetCompressionLevel() const { return GetValueLong(_CompressionLevelTag, 0); } void RenderParams::SetCompressionLevel(int level) { SetValueLong(_CompressionLevelTag, "Set compression level", level); } void RenderParams::SetRefinementLevel(int level) { if (level < 0) level = 0; SetValueLong(_RefinementLevelTag, "Set refinement level", level); } int RenderParams::GetRefinementLevel() const { return (GetValueLong(_RefinementLevelTag, 0)); } void RenderParams::SetHistoStretch(float factor) { if (factor < 0.0) factor = 0.0; SetValueDouble(_histoScaleTag, "Set histo stretch", (double)factor); } float RenderParams::GetHistoStretch() const { float factor = GetValueDouble(_histoScaleTag, (float)1.0); if (factor < 0.0) factor = 0.0; return (factor); } void RenderParams::SetColorbarPbase(ColorbarPbase *pb) { if (_Colorbar) delete _Colorbar; _Colorbar = new ColorbarPbase(*pb); _Colorbar->SetParent(this); } void RenderParams::_calculateStride(string varName) { if (varName.empty() || varName == "NULL") { _stride = 1; return; } std::vector dimsAtLevel; int ref = GetRefinementLevel(); // Yikes. Error reporting is turned off, so ignore the return code _dataMgr->GetDimLensAtLevel(varName, ref, dimsAtLevel, GetCurrentTimestep()); int size = 1; for (int i = 0; i < dimsAtLevel.size(); i++) size *= dimsAtLevel[i]; _stride = 1; if (size > REQUIRED_SAMPLE_SIZE) _stride = 1 + size / REQUIRED_SAMPLE_SIZE; } MapperFunction *RenderParams::GetMapperFunc(string varname) { // This way we always return a valid MapperFunction // if (varname.empty()) { varname = "NULL"; } MapperFunction *tfptr = dynamic_cast(_TFs->GetParams(varname)); if (tfptr) { return (tfptr); } // Disable state saving for Get function // bool enabled = _ssave->GetEnabled(); _ssave->SetEnabled(false); MapperFunction tf(_ssave); _calculateStride(varname); size_t ts = 0; int level = 0; int lod = 0; if (_dataMgr->VariableExists(ts, varname, level, lod)) { CoordType minExt, maxExt; _Box->GetExtents(minExt, maxExt); vector range; bool prev = EnableErrMsg(false); // no error handling int rc = _dataMgr->GetDataRange(ts, varname, level, lod, minExt, maxExt, range); if (rc < 0) { range = {0.0, 1.0}; } EnableErrMsg(prev); tf.setMinMaxMapValue(range[0], range[1]); } _TFs->Insert(&tf, varname); tfptr = (MapperFunction *)_TFs->GetParams(varname); VAssert(tfptr != NULL); _ssave->SetEnabled(enabled); return (tfptr); } void RenderParams::RemoveMapperFunc(string varname) { _TFs->Remove(varname); } void RenderParams::SetMapperFunc(string varname, MapperFunction *mf) { if (_TFs->GetParams(varname)) { _TFs->Remove(varname); } _TFs->Insert(mf, varname); } void RenderParams::SetCursorCoords(const float coords[2]) { vector coordsv; coordsv.push_back(coords[0]); coordsv.push_back(coords[1]); SetValueDoubleVec(_cursorCoordsTag, "set cursor coords", coordsv); } void RenderParams::GetCursorCoords(float coords[2]) const { coords[0] = coords[1] = 2; vector defaultv(2, 0.0); vector coordsv = GetValueDoubleVec(_cursorCoordsTag, defaultv); } vector RenderParams::GetFieldVariableNames() const { // vector defaultv(3, ""); vector varnames(3); // varnames = GetValueStringVec(_fieldVariableNamesTag, defaultv); varnames[0] = GetValueString(_xFieldVariableNameTag, ""); varnames[1] = GetValueString(_yFieldVariableNameTag, ""); varnames[2] = GetValueString(_zFieldVariableNameTag, ""); varnames = string_replace(varnames, "NULL", ""); for (int i = varnames.size(); i < 3; i++) varnames.push_back(""); return (varnames); } void RenderParams::SetFieldVariableNames(vector varnames) { varnames = string_replace(varnames, "", "NULL"); varnames = string_replace(varnames, "", "NULL"); for (int i = varnames.size(); i < 3; i++) varnames.push_back("NULL"); SetValueString(_xFieldVariableNameTag, "", varnames[0]); SetValueString(_yFieldVariableNameTag, "", varnames[1]); SetValueString(_zFieldVariableNameTag, "", varnames[2]); } std::string RenderParams::GetXFieldVariableName() const { std::vector fieldVars = GetFieldVariableNames(); VAssert(fieldVars.size() == 3); return fieldVars[0]; } void RenderParams::SetXFieldVariableName(std::string varName) { std::vector fieldVars = GetFieldVariableNames(); VAssert(fieldVars.size() == 3); fieldVars[0] = varName; SetFieldVariableNames(fieldVars); } std::string RenderParams::GetYFieldVariableName() const { std::vector fieldVars = GetFieldVariableNames(); VAssert(fieldVars.size() == 3); return fieldVars[1]; } void RenderParams::SetYFieldVariableName(std::string varName) { std::vector fieldVars = GetFieldVariableNames(); VAssert(fieldVars.size() == 3); fieldVars[1] = varName; SetFieldVariableNames(fieldVars); } std::string RenderParams::GetZFieldVariableName() const { std::vector fieldVars = GetFieldVariableNames(); VAssert(fieldVars.size() == 3); return fieldVars[2]; } void RenderParams::SetZFieldVariableName(std::string varName) { std::vector fieldVars = GetFieldVariableNames(); VAssert(fieldVars.size() == 3); fieldVars[2] = varName; SetFieldVariableNames(fieldVars); } vector RenderParams::GetAuxVariableNames() const { std::vector varnames = GetValueStringVec(_auxVariableNamesTag); varnames = string_replace(varnames, "NULL", ""); return (varnames); } void RenderParams::SetAuxVariableNames(std::vector varnames) { varnames = string_replace(varnames, "", "NULL"); varnames = string_replace(varnames, "", "NULL"); SetValueStringVec(_auxVariableNamesTag, "Specify auxiliary varnames", varnames); } string RenderParams::GetFirstVariableName() const { string str = GetVariableName(); if (str.length()) return str; // scalar vector strvec = GetFieldVariableNames(); for (int i = 0; i < strvec.size(); i++) { if (strvec[i] != "") return strvec[i]; // vector } str = GetColorMapVariableName(); if (!str.empty()) return str; str = GetHeightVariableName(); if (str.length()) return str; // height return ""; // none } string RenderParams::GetHeightVariableName() const { string varname = GetValueString(_heightVariableNameTag, ""); varname = string_replace(varname, "NULL", ""); return (varname); } void RenderParams::SetHeightVariableName(string varname) { varname = string_replace(varname, "", "NULL"); varname = string_replace(varname, "", "NULL"); SetValueString(_heightVariableNameTag, "Set height variable name", varname); // setAllBypass(false); } string RenderParams::GetColorMapVariableName() const { string varname = GetValueString(_colorMapVariableNameTag, ""); varname = string_replace(varname, "NULL", ""); return (varname); } bool RenderParams::UseSingleColor() const { return GetValueLong(_useSingleColorTag, GetUseSingleColorDefault()); } void RenderParams::SetUseSingleColor(bool val) { SetValueLong(_useSingleColorTag, "enable/disable use single color", (long)val); } void RenderParams::SetColorMapVariableName(string varname) { varname = string_replace(varname, "", "NULL"); varname = string_replace(varname, "", "NULL"); SetValueString(_colorMapVariableNameTag, "Set color map variable name", varname); } void RenderParams::SetConstantColor(const float rgb[3]) { vector rgbv; for (int i = 0; i < 3; i++) { float v = rgb[i]; if (v < 0.0) v = 0.0; if (v > 1.0) v = 1.0; rgbv.push_back(v); } SetValueDoubleVec(_constantColorTag, "Specify constant color in RGB", rgbv); } void RenderParams::SetConstantColor(vector rgb) { rgb.resize(3, 0); SetConstantColor(rgb.data()); } void RenderParams::GetConstantColor(float rgb[3]) const { vector defaultv(3, 1.0); vector rgbv = GetValueDoubleVec(_constantColorTag, defaultv); for (int i = 0; i < rgbv.size() && i < 3; i++) { float v = rgbv[i]; if (v < 0.0) v = 0.0; if (v > 1.0) v = 1.0; rgb[i] = rgbv[i]; } }; void RenderParams::SetConstantOpacity(float o) { if (o < 0.0) o = 0.0; if (o > 1.0) o = 1.0; SetValueDouble(_constantOpacityTag, "Specify constant opacity", o); } float RenderParams::GetConstantOpacity() const { vector defaultv(1, 1.0); vector vec = GetValueDoubleVec(_constantOpacityTag, defaultv); float o = 1.0; if (vec.size()) o = vec[0]; if (o < 0.0) o = 0.0; if (o > 1.0) o = 1.0; return (o); } string RenderParams::_findVarStartingWithLetter(vector searchVars, char letter) { for (auto &element : searchVars) { if (element[0] == letter || element[0] == toupper(letter)) { return element; } } return ""; } string RenderParams::_findVarEndingWithLetter(vector searchVars, char letter) { for (auto &element : searchVars) { int last = element.size()-1; if (element[last] == letter || element[last] == toupper(letter)) { return element; } } return ""; } ////////////////////////////////////////////////////////////////////////// // // RenParamsFactory Class // ///////////////////////////////////////////////////////////////////////// RenderParams *RenParamsFactory::CreateInstance(string className, DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) { RenderParams *instance = NULL; // find className in the registry and call factory method. // auto it = _factoryFunctionRegistry.find(className); if (it != _factoryFunctionRegistry.end()) instance = it->second(dataMgr, ssave, node); if (instance != NULL) return instance; else return NULL; } vector RenParamsFactory::GetFactoryNames() const { vector names; map>::const_iterator itr; for (itr = _factoryFunctionRegistry.begin(); itr != _factoryFunctionRegistry.end(); ++itr) { names.push_back(itr->first); } return (names); } ////////////////////////////////////////////////////////////////////////// // // RenParamsContainer Class // ///////////////////////////////////////////////////////////////////////// RenParamsContainer::RenParamsContainer(DataMgr *dataMgr, ParamsBase::StateSave *ssave, const string &name) { VAssert(dataMgr != NULL); VAssert(ssave != NULL); _dataMgr = dataMgr; _ssave = ssave; _separator = NULL; _elements.clear(); _separator = new ParamsSeparator(ssave, name); } RenParamsContainer::RenParamsContainer(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) { VAssert(dataMgr != NULL); VAssert(ssave != NULL); VAssert(node != NULL); _dataMgr = dataMgr; _ssave = ssave; _separator = new ParamsSeparator(ssave, node); _elements.clear(); for (int i = 0; i < node->GetNumChildren(); i++) { XmlNode *eleNameNode = node->GetChild(i); if (!eleNameNode->HasChild(0)) continue; // bad node XmlNode *eleNode = eleNameNode->GetChild(0); string eleName = eleNameNode->GetTag(); string classname = eleNode->GetTag(); RenderParams *rParams = RenParamsFactory::Instance()->CreateInstance(classname, dataMgr, ssave, eleNode); if (rParams == NULL) { SetDiagMsg("RenParamsContainer::RenParamsContainer() unrecognized class: %s", classname.c_str()); continue; } _elements[eleName] = rParams; } } RenParamsContainer::RenParamsContainer(const RenParamsContainer &rhs) { _dataMgr = rhs._dataMgr; _ssave = rhs._ssave; _separator = NULL; _elements.clear(); _separator = new ParamsSeparator(*(rhs._separator)); _separator->SetParent(NULL); vector names = rhs.GetNames(); for (int i = 0; i < names.size(); i++) { // Make copy of RenderParams // RenderParams *rhspb = rhs.GetParams(names[i]); XmlNode * node = new XmlNode(*(rhspb->GetNode())); string classname = rhspb->GetName(); RenderParams *mypb = RenParamsFactory::Instance()->CreateInstance(classname, _dataMgr, _ssave, node); mypb->SetParent(_separator); _elements[names[i]] = mypb; } } RenParamsContainer &RenParamsContainer::operator=(const RenParamsContainer &rhs) { VAssert(_separator); vector mynames = GetNames(); for (int i = 0; i < mynames.size(); i++) { Remove(mynames[i]); } _elements.clear(); _dataMgr = rhs._dataMgr; _ssave = rhs._ssave; _separator = rhs._separator; vector names = rhs.GetNames(); for (int i = 0; i < names.size(); i++) { XmlNode *eleNameNode = _separator->GetNode()->GetChild(names[i]); VAssert(eleNameNode); ParamsSeparator mySep(_ssave, eleNameNode); XmlNode *eleNode = eleNameNode->GetChild(0); string eleName = eleNameNode->GetTag(); string classname = eleNode->GetTag(); RenderParams *mypb = RenParamsFactory::Instance()->CreateInstance(classname, _dataMgr, _ssave, eleNode); mypb->SetParent(&mySep); _elements[names[i]] = mypb; } return (*this); } RenParamsContainer::~RenParamsContainer() { map::iterator itr; for (itr = _elements.begin(); itr != _elements.end(); ++itr) { if (itr->second) delete itr->second; } if (_separator) delete _separator; } RenderParams *RenParamsContainer::Insert(const RenderParams *pb, string name) { VAssert(pb != NULL); if (name.empty()) { name = "NULL"; } map::iterator itr = _elements.find(name); if (itr != _elements.end()) { delete itr->second; } // Create a separator node // ParamsSeparator mySep(_ssave, name); mySep.SetParent(_separator); // Create element name node // string classname = pb->GetName(); XmlNode * node = new XmlNode(*(pb->GetNode())); RenderParams *mypb = RenParamsFactory::Instance()->CreateInstance(classname, _dataMgr, _ssave, node); VAssert(mypb != NULL); mypb->SetParent(&mySep); _elements[name] = mypb; return (mypb); } RenderParams *RenParamsContainer::Create(string className, string name) { VAssert(!className.empty()); VAssert(!name.empty()); map::iterator itr = _elements.find(name); if (itr != _elements.end()) { delete itr->second; } // Create a separator node // ParamsSeparator mySep(_ssave, name); mySep.SetParent(_separator); // Create the desired class // RenderParams *mypb = RenParamsFactory::Instance()->CreateInstance(className, _dataMgr, _ssave, NULL); VAssert(mypb != NULL); mypb->SetParent(&mySep); _elements[name] = mypb; return (mypb); } void RenParamsContainer::Remove(string name) { map::iterator itr = _elements.find(name); if (itr == _elements.end()) return; RenderParams *mypb = itr->second; // Set parent to root so Xml representation will be deleted // mypb->SetParent(NULL); delete mypb; _elements.erase(itr); } RenderParams *RenParamsContainer::GetParams(string name) const { if (name.empty()) { name = "NULL"; } map::const_iterator itr = _elements.find(name); if (itr != _elements.end()) return (itr->second); return (NULL); } vector RenParamsContainer::GetNames() const { map::const_iterator itr; vector names; for (itr = _elements.begin(); itr != _elements.end(); ++itr) { names.push_back(itr->first); } return (names); } bool RenderParams::GetOrientable() const { return false; } vector RenderParams::GetSlicePlaneRotation() const { vector v; v.push_back(GetValueDouble(XSlicePlaneRotationTag, 0)); v.push_back(GetValueDouble(YSlicePlaneRotationTag, 0)); v.push_back(GetValueDouble(ZSlicePlaneRotationTag, 0)); return v; } vector RenderParams::GetSlicePlaneOrigin() const { vector v; v.push_back(GetXSlicePlaneOrigin()); v.push_back(GetYSlicePlaneOrigin()); v.push_back(GetZSlicePlaneOrigin()); return v; } vector RenderParams::GetSlicePlaneNormal() const { vector v; v.push_back(GetValueDouble(SlicePlaneNormalXTag, 0)); v.push_back(GetValueDouble(SlicePlaneNormalYTag, 0)); v.push_back(GetValueDouble(SlicePlaneNormalZTag, 1)); float l = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); if (abs(l) < FLT_EPSILON) l = 1; v[0] /= l; v[1] /= l; v[2] /= l; return v; } void RenderParams::SetXSlicePlaneOrigin(double xOrigin) { SetValueDouble(XSlicePlaneOriginTag, "Set origin of plane on X axis", xOrigin); } void RenderParams::SetYSlicePlaneOrigin(double yOrigin) { SetValueDouble(YSlicePlaneOriginTag, "Set origin of plane on Y axis", yOrigin); } void RenderParams::SetZSlicePlaneOrigin(double zOrigin) { SetValueDouble(ZSlicePlaneOriginTag, "Set origin of plane on Z axis", zOrigin); } double RenderParams::GetXSlicePlaneOrigin() const { VAPoR::CoordType min, max; GetBox()->GetExtents(min, max); double defaultVal = (min[0] + max[0]) / 2.; return GetValueDouble(XSlicePlaneOriginTag, defaultVal); } double RenderParams::GetYSlicePlaneOrigin() const { VAPoR::CoordType min, max; GetBox()->GetExtents(min, max); double defaultVal = (min[1] + max[1]) / 2.; return GetValueDouble(YSlicePlaneOriginTag, defaultVal); } double RenderParams::GetZSlicePlaneOrigin() const { VAPoR::CoordType min, max; GetBox()->GetExtents(min, max); double defaultVal = (min[2] + max[2]) / 2.; return GetValueDouble(ZSlicePlaneOriginTag, defaultVal); } void RenderParams::SetDrawInFront(bool drawOnTop) { return SetValueLong(DrawInFrontTag, "Set renderer whether to draw on top (no depth testing)", drawOnTop); } bool RenderParams::GetDrawInFront() const { return GetValueLong(DrawInFrontTag, 0); } bool RenderParams::InitBoxFromVariable(size_t ts, string varName) { bool enabled = _ssave->GetEnabled(); _ssave->SetEnabled(false); CoordType minExt, maxExt; int rc = _dataMgr->GetVariableExtents(ts, varName, 0, 0, minExt, maxExt); if (rc < 0) { _ssave->SetEnabled(enabled); return (false); } _ssave->SetEnabled(enabled); // Configure box as planar or volumetric. // // N.B.Not handling case where ndim == 1!!! // size_t ndim = _dataMgr->GetVarTopologyDim(varName); bool planar = ndim == 2; if (planar) { _Box->SetOrientation(VAPoR::Box::XY); } else { _Box->SetOrientation(VAPoR::Box::XYZ); } vector minExtVec = {minExt[0], minExt[1], minExt[2]}; vector maxExtVec = {maxExt[0], maxExt[1], maxExt[2]}; _Box->SetExtents(minExtVec, maxExtVec); _Box->SetPlanar(planar); vector origin(minExt.size()); for (int i = 0; i < minExt.size(); i++) { origin[i] = minExt[i] + (maxExt[i] - minExt[i]) * 0.5; } if (planar) { bool ok = DataMgrUtils::GetFirstExistingVariable(_dataMgr, 0, 0, 3, varName, ts); if (ok) { CoordType minExt, maxExt; int rc = _dataMgr->GetVariableExtents(ts, varName, 0, 0, minExt, maxExt); if (rc == 0) { origin[2] = minExt[2] + (maxExt[2] - minExt[2]) * 0.5; } } } _transform->SetOrigin(origin); SetValueDouble(XSlicePlaneOriginTag, "", origin[0]); SetValueDouble(YSlicePlaneOriginTag, "", origin[1]); SetValueDouble(ZSlicePlaneOriginTag, "", origin[2]); SetValueDouble(SampleRateTag, "", 200); SetValueDouble(SlicePlaneNormalZTag, "", 0); SetValueDouble(SlicePlaneNormalYTag, "", 0); SetValueDouble(SlicePlaneNormalZTag, "", 1); SetValueLong(SlicePlaneOrientationModeTag, "", (int)SlicePlaneOrientationMode::Rotation); return (true); } ================================================ FILE: lib/params/SettingsParams.cpp ================================================ //************************************************************************ // * // Copyright (C) 2015 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: SettingsParams.cpp // // Author: Scott Pearse // Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: June 2015 // // Description: Implements the SettingsParams class. // This class supports parameters associted with the // initial VAPOR settings settings // #ifdef WIN32 // Annoying unreferenced formal parameter warning #pragma warning(disable : 4100) #endif #include #include #include #include #include #include #include using namespace VAPoR; using namespace Wasp; const string SettingsParams::_classType = "SettingsParams"; const string SettingsParams::_shortName = "Settings"; const string SettingsParams::_cacheMBTag = "CacheMBs"; const string SettingsParams::_numThreadsTag = "NumThreads"; const string SettingsParams::_texSizeTag = "TexSize"; const string SettingsParams::_texSizeEnableTag = "TexSizeEnabled"; const string SettingsParams::_sessionDirTag = "SessionDir"; const string SettingsParams::_defaultSessionDirTag = "SessionDir"; const string SettingsParams::_metadataDirTag = "MetadataDir"; const string SettingsParams::_defaultMetadataDirTag = "MetadataDir"; const string SettingsParams::_tfDirTag = "TFDir"; const string SettingsParams::_defaultTfDirTag = "TFDir"; const string SettingsParams::_flowDirTag = "FlowDir"; const string SettingsParams::_defaultFlowDirTag = "FlowDir"; const string SettingsParams::_pythonDirTag = "PythonDir"; const string SettingsParams::_defaultPythonDirTag = "PythonDir"; const string SettingsParams::_currentPrefsPathTag = "CurrentPrefsPath"; const string SettingsParams::_fidelityDefault2DTag = "Fidelity2DDefault"; const string SettingsParams::_fidelityDefault3DTag = "Fidelity3DDefault"; const string SettingsParams::_autoStretchTag = "AutoStretch"; const string SettingsParams::_jpegQualityTag = "JpegImageQuality"; const string SettingsParams::_changesPerAutoSaveTag = "ChangesPerAutoSave"; const string SettingsParams::_autoSaveFileLocationTag = "AutoSaveFileLocation"; const string SettingsParams::_defaultAutoSaveFileTag = "DefaultAutoSaveFile"; const string SettingsParams::_sessionAutoSaveEnabledTag = "AutoSaveEnabled"; const string SettingsParams::_fontFileTag = "FontFile"; const string SettingsParams::_fontSizeTag = "FontSize"; const string SettingsParams::_dontShowIntelDriverWarningTag = "DontShowIntelDriverWarning"; const string SettingsParams::_settingsNeedsWriteTag = "SettingsNeedsWrite"; const string SettingsParams::UseAllCoresTag = "UseAllCoresTag"; const string SettingsParams::AutoCheckForUpdatesTag = "AutoCheckForUpdatesTag"; const string SettingsParams::AutoCheckForNoticesTag = "AutoCheckForNoticesTag"; const string SettingsParams::CasperVGLCheck = "CasperVGLCheck"; // // Register class with object factory!!! // static ParamsRegistrar registrar(SettingsParams::GetClassType()); namespace { string SettingsFile = ".vapor3_settings"; const size_t defaultCacheSize = 0; } // namespace SettingsParams::SettingsParams(ParamsBase::StateSave *ssave, bool loadFromFile) : ParamsBase(ssave, _classType) { _settingsPath = FileUtils::JoinPaths({FileUtils::HomeDir(), SettingsFile}); // Try to get settings params from .settings file // if (loadFromFile) { bool ok = LoadFromSettingsFile(); if (ok) return; } Init(); } SettingsParams::SettingsParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) { _settingsPath = FileUtils::JoinPaths({FileUtils::HomeDir(), SettingsFile}); // If node isn't tagged correctly we correct the tag and reinitialize // from scratch; // if (node->GetTag() != SettingsParams::GetClassType()) { node->SetTag(SettingsParams::GetClassType()); // Try to get settings params from .settings file // bool ok = LoadFromSettingsFile(); if (ok) return; else Init(); } } SettingsParams::SettingsParams(const SettingsParams &rhs) : ParamsBase(new ParamsBase::StateSave, _classType) { _settingsPath = FileUtils::JoinPaths({FileUtils::HomeDir(), SettingsFile}); Init(); } SettingsParams &SettingsParams::operator=(const SettingsParams &rhs) { ParamsBase::operator=(rhs); _settingsPath = FileUtils::JoinPaths({FileUtils::HomeDir(), SettingsFile}); return (*this); } void SettingsParams::Reinit() { Init(); } SettingsParams::~SettingsParams() {} void SettingsParams::_swapTildeWithHome(std::string &file) const { size_t pos = 0; while ((pos = file.find("~", pos)) != std::string::npos) { file.replace(pos, 1, FileUtils::HomeDir()); pos += FileUtils::HomeDir().length(); } } long SettingsParams::GetCacheMB() const { long val = GetValueLong(_cacheMBTag, 0); if (val < 0) val = defaultCacheSize; return (val); } void SettingsParams::SetCacheMB(long val) { if (val < 0) val = defaultCacheSize; SetValueLong(_cacheMBTag, "Set cache size", val); } long SettingsParams::GetTextureSize() const { long val = GetValueLong(_texSizeTag, 0); if (val < 0) val = 0; return (val); } void SettingsParams::SetTextureSize(long val) { if (val < 0) val = 0; SetValueLong(_texSizeTag, "Set graphic tex size", val); } void SettingsParams::SetTexSizeEnable(bool val) { SetValueLong(_texSizeEnableTag, "toggle enable texture size", (long)val); } bool SettingsParams::GetTexSizeEnable() const { return (0 != GetValueLong(_texSizeEnableTag, (long)0)); } bool SettingsParams::GetAutoStretchEnabled() const { return (0 != GetValueLong(_autoStretchTag, (long)true)); } void SettingsParams::SetAutoStretchEnabled(bool val) { SetValueLong(_autoStretchTag, "Enable Auto Stretch", val); } int SettingsParams::GetJpegQuality() const { int quality = (int)GetValueDouble(_jpegQualityTag, 100.f); return quality; } void SettingsParams::SetJpegQuality(int quality) { string description = "Specify the quality of JPEG screen captures"; SetValueDouble(_jpegQualityTag, description, quality); } bool SettingsParams::GetSessionAutoSaveEnabled() const { double enabled = GetValueLong(_sessionAutoSaveEnabledTag, 1); if (enabled > 0) return true; else return false; } void SettingsParams::SetSessionAutoSaveEnabled(bool enabled) { string description = "Enable/disable auto save of session files"; SetValueLong(_sessionAutoSaveEnabledTag, description, (long)enabled); } int SettingsParams::GetChangesPerAutoSave() const { int changes = (int)GetValueLong(_changesPerAutoSaveTag, 5); return changes; } void SettingsParams::SetChangesPerAutoSave(int count) { if (count < 0) count = 5; string description = "User changes before auto saving session file"; SetValueLong(_changesPerAutoSaveTag, description, count); } string SettingsParams::GetAutoSaveSessionFile() const { string autoSaveDir = FileUtils::HomeDir(); string defaultFile = autoSaveDir + "/VaporAutoSave.vs3"; string file = GetValueString(_autoSaveFileLocationTag, defaultFile); _swapTildeWithHome(file); return file; } void SettingsParams::SetAutoSaveSessionFile(string file) { string description = "Session auto-save file location"; SetValueString(_autoSaveFileLocationTag, description, file); } string SettingsParams::GetSessionDir() const { string defaultDir = GetDefaultSessionDir(); string dir = GetValueString(_sessionDirTag, defaultDir); _swapTildeWithHome(dir); return (dir); } void SettingsParams::SetSessionDir(string name) { SetValueString(_sessionDirTag, "Set session directory", name); } string SettingsParams::GetDefaultSessionDir() const { string dir = GetValueString(_defaultSessionDirTag, string(".")); _swapTildeWithHome(dir); return (dir); } void SettingsParams::SetDefaultAutoSaveFile(string autoSaveFile) { string description = "Set default auto-save session directory"; SetValueString(_defaultAutoSaveFileTag, description, autoSaveFile); } void SettingsParams::SetDefaultSessionDir(string name) { string description = "Set default session directory"; SetValueString(_defaultSessionDirTag, description, name); } string SettingsParams::GetMetadataDir() const { string defaultDir = GetDefaultMetadataDir(); string dir = GetValueString(_metadataDirTag, defaultDir); _swapTildeWithHome(dir); return (dir); } void SettingsParams::SetMetadataDir(string dir) { SetValueString(_metadataDirTag, "set metadata directory", dir); } string SettingsParams::GetDefaultMetadataDir() const { string dir = GetValueString(_defaultMetadataDirTag, string(".")); _swapTildeWithHome(dir); return (dir); } void SettingsParams::SetDefaultMetadataDir(string dir) { string description = "set default metadata directory"; SetValueString(_defaultMetadataDirTag, description, dir); } string SettingsParams::GetTFDir() const { string defaultDir = GetDefaultTFDir(); string dir = GetValueString(_tfDirTag, defaultDir); _swapTildeWithHome(dir); return (dir); } void SettingsParams::SetTFDir(string dir) { SetValueString(_tfDirTag, "set trans function directory", dir); } string SettingsParams::GetDefaultTFDir() const { string dir = GetValueString(_defaultTfDirTag, string("")); _swapTildeWithHome(dir); return (dir); } void SettingsParams::SetDefaultTFDir(string dir) { string description = "set default trans function directory"; SetValueString(_defaultTfDirTag, description, dir); } string SettingsParams::GetFlowDir() const { string defaultDir = GetDefaultFlowDir(); string dir = GetValueString(_flowDirTag, defaultDir); _swapTildeWithHome(dir); return (dir); } void SettingsParams::SetFlowDir(string dir) { SetValueString(_flowDirTag, "set flow save directory", dir); } string SettingsParams::GetDefaultFlowDir() const { string dir = GetValueString(_defaultFlowDirTag, string(".")); _swapTildeWithHome(dir); return (dir); } void SettingsParams::SetDefaultFlowDir(string dir) { SetValueString(_defaultFlowDirTag, "set default flow save directory", dir); } string SettingsParams::GetPythonDir() const { string defaultDir = GetDefaultPythonDir(); string dir = GetValueString(_pythonDirTag, defaultDir); _swapTildeWithHome(dir); return (dir); } void SettingsParams::SetPythonDir(string dir) { SetValueString(_pythonDirTag, "set python directory", dir); } string SettingsParams::GetDefaultPythonDir() const { string dir = GetValueString(_defaultPythonDirTag, string(".")); _swapTildeWithHome(dir); return (dir); } void SettingsParams::SetDefaultPythonDir(string dir) { SetValueString(_defaultPythonDirTag, "set default python directory", dir); } string SettingsParams::GetCurrentPrefsPath() const { string defaultv = "/tmp/.vapor3_prefs"; return GetValueString(_currentPrefsPathTag, defaultv); } void SettingsParams::SetCurrentPrefsPath(string pth) { SetValueString(_currentPrefsPathTag, "set current preference path", pth); } int SettingsParams::GetNumThreads() const { if (GetValueLong(UseAllCoresTag, true)) { return 0; } long val = GetValueLong(_numThreadsTag, 0); val = val >= 0 ? val : 0; return ((int)val); } void SettingsParams::SetNumThreads(int val) { SetValueLong(_numThreadsTag, "Number of execution threads", val); } int SettingsParams::GetFontSize() const { return 24; } void SettingsParams::SetFontSize(int size) {} string SettingsParams::GetFontFile() const { return ""; } void SettingsParams::SetFontFile(string file) {} bool SettingsParams::GetDontShowIntelDriverWarning() const { return GetValueLong(_dontShowIntelDriverWarningTag, false); } void SettingsParams::SetDontShowIntelDriverWarning(bool b) { SetValueLong(_dontShowIntelDriverWarningTag, "Hide Intel driver warning", b); } void SettingsParams::SetFidelityDefault3D(long lodDef, long refDef) { vector val; val.push_back(lodDef); val.push_back(refDef); SetValueLongVec(_fidelityDefault3DTag, "Set fidelity 3D default", val); } void SettingsParams::SetFidelityDefault2D(long lodDef, long refDef) { vector val; val.push_back(lodDef); val.push_back(refDef); SetValueLongVec(_fidelityDefault2DTag, "Set fidelity 2D default", val); } void SettingsParams::SetAutoCheckForUpdates(bool b) { SetValueLong(AutoCheckForUpdatesTag, "", b); } bool SettingsParams::GetAutoCheckForUpdates() const { return GetValueLong(AutoCheckForUpdatesTag, true); } void SettingsParams::SetAutoCheckForNotices(bool b) { SetValueLong(AutoCheckForNoticesTag, "", b); } bool SettingsParams::GetAutoCheckForNotices() const { return GetValueLong(AutoCheckForNoticesTag, true); } void SettingsParams::SetCasperCheckForVGL(bool b) { SetValueLong(CasperVGLCheck, "", b); } bool SettingsParams::GetCasperCheckForVGL() const { return GetValueLong(CasperVGLCheck, true); } bool SettingsParams::LoadFromSettingsFile() { XmlNode *node = GetNode(); VAssert(node != NULL); bool enabled = MyBase::GetEnableErrMsg(); MyBase::EnableErrMsg(false); XmlParser xmlparser; int rc = xmlparser.LoadFromFile(node, _settingsPath); bool status = rc >= 0; MyBase::EnableErrMsg(enabled); return status; } void SettingsParams::FindDefaultSettingsPath() { string prefPath; string preffile = #ifdef WIN32 "\\.vapor3_prefs"; #else "/.vapor3_prefs"; #endif char *pPath = getenv("VAPOR3_PREFS_DIR"); if (!pPath) pPath = getenv("HOME"); if (!pPath) { vector tpath; tpath.push_back("examples"); tpath.push_back(preffile); prefPath = GetSharePath("examples/" + preffile); } else { prefPath = string(pPath) + preffile; } SetCurrentPrefsPath(prefPath); } int SettingsParams::SaveSettings() const { ofstream fileout; string s; fileout.open(_settingsPath.c_str()); if (!fileout) { MyBase::SetErrMsg("Unable to open output settings file %s : %M", _settingsPath.c_str()); return (-1); } const XmlNode *node = GetNode(); XmlNode::streamOut(fileout, *node); if (fileout.bad()) { MyBase::SetErrMsg("Unable to open output settings file %s : %M", _settingsPath.c_str()); return (-1); } fileout.close(); return (0); } // Reset settings settings to initial state void SettingsParams::Init() { SetSessionAutoSaveEnabled(true); SetChangesPerAutoSave(5); std::string homeDir = FileUtils::HomeDir(); SetAutoSaveSessionFile(homeDir + "/VaporAutoSave.vs3"); SetAutoStretchEnabled(true); SetValueLong(UseAllCoresTag, "", true); SetValueLong(AutoCheckForUpdatesTag, "", true); SetValueLong(AutoCheckForNoticesTag, "", true); SetNumThreads(4); SetCacheMB(defaultCacheSize); SetDefaultSessionDir(string(homeDir)); SetDefaultMetadataDir(string(homeDir)); SetDefaultFlowDir(string(homeDir)); string palettes = GetSharePath("palettes"); SetDefaultTFDir(string(palettes)); string python = GetPythonDir(); SetDefaultPythonDir(string(python)); } std::string SettingsParams::GetSettingsPath() const { return _settingsPath; } ================================================ FILE: lib/params/SliceParams.cpp ================================================ #include #include #include using namespace Wasp; using namespace VAPoR; #define THREED 3 #define X 0 #define Y 1 #define Z 2 #define XY 0 #define XZ 1 #define YZ 2 #define DEFAULT_SAMPLERATE 200 // // Register class with object factory!!! // static RenParamsRegistrar registrar(SliceParams::GetClassType()); SliceParams::SliceParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, SliceParams::GetClassType(), THREED) { SetDiagMsg("SliceParams::SliceParams() this=%p", this); _cachedValues.clear(); _init(); } SliceParams::SliceParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node, THREED) { _initialized = true; } SliceParams::~SliceParams() { SetDiagMsg("SliceParams::~SliceParams() this=%p", this); } void SliceParams::_init() { SetDiagMsg("SliceParams::_init()"); SetFieldVariableNames(vector()); } int SliceParams::Initialize() { int rc = RenderParams::Initialize(); if (rc < 0) return (rc); if (_initialized) return 0; _initialized = true; Box *box = GetBox(); box->SetOrientation(Box::XYZ); std::vector minExt, maxExt; box->GetExtents(minExt, maxExt); std::vector sampleLocation(3); for (int i = 0; i < 3; i++) sampleLocation[i] = (minExt[i] + maxExt[i]) / 2.0; SetValueDouble(RenderParams::XSlicePlaneOriginTag, "", sampleLocation[0]); SetValueDouble(RenderParams::YSlicePlaneOriginTag, "", sampleLocation[1]); SetValueDouble(RenderParams::ZSlicePlaneOriginTag, "", sampleLocation[2]); SetValueDouble(RenderParams::SampleRateTag, "", DEFAULT_SAMPLERATE); return (0); } void SliceParams::SetCachedValues(std::vector values) { _cachedValues.clear(); _cachedValues = values; } std::vector SliceParams::GetCachedValues() const { return _cachedValues; } bool SliceParams::GetOrientable() const { return true; } ================================================ FILE: lib/params/TFInterpolator.cpp ================================================ //************************************************************************ // Copyright (C) 2004 // University Corporation for Atmospheric Research // All Rights Reserved //************************************************************************/ // // File: TFInterpolator.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: November 2004 // // Description: Implements the TFInterpolator class: // A class to interpolate transfer function values // Currently only supports linear interpolation // #include #include "vapor/VAssert.h" #include #include using namespace std; using namespace VAPoR; #ifdef WIN32 #ifndef NAN static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff}; #define NAN (*(const float *)__nan) #endif #endif float TFInterpolator::Xn = 95.047; float TFInterpolator::Yn = 100.0; float TFInterpolator::Zn = 108.883; float TFInterpolator::XYZtransferMatrix[9] = {0.4124564, 0.2126729, 0.0193339, 0.3575761, 0.7151522, 0.1191920, 0.1804375, 0.0721750, 0.9503041}; float TFInterpolator::XYZinverseMatrix[9] = {3.2404548360214087, -0.9692663898756537, 0.05564341960421365, -1.5371388501025751, 1.876010928842491, -0.20402585426769812, -0.4985315468684809, 0.04155608234667354, 1.0572251624579287}; float *TFInterpolator::colorMap = NULL; TFInterpolator::~TFInterpolator() { if (colorMap) delete colorMap; } // Determine the interpolated value at intermediate value 0<=r<=1 // where the value at left and right endpoint is known // This method is just a stand-in until we get more sophistication // float TFInterpolator::interpolate(TFInterpolator::type t, float leftVal, float rightVal, float r) { if (t == TFInterpolator::discrete) { if (r < 0.5) return leftVal; else return rightVal; } float val = (float)(leftVal * (1. - r) + r * rightVal); // if (val < 0.f || val > 1.f){ // VAssert(val <= 1.f && val >= 0.f); //} return val; } float TFInterpolator::interpCirc(type t, float leftVal, float rightVal, float r) { if (t == TFInterpolator::discrete) { if (r < 0.5) return leftVal; else return rightVal; } if (fabs(rightVal - leftVal) <= 0.5f) return interpolate(t, leftVal, rightVal, r); // replace smaller by 1+smaller, interpolate, then fit back into interval // float interpVal; if (leftVal <= rightVal) { interpVal = interpolate(t, leftVal + 1.f, rightVal, r); } else interpVal = interpolate(t, leftVal, rightVal + 1.f, r); if (interpVal >= 1.f) interpVal -= 1.f; if (interpVal < 0.f || interpVal > 1.f) { VAssert(interpVal <= 1.f && interpVal >= 0.f); } return interpVal; } float *TFInterpolator::genDivergentMap(float rgb1[3], float rgb2[3], int numColors) { float interp; float color[3]; float *colorMap1 = new float[numColors * 3]; for (float i = 0; i < (float)numColors; i++) { interp = (float)i / (float)numColors; divergentInterpolation(rgb1, rgb2, color, interp); colorMap1[(int)i * 3] = color[0]; colorMap1[(int)i * 3 + 1] = color[1]; colorMap1[(int)i * 3 + 2] = color[2]; } return colorMap1; } void TFInterpolator::correctiveDivergentInterpolation(float rgb1[3], float rgb2[3], float output[3], float interp) { divergentInterpolation(rgb1, rgb2, output, interp, true); } int TFInterpolator::divergentInterpolation(float rgb1[3], float rgb2[3], float output[3], float interp, bool corrective) { interp = 1 - interp; static float msh1[3], msh2[3], mshMid[3]; float m1, s1, h1; float m2, s2, h2; srgb2msh(rgb1, msh1); m1 = msh1[0]; s1 = msh1[1]; h1 = msh1[2]; srgb2msh(rgb2, msh2); m2 = msh2[0]; s2 = msh2[1]; h2 = msh2[2]; // If pohsv[1] are saturated and distinct, place white in the middle if (corrective) { if ((s1 > 0.05) && (s2 > .05) && (fabs(h1 - h2) > (3.1415 / 3.0))) { float Mmid; if ((m1 > m2) && (m1 > 88.f)) Mmid = m1; else if ((m2 > m1) && (m2 > 88.f)) Mmid = m2; else Mmid = 88.f; if (interp < 0.5) { m2 = Mmid; s2 = 0.0; h2 = 0.0; interp = 2 * interp; } else { m1 = Mmid; s1 = 0.0; h1 = 0.0; interp = 2 * interp - 1; } } } // Adjust hue of unsaturated colors if ((s1 < 0.05) && (s2 > 0.05)) h1 = adjustHue(m2, s2, h2, m1); else if ((s2 < 0.05) && (s1 > 0.05)) h2 = adjustHue(m1, s1, h1, m2); mshMid[0] = (1 - interp) * m1 + interp * m2; mshMid[1] = (1 - interp) * s1 + interp * s2; mshMid[2] = (1 - interp) * h1 + interp * h2; msh2srgb(mshMid, output); // Clip colors that are out of bounds float maxVal = output[0]; if (maxVal < output[1]) maxVal = output[1]; if (maxVal < output[2]) maxVal = output[2]; if (maxVal > 255.0) { output[0] = output[0] * 255.0 / maxVal; output[1] = output[1] * 255.0 / maxVal; output[2] = output[2] * 255.0 / maxVal; } if (output[0] < 0) output[0] = 0.0; if (output[1] < 0) output[1] = 0.0; if (output[2] < 0) output[2] = 0.0; return 0; } float TFInterpolator::adjustHue(float m, float s, float h, float mUnsat) { if (m >= mUnsat - .1) return h; // mUnsat; else { float hSpin; hSpin = s * sqrt(pow(mUnsat, 2.f) - pow(m, 2.f)) / (m * sin(s)); if (h > (-3.14159 / 3)) return h + hSpin; else return h - hSpin; } } int TFInterpolator::msh2srgb(float msh[3], float rgb[3]) { static float lab[3]; msh2lab(msh, lab); lab2srgb(lab, rgb); return 0; } int TFInterpolator::msh2lab(float msh[3], float lab[3]) { float l, a, b; float m = msh[0]; float s = msh[1]; float h = msh[2]; l = m * cos(s); a = m * sin(s) * cos(h); b = m * sin(s) * sin(h); lab[0] = l; lab[1] = a; lab[2] = b; return 0; } float lab2srgbHelper(float val) { float xlim = 0.008856; float a = 7.787; float b = 16.f / 116.f; float ylim = a * xlim + b; if (val > ylim) { return pow(val, 3); } else { return (val - b) / a; } } void LabToXYZ(double L, double a, double b, double *x, double *y, double *z) { // LAB to XYZ double var_Y = (L + 16) / 116; double var_X = a / 500 + var_Y; double var_Z = var_Y - b / 200; if (pow(var_Y, 3) > 0.008856) var_Y = pow(var_Y, 3); else var_Y = (var_Y - 16.0 / 116.0) / 7.787; if (pow(var_X, 3) > 0.008856) var_X = pow(var_X, 3); else var_X = (var_X - 16.0 / 116.0) / 7.787; if (pow(var_Z, 3) > 0.008856) var_Z = pow(var_Z, 3); else var_Z = (var_Z - 16.0 / 116.0) / 7.787; const double ref_X = 0.9505; const double ref_Y = 1.000; const double ref_Z = 1.089; *x = ref_X * var_X; // ref_X = 0.9505 Observer= 2 deg Illuminant= D65 *y = ref_Y * var_Y; // ref_Y = 1.000 *z = ref_Z * var_Z; // ref_Z = 1.089 } int TFInterpolator::lab2srgb(float lab[3], float rgb[3]) { static float xyz[3]; float x, y, z; float l = lab[0]; float a = lab[1]; float b = lab[2]; x = Xn * lab2srgbHelper((a / 500.f) + (l + 16.f) / (116.f)); y = Yn * lab2srgbHelper((l + 16.f) / 116.f); z = Zn * lab2srgbHelper((l + 16.f) / 116.f - (b / 200.f)); xyz[0] = x; xyz[1] = y; xyz[2] = z; TFInterpolator::xyz2srgb(xyz, rgb); return 0; } int TFInterpolator::srgb2msh(float rgb[3], float msh[3]) { static float lab[3]; srgb2lab(rgb, lab); lab2msh(lab, msh); return 0; } int TFInterpolator::lab2msh(float lab[3], float msh[3]) { float m, s, h; float l = lab[0]; float a = lab[1]; float b = lab[2]; m = sqrt(pow(l, 2) + pow(a, 2) + pow(b, 2)); s = acos(l / m); h = atan2(b, a); msh[0] = m; msh[1] = s; msh[2] = h; return 0; } float srgb2labHelper(float val) { float limit = 0.008856; if (val > limit) return pow(val, (float)(1.0 / 3.0)); else return 7.787 * val + 16.0 / 116.0; } int TFInterpolator::srgb2lab(float rgb[3], float lab[3]) { float l, a, b; static float xyz[3]; static float srgb[3]; // Newly added! rgb2srgb(rgb, srgb); srgb2xyz(rgb, xyz); // srgb2xyz(rgb,xyz); float x = xyz[0]; float y = xyz[1]; float z = xyz[2]; l = 116.0 * (srgb2labHelper(y / Yn) - 16.0 / 116.0); a = 500.0 * (srgb2labHelper(x / Xn) - srgb2labHelper(y / Yn)); b = 200.0 * (srgb2labHelper(y / Yn) - srgb2labHelper(z / Zn)); lab[0] = l; lab[1] = a; lab[2] = b; return 0; } int TFInterpolator::xyz2srgb(float xyz[3], float srgb[3]) { float r, g, b; float rgb[3]; float x = xyz[0]; float y = xyz[1]; float z = xyz[2]; r = x * XYZinverseMatrix[0] + y * XYZinverseMatrix[3] + z * XYZinverseMatrix[6]; g = x * XYZinverseMatrix[1] + y * XYZinverseMatrix[4] + z * XYZinverseMatrix[7]; b = x * XYZinverseMatrix[2] + y * XYZinverseMatrix[5] + z * XYZinverseMatrix[8]; rgb[0] = r; rgb[1] = g; rgb[2] = b; rgb2srgb(rgb, srgb); r = srgb[0]; g = srgb[1]; b = srgb[2]; return 0; } int TFInterpolator::rgb2srgb(float rgb[3], float srgb[3]) { float val; for (int i = 0; i < 3; i++) { val = rgb[i] / 100.0; if (val > 0.00313080495356037152) val = (1.055 * pow(val, (float)(1.0 / 2.4)) - .055); else val = val * 12.92; val = val * 255.0; // if ((val-floor(val)) > .5) val = ceil(val); // else val = floor(val); srgb[i] = val; } /* Clip colors that are out of bounds float maxVal = srgb[0]; if (maxVal < srgb[1]) maxVal = srgb[1]; if (maxVal < srgb[2]) maxVal = srgb[2]; cout << maxVal << endl; if (maxVal > 255.0) { cout << "Correcting by " << maxVal << endl; srgb[0] /= maxVal; srgb[1] /= maxVal; srgb[2] /= maxVal; } if (srgb[0]<0) srgb[0]=0; if (srgb[1]<0) srgb[1]=0; if (srgb[2]<0) srgb[2]=0;*/ return 0; } int TFInterpolator::srgb2rgb(float srgb[3], float rgb[3]) { float val; for (int i = 0; i < 3; i++) { val = srgb[i] / 255.0; if (val > 0.04045) { val = pow(((val + 0.055) / 1.055), 2.4); } else { val = val / 12.92; } rgb[i] = val * 100; } /* Clip colors that are out of bounds double maxVal = rgb[0]; if (maxVal < rgb[1]) maxVal = rgb[1]; if (maxVal < rgb[2]) maxVal = rgb[2]; cout << maxVal << endl; if (maxVal > 100.0) { cout << "Correcting by " << maxVal << endl; rgb[0] /= maxVal; rgb[1] /= maxVal; rgb[2] /= maxVal; } if (rgb[0]<0) rgb[0]=0; if (rgb[1]<0) rgb[1]=0; if (rgb[2]<0) rgb[2]=0;*/ return 0; } int TFInterpolator::srgb2xyz(float rgb[3], float xyz[3]) { float linearRGB[3]; float x, y, z, r, g, b; srgb2rgb(rgb, linearRGB); r = linearRGB[0]; g = linearRGB[1]; b = linearRGB[2]; x = r * XYZtransferMatrix[0] + g * XYZtransferMatrix[3] + b * XYZtransferMatrix[6]; y = r * XYZtransferMatrix[1] + g * XYZtransferMatrix[4] + b * XYZtransferMatrix[7]; z = r * XYZtransferMatrix[2] + g * XYZtransferMatrix[5] + b * XYZtransferMatrix[8]; xyz[0] = x; xyz[1] = y; xyz[2] = z; return 0; } int TFInterpolator::rgb2hsv(float rgb[3], float hsv[3]) { // hsv out; double min, max, delta; min = rgb[0] < rgb[1] ? rgb[0] : rgb[1]; min = min < rgb[2] ? min : rgb[2]; max = rgb[0] > rgb[1] ? rgb[0] : rgb[1]; max = max > rgb[2] ? max : rgb[2]; hsv[2] = max; // 255.0; // v delta = max - min; if (delta < 0.00001) { hsv[1] = 0; hsv[0] = 0; // undefined, maybe nan? return 0; } if (max > 0.0) { // NOTE: if Max is == 0, this divide would cause a crash hsv[1] = (delta / max); // s } else { // if max is 0, then r = g = b = 0 // s = 0, v is undefined hsv[1] = 0.0; hsv[0] = NAN; // its now undefined return 0; } if (rgb[0] >= max) // > is bogus, just keeps compilor happy hsv[0] = (rgb[1] - rgb[2]) / delta; // between yellow & magenta else if (rgb[1] >= max) hsv[0] = 2.0 + (rgb[2] - rgb[0]) / delta; // between cyan & yellow else hsv[0] = 4.0 + (rgb[0] - rgb[1]) / delta; // between magenta & cyan hsv[0] *= 60.0; // degrees if (hsv[0] < 0.0) hsv[0] += 360.0; // hsv[0] = hsv[0]/360.0; return 0; } int TFInterpolator::hsv2rgb(float hsv[3], float rgb[3]) { double hh, p, q, t, ff; long i; // rgb out; hsv[0] = hsv[0] * 360.0; //*360.0;//2.0*3.14159; // scale to unit circle if (hsv[1] <= 0.0) { // < is bogus, just shuts up warnhsv[1] rgb[0] = hsv[2]; rgb[1] = hsv[2]; rgb[2] = hsv[2]; return 0; } hh = hsv[0]; if (hh >= 360.0) hh = 0.0; hh /= 60.0; i = (long)hh; ff = hh - i; p = hsv[2] * (1.0 - hsv[1]); q = hsv[2] * (1.0 - (hsv[1] * ff)); t = hsv[2] * (1.0 - (hsv[1] * (1.0 - ff))); switch (i) { case 0: rgb[0] = hsv[2]; rgb[1] = t; rgb[2] = p; break; case 1: rgb[0] = q; rgb[1] = hsv[2]; rgb[2] = p; break; case 2: rgb[0] = p; rgb[1] = hsv[2]; rgb[2] = t; break; case 3: rgb[0] = p; rgb[1] = q; rgb[2] = hsv[2]; break; case 4: rgb[0] = t; rgb[1] = p; rgb[2] = hsv[2]; break; case 5: default: rgb[0] = hsv[2]; rgb[1] = p; rgb[2] = q; break; } // rgb[0] = rgb[0]*255; // rgb[1] = rgb[1]*255; // rgb[2] = rgb[2]*255; return 0; } ================================================ FILE: lib/params/TODO.txt ================================================ Is params::restart() method needed? It sets params to default state when no data (i.e. datamgr) are present. Why not require data to be present before initializing render params? RenderParams should require a valid (non-NULL) data mgr, and should not have to handle cases where one does not exist. I.e. there should be no need for RenderParams::Valid(type==0) Remove deprecated constructors (or constructor arguments) from MapperFunction. e.g. nBits RenderParams ------------ + Should Set* functions all be made no-fail? I.e. return void and adjust inputs as necessary to provide a correct value when calling SetValueDouble, etc. + Move Barb specific stuff into Barb renderer (e.g. {Set,Get}Grid(), IsAlignedTo Data(), SetGridAlignStrides, etc). + How do get{Min,Max}EditBound() differ from MapperFunction::get{Min,Map}Value(). Ans: These methods are used purely for presentation within the GUI and should be moved out of the RenderParams class to one of the session state classes + RenderParams subclass instances appear to be created at applicaiton startup, and whenever a new session is created. These constructors are fired *before* data are loaded. However, when a new instance of a renderer is created (via the "New" button) another instance of the params class is created again. Destructors are also not being called properly. + No error handing performed for Set or Get methods. E.g. Setting RGB color to value outside 0..1.0, setting variable to name that doesn't exist, etc. How should these be handle? Ignore invalid values? Reconcile to valid value? etc. + Move common text stuff (e.g. font size, text type, precision) from isolineparams to RenderParams MISC ---- + Get/Set param acessors need validation has is done for isolineparams ================================================ FILE: lib/params/Transform.cpp ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: Transform.cpp // // Author: Scott Pearse // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: May 2017 // // Description: Implements the Transform class // This class contains the translation, rotation, and scale // parameters associated with a loaded data set // #ifdef WIN32 // Annoying unreferenced formal parameter warning #pragma warning(disable : 4100) #endif #include #include using namespace VAPoR; using namespace Wasp; const string Transform::_translationTag = "Translation"; const string Transform::_rotationTag = "Rotation"; const string Transform::_scaleTag = "Scale"; const string Transform::_originTag = "Origin"; const string Transform::_originInitializedTag = "OriginInitialized"; // // Register class with object factory!!! // static ParamsRegistrar registrar(Transform::GetClassType()); //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- Transform::Transform(ParamsBase::StateSave *ssave) : ParamsBase(ssave, Transform::GetClassType()) {} Transform::Transform(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {} //---------------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------------- Transform::~Transform() { MyBase::SetDiagMsg("Transform::~Transform() this=%p", this); } void Transform::SetScales(const vector scale) { SetValueDoubleVec(_scaleTag, "Set scale transform", scale); } vector Transform::GetOrigin() const { vector defaultv(3, 0.0); vector origin = GetValueDoubleVec(_originTag, defaultv); return origin; } void Transform::SetOrigin(const vector origin) { SetValueDoubleVec(_originTag, "Set origin for transforms", origin); SetOriginInitialized(true); } bool Transform::IsOriginInitialized() const { return GetValueLong(_originInitializedTag, false); } void Transform::SetOriginInitialized(bool value) { SetValueLong(_originInitializedTag, "Set is origin initialized for transforms", value); } ================================================ FILE: lib/params/TwoDDataParams.cpp ================================================ #include #include #include #include using namespace Wasp; using namespace VAPoR; // // Register class with object factory!!! // static RenParamsRegistrar registrar(TwoDDataParams::GetClassType()); TwoDDataParams::TwoDDataParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, TwoDDataParams::GetClassType(), 2) { SetDiagMsg("TwoDDataParams::TwoDDataParams() this=%p", this); _init(); } TwoDDataParams::TwoDDataParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node, 2) {} TwoDDataParams::~TwoDDataParams() { SetDiagMsg("TwoDDataParams::~TwoDDataParams() this=%p", this); } // Set everything to default values void TwoDDataParams::_init() { SetDiagMsg("TwoDDataParams::_init()"); // Necessary? // SetFieldVariableNames(vector()); } ================================================ FILE: lib/params/Viewpoint.cpp ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: Viewpoint.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: May 2005 // // Description: Implements the Viewpoint class // This class contains the parameters associated with one viewpoint // #ifdef WIN32 // Annoying unreferenced formal parameter warning #pragma warning(disable : 4100) #endif #include #include #define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH #include using namespace VAPoR; using namespace Wasp; const string Viewpoint::_modelViewMatrixTag = "ModelViewMatrix"; const string Viewpoint::_projectionMatrixTag = "ProjectionMatrix"; const string Viewpoint::_rotationCenterTag = "RotationCenter"; double Viewpoint::_defaultModelViewMatrix[] = {1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0}; double Viewpoint::_defaultProjectionMatrix[] = {1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0}; // // Register class with object factory!!! // static ParamsRegistrar registrar(Viewpoint::GetClassType()); //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- Viewpoint::Viewpoint(ParamsBase::StateSave *ssave) : ParamsBase(ssave, Viewpoint::GetClassType()) { _init(); } Viewpoint::Viewpoint(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {} //---------------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------------- Viewpoint::~Viewpoint() { MyBase::SetDiagMsg("Viewpoint::~Viewpoint() this=%p", this); } void Viewpoint::_init() { double proj[] = {1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0}; double modelview[] = {1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0}; SetProjectionMatrix(proj); SetModelViewMatrix(modelview); } void Viewpoint::GetModelViewMatrix(double m[16]) const { vector defaultv; for (int i = 0; i < 16; i++) defaultv.push_back(_defaultModelViewMatrix[i]); vector val = GetValueDoubleVec(_modelViewMatrixTag, defaultv); VAssert(val.size() == 16); for (int i = 0; i < val.size(); i++) m[i] = val[i]; } void Viewpoint::SetModelViewMatrix(const double m[16]) { vector val; for (int i = 0; i < 16; i++) val.push_back(m[i]); #ifdef VAPOR3_0_0_ALPHA for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++) { cout << m[j * 4 + i] << " "; } cout << endl; } cout << endl; #endif SetValueDoubleVec(_modelViewMatrixTag, "Model view matrix", val); } void Viewpoint::GetProjectionMatrix(double m[16]) const { vector defaultv; for (int i = 0; i < 16; i++) defaultv.push_back(_defaultProjectionMatrix[i]); vector val = GetValueDoubleVec(_projectionMatrixTag, defaultv); VAssert(val.size() == 16); for (int i = 0; i < val.size(); i++) m[i] = val[i]; } void Viewpoint::SetProjectionMatrix(const double m[16]) { vector val; for (int i = 0; i < 16; i++) val.push_back(m[i]); SetValueDoubleVec(_projectionMatrixTag, "Projection matrix", val); } bool Viewpoint::ReconstructCamera(const double m[16], double position[3], double upVec[3], double viewDir[3]) const { double minv[16]; int rc = minvert((double *)m, minv); if (rc < 0) return (false); vscale(minv + 8, -1.0); for (int i = 0; i < 3; i++) { position[i] = minv[12 + i]; // position vector is minv[12..14] upVec[i] = minv[4 + i]; // up vector is minv[4..6] viewDir[i] = minv[8 + i]; // view direction is minv[8..10] } vnormal(upVec); vnormal(viewDir); return (true); } ================================================ FILE: lib/params/ViewpointParams.cpp ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: ViewpointParams.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: August 2004 // // Description: Implements the ViewpointParams class // This class contains the parameters associated with viewpoint and lights // #ifdef WIN32 // Annoying unreferenced formal parameter warning #pragma warning(disable : 4100) #endif #include #include #include double VAPoR::ViewpointParams::_defaultLightDirection[3][4] = {{0.f, 0.f, 1.f, 0.f}, {0.f, 1.f, 0.f, 0.f}, {1.f, 0.f, 0.f, 0.f}}; int VAPoR::ViewpointParams::_defaultNumLights = 1; double VAPoR::ViewpointParams::_defaultDiffuseCoeff[3] = {0.8f, 0.8f, 0.8f}; double VAPoR::ViewpointParams::_defaultSpecularCoeff[3] = {0.3f, 0.3f, 0.3f}; double VAPoR::ViewpointParams::_defaultAmbientCoeff = 0.1f; double VAPoR::ViewpointParams::_defaultSpecularExp = 20.f; using namespace VAPoR; using namespace Wasp; const string ViewpointParams::UseCustomFramebufferTag = "UseCustomFramebuffer"; const string ViewpointParams::CustomFramebufferWidthTag = "CustomFramebufferWidth"; const string ViewpointParams::CustomFramebufferHeightTag = "CustomFramebufferHeight"; const string ViewpointParams::_viewPointsTag = "Viewpoints"; const string ViewpointParams::_transformsTag = "Transforms"; const string ViewpointParams::_currentViewTag = "CurrentViewpoint"; const string ViewpointParams::_lightDirectionsTag = "LightDirections"; const string ViewpointParams::_diffuseCoeffTag = "DiffuseCoefficients"; const string ViewpointParams::_specularCoeffTag = "SpecularCoefficients"; const string ViewpointParams::_specularExpTag = "SpecularExponent"; const string ViewpointParams::_ambientCoeffTag = "AmbientCoefficient"; const string ViewpointParams::_numLightsTag = "NumLights"; const string ViewpointParams::m_windowSizeTag = "WindowSize"; const string ViewpointParams::m_stretchFactorsTag = "StretchFactors"; const string ViewpointParams::m_fieldOfView = "FieldOfView"; const string ViewpointParams::_orthoProjectionSizeTag = "OrthoProjectionSize"; const string ViewpointParams::_projectionTypeTag = "ProjectionType"; //---------------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------------- ViewpointParams::ViewpointParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, ViewpointParams::GetClassType()) { _init(); m_VPs = new ParamsContainer(ssave, _viewPointsTag); m_VPs->SetParent(this); Viewpoint currentVP(ssave); m_VPs->Insert(¤tVP, _currentViewTag); _transforms = new ParamsContainer(ssave, _transformsTag); _transforms->SetParent(this); } ViewpointParams::ViewpointParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) { if (node->HasChild(_viewPointsTag)) { m_VPs = new ParamsContainer(ssave, node->GetChild(_viewPointsTag)); } else { // Node doesn't contain a viewpoint container // m_VPs = new ParamsContainer(ssave, _viewPointsTag); m_VPs->SetParent(this); } if (node->HasChild(_transformsTag)) { _transforms = new ParamsContainer(ssave, node->GetChild(_transformsTag)); } else { // Node doesn't contain a transforms container // _transforms = new ParamsContainer(ssave, _transformsTag); _transforms->SetParent(this); } } ViewpointParams::ViewpointParams(const ViewpointParams &rhs) : ParamsBase(rhs) { m_VPs = new ParamsContainer(*(rhs.m_VPs)); _transforms = new ParamsContainer(*(rhs._transforms)); } ViewpointParams &ViewpointParams::operator=(const ViewpointParams &rhs) { if (m_VPs) delete m_VPs; if (_transforms) delete _transforms; // Note: the following assign operation has to happen AFTER destroying // _transforms 2 lines above. Otherwise, memory error will occur. ParamsBase::operator=(rhs); m_VPs = new ParamsContainer(*(rhs.m_VPs)); _transforms = new ParamsContainer(*(rhs._transforms)); return (*this); } //---------------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------------- ViewpointParams::~ViewpointParams() { MyBase::SetDiagMsg("ViewpointParams::~ViewpointParams() this=%p", this); if (m_VPs) { delete m_VPs; m_VPs = NULL; } if (_transforms) { delete _transforms; _transforms = NULL; } } // Reinitialize viewpoint settings, to center view on the center of full region. //(this is starting state) void ViewpointParams::_init() { setNumLights(_defaultNumLights); setExponent(_defaultSpecularExp); setAmbientCoeff(_defaultAmbientCoeff); for (int i = 0; i < 3; i++) { setDiffuseCoeff(i, _defaultDiffuseCoeff[i]); } for (int i = 0; i < 3; i++) { setSpecularCoeff(i, _defaultSpecularCoeff[i]); } for (int light = 0; light < 3; light++) { for (int i = 0; i < 4; i++) { setLightDirection(light, i, _defaultLightDirection[light][i]); } } // SetStretchFactors(vector (3,1.0)); SetWindowSize(100, 100); SetValueLong(UseCustomFramebufferTag, UseCustomFramebufferTag, false); SetValueLong(CustomFramebufferWidthTag, CustomFramebufferWidthTag, 1920); SetValueLong(CustomFramebufferHeightTag, CustomFramebufferHeightTag, 1080); } Transform *ViewpointParams::GetTransform(string dataSetName) { if (_transforms->GetParams(dataSetName) == NULL) { bool enabled = _ssave->GetEnabled(); _ssave->SetEnabled(false); Transform newTransform(_ssave); _transforms->Insert(&newTransform, dataSetName); _ssave->SetEnabled(enabled); } return (Transform *)_transforms->GetParams(dataSetName); } double ViewpointParams::getLightDirection(int lightNum, int dir) const { if (lightNum < 0 || lightNum > 2) lightNum = 0; if (dir < 0 || dir > 3) dir = 0; vector defaultv; for (int light = 0; light < 3; light++) { for (int i = 0; i < 4; i++) { defaultv.push_back(_defaultLightDirection[light][i]); } } vector v = GetValueDoubleVec(_lightDirectionsTag, defaultv); return (v[lightNum * 4 + dir]); } void ViewpointParams::setLightDirection(int lightNum, int dir, double val) { if (lightNum < 0 || lightNum > 2) lightNum = 0; if (dir < 0 || dir > 3) dir = 0; vector defaultv; for (int light = 0; light < 3; light++) { for (int i = 0; i < 4; i++) { defaultv.push_back(_defaultLightDirection[light][i]); } } vector v = GetValueDoubleVec(_lightDirectionsTag, defaultv); v[lightNum * 4 + dir] = val; SetValueDoubleVec(_lightDirectionsTag, "Set light direction", v); } double ViewpointParams::getDiffuseCoeff(int lightNum) const { if (lightNum < 0 || lightNum > 2) lightNum = 0; vector defaultv; for (int i = 0; i < 3; i++) defaultv.push_back(_defaultDiffuseCoeff[i]); double v = GetValueDoubleVec(_diffuseCoeffTag, defaultv)[lightNum]; return (v); } double ViewpointParams::getSpecularCoeff(int lightNum) const { if (lightNum < 0 || lightNum > 2) lightNum = 0; vector defaultv; for (int i = 0; i < 3; i++) defaultv.push_back(_defaultSpecularCoeff[i]); double v = GetValueDoubleVec(_specularCoeffTag, defaultv)[lightNum]; return (v); } void ViewpointParams::setDiffuseCoeff(int lightNum, double val) { if (lightNum < 0 || lightNum > 2) lightNum = 0; vector defaultv; for (int i = 0; i < 3; i++) defaultv.push_back(_defaultDiffuseCoeff[i]); vector v = GetValueDoubleVec(_diffuseCoeffTag, defaultv); v[lightNum] = val; SetValueDoubleVec(_diffuseCoeffTag, "Set diffuse coefficient", v); } void ViewpointParams::setSpecularCoeff(int lightNum, double val) { if (lightNum < 0 || lightNum > 2) lightNum = 0; vector defaultv; for (int i = 0; i < 3; i++) defaultv.push_back(_defaultSpecularCoeff[i]); vector v = GetValueDoubleVec(_specularCoeffTag, defaultv); v[lightNum] = val; SetValueDoubleVec(_specularCoeffTag, "Set specular coefficient", v); } void ViewpointParams::SetCurrentViewpoint(Viewpoint *newVP) { m_VPs->Insert(newVP, _currentViewTag); } void ViewpointParams::SetWindowSize(size_t width, size_t height) { vector v; v.push_back(width); v.push_back(height); SetValueLongVec(m_windowSizeTag, "Set window width and height", v); } void ViewpointParams::GetWindowSize(size_t &width, size_t &height) const { vector defaultv(2, 100); vector val = GetValueLongVec(m_windowSizeTag, defaultv); width = val[0]; height = val[1]; } void ViewpointParams::SetFOV(float v) { if (v < 5) v = 5; if (v > 90) v = 90; SetValueDouble(m_fieldOfView, "Set Field of View", v); } double ViewpointParams::GetFOV() const { double defaultv = 45.0; double v = GetValueDouble(m_fieldOfView, defaultv); if (v < 5) v = 5; if (v > 90) v = 90; return (v); } void ViewpointParams::SetOrthoProjectionSize(float f) { SetValueDouble(_orthoProjectionSizeTag, "Set orthographic projection size", f); } double ViewpointParams::GetOrthoProjectionSize() const { double defaultv = 1.0; double v = GetValueDouble(_orthoProjectionSizeTag, defaultv); return v; } void ViewpointParams::SetProjectionType(ViewpointParams::ProjectionType type) { SetValueLong(_projectionTypeTag, "Set projection type", type); } ViewpointParams::ProjectionType ViewpointParams::GetProjectionType() const { const long defaultV = Perspective; return (ViewpointParams::ProjectionType)GetValueLong(_projectionTypeTag, defaultV); } vector ViewpointParams::GetStretchFactors() const { vector defaultvec(3, 1.); vector val = GetValueDoubleVec(m_stretchFactorsTag, defaultvec); for (int i = 0; i < val.size(); i++) { if (val[i] == 0) val[i] = 1.0; if (val[i] < 0) val[i] *= -1.0; } return (val); } int ViewpointParams::SetCameraFromFile(const std::string &path) { XmlParser xmlparser; XmlNode *node = new XmlNode(); int rc = xmlparser.LoadFromFile(node, path); if (rc < 0) { MyBase::SetErrMsg("Failed to read file %s : %M", path.c_str()); return (-1); } Viewpoint* v = new Viewpoint(_ssave, node); SetCurrentViewpoint(v); delete v; _ssave->Save(_node, "Load camera from file"); return (0); } int ViewpointParams::SaveCameraToFile(const std::string &path) { ofstream out(path); if (!out) { MyBase::SetErrMsg("Failed to open file %s : %M", path.c_str()); return (-1); } Viewpoint * vp = getCurrentViewpoint(); XmlNode *node = vp->GetNode(); out << *node; if (out.bad()) { MyBase::SetErrMsg("Failed to write file %s : %M", path.c_str()); return (-1); } out.close(); return (0); } #ifdef VAPOR3_0_0_ALPHA void ViewpointParams::SetStretchFactors(vector val) { vector defaultv(3, 1.); if (val.size() != defaultv.size()) val = defaultv; for (int i = 0; i < val.size(); i++) { if (val[i] == 0) val[i] = 1.0; if (val[i] < 0) val[i] *= -1.0; } SetValueDoubleVec(m_stretchFactorsTag, "Scene scaling factors", val); } #endif #ifdef VAPOR3_0_0_ALPHA // Rescale viewing parameters when the scene is rescaled by factor void ViewpointParams::rescale(vector scaleFac) { double vtemp[3], vtemph[3]; vector vtemp2, vtemp2h; Viewpoint * vp = getCurrentViewpoint(); Viewpoint * vph = getHomeViewpoint(); vector vps = vp->getCameraPosLocal(); vector vctr = vp->getRotationCenterLocal(); vector vpsh = vph->getCameraPosLocal(); vector vctrh = vph->getRotationCenterLocal(); for (int i = 0; i < 3; i++) { vtemp[i] = vps[i] - vctr[i]; vtemph[i] = vpsh[i] - vctrh[i]; } // Want to move the camera in or out, based on scaling in directions orthogonal to view dir. for (int i = 0; i < 3; i++) { vtemp[i] /= scaleFac[i]; vtemph[i] /= scaleFac[i]; } for (int i = 0; i < 3; i++) { vtemp2.push_back(vtemp[i] + vctr[i]); vtemp2h.push_back(vtemph[i] + vctrh[i]); } vp->setCameraPosLocal(vtemp2); vph->setCameraPosLocal(vtemp2h); return; } #endif #ifdef VAPOR3_0_0_ALPHA double ViewpointParams::GetCurrentViewDiameter(vector stretchFactors) const { double campos[3], rotctr[3]; getStretchedCamPosLocal(stretchFactors, campos); getStretchedRotCtrLocal(stretchFactors, rotctr); return (2. * vdist(campos, rotctr) * tan(22.5 * M_PI / 180.)); } #endif ================================================ FILE: lib/params/VolumeIsoParams.cpp ================================================ #include #include #include using namespace Wasp; using namespace VAPoR; // // Register class with object factory!!! // static RenParamsRegistrar registrar(VolumeIsoParams::GetClassType()); VolumeIsoParams::VolumeIsoParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : VolumeParams(dataMgr, ssave, VolumeIsoParams::GetClassType()) { SetDiagMsg("VolumeIsoParams::VolumeIsoParams() this=%p", this); _init(); } VolumeIsoParams::VolumeIsoParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : VolumeParams(dataMgr, ssave, node) {} VolumeIsoParams::~VolumeIsoParams() { SetDiagMsg("VolumeIsoParams::~VolumeIsoParams() this=%p", this); } string VolumeIsoParams::GetDefaultAlgorithmName() const { return "Iso Regular"; } // Set everything to default values void VolumeIsoParams::_init() { SetDiagMsg("VolumeParams::_init()"); SetValueLong(UseColormapVariableTag, UseColormapVariableTag, false); SetFieldVariableNames(vector()); SetValueLong(LightingEnabledTag, "", GetDefaultLightingEnabled()); SetValueDouble(PhongAmbientTag, "", GetDefaultPhongAmbient()); SetValueDouble(PhongDiffuseTag, "", GetDefaultPhongDiffuse()); SetValueDouble(PhongSpecularTag, "", GetDefaultPhongSpecular()); SetValueDouble(PhongShininessTag, "", GetDefaultPhongShininess()); } ================================================ FILE: lib/params/VolumeParams.cpp ================================================ #include #include #include #include using namespace Wasp; using namespace VAPoR; // // Register class with object factory!!! // static RenParamsRegistrar registrar(VolumeParams::GetClassType()); std::vector VolumeParams::_algorithms; const std::string VolumeParams::_algorithmTag = "AlgorithmTag"; const std::string VolumeParams::_algorithmWasManuallySetByUserTag = "AlgorithmWasManuallySetByUserTag"; const std::string VolumeParams::_isoValuesTag = "IsoValuesTag"; const std::string VolumeParams::_enabledIsoValuesTag = "EnabledIsoValuesTag"; const std::string VolumeParams::LightingEnabledTag = "LightingEnabledTag"; const std::string VolumeParams::PhongAmbientTag = "PhongAmbientTag"; const std::string VolumeParams::PhongDiffuseTag = "PhongDiffuseTag"; const std::string VolumeParams::PhongSpecularTag = "PhongSpecularTag"; const std::string VolumeParams::PhongShininessTag = "PhongShininessTag"; const std::string VolumeParams::UseColormapVariableTag = "UseColormapVariable"; const std::string VolumeParams::SamplingRateMultiplierTag = "SamplingRateMultiplierTag"; const std::string VolumeParams::VolumeDensityTag = "VolumeDensityTag"; const std::string VolumeParams::OSPDensity = "OSPDensity"; const std::string VolumeParams::OSPSampleRateScalar = "OSPSampleRateScalar"; const std::string VolumeParams::OSPAmbientLightIntensity = "OSPAmbientLightIntensity"; const std::string VolumeParams::OSPDirectionalLightIntensity = "OSPDirectionalLightIntensity"; const std::string VolumeParams::OSPVolmeAlgorithmName = "OSPRay (experimental)"; VolumeParams::VolumeParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, VolumeParams::GetClassType(), 3) { SetDiagMsg("VolumeParams::VolumeParams() this=%p", this); _init(); } VolumeParams::VolumeParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, std::string classType) : RenderParams(dataMgr, ssave, classType, 3) { SetDiagMsg("VolumeParams::VolumeParams() this=%p", this); _init(); } VolumeParams::VolumeParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node, 3) {} VolumeParams::~VolumeParams() { SetDiagMsg("VolumeParams::~VolumeParams() this=%p", this); } string VolumeParams::GetDefaultAlgorithmName() const { return "Regular"; } std::string VolumeParams::GetAlgorithm() const { return GetValueString(_algorithmTag, GetDefaultAlgorithmName()); } void VolumeParams::SetAlgorithm(std::string algorithm) { if (!STLUtils::Contains(GetAlgorithmNames(), algorithm)) MyBase::SetErrMsg("Invalid volume rendering algorithm \"%s\"", algorithm.c_str()); SetValueString(_algorithmTag, "Volume rendering algorithm", algorithm); } void VolumeParams::SetAlgorithmByUser(std::string algorithm) { BeginGroup("Set Algorithm and set by user"); SetAlgorithm(algorithm); SetAlgorithmWasManuallySetByUser(true); EndGroup(); } bool VolumeParams::GetAlgorithmWasManuallySetByUser() const { return GetValueLong(_algorithmWasManuallySetByUserTag, false); } void VolumeParams::SetAlgorithmWasManuallySetByUser(bool v) { SetValueLong(_algorithmWasManuallySetByUserTag, "User manually changed the algorithm", v); } std::vector VolumeParams::GetSamplingRateMultiples() { return {1, 2, 4, 8, 16}; } long VolumeParams::GetSamplingMultiplier() const { return GetValueLong(SamplingRateMultiplierTag, 1); } void VolumeParams::SetSamplingMultiplier(long d) { SetValueLong(SamplingRateMultiplierTag, "Sampling Rate Multiplier", d); } vector VolumeParams::GetIsoValues(const string &variable) { const string tag = "IsoValues_" + variable; if (!GetNode()->HasElementDouble(tag)) { const MapperFunction *mf = GetMapperFunc(variable); const float min = mf->getMinMapValue(); const float max = mf->getMaxMapValue(); const float middle = (min + max) / 2.f; SetIsoValues(variable, {middle}); } return GetValueDoubleVec(tag); } void VolumeParams::SetIsoValues(const string &variable, const vector &values) { assert(values.size() <= 4); const string tag = "IsoValues_" + variable; SetValueDoubleVec(tag, tag, values); } void VolumeParams::SetLightingEnabled(bool v) { SetValueLong(LightingEnabledTag, "Lighting enabled", v); } bool VolumeParams::GetLightingEnabled() const { return GetValueLong(LightingEnabledTag, GetDefaultLightingEnabled()); } void VolumeParams::SetPhongAmbient(float v) { SetValueDouble(PhongAmbientTag, "Phong ambient", v); }; float VolumeParams::GetPhongAmbient() const { return GetValueDouble(PhongAmbientTag, GetDefaultPhongAmbient()); }; void VolumeParams::SetPhongDiffuse(float v) { SetValueDouble(PhongDiffuseTag, "Phong diffuse", v); }; float VolumeParams::GetPhongDiffuse() const { return GetValueDouble(PhongDiffuseTag, GetDefaultPhongDiffuse()); }; void VolumeParams::SetPhongSpecular(float v) { SetValueDouble(PhongSpecularTag, "Phong specular", v); }; float VolumeParams::GetPhongSpecular() const { return GetValueDouble(PhongSpecularTag, GetDefaultPhongSpecular()); }; void VolumeParams::SetPhongShininess(float v) { SetValueDouble(PhongShininessTag, "Phong shininess", v); }; float VolumeParams::GetPhongShininess() const { return GetValueDouble(PhongShininessTag, GetDefaultPhongShininess()); }; const std::vector VolumeParams::GetAlgorithmNames(Type type) { vector names; for (const AlgorithmEntry &entry : _algorithms) { if (entry.type == type || type == Type::Any) names.push_back(entry.name); } return names; } void VolumeParams::Register(const std::string &name, Type type) { AlgorithmEntry entry = {name, type}; for (const AlgorithmEntry &existing : _algorithms) if (entry == existing) VAssert(!"Algorithm already registered"); _algorithms.push_back(entry); } // Set everything to default values void VolumeParams::_init() { SetDiagMsg("VolumeParams::_init()"); SetFieldVariableNames(vector()); SetValueDouble(VolumeDensityTag, "", 1); SetValueLong(LightingEnabledTag, "", GetDefaultLightingEnabled()); SetValueDouble(PhongAmbientTag, "", GetDefaultPhongAmbient()); SetValueDouble(PhongDiffuseTag, "", GetDefaultPhongDiffuse()); SetValueDouble(PhongSpecularTag, "", GetDefaultPhongSpecular()); SetValueDouble(PhongShininessTag, "", GetDefaultPhongShininess()); SetValueDouble(OSPDensity, "", 1); SetValueDouble(OSPSampleRateScalar, "", 1); SetValueDouble(OSPAmbientLightIntensity, "", 0.2); SetValueDouble(OSPDirectionalLightIntensity, "", 1); } ================================================ FILE: lib/params/WireFrameParams.cpp ================================================ #include #include #include using namespace Wasp; using namespace VAPoR; // // Register class with object factory!!! // static RenParamsRegistrar registrar(WireFrameParams::GetClassType()); WireFrameParams::WireFrameParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, WireFrameParams::GetClassType(), 3) { SetDiagMsg("WireFrameParams::WireFrameParams() this=%p", this); _init(); } WireFrameParams::WireFrameParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node, 3) {} WireFrameParams::~WireFrameParams() { SetDiagMsg("WireFrameParams::~WireFrameParams() this=%p", this); } // Set everything to default values void WireFrameParams::_init() { SetDiagMsg("WireFrameParams::_init()"); SetFieldVariableNames(vector()); } ================================================ FILE: lib/params/XmlNode.cpp ================================================ // // $Id$ // //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: XmlNode.cpp // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: Thu Sep 30 14:06:17 MDT 2004 // // Description: // #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include using namespace VAPoR; using namespace Wasp; // Enable memory checking // #define MEMCHECK namespace VAPoR { vector XmlNode::_emptyDoubleVec; vector XmlNode::_emptyLongVec; vector XmlNode::_emptyStringVec; string XmlNode::_emptyString; std::vector XmlNode::_allocatedNodes; }; // namespace VAPoR namespace { string TypeAttr = "Type"; const string LongType = "Long"; const string DoubleType = "Double"; const string StringType = "String"; }; // namespace namespace { string escapeStr(string s) { string eS; for (int i = 0; i < s.length(); i++) { if (s[i] == '<') { eS += "<"; } else if (s[i] == '>') { eS += ">"; } else if (s[i] == '"') { eS += """; } else if (s[i] == '\'') { eS += "'"; } else if (s[i] == '&') { eS += "'"; } else { eS += s[i]; } } return (eS); } }; // namespace bool XmlNode::IsValidXMLElement(const string &s, int *badIdx) { int _; badIdx = badIdx?badIdx:&_; *badIdx = 0; if (s.empty()) return (false); if (!(std::isalpha(s[0]) || s[0] == '_')) return (false); for (string::const_iterator itr = s.begin(); itr != s.end(); ++itr) { if (!(std::isalnum(*itr) || std::isdigit(*itr) || *itr == '-' || *itr == '_' || *itr == '.')) { return (false); } if (isspace(*itr)) return (false); ++*badIdx; } *badIdx = -1; return (true); } string XmlNode::SanitizeXMLTag(string s) { if(s.empty()) return "__empty__"; int i; while (!IsValidXMLElement(s, &i)) { s = s.substr(0, i) + "_" + to_string((int)s[i]) + "_" + s.substr(i+1); } return s; } XmlNode::XmlNode(const string &tag, const map &attrs, size_t numChildrenHint) { VAssert(IsValidXMLElement(tag)); _longmap.clear(); _doublemap.clear(); _stringmap.clear(); _attrmap.clear(); _children.clear(); _tag.clear(); _asciiLimit = 1024; _parent = NULL; _tag = tag; _attrmap = attrs; if (numChildrenHint) _children.reserve(numChildrenHint); #ifdef MEMCHECK _allocatedNodes.push_back(this); #endif } XmlNode::XmlNode(const string &tag, size_t numChildrenHint) { VAssert(IsValidXMLElement(tag)); _longmap.clear(); _doublemap.clear(); _stringmap.clear(); _attrmap.clear(); _children.clear(); _tag.clear(); _asciiLimit = 1024; _parent = NULL; _tag = tag; if (numChildrenHint) _children.reserve(numChildrenHint); #ifdef MEMCHECK _allocatedNodes.push_back(this); #endif } XmlNode::XmlNode() { _longmap.clear(); _doublemap.clear(); _stringmap.clear(); _attrmap.clear(); _children.clear(); _tag.clear(); _asciiLimit = 1024; _parent = NULL; #ifdef MEMCHECK _allocatedNodes.push_back(this); #endif } XmlNode::XmlNode(const XmlNode &rhs) : _longmap(rhs._longmap), _doublemap(rhs._doublemap), _stringmap(rhs._stringmap), _attrmap(rhs._attrmap), _children(rhs._children), _tag(rhs._tag), _asciiLimit(rhs._asciiLimit), _parent(NULL) // Set parent to NULL { _children.clear(); for (int i = 0; i < rhs._children.size(); i++) { AddChild(rhs._children[i]); } #ifdef MEMCHECK _allocatedNodes.push_back(this); #endif } XmlNode &XmlNode::operator=(const XmlNode &rhs) { DeleteAll(); MyBase::operator=(rhs); _children.clear(); _longmap = rhs._longmap; _doublemap = rhs._doublemap; _stringmap = rhs._stringmap; _attrmap = rhs._attrmap; _children = rhs._children; _tag = rhs._tag; _asciiLimit = rhs._asciiLimit; _parent = NULL; // Set parent to NULL _children.clear(); for (int i = 0; i < rhs._children.size(); i++) { AddChild(rhs._children[i]); } return (*this); } bool XmlNode::operator==(const XmlNode &rhs) const { if (_longmap != rhs._longmap) return (false); if (_doublemap != rhs._doublemap) return (false); if (_stringmap != rhs._stringmap) return (false); if (_attrmap != rhs._attrmap) return (false); if (_tag != rhs._tag) return (false); if (_children.size() != rhs._children.size()) return (false); for (int i = 0; i < _children.size(); i++) { // Recusrively call '==' operator // if (!(*(_children[i]) == *(rhs._children[i]))) return (false); } // Don't check parent!!! // // if (_parent != rhs._parent) return(false); return (true); } XmlNode::~XmlNode() { DeleteAll(); #ifdef MEMCHECK std::vector::iterator itr; for (itr = _allocatedNodes.begin(); itr != _allocatedNodes.end(); ++itr) { if (*itr == this) { _allocatedNodes.erase(itr); break; } } #endif } void XmlNode::SetElementLong(const string &tag, const vector &values) { VAssert(IsValidXMLElement(tag)); _longmap[tag] = values; } void XmlNode::SetElementLong(const vector &tags, const vector &values) { VAssert(!tags.empty()); // Iterate through tags, finding associated node XmlNode *currNode = this; for (int i = 0; i < tags.size() - 1; i++) { XmlNode *child = currNode->GetChild(tags[i]); if (!child) { child = currNode->NewChild(tags[i]); } currNode = child; } string tag = tags[tags.size() - 1]; VAssert(IsValidXMLElement(tag)); currNode->_longmap[tag] = values; } void XmlNode::SetElementDouble(const vector &tags, const vector &values) { VAssert(!tags.empty()); // Iterate through tags, finding associated node XmlNode *currNode = this; for (int i = 0; i < tags.size() - 1; i++) { XmlNode *child = currNode->GetChild(tags[i]); if (!child) { child = currNode->NewChild(tags[i]); } currNode = child; } string tag = tags[tags.size() - 1]; VAssert(IsValidXMLElement(tag)); currNode->_doublemap[tag] = values; } const vector &XmlNode::GetElementLong(const string &tag) const { map>::const_iterator p = _longmap.find(tag); // see if entry for this key (tag) already exists // if (p == _longmap.end()) { return (_emptyLongVec); } return (p->second); } bool XmlNode::HasElementLong(const string &tag) const { map>::const_iterator p = _longmap.find(tag); return (p != _longmap.end()); } void XmlNode::SetElementDouble(const string &tag, const vector &values) { VAssert(IsValidXMLElement(tag)); _doublemap[tag] = values; } const vector &XmlNode::GetElementDouble(const string &tag) const { map>::const_iterator p = _doublemap.find(tag); // see if entry for this key (tag) already exists // if (p == _doublemap.end()) { return (_emptyDoubleVec); } return (p->second); } bool XmlNode::HasElementDouble(const string &tag) const { if (_doublemap.empty()) return false; map>::const_iterator p = _doublemap.find(tag); return (p != _doublemap.end()); } void XmlNode::SetElementString(const string &tag, const string &str) { VAssert(IsValidXMLElement(tag)); _stringmap[tag] = str; } void XmlNode::SetElementStringVec(const string &tag, const vector &strvec) { VAssert(IsValidXMLElement(tag)); string s; for (int i = 0; i < strvec.size(); i++) { s.append(STLUtils::ReplaceAll(strvec[i], " ", "\\ ")); if (i < strvec.size() - 1) s.append(" "); } return (XmlNode::SetElementString(tag, s)); } void XmlNode::SetElementStringVec(const vector &tags, const vector &strvec) { VAssert(!tags.empty()); // Iterate through tags, finding associated node XmlNode *currNode = this; for (int i = 0; i < tags.size() - 1; i++) { XmlNode *child = currNode->GetChild(tags[i]); if (!child) { child = currNode->NewChild(tags[i]); } currNode = child; } string tag = tags[tags.size() - 1]; VAssert(IsValidXMLElement(tag)); string s; for (int i = 0; i < strvec.size(); i++) { s.append(strvec[i]); if (i < strvec.size() - 1) s.append(" "); } return (currNode->SetElementString(tag, s)); } const string &XmlNode::GetElementString(const string &tag) const { map::const_iterator p = _stringmap.find(tag); // see if entry for this key (tag) already exists // if (p == _stringmap.end()) { return (_emptyString); } return (p->second); } void XmlNode::GetElementStringVec(const string &tag, vector &vec) const { string s = XmlNode::GetElementString(tag); StrToWordVec(s, vec); for (string &e : vec) e = STLUtils::ReplaceAll(e, "\\ ", " "); } bool XmlNode::HasElementString(const string &tag) const { map::const_iterator p = _stringmap.find(tag); return (p != _stringmap.end()); } XmlNode *XmlNode::NewChild(const string &tag, const map &attrs, size_t numChildrenHint) { // Delete duplicates // if (HasChild(tag)) { DeleteChild(tag); } XmlNode *mychild = Construct(tag, attrs, numChildrenHint); mychild->_parent = this; _children.push_back(mychild); return (mychild); } XmlNode *XmlNode::AddChild(const XmlNode *child) { return (AddChild(*child)); } XmlNode *XmlNode::AddChild(const XmlNode &child) { XmlNode *mychild = new XmlNode(child); // Delete duplicates // if (HasChild(mychild->Tag())) { DeleteChild(mychild->Tag()); } mychild->_parent = this; _children.push_back(mychild); return (mychild); } #ifdef VAPOR3_0_0_ALPHA int XmlNode::ReplaceChild(XmlNode *prevChildNode, XmlNode *newChildNode) { for (int index = 0; index < _children.size(); index++) { XmlNode *node = _children[index]; if (node == prevChildNode) { delete node; _children[index] = new XmlNode(*newChildNode); newChildNode->_parent = this; return index; } } SetErrMsg("Node not found"); return (-1); } #endif int XmlNode::DeleteChild(size_t index) { if (index >= _children.size()) { SetErrMsg("Invalid child id : %d", index); return (-1); } XmlNode *node = _children[index]; VAssert(node); // Remove from parent's list of children and // recursively delete this node's children, if any // node->SetParent(NULL); delete node; return (0); } int XmlNode::DeleteChild(const string &tag) { XmlNode *child; for (size_t i = 0; i < _children.size(); i++) { child = GetChild(i); VAssert(child); if (child->_tag == tag) { return (XmlNode::DeleteChild(i)); } } SetErrMsg("Invalid child name (does not exist) : %s", tag.c_str()); return (-1); } XmlNode *XmlNode::GetChild(size_t index) const { if (index >= _children.size()) { SetErrMsg("Invalid child id : %d", index); return (NULL); } return (_children[index]); } bool XmlNode::HasChild(size_t index) const { return (index < _children.size()); } XmlNode *XmlNode::GetChild(const string &tag) const { XmlNode *child; for (size_t i = 0; i < _children.size(); i++) { if (!(child = GetChild(i))) return (NULL); if (child->_tag == tag) return (child); } return (NULL); } bool XmlNode::HasChild(const string &tag) const { XmlNode *child = NULL; for (size_t i = 0; i < _children.size(); i++) { child = GetChild(i); VAssert(child != NULL); if (child->_tag == tag) return (true); } return (false); } XmlNode *XmlNode::GetNode(std::vector path, bool absolute) const { if (path.empty()) return (NULL); const XmlNode *node = this; // If absolute path find the root of the tree // if (absolute) { while (node->GetParent() != NULL) { node = node->GetParent(); } if (node->GetTag() != path[0]) return (NULL); path.erase(path.begin()); } // Now walk the path down to the last node in the path // for (int i = 0; i < path.size(); i++) { if (!node->HasChild(path[i])) return (NULL); node = node->GetChild(path[i]); } return ((XmlNode *)node); } XmlNode *XmlNode::GetNode(string path) const { if (path.empty()) return (NULL); vector pathvec; Wasp::SplitString(path, '/', pathvec); // Absolute or relative path? // if (path[0] == '/') { return (GetNode(pathvec, true)); } else { return (GetNode(pathvec, false)); } } void XmlNode::SetParent(XmlNode *parent) { // No-op case // if (parent == _parent) return; // Delete duplicates on new parent // if (parent && parent->HasChild(Tag())) { parent->DeleteChild(Tag()); } // Remove from current parent's list of children // if (_parent) { vector::iterator itr = _parent->_children.begin(); for (; itr != _parent->_children.end(); ++itr) { XmlNode *node = *itr; if (node->Tag() == Tag()) { _parent->_children.erase(itr); break; } } } // If new parent is not NULL // if (parent) { parent->_children.push_back(this); } _parent = parent; } // Recursively delete all descendants of this node // void XmlNode::DeleteAll() { for (int i = 0; i < (int)_children.size(); i++) { if (_children[i]) { XmlNode *node = _children[i]; VAssert(node); delete node; } } _children.clear(); } vector XmlNode::GetPathVec() const { vector path; path.push_back(GetTag()); const XmlNode *child = this; const XmlNode *parent = NULL; while ((parent = child->GetParent()) != NULL) { path.push_back(parent->GetTag()); child = parent; } // Reverse so root is first // reverse(path.begin(), path.end()); return (path); } string XmlNode::GetPath() const { vector tags = GetPathVec(); string path; for (int i = 0; i < tags.size(); i++) { path += "/"; path += tags[i]; } return (path); } XmlNode *XmlNode::GetRoot() const { const XmlNode *node = this; // Why must node be const? while (node->GetParent()) { node = node->GetParent(); } return ((XmlNode *)node); } ostream &XmlNode::streamOut(ostream &os, const XmlNode &node) { os << node; return os; } namespace VAPoR { std::ostream &operator<<(ostream &os, const VAPoR::XmlNode &node) { map>::const_iterator plong; map>::const_iterator pdouble; map::const_iterator pstring; map::const_iterator pattr; int i; // os.setf(ios_base::scientific, ios_base::floatfield); os.precision(16); plong = node._longmap.begin(); pdouble = node._doublemap.begin(); pstring = node._stringmap.begin(); pattr = node._attrmap.begin(); os << "<" << node._tag; for (; pattr != node._attrmap.end(); pattr++) { const string &name = pattr->first; const string &value = pattr->second; os << " " << name << "=\"" << value << "\" "; } os << ">" << endl; for (; plong != node._longmap.end(); plong++) { const string &tag = plong->first; const vector &v = plong->second; os << "<" << tag << " Type=\"Long\">" << endl; for (i = 0; i < (int)v.size(); i++) { os << v[i] << " "; } os << endl; os << "" << endl; } for (; pdouble != node._doublemap.end(); pdouble++) { const string &tag = pdouble->first; os << "<" << tag << " Type=\"Double\">" << endl; const vector &v = pdouble->second; for (i = 0; i < (int)v.size(); i++) { os << v[i] << " "; } os << endl; os << "" << endl; } for (; pstring != node._stringmap.end(); pstring++) { const string &tag = pstring->first; os << "<" << tag << " Type=\"String\">" << endl; string v = escapeStr(pstring->second); os << v; os << endl; os << "" << endl; } if (node._children.size()) { for (int i = 0; i < (int)node._children.size(); i++) { XmlNode *childptr; childptr = node._children[i]; os << *childptr; } } os << "" << endl; return (os); } void _StartElementHandler(void *userData, const char *tag, const char **attrs) { XmlParser *parser = (XmlParser *)userData; string mytag(tag); map myattrs; while (*attrs) { string key = *attrs; attrs++; VAssert(*attrs); string value = *attrs; attrs++; myattrs[key] = value; } parser->_startElementHandler(mytag, myattrs); } void _EndElementHandler(void *userData, const char *tag) { XmlParser *parser = (XmlParser *)userData; string mytag(tag); parser->_endElementHandler(mytag); } void _CharDataHandler(void *userData, const char *s, int len) { XmlParser *parser = (XmlParser *)userData; string mys(s, len); parser->_charDataHandler(mys); } }; // namespace VAPoR XmlParser::XmlParser() { _root = NULL; _nodeType = UNKNOWN; //_nodeStack.clear(); // No stack clear! Sigh _stringData.clear(); } int XmlParser::LoadFromFile(XmlNode *node, string path) { ifstream in(path); if (!in) { SetErrMsg("Failed to open file %s : %M", path.c_str()); return (-1); } int rc = LoadFromFile(node, in); in.close(); if (rc < 0 || in.bad() || !_nodeStack.empty()) { SetErrMsg("IO Error reading XML file"); return (-1); } return (0); } int XmlParser::LoadFromFile(XmlNode *node, istream &in) { VAssert(node != NULL); _root = node; _nodeType = UNKNOWN; _stringData.clear(); //_nodeStack.clear(); while (_nodeStack.size()) _nodeStack.pop(); // Delete all current children // _root->DeleteAll(); XML_Parser expatParser = XML_ParserCreate(NULL); VAssert(expatParser != NULL); XML_SetElementHandler(expatParser, _StartElementHandler, _EndElementHandler); XML_SetCharacterDataHandler(expatParser, _CharDataHandler); XML_SetUserData(expatParser, (void *)this); // Parse the file until we run out of elements or a parsing error occurs // char line[1024]; while (in.good()) { int rc; in.read(line, sizeof(line) - 1); if ((rc = in.gcount()) > 0) { if (XML_Parse(expatParser, line, rc, 0) == XML_STATUS_ERROR) { SetErrMsg("Error parsing xml file at line %d : %s", XML_GetCurrentLineNumber(expatParser), XML_ErrorString(XML_GetErrorCode(expatParser))); XML_ParserFree(expatParser); return (-1); } } } XML_ParserFree(expatParser); return 0; } void XmlParser::_startElementHandler(string tag, map &myattrs) { _nodeType = UNKNOWN; _stringData.clear(); type dtype; if (_isParentElement(tag, myattrs)) { _nodeType = PARENT; XmlNode *parent = NULL; if (_nodeStack.empty()) { parent = _root; parent->Tag() = tag; parent->Attrs() = myattrs; _nodeStack.push(parent); } else { XmlNode child(tag, myattrs); parent = _nodeStack.top(); XmlNode *childptr = parent->AddChild(&child); _nodeStack.push(childptr); } } else if (_isDataElement(tag, myattrs, dtype)) { VAssert(!_nodeStack.empty()); _nodeType = dtype; } // cout << "_startElementHandler() tag, type " << tag << " " << _nodeType << endl; } void XmlParser::_endElementHandler(string tag) { VAssert(!_nodeStack.empty()); // cout << "_endElementHandler() tag, type /" << tag << " " << _nodeType << endl; // remove leading and trailing white space from the XML char data // StrRmWhiteSpace(_stringData); XmlNode *node = _nodeStack.top(); switch (_nodeType) { case PARENT: VAssert(tag == node->Tag()); _nodeStack.pop(); break; case LONG_DATA: { istringstream ist(_stringData); long v; vector values; while (ist >> v) values.push_back(v); node->SetElementLong(tag, values); break; } case DOUBLE_DATA: { istringstream ist(_stringData); double v; vector values; while (ist >> v) values.push_back(v); node->SetElementDouble(tag, values); break; } case STRING_DATA: node->SetElementString(tag, _stringData); break; default: VAssert(0); } _nodeType = PARENT; } void XmlParser::_charDataHandler(string s) { if (!(_nodeType == LONG_DATA || _nodeType == DOUBLE_DATA || _nodeType == STRING_DATA)) return; // cout << "_CharDataHandler() : " << "\""< myattrs) const { type dtype; if (_isDataElement(tag, myattrs, dtype)) return (false); return (true); } bool XmlParser::_isDataElement(string tag, map myattrs, type &dtype) const { dtype = UNKNOWN; if (myattrs.size() != 1) return false; map::const_iterator itr = myattrs.begin(); if (StrCmpNoCase(itr->first, TypeAttr) != 0) return false; if (StrCmpNoCase(itr->second, LongType) == 0) { dtype = LONG_DATA; return true; } else if (StrCmpNoCase(itr->second, DoubleType) == 0) { dtype = DOUBLE_DATA; return true; } else if (StrCmpNoCase(itr->second, StringType) == 0) { dtype = STRING_DATA; return true; } return (false); } ================================================ FILE: lib/params/regionparams.cpp ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: regionparams.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: September 2004 // // Description: Implements the RegionParams class. // This class supports parameters associted with the // region panel // #ifdef WIN32 // Annoying unreferenced formal parameter warning #pragma warning(disable : 4100) #endif #include #include using namespace VAPoR; const string RegionParams::_domainVariablesTag = "DomainVariables"; // // Register class with object factory!!! // static ParamsRegistrar registrar(RegionParams::GetClassType()); RegionParams::RegionParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, RegionParams::GetClassType()) { // Initialize DataMgr dependent parameters // _init(); m_Box = new Box(ssave); m_Box->SetParent(this); } RegionParams::RegionParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) { if (node->HasChild(Box::GetClassType())) { m_Box = new Box(ssave, node->GetChild(Box::GetClassType())); } else { // Node doesn't contain a Box // m_Box = new Box(ssave); m_Box->SetParent(this); } _reconcile(); } RegionParams::RegionParams(const RegionParams &rhs) : ParamsBase(rhs) { m_Box = new Box(*(rhs.m_Box)); } RegionParams &RegionParams::operator=(const RegionParams &rhs) { if (m_Box) delete m_Box; ParamsBase::operator=(rhs); m_Box = new Box(*(rhs.m_Box)); return (*this); } RegionParams::~RegionParams() { if (m_Box) delete m_Box; } // Reset region settings to initial state void RegionParams::_init() { #ifdef VAPOR3_0_0_ALPHA const double * extents = m_dataStatus->getLocalExtents(); vector exts(3, 0.0); for (i = 0; i < 3; i++) { exts.push_back(extents[i + 3] - extents[i]); } GetBox()->SetLocalExtents(exts); GetBox()->Trim(); vector novars; SetDomainVariables(novars); #endif } void RegionParams::_reconcile() { #ifdef VAPOR3_0_0_ALPHA vector times = GetBox()->GetTimes(); double regionExtents[6]; for (int timenum = 0; timenum < times.size(); timenum++) { int currTime = times[timenum]; GetBox()->GetLocalExtents(regionExtents, currTime); // force them to fit in current volume for (i = 0; i < 3; i++) { if (regionExtents[i] > extents[i + 3] - extents[i]) regionExtents[i] = extents[i + 3] - extents[i]; if (regionExtents[i] < 0.) regionExtents[i] = 0.; if (regionExtents[i + 3] > extents[i + 3] - extents[i]) regionExtents[i + 3] = extents[i + 3] - extents[i]; if (regionExtents[i + 3] < 0.) regionExtents[i + 3] = 0.; if (regionExtents[i] > regionExtents[i + 3]) regionExtents[i + 3] = regionExtents[i]; } exts.clear(); for (int j = 0; j < 6; j++) exts.push_back(regionExtents[j]); GetBox()->SetLocalExtents(exts, this, currTime); } #endif } #ifdef VAPOR3_0_0_ALPHA bool RegionParams::insertTime(int timestep) { return true; } bool RegionParams::removeTime(int timestep) { return true; } #endif ================================================ FILE: lib/render/AnnotationRenderer.cpp ================================================ //-- AnnotationRenderer.cpp ---------------------------------------------------------- // // Copyright (C) 2015 // University Corporation for Atmospheric Research // All Rights Reserved // //---------------------------------------------------------------------------- // // File: AnnotationRenderer.cpp // // Author: Alan Norton // // Description: Implementation of AnnotationRenderer class // //---------------------------------------------------------------------------- #include // Must be included first!!! #include #include #include #include #include #include #include #ifndef WIN32 #include #endif #include #include #include #include #include #include "vapor/LegacyGL.h" #include "vapor/TextLabel.h" #include "vapor/AnnotationParams.h" #define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH #include #define X 0 #define Y 1 #define Z 2 #define ARROW_SCALE_FACTOR .25 using namespace VAPoR; using namespace Wasp; //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- AnnotationRenderer::AnnotationRenderer(const ParamsMgr *pm, const DataStatus *dataStatus, string winName) { m_paramsMgr = pm; m_dataStatus = dataStatus; m_winName = winName; _glManager = nullptr; _currentTimestep = 0; _fontName = "arimo"; _fontFile = GetSharePath("fonts/" + _fontName + ".ttf"); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- AnnotationRenderer::~AnnotationRenderer() { #ifdef VAPOR3_0_0_ALPHA if (_textObjectsValid) invalidateCache(); #endif } void AnnotationRenderer::InitializeGL(GLManager *glManager) { _glManager = glManager; } void AnnotationRenderer::drawDomainFrame(std::vector corners) const { assert(corners.size() == 6); AnnotationParams *vfParams = m_paramsMgr->GetAnnotationParams(m_winName); std::vector minExts = {corners[X], corners[Y], corners[Z]}; std::vector maxExts = {corners[X + 3], corners[Y + 3], corners[Z + 3]}; int i; int numLines[3]; double fullSize[3], modMin[3], modMax[3]; // Instead: either have 2 or 1 lines in each dimension. 2 if the size is < 1/3 for (i = 0; i < minExts.size(); i++) { double regionSize = maxExts[i] - minExts[i]; // Stretch size by 1% fullSize[i] = (maxExts[i] - minExts[i]) * 1.01; double mid = 0.5f * (maxExts[i] + minExts[i]); modMin[i] = mid - 0.5f * fullSize[i]; modMax[i] = mid + 0.5f * fullSize[i]; if (regionSize < fullSize[i] * .3) numLines[i] = 2; else numLines[i] = 1; } double clr[3]; vfParams->GetDomainColor(clr); // glLineWidth(1); // Now draw the lines. Divide each dimension into numLines[dim] sections. int x, y, z; // Do the lines in each z-plane // Turn on writing to the z-buffer glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); LegacyGL *lgl = _glManager->legacy; lgl->Color3f(clr[0], clr[1], clr[2]); lgl->Begin(GL_LINES); for (z = 0; z <= numLines[2]; z++) { float zCrd = modMin[2] + ((float)z / (float)numLines[2]) * fullSize[2]; // Draw lines in x-direction for each y for (y = 0; y <= numLines[1]; y++) { float yCrd = modMin[1] + ((float)y / (float)numLines[1]) * fullSize[1]; lgl->Vertex3f(modMin[0], yCrd, zCrd); lgl->Vertex3f(modMax[0], yCrd, zCrd); } // Draw lines in y-direction for each x for (x = 0; x <= numLines[0]; x++) { float xCrd = modMin[0] + ((float)x / (float)numLines[0]) * fullSize[0]; lgl->Vertex3f(xCrd, modMin[1], zCrd); lgl->Vertex3f(xCrd, modMax[1], zCrd); } } // Do the lines in each y-plane for (y = 0; y <= numLines[1]; y++) { float yCrd = modMin[1] + ((float)y / (float)numLines[1]) * fullSize[1]; // Draw lines in x direction for each z for (z = 0; z <= numLines[2]; z++) { float zCrd = modMin[2] + ((float)z / (float)numLines[2]) * fullSize[2]; lgl->Vertex3f(modMin[0], yCrd, zCrd); lgl->Vertex3f(modMax[0], yCrd, zCrd); } // Draw lines in z direction for each x for (x = 0; x <= numLines[0]; x++) { float xCrd = modMin[0] + ((float)x / (float)numLines[0]) * fullSize[0]; lgl->Vertex3f(xCrd, yCrd, modMin[2]); lgl->Vertex3f(xCrd, yCrd, modMax[2]); } } // Do the lines in each x-plane for (x = 0; x <= numLines[0]; x++) { float xCrd = modMin[0] + ((float)x / (float)numLines[0]) * fullSize[0]; // Draw lines in y direction for each z for (z = 0; z <= numLines[2]; z++) { float zCrd = modMin[2] + ((float)z / (float)numLines[2]) * fullSize[2]; lgl->Vertex3f(xCrd, modMin[1], zCrd); lgl->Vertex3f(xCrd, modMax[1], zCrd); } // Draw lines in z direction for each y // Draw lines in z direction for each y for (y = 0; y <= numLines[1]; y++) { float yCrd = modMin[1] + ((float)y / (float)numLines[1]) * fullSize[1]; lgl->Vertex3f(xCrd, yCrd, modMin[2]); lgl->Vertex3f(xCrd, yCrd, modMax[2]); } } lgl->End(); glEnable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); } void AnnotationRenderer::DrawText() { _glManager->PixelCoordinateSystemPush(); DrawText(_miscAnnot); _drawTimeAnnotation(); DrawText(_axisAnnot); _glManager->PixelCoordinateSystemPop(); } void AnnotationRenderer::_drawTimeAnnotation() { AnnotationParams *params = m_paramsMgr->GetAnnotationParams(m_winName); // size_t ts = params->GetCurrentTimestep(); std::string timeText; auto type = params->GetValueLong(AnnotationParams::_timeTypeTag, 0); if (type == 0) { ClearText(1); } else if (type == 1) { // drawTimeStep timeText = "Timestep: " + std::to_string(_currentTimestep); } else if (type == 2) { // drawTimeUser() vector timeCoords = m_dataStatus->GetTimeCoordinates(); std::ostringstream ss; ss << timeCoords[_currentTimestep]; timeText = ss.str(); } else if (type == 3) { // drawTimeStamp() timeText = m_dataStatus->GetTimeCoordsFormatted()[_currentTimestep]; } billboard board; board.text = timeText; board.xn = params->GetValueDouble(AnnotationParams::_timeLLXTag, 0.01); board.yn = params->GetValueDouble(AnnotationParams::_timeLLYTag, 0.01); board.x = 0; board.y = 0; board.size = params->GetValueLong(AnnotationParams::_timeSizeTag, 24.); std::vector color = params->GetValueDoubleVec(AnnotationParams::_timeColorTag, {1.0, 1.0, 1.0}); board.color[0] = color[0]; board.color[1] = color[1]; board.color[2] = color[2]; DrawText({board}); } void AnnotationRenderer::DrawText(vector billboards) { float txtColor[] = {1.f, 1.f, 1.f, 1.f}; float bgColor[] = {0.f, 0.f, 0.f, 0.f}; float coords[] = {67.5f, 31.6f, 0.f}; auto size = _glManager->GetViewportSize(); for (int i = 0; i < billboards.size(); i++) { string text = billboards[i].text; if (billboards[i].x == 0 && billboards[i].y == 0) { coords[0] = billboards[i].xn * size.x; coords[1] = billboards[i].yn * size.y; } else { coords[0] = billboards[i].x; coords[1] = billboards[i].y; } int size = billboards[i].size; txtColor[0] = billboards[i].color[0]; txtColor[1] = billboards[i].color[1]; txtColor[2] = billboards[i].color[2]; TextLabel label(_glManager, _fontName, size); label.ForegroundColor = glm::make_vec4(txtColor); label.BackgroundColor = glm::make_vec4(bgColor); label.DrawText(glm::make_vec2(coords), text); } } void AnnotationRenderer::AddText(string text, int x, int y, int size, float color[3], int type) { //_billboards.clear(); // Temporary hack. We eventually need separate // billboard groups for time annotations, axis // labels, etc. Grouping them all in the same // vector makes it hard if not impossible to // make changes to any of the labels (color, size, // etc) billboard myBoard; myBoard.text = text; myBoard.x = x; myBoard.y = y; myBoard.xn = 0; myBoard.yn = 0; myBoard.size = size; myBoard.color[0] = color[0]; myBoard.color[1] = color[1]; myBoard.color[2] = color[2]; if (type == 0) { // Miscellaneous annotation _miscAnnot.push_back(myBoard); } else if (type == 1) { // Time annotation _timeAnnot.push_back(myBoard); } else if (type == 2) { _axisAnnot.push_back(myBoard); } } void AnnotationRenderer::AddTextNormalizedCoords(string text, float x, float y, int size, float color[3], int type) { billboard myBoard; myBoard.text = text; myBoard.x = 0; myBoard.y = 0; myBoard.xn = x; myBoard.yn = y; myBoard.size = size; myBoard.color[0] = color[0]; myBoard.color[1] = color[1]; myBoard.color[2] = color[2]; if (type == 0) { // Miscellaneous annotation _miscAnnot.push_back(myBoard); } else if (type == 1) { // Time annotation _timeAnnot.push_back(myBoard); } else if (type == 2) { _axisAnnot.push_back(myBoard); } } void AnnotationRenderer::ClearText(int type) { if (type == -1) { _miscAnnot.clear(); _timeAnnot.clear(); _axisAnnot.clear(); } if (type == 0) { _miscAnnot.clear(); } else if (type == 1) { _timeAnnot.clear(); } else if (type == 2) { _axisAnnot.clear(); } } void AnnotationRenderer::applyTransform(Transform *t) { vector scale = t->GetScales(); vector origin = t->GetOrigin(); vector translate = t->GetTranslations(); vector rotate = t->GetRotations(); VAssert(translate.size() == 3); VAssert(rotate.size() == 3); VAssert(scale.size() == 3); VAssert(origin.size() == 3); _glManager->matrixManager->Translate(translate[0], translate[1], translate[2]); _glManager->matrixManager->Translate(origin[0], origin[1], origin[2]); _glManager->matrixManager->Rotate(glm::radians(rotate[0]), 1, 0, 0); _glManager->matrixManager->Rotate(glm::radians(rotate[1]), 0, 1, 0); _glManager->matrixManager->Rotate(glm::radians(rotate[2]), 0, 0, 1); _glManager->matrixManager->Scale(scale[0], scale[1], scale[2]); _glManager->matrixManager->Translate(-origin[0], -origin[1], -origin[2]); } void AnnotationRenderer::_makeTransformMatrix(const Transform *transform, glm::mat4 &transformMatrix) const { vector scales = transform->GetScales(); vector origins = transform->GetOrigin(); vector translations = transform->GetTranslations(); vector rotations = transform->GetRotations(); glm::mat4 m; m = glm::translate(glm::mat4(1.f), glm::vec3(translations[X], translations[Y], translations[Z])); m = glm::translate(m, glm::vec3(origins[X], origins[Y], origins[Z])); m = glm::rotate(m, glm::radians((float)rotations[X]), glm::vec3(1.f, 0.f, 0.f)); m = glm::rotate(m, glm::radians((float)rotations[Y]), glm::vec3(0.f, 1.f, 0.f)); m = glm::rotate(m, glm::radians((float)rotations[Z]), glm::vec3(0.f, 0.f, 1.f)); m = glm::scale(m, glm::vec3(scales[X], scales[Y], scales[Z])); m = glm::translate(m, glm::vec3(-origins[X], -origins[Y], -origins[Z])); transformMatrix = m; } void AnnotationRenderer::_applyDataMgrCornerToDomain(std::vector &domainExtents, const glm::vec4 &dataMgrCorner, const glm::mat4 &transformMatrix) const { assert(domainExtents.size() == 6); // transform our corner glm::vec4 transformedCorner; transformedCorner = transformMatrix * dataMgrCorner; // See if the minimum and maximum extents of our corner exceed the // the currently defined domain. for (int i = 0; i < 6; i++) { int transformedCornerIndex = i % 3; // use this corner to define all domain corners that are uninitialized if (std::isnan(domainExtents[i])) domainExtents[i] = transformedCorner[transformedCornerIndex]; // otherwise see if the corner exceeds our currently defined domain minima else if (i < 3) { if (transformedCorner[transformedCornerIndex] < domainExtents[i]) { domainExtents[i] = transformedCorner[transformedCornerIndex]; } } // otherwise see if the corner exceeds our currently defined domain maxima else { if (transformedCorner[transformedCornerIndex] > domainExtents[i]) { domainExtents[i] = transformedCorner[transformedCornerIndex]; } } } } // The lookup table below designates how the eight corners of the dataMgr are // defined. // // For example, corner# 3 will be comprised of the following dataMgr // extent values: { minX, maxY, maxZ}. Corner#6 is { maxX, maxY, minZ} // // X Y Z corner# // 0 0 0 0 // 0 0 1 1 // 0 1 0 2 // 0 1 1 3 // 1 0 0 4 // 1 0 1 5 // 1 1 0 6 // 1 1 1 7 void AnnotationRenderer::_getDataMgrCorner(const int cornerNumber, glm::vec4 &dataMgrCorner, const CoordType &minDataMgrExtents, const CoordType &maxDataMgrExtents) const { assert(cornerNumber >= 0 && cornerNumber <= 7); double xCoord, yCoord, zCoord; if (cornerNumber & 0b100) xCoord = maxDataMgrExtents[X]; else xCoord = minDataMgrExtents[X]; if (cornerNumber & 0b010) yCoord = maxDataMgrExtents[Y]; else yCoord = minDataMgrExtents[Y]; if (cornerNumber & 0b001) zCoord = maxDataMgrExtents[Z]; else zCoord = minDataMgrExtents[Z]; dataMgrCorner = glm::vec4(xCoord, yCoord, zCoord, 1.f); } void AnnotationRenderer::_applyDataMgrToDomainExtents(std::vector &domainExtents, const CoordType &dataMgrMinExts, const CoordType &dataMgrMaxExts, const Transform *transform) const { assert(domainExtents.size() == 6); glm::mat4 transformMatrix; _makeTransformMatrix(transform, transformMatrix); glm::vec4 dataMgrCorner; for (int i = 0; i < 8; i++) { _getDataMgrCorner(i, dataMgrCorner, dataMgrMinExts, dataMgrMaxExts); _applyDataMgrCornerToDomain(domainExtents, dataMgrCorner, transformMatrix); } } void AnnotationRenderer::_calculateDomainExtents(std::vector &domainExtents) const { domainExtents = {NAN, NAN, NAN, NAN, NAN, NAN}; vector names = m_dataStatus->GetDataMgrNames(); for (int i = 0; i < names.size(); i++) { CoordType dataMgrMinExts, dataMgrMaxExts; m_dataStatus->GetActiveExtents(m_paramsMgr, m_winName, names[i], _currentTimestep, dataMgrMinExts, dataMgrMaxExts); ViewpointParams *vpParams = m_paramsMgr->GetViewpointParams(m_winName); Transform * transform = vpParams->GetTransform(names[i]); _applyDataMgrToDomainExtents(domainExtents, dataMgrMinExts, dataMgrMaxExts, transform); } for (int i = 0; i < 6; i++) { if (std::isnan(domainExtents[i])) domainExtents[i] = 0.f; } } void AnnotationRenderer::InScenePaint(size_t ts) { AnnotationParams *vfParams = m_paramsMgr->GetAnnotationParams(m_winName); MatrixManager * mm = _glManager->matrixManager; _currentTimestep = ts; ViewpointParams *vpParams = m_paramsMgr->GetViewpointParams(m_winName); std::vector domainExtents; _calculateDomainExtents(domainExtents); mm->MatrixModeModelView(); mm->PushMatrix(); if (vfParams->GetUseDomainFrame()) drawDomainFrame(domainExtents); vector names = m_dataStatus->GetDataMgrNames(); Transform * t = vpParams->GetTransform(names[0]); applyTransform(t); double mvMatrix[16]; mm->GetDoublev(MatrixManager::Mode::ModelView, mvMatrix); vpParams->SetModelViewMatrix(mvMatrix); AxisAnnotation *aa = vfParams->GetAxisAnnotation(); if (aa->GetAxisAnnotationEnabled()) { drawAxisTics(aa); } mm->MatrixModeModelView(); mm->PopMatrix(); mm->GetDoublev(MatrixManager::Mode::ModelView, mvMatrix); vpParams->SetModelViewMatrix(mvMatrix); CheckGLErrorMsg(m_winName.c_str()); } void AnnotationRenderer::scaleNormalizedCoordinatesToWorld(std::vector &coords, string dataMgrName) { std::vector extents = getDomainExtents(); int dims = extents.size() / 2; for (int i = 0; i < dims; i++) { double offset = coords[i] * (extents[i + dims] - extents[i]); double minimum = extents[i]; coords[i] = offset + minimum; } } void AnnotationRenderer::drawAxisTics(AxisAnnotation *aa) { drawAxisTics(aa, std::vector(), std::vector()); } void AnnotationRenderer::drawAxisTics(AxisAnnotation *aa, std::vector minTic, std::vector maxTic) { if (aa == NULL) aa = getCurrentAxisAnnotation(); if (minTic.empty()) minTic = aa->GetMinTics(); if (maxTic.empty()) maxTic = aa->GetMaxTics(); std::vector origin = aa->GetAxisOrigin(); string dmName = aa->GetDataMgrName(); scaleNormalizedCoordinatesToWorld(origin, dmName); scaleNormalizedCoordinatesToWorld(minTic, dmName); scaleNormalizedCoordinatesToWorld(maxTic, dmName); vector ticLength = aa->GetTicSize(); vector ticDir = aa->GetTicDirs(); vector numTics = aa->GetNumTics(); vector axisColor = aa->GetAxisColor(); double width = aa->GetTicWidth(); bool latLon = aa->GetLatLonAxesEnabled(); _drawAxes(minTic, maxTic, origin, axisColor, width); double pointOnAxis[3]; double ticVec[3]; double startPosn[3], endPosn[3]; vector extents = getDomainExtents(); // Now draw tic marks for x: pointOnAxis[1] = origin[1]; pointOnAxis[2] = origin[2]; ticVec[0] = 0.f; ticVec[1] = 0.f; ticVec[2] = 0.f; double scaleFactor; if (ticDir[0] == 1) { // Y orientation scaleFactor = extents[4] - extents[1]; ticVec[1] = ticLength[0] * scaleFactor; } else { // Z orientation scaleFactor = extents[5] - extents[2]; ticVec[2] = ticLength[0] * scaleFactor; } // ticVec[1] = ticLength[1]*scaleFactor; // ticVec[2] = ticLength[2]*scaleFactor; for (int i = 0; i < numTics[0]; i++) { pointOnAxis[0] = minTic[0] + (float)i * (maxTic[0] - minTic[0]) / (float)(numTics[0] - 1); vsub(pointOnAxis, ticVec, startPosn); vadd(pointOnAxis, ticVec, endPosn); //_drawTic(startPosn, endPosn, length, width, axisColor); _drawTic(startPosn, endPosn, width, axisColor); double xValue = pointOnAxis[0]; double yValue = pointOnAxis[1]; if (latLon) convertPointToLonLat(xValue, yValue); renderText(xValue, startPosn, aa); } // Now draw tic marks for y: pointOnAxis[0] = origin[0]; pointOnAxis[2] = origin[2]; ticVec[0] = 0.f; ticVec[1] = 0.f; ticVec[2] = 0.f; if (ticDir[1] == 2) { // Z orientation scaleFactor = extents[5] - extents[2]; ticVec[2] = ticLength[1] * scaleFactor; } else { // X orientation scaleFactor = extents[4] - extents[1]; ticVec[0] = ticLength[1] * scaleFactor; } for (int i = 0; i < numTics[1]; i++) { pointOnAxis[1] = minTic[1] + (float)i * (maxTic[1] - minTic[1]) / (float)(numTics[1] - 1); vsub(pointOnAxis, ticVec, startPosn); vadd(pointOnAxis, ticVec, endPosn); _drawTic(startPosn, endPosn, width, axisColor); double xValue = pointOnAxis[0]; double yValue = pointOnAxis[1]; if (latLon) convertPointToLonLat(xValue, yValue); renderText(yValue, startPosn, aa); } // Now draw tic marks for z: pointOnAxis[0] = origin[0]; pointOnAxis[1] = origin[1]; ticVec[0] = 0.f; ticVec[1] = 0.f; ticVec[2] = 0.f; if (ticDir[2] == 1) { // Y orientation scaleFactor = extents[4] - extents[1]; ticVec[1] = ticLength[2] * scaleFactor; } else { // X orientation scaleFactor = extents[3] - extents[0]; ticVec[0] = ticLength[2] * scaleFactor; } for (int i = 0; i < numTics[2]; i++) { pointOnAxis[2] = minTic[2] + (float)i * (maxTic[2] - minTic[2]) / (float)(numTics[2] - 1); vsub(pointOnAxis, ticVec, startPosn); vadd(pointOnAxis, ticVec, endPosn); _drawTic(startPosn, endPosn, width, axisColor); renderText(pointOnAxis[2], startPosn, aa); } } void AnnotationRenderer::_drawAxes(std::vector min, std::vector max, std::vector origin, std::vector color, double width) { LegacyGL *lgl = _glManager->legacy; glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); lgl->Color4f(color[0], color[1], color[2], color[3]); // glLineWidth(width); glEnable(GL_LINE_SMOOTH); lgl->Begin(GL_LINES); lgl->Vertex3f(min[0], origin[1], origin[2]); lgl->Vertex3f(max[0], origin[1], origin[2]); lgl->Vertex3f(origin[0], min[1], origin[2]); lgl->Vertex3f(origin[0], max[1], origin[2]); lgl->Vertex3f(origin[0], origin[1], min[2]); lgl->Vertex3f(origin[0], origin[1], max[2]); lgl->End(); glDisable(GL_LINE_SMOOTH); } void AnnotationRenderer::_drawTic(double startPosn[], double endPosn[], double width, std::vector color) { LegacyGL *lgl = _glManager->legacy; lgl->Color4f(color[0], color[1], color[2], color[3]); // glLineWidth(width); glEnable(GL_LINE_SMOOTH); lgl->Begin(GL_LINES); lgl->Vertex3dv(startPosn); lgl->Vertex3dv(endPosn); lgl->End(); glDisable(GL_LINE_SMOOTH); } void AnnotationRenderer::convertPointToLonLat(double &xCoord, double &yCoord) { double coords[2] = {xCoord, yCoord}; double coordsForError[2] = {coords[0], coords[1]}; string projString = m_dataStatus->GetMapProjection(); int rc = DataMgrUtils::ConvertPCSToLonLat(projString, coords, 1); if (!rc) { MyBase::SetErrMsg("Could not convert point %f, %f to Lon/Lat", coordsForError[0], coordsForError[1]); } xCoord = coords[0]; yCoord = coords[1]; } Transform *AnnotationRenderer::getTransform(string dataMgrName) { if (dataMgrName == "") dataMgrName = getCurrentDataMgrName(); ViewpointParams *vpParams = m_paramsMgr->GetViewpointParams(m_winName); vector names = m_paramsMgr->GetDataMgrNames(); Transform * t = vpParams->GetTransform(names[0]); return t; } AxisAnnotation *AnnotationRenderer::getCurrentAxisAnnotation() { AnnotationParams *vfParams = m_paramsMgr->GetAnnotationParams(m_winName); string currentAxisDataMgr = vfParams->GetCurrentAxisDataMgrName(); AxisAnnotation * aa = vfParams->GetAxisAnnotation(); return aa; } string AnnotationRenderer::getCurrentDataMgrName() const { AnnotationParams *vfParams = m_paramsMgr->GetAnnotationParams(m_winName); string currentAxisDataMgr = vfParams->GetCurrentAxisDataMgrName(); return currentAxisDataMgr; } std::vector AnnotationRenderer::getDomainExtents() const { CoordType minExts, maxExts; m_dataStatus->GetActiveExtents(m_paramsMgr, _currentTimestep, minExts, maxExts); std::vector extents; for (int i = 0; i < minExts.size(); i++) { extents.push_back(minExts[i]); } for (int i = 0; i < maxExts.size(); i++) { extents.push_back(maxExts[i]); } return extents; } void AnnotationRenderer::renderText(double text, double coord[], AxisAnnotation *aa) { if (aa == NULL) aa = getCurrentAxisAnnotation(); std::vector axisColor = aa->GetAxisColor(); std::vector backgroundColor = aa->GetAxisBackgroundColor(); int fontSize = aa->GetAxisFontSize(); int precision = (int)aa->GetAxisDigits(); std::stringstream ss; ss << fixed << setprecision(precision) << text; string textString = ss.str(); TextLabel label(_glManager, _fontName, fontSize); label.HorizontalAlignment = TextLabel::Center; label.VerticalAlignment = TextLabel::Top; label.Padding = fontSize / 4.f; label.ForegroundColor = glm::vec4(axisColor[0], axisColor[1], axisColor[2], axisColor[3]); label.BackgroundColor = glm::vec4(backgroundColor[0], backgroundColor[1], backgroundColor[2], 1.); label.DrawText(glm::vec3(coord[0], coord[1], coord[2]), textString); } // Find the world corrdinates of the user-selected screen coordinates, and translate the current matrix to that point // void AnnotationRenderer::_configureMatrixForArrows(MatrixManager *matrixManager) { matrixManager->MatrixModeModelView(); matrixManager->PushMatrix(); // Calculate the pixel location on the screen from the user's value, which is between 0 and 1 // AnnotationParams *vfParams = m_paramsMgr->GetAnnotationParams(m_winName); double winX = vfParams->GetAxisArrowXPos(); // X position of arrows, between 0 and 1 double winY = vfParams->GetAxisArrowYPos(); // Y position of arrows, between 0 and 1 // Scale the Params values by the window width/height std::vector viewport = _glManager->GetViewport(); winX = winX * viewport[2]; // viewport[2] is window width winY = winY * viewport[3]; // viewport[3] is window hight // Gather parameters for glm::unProject // // glm::unProject requires glm::mat4 for the modelview and projection matrices, so we need to // convert from vapor's array representation to glm::mat4 double modelview[16], projection[16]; _glManager->matrixManager->GetDoublev(MatrixManager::Mode::ModelView, modelview); _glManager->matrixManager->GetDoublev(MatrixManager::Mode::Projection, projection); glm::mat4 mat4modelview = glm::make_mat4(modelview); glm::mat4 mat4projection = glm::make_mat4(projection); // glm::unProject requres a glm::vec4 for the viewport, so we need to convert it from its std::vector glm::vec4 vec4viewport(viewport[0], viewport[1], viewport[2], viewport[3]); // Now un-project to find the world coordinates of the selected pixel, and and translate to it for drawing // glm::vec3 win = {winX, winY, .5}; glm::vec3 coords = glm::unProject(win, mat4modelview, mat4projection, vec4viewport); _glManager->matrixManager->Translate(coords[0], coords[1], coords[2]); // Finally, apply an scale factor that cancels the scaling done when zooming in and out, so that the arrows // retain a constant size on the screen. This code was derived from // https://gamedev.stackexchange.com/questions/24968/constant-size-geometries with the exception of using // glm::unproject instead of the deprecated gluUnProject function. // const double fov = m_paramsMgr->GetViewpointParams(m_winName)->GetFOV(); double cameraPosD[3], cameraUpD[3], cameraDirD[3]; m_paramsMgr->GetViewpointParams(m_winName)->ReconstructCamera(modelview, cameraPosD, cameraUpD, cameraDirD); glm::vec3 cameraPos = glm::vec3(cameraPosD[0], cameraPosD[1], cameraPosD[2]); float cameraObjectDistance = sqrt(pow(cameraPos[0] - coords[0], 2) + pow(cameraPos[1] - coords[1], 2) + pow(cameraPos[2] - coords[2], 2)); float worldSize = (2 * tan(fov / 2.0)) * cameraObjectDistance; float size = vfParams->GetAxisArrowSize() * worldSize * ARROW_SCALE_FACTOR; matrixManager->Scale(size, size, size); } void AnnotationRenderer::DrawAxisArrows() { AnnotationParams *vfParams = m_paramsMgr->GetAnnotationParams(m_winName); if (!vfParams->GetAxisArrowEnabled()) { return; } LegacyGL * lgl = _glManager->legacy; MatrixManager *mm = _glManager->matrixManager; _configureMatrixForArrows(mm); glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); // Begin drawing // glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); lgl->Color3f(1, 0, 0); glEnable(GL_LINE_SMOOTH); lgl->Begin(GL_LINES); lgl->Vertex3f(0, 0, 0); lgl->Vertex3f(1, 0, 0); lgl->End(); lgl->Begin(GL_TRIANGLES); lgl->Vertex3f(1, 0, 0); lgl->Vertex3f(.8, .1, 0); lgl->Vertex3f(.8, 0, .1); lgl->Vertex3f(1, 0, 0); lgl->Vertex3f(.8, 0, .1); lgl->Vertex3f(.8, -.1, 0); lgl->Vertex3f(1, 0, 0); lgl->Vertex3f(.8, -.1, 0); lgl->Vertex3f(.8, 0, -.1); lgl->Vertex3f(1, 0, 0); lgl->Vertex3f(.8, 0, -.1); lgl->Vertex3f(.8, .1, 0); lgl->End(); lgl->Color3f(0, 1, 0); lgl->Begin(GL_LINES); lgl->Vertex3f(0, 0, 0); lgl->Vertex3f(0, 1, 0); lgl->End(); lgl->Begin(GL_TRIANGLES); lgl->Vertex3f(0, 1, 0); lgl->Vertex3f(.1, .8, 0); lgl->Vertex3f(0, .8, .1); lgl->Vertex3f(0, 1, 0); lgl->Vertex3f(0, .8, .1); lgl->Vertex3f(-.1, .8, 0); lgl->Vertex3f(0, 1, 0); lgl->Vertex3f(-.1, .8, 0); lgl->Vertex3f(0, .8, -.1); lgl->Vertex3f(0, 1, 0); lgl->Vertex3f(0, .8, -.1); lgl->Vertex3f(.1, .8, 0); lgl->End(); lgl->Color3f(0, 0.3, 1); lgl->Begin(GL_LINES); lgl->Vertex3f(0, 0, 0); lgl->Vertex3f(0, 0, 1); lgl->End(); lgl->Begin(GL_TRIANGLES); lgl->Vertex3f(0, 0, 1); lgl->Vertex3f(.1, 0, .8); lgl->Vertex3f(0, .1, .8); lgl->Vertex3f(0, 0, 1); lgl->Vertex3f(0, .1, .8); lgl->Vertex3f(-.1, 0, .8); lgl->Vertex3f(0, 0, 1); lgl->Vertex3f(-.1, 0, .8); lgl->Vertex3f(0, -.1, .8); lgl->Vertex3f(0, 0, 1); lgl->Vertex3f(0, -.1, .8); lgl->Vertex3f(.1, 0, .8); lgl->End(); glDepthRange(0, 1.0); mm->PopMatrix(); glDisable(GL_LINE_SMOOTH); } ================================================ FILE: lib/render/BarbRenderer.cpp ================================================ //************************************************************* // // Copyright (C) 2017 // University Corporation for Atmospheric Research // All Rights Reserved // // ************************************************************ // Specify the barbhead width compared with barb diameter: #define BARB_HEAD_FACTOR 3.0 // Specify how long the barb tube is, in front of where the // barbhead is attached: #define BARB_LENGTH_FACTOR 0.9 // Specify the maximum cylinder radius in proportion to the // hypotenuse of the domain, divided by 4 (the maximum barb thicness param) // I.E. if the user sets the thickness to 4 (the maximum), then the // barbs will have max radius = 4 * BARB_RADIUS_TO_HYPOTENUSE * hypotenuse //#define BARB_RADIUS_TO_HYPOTENUSE .00625 #define BARB_RADIUS_TO_HYPOTENUSE .001875 // Specify the maximum barb length in proportion to the // hypotenuse of the domain, divided by 4 (the maximum barb length param) // I.E. if the user sets the length to 4 (the maximum), then the longest // barb will have max length = 4 * BARB_LENGTH_TO_HYPOTENUSE * hypotenuse #define BARB_LENGTH_TO_HYPOTENUSE .0625 #include // Must be included first!!! #include #include #include #include #ifndef WIN32 #include #endif #include #include #include #include #include #include #include #include #include #define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH #include #include "vapor/LegacyGL.h" #include "vapor/GLManager.h" #include #define X 0 #define Y 1 #define Z 2 #define XMIN 0 #define YMIN 1 #define ZMIN 2 #define XMAX 3 #define YMAX 4 #define ZMAX 5 int counter = 0; using namespace VAPoR; using namespace Wasp; static RendererRegistrar registrar(BarbRenderer::GetClassType(), BarbParams::GetClassType()); BarbRenderer::BarbRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr) : Renderer(pm, winName, dataSetName, BarbParams::GetClassType(), BarbRenderer::GetClassType(), instName, dataMgr) { _fieldVariables.clear(); _vectorScaleFactor = .2; _maxThickness = .2; _maxValue = 0.f; } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- BarbRenderer::~BarbRenderer() {} std::string BarbRenderer::_getColorbarVariableName() const { RenderParams *rParams = GetActiveParams(); return rParams->GetColorMapVariableName(); } // Totally unnecessary? // int BarbRenderer::_initializeGL() { //_initialized = true; return (0); } void BarbRenderer::_saveCacheParams() { BarbParams *p = dynamic_cast(GetActiveParams()); VAssert(p); _cacheParams.fieldVarNames = p->GetFieldVariableNames(); _cacheParams.heightVarName = p->GetHeightVariableName(); _cacheParams.colorVarName = p->GetColorMapVariableName(); _cacheParams.ts = p->GetCurrentTimestep(); _cacheParams.level = p->GetRefinementLevel(); _cacheParams.lod = p->GetCompressionLevel(); _cacheParams.grid = p->GetGrid(); _cacheParams.needToRecalc = p->GetNeedToRecalculateScales(); _cacheParams.useSingleColor = p->UseSingleColor(); p->GetBox()->GetExtents(_cacheParams.boxMin, _cacheParams.boxMax); } bool BarbRenderer::_isCacheDirty() const { BarbParams *p = dynamic_cast(GetActiveParams()); VAssert(p); if (_cacheParams.fieldVarNames != p->GetFieldVariableNames()) return true; if (_cacheParams.heightVarName != p->GetHeightVariableName()) return true; if (_cacheParams.colorVarName != p->GetColorMapVariableName()) return true; if (_cacheParams.ts != p->GetCurrentTimestep()) return true; if (_cacheParams.level != p->GetRefinementLevel()) return true; if (_cacheParams.lod != p->GetCompressionLevel()) return true; if (_cacheParams.grid != p->GetGrid()) return true; if (_cacheParams.needToRecalc != p->GetNeedToRecalculateScales()) return true; if (_cacheParams.useSingleColor != p->UseSingleColor()) return true; vector min, max, contourValues; p->GetBox()->GetExtents(min, max); if (_cacheParams.boxMin != min) return true; if (_cacheParams.boxMax != max) return true; return false; } void BarbRenderer::_recalculateScales( // std::vector varnames, std::vector &varData, int ts) { BarbParams *bParams = dynamic_cast(GetActiveParams()); VAssert(bParams); vector varnames = bParams->GetFieldVariableNames(); bool recalculateScales = bParams->GetNeedToRecalculateScales(); if (varnames != _fieldVariables || recalculateScales) { //_setDefaultLengthAndThicknessScales(ts, varnames, bParams); _setDefaultLengthAndThicknessScales(ts, varData, bParams); _fieldVariables = varnames; bParams->SetNeedToRecalculateScales(false); } } int BarbRenderer::_getVectorVarGrids(int ts, int refLevel, int lod, CoordType minExts, CoordType maxExts, std::vector &varData) { BarbParams *bParams = dynamic_cast(GetActiveParams()); VAssert(bParams); vector varnames = bParams->GetFieldVariableNames(); if (!VariableExists(ts, varnames, refLevel, lod, true)) { SetErrMsg("One or more selected field variables does not exist"); return -1; } // Get grids for our vector variables // int rc = DataMgrUtils::GetGrids(_dataMgr, ts, varnames, minExts, maxExts, true, &refLevel, &lod, varData); return rc; } void BarbRenderer::_getGridRequirements(int &ts, int &refLevel, int &lod, CoordType &minExts, CoordType &maxExts) const { BarbParams *bParams = dynamic_cast(GetActiveParams()); VAssert(bParams); ts = bParams->GetCurrentTimestep(); refLevel = bParams->GetRefinementLevel(); lod = bParams->GetCompressionLevel(); bParams->GetBox()->GetExtents(minExts, maxExts); } int BarbRenderer::_getVarGrid(int ts, int refLevel, int lod, string varName, CoordType minExts, CoordType maxExts, std::vector &varData) { Grid *sg = NULL; varData.push_back(sg); if (!varName.empty()) { int rc = DataMgrUtils::GetGrids(_dataMgr, ts, varName, minExts, maxExts, true, &refLevel, &lod, &sg); if (rc < 0) { return (rc); } varData[varData.size() - 1] = sg; } return 0; } int BarbRenderer::_paintGL(bool) { if (_isCacheDirty()) { if (_generateBarbs() < 0) return -1; _saveCacheParams(); } glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); _setUpLightingAndColor(); float clut[1024]; bool doColorMapping = _makeCLUT(clut); auto crange = GetActiveParams()->GetMapperFunc(GetActiveParams()->GetColorMapVariableName())->getMinMaxMapValue(); for (auto b : _barbCache) _drawBarb(b, doColorMapping, clut, crange.data()); _glManager->legacy->DisableLighting(); return 0; } int BarbRenderer::_generateBarbs() { int rc; // Set up the variable data required, while determining data // extents to use in rendering // vector varData; int ts, refLevel, lod; CoordType minExts, maxExts; _getGridRequirements(ts, refLevel, lod, minExts, maxExts); // Get vector variables rc = _getVectorVarGrids(ts, refLevel, lod, minExts, maxExts, varData); if (rc < 0) { SetErrMsg("One or more selected field variables does not exist"); return -1; } BarbParams *bParams = dynamic_cast(GetActiveParams()); VAssert(bParams); // Get height variable string heightVar = bParams->GetHeightVariableName(); rc = _getVarGrid(ts, refLevel, lod, heightVar, minExts, maxExts, varData); if (rc < 0) { SetErrMsg("Height variable does not exist"); return -1; } // Get color variable string colorVar = bParams->GetColorMapVariableName(); rc = _getVarGrid(ts, refLevel, lod, colorVar, minExts, maxExts, varData); if (rc < 0) { SetErrMsg("Color variable does not exist"); return -1; } _recalculateScales(varData, ts); _barbCache.clear(); // Render the barbs _operateOnGrid(varData); return (rc); } float BarbRenderer::_calculateDirVec(const float start[3], const float end[3], float dirVec[3]) { vsub(end, start, dirVec); float len = vlength(dirVec); if (len != 0.f) vscale(dirVec, 1. / len); return len; } void BarbRenderer::_drawBackOfBarb(const float dirVec[3], const float startVertex[3]) const { // TODO GL /* glBegin(GL_POLYGON); glNormal3fv(dirVec); for (int k = 0; k<6; k++){ glVertex3fv(startVertex+3*k); } glEnd(); */ } void BarbRenderer::_drawCylinderSides(const float nextNormal[3], const float nextVertex[3], const float startNormal[3], const float startVertex[3]) const { LegacyGL *lgl = _glManager->legacy; lgl->Begin(GL_TRIANGLE_STRIP); for (int i = 0; i < 6; i++) { lgl->Normal3fv(nextNormal + 3 * i); lgl->Vertex3fv(nextVertex + 3 * i); lgl->Normal3fv(startNormal + 3 * i); lgl->Vertex3fv(startVertex + 3 * i); } // repeat first two vertices to close cylinder: lgl->Normal3fv(nextNormal); lgl->Vertex3fv(nextVertex); lgl->Normal3fv(startNormal); lgl->Vertex3fv(startVertex); lgl->End(); } void BarbRenderer::_drawBarbHead(const float dirVec[3], const float vertexPoint[3], const float startNormal[3], const float startVertex[3]) const { LegacyGL *lgl = _glManager->legacy; // Create a triangle fan from these 6 vertices. lgl->Begin(GL_TRIANGLE_FAN); lgl->Normal3fv(dirVec); lgl->Vertex3fv(vertexPoint); for (int i = 0; i < 6; i++) { lgl->Normal3fv(startNormal + 3 * i); lgl->Vertex3fv(startVertex + 3 * i); } // Repeat first point to close fan: lgl->Normal3fv(startNormal); lgl->Vertex3fv(startVertex); lgl->End(); } #ifdef DEBUG void BarbRenderer::_printBackDiameter(const float startVertex[18]) const { float pointA[3] = {startVertex[0], startVertex[1], startVertex[2]}; float pointB[3] = {startVertex[3], startVertex[4], startVertex[5]}; float pointC[3] = {startVertex[6], startVertex[7], startVertex[8]}; float pointD[3] = {startVertex[9], startVertex[10], startVertex[11]}; float pointE[3] = {startVertex[12], startVertex[13], startVertex[14]}; float pointF[3] = {startVertex[15], startVertex[16], startVertex[17]}; cout << " " << pointA[0] << "\t\t" << pointB[0] << "\t\t\t" << pointC[0]; cout << "\t\t" << pointD[0] << "\t\t" << pointE[0] << "\t\t" << pointF[0] << endl; cout << " " << pointA[1] << "\t\t" << pointB[1] << "\t\t" << pointC[1]; cout << "\t" << pointD[1] << "\t" << pointE[1] << "\t\t" << pointF[1] << endl; cout << " " << pointA[2] << "\t\t" << pointB[2] << "\t\t" << pointC[2]; cout << "\t\t" << pointD[2] << "\t\t" << pointE[2] << "\t\t" << pointF[2] << endl; cout << "Back Diameter " << _calculateLength(pointA, pointD) << endl; } #endif // Issue OpenGL calls to draw a cylinder with orthogonal ends from // one point to another. Then put an barb head on the end // void BarbRenderer::_drawBarb(const std::vector variableData, const float startPoint_[3], bool doColorMapping, const float clut[1024]) { Barb b; memcpy(b.startPoint, startPoint_, sizeof(float) * 3); b.lengthScalar = ((BarbParams *)GetActiveParams())->GetLengthScale() * _vectorScaleFactor; VAssert(variableData.size() == 5); bool missing = _defineBarb(variableData, b.startPoint, b.endPoint, &b.value, doColorMapping, clut); if (missing) return; _barbCache.push_back(b); } void BarbRenderer::_setBarbColor(float value, const float clut[1024], double crange[2]) const { float range = crange[1] - crange[0]; float n = (value - crange[0]) / range; n = glm::clamp(n, 0.f, 1.f); int i = 255 * n; _glManager->legacy->Color4fv(&clut[i * 4]); } void BarbRenderer::_drawBarb(Barb b, bool doColorMapping, const float clut[1024], double crange[2]) { float * startPoint = b.startPoint; float * endPoint = b.endPoint; MatrixManager *mm = _glManager->matrixManager; if (doColorMapping) _setBarbColor(b.value, clut, crange); float newLengthScalar = ((BarbParams *)GetActiveParams())->GetLengthScale() * _vectorScaleFactor; glm::vec3 v = glm::make_vec3(b.endPoint) - glm::make_vec3(b.startPoint); float l = glm::length(v) / b.lengthScalar * newLengthScalar; glm::vec3 end = glm::make_vec3(b.startPoint) + glm::normalize(v) * l; memcpy(b.endPoint, glm::value_ptr(end), sizeof(float) * 3); mm->MatrixModeModelView(); mm->PushMatrix(); mm->Translate(startPoint[0], startPoint[1], startPoint[2]); endPoint[0] -= startPoint[0]; endPoint[1] -= startPoint[1]; endPoint[2] -= startPoint[2]; startPoint[0] = startPoint[1] = startPoint[2] = 0; vector scales = _getScales(); mm->Scale(1.f / scales[0], 1.f / scales[1], 1.f / scales[2]); // Constants are needed for cosines and sines, at // 60 degree intervals. The barb is really a hexagonal tube, // but the shading makes it look round. const float sines[6] = {0.f, (float)(sqrt(3.) / 2.), (float)(sqrt(3.) / 2.), 0.f, (float)(-sqrt(3.) / 2.), (float)(-sqrt(3.) / 2.)}; const float coses[6] = {1.f, 0.5, -0.5, -1., -.5, 0.5}; float nextPoint[3]; float vertexPoint[3]; float headCenter[3]; float startNormal[18]; float nextNormal[18]; float startVertex[18]; float nextVertex[18]; float testVec[3]; float testVec2[3]; // Calculate an orthonormal frame // dirVec is the barb direction float dirVec[3]; float len = _calculateDirVec(startPoint, endPoint, dirVec); // Calculate uVec, orthogonal to dirVec // Not sure what bVec is. Up direction? float uVec[3], bVec[3]; vset(testVec, 1., 0., 0.); vcross(dirVec, testVec, uVec); len = vdot(uVec, uVec); if (len == 0.f) { vset(testVec, 0., 1., 0.); vcross(dirVec, testVec, uVec); len = vdot(uVec, uVec); } vscale(uVec, 1.f / sqrt(len)); vcross(uVec, dirVec, bVec); BarbParams *bParams = dynamic_cast(GetActiveParams()); VAssert(bParams); float radius = bParams->GetLineThickness() * _maxThickness; // calculate 6 points in plane orthog to dirVec, in plane of point for (int i = 0; i < 6; i++) { // testVec and testVec2 are components of point in plane vmult(uVec, coses[i], testVec); vmult(bVec, sines[i], testVec2); // Calc outward normal as a sideEffect.. // It is the vector sum of x,y components (norm 1) vadd(testVec, testVec2, startNormal + 3 * i); // stretch by radius to get current displacement vmult(startNormal + 3 * i, radius, startVertex + 3 * i); // add to current point vadd(startVertex + 3 * i, startPoint, startVertex + 3 * i); } #ifdef DEBUG _printBackDiameter(startVertex); #endif _drawBackOfBarb(dirVec, startVertex); // The variables are located as follows: // - - - - > // ^ ^ ^ // start next end // Calculate nextPoint and vertexPoint, for barbhead for (int i = 0; i < 3; i++) { nextPoint[i] = (1. - BARB_LENGTH_FACTOR) * startPoint[i] + BARB_LENGTH_FACTOR * endPoint[i]; // Assume a vertex angle of 45 degrees: vertexPoint[i] = nextPoint[i] + dirVec[i] * radius; headCenter[i] = nextPoint[i] - dirVec[i] * (BARB_HEAD_FACTOR * radius - radius); } // calc for endpoints: for (int i = 0; i < 6; i++) { // testVec and testVec2 are components of point in plane vmult(uVec, coses[i], testVec); vmult(bVec, sines[i], testVec2); // Calc outward normal as a sideEffect.. // It is the vector sum of x,y components (norm 1) vadd(testVec, testVec2, nextNormal + 3 * i); // stretch by radius to get current displacement vmult(nextNormal + 3 * i, radius, nextVertex + 3 * i); // add to current point vadd(nextVertex + 3 * i, nextPoint, nextVertex + 3 * i); } _drawCylinderSides(nextNormal, nextVertex, startNormal, startVertex); // Now draw the barb head. First calc 6 vertices at back of barbhead // Reuse startNormal and startVertex vectors // calc for endpoints: for (int i = 0; i < 6; i++) { // testVec and testVec2 are components of point in plane // Can reuse them from previous (cylinder end) calculation vmult(uVec, coses[i], testVec); vmult(bVec, sines[i], testVec2); // Calc outward normal as a sideEffect.. // It is the vector sum of x,y components (norm 1) vadd(testVec, testVec2, startNormal + 3 * i); // stretch by radius to get current displacement vmult(startNormal + 3 * i, BARB_HEAD_FACTOR * radius, startVertex + 3 * i); // add to current point vadd(startVertex + 3 * i, headCenter, startVertex + 3 * i); // Now tilt normals in direction of barb: for (int k = 0; k < 3; k++) { startNormal[3 * i + k] = 0.5 * startNormal[3 * i + k] + 0.5 * dirVec[k]; } } _drawBarbHead(dirVec, vertexPoint, startNormal, startVertex); mm->PopMatrix(); } void BarbRenderer::_setUpLightingAndColor() { LegacyGL * lgl = _glManager->legacy; string winName = GetVisualizer(); // GetVisualizer is not const :( ViewpointParams *vpParams = _paramsMgr->GetViewpointParams(winName); int nLights = vpParams->getNumLights(); float fcolor[3]; BarbParams *bParams = dynamic_cast(GetActiveParams()); VAssert(bParams); bParams->GetConstantColor(fcolor); if (nLights == 0 || !bParams->GetValueLong(RenderParams::LightingEnabledTag, 0)) { lgl->DisableLighting(); } else { // All the geometry will get a white specular color: float specColor[4]; specColor[0] = specColor[1] = specColor[2] = 0.8f; specColor[3] = 1.f; lgl->EnableLighting(); double m[16]; double cameraPosD[3], cameraUpD[3], cameraDirD[3]; _paramsMgr->GetViewpointParams(_winName)->GetModelViewMatrix(m); _paramsMgr->GetViewpointParams(_winName)->ReconstructCamera(m, cameraPosD, cameraUpD, cameraDirD); // Why do we need to invert the lighting direction here? Are the barb normals backwards or something? float cameraDirF[3] = {(float)cameraDirD[0]*-1, (float)cameraDirD[1]*-1, (float)cameraDirD[2]*-1}; lgl->LightDirectionfv(cameraDirF); } lgl->Color3fv(fcolor); } void BarbRenderer::_reFormatExtents(vector &rakeExts) const { rakeExts.clear(); BarbParams *bParams = dynamic_cast(GetActiveParams()); VAssert(bParams); vector rMinExtents, rMaxExtents; bParams->GetBox()->GetExtents(rMinExtents, rMaxExtents); bool planar = bParams->GetBox()->IsPlanar(); rakeExts.push_back(rMinExtents[X]); rakeExts.push_back(rMinExtents[Y]); rakeExts.push_back(planar ? GetDefaultZ(_dataMgr, bParams->GetCurrentTimestep()) : rMinExtents[Z]); rakeExts.push_back(rMaxExtents[X]); rakeExts.push_back(rMaxExtents[Y]); rakeExts.push_back(planar ? GetDefaultZ(_dataMgr, bParams->GetCurrentTimestep()) : rMaxExtents[Z]); } void BarbRenderer::_makeRakeGrid(vector &rakeGrid) const { rakeGrid.clear(); BarbParams *bParams = dynamic_cast(GetActiveParams()); VAssert(bParams); vector longGrid = bParams->GetGrid(); rakeGrid.push_back((int)longGrid[X]); rakeGrid.push_back((int)longGrid[Y]); rakeGrid.push_back((int)longGrid[Z]); } float BarbRenderer::_getHeightOffset(Grid *heightVar, float xCoord, float yCoord, bool &missing) const { VAssert(heightVar); float missingVal = heightVar->GetMissingValue(); float offset = heightVar->GetValue(xCoord, yCoord, 0.f); if (offset == missingVal) { missing = true; offset = 0.f; } BarbParams* p = (BarbParams *)GetActiveParams(); offset -= GetDefaultZ(_dataMgr, p->GetCurrentTimestep()); return offset; } void BarbRenderer::_getDirection(float direction[3], vector variableData, float xCoord, float yCoord, float zCoord, bool &missing) const { for (int dim = 0; dim < 3; dim++) { direction[dim] = 0.f; if (variableData[dim]) { direction[dim] = variableData[dim]->GetValue(xCoord, yCoord, zCoord); float missingVal = variableData[dim]->GetMissingValue(); if (direction[dim] == missingVal) { missing = true; } } } } bool BarbRenderer::_makeCLUT(float clut[1024]) const { BarbParams *bParams = dynamic_cast(GetActiveParams()); VAssert(bParams); string colorVar = bParams->GetColorMapVariableName(); bool doColorMapping = !bParams->UseSingleColor() && !colorVar.empty(); if (doColorMapping) { MapperFunction *tf = 0; tf = (MapperFunction *)bParams->GetMapperFunc(colorVar); VAssert(tf); tf->makeLut(clut); } return doColorMapping; } vector BarbRenderer::_getScales() { string myVisName = GetVisualizer(); // Not const :( VAPoR::ViewpointParams *vpp = _paramsMgr->GetViewpointParams(myVisName); string datasetName = GetMyDatasetName(); Transform * tDataset = vpp->GetTransform(datasetName); Transform * tRenderer = GetActiveParams()->GetTransform(); vector scales = tDataset->GetScales(); vector rendererScales = tRenderer->GetScales(); scales[0] *= rendererScales[0]; scales[1] *= rendererScales[1]; scales[2] *= rendererScales[2]; return scales; } float BarbRenderer::_calculateLength(float start[3], float end[3]) const { float xDist = start[X] - end[X]; float yDist = start[Y] - end[Y]; float zDist = start[Z] - end[Z]; float length = sqrt(xDist * xDist + yDist * yDist + zDist * zDist); return length; } void BarbRenderer::_makeStartAndEndPoint(float start[3], float end[3], float direction[3]) { BarbParams *bParams = dynamic_cast(GetActiveParams()); VAssert(bParams); float length = bParams->GetLengthScale() * _vectorScaleFactor; vector scales = _getScales(); end[X] = start[X] + scales[X] * direction[X] * length; end[Y] = start[Y] + scales[Y] * direction[Y] * length; end[Z] = start[Z] + scales[Z] * direction[Z] * length; } void BarbRenderer::_getStrides(vector &strides, vector &rakeGrid, vector &rakeExts) const { strides.clear(); float xStride = (rakeExts[XMAX] - rakeExts[XMIN]) / ((float)rakeGrid[X] + 1); strides.push_back(xStride); float yStride = (rakeExts[YMAX] - rakeExts[YMIN]) / ((float)rakeGrid[Y] + 1); strides.push_back(yStride); float zStride = (rakeExts[ZMAX] - rakeExts[ZMIN]) / ((float)rakeGrid[Z] + 1); strides.push_back(zStride); } bool BarbRenderer::_defineBarb(const std::vector variableData, float start[3], float end[3], float *value, bool doColorMapping, const float clut[1024]) { bool missing = false; Grid *heightVar = variableData[3]; if (heightVar) { start[Z] += _getHeightOffset(heightVar, start[X], start[Y], missing); } float direction[3] = {0.f, 0.f, 0.f}; _getDirection(direction, variableData, start[X], start[Y], start[Z], missing); _makeStartAndEndPoint(start, end, direction); if (doColorMapping) { float val = variableData[4]->GetValue(start[X], start[Y], start[Z]); *value = val; if (val == variableData[4]->GetMissingValue()) missing = true; else { missing = _getColorMapping(val, clut); } } return missing; } void BarbRenderer::_operateOnGrid(vector variableData, bool drawBarb) { vector rakeGrid; _makeRakeGrid(rakeGrid); vector rakeExts; _reFormatExtents(rakeExts); vector strides; _getStrides(strides, rakeGrid, rakeExts); float clut[1024]; bool doColorMapping = _makeCLUT(clut); float start[3]; for (int i = 1; i <= rakeGrid[X]; i++) { start[X] = strides[X] * i + rakeExts[X]; // + xStride/2.0; for (int j = 1; j <= rakeGrid[Y]; j++) { start[Y] = strides[Y] * j + rakeExts[Y]; // + yStride/2.0; for (int k = 1; k <= rakeGrid[Z]; k++) { start[Z] = strides[Z] * k + rakeExts[Z]; //+ zStride/2.0; if (drawBarb) { _drawBarb(variableData, start, doColorMapping, clut); } else { _getMagnitudeAtPoint(variableData, start); } } } } return; } void BarbRenderer::_getMagnitudeAtPoint(std::vector variables, float point[3]) { VAPoR::Grid *grid; double maxValue = 0.f; for (int i = 0; i < 3; i++) { grid = variables[i]; if (grid == NULL) continue; else { double value = grid->GetValue(point[X], point[Y], point[Z]); double missingValue = grid->GetMissingValue(); if (value == missingValue) { continue; } value = abs(value); if (value > maxValue && value < std::numeric_limits::max() && value > std::numeric_limits::lowest() && !std::isnan(value)) maxValue = value; } } if (maxValue > _maxValue) { _maxValue = maxValue; } } bool BarbRenderer::_getColorMapping(float val, const float clut[256 * 4]) { bool missing = false; MapperFunction *tf = 0; BarbParams * bParams = dynamic_cast(GetActiveParams()); VAssert(bParams); string colorVar = bParams->GetColorMapVariableName(); tf = (MapperFunction *)bParams->GetMapperFunc(colorVar); VAssert(tf); float mappedColor[4] = {0., 0., 0., 0.}; // Use the transfer function to map the data: int lutIndex = tf->mapFloatToIndex(val); for (int i = 0; i < 4; i++) mappedColor[i] = clut[4 * lutIndex + i]; _glManager->legacy->Color4fv(mappedColor); return missing; } double BarbRenderer::_getDomainHypotenuse(size_t ts) const { std::vector axes; CoordType minExts, maxExts; std::vector varNames; BarbParams *p = dynamic_cast(GetActiveParams()); VAssert(p); varNames = p->GetFieldVariableNames(); bool status = DataMgrUtils::GetExtents(_dataMgr, ts, varNames, 0, 0, minExts, maxExts, axes); VAssert(status); if (varNames[0] == "" && varNames[1] == "" && varNames[2] == "") return 0.0; double xLen = maxExts[0] - minExts[0]; double yLen = maxExts[1] - minExts[1]; double zLen = maxExts[2] - minExts[2]; double diag = sqrt(xLen * xLen + yLen * yLen + zLen * zLen); return diag; } void BarbRenderer::_setDefaultLengthAndThicknessScales(size_t ts, const std::vector &varData, const BarbParams *bParams) { VAssert(varData.size() >= 3); _maxValue = 0; _operateOnGrid(varData, false); double hypotenuse = _getDomainHypotenuse(ts); if (hypotenuse == 0.f) return; _maxThickness = hypotenuse * BARB_RADIUS_TO_HYPOTENUSE; _vectorScaleFactor = hypotenuse * BARB_LENGTH_TO_HYPOTENUSE; _vectorScaleFactor *= 1.0 / _maxValue; } ================================================ FILE: lib/render/CMakeLists.txt ================================================ set (SRC BarbRenderer.cpp ControlExecutive.cpp VolumeRenderer.cpp VolumeIsoRenderer.cpp HelloRenderer.cpp Renderer.cpp ShaderProgram.cpp TwoDDataRenderer.cpp TwoDRenderer.cpp WireFrameRenderer.cpp GeoTile.cpp GeoTileMercator.cpp GeoTileEquirectangular.cpp GeoImage.cpp GeoImageTMS.cpp GeoImageGeoTiff.cpp ImageRenderer.cpp Visualizer.cpp AnnotationRenderer.cpp jfilewrite.cpp RayCaster.cpp FlowRenderer.cpp ControlExecutive.cpp ContourRenderer.cpp SliceRenderer.cpp MyPython.cpp MatrixManager.cpp Shader.cpp LegacyGL.cpp ShaderManager.cpp GLManager.cpp FontManager.cpp Font.cpp TextLabel.cpp PyEngine.cpp CalcEngineMgr.cpp GeoTIFWriter.cpp ImageWriter.cpp JPGWriter.cpp PNGWriter.cpp TIFWriter.cpp Proj4StringParser.cpp glutil.cpp VolumeAlgorithm.cpp VolumeGLSL.cpp VolumeRegular.cpp VolumeRectilinear.cpp # VolumeResampled.cpp # VolumeTest.cpp # VolumeTest2.cpp VolumeCellTraversal.cpp Texture.cpp Framebuffer.cpp ModelRenderer.cpp OSPRay.cpp ColorbarRenderer.cpp ParticleRenderer.cpp TrackBall.cpp NavigationUtils.cpp Histo.cpp ) set (HEADERS ${PROJECT_SOURCE_DIR}/include/vapor/BarbRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/ControlExecutive.h ${PROJECT_SOURCE_DIR}/include/vapor/HelloRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/VolumeRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/VolumeIsoRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/Renderer.h ${PROJECT_SOURCE_DIR}/include/vapor/ShaderProgram.h ${PROJECT_SOURCE_DIR}/include/vapor/TwoDDataRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/TwoDRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/WireFrameRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/GeoTile.h ${PROJECT_SOURCE_DIR}/include/vapor/GeoTileMercator.h ${PROJECT_SOURCE_DIR}/include/vapor/GeoTileEquirectangular.h ${PROJECT_SOURCE_DIR}/include/vapor/GeoImage.h ${PROJECT_SOURCE_DIR}/include/vapor/GeoImageTMS.h ${PROJECT_SOURCE_DIR}/include/vapor/GeoImageGeoTiff.h ${PROJECT_SOURCE_DIR}/include/vapor/ImageRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/Visualizer.h ${PROJECT_SOURCE_DIR}/include/vapor/AnnotationRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/ControlExecutive.h ${PROJECT_SOURCE_DIR}/include/vapor/ContourRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/MyPython.h ${PROJECT_SOURCE_DIR}/include/vapor/MatrixManager.h ${PROJECT_SOURCE_DIR}/include/vapor/Shader.h ${PROJECT_SOURCE_DIR}/include/vapor/LegacyGL.h ${PROJECT_SOURCE_DIR}/include/vapor/ShaderManager.h ${PROJECT_SOURCE_DIR}/include/vapor/GLManager.h ${PROJECT_SOURCE_DIR}/include/vapor/FontManager.h ${PROJECT_SOURCE_DIR}/include/vapor/Font.h ${PROJECT_SOURCE_DIR}/include/vapor/IResourceManager.h ${PROJECT_SOURCE_DIR}/include/vapor/TextLabel.h ${PROJECT_SOURCE_DIR}/include/vapor/RayCaster.h ${PROJECT_SOURCE_DIR}/include/vapor/FlowRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/PyEngine.h ${PROJECT_SOURCE_DIR}/include/vapor/CalcEngineMgr.h ${PROJECT_SOURCE_DIR}/include/vapor/GeoTIFWriter.h ${PROJECT_SOURCE_DIR}/include/vapor/ImageWriter.h ${PROJECT_SOURCE_DIR}/include/vapor/JPGWriter.h ${PROJECT_SOURCE_DIR}/include/vapor/PNGWriter.h ${PROJECT_SOURCE_DIR}/include/vapor/TIFWriter.h ${PROJECT_SOURCE_DIR}/include/vapor/jpegapi.h ${PROJECT_SOURCE_DIR}/include/vapor/Proj4StringParser.h ${PROJECT_SOURCE_DIR}/include/vapor/SliceRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/glutil.h ${PROJECT_SOURCE_DIR}/include/vapor/VolumeAlgorithm.h ${PROJECT_SOURCE_DIR}/include/vapor/VolumeGLSL.h ${PROJECT_SOURCE_DIR}/include/vapor/VolumeRegular.h ${PROJECT_SOURCE_DIR}/include/vapor/VolumeRectilinear.h # ${PROJECT_SOURCE_DIR}/include/vapor/VolumeResampled.h # ${PROJECT_SOURCE_DIR}/include/vapor/VolumeTest.h # ${PROJECT_SOURCE_DIR}/include/vapor/VolumeTest2.h ${PROJECT_SOURCE_DIR}/include/vapor/VolumeCellTraversal.h ${PROJECT_SOURCE_DIR}/include/vapor/VolumeOSPRay.h ${PROJECT_SOURCE_DIR}/include/vapor/Texture.h ${PROJECT_SOURCE_DIR}/include/vapor/Framebuffer.h ${PROJECT_SOURCE_DIR}/include/vapor/ModelRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/OSPRay.h ${PROJECT_SOURCE_DIR}/include/vapor/ColorbarRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/ParticleRenderer.h ${PROJECT_SOURCE_DIR}/include/vapor/TrackBall.h ${PROJECT_SOURCE_DIR}/include/vapor/NavigationUtils.h ${PROJECT_SOURCE_DIR}/include/vapor/Histo.h ${PROJECT_SOURCE_DIR}/include/vapor/VisualizerGLContextManager.h ) if(BUILD_OSP) set(SRC ${SRC} VolumeOSPRay.cpp ) endif() add_library (render SHARED ${SRC} ${HEADERS}) target_link_libraries (render PUBLIC common vdc params flow osgl ${FTGL} ${FREETYPE} ${GEOTIFF} ${JPEG} ${TIFF} ${ASSIMP}) # Omitted # - ${Python_LIBRARIES} # - ${GLEW} # - ${OPENGL_LIBRARIES} if (APPLE) # Required to load library from python # Binaries using this library need to link python SET_TARGET_PROPERTIES( render PROPERTIES LINK_FLAGS "-undefined dynamic_lookup" ) endif () if (UNIX AND NOT APPLE) target_compile_options(render PRIVATE -Wno-conversion-null) # target_link_libraries (render PUBLIC GLU) endif () if(BUILD_OSP) find_library (OSPRAY ospray HINTS ${OSPRAYDIR}/lib REQUIRED) target_link_libraries (render PUBLIC ${OSPRAY}) target_include_directories (render PUBLIC ${OSPRAYDIR}/include) target_compile_definitions (render PUBLIC BUILD_OSPRAY) endif() add_definitions (-DRENDER_EXPORTS) OpenMPInstall ( TARGETS render DESTINATION ${INSTALL_LIB_DIR} COMPONENT Libraries ) install ( FILES ${HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR} COMPONENT Libraries ) ================================================ FILE: lib/render/CalcEngineMgr.cpp ================================================ #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; using namespace VAPoR; using namespace Wasp; int CalcEngineMgr::AddFunction(string scriptType, string dataSetName, string scriptName, string script, const vector &inputVarNames, const vector &outputVarNames, const vector &outputVarMeshes, bool coordFlag) { if (scriptType != "Python") { SetErrMsg("Unsupported script type %s", scriptType.c_str()); return (-1); } DataMgr *dataMgr = _dataStatus->GetDataMgr(dataSetName); if (!dataMgr) { SetErrMsg("Invalid data set name %s", dataSetName.c_str()); return (-1); } int rc = _pyScripts[dataSetName]->AddFunction(scriptName, script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag); if (rc < 0) return (-1); // If the output variable had a previous definition we need to purge // the variable from the RenderParams mapper functions :-( // vector rParams; _paramsMgr->GetRenderParams(rParams); for (int j = 0; j < rParams.size(); j++) { for (int i = 0; i < outputVarNames.size(); i++) { rParams[j]->RemoveMapperFunc(outputVarNames[i]); } } _paramsMgr->GetDatasetsParams()->SetScript(dataSetName, scriptName, script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag); return (0); } void CalcEngineMgr::RemoveFunction(string scriptType, string dataSetName, string scriptName) { if (scriptType != "Python") return; string script; vector inputVarNames, outputVarNames, inputVarMeshes; bool coordFlag; _paramsMgr->GetDatasetsParams()->GetScript(dataSetName, scriptName, script, inputVarNames, outputVarNames, inputVarMeshes, coordFlag); _paramsMgr->GetDatasetsParams()->RemoveScript(dataSetName, scriptName); SetCacheDirty(); } vector CalcEngineMgr::GetFunctionNames(string scriptType, string dataSetName) { if (scriptType != "Python") return (vector()); return _paramsMgr->GetDatasetsParams()->GetScriptNames(dataSetName); } bool CalcEngineMgr::GetFunctionScript(string scriptType, string dataSetName, string scriptName, string &script, vector &inputVarNames, vector &outputVarNames, vector &outputVarMeshes, bool &coordFlag) { script.clear(); inputVarNames.clear(); outputVarNames.clear(); outputVarMeshes.clear(); if (scriptType != "Python") return (false); return _paramsMgr->GetDatasetsParams()->GetScript(dataSetName, scriptName, script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag); } string CalcEngineMgr::GetFunctionStdout(string scriptType, string dataSetName, string scriptName) { if (scriptType != "Python") return (""); std::map::const_iterator itr; itr = _pyScripts.find(dataSetName); if (itr == _pyScripts.cend()) return (""); PyEngine *pyEngine = itr->second; return (pyEngine->GetFunctionStdout(scriptName)); } CalcEngineMgr::~CalcEngineMgr() { _clean(); } void CalcEngineMgr::_clean() { std::map::iterator itr; while ((itr = _pyScripts.begin()) != _pyScripts.end()) { PyEngine *pyEngine = itr->second; if (pyEngine) delete pyEngine; _pyScripts.erase(itr); } } void CalcEngineMgr::ReinitFromState() { _clean(); SyncWithParams(); SetCacheDirty(); } void CalcEngineMgr::SyncWithParams() { const vector datasetNames = _dataStatus->GetDataMgrNames(); DatasetsParams *datasetsParams = _paramsMgr->GetDatasetsParams(); for (const auto &name : STLUtils::SyncToRemove(datasetNames, STLUtils::MapKeys(_pyScripts))) { delete _pyScripts[name]; _pyScripts.erase(name); } for (const auto &name : STLUtils::SyncToAdd(datasetNames, STLUtils::MapKeys(_pyScripts))) { _pyScripts[name] = new PyEngine(_dataStatus->GetDataMgr(name)); _pyScripts[name]->Initialize(); } for (const auto &dataset : datasetNames) { const auto funcNames = datasetsParams->GetScriptNames(dataset); auto engine = _pyScripts[dataset]; for (const auto &name : STLUtils::SyncToRemove(funcNames, engine->GetFunctionNames())) { engine->RemoveFunction(name); SetCacheDirty(); } for (const auto &name : engine->GetFunctionNames()) { string script, p_script; vector inputVarNames, outputVarNames, outputMeshNames, p_inputVarNames, p_outputVarNames, p_outputMeshNames; bool coordFlag, p_coordFlag; engine->GetFunctionScript(name, script, inputVarNames, outputVarNames, outputMeshNames, coordFlag); datasetsParams->GetScript(dataset, name, p_script, p_inputVarNames, p_outputVarNames, p_outputMeshNames, p_coordFlag); #define T(v) (v != p_##v) if (T(script) || T(inputVarNames) || T(outputVarNames) || T(outputMeshNames) || T(coordFlag)) { engine->RemoveFunction(name); engine->AddFunction(name, p_script, p_inputVarNames, p_outputVarNames, p_outputMeshNames, p_coordFlag); SetCacheDirty(); } } for (const auto &name : STLUtils::SyncToAdd(funcNames, engine->GetFunctionNames())) { string p_script; vector p_inputVarNames, p_outputVarNames, p_outputMeshNames; bool p_coordFlag; datasetsParams->GetScript(dataset, name, p_script, p_inputVarNames, p_outputVarNames, p_outputMeshNames, p_coordFlag); engine->AddFunction(name, p_script, p_inputVarNames, p_outputVarNames, p_outputMeshNames, p_coordFlag); } } _wasCacheDirty = _isDataCacheDirty; _isDataCacheDirty = false; } ================================================ FILE: lib/render/ColorbarRenderer.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include using namespace VAPoR; using glm::vec2; using glm::vec3; using glm::vec4; static vec2 D2V2(vector d) { assert(d.size() >= 2); return vec2(d[0], d[1]); } static void DrawRect(LegacyGL *lgl, vec2 pos, vec2 size) { lgl->Begin(LGL_QUADS); lgl->TexCoord2f(0, 0); lgl->Vertex2f(pos[0], pos[1]); lgl->TexCoord2f(0, 1); lgl->Vertex2f(pos[0], pos[1] + size[1]); lgl->TexCoord2f(1, 1); lgl->Vertex2f(pos[0] + size[0], pos[1] + size[1]); lgl->TexCoord2f(1, 0); lgl->Vertex2f(pos[0] + size[0], pos[1]); lgl->End(); } static void DrawColorBar(LegacyGL *lgl, MapperFunction *mf, vec2 pos, vec2 size) { float lut[4 * 256]; mf->makeLut(lut); for (int i = 0; i < 256; i++) lut[4 * i + 3] = 1; Texture2D tex; tex.Generate(); tex.TexImage(GL_RGB, 1, 256, 0, GL_RGBA, GL_FLOAT, lut); tex.Bind(); lgl->EnableTexture(); lgl->Color3f(1, 1, 1); DrawRect(lgl, pos, size); lgl->DisableTexture(); } class Div { public: vec2 Size = vec2(0); function Draw; void Render(GLManager *glm, vec2 pos) { glm->matrixManager->PushMatrix(); glm->matrixManager->Translate(pos.x, pos.y, 0); RenderInner(glm); glm->matrixManager->PopMatrix(); } protected: virtual void RenderInner(GLManager *glm) { Draw(); } }; template class Stack : public Div { vector
_children; int _spacing; public: Stack(const vector
&c, int spacing = 5) { _children = c; _spacing = spacing; Size.*primaryAxis = -spacing; for (const auto d : c) { Size.*primaryAxis += d->Size.*primaryAxis; Size.*secondaryAxis = std::max(Size.*secondaryAxis, d->Size.*secondaryAxis); if (d->Size.*primaryAxis > 0) Size.*primaryAxis += spacing; } } protected: virtual void RenderInner(GLManager *glm) { vec2 p(0); for (auto d : _children) { d->Render(glm, p); p.*primaryAxis += d->Size.*primaryAxis + _spacing; } }; }; struct HStack : public Stack<&vec2::x, &vec2::y> { using Stack::Stack; }; struct VStack : public Stack<&vec2::y, &vec2::x> { using Stack::Stack; }; void ColorbarRenderer::Render(GLManager *glm, RenderParams *rp) { LegacyGL * lgl = glm->legacy; ColorbarPbase *cp = rp->GetColorbarPbase(); if (!cp->IsEnabled()) return; auto size = D2V2(cp->GetSize()); float scale = size.x; size.y += (1.f - size.y) * scale; size = glm::max(size, vec2(0.01, 0.01)); glm->PixelCoordinateSystemPush(); vec2 viewSize = glm->GetViewportSize(); size *= viewSize; vec3 foregroundColor = [](vector v){ return vec3(v[0], v[1], v[2]); }(cp->GetForegroundColor()); vec4 backgroundColor = [](vector v){ return vec4(v[0], v[1], v[2], v[3]); }(cp->GetBackgroundColor()); string fontName = "arimo"; float border = roundf(glm::length(viewSize) * 0.001 * (1 + scale * 2)); float padding = roundf(glm::length(viewSize) * 0.007 * (1 + scale * 2)); vec2 colorbarSize = glm::round(vec2(glm::length(viewSize) * 0.03 * (1 + scale), size.y - padding * 2)); colorbarSize = glm::max(colorbarSize, vec2(0, viewSize.y * 0.06f)); int tickCount = cp->GetNumTicks(); int fontSize = roundf(colorbarSize.y / tickCount * 0.8); fontSize = min(fontSize, (int)(padding * 1.8f)); int manualFontSize = cp->GetFontSize(); if (cp->GetValueLong("manual_font", false)) { fontSize = manualFontSize; padding = max(padding, fontSize / 2.f); colorbarSize.y = max(roundf(fontSize * tickCount / 0.8), colorbarSize.y); colorbarSize.x = roundf(max(colorbarSize.x, fontSize * 1.618f)); size.y = roundf(colorbarSize.y + padding * 2); } int titleFontSize = max(fontSize * 1.3f, padding * 2.f); float tickThickness = roundf(std::max(1.f, fontSize * 0.1f)); float tickLength = roundf(std::max(8.f, fontSize * 0.4f)); float tickPadding = 3; auto colormapVarName = rp->GetActualColorMapVariableName(); MapperFunction *mf = rp->GetMapperFunc(colormapVarName); vec2 mfRange = D2V2(mf->getMinMaxMapValue()); Div colorbar; colorbar.Size = colorbarSize; colorbar.Draw = [&]() { DrawColorBar(lgl, mf, vec2(0), colorbarSize); }; Div ticks; ticks.Size = vec2(tickLength, tickThickness); ticks.Draw = [&]() { float h = colorbarSize.y; lgl->Color(foregroundColor); for (int i = 0; i < tickCount; i++) { vec2 tickPos = glm::round(vec2(0, (h - tickThickness) * i / (tickCount - 1.f))); DrawRect(lgl, tickPos, vec2(tickLength, tickThickness)); } }; TextLabel tickFont(glm, fontName, fontSize); tickFont.ForegroundColor = glm::vec4(foregroundColor, 1); tickFont.VerticalAlignment = TextLabel::Center; tickFont.HorizontalAlignment = TextLabel::Left; auto formatTick = makeFormatter(mf, cp->GetNumDigits(), cp->GetValueLong(cp->UseScientificNotationTag, false)); auto valueForTick = [&](int i) -> float { return mfRange.x + (mfRange.y - mfRange.x) * i / (tickCount - 1.f); }; auto textForTick = [&](int i) -> string { return formatTick(valueForTick(i)); }; auto tickTextSize = [&](int i) -> vec2 { return tickFont.GetFont()->TextDimensions(textForTick(i)); }; Div tickLabels; for (int i = 0; i < tickCount; i++) { tickLabels.Size = glm::max(tickLabels.Size, tickTextSize(i)); } tickLabels.Draw = [&]() { float h = colorbarSize.y; lgl->Color(foregroundColor); for (int i = 0; i < tickCount; i++) { vec2 textPos = glm::round(vec2(0, tickThickness / 2.f + (h - tickThickness) * i / (tickCount - 1.f))); tickFont.DrawText(textPos, textForTick(i)); } }; HStack labledColorbar({&colorbar, &ticks, &tickLabels}, tickPadding); TextLabel titleFont(glm, fontName, titleFontSize); titleFont.ForegroundColor = glm::vec4(foregroundColor, 1); titleFont.VerticalAlignment = TextLabel::Bottom; titleFont.HorizontalAlignment = TextLabel::Left; Div title; string titleText = cp->GetTitle(); title.Size = titleFont.GetFont()->TextDimensions(titleText); title.Draw = [&]() { titleFont.DrawText(vec2(0), titleText); }; VStack titledColorbar({&labledColorbar, &title}, padding * 1.618); size = titledColorbar.Size + vec2(padding * 2); vec2 corner = D2V2(cp->GetCornerPosition()); vec2 pos = (corner * viewSize) - (size * corner); vec2 colorbarPos = glm::round(pos + padding); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); lgl->Color(foregroundColor); #if DRAW_COLORBAR_BORDER if (backgroundColor.w > 0.99) DrawRect(lgl, pos, size); #endif lgl->Color(backgroundColor); DrawRect(lgl, pos + vec2(border), size - vec2(border * 2)); titledColorbar.Render(glm, colorbarPos); glDisable(GL_BLEND); glm->PixelCoordinateSystemPop(); } std::function ColorbarRenderer::makeFormatter(MapperFunction *mf, int sigFigs, bool scientificNotation) { vec2 mfRange = D2V2(mf->getMinMaxMapValue()); float mfDiff = mfRange[1] - mfRange[0]; float mfMax = max(abs(mfRange[0]), abs(mfRange[1])); int diffLog10 = ceil(log10(mfDiff)); int maxLog10 = ceil(log10(mfMax)); int nDecimals = max(sigFigs - max(diffLog10, maxLog10), 0); auto formatTick = [=](float x) -> string { char buf[64]; if (scientificNotation) { snprintf(buf, 64, "%.*e", sigFigs - 1, x); } else { if (x > FLT_EPSILON) { int exp = ceil(log10(x)); int shift = sigFigs - exp; x = pow(10, -shift) * round((x * pow(10, shift))); } snprintf(buf, 64, "%.*f", nDecimals, x); } return string(buf); }; return formatTick; } ================================================ FILE: lib/render/ContourRenderer.cpp ================================================ //************************************************************************ // * // Copyright (C) 2018 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: ContourRenderer.cpp // // Author: Stas Jaroszynski // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: March 2018 // // Description: // Implementation of ContourRenderer // #include #include #include #include // Must be included first!!! #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace VAPoR; #pragma pack(push, 4) struct ContourRenderer::VertexData { float x, y, z; float v; }; #pragma pack(pop) static RendererRegistrar registrar(ContourRenderer::GetClassType(), ContourParams::GetClassType()); ContourRenderer::ContourRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr) : Renderer(pm, winName, dataSetName, ContourParams::GetClassType(), ContourRenderer::GetClassType(), instName, dataMgr), _VAO(0), _VBO(0), _nVertices(0) { } ContourRenderer::~ContourRenderer() { if (_VAO) glDeleteVertexArrays(1, &_VAO); if (_VBO) glDeleteBuffers(1, &_VBO); _VAO = _VBO = 0; } void ContourRenderer::_saveCacheParams() { ContourParams *p = (ContourParams *)GetActiveParams(); _cacheParams.varName = p->GetVariableName(); _cacheParams.heightVarName = p->GetHeightVariableName(); _cacheParams.ts = p->GetCurrentTimestep(); _cacheParams.level = p->GetRefinementLevel(); _cacheParams.lod = p->GetCompressionLevel(); _cacheParams.lineThickness = p->GetLineThickness(); p->GetBox()->GetExtents(_cacheParams.boxMin, _cacheParams.boxMax); _cacheParams.contourValues = p->GetContourValues(_cacheParams.varName); _cacheParams.sliceRotation = p->GetSlicePlaneRotation(); _cacheParams.sliceNormal = p->GetSlicePlaneNormal(); _cacheParams.sliceOrigin = p->GetSlicePlaneOrigin(); _cacheParams.sliceOffset = p->GetValueDouble(p->SliceOffsetTag, 0); _cacheParams.sliceResolution = p->GetValueDouble(RenderParams::SampleRateTag, 200); _cacheParams.sliceOrientationMode = p->GetValueLong(RenderParams::SlicePlaneOrientationModeTag, 0); } bool ContourRenderer::_isCacheDirty() const { ContourParams *p = (ContourParams *)GetActiveParams(); if (_cacheParams.varName != p->GetVariableName()) return true; if (_cacheParams.heightVarName != p->GetHeightVariableName()) return true; if (_cacheParams.ts != p->GetCurrentTimestep()) return true; if (_cacheParams.level != p->GetRefinementLevel()) return true; if (_cacheParams.lod != p->GetCompressionLevel()) return true; if (_cacheParams.lineThickness != p->GetLineThickness()) return true; if (_cacheParams.sliceRotation != p->GetSlicePlaneRotation()) return true; if (_cacheParams.sliceNormal != p->GetSlicePlaneNormal()) return true; if (_cacheParams.sliceOrigin != p->GetSlicePlaneOrigin()) return true; if (_cacheParams.sliceOffset != p->GetValueDouble(p->SliceOffsetTag, 0)) return true; if (_cacheParams.sliceResolution != p->GetValueDouble(RenderParams::SampleRateTag, 200)) return true; if (_cacheParams.sliceOrientationMode != p->GetValueLong(RenderParams::SlicePlaneOrientationModeTag, 0)) return true; vector min, max, contourValues; p->GetBox()->GetExtents(min, max); contourValues = p->GetContourValues(_cacheParams.varName); if (_cacheParams.boxMin != min) return true; if (_cacheParams.boxMax != max) return true; if (_cacheParams.contourValues != contourValues) return true; return false; } static CoordType ToCoordType(const vector &v) { CoordType c; for (int i = 0; i < std::min(c.size(), v.size()); i++) c[i] = v[i]; return c; } static glm::vec3 ToVec3(const vector &v) { glm::vec3 c; for (int i = 0; i < std::min(c.length(), (int)v.size()); i++) c[i] = v[i]; return c; } static vector ToDoubleVec(const glm::vec3 &v) { vector c(v.length()); for (int i = 0; i < v.length(); i++) c[i] = v[i]; return c; } int ContourRenderer::_buildCache(bool fast) { ContourParams *cParams = (ContourParams *)GetActiveParams(); _saveCacheParams(); vector vertices; if (cParams->GetVariableName().empty()) { MyBase::SetErrMsg("Missing Variable"); return 1; } vector contours = cParams->GetContourValues(_cacheParams.varName); CoordType boxMin = {0.0, 0.0, 0.0}; CoordType boxMax = {0.0, 0.0, 0.0}; Grid::CopyToArr3(_cacheParams.boxMin, boxMin); Grid::CopyToArr3(_cacheParams.boxMax, boxMax); Grid *grid = _dataMgr->GetVariable(_cacheParams.ts, _cacheParams.varName, _cacheParams.level, _cacheParams.lod, boxMin, boxMax); Grid *grid2 = nullptr; Grid *heightGrid = nullptr; _sliceQuad.clear(); int dims = grid->GetTopologyDim(); if (!_cacheParams.heightVarName.empty() && dims == 2) { heightGrid = _dataMgr->GetVariable(_cacheParams.ts, _cacheParams.heightVarName, _cacheParams.level, _cacheParams.lod, boxMin, boxMax); } if (grid == NULL || (heightGrid == NULL && !_cacheParams.heightVarName.empty())) { if (grid) delete grid; if (grid2) delete grid2; if (heightGrid) delete heightGrid; return -1; } if (dims == 3) { planeDescription pd; pd.boxMin = ToCoordType(_cacheParams.boxMin); pd.boxMax = ToCoordType(_cacheParams.boxMax); pd.origin = _cacheParams.sliceOrigin; pd.sideSize = _cacheParams.sliceResolution; if (_cacheParams.sliceOrientationMode == (int)RenderParams::SlicePlaneOrientationMode::Normal) pd.normal = _cacheParams.sliceNormal; else pd.normal = ToDoubleVec(ArbitrarilyOrientedRegularGrid::GetNormalFromRotations(_cacheParams.sliceRotation)); auto o = ToVec3(_cacheParams.sliceOrigin); auto n = ToVec3(pd.normal); auto offsetOrigin = o + n * (float)_cacheParams.sliceOffset; pd.origin = ToDoubleVec(offsetOrigin); _finalOrigin = offsetOrigin; DimsType dims = {pd.sideSize, pd.sideSize, 1}; ArbitrarilyOrientedRegularGrid *grid2d = new ArbitrarilyOrientedRegularGrid(grid, pd, dims); grid2 = grid; grid = grid2d; CoordType corner1, corner2, corner3, corner4; grid2d->GetUserCoordinates({0, 0, 0}, corner1); grid2d->GetUserCoordinates({0, pd.sideSize - 1, 0}, corner2); grid2d->GetUserCoordinates({pd.sideSize - 1, 0, 0}, corner3); grid2d->GetUserCoordinates({pd.sideSize - 1, pd.sideSize - 1, 0}, corner4); cParams->SetSlicePlaneQuad({ {corner1[0], corner1[1], corner1[2]}, {corner3[0], corner3[1], corner3[2]}, {corner4[0], corner4[1], corner4[2]}, {corner2[0], corner2[1], corner2[2]}, }); if (fast) { _cacheParams.varName = ""; if (grid) delete grid; if (grid2) delete grid2; if (heightGrid) delete heightGrid; return 0; } } double mv = grid->GetMissingValue(); float Z0 = GetDefaultZ(_dataMgr, _cacheParams.ts); Grid::ConstCellIterator it = grid->ConstCellBegin(boxMin, boxMax); size_t maxNodes = grid->GetMaxVertexPerCell(); vector nodes(maxNodes); vector values(maxNodes); vector coords(maxNodes); Grid::ConstCellIterator end = grid->ConstCellEnd(); for (; it != end; ++it) { const DimsType &cell = *it; grid->GetCellNodes(cell, nodes); bool hasMissing = false; for (int i = 0; i < nodes.size(); i++) { grid->GetUserCoordinates(nodes[i], coords[i]); values[i] = grid->GetValueAtIndex(nodes[i]); if (values[i] == mv) { hasMissing = true; } } if (hasMissing) continue; for (int ci = 0; ci != contours.size(); ci++) { for (int a = nodes.size() - 1, b = 0; b < nodes.size(); a++, b++) { if (a == nodes.size()) a = 0; float contour = contours[ci]; if ((values[a] <= contour && values[b] <= contour) || (values[a] > contour && values[b] > contour)) continue; float t = (contour - values[a]) / (values[b] - values[a]); float v[3]; v[0] = coords[a][0] + t * (coords[b][0] - coords[a][0]); v[1] = coords[a][1] + t * (coords[b][1] - coords[a][1]); v[2] = coords[a][2] + t * (coords[b][2] - coords[a][2]); if (dims == 2) v[2] = Z0; if (heightGrid) { float aHeight = heightGrid->GetValueAtIndex(nodes[a]); float bHeight = heightGrid->GetValueAtIndex(nodes[b]); v[2] = aHeight + t * (bHeight - aHeight); } vertices.push_back({v[0], v[1], v[2], contour}); } } } _nVertices = vertices.size(); glBindVertexArray(_VAO); glBindBuffer(GL_ARRAY_BUFFER, _VBO); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_DYNAMIC_DRAW); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); if (grid) delete grid; if (grid2) delete grid2; if (heightGrid) delete heightGrid; return 0; } int ContourRenderer::_paintGL(bool fast) { int rc = 0; if (_isCacheDirty()) { rc = _buildCache(fast); } if (rc != 0) return rc; RenderParams * rp = GetActiveParams(); MapperFunction *tf = rp->GetMapperFunc(rp->GetVariableName()); float lut[4 * 256]; tf->makeLut(lut); if (rp->UseSingleColor()) { float c[3]; rp->GetConstantColor(c); for (int i = 0; i < 256; i++) { lut[i * 4 + 0] = c[0]; lut[i * 4 + 1] = c[1]; lut[i * 4 + 2] = c[2]; } } _lutTexture.TexImage(GL_RGBA8, 256, 0, 0, GL_RGBA, GL_FLOAT, lut); ShaderProgram *shader = _glManager->shaderManager->GetShader("Contour"); if (shader == nullptr) return -1; shader->Bind(); shader->SetUniform("MVP", _glManager->matrixManager->GetModelViewProjectionMatrix()); shader->SetUniform("minLUTValue", tf->getMinMapValue()); shader->SetUniform("maxLUTValue", tf->getMaxMapValue()); shader->SetSampler("colormap", _lutTexture); // glLineWidth(_cacheParams.lineThickness); glDepthMask(true); glEnable(GL_DEPTH_TEST); glBindVertexArray(_VAO); glDrawArrays(GL_LINES, 0, _nVertices); glBindVertexArray(0); shader->UnBind(); return rc; } int ContourRenderer::_initializeGL() { glGenVertexArrays(1, &_VAO); glBindVertexArray(_VAO); glGenBuffers(1, &_VBO); glBindBuffer(GL_ARRAY_BUFFER, _VBO); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), NULL); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void *)offsetof(struct VertexData, v)); glEnableVertexAttribArray(1); glBindVertexArray(0); _lutTexture.Generate(); return 0; } ================================================ FILE: lib/render/ControlExecutive.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace VAPoR; using namespace std; ControlExec::ControlExec(ParamsMgr *pm, size_t cacheSizeMB, int nThreads) : MyBase() { _paramsMgr = pm; _dataStatus = new DataStatus(cacheSizeMB, nThreads); _calcEngineMgr = new CalcEngineMgr(_dataStatus, _paramsMgr); _visualizers.clear(); auto sp = pm->GetParams(); SetCacheSize(sp->GetCacheMB()); SetNumThreads(sp->GetNumThreads()); } ControlExec::~ControlExec() { #ifdef DEBUG cout << "Allocated XmlNode count before delete " << XmlNode::GetAllocatedNodes().size() << endl; const vector &nodes = XmlNode::GetAllocatedNodes(); for (int i = 0; i < nodes.size(); i++) { cout << " " << nodes[i]->GetTag() << " " << XmlNode::streamOut(cout, nodes[i]) << endl; } #endif if (_paramsMgr) delete _paramsMgr; if (_dataStatus) delete _dataStatus; #ifdef DEBUG cout << "Allocated XmlNode count after delete " << XmlNode::GetAllocatedNodes().size() << endl; for (int i = 0; i < nodes.size(); i++) { cout << " " << nodes[i]->GetTag() << " " << XmlNode::streamOut(cout, nodes[i]) << endl; } #endif } int ControlExec::NewVisualizer(string winName) { // TODO Maybe remove this and RemoveVisualizer winName = _paramsMgr->CreateVisualizerParamsInstance(winName); if (winName.empty()) { SetErrMsg("Failed to create Visualizer parameters"); return -1; } return 0; } void ControlExec::RemoveVisualizer(string winName, bool hasOpenGLContext) { _paramsMgr->RemoveVisualizer(winName); } void ControlExec::SyncWithParams() { syncDatasetsWithParams(); syncVisualizersWithParams(); _calcEngineMgr->SyncWithParams(); } void ControlExec::syncVisualizersWithParams() { vector vizNames = GetParamsMgr()->GetVisualizerNames(); for (const auto &name : STLUtils::SyncToRemove(vizNames, STLUtils::MapKeys(_visualizers))) CleanupVisualizer(name, false); for (const auto &name : STLUtils::SyncToAdd(vizNames, STLUtils::MapKeys(_visualizers))) _visualizers[name] = new Visualizer(_paramsMgr, _dataStatus, name); } void ControlExec::syncDatasetsWithParams() { auto gp = GetParams(); auto openDatasets = gp->GetOpenDataSetNames(); auto toRemove = STLUtils::SyncToRemove(openDatasets, _dataStatus->GetDataMgrNames()); if (_dataCachedProjStr != gp->GetProjectionString()) { toRemove = _dataStatus->GetDataMgrNames(); _dataCachedProjStr = gp->GetProjectionString(); } for (const auto &name : toRemove) _dataStatus->Close(name); for (const auto &name : STLUtils::SyncToAdd(openDatasets, _dataStatus->GetDataMgrNames())) OpenData(gp->GetOpenDataSetPaths(name), name, gp->GetOpenDataSetFormat(name)); _dataStatus->_wasCacheDirty = _dataStatus->_isDataCacheDirty; _dataStatus->_isDataCacheDirty = false; } void ControlExec::EnforceDefaultAppState() { vector vizNames = _paramsMgr->GetVisualizerNames(); auto gsp = GetParams(); if (!vizNames.empty() && !STLUtils::Contains(vizNames, gsp->GetActiveVizName())) { _paramsMgr->PushSaveStateEnabled(false); gsp->SetActiveVizName(vizNames[0]); _paramsMgr->PopSaveStateEnabled(); } } void ControlExec::CleanupVisualizer(string winName, bool hasOpenGLContext) { auto viz = getVisualizer(winName); if (!viz) return; if (!hasOpenGLContext) _vizGLMgr->Activate(winName); RemoveAllRenderers(winName, true, false); _visualizers.erase(winName); delete viz; } int ControlExec::InitializeViz(string winName, GLManager *glManager) { Visualizer *v = getVisualizer(winName); if (!v) { SetErrMsg("Invalid Visualizer \"%s\"", winName.c_str()); return -1; } if (v->InitializeGL(glManager) < 0) { SetErrMsg("InitializeGL failure"); return -1; } _cachedVendor = glManager->GetVendor(); return 0; } vector ControlExec::GetVisualizerNames() const { vector names; std::map::const_iterator itr; for (itr = _visualizers.begin(); itr != _visualizers.end(); ++itr) { names.push_back(itr->first); } return (names); } int ControlExec::ResizeViz(string winName, int width, int height) { Visualizer *v = getVisualizer(winName); if (!v) { SetErrMsg("Invalid Visualizer \"%s\"", winName.c_str()); return -1; } if (v->resizeGL(width, height) < 0) return -1; return 0; } void ControlExec::ClearRenderCache(const string &winName, const string &inst) { getVisualizer(winName)->ClearRenderCache(inst); } void ControlExec::ClearAllRenderCaches() { std::map::const_iterator itr; for (itr = _visualizers.begin(); itr != _visualizers.end(); ++itr) { itr->second->ClearRenderCache(); } } GLManager::Vendor ControlExec::GetGPUVendor() const { return _cachedVendor; } int ControlExec::Paint(string winName, bool fast) { Visualizer *v = getVisualizer(winName); if (!v) { SetErrMsg("Invalid Visualizer \"%s\"", winName.c_str()); return -1; } // Disable state saving when generating the transfer function // bool enabled = _paramsMgr->GetSaveStateEnabled(); _paramsMgr->SetSaveStateEnabled(false); int rc = v->paintEvent(fast); _paramsMgr->SetSaveStateEnabled(enabled); if (rc) SetErrMsg("Error performing paint event"); return rc; } // TODO Replace with params-only int ControlExec::ActivateRender(string winName, string dataSetName, string renderType, string renderName, bool on) { if (!_dataStatus->GetDataMgrNames().size()) { SetErrMsg("Invalid state : no data"); return -1; } if (!STLUtils::Contains(_paramsMgr->GetVisualizerNames(), winName)) { SetErrMsg("Invalid Visualizer \"%s\"", winName.c_str()); return -1; } _paramsMgr->BeginSaveStateGroup("Activate Renderer"); string paramsType = RendererFactory::Instance()->GetParamsClassFromRenderClass(renderType); VAssert(!paramsType.empty()); RenderParams *rp = _paramsMgr->GetRenderParams(winName, dataSetName, paramsType, renderName); if (!rp) { rp = _paramsMgr->CreateRenderParamsInstance(winName, dataSetName, paramsType, renderName); if (!rp) { SetErrMsg("Invalid renderer of type \"%s\"", renderType.c_str()); _paramsMgr->EndSaveStateGroup(); return -1; } rp->SetCurrentTimestep(NavigationUtils::GetCurrentTimeStep(this)); int rc = rp->Initialize(); if (rc < 0) { SetErrMsg("Failed to initialize of type \"%s\"", renderType.c_str()); _paramsMgr->EndSaveStateGroup(); return (-1); } } VAssert(rp); rp->SetEnabled(on); if (on) { Visualizer *v = getVisualizer(winName); if (v) { // TODO Replace rendering order using params v->MoveRendererToFront(renderType, renderName); v->MoveRenderersOfTypeToFront(VolumeRenderer::GetClassType()); } } _paramsMgr->EndSaveStateGroup(); return 0; } void ControlExec::_removeRendererHelper(string winName, string dataSetName, string pClassName, string renderName, bool hasOpenGLContext) { // No-op if tuple of winName, dataSetName, renderType, and // renderName is unknown // // Convert from params render type to render type. Sigh // string rClassName = RendererFactory::Instance()->GetRenderClassFromParamsClass(pClassName); RenderParams *rParams = _paramsMgr->GetRenderParams(winName, dataSetName, pClassName, renderName); if (!rParams) return; Visualizer *v = getVisualizer(winName); if (!v) return; v->DestroyRenderer(rClassName, renderName, hasOpenGLContext); _paramsMgr->RemoveRenderParamsInstance(winName, dataSetName, pClassName, renderName); } void ControlExec::RemoveRenderer(string winName, string dataSetName, string renderType, string renderName, bool hasOpenGLContext) { string pClassName = RendererFactory::Instance()->GetParamsClassFromRenderClass(renderType); RenderParams *rParams = _paramsMgr->GetRenderParams(winName, dataSetName, pClassName, renderName); if (!rParams) return; _removeRendererHelper(winName, dataSetName, pClassName, renderName, hasOpenGLContext); } void ControlExec::RemoveAllRenderers(string winName, bool hasOpenGLContext, bool removeFromParamsFlag) { vector dataSetNames = _paramsMgr->GetDataMgrNames(); for (int k = 0; k < dataSetNames.size(); k++) { vector pClassNames = _paramsMgr->GetRenderParamsClassNames(winName, dataSetNames[k]); for (int j = 0; j < pClassNames.size(); j++) { vector instNames = _paramsMgr->GetRenderParamInstances(winName, dataSetNames[k], pClassNames[j]); for (int i = 0; i < instNames.size(); i++) { _removeRendererHelper(winName, dataSetNames[k], pClassNames[j], instNames[i], hasOpenGLContext); } } } } void ControlExec::LoadState() { _paramsMgr->LoadState(); } void ControlExec::LoadState(const XmlNode *rootNode) { _paramsMgr->LoadState(rootNode); } int ControlExec::LoadState(string stateFile, LoadStateRelAndAbsPathsExistAction relAndAbsPathsExistAction) { _paramsMgr->BeginSaveStateGroup("Load state"); vector vizNames = GetVisualizerNames(); for (int i = 0; i < vizNames.size(); i++) { RemoveVisualizer(vizNames[i]); } // Bug prevents using the real PM here ParamsMgr tempPM({GUIStateParams::GetClassType()}); if (tempPM.LoadState(stateFile) < 0) { _paramsMgr->EndSaveStateGroup(); return -1; } GUIStateParams *tmpGsp = (GUIStateParams *)tempPM.GetParams(GUIStateParams::GetClassType()); map> useRelativePaths; auto sesDir = FileUtils::Dirname(stateFile); for (auto dataset : tmpGsp->GetOpenDataSetNames()) { auto paths = tmpGsp->GetOpenDataSetPaths(dataset); auto relPaths = tmpGsp->GetOpenDataSetRelativePaths(dataset); for (int i = 0; i < relPaths.size(); i++) relPaths[i] = FileUtils::JoinPaths({sesDir, relPaths[i]}); if (relPaths.empty()) continue; auto absoluteExist = std::all_of(paths.begin(), paths.end(), [](string p){return FileUtils::Exists(p);}); auto relativeExist = std::all_of(relPaths.begin(), relPaths.end(), [](string p){return FileUtils::Exists(p);}); if (absoluteExist && !relativeExist) continue; if (!absoluteExist && relativeExist) { useRelativePaths[dataset] = relPaths; continue; } if (absoluteExist && relativeExist) { bool same = paths.size() == relPaths.size(); for (int i = 0; i < paths.size() && same; i++) same &= FileUtils::AreSameFile(paths[i], relPaths[i]); if (same) continue; switch (relAndAbsPathsExistAction) { case LoadStateRelAndAbsPathsExistAction::LoadAbs: continue; case LoadStateRelAndAbsPathsExistAction::LoadRel: useRelativePaths[dataset] = relPaths; continue; case LoadStateRelAndAbsPathsExistAction::Ask: _paramsMgr->EndSaveStateGroup(); throw RelAndAbsPathsExistException(paths[0], relPaths[0]); } } } int rc = _paramsMgr->LoadState(stateFile); if (rc < 0) { _paramsMgr->EndSaveStateGroup(); return (-1); } auto gsp = (GUIStateParams *)_paramsMgr->GetParams(GUIStateParams::GetClassType()); for (const auto &it : useRelativePaths) gsp->InsertOpenDataSet(it.first, gsp->GetOpenDataSetFormat(it.first), it.second); _paramsMgr->EndSaveStateGroup(); return (0); } void ControlExec::SetNumThreads(size_t nthreads) { // Set the number of PThreads to use _dataStatus->SetNumThreads(nthreads); if (nthreads > 0) { omp_set_num_threads(nthreads); } } size_t ControlExec::GetNumThreads() const { return (_dataStatus->GetNumThreads()); } void ControlExec::SetCacheSize(size_t sizeMB) { _dataStatus->SetCacheSize(sizeMB); } int ControlExec::OpenData(const std::vector &files, string dataSetName, string typ) { _paramsMgr->BeginSaveStateGroup("Open Dataset"); vector options = {"-project_to_pcs", "-vertical_xform"}; if (GetParams()->GetAutoStretchEnabled()) options.push_back("-auto_stretch_z"); // This is a minor bug if the first dataset has an empty proj string however this has been a bug for as long as I can tell and it is not worth fixing at the moment if (!GetParams()->GetProjectionString().empty()) STLUtils::AppendTo(options, {"-proj4", GetParams()->GetProjectionString()}); SetDataCacheDirty(dataSetName); int rc = _dataStatus->Open(files, options, dataSetName, typ); if (rc < 0) { SetErrMsg("Failure to open data set of type \"%s\"", typ.c_str()); _paramsMgr->EndSaveStateGroup(); return -1; } _paramsMgr->AddDataMgr(dataSetName, _dataStatus->GetDataMgr(dataSetName)); // Need to call initializers for any registered application renderers // vector appRenderParams; _paramsMgr->GetAppRenderParams(dataSetName, appRenderParams); for (int i = 0; i < appRenderParams.size(); i++) { int rc = appRenderParams[i]->Initialize(); if (rc < 0) { _calcEngineMgr->Clean(); _dataStatus->Close(dataSetName); _paramsMgr->RemoveDataMgr(dataSetName); SetErrMsg("Failure to initialize application renderer \"%s\"", appRenderParams[i]->GetName().c_str()); _paramsMgr->EndSaveStateGroup(); return -1; } } _setDefaultOrigin(dataSetName); if (STLUtils::Contains(options, string("-auto_stretch_z"))) _autoStretchExtents(dataSetName); // vvvv NOPs if existing used _dataCachedProjStr = _dataStatus->GetMapProjection(); GetParams()->SetProjectionString(_dataCachedProjStr); // ^^^^ _paramsMgr->EndSaveStateGroup(); return rc; } void ControlExec::CloseData(string dataSetName) { if (!_dataStatus->GetDataMgr(dataSetName)) return; SetDataCacheDirty(dataSetName); _paramsMgr->BeginSaveStateGroup("Close Dataset"); GetParams()->RemoveOpenDataSet(dataSetName); for (const auto &renName : _paramsMgr->GetRenderParamNamesForDataset(dataSetName)) { string vizName, className, _; _paramsMgr->RenderParamsLookup(renName, vizName, _, className); _paramsMgr->RemoveRenderParamsInstance(vizName, dataSetName, className, renName); } _paramsMgr->RemoveDataMgr(dataSetName); _dataStatus->Close(dataSetName); _paramsMgr->EndSaveStateGroup(); } int ControlExec::EnableImageCapture(string filename, string winName, bool fast) { Visualizer *v = getVisualizer(winName); if (!v) { SetErrMsg("Invalid Visualizer \"%s\"", winName.c_str()); return -1; } if (v->SetImageCaptureEnabled(true, filename)) { SetErrMsg("Visualizer (%s) failed to enable capturing image.", winName.c_str()); return -1; } // Disable state saving when capturing an image // bool enabled = _paramsMgr->GetSaveStateEnabled(); _paramsMgr->SetSaveStateEnabled(false); int rc = v->paintEvent(fast); // paint with image capture enabled _paramsMgr->SetSaveStateEnabled(enabled); if (rc != 0) { SetErrMsg("Visualizer (%s) failed to paint and thus not capturing image.", winName.c_str()); return -1; } return 0; } int ControlExec::EnableAnimationCapture(string winName, bool onOff, string filename) { Visualizer *v = getVisualizer(winName); if (!v) { SetErrMsg("Invalid Visualizer \"%s\"", winName.c_str()); return -1; } if (v->SetAnimationCaptureEnabled(onOff, filename)) return -1; return 0; } string ControlExec::MakeStringConformant(string s) { if (s.empty()) s += "_"; if (!(isalpha(s[0]) || s[0] == '_')) { s = "_" + s; } for (string::iterator itr = s.begin(); itr != s.end(); ++itr) { if (!(isalnum(*itr) || isdigit(*itr) || *itr == '-' || *itr == '_' || *itr == '.')) { *itr = '_'; } if (isspace(*itr)) { *itr = '_'; } } return (s); } int ControlExec::SaveSession(string filename) { ofstream fileout; const XmlNode *node = nullptr; GUIStateParams *gsp = (GUIStateParams *)_paramsMgr->GetParams(GUIStateParams::GetClassType()); bool saveStateEnabled = _paramsMgr->GetSaveStateEnabled(); _paramsMgr->SetSaveStateEnabled(false); auto datasets = gsp->GetOpenDataSetNames(); for (auto dataset : datasets) { auto paths = gsp->GetOpenDataSetPaths(dataset); auto format = gsp->GetOpenDataSetFormat(dataset); vector relpaths(paths.size()); for (int i = 0; i < paths.size(); i++) { paths[i] = FileUtils::Realpath(paths[i]); relpaths[i] = FileUtils::Relpath(paths[i], filename); } gsp->InsertOpenDataSet(dataset, format, paths, relpaths); } _paramsMgr->SetSaveStateEnabled(saveStateEnabled); fileout.open(filename.c_str()); if (!fileout) { SetErrMsg("Unable to open output session file : %M"); return -1; } node = _paramsMgr->GetXMLRoot(); XmlNode::streamOut(fileout, *node); if (fileout.bad()) { SetErrMsg("Unable to write output session file : %M"); return -1; } return 0; } RenderParams *ControlExec::GetRenderParams(string winName, string dataSetName, string renderType, string instName) const { string paramsType = RendererFactory::Instance()->GetParamsClassFromRenderClass(renderType); RenderParams *rParams = _paramsMgr->GetRenderParams(winName, dataSetName, paramsType, instName); if (!rParams) { SetErrMsg("Invalid window name, render type, or instance name"); return (NULL); } return (rParams); } vector ControlExec::GetRenderClassNames(string winName) const { vector v = _paramsMgr->GetRenderParamsClassNames(winName); for (int i = 0; i < v.size(); i++) { v[i] = RendererFactory::Instance()->GetRenderClassFromParamsClass(v[i]); } return (v); } vector ControlExec::GetRenderInstances(string winName, string renderType) const { string paramsType = RendererFactory::Instance()->GetParamsClassFromRenderClass(renderType); return (_paramsMgr->GetRenderParamInstances(winName, paramsType)); } vector ControlExec::GetAllRenderClasses() { return (RendererFactory::Instance()->GetFactoryNames()); } bool ControlExec::RenderLookup(string instName, string &winName, string &dataSetName, string &renderType) const { string paramsType; bool ok = _paramsMgr->RenderParamsLookup(instName, winName, dataSetName, paramsType); if (!ok) return (ok); renderType = RendererFactory::Instance()->GetRenderClassFromParamsClass(paramsType); return (ok); } string ControlExec::MakeRendererNameUnique(string name) const { string newname = name; ParamsMgr *pm = GetParamsMgr(); vector allInstNames; // Get ALL of the renderer instance names defined // vector vizNames = pm->GetVisualizerNames(); for (int i = 0; i < vizNames.size(); i++) { vector classNames = GetRenderClassNames(vizNames[i]); for (int j = 0; j < classNames.size(); j++) { vector rendererNames = GetRenderInstances(vizNames[i], classNames[j]); allInstNames.insert(allInstNames.begin(), rendererNames.begin(), rendererNames.end()); } } while (1) { bool match = false; for (int i = 0; i < allInstNames.size(); i++) { string usedName = allInstNames[i]; if (newname != usedName) continue; match = true; size_t lastnonint = newname.find_last_not_of("0123456789"); if (lastnonint < newname.length() - 1) { string endchars = newname.substr(lastnonint + 1); int termInt = atoi(endchars.c_str()); termInt++; std::stringstream ss; ss << termInt; endchars = ss.str(); newname.replace(lastnonint + 1, string::npos, endchars); } else { newname = newname + "_1"; } } if (!match) break; } return newname; } int ControlExec::AddFunction(string scriptType, string dataSetName, string scriptName, string script, const vector &inputVarNames, const vector &outputVarNames, const vector &outputVarMeshes, bool coordFlag) { // Ugh. Need to force each renderer to clear any cached data because // if we redefine a variable the variable's data will change but // the variable's name will not. Hence, if we don't clear the data // the renderer may continue using old data // // ClearAllRenderCaches(); return (_calcEngineMgr->AddFunction(scriptType, dataSetName, scriptName, script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag)); } void ControlExec::RemoveFunction(string scriptType, string dataSetName, string scriptName) { return (_calcEngineMgr->RemoveFunction(scriptType, dataSetName, scriptName)); } bool ControlExec::GetFunction(string scriptType, string dataSetName, string scriptName, string &script, vector &inputVarNames, vector &outputVarNames, vector &outputVarMeshes, bool &coordFlag) const { script.clear(); inputVarNames.clear(); outputVarNames.clear(); outputVarMeshes.clear(); return (_calcEngineMgr->GetFunctionScript(scriptType, dataSetName, scriptName, script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag)); } string ControlExec::GetFunctionStdout(string scriptType, string dataSetName, string scriptName) const { return (_calcEngineMgr->GetFunctionStdout(scriptType, dataSetName, scriptName)); } std::vector ControlExec::GetFunctionNames(string scriptType, string dataSetName) const { return (_calcEngineMgr->GetFunctionNames(scriptType, dataSetName)); } // Function moved from old NavigationEventRouter.cpp void ControlExec::_autoStretchExtents(string dataSetName) { DataStatus *ds = GetDataStatus(); ParamsMgr * paramsMgr = GetParamsMgr(); vector winNames = paramsMgr->GetVisualizerNames(); CoordType minExt, maxExt; for (int i = 0; i < winNames.size(); i++) { ViewpointParams * vpParams = paramsMgr->GetViewpointParams(winNames[i]); Transform * transform = vpParams->GetTransform(dataSetName); std::vector scales = transform->GetScales(); int xDimension = 0; int yDimension = 1; int zDimension = 2; // If a dimension's scale is not 1.f, the user has saved a session with // a non-default value. Don't modify it. if (scales[xDimension] != 1.f) continue; if (scales[yDimension] != 1.f) continue; if (scales[zDimension] != 1.f) continue; // size_t ts = GetCurrentTimeStep(); size_t ts = 0; ds->GetActiveExtents(paramsMgr, winNames[i], dataSetName, ts, minExt, maxExt); vector range; float maxRange = 0.0; for (int i = 0; i < minExt.size(); i++) { float r = fabs(maxExt[i] - minExt[i]); if (maxRange < r) { maxRange = r; } range.push_back(r); } if (fabs(maxRange) <= FLT_EPSILON) maxRange = 1.0; vector scale(range.size(), 1.0); for (int i = 0; i < range.size(); i++) { if (range[i] < (maxRange / 10.0) && fabs(range[i]) > FLT_EPSILON) { scale[i] = maxRange / (10.0 * range[i]); } } transform->SetScales(scale); } } void ControlExec::_setDefaultOrigin(string datasetName) { DataStatus *ds = GetDataStatus(); ParamsMgr * paramsMgr = GetParamsMgr(); vector winNames = paramsMgr->GetVisualizerNames(); CoordType minExt, maxExt; for (int i = 0; i < winNames.size(); i++) { ViewpointParams * vpParams = paramsMgr->GetViewpointParams(winNames[i]); Transform * transform = vpParams->GetTransform(datasetName); std::vector origin = transform->GetOrigin(); // Skip if not default bool skip = false; for (int i = 0; i < 3; i++) if (origin[i] != 0.f) skip = true; if (skip) continue; size_t ts = 0; ds->GetActiveExtents(paramsMgr, winNames[i], datasetName, ts, minExt, maxExt); for (int i = 0; i < minExt.size(); i++) origin[i] = (maxExt[i] + minExt[i]) / 2; transform->SetOrigin(origin); } } bool ControlExec::WasDataCacheDirty() const { return _dataStatus->WasCacheDirty() || _calcEngineMgr->_wasCacheDirty; } ================================================ FILE: lib/render/FlowRenderer.cpp ================================================ #include "vapor/glutil.h" #include "vapor/FlowRenderer.h" #include "vapor/Particle.h" #include "vapor/AdvectionIO.h" #include #include #include #include #include #include #define GL_ERROR -20 using namespace VAPoR; using glm::vec3; using glm::vec4; static RendererRegistrar registrar(FlowRenderer::GetClassType(), FlowParams::GetClassType()); // Constructor FlowRenderer::FlowRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string &instName, DataMgr *dataMgr) : Renderer(pm, winName, dataSetName, FlowParams::GetClassType(), FlowRenderer::GetClassType(), instName, dataMgr), _colorMapTexOffset(0) { } // Destructor FlowRenderer::~FlowRenderer() { // Delete vertex arrays if (_vertexArrayId) { glDeleteVertexArrays(1, &_vertexArrayId); _vertexArrayId = 0; } if (_vertexBufferId) { glDeleteBuffers(1, &_vertexBufferId); _vertexBufferId = 0; } if (_colorMapTexId) { glDeleteTextures(1, &_colorMapTexId); _colorMapTexId = 0; } } std::string FlowRenderer::_getColorbarVariableName() const { return GetActiveParams()->GetColorMapVariableName(); } int FlowRenderer::_initializeGL() { _velocityField.AssignDataManager(_dataMgr); _colorField.AssignDataManager(_dataMgr); _timestamps = _dataMgr->GetTimeCoordinates(); // Followed by real OpenGL initializations ShaderProgram *shader = nullptr; if ((shader = _glManager->shaderManager->GetShader("FlowLine"))) _shader = shader; else return GL_ERROR; /* Create Vertex Array Object (VAO) */ glGenVertexArrays(1, &_vertexArrayId); glGenBuffers(1, &_vertexBufferId); /* Generate and configure 1D texture: _colorMapTexId */ glGenTextures(1, &_colorMapTexId); glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset); glBindTexture(GL_TEXTURE_1D, _colorMapTexId); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glBindTexture(GL_TEXTURE_1D, 0); glGenVertexArrays(1, &_VAO); glGenBuffers(1, &_VBO); assert(_VAO); assert(_VBO); glBindVertexArray(_VAO); glBindBuffer(GL_ARRAY_BUFFER, _VBO); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), NULL); glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (void *)sizeof(glm::vec3)); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); return 0; } int FlowRenderer::_outputFlowLines() { auto *params = dynamic_cast(GetActiveParams()); assert(params != nullptr); // Retrieve additional variables that users require to sample const auto addiVars = params->GetFlowOutputMoreVariables(); // Identify variables that an advection already has, but the user doesn't // include in addiVars. Remove them. // // start by listing all variables as potentially to be removed auto removeVars = _advection.GetPropertyVarNames(); auto containV = [&addiVars](const std::string &v) { return std::find(addiVars.cbegin(), addiVars.cend(), v) != addiVars.cend(); }; // remove those confirmed by the user from the "to remove" list removeVars.erase(std::remove_if(removeVars.begin(), removeVars.end(), containV), removeVars.end()); for (const auto &rmV : removeVars) { _advection.RemoveParticleProperty(rmV); if (_2ndAdvection) _2ndAdvection->RemoveParticleProperty(rmV); } for (const auto &v : addiVars) { // Create a VaporField with this variable flow::VaporField varField; varField.AssignDataManager(_dataMgr); varField.UpdateParams(params); varField.ScalarName = v; // Sample values along the pathlines. // Note that the advection class will do nothing if this variable already exists. // Also note that the advection class will do a simple copy if this variable is // the same as particle values. _advection.CalculateParticleProperties(&varField); if (_2ndAdvection) _2ndAdvection->CalculateParticleProperties(&varField); } // In case of steady flow, output the number of particles that // equals to the advection steps. // In the case of unsteady flow, output particles that are up to // the advection timestamp. int rv; if (params->GetIsSteady()) { rv = flow::OutputFlowlinesNumSteps(&_advection, params->GetFlowlineOutputFilename().c_str(), params->GetSteadyNumOfSteps(), _dataMgr->GetMapProjection(), false); } else { rv = flow::OutputFlowlinesMaxTime(&_advection, params->GetFlowlineOutputFilename().c_str(), _timestamps.at(params->GetCurrentTimestep()), _dataMgr->GetMapProjection(), false); } if (rv != 0) { MyBase::SetErrMsg("Output flow lines wrong!"); return rv; } if (_2ndAdvection) { // bi-directional advection if (params->GetIsSteady()) { rv = flow::OutputFlowlinesNumSteps(_2ndAdvection.get(), params->GetFlowlineOutputFilename().c_str(), params->GetSteadyNumOfSteps(), _dataMgr->GetMapProjection(), true); } else { rv = flow::OutputFlowlinesMaxTime(_2ndAdvection.get(), params->GetFlowlineOutputFilename().c_str(), _timestamps.at(params->GetCurrentTimestep()), _dataMgr->GetMapProjection(), true); } if (rv != 0) { MyBase::SetErrMsg("Output flow lines wrong!"); return rv; } } return 0; } int FlowRenderer::_paintGL(bool fast) { FlowParams *params = dynamic_cast(GetActiveParams()); int rv = 0; // return value if (params->GetNeedFlowlineOutput()) { rv = _outputFlowLines(); params->SetNeedFlowlineOutput(false); _printNonZero(rv, __FILE__, __func__, __LINE__); if (rv != 0) return rv; } rv = _updateFlowCacheAndStates(params); _printNonZero(rv, __FILE__, __func__, __LINE__); if (rv != 0) { MyBase::SetErrMsg("Parameters not ready!"); return flow::PARAMS_ERROR; } if (_velocityStatus != FlowStatus::UPTODATE || _colorStatus != FlowStatus::UPTODATE) _renderStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityField.UpdateParams(params); _velocityField.ScalarName.clear(); auto vel_tmp = params->GetFieldVariableNames(); for (int i = 0; i < 3; i++) _velocityField.VelocityNames[i] = i < vel_tmp.size() ? vel_tmp[i] : ""; _colorField.UpdateParams(params); for (int i = 0; i < 3; i++) _colorField.VelocityNames[i].clear(); _colorField.ScalarName = params->GetColorMapVariableName(); // In case there's 0 variable selected, meaning that more than 2 of the velocity // variable names are empty strings, then the paint routine aborts. if (_velocityField.GetNumOfEmptyVelocityNames() > 2) { MyBase::SetErrMsg("Please provide at least 1 field variables for advection!"); return flow::PARAMS_ERROR; } if (_velocityStatus == FlowStatus::SIMPLE_OUTOFDATE) { // First step is to re-calculate deltaT rv = _velocityField.CalcDeltaTFromCurrentTimeStep(_cache_deltaT); _printNonZero(rv, __FILE__, __func__, __LINE__); if (rv == flow::FIELD_ALL_ZERO) { MyBase::SetErrMsg("The velocity field seems to contain only zero values!"); return flow::PARAMS_ERROR; } else if (rv != 0) { MyBase::SetErrMsg("Update deltaT failed!"); return rv; } // Obtain seeds for Flow Renderer. std::vector seeds; if (_cache_seedGenMode == FlowSeedMode::UNIFORM) rv = _genSeedsRakeUniform(seeds); else if (_cache_seedGenMode == FlowSeedMode::RANDOM) rv = _genSeedsRakeRandom(seeds); else if (_cache_seedGenMode == FlowSeedMode::RANDOM_BIAS) rv = _genSeedsRakeRandomBiased(seeds); else if (_cache_seedGenMode == FlowSeedMode::LIST) rv = _genSeedsFromList(seeds); _printNonZero(rv, __FILE__, __func__, __LINE__); if (rv != 0) { MyBase::SetErrMsg("Generating seeds failed!"); return flow::NO_SEED_PARTICLE_YET; } // Note on UseSeedParticles(): this is the only function that resets // all the streams inside of an Advection class. // It should immediately be followed by a function to set its periodicity _advection.UseSeedParticles(seeds); rv = _updateAdvectionPeriodicity(&_advection); _printNonZero(rv, __FILE__, __func__, __LINE__); if (rv != 0) { MyBase::SetErrMsg("Update Advection Periodicity failed!"); return flow::GRID_ERROR; } if (_2ndAdvection) // bi-directional advection { _2ndAdvection->UseSeedParticles(seeds); rv = _updateAdvectionPeriodicity(_2ndAdvection.get()); _printNonZero(rv, __FILE__, __func__, __LINE__); if (rv != 0) { MyBase::SetErrMsg("Update Advection Periodicity failed!"); return flow::GRID_ERROR; } } _advectionComplete = false; _velocityStatus = FlowStatus::UPTODATE; } else if (_velocityStatus == FlowStatus::TIME_STEP_OOD) { _advectionComplete = false; _velocityStatus = FlowStatus::UPTODATE; } if (!params->UseSingleColor()) { if (_colorStatus == FlowStatus::SIMPLE_OUTOFDATE) { _advection.ResetParticleValues(); _coloringComplete = false; _colorStatus = FlowStatus::UPTODATE; if (_2ndAdvection) // bi-directional advection _2ndAdvection->ResetParticleValues(); } else if (_colorStatus == FlowStatus::TIME_STEP_OOD) { _coloringComplete = false; _colorStatus = FlowStatus::UPTODATE; } } if (!_advectionComplete) { auto deltaT = _cache_deltaT; const auto fixedSteps = params->GetUseFixedAdvectionSteps(); if (fixedSteps && params->GetFixedAdvectionStepSize() > 0.0) deltaT = params->GetFixedAdvectionStepSize(); rv = flow::ADVECT_HAPPENED; // Advection scheme 1: advect a maximum number of steps. // This scheme is used for steady flow if (params->GetIsSteady()) { // If the advection is single-directional if (params->GetFlowDirection() == 1) // backward integration deltaT *= -1.0; long numOfSteps = params->GetSteadyNumOfSteps(); Progress::StartIndefinite("Performing flowline calculations"); Progress::Update(0); rv = _advection.AdvectSteps(&_velocityField, deltaT, numOfSteps, fixedSteps); _printNonZero(rv, __FILE__, __func__, __LINE__); // If the advection is bi-directional if (_2ndAdvection) { Progress::Update(5); assert(deltaT > 0.0); auto deltaT2 = deltaT * -1.0; rv = _2ndAdvection->AdvectSteps(&_velocityField, deltaT2, numOfSteps, fixedSteps); _printNonZero(rv, __FILE__, __func__, __LINE__); } Progress::Finish(); } // Advection scheme 2: advect to a certain timestamp. // This scheme is used for unsteady flow else { for (int i = 1; i <= _cache_currentTS; i++) { rv = _advection.AdvectTillTime(&_velocityField, _timestamps.at(i - 1), deltaT, _timestamps.at(i), fixedSteps); _printNonZero(rv, __FILE__, __func__, __LINE__); } } _advectionComplete = true; } if (!_coloringComplete) { bool integrate = params->GetValueLong(params->_doIntegrationTag, false); bool setAllToFinalValue = params->GetValueLong(params->_integrationSetAllToFinalValueTag, false); if (integrate) { vector integrationVolumeMin, integrationVolumeMax; params->GetIntegrationBox()->GetExtents(integrationVolumeMin, integrationVolumeMax); float distScale = params->GetValueDouble(params->_integrationScalarTag, 1.f); rv = _advection.CalculateParticleIntegratedValues(&_colorField, true, distScale, integrationVolumeMin, integrationVolumeMax); _printNonZero(rv, __FILE__, __func__, __LINE__); if (_2ndAdvection) // bi-directional advection rv = _2ndAdvection->CalculateParticleIntegratedValues(&_colorField, true, distScale, integrationVolumeMin, integrationVolumeMax); if (setAllToFinalValue) { int numSamplesPerStream; if (_cache_isSteady) numSamplesPerStream = _cache_steadyNumOfSteps; else numSamplesPerStream = _cache_currentTS; _advection.SetAllStreamValuesToFinalValue(numSamplesPerStream); if (_2ndAdvection) _2ndAdvection->SetAllStreamValuesToFinalValue(numSamplesPerStream); } vector histoRange; vector histo(256); _advection.CalculateParticleHistogram(histoRange, histo); params->SetValueLongVec(RenderParams::CustomHistogramDataTag, "", histo); params->SetValueDoubleVec(RenderParams::CustomHistogramRangeTag, "", histoRange); } else { rv = _advection.CalculateParticleValues(&_colorField, true); _printNonZero(rv, __FILE__, __func__, __LINE__); if (_2ndAdvection) // bi-directional advection rv = _2ndAdvection->CalculateParticleValues(&_colorField, true); if (params->GetValueDoubleVec(RenderParams::CustomHistogramRangeTag).size()) { params->SetValueLongVec(RenderParams::CustomHistogramDataTag, "", {}); params->SetValueDoubleVec(RenderParams::CustomHistogramRangeTag, "", {}); } } _printNonZero(rv, __FILE__, __func__, __LINE__); _coloringComplete = true; } glEnable(GL_DEPTH_TEST); glDepthMask(true); _prepareColormap(params); rv = 0; if (params->GetValueLong("old_render", 0)) { _renderFromAnAdvectionLegacy(&_advection, params, fast); if (_2ndAdvection) { // If the advection is bi-directional _renderFromAnAdvectionLegacy(_2ndAdvection.get(), params, fast); } } else { // Workaround for how bi-directional was implemented. // The rendering caches the flow data on the GPU however it // only caches one advection at a time. Since when using bidirectional // flow it results in two separate advections, we need to reset the cache // before each half is drawn. if (_2ndAdvection) _renderStatus = FlowStatus::SIMPLE_OUTOFDATE; rv |= _renderAdvection(&_advection); _printNonZero(rv, __FILE__, __func__, __LINE__); /* If the advection is bi-directional */ if (_2ndAdvection) { _renderStatus = FlowStatus::SIMPLE_OUTOFDATE; rv |= _renderAdvection(_2ndAdvection.get()); _printNonZero(rv, __FILE__, __func__, __LINE__); } } _restoreGLState(); // Release grids that are acquired during this paint event // before their DataMgr is destroyed by others. _velocityField.ReleaseLockedGrids(); _colorField.ReleaseLockedGrids(); return rv; } int FlowRenderer::_renderAdvection(const flow::Advection *adv) { FlowParams *rp = dynamic_cast(GetActiveParams()); if (_renderStatus != FlowStatus::UPTODATE) { int nStreams = adv->GetNumberOfStreams(); typedef struct { vec3 p; float v; } Vertex; vector vertices; vector sizes; vector sv; // If streams are larger than this then need to skip remaining size_t maxSamples = rp->GetSteadyNumOfSteps() + 1; // First calculate the starting time stamp. Copied from legacy. double startingTime = _timestamps[0]; if (!_cache_isSteady) { startingTime = _timestamps[0]; // note that _cache_currentTS is cast to a signed integer. if (int(_cache_currentTS) - _cache_pastNumOfTimeSteps > 0) startingTime = _timestamps[_cache_currentTS - _cache_pastNumOfTimeSteps]; } for (int s = 0; s < nStreams; s++) { const vector &stream = adv->GetStreamAt(s); sv.clear(); int sn = stream.size(); if (_cache_isSteady) sn = std::min(sn, (int)maxSamples); for (int i = 0; i < sn + 1; i++) { // "IsSpecial" means don't render this sample. if (i == sn || stream[i].IsSpecial()) { int svn = sv.size(); if (svn < 2) { sv.clear(); continue; } vec3 prep(-normalize(sv[1].p - sv[0].p) + sv[0].p); vec3 post(normalize(sv[svn - 1].p - sv[svn - 2].p) + sv[svn - 1].p); size_t vn = vertices.size(); vertices.resize(vn + svn + 2); vertices[vn] = {prep, sv[0].v}; vertices[vertices.size() - 1] = {post, sv[svn - 1].v}; memcpy(vertices.data() + vn + 1, sv.data(), sizeof(Vertex) * svn); sizes.push_back(svn + 2); sv.clear(); } else { const flow::Particle &p = stream[i]; if (_cache_isSteady) { sv.push_back({p.location, p.value}); } else { if (p.time > _timestamps.at(_cache_currentTS)) continue; if (p.time >= startingTime) sv.push_back({p.location, p.value}); } } } _renderStatus = FlowStatus::UPTODATE; } assert(glIsVertexArray(_VAO) == GL_TRUE); assert(glIsBuffer(_VBO) == GL_TRUE); glBindVertexArray(_VAO); glBindBuffer(GL_ARRAY_BUFFER, _VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size(), vertices.data(), GL_STREAM_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); _streamSizes = sizes; } bool show_dir = rp->GetValueLong(FlowParams::RenderShowStreamDirTag, false); _renderAdvectionHelper(show_dir); if (show_dir) _renderAdvectionHelper(false); return 0; } int FlowRenderer::_renderAdvectionHelper(bool renderDirection) { auto rp = GetActiveParams(); FlowParams::RenderType renderType = (FlowParams::RenderType)rp->GetValueLong(FlowParams::RenderTypeTag, FlowParams::RenderTypeStream); FlowParams::GlpyhType glyphType = (FlowParams::GlpyhType)rp->GetValueLong(FlowParams::RenderGlyphTypeTag, FlowParams::GlpyhTypeSphere); bool geom3d = rp->GetValueLong(FlowParams::RenderGeom3DTag, false); float radiusBase = rp->GetValueDouble(FlowParams::RenderRadiusBaseTag, -1); if (radiusBase == -1) { CoordType mind, maxd; // Need to find a non-empty variable from color mapping or velocity variables. std::string nonEmptyVarName = rp->GetColorMapVariableName(); if (nonEmptyVarName.empty()) { for (auto it = _velocityField.VelocityNames.cbegin(); it != _velocityField.VelocityNames.cend(); ++it) { if (!it->empty()) { nonEmptyVarName = *it; break; } } } assert(!nonEmptyVarName.empty()); _dataMgr->GetVariableExtents(rp->GetCurrentTimestep(), nonEmptyVarName, rp->GetRefinementLevel(), rp->GetCompressionLevel(), mind, maxd); vec3 min(mind[0], mind[1], mind[2]); vec3 max(maxd[0], maxd[1], maxd[2]); vec3 lens = max - min; float largestDim = glm::max(lens.x, glm::max(lens.y, lens.z)); radiusBase = largestDim / 560.f; rp->SetValueDouble(FlowParams::RenderRadiusBaseTag, "", radiusBase); } float radiusScalar = rp->GetValueDouble(FlowParams::RenderRadiusScalarTag, 1); float radius = radiusBase * radiusScalar; int glyphStride = rp->GetValueLong(FlowParams::RenderGlyphStrideTag, 5); ShaderProgram *shader = nullptr; if (renderType == FlowParams::RenderTypeStream) { if (geom3d) if (renderDirection) shader = _glManager->shaderManager->GetShader("FlowGlyphsTubeDirArrow"); else shader = _glManager->shaderManager->GetShader("FlowTubes"); else if (renderDirection) shader = _glManager->shaderManager->GetShader("FlowGlyphsLineDirArrow2D"); else shader = _glManager->shaderManager->GetShader("FlowLines"); } else if (renderType == FlowParams::RenderTypeSamples) { if (glyphType == FlowParams::GlpyhTypeSphere) if (geom3d) shader = _glManager->shaderManager->GetShader("FlowGlyphsSphereSplat"); else shader = _glManager->shaderManager->GetShader("FlowGlyphsSphere2D"); else if (geom3d) shader = _glManager->shaderManager->GetShader("FlowGlyphsArrow"); else shader = _glManager->shaderManager->GetShader("FlowGlyphsArrow2D"); } else { shader = _glManager->shaderManager->GetShader("FlowLines"); } if (!shader) return -1; double m[16]; double cameraPosD[3], cameraUpD[3], cameraDirD[3]; _paramsMgr->GetViewpointParams(_winName)->GetModelViewMatrix(m); _paramsMgr->GetViewpointParams(_winName)->ReconstructCamera(m, cameraPosD, cameraUpD, cameraDirD); vec3 cameraDir = vec3(cameraDirD[0], cameraDirD[1], cameraDirD[2]); vec3 cameraPos = vec3(cameraPosD[0], cameraPosD[1], cameraPosD[2]); shader->Bind(); shader->SetUniform("P", _glManager->matrixManager->GetProjectionMatrix()); shader->SetUniform("MV", _glManager->matrixManager->GetModelViewMatrix()); shader->SetUniform("aspect", _glManager->matrixManager->GetProjectionAspectRatio()); shader->SetUniform("radius", radius); shader->SetUniform("lightingEnabled", true); shader->SetUniform("glyphStride", glyphStride); shader->SetUniform("showOnlyLeadingSample", (bool)rp->GetValueLong(FlowParams::RenderGlyphOnlyLeadingTag, false)); shader->SetUniform("scales", _getScales()); shader->SetUniform("cameraPos", cameraPos); if (rp->GetValueLong(FlowParams::RenderLightAtCameraTag, true)) shader->SetUniform("lightDir", cameraDir); else shader->SetUniform("lightDir", vec3(0, 0, -1)); shader->SetUniform("phongAmbient", (float)rp->GetValueDouble(FlowParams::PhongAmbientTag, 0)); shader->SetUniform("phongDiffuse", (float)rp->GetValueDouble(FlowParams::PhongDiffuseTag, 0)); shader->SetUniform("phongSpecular", (float)rp->GetValueDouble(FlowParams::PhongSpecularTag, 0)); shader->SetUniform("phongShininess", (float)rp->GetValueDouble(FlowParams::PhongShininessTag, 0)); shader->SetUniform("mapRange", glm::make_vec2(_colorMapRange)); shader->SetUniform("fade_tails", (bool)rp->GetValueLong(FlowParams::RenderFadeTailTag, 0)); shader->SetUniform("fade_start", (int)rp->GetValueLong(FlowParams::RenderFadeTailStartTag, 10)); shader->SetUniform("fade_length", (int)rp->GetValueLong(FlowParams::RenderFadeTailLengthTag, 10)); shader->SetUniform("fade_stop", (int)rp->GetValueLong(FlowParams::RenderFadeTailStopTag, 0)); shader->SetUniform("density", renderType == FlowParams::RenderTypeDensity); shader->SetUniform("falloff", (float)rp->GetValueDouble(FlowParams::RenderDensityFalloffTag, 1)); shader->SetUniform("tone", (float)rp->GetValueDouble(FlowParams::RenderDensityToneMappingTag, 1)); // Features supported by shaders but not implemented in GUI/not finished // // shader->SetUniform("constantColorEnabled", false); // shader->SetUniform("Color", vec3(1.0f)); // shader->SetUniform("antiAlias", (bool)rp->GetValueLong("anti_alias", 0)); // auto bcd = rp->GetValueDoubleVec("border_color"); // if (bcd.size()) // shader->SetUniform("borderColor", vec3((float)bcd[0], bcd[1], bcd[2])); // shader->SetUniform("border", (float)rp->GetValueDouble("border", 0)); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, _colorMapTexId); shader->SetUniform("LUT", 0); EnableClipToBox(shader, 0.01); glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glEnable(GL_BLEND); glBindVertexArray(_VAO); if (renderType == FlowParams::RenderTypeDensity) { glBlendFunc(GL_SRC_ALPHA, GL_ONE); if (rp->GetValueLong("invert", false)) glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); else glBlendEquation(GL_FUNC_ADD); glDepthMask(GL_FALSE); } size_t offset = 0; for (int n : _streamSizes) { shader->SetUniform("nVertices", n); glDrawArrays(GL_LINE_STRIP_ADJACENCY, offset, n); offset += n; } glDepthMask(GL_TRUE); glDisable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glBindVertexArray(0); glDisable(GL_CULL_FACE); shader->UnBind(); DisableClippingPlanes(); return 0; } glm::vec3 FlowRenderer::_getScales() { string myVisName = GetVisualizer(); VAPoR::ViewpointParams *vpp = _paramsMgr->GetViewpointParams(myVisName); string datasetName = GetMyDatasetName(); Transform * tDataset = vpp->GetTransform(datasetName); Transform * tRenderer = GetActiveParams()->GetTransform(); vector scales = tDataset->GetScales(); vector rendererScales = tRenderer->GetScales(); scales[0] *= rendererScales[0]; scales[1] *= rendererScales[1]; scales[2] *= rendererScales[2]; return vec3(scales[0], scales[1], scales[2]); } int FlowRenderer::_renderFromAnAdvectionLegacy(const flow::Advection *adv, FlowParams *params, bool fast) { size_t numOfStreams = adv->GetNumberOfStreams(); auto numOfPart = params->GetSteadyNumOfSteps() + 1; bool singleColor = params->UseSingleColor(); if (_cache_isSteady) { std::vector vec; for (size_t s = 0; s < numOfStreams; s++) { const auto &stream = adv->GetStreamAt(s); for (size_t i = 0; i < stream.size() && i < numOfPart; i++) { const auto &p = stream[i]; _particleHelper1(vec, p, singleColor); } // Finish processing a stream if (!vec.empty()) { _drawALineStrip(vec.data(), vec.size() / 4, singleColor); vec.clear(); } } // Finish processing all streams } else // Unsteady flow (only occurs with forward direction) { // First calculate the starting time stamp double startingTime = _timestamps[0]; if (int(_cache_currentTS) - _cache_pastNumOfTimeSteps > 0) startingTime = _timestamps[_cache_currentTS - _cache_pastNumOfTimeSteps]; std::vector vec; for (size_t s = 0; s < numOfStreams; s++) { const auto &stream = adv->GetStreamAt(s); for (const auto &p : stream) { if (p.IsSpecial()) // If p is a separator, directly send it to the helper function { _particleHelper1(vec, p, singleColor); } else // Otherwise, examine its timestamp to decide how to handle { // Finish this stream once we go beyond the current TS if (p.time > _timestamps.at(_cache_currentTS)) break; // Only start this stream if the current time stamp passes startingTime if (p.time >= startingTime) _particleHelper1(vec, p, singleColor); } } // Finish processing a stream if (!vec.empty()) { _drawALineStrip(vec.data(), vec.size() / 4, singleColor); vec.clear(); } } // Finish processing all streams } return 0; } void FlowRenderer::_particleHelper1(std::vector &vec, const flow::Particle &p, bool singleColor) const { if (!p.IsSpecial()) // p isn't a separator { vec.push_back(p.location.x); vec.push_back(p.location.y); vec.push_back(p.location.z); vec.push_back(p.value); } else if (vec.size() > 0) // p is a separator and vec is non-empty { _drawALineStrip(vec.data(), vec.size() / 4, singleColor); vec.clear(); } } int FlowRenderer::_drawALineStrip(const float *buf, size_t numOfParts, bool singleColor) const { // Make some OpenGL function calls glm::mat4 modelview = _glManager->matrixManager->GetModelViewMatrix(); glm::mat4 projection = _glManager->matrixManager->GetProjectionMatrix(); _shader->Bind(); _shader->SetUniform("MV", modelview); _shader->SetUniform("Projection", projection); _shader->SetUniform("colorMapRange", glm::make_vec3(_colorMapRange)); _shader->SetUniform("singleColor", int(singleColor)); Renderer::EnableClipToBox(_shader, 0.01); glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset); glBindTexture(GL_TEXTURE_1D, _colorMapTexId); _shader->SetUniform("colorMapTexture", _colorMapTexOffset); glBindVertexArray(_vertexArrayId); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * numOfParts, buf, GL_STREAM_DRAW); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, (void *)0); glDrawArrays(GL_LINE_STRIP, 0, numOfParts); // Some OpenGL cleanup glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableVertexAttribArray(0); glBindTexture(GL_TEXTURE_1D, _colorMapTexId); glBindVertexArray(0); return 0; } int FlowRenderer::_updateFlowCacheAndStates(const FlowParams *params) { /* * This function servers two purposes: * 1) update the cached parameters, and 2) determine if the advection is out of date. * * Strategy: * First, compare parameters that if changed, they would put both steady and unsteady * streams out of date. * Second, branch into steady and unsteady cases, and deal with them separately. */ // Check seed generation mode if (_cache_seedGenMode != static_cast(params->GetSeedGenMode())) { _cache_seedGenMode = static_cast(params->GetSeedGenMode()); _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; } // Check seed input filename if (_cache_seedInputFilename != params->GetSeedInputFilename()) { _cache_seedInputFilename = params->GetSeedInputFilename(); // we only update status if the current seed generation mode IS seed list. if (_cache_seedGenMode == FlowSeedMode::LIST) { _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; } } // Check velocity variable names // If names not the same, entire stream is out of date // Note: variable names are kept in VaporFields. // Note: RenderParams always returns arrays of size 3 here. std::vector varnames = params->GetFieldVariableNames(); if ((varnames.at(0) != _velocityField.VelocityNames[0]) || (varnames.at(1) != _velocityField.VelocityNames[1]) || (varnames.at(2) != _velocityField.VelocityNames[2])) { _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; // When new velocity variables are selected, new particles will be generated, // so we should declare color status out of date too. _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; } // Check color mapping variable names std::string colorVarName = params->GetColorMapVariableName(); if (colorVarName != _colorField.ScalarName) { _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; } // Check compression parameters // If these parameters not the same, entire stream is out of date if (_cache_refinementLevel != params->GetRefinementLevel()) { _cache_refinementLevel = params->GetRefinementLevel(); _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } if (_cache_compressionLevel != params->GetCompressionLevel()) { _cache_compressionLevel = params->GetCompressionLevel(); _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } // Check velocity multiplier // If the multiplier is changed, then the entire stream is out of date if (_cache_velocityMltp != params->GetVelocityMultiplier()) { _cache_velocityMltp = params->GetVelocityMultiplier(); _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } // Check first step size multiplier // If the multiplier is changed, then the entire stream is out of date if (_cache_firstStepSizeMltp != params->GetFirstStepSizeMultiplier()) { _cache_firstStepSizeMltp = params->GetFirstStepSizeMultiplier(); _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } // Check if using the fixed advection steps. // If changed, then the entire stream is out ot date. if (_cache_useFixedAdvectionSteps != params->GetUseFixedAdvectionSteps()) { _cache_useFixedAdvectionSteps = params->GetUseFixedAdvectionSteps(); _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } // Check if the fixed advection step size is out of date only when specified to use fixed steps. if (_cache_useFixedAdvectionSteps && _cache_fixedAdvectionStepSize != params->GetFixedAdvectionStepSize()) { _cache_fixedAdvectionStepSize = params->GetFixedAdvectionStepSize(); _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } // Check periodicity // If periodicity changes along any dimension, then the entire stream is out of date // Note: FlowParams return a vector of size either 2 or 3. bool diff = false; const auto peri = params->GetPeriodic(); if (peri.size() != _cache_periodic.size()) diff = true; else { for (int i = 0; i < peri.size(); i++) if (peri[i] != _cache_periodic[i]) { diff = true; break; } } if (diff) { _cache_periodic = peri; _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } // Check the rake defined by 6 or 4 extents. // We update these parameters anyway, and decide if the advection is out of date in rake mode. diff = false; const auto rake = params->GetRake(); if (rake.size() != _cache_rake.size()) diff = true; else { for (int i = 0; i < rake.size(); i++) if (rake[i] != _cache_rake[i]) { diff = true; break; } } if (diff) { _cache_rake = rake; // Mark out-of-date if we're currently using any mode that involves a rake if (_cache_seedGenMode != FlowSeedMode::LIST) { _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } } // Check the gridded number of seeds in the rake diff = false; const auto gridNOS = params->GetGridNumOfSeeds(); if (gridNOS.size() != _cache_gridNumOfSeeds.size()) diff = true; else { for (int i = 0; i < gridNOS.size(); i++) if (gridNOS[i] != _cache_gridNumOfSeeds[i]) { diff = true; break; } } if (diff) { _cache_gridNumOfSeeds = gridNOS; if (_cache_seedGenMode == FlowSeedMode::UNIFORM) { _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } } // Check the random num of seeds const auto randNOS = params->GetRandomNumOfSeeds(); if (randNOS != _cache_randNumOfSeeds) { _cache_randNumOfSeeds = randNOS; if (_cache_seedGenMode == FlowSeedMode::RANDOM || _cache_seedGenMode == FlowSeedMode::RANDOM_BIAS) { _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } } // Check the bias variable and bias strength const auto rakeBiasVariable = params->GetRakeBiasVariable(); const auto rakeBiasStrength = params->GetRakeBiasStrength(); if (_cache_rakeBiasStrength != rakeBiasStrength || _cache_rakeBiasVariable.compare(rakeBiasVariable) != 0) { _cache_rakeBiasVariable = rakeBiasVariable; _cache_rakeBiasStrength = rakeBiasStrength; if (_cache_seedGenMode == FlowSeedMode::RANDOM_BIAS) { _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } } const auto doIntegration = params->GetValueLong(params->_doIntegrationTag, false); const auto integrationSetAllToFinalValue = params->GetValueLong(params->_integrationSetAllToFinalValueTag, false); const auto integrationDistScalar = params->GetValueDouble(params->_integrationScalarTag, false); const auto integrationVolume = params->GetValueDoubleVec(params->_integrationBoxTag); if (doIntegration != _cache_doIntegration || integrationSetAllToFinalValue != _cache_integrationSetAllToFinalValue || integrationDistScalar != _cache_integrationDistScalar || integrationVolume != _cache_integrationVolume) { _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; } _cache_doIntegration = doIntegration; _cache_integrationSetAllToFinalValue = integrationSetAllToFinalValue; _cache_integrationDistScalar = integrationDistScalar; _cache_integrationVolume = integrationVolume; // // Now we branch into steady and unsteady cases, and treat them separately // if (params->GetIsSteady()) { if (_cache_isSteady) // steady state isn't changed { if (params->GetSteadyNumOfSteps() > _cache_steadyNumOfSteps) { if (_colorStatus == FlowStatus::UPTODATE) _colorStatus = FlowStatus::TIME_STEP_OOD; if (_velocityStatus == FlowStatus::UPTODATE) _velocityStatus = FlowStatus::TIME_STEP_OOD; } if (params->GetSteadyNumOfSteps() != _cache_steadyNumOfSteps) _renderStatus = FlowStatus::SIMPLE_OUTOFDATE; if (params->GetSteadyNumOfSteps() < _cache_steadyNumOfSteps && doIntegration) _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _cache_steadyNumOfSteps = params->GetSteadyNumOfSteps(); if (_cache_currentTS != params->GetCurrentTimestep()) { _cache_currentTS = params->GetCurrentTimestep(); _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } } else // switched from unsteady to steady. Everything is out of date in this case. { _cache_isSteady = true; _cache_steadyNumOfSteps = params->GetSteadyNumOfSteps(); _cache_currentTS = params->GetCurrentTimestep(); _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } if (_cache_flowDir != static_cast(params->GetFlowDirection())) { _cache_flowDir = static_cast(params->GetFlowDirection()); _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; if (_cache_flowDir == FlowDir::BI_DIR) _2ndAdvection.reset(new flow::Advection()); else _2ndAdvection.reset(nullptr); } } else // in case of unsteady flow { if (!_cache_isSteady) // unsteady state isn't changed { // First consider if the advection needs to be updated. if (_cache_currentTS < params->GetCurrentTimestep()) { if (_colorStatus == FlowStatus::UPTODATE) { _colorStatus = FlowStatus::TIME_STEP_OOD; } if (_velocityStatus == FlowStatus::UPTODATE) { _velocityStatus = FlowStatus::TIME_STEP_OOD; } } // Second consider if the rendering needs to be updated. if (_cache_currentTS != params->GetCurrentTimestep() || _cache_pastNumOfTimeSteps != params->GetPastNumOfTimeSteps()) { _renderStatus = FlowStatus::SIMPLE_OUTOFDATE; } _cache_currentTS = params->GetCurrentTimestep(); _cache_steadyNumOfSteps = params->GetSteadyNumOfSteps(); _cache_pastNumOfTimeSteps = params->GetPastNumOfTimeSteps(); } else // switched from steady to unsteady { _cache_isSteady = false; _cache_steadyNumOfSteps = params->GetSteadyNumOfSteps(); _cache_currentTS = params->GetCurrentTimestep(); _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } if (_cache_seedInjInterval != params->GetSeedInjInterval()) { _cache_seedInjInterval = params->GetSeedInjInterval(); _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE; } } return 0; } void FlowRenderer::_dupSeedsNewTime(std::vector &seeds, size_t firstN, double newTime) const { VAssert(firstN <= seeds.size()); for (size_t i = 0; i < firstN; i++) seeds.emplace_back(seeds[i].location, newTime); } int FlowRenderer::_genSeedsRakeUniform(std::vector &seeds) const { FlowParams *params = dynamic_cast(GetActiveParams()); VAssert(params); // sanity check: rake extents and uniform seed numbers match dims size_t dim = _cache_gridNumOfSeeds.size(); VAssert(dim == 2 || dim == 3); VAssert(_cache_rake.size() == dim * 2); // Populate the list of seeds float start[3], step[3]; for (size_t i = 0; i < dim; i++) { step[i] = (_cache_rake[i * 2 + 1] - _cache_rake[i * 2]) / float(_cache_gridNumOfSeeds[i]); start[i] = _cache_rake[i * 2]; } if (dim == 2) { start[2] = Renderer::GetDefaultZ(_dataMgr, params->GetCurrentTimestep()); step[2] = 0.0f; } size_t seedsZ = 1; if (dim == 3) { seedsZ = _cache_gridNumOfSeeds[2]; } auto timeVal = _timestamps.at(0); // Default time value glm::vec3 loc; seeds.clear(); seeds.reserve(seedsZ * _cache_gridNumOfSeeds[1] * _cache_gridNumOfSeeds[0]); for (long k = 0; k < seedsZ; k++) { for (long j = 0; j < _cache_gridNumOfSeeds[1]; j++) { for (long i = 0; i < _cache_gridNumOfSeeds[0]; i++) { loc.x = start[0] + (float(i) + 0.5f) * step[0]; loc.y = start[1] + (float(j) + 0.5f) * step[1]; loc.z = start[2] + (float(k) + 0.5f) * step[2]; seeds.emplace_back(loc, timeVal); } } } // If in unsteady case and there are multiple seed injections, // we insert more seeds. if (!_cache_isSteady && _cache_seedInjInterval > 0) { size_t firstN = seeds.size(); // Check every time step available, see if we need to inject seeds at that time step for (size_t ts = 1; ts < _timestamps.size(); ts++) if (ts % _cache_seedInjInterval == 0) { _dupSeedsNewTime(seeds, firstN, _timestamps[ts]); } } return 0; } int FlowRenderer::_genSeedsFromList(std::vector &seeds) const { FlowParams *params = dynamic_cast(GetActiveParams()); VAssert(params); // Read seed locations (X, Y, Z) from a file. std::vector read_from_disk = flow::InputSeedsCSV(params->GetSeedInputFilename()); if (read_from_disk.empty()) return flow::NO_SEED_PARTICLE_YET; // Set seed time to be the time stamp at step 0 double timeVal = _timestamps.at(0); for (auto &seed : read_from_disk) seed.time = timeVal; seeds = std::move(read_from_disk); // If in unsteady case and there are multiple seed injections, we insert more seeds. if (!_cache_isSteady && _cache_seedInjInterval > 0) { size_t firstN = seeds.size(); // Check every time step available, see if we need to inject seeds at that time step for (size_t ts = 1; ts < _timestamps.size(); ts++) { if (ts % _cache_seedInjInterval == 0) { _dupSeedsNewTime(seeds, firstN, _timestamps[ts]); } } } return 0; } int FlowRenderer::_genSeedsRakeRandom(std::vector &seeds) const { FlowParams *params = dynamic_cast(GetActiveParams()); VAssert(_cache_rake.size() == 6 || _cache_rake.size() == 4); int dim = _cache_rake.size() / 2; for (int i = 0; i < dim; i++) VAssert(_cache_rake[i * 2 + 1] >= _cache_rake[i * 2]); /* Create uniform distributions along 2 or 3 dimensions */ /* Use a fixed value for the generator seed. */ unsigned int randSeed = 32; std::mt19937 gen(randSeed); // Standard mersenne_twister_engine std::uniform_real_distribution distX(_cache_rake[0], _cache_rake[1]); std::uniform_real_distribution distY(_cache_rake[2], _cache_rake[3]); auto timeVal = _timestamps.at(0); seeds.resize(_cache_randNumOfSeeds); if (dim == 3) { std::uniform_real_distribution distZ(_cache_rake[4], _cache_rake[5]); for (long i = 0; i < _cache_randNumOfSeeds; i++) { seeds[i].location.x = distX(gen); seeds[i].location.y = distY(gen); seeds[i].location.z = distZ(gen); seeds[i].time = timeVal; } } else { const float dfz = Renderer::GetDefaultZ(_dataMgr, params->GetCurrentTimestep()); for (long i = 0; i < _cache_randNumOfSeeds; i++) { seeds[i].location.x = distX(gen); seeds[i].location.y = distY(gen); seeds[i].location.z = dfz; seeds[i].time = timeVal; } } // If in unsteady case and there are multiple seed injections, we insert more seeds. if (!_cache_isSteady && _cache_seedInjInterval > 0) { size_t firstN = seeds.size(); // Check every time step available, see if we need to inject seeds at that time step for (size_t ts = 1; ts < _timestamps.size(); ts++) { if (ts % _cache_seedInjInterval == 0) { _dupSeedsNewTime(seeds, firstN, _timestamps[ts]); } } } return 0; } int FlowRenderer::_genSeedsRakeRandomBiased(std::vector &seeds) const { FlowParams *params = dynamic_cast(GetActiveParams()); VAssert(_cache_rake.size() == 6 || _cache_rake.size() == 4); int dim = _cache_rake.size() / 2; for (int i = 0; i < dim; i++) VAssert(_cache_rake[i * 2 + 1] >= _cache_rake[i * 2]); CoordType rakeExtMin = {0.0, 0.0, 0.0}; CoordType rakeExtMax = {0.0, 0.0, 0.0}; for (int i = 0; i < dim; i++) { rakeExtMin[i] = _cache_rake[i * 2]; rakeExtMax[i] = _cache_rake[i * 2 + 1]; } const auto numOfSeedsNeeded = _cache_randNumOfSeeds; /* request a grid representing the rake area */ Grid *grid = _dataMgr->GetVariable(params->GetCurrentTimestep(), _cache_rakeBiasVariable, params->GetRefinementLevel(), params->GetCompressionLevel(), rakeExtMin, rakeExtMax); if (grid == nullptr) { MyBase::SetErrMsg("Not able to get a grid!"); return flow::GRID_ERROR; } /* * The bias strategy is: * We generate more random seeds than needed, and then sort them. * The first batch of these seeds are used as the final seeds. */ /* Create three uniform distributions in 3 dimensions */ unsigned int procID = 32; std::mt19937 gen(procID); // Standard mersenne_twister engine std::uniform_real_distribution distX(_cache_rake[0], _cache_rake[1]); std::uniform_real_distribution distY(_cache_rake[2], _cache_rake[3]); // Now we generate many seeds. // We test missing values in case 1) the bias variable does have missing values, and 2) // the rake extents are outside of the bias variable. // Thus, we only keep random seeds that are falling on non-missing-value locations. glm::vec3 loc; std::vector locD(3); auto timeVal = _timestamps.at(0); // This is the total number of seeds to generate, based on the bias strength. auto numOfSeedsToGen = numOfSeedsNeeded * (std::abs(_cache_rakeBiasStrength) + 1); long numOfTrials = 0; seeds.clear(); seeds.reserve(numOfSeedsToGen); // For performance reasons // Note: in the case that too many random seeds fall on missing values, // we set a limit of 10 times numOfSeedsToGen. long numOfTrialLimit = 10 * numOfSeedsToGen; float val, mv = grid->GetMissingValue(); if (dim == 3) { std::uniform_real_distribution distZ(_cache_rake[4], _cache_rake[5]); while (numOfTrials < numOfTrialLimit && seeds.size() < numOfSeedsToGen) { loc.x = distX(gen); locD[0] = loc.x; loc.y = distY(gen); locD[1] = loc.y; loc.z = distZ(gen); locD[2] = loc.z; val = grid->GetValue(locD); if (val != mv) seeds.emplace_back(loc, timeVal, val); numOfTrials++; } } else // dim == 2 { const auto dfz = Renderer::GetDefaultZ(_dataMgr, params->GetCurrentTimestep()); loc.z = dfz; locD[2] = dfz; while (numOfTrials < numOfTrialLimit && seeds.size() < numOfSeedsToGen) { loc.x = distX(gen); locD[0] = loc.x; loc.y = distY(gen); locD[1] = loc.y; val = grid->GetValue(locD); if (val != mv) seeds.emplace_back(loc, timeVal, val); numOfTrials++; } } delete grid; // Delete the temporary grid // If we reach numOfTrialLimit without collecting enough seeds, bail. if (numOfTrials == numOfTrialLimit && seeds.size() < numOfSeedsNeeded) { seeds.clear(); return flow::GRID_ERROR; } // How we sort all seeds based on their values auto ascLambda = [](const flow::Particle &p1, const flow::Particle &p2) { return p1.value < p2.value; }; auto desLambda = [](const flow::Particle &p1, const flow::Particle &p2) { return p2.value < p1.value; }; if (_cache_rakeBiasStrength < 0) { std::nth_element(seeds.begin(), seeds.begin() + numOfSeedsNeeded, seeds.end(), ascLambda); } else { std::nth_element(seeds.begin(), seeds.begin() + numOfSeedsNeeded, seeds.end(), desLambda); } seeds.resize(numOfSeedsNeeded); // We only take first chunck of seeds that we need seeds.shrink_to_fit(); // Free up some memory for (auto &e : seeds) { // reset the value field of each particle e.value = 0.0; } // If in unsteady case and there are multiple seed injections, we insert more seeds. if (!_cache_isSteady && _cache_seedInjInterval > 0) { size_t firstN = seeds.size(); // Check every time step available, see if we need to inject seeds at that time step for (size_t ts = 1; ts < _timestamps.size(); ts++) { if (ts % _cache_seedInjInterval == 0) { _dupSeedsNewTime(seeds, firstN, _timestamps[ts]); } } } return 0; } void FlowRenderer::_prepareColormap(FlowParams *params) { if (params->UseSingleColor()) { float singleColor[4]; params->GetConstantColor(singleColor); singleColor[3] = 1.0f; // 1.0 in alpha channel _colorMap.resize(8); // _colorMap will have 2 RGBA values for (int i = 0; i < 8; i++) _colorMap[i] = singleColor[i % 4]; _colorMapRange[0] = 0.0f; // min value of the color map _colorMapRange[1] = 0.0f; // max value of the color map _colorMapRange[2] = 1e-5f; // diff of color map. Has to be non-zero though. } else { // This is the line that's not const VAPoR::MapperFunction *mapperFunc = params->GetMapperFunc(params->GetColorMapVariableName()); mapperFunc->makeLut(_colorMap); assert(_colorMap.size() % 4 == 0); std::vector range = mapperFunc->getMinMaxMapValue(); _colorMapRange[0] = float(range[0]); _colorMapRange[1] = float(range[1]); _colorMapRange[2] = (_colorMapRange[1] - _colorMapRange[0]) > 1e-5f ? (_colorMapRange[1] - _colorMapRange[0]) : 1e-5f; } glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset); glBindTexture(GL_TEXTURE_1D, _colorMapTexId); glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, _colorMap.size() / 4, 0, GL_RGBA, GL_FLOAT, _colorMap.data()); } void FlowRenderer::_restoreGLState() const { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, 0); } int FlowRenderer::_updateAdvectionPeriodicity(flow::Advection *advc) { glm::vec3 minxyz, maxxyz; int rv = _velocityField.GetVelocityIntersection(_cache_currentTS, minxyz, maxxyz); if (rv != 0) return rv; if (_cache_periodic[0]) advc->SetXPeriodicity(true, minxyz.x, maxxyz.x); else advc->SetXPeriodicity(false, 0.0f, 1.0f); if (_cache_periodic[1]) advc->SetYPeriodicity(true, minxyz.y, maxxyz.y); else advc->SetYPeriodicity(false, 0.0f, 1.0f); if (_cache_periodic.size() == 2) advc->SetZPeriodicity(false, 0.0f, 1.0f); else { if (_cache_periodic[2]) advc->SetZPeriodicity(true, minxyz.z, maxxyz.z); else advc->SetZPeriodicity(false, 0.0f, 1.0f); } return 0; } void FlowRenderer::_printNonZero(int rtn, const char *file, const char *func, int line) const { #ifdef VPRINT if (rtn != 0) { printf("Rtn == %d: %s:(%s):%d\n", rtn, file, func, line); } #endif } ================================================ FILE: lib/render/Font.cpp ================================================ #include "vapor/glutil.h" #include "vapor/Font.h" #include "vapor/VAssert.h" #include "vapor/ShaderManager.h" #include #include "vapor/GLManager.h" using namespace VAPoR; using glm::vec2; using std::string; Font::Font(GLManager *glManager, const std::string &path, int size, FT_Library library) : _glManager(glManager), _library(nullptr), _size(size) { if (library == nullptr) { int err = FT_Init_FreeType(&_library); VAssert(!err); library = _library; } int err = FT_New_Face(library, path.c_str(), 0, &_face); VAssert(!err); FT_Set_Pixel_Sizes(_face, 0, _size); glGenVertexArrays(1, &_VAO); glGenBuffers(1, &_VBO); glBindVertexArray(_VAO); glBindBuffer(GL_ARRAY_BUFFER, _VBO); glBufferData(GL_ARRAY_BUFFER, 6 * 4 * sizeof(float), NULL, GL_STREAM_DRAW); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } Font::~Font() { FT_Done_Face(_face); if (_library) FT_Done_FreeType(_library); glDeleteVertexArrays(1, &_VAO); glDeleteBuffers(1, &_VBO); for (auto it = _glyphMap.begin(); it != _glyphMap.end(); ++it) glDeleteTextures(1, &it->second.textureID); } bool Font::LoadGlyph(int c) { if (FT_Load_Char(_face, c, FT_LOAD_RENDER)) { printf("FAILED TO LOAD CHAR\n"); return false; } unsigned int texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, _face->glyph->bitmap.width, _face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE, _face->glyph->bitmap.buffer); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); _glyphMap[c] = {texture, (int)_face->glyph->bitmap.width, (int)_face->glyph->bitmap.rows, _face->glyph->bitmap_left, _face->glyph->bitmap_top, _face->glyph->advance.x}; return true; } Font::Glyph Font::GetGlyph(int c) { auto it = _glyphMap.find(c); if (it == _glyphMap.end()) { LoadGlyph(c); return _glyphMap[c]; } return it->second; } void Font::DrawText(const std::string &text, const glm::vec4 &color) { SmartShaderProgram shader = _glManager->shaderManager->GetSmartShader("font"); shader->SetUniform("MVP", _glManager->matrixManager->GetModelViewProjectionMatrix()); shader->SetUniform("color", color); glActiveTexture(GL_TEXTURE0); glBindVertexArray(_VAO); glBindBuffer(GL_ARRAY_BUFFER, _VBO); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); const float xStart = 0; const float yStart = 0; float cursorX = xStart; float cursorY = yStart; for (int i = 0; i < text.size(); i++) { if (text[i] == '\n') { cursorY -= LineHeight(); cursorX = xStart; continue; } if (text[i] == '\r') { cursorX = xStart; continue; } Glyph ch = GetGlyph(text[i]); float x = cursorX + ch.bearingX; float y = cursorY - (ch.sizeY - ch.bearingY); float w = ch.sizeX; float h = ch.sizeY; float vertices[6][4] = {{x, y + h, 0, 0}, {x, y, 0, 1}, {x + w, y, 1, 1}, {x, y + h, 0, 0}, {x + w, y, 1, 1}, {x + w, y + h, 1, 0}}; glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); glBindTexture(GL_TEXTURE_2D, ch.textureID); glDrawArrays(GL_TRIANGLES, 0, 6); cursorX += ch.advance / 64; } glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_BLEND); } glm::vec2 Font::TextDimensions(const std::string &text) { vec2 dimensions(0.f); float lineWidth = 0; float maxHeightForLine = 0; for (int i = 0; i < text.size(); i++) { if (text[i] == '\n') { if (lineWidth > dimensions.x) dimensions.x = lineWidth; dimensions.y += LineHeight(); maxHeightForLine = 0; lineWidth = 0; continue; } if (text[i] == '\r') { if (lineWidth > dimensions.x) dimensions.x = lineWidth; lineWidth = 0; continue; } Glyph ch = GetGlyph(text[i]); lineWidth += ch.advance / 64; if (ch.sizeY > maxHeightForLine) maxHeightForLine = ch.sizeY; } if (lineWidth > dimensions.x) dimensions.x = lineWidth; dimensions.y += maxHeightForLine; return dimensions; } float Font::LineHeight() const { return _face->size->metrics.height / 64; // return _face->height / 64; } ================================================ FILE: lib/render/FontManager.cpp ================================================ #include "vapor/glutil.h" #include "vapor/FontManager.h" #include using namespace VAPoR; using namespace Wasp; using std::map; using std::pair; using std::string; FontManager::FontManager(GLManager *glManager) : _glManager(glManager), _library(nullptr) { VAssert(glManager); VAssert(!FT_Init_FreeType(&_library)); } FontManager::~FontManager() { for (auto it = _map.begin(); it != _map.end(); ++it) delete it->second; _map.clear(); if (_library) FT_Done_FreeType(_library); } Font *FontManager::GetFont(const std::string &name, unsigned int size) { return GetResource(pair(name, size)); } int FontManager::LoadResourceByKey(const std::pair &key) { if (HasResource(key)) { VAssert(!"Font already loaded"); return -1; } const string name = key.first; const unsigned int size = key.second; const string path = GetSharePath("fonts/" + name + ".ttf"); Font * f = new Font(_glManager, path, size, _library); AddResource(key, f); return 1; } ================================================ FILE: lib/render/Framebuffer.cpp ================================================ #include #include #include #include "vapor/VAssert.h" using namespace VAPoR; Framebuffer::~Framebuffer() { if (_id) glDeleteFramebuffers(1, &_id); _id = 0; } int Framebuffer::Generate() { VAssert(!Initialized()); GLint savedId; glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &savedId); glGenFramebuffers(1, &_id); glBindFramebuffer(GL_FRAMEBUFFER, _id); VAssert(_id); _colorBuffer.Generate(); _colorBuffer.TexImage(GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _colorBuffer._id, 0); if (_hasDepthBuffer) { _depthBuffer.Generate(); _depthBuffer.TexImage(GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depthBuffer._id, 0); } glBindFramebuffer(GL_FRAMEBUFFER, savedId); return 0; } bool Framebuffer::Initialized() const { return _id; } bool Framebuffer::IsComplete() const { return Initialized() && GetStatus() == GL_FRAMEBUFFER_COMPLETE; } int Framebuffer::GetStatus() const { return glCheckFramebufferStatus(GL_FRAMEBUFFER); } const char *Framebuffer::GetStatusString() const { return GetStatusString(GetStatus()); } const char *Framebuffer::GetStatusString(int status) { switch (status) { case GL_FRAMEBUFFER_COMPLETE: return "GL_FRAMEBUFFER_COMPLETE"; case GL_FRAMEBUFFER_UNDEFINED: return "GL_FRAMEBUFFER_UNDEFINED"; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: return "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: return "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; case GL_FRAMEBUFFER_UNSUPPORTED: return "GL_FRAMEBUFFER_UNSUPPORTED"; case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: return "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; default: return "Unknown GL enum"; } } void Framebuffer::Bind() { VAssert(Initialized()); glBindFramebuffer(GL_FRAMEBUFFER, _id); } void Framebuffer::UnBind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } void Framebuffer::SetSize(int width, int height) { VAssert(Initialized()); width = width <= 0 ? 1 : width; height = height <= 0 ? 1 : height; if (width != _width || height != _height) { _width = width; _height = height; _colorBuffer.TexImage(GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); if (_hasDepthBuffer) _depthBuffer.TexImage(GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); } } void Framebuffer::GetSize(int *width, int *height) const { *width = _width; *height = _height; } int Framebuffer::MakeRenderTarget() { Bind(); if (!IsComplete()) { Wasp::MyBase::SetErrMsg("Incomplete framebuffer: %s\n", GetStatusString()); UnBind(); VAssert(false); return -1; } glViewport(0, 0, _width, _height); return 0; } void Framebuffer::EnableDepthBuffer() { VAssert(!Initialized()); _hasDepthBuffer = true; } const Texture2D *Framebuffer::GetColorTexture() const { VAssert(Initialized()); return &_colorBuffer; } const Texture2D *Framebuffer::GetDepthTexture() const { VAssert(Initialized()); if (!_hasDepthBuffer) { VAssert(!"Depth buffer requested from Framebuffer that does not have one"); return nullptr; } return &_depthBuffer; } ================================================ FILE: lib/render/GLManager.cpp ================================================ #include "vapor/glutil.h" #include "vapor/GLManager.h" #include "vapor/LegacyGL.h" #include "vapor/FontManager.h" #include "vapor/STLUtils.h" #include using namespace VAPoR; using namespace std::chrono; GLManager::Vendor GLManager::_cachedVendor = Vendor::Unknown; GLManager::GLManager() : shaderManager(new ShaderManager), fontManager(new FontManager(this)), matrixManager(new MatrixManager), legacy(new LegacyGL(this)) { _queryVendor(); } GLManager::~GLManager() { delete shaderManager; delete fontManager; delete matrixManager; delete legacy; } std::vector GLManager::GetViewport() { GLint v[4] = {0}; glGetIntegerv(GL_VIEWPORT, v); return {v[0], v[1], v[2], v[3]}; } glm::vec2 GLManager::GetViewportSize() { const auto v = GetViewport(); return glm::vec2(v[2] - v[0], v[3] - v[1]); } void GLManager::PixelCoordinateSystemPush() { MatrixManager * mm = matrixManager; std::vector viewport = GLManager::GetViewport(); mm->MatrixModeProjection(); mm->PushMatrix(); mm->Ortho(viewport[0], viewport[2], viewport[1], viewport[3]); mm->MatrixModeModelView(); mm->PushMatrix(); mm->LoadIdentity(); } void GLManager::PixelCoordinateSystemPop() { MatrixManager *mm = matrixManager; mm->PopMatrix(); mm->MatrixModeProjection(); mm->PopMatrix(); mm->MatrixModeModelView(); } GLManager::Vendor GLManager::GetVendor() { return _cachedVendor; } void GLManager::_queryVendor() { string vendorString((const char *)glGetString(GL_VERSION)); vendorString = STLUtils::ToLower(vendorString); if (STLUtils::Contains(vendorString, "intel")) _cachedVendor = Vendor::Intel; else if (STLUtils::Contains(vendorString, "nvidia")) _cachedVendor = Vendor::Nvidia; else if (STLUtils::Contains(vendorString, "amd")) _cachedVendor = Vendor::AMD; else if (STLUtils::Contains(vendorString, "mesa")) _cachedVendor = Vendor::Mesa; else _cachedVendor = Vendor::Other; } void GLManager::GetGLVersion(int *major, int *minor) { // Only >=3.0 guarentees glGetIntegerv string version = string((const char *)glGetString(GL_VERSION)); version = version.substr(0, version.find(" ")); const string majorString = version.substr(0, version.find(".")); *major = std::stoi(majorString); if (majorString.length() < version.length()) { version = version.substr(majorString.length() + 1); const string minorString = version.substr(0, version.find(".")); if (!minorString.empty()) *minor = std::stoi(minorString); else *minor = 0; } } int GLManager::GetGLSLVersion() { int major, minor; GetGLVersion(&major, &minor); // This does not work for < OpenGL 3.3 but we do not support it anyway return 100 * major + 10 * minor; } bool GLManager::IsCurrentOpenGLVersionSupported() { int major, minor; GetGLVersion(&major, &minor); int version = major * 100 + minor; if (version >= 303) return true; Wasp::MyBase::SetErrMsg("OpenGL Version \"%s\" is too low and is not supported", glGetString(GL_VERSION)); return false; } bool GLManager::CheckError() { int err = glGetError(); if (err != GL_NO_ERROR) { return false; } return true; } #ifndef NDEBUG void GLManager::ShowDepthBuffer() { static bool initialized = false; static unsigned int VAO = 0; static unsigned int VBO = 0; static unsigned int texID = 0; static float BL = 0.5; static float data[] = {BL, BL, 0, 0, 1, BL, 1, 0, BL, 1, 0, 1, BL, 1, 0, 1, 1, BL, 1, 0, 1, 1, 1, 1}; // Since this is just for debugging purposes, initialized stays false to support use in multiple contexts if (!initialized) { glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float))); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } GLint viewport[4] = {0}; glGetIntegerv(GL_VIEWPORT, viewport); glBindTexture(GL_TEXTURE_2D, texID); // glReadBuffer(GL_BACK); glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, viewport[0], viewport[1], viewport[2], viewport[3], 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texID); glBindVertexArray(VAO); SmartShaderProgram shader = shaderManager->GetSmartShader("DepthBuffer"); shader->SetUniform("near", matrixManager->Near); shader->SetUniform("far", matrixManager->Far); shader->SetUniform("linearize", true); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); } #endif void *GLManager::BeginTimer() { glFinish(); auto start = new chrono::time_point; *start = chrono::high_resolution_clock::now(); return start; } double GLManager::EndTimer(void *startTime) { VAssert(startTime); auto start = (chrono::time_point *)startTime; glFinish(); auto stop = chrono::high_resolution_clock::now(); auto duration = chrono::duration_cast(stop - *start); delete start; return (double)duration.count() / 1000000.0; } ================================================ FILE: lib/render/GeoImage.cpp ================================================ #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include #include "vapor/GeoImage.h" #ifdef WIN32 #pragma warning(disable : 4996) #endif using namespace VAPoR; using namespace Wasp; namespace { // Error handling for TIFF library // void myTiffErrHandler(const char *module, const char *fmt, va_list ap) { char buf[1024]; #ifdef WIN32 _vsnprintf(buf, sizeof(buf), fmt, ap); #else vsnprintf(buf, sizeof(buf), fmt, ap); #endif if (module) { MyBase::SetErrMsg("%s : %s", module, buf); } else { MyBase::SetErrMsg("%s", buf); } } }; // namespace GeoImage::GeoImage(int pixelsize, int nbands) : _pixelsize(pixelsize), _nbands(nbands) { VAssert(pixelsize = 8); VAssert(nbands = 4); _tif = NULL; _path.clear(); } GeoImage::GeoImage() : _pixelsize(8), _nbands(4) { _path.clear(); _tif = NULL; } GeoImage::~GeoImage() { GeoImage::TiffClose(); } int GeoImage::TiffOpen(string path) { TIFFSetErrorHandler(myTiffErrHandler); GeoImage::TiffClose(); // Check for a valid file name (this avoids Linux crash): // struct stat statbuf; if (stat(path.c_str(), &statbuf) < 0) { SetErrMsg("Invalid tiff file: %s\n", path.c_str()); return -1; } // Not using memory-mapped IO (m) is reputed to help plug // leaks (but doesn't do any good on windows for me) // _tif = XTIFFOpen(path.c_str(), "rm"); if (!_tif) { SetErrMsg("Unable to open tiff file: %s\n", path.c_str()); return -1; } char emsg[1000]; int ok = TIFFRGBAImageOK(_tif, emsg); if (!ok) { MyBase::SetErrMsg("Unable to process tiff file:\n %s\nError message: %s", path.c_str(), emsg); return (-1); } // Check compression. Some compressions, e.g. jpeg, cause crash on Linux // #ifdef VAPOR3_0_0_ALPHA short compr = 1; ok = TIFFGetField(_tif, TIFFTAG_COMPRESSION, &compr); if (ok) { if (compr != COMPRESSION_NONE && compr != COMPRESSION_LZW && compr != COMPRESSION_JPEG && compr != COMPRESSION_CCITTRLE) { MyBase::SetErrMsg("Unsupported Tiff compression"); return (-1); } } #endif return (0); } void GeoImage::TiffClose() { if (_tif) XTIFFClose(_tif); _path.clear(); _tif = NULL; } // Return dimensions of image at selected directory number // int GeoImage::TiffGetImageDimensions(int dirnum, size_t &width, size_t &height) const { VAssert(_tif != NULL); width = 0; height = 0; bool ok = (bool)TIFFSetDirectory(_tif, dirnum); if (!ok) return (-1); uint32_t w; ok = (bool)TIFFGetField(_tif, TIFFTAG_IMAGEWIDTH, &w); if (!ok) return (-1); uint32_t h; ok = (bool)TIFFGetField(_tif, TIFFTAG_IMAGELENGTH, &h); if (!ok) return (-1); width = (size_t)w; height = (size_t)h; return (0); } // Read the indicated TIFF image and return it as a 2D texture. // int GeoImage::TiffReadImage(int dirnum, unsigned char *texture) const { VAssert(_tif != NULL); uint32_t *texuint32_t = (uint32_t *)texture; bool ok = (bool)TIFFSetDirectory(_tif, dirnum); if (!ok) return (-1); size_t w, h; int rc = GeoImage::TiffGetImageDimensions(dirnum, w, h); if (rc < 0) return (-1); // Check if this is a 2-component 8-bit image. These are read // by scanline since TIFFReadRGBAImage // apparently does not know how to get the alpha channel // short nsamples, nbitspersample; ok = TIFFGetField(_tif, TIFFTAG_SAMPLESPERPIXEL, &nsamples); if (!ok) return (-1); ok = TIFFGetField(_tif, TIFFTAG_BITSPERSAMPLE, &nbitspersample); if (!ok) return (-1); if (nsamples == 2 && nbitspersample == 8) { tdata_t buf; uint32_t row; short config; short photometric; TIFFGetField(_tif, TIFFTAG_PLANARCONFIG, &config); if (!ok) return (-1); TIFFGetField(_tif, TIFFTAG_PHOTOMETRIC, &photometric); if (!ok) return (-1); buf = _TIFFmalloc(TIFFScanlineSize(_tif)); VAssert(buf != NULL); unsigned char *charArray = (unsigned char *)buf; int scanlength = TIFFScanlineSize(_tif) / 2; if (config == PLANARCONFIG_CONTIG) { for (row = 0; row < h; row++) { int revrow = h - row - 1; // reverse, go bottom up int rc = TIFFReadScanline(_tif, buf, row); if (rc < 0) { MyBase::SetErrMsg("Error reading tiff file:\n %s\n", _path.c_str()); _TIFFfree(buf); return (-1); } for (int k = 0; k < scanlength; k++) { unsigned char greyval = charArray[2 * k]; // If white is zero, reverse it: if (!photometric) greyval = 255 - greyval; unsigned char alphaval = charArray[2 * k + 1]; texuint32_t[revrow * w + k] = alphaval << 24 | greyval << 16 | greyval << 8 | greyval; } } } else if (config == PLANARCONFIG_SEPARATE) { uint16_t s; // Note: following loop (adapted from tiff docs) has not // been tested. Are there tiff // examples with separate alpha channel? // for (s = 0; s < nsamples; s++) { for (row = 0; row < h; row++) { int rc = TIFFReadScanline(_tif, buf, row, s); if (rc < 0) { MyBase::SetErrMsg("Error reading tiff file:\n %s\n", _path.c_str()); _TIFFfree(buf); return (-1); } int revrow = h - row - 1; // reverse, go bottom up if (!(s % 2)) { // color for (int k = 0; k < h; k++) { unsigned char greyval = charArray[k]; // If white is zero, reverse it: if (!photometric) greyval = 255 - greyval; texuint32_t[revrow * w + k] = greyval << 16 | greyval << 8 | greyval; } } else { // alpha for (int k = 0; k < h; k++) { unsigned char alphaval = charArray[k]; texuint32_t[revrow * w + k] = alphaval << 24 | (texuint32_t[revrow * w + k] & 0xffffff); } } } } } _TIFFfree(buf); return (0); } else { // Read pixels, whether or not we are georeferenced: ok = TIFFReadRGBAImage(_tif, w, h, texuint32_t, 0); if (!ok) { MyBase::SetErrMsg("Error reading tiff file:\n %s\n", _path.c_str()); return -1; } return (0); } } // Project extents (ll, ur) given in PCS coordinates in srccoords using the // specified projection in proj4src // into 4 corners and return the extents (ll, ur) in the projected // space. Because the projected space may be convex - the maximum and // minimum values may not occur at the corner points - we need to walk // around the boundaries to find the extents in the projected space. // int GeoImage::CornerExtents(const double srccoords[4], double dstcoords[4], string proj4src) const { proj4src += " +over"; Proj4API proj4API; int rc = proj4API.Initialize(proj4src, ""); if (rc < 0) return (-1); size_t nx = 256; size_t ny = 256; size_t ntotal = nx * ny; std::vector xsamples(ntotal); std::vector ysamples(ntotal); double deltax = (srccoords[2] - srccoords[0]) / (double)(nx - 1); double deltay = (srccoords[3] - srccoords[1]) / (double)(ny - 1); for (int j = 0; j < ny; j++) { for (int i = 0; i < nx; i++) { xsamples[j * nx + i] = srccoords[0] + i * deltax; ysamples[j * nx + i] = srccoords[1] + j * deltay; } } proj4API.Transform(xsamples.data(), ysamples.data(), ntotal, 1); // Find the extents the extents of the // entire enclosed region. The inverse Proj4 transform does not prevent // wraparound // double minx = *(std::min_element(xsamples.begin(), xsamples.end())); double maxx = *(std::max_element(xsamples.begin(), xsamples.end())); double miny = *(std::min_element(ysamples.begin(), ysamples.end())); double maxy = *(std::max_element(ysamples.begin(), ysamples.end())); // still needed? // if ((maxx - minx) >= 359.99) { maxx = minx + 359.99; } dstcoords[0] = minx; dstcoords[1] = miny; dstcoords[2] = maxx; dstcoords[3] = maxy; return (0); } ================================================ FILE: lib/render/GeoImageGeoTiff.cpp ================================================ #include #include #include #include "vapor/VAssert.h" #include #include #include #ifdef WIN32 #include #include #else #include #include #endif #include #include #include #include #include using namespace VAPoR; using namespace Wasp; GeoImageGeoTiff::GeoImageGeoTiff() : GeoImage(8, 4) { _tiffTimes.clear(); _times.clear(); _texture = NULL; _textureSize = 0; } GeoImageGeoTiff::~GeoImageGeoTiff() { if (_texture) delete[] _texture; _textureSize = 0; } int GeoImageGeoTiff::Initialize(string path, vector times) { GeoImage::TiffClose(); _tiffTimes.clear(); _times.clear(); int rc = GeoImage::TiffOpen(path); if (rc < 0) return (-1); // Set up time vector // _initTimeVector(GeoImage::TiffGetHandle(), times); return (0); } unsigned char *GeoImageGeoTiff::GetImage(size_t ts, size_t &width, size_t &height) { // Get tiff directory number for this time step // int dirnum = _getBestDirNum(ts); // Get dimensions image at given time step // int rc = GeoImage::TiffGetImageDimensions(dirnum, width, height); if (rc < 0) return (NULL); // // Read the image texture from a file // size_t size = width * height * 4; if (_textureSize < size) { delete[] _texture; _texture = new unsigned char[size]; _textureSize = size; } rc = GeoImage::TiffReadImage(dirnum, _texture); if (!_texture) return (NULL); return (_texture); } unsigned char *GeoImageGeoTiff::GetImage(size_t ts, const double pcsExtentsReq[4], string proj4StringReq, size_t maxWidthReq, size_t maxHeightReq, // not used double pcsExtentsImg[4], double geoCornersImg[8], string &proj4StringImg, size_t &width, size_t &height) { for (int i = 0; i < 4; i++) { pcsExtentsImg[i] = pcsExtentsReq[i]; geoCornersImg[i] = 0.0; geoCornersImg[i + 4] = 0.0; // Do we need this parameter? } proj4StringImg.clear(); width = height = 0; _texture = GeoImageGeoTiff::GetImage(ts, width, height); if (!_texture) return (NULL); // // Get extents of image in both Projected Coordinates (PCS) // and lat-long. // N.B. if the proj4String defined a lat-long // projection (proj=latlong), it's modified to be cylindrical // equidistant (proj=eqc) // int rc = _getGTIFInfo(GeoImage::TiffGetHandle(), width, height, pcsExtentsImg, geoCornersImg, proj4StringImg); if (rc < 0) return (NULL); // // If image is not geo referenced we're done. pcsExtentsImg are // already initialized to pcsExtentsReq // if (!proj4StringImg.size()) return (_texture); // // Attempt to crop the texture to the smallest rectangle // that covers the data space. Only possible if image is // a global, cylindrical-equidistant or pseudo mercator projection. // _extractSubtexture() // modifies with, height, and pcsExtents if successful, otherwise // they are unchanged. // (void)_extractSubtexture(_texture, width, height, pcsExtentsReq, proj4StringReq, pcsExtentsImg, geoCornersImg, proj4StringImg, proj4StringImg, width, height, pcsExtentsImg, geoCornersImg); return (unsigned char *)_texture; } // Get the Proj4 projection string from a GTIF handle // string GeoImageGeoTiff::_getProjectionFromGTIF(GTIF *gtifHandle) const { GTIFDefn gtifDef; GTIFGetDefn(gtifHandle, >ifDef); string proj4String = GTIFGetProj4Defn(>ifDef); if (proj4String.empty()) return (proj4String); // If there's no "ellps=" in the string, force it to be spherical, // This avoids a bug in the geotiff routines // if (std::string::npos == proj4String.find("ellps=")) { proj4String += " +ellps=sphere"; } return (proj4String); } // Construct a time vector, _tiffTimes, containing the time coordinates // for all images in the TIFF data base // void GeoImageGeoTiff::_initTimeVector(TIFF *tif, const vector ×) { _times = times; _tiffTimes.clear(); // Check if the first time step (tiff "directory" has a time stamp. // If it does all directories must have a time stamp. If no time // stamp is present then the time stamp is taken from the data itself. // TIFFSetDirectory(tif, 0); char *timePtr = NULL; bool hasTime = TIFFGetField(tif, TIFFTAG_DATETIME, &timePtr); // build a list of the times in the tiff // UDUnits udunits; udunits.Initialize(); do { int dircount = 0; if (hasTime) { double tifftime = 0.0; bool ok = _getTiffTime(tif, &udunits, tifftime); if (!ok) { SetDiagMsg("Failed to read time stamp from TIFF image"); break; } _tiffTimes.push_back(tifftime); } else { if (dircount < _times.size()) _tiffTimes.push_back(_times[dircount]); } dircount++; } while (TIFFReadDirectory(tif)); return; } // Get the time coordinate of the current tiff directory, convert it // from a date to seconds since EPOCH using udunits // bool GeoImageGeoTiff::_getTiffTime(TIFF *tif, UDUnits *udunits, double &tifftime) const { tifftime = 0.0; char *timePtr = NULL; bool hasTime = (bool)TIFFGetField(tif, TIFFTAG_DATETIME, &timePtr); if (!hasTime) return (false); // determine seconds from the time stamp in the tiff // convert tifftags to use WRF style date/time strings // int year, mon, mday, hour, min, sec; const char *format = "%4d:%2d:%2d %2d:%2d:%2d"; int rc = sscanf(timePtr, format, &year, &mon, &mday, &hour, &min, &sec); // For backwords compatibility check WRF-style format // if (rc != 6) { format = "%4d-%2d-%2d_%2d:%2d:%2d"; rc = sscanf(timePtr, format, &year, &mon, &mday, &hour, &min, &sec); if (rc != 6) return (false); } tifftime = udunits->EncodeTime(year, mon, mday, hour, min, sec); return (true); } // Find the tiff time coordinate that best matches the time step // indicated by ts. Return an index into _tiffTimes for the best // match. // int GeoImageGeoTiff::_getBestDirNum(size_t ts) const { VAssert(ts < _times.size()); VAssert(_tiffTimes.size()); double t = _times[ts]; int bestdir = 0; for (int i = 0; i < _tiffTimes.size(); i++) { if (fabs(_tiffTimes[i] - t) < fabs(_tiffTimes[bestdir] - t)) { bestdir = i; } } return (bestdir); } int GeoImageGeoTiff::_getGTIFInfo(TIFF *tif, size_t width, size_t height, double pcsExtents[4], double geoCorners[8], string &proj4String) const { for (int i = 0; i < 4; i++) { pcsExtents[i] = 0.0; geoCorners[i] = geoCorners[i + 4] = 0.0; } proj4String.clear(); GTIF *gtifHandle = GTIFNew(tif); VAssert(gtifHandle != NULL); // Read proj4 string from geotiff file // proj4String = _getProjectionFromGTIF(gtifHandle); if (proj4String.empty()) return (0); // // Get image extents by converting from pixel to // Projection Coordinate Space (PCS). Note, if the // proj4 projection is "latlong" the conversion will be from // pixels to geographic coords (i.e. lat and long) :-( // // N.B. GTIF library expects Y origin at top of image, we // us bottom for Y origin // // double extents[4] = {0.0, height-1, width-1, 0}; double extents[4] = {0.0, (double)height, (double)width, 0.0}; bool ok = GTIFImageToPCS(gtifHandle, &extents[0], &extents[1]); if (!ok) { SetErrMsg("GTIFImageToPCS()"); GTIFFree(gtifHandle); return (-1); } ok = GTIFImageToPCS(gtifHandle, &extents[2], &extents[3]); if (!ok) { SetErrMsg("GTIFImageToPCS()"); GTIFFree(gtifHandle); return (-1); } GTIFFree(gtifHandle); // // Set up proj4 to convert from PCS, image space to lat-long // Proj4API proj4API; int rc = proj4API.Initialize(proj4String, ""); if (rc < 0) return (-1); // Make sure projection is not lat-long. If so, convert to eqc // if (proj4API.IsLatLonSrc()) { // Oops. Projection string was lat-long. This means we have // lat long coordinates in 'extents', not PCS. We need to generate // a new proj4 string to find geographic (lat-lon) coordinates // double lon_0 = (extents[0] + extents[2]) / 2.0; double lat_0 = (extents[1] + extents[3]) / 2.0; ostringstream oss; oss.precision(12); oss << " +lon_0=" << lon_0 << " +lat_0=" << lat_0; proj4String = "+proj=eqc +ellps=WGS84" + oss.str(); int rc = proj4API.Initialize("", proj4String); if (rc < 0) return (-1); // Map geographic to PCS coordinates // proj4API.Transform(extents, extents + 1, 2, 2); // Reinitialize proj4API to map from geographic to PCS coordinates // rc = proj4API.Initialize(proj4String, ""); if (rc < 0) return (-1); } // Clamp image bounds to range permitted by projection. // proj4API.Clamp(extents, extents + 1, 2, 2); for (int i = 0; i < 4; i++) { pcsExtents[i] = extents[i]; } // // clockwise order starting with lower-left // geoCorners[0] = extents[0]; geoCorners[1] = extents[1]; geoCorners[2] = extents[0]; geoCorners[3] = extents[3]; geoCorners[4] = extents[2]; geoCorners[5] = extents[3]; geoCorners[6] = extents[2]; geoCorners[7] = extents[1]; // // Transform from PCS to lat-long // proj4API.Transform(geoCorners, geoCorners + 1, 4, 2); // Don't allow latlong image to go all the way to the poles // Not sure why they can't to to 90. This code may no longer // be necessary. // if (geoCorners[1] < -89.9999) geoCorners[1] = -89.9999; if (geoCorners[7] < -89.9999) geoCorners[7] = -89.9999; if (geoCorners[3] > 89.9999) geoCorners[3] = 89.9999; if (geoCorners[5] > 89.9999) geoCorners[5] = 89.9999; return (0); } // Extract a ROI from a GeoTiff texture. Only possible if image is global // and in either cylindrical equidistant or mercator projection. Otherwise // the original texture is returned unchanged. // // texture : Pointer to a 2D texture containing the geoimage // width, height : dimensions of texture in pixels // pcsExtentsReq : Extents (llx, lly, urx, ury) of desired ROI expressed // in PCS coordinates of the *image* // // proj4StringReq : Proj4 string associated with texture // pcsExtentsImg : Extents (llx, lly, urx, ury) of texture expressed // in PCS coordinates of the *image* // // geoCornersImg : Corner points (lat, lon) of image corners // in clockwise order starting from S.W. corner // // proj4StringImg : Proj4 string associated with texture (how different // from proj4StringReq)/ // // subProj4StringImg : Proj4 string for returned image. The string // may be modified from the orginal if the desired ROI crosses // the boundary of the original image // // subWidth, subHeight : width and height of returned texture // subPCSExtentsImg : Extents (llx, lly, urx, ury) of returned texture // expressed // in PCS coordinates of the *image* // bool GeoImageGeoTiff::_extractSubtexture(unsigned char *texture, size_t width, size_t height, const double pcsExtentsReq[4], string proj4StringReq, const double pcsExtentsImg[4], const double geoCornersImg[8], string proj4StringImg, string &subProj4StringImg, size_t &subWidth, size_t &subHeight, double subPCSExtentsImg[4], double subGeoCornersImg[8]) const { // // Initialize output params to inputs in case of failure, in which // case the entire image is returned unchanged (uncropped) // subProj4StringImg = proj4StringImg; subWidth = width; subHeight = height; for (int i = 0; i < 4; i++) { subPCSExtentsImg[i] = pcsExtentsImg[i]; } for (int i = 0; i < 8; i++) { subGeoCornersImg[i] = geoCornersImg[i]; } // // Can only extract sub-textures from georeferenced images // with cylindrical equi-distant or mercator projections that cover // entire globe. This is really a hack and we need a better test // for global coverage. // bool mercator = std::string::npos != subProj4StringImg.find("proj=merc"); bool eqc = std::string::npos != subProj4StringImg.find("proj=eqc"); if (!mercator && !eqc) return (false); // There must be a better way to determine if image is global // if (geoCornersImg[0] > -179.5 || geoCornersImg[4] < 179.5) { return (false); } if (eqc) { if (geoCornersImg[1] > -89.5 || geoCornersImg[5] < 89.5) return (false); if (width != 2 * height) return (false); } if (mercator) { if (geoCornersImg[1] > -85.0 || geoCornersImg[5] < 85.0) return (false); if (width != height) return (false); } // Convert requested data extents from PCS coordinates to geographic // and crop data latitude extents to image latitude extents. With Mercator // projections latitudes can't extend beyond ~85 degrees // double myGeoExtentsData[4]; for (int i = 0; i < 4; i++) myGeoExtentsData[i] = pcsExtentsReq[i]; (void)CornerExtents(myGeoExtentsData, myGeoExtentsData, proj4StringReq); // Clamp latitude to extents of image. Can't do same for longitude // becuase they may be shifted // if (myGeoExtentsData[1] < geoCornersImg[1]) myGeoExtentsData[1] = geoCornersImg[1]; if (myGeoExtentsData[3] > geoCornersImg[5]) myGeoExtentsData[3] = geoCornersImg[5]; // // Construct a GeoTile. It supports subregion extraction and handles // wraparound // GeoTile *geotile; if (eqc) { geotile = new GeoTileEquirectangular(width, height, 4); } else { geotile = new GeoTileMercator(width, height, 4); } geotile->Insert("", (unsigned char *)texture); size_t pixelSW[2]; size_t pixelNE[2]; size_t nx, ny; // // Get GeoTile's pixel coordinates of subregion. // geotile->LatLongRectToPixelRect(myGeoExtentsData, myGeoExtentsData + 2, 0, pixelSW, pixelNE); int rc = geotile->MapSize(pixelSW[0], pixelSW[1], pixelNE[0], pixelNE[1], 0, nx, ny); if (rc != 0) { delete geotile; return false; }; // // Extract the image // VAssert(nx <= width); VAssert(ny <= height); rc = geotile->GetMap(pixelSW[0], pixelSW[1], pixelNE[0], pixelNE[1], 0, texture); if (rc != 0) { delete geotile; return false; }; delete geotile; // // If data crosses -180 or 180 we need to generate a new // proj4 string with the correct centering // if (myGeoExtentsData[0] < -180 || myGeoExtentsData[2] > 180.0) { double lon_0 = (myGeoExtentsData[0] + myGeoExtentsData[2]) / 2.0; ostringstream oss; oss.precision(12); oss << " +lon_0=" << lon_0; string::size_type first = subProj4StringImg.find("+lon_0"); if (first == string::npos) { subProj4StringImg += oss.str(); } else { string::size_type last = subProj4StringImg.find(" ", first); VAssert(last != string::npos); subProj4StringImg.replace(first, last - first, oss.str()); } } // // Finally, update the extents of the new image in PCS coordinates // by mapping geographic coordinates of corners to PCS. // Since the projection is eqc we only need south-west and north-east // points. // Proj4API proj4API; proj4API.Initialize("", subProj4StringImg); subPCSExtentsImg[0] = myGeoExtentsData[0]; subPCSExtentsImg[1] = myGeoExtentsData[1]; subPCSExtentsImg[2] = myGeoExtentsData[2]; subPCSExtentsImg[3] = myGeoExtentsData[3]; proj4API.Transform(subPCSExtentsImg, subPCSExtentsImg + 1, 2, 2); subWidth = (int)nx; subHeight = (int)ny; // Image is rectangular so corners come directry from extents // subGeoCornersImg[0] = myGeoExtentsData[0]; subGeoCornersImg[1] = myGeoExtentsData[1]; subGeoCornersImg[2] = myGeoExtentsData[0]; subGeoCornersImg[3] = myGeoExtentsData[3]; subGeoCornersImg[4] = myGeoExtentsData[2]; subGeoCornersImg[5] = myGeoExtentsData[3]; subGeoCornersImg[6] = myGeoExtentsData[2]; subGeoCornersImg[7] = myGeoExtentsData[1]; return true; } ================================================ FILE: lib/render/GeoImageTMS.cpp ================================================ #include #include #include "vapor/VAssert.h" #include #include #ifdef WIN32 #include #include #else #include #include #endif #include #include #include #include #include using namespace VAPoR; using namespace Wasp; GeoImageTMS::GeoImageTMS() : GeoImage(8, 4) { _dir.clear(); _currentLOD = -1; _maxLOD = 0; _texture = NULL; _textureSize = 0; _tileBuf = NULL; _tileBufSize = 0; _geotile = NULL; // The default projection string for imagery centered at 0 degrees // longitude. This string is modified (+lon_0 is edited) if a // reconstructed contiguous image is not centered at 0 degrees longitude // _defaultProj4String = "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 " "+lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext " "+no_defs"; } GeoImageTMS::~GeoImageTMS() { if (_texture) delete[] _texture; _textureSize = 0; if (_tileBuf) delete[] _tileBuf; _tileBufSize = 0; if (_geotile) delete _geotile; } int GeoImageTMS::Initialize(string dir, vector times) { SetDiagMsg("GeoImageTMS::Initialize(%s)", dir.c_str()); if (_geotile) delete _geotile; _geotile = NULL; _dir = dir; _maxLOD = 0; // Find the maximum available LOD in the TMS database. // int lod = TMSUtils::GetNumTMSLODs(_dir) - 1; if (lod < 0) { SetErrMsg("Failed to initialize TMS directory %s", _dir.c_str()); return (-1); } _maxLOD = lod; size_t w, h; int rc = _tileSize(_dir, 0, 0, 0, w, h); if (rc < 0) return (-1); // // Construct a GeoTile. It supports subregion extraction and handles // wraparound. I.e. GeoTile can reconstruct contigous image for any // longitudinal span // _geotile = new GeoTileMercator(w, h, 4); // // Allocate space to buffer a tile // size_t size = w * h * 4; if (_tileBufSize < size) { delete[] _tileBuf; _tileBuf = new unsigned char[size]; _tileBufSize = size; } return (0); } void GeoImageTMS::SetLOD(int lod) { _currentLOD = lod; } unsigned char *GeoImageTMS::GetImage(size_t ts, size_t &width, size_t &height) { _geotile->GetTileSize(width, height); size_t size = width * height * 4; if (_textureSize < size) { delete[] _texture; _texture = new unsigned char[size]; _textureSize = size; } // // Just return the base texture // int rc = _tileRead(_dir, 0, 0, 0, _texture); if (rc < 0) return (NULL); return (_texture); } unsigned char *GeoImageTMS::GetImage(size_t ts, const double pcsExtentsReq[4], string proj4StringReq, size_t maxWidthReq, size_t maxHeightReq, double pcsExtentsImg[4], double geoCornersImg[8], string &proj4StringImg, size_t &width, size_t &height) { SetDiagMsg("GeoImageTMS::GetImage()"); proj4StringImg = _defaultProj4String; width = height = 0; // Convert requested data extents from PCS coordinates to geographic // and crop data latitude extents to image latitude extents. With Mercator // projections latitudes can't extend beyond ~85 degrees // double myGeoExtentsData[4]; for (int i = 0; i < 4; i++) myGeoExtentsData[i] = pcsExtentsReq[i]; (void)CornerExtents(myGeoExtentsData, myGeoExtentsData, proj4StringReq); // Clamp latitude to extents of image. Can't do same for longitude // because they may be shifted // // Get the supported lat and lon extents for the GeoTile, which // are guaranteed to be rectangular by the mercator projection. // double minlon, minlat, maxlon, maxlat; _geotile->GetLatLonExtents(minlon, minlat, maxlon, maxlat); if (myGeoExtentsData[1] < minlat) myGeoExtentsData[1] = minlat; if (myGeoExtentsData[3] > maxlat) myGeoExtentsData[3] = maxlat; // Pick a lod that won't allow the resulting image to // exceed the max width and height // int lod; if (_currentLOD == -1) { lod = _getBestLOD(myGeoExtentsData, maxWidthReq, maxHeightReq); } else { lod = _currentLOD; } SetDiagMsg("GeoImageTMS::GetImage() LOD : %d", lod); // // Get GeoTile's pixel coordinates of subregion at the given lod // size_t pixelSW[2]; size_t pixelNE[2]; size_t nx, ny; _geotile->LatLongRectToPixelRect(myGeoExtentsData, myGeoExtentsData + 2, lod, pixelSW, pixelNE); int rc = _geotile->MapSize(pixelSW[0], pixelSW[1], pixelNE[0], pixelNE[1], lod, nx, ny); // // Resize the buffer if needed. // size_t size = nx * ny * 4; if (_textureSize < size) { delete[] _texture; _texture = new unsigned char[size]; _textureSize = size; } // // Extract the image // rc = _getMap(pixelSW, pixelNE, lod, _texture); if (rc < 0) return (NULL); // // If data crosses -180 or 180 we need to generate a new // proj4 string with the correct centering // if (myGeoExtentsData[0] < -180 || myGeoExtentsData[2] > 180.0) { double lon_0 = (myGeoExtentsData[0] + myGeoExtentsData[2]) / 2.0; ostringstream oss; oss.precision(12); oss << " +lon_0=" << lon_0; string::size_type first = proj4StringImg.find("+lon_0"); if (first == string::npos) { proj4StringImg += oss.str(); } else { string::size_type last = proj4StringImg.find(" ", first); VAssert(last != string::npos); proj4StringImg.replace(first, last - first, oss.str()); } } // // Finally, update the extents of the new image in PCS coordinates // by mapping geographic coordinates of corners to PCS. // Since the projection is eqc we only need south-west and north-east // points. // Proj4API proj4API; proj4API.Initialize("", proj4StringImg); pcsExtentsImg[0] = myGeoExtentsData[0]; pcsExtentsImg[1] = myGeoExtentsData[1]; pcsExtentsImg[2] = myGeoExtentsData[2]; pcsExtentsImg[3] = myGeoExtentsData[3]; proj4API.Transform(pcsExtentsImg, pcsExtentsImg + 1, 2, 2); width = nx; height = ny; // Image is rectangular so corners come directry from extents // geoCornersImg[0] = myGeoExtentsData[0]; geoCornersImg[1] = myGeoExtentsData[1]; geoCornersImg[2] = myGeoExtentsData[0]; geoCornersImg[3] = myGeoExtentsData[3]; geoCornersImg[4] = myGeoExtentsData[2]; geoCornersImg[5] = myGeoExtentsData[3]; geoCornersImg[6] = myGeoExtentsData[2]; geoCornersImg[7] = myGeoExtentsData[1]; return (_texture); } // Get the dimensions of a single tile from the TMS database // N.B. This method allows the specification of the tile coordinates, // but all tiles in a single TMS must be the same size // int GeoImageTMS::_tileSize(string dir, size_t tileX, size_t tileY, int lod, size_t &w, size_t &h) { string path = TMSUtils::TilePath(dir, tileX, tileY, lod); if (path.empty()) { SetErrMsg("Tile %d %d %d does not exist", tileX, tileY, lod); return (-1); } int rc = GeoImage::TiffOpen(path); if (rc < 0) return (-1); rc = GeoImage::TiffGetImageDimensions(0, w, h); if (rc < 0) { GeoImage::TiffClose(); return (-1); } GeoImage::TiffClose(); return (0); } // Read a single tile from the TMS database and return as a raster // image // int GeoImageTMS::_tileRead(string dir, size_t tileX, size_t tileY, int lod, unsigned char *tile) { SetDiagMsg("GeoImageTMS::_tileRead(%s,%d,%d,%d)", dir.c_str(), tileX, tileY, lod); string path = TMSUtils::TilePath(dir, tileX, tileY, lod); if (path.empty()) { SetErrMsg("Tile %d %d %d does not exist", tileX, tileY, lod); return (-1); } SetDiagMsg("GeoImageTMS::_tileRead() path : %s", path.c_str()); int rc = GeoImage::TiffOpen(path); if (rc < 0) return (-1); rc = GeoImage::TiffReadImage(0, tile); if (rc < 0) { GeoImage::TiffClose(); return (-1); } GeoImage::TiffClose(); return (0); } // Determine the best lod for a region specified in lat-lon // coordinates. I.e. the largest lod where the resulting image // dimensions won't exceed maxWidthReq or maxHeightReq // int GeoImageTMS::_getBestLOD(const double myGeoExtentsData[4], int maxWidthReq, int maxHeightReq) const { size_t pixelSW[2]; size_t pixelNE[2]; bool done = false; int lod = 0; for (; lod < _maxLOD && !done; lod++) { size_t nx, ny; // // Get GeoTile's pixel coordinates of subregion. // _geotile->LatLongRectToPixelRect(myGeoExtentsData, myGeoExtentsData + 2, lod, pixelSW, pixelNE); int rc = _geotile->MapSize(pixelSW[0], pixelSW[1], pixelNE[0], pixelNE[1], lod, nx, ny); VAssert(!(rc < 0)); if (nx > maxWidthReq || ny > maxHeightReq) { done = true; if (lod > 0) lod--; } } return (lod); } // Construct a contiguous map (raster image) from the TMS for the // specified ROI // int GeoImageTMS::_getMap(const size_t pixelSW[2], const size_t pixelNE[2], int lod, unsigned char *texture) { size_t tileX0, tileX1; size_t tileY0, tileY1; size_t dummy; _geotile->PixelXYToTileXY(pixelSW[0], pixelSW[1], tileX0, tileY0, dummy, dummy); _geotile->PixelXYToTileXY(pixelNE[0], pixelNE[1], tileX1, tileY1, dummy, dummy); // Deal with wraparound // size_t ntiles = 1 << lod; size_t nxtiles, nytiles; if (pixelSW[0] < pixelNE[0]) { nxtiles = tileX1 - tileX0 + 1; } else { nxtiles = ntiles - ((tileX1 == tileX0) ? 0 : (tileX0 - tileX1 - 1)); } if (pixelSW[1] < pixelNE[1]) { nytiles = tileY1 - tileY0 + 1; } else { nytiles = ntiles - ((tileY1 == tileY0) ? 0 : (tileY0 - tileY1 - 1)); } // Make sure tiles need for this map are loaded. If not, read // and load them // size_t tileY = tileY0; for (size_t y = 0; y < nytiles; y++) { size_t tileX = tileX0; for (size_t x = 0; x < nxtiles; x++) { string quadkey = _geotile->TileXYToQuadKey(tileX, tileY, lod); if (!_geotile->GetTile(quadkey)) { int rc = _tileRead(_dir, tileX, tileY, lod, _tileBuf); if (rc < 0) return (-1); rc = _geotile->Insert(quadkey, _tileBuf); VAssert(!(rc < 0)); } tileX = (tileX + 1) % ntiles; } tileY = (tileY + 1) % ntiles; } int rc = _geotile->GetMap(pixelSW[0], pixelSW[1], pixelNE[0], pixelNE[1], lod, texture); return (rc); } ================================================ FILE: lib/render/GeoTIFWriter.cpp ================================================ #include "vapor/GeoTIFWriter.h" #include "vapor/Proj4StringParser.h" #include "vapor/VAssert.h" #ifdef WIN32 #include #include #else #include #endif using namespace VAPoR; GeoTIFWriter::GeoTIFWriter(const std::string &path) : TIFWriter(path), gtif(nullptr), _hasTiePoint(false), _hasPixelScale(false), _geoTiffWasConfigured(false) { if (opened) { gtif = GTIFNew(tif); if (!gtif) opened = false; } } GeoTIFWriter::~GeoTIFWriter() { if (gtif) GTIFFree(gtif); } int GeoTIFWriter::Write(const unsigned char *buffer, const unsigned int width, const unsigned int height) { VAssert(_hasTiePoint); VAssert(_hasPixelScale); VAssert(_geoTiffWasConfigured); GTIFWriteKeys(gtif); return TIFWriter::Write(buffer, width, height); } int GeoTIFWriter::ConfigureFromProj4(const std::string proj4String) { Proj4StringParser proj(proj4String); if (proj.GetString("ellps") == "sphere") { SetErrMsg("Arbitrary sphere projections not supported"); return -1; } if (proj.GetString("proj") == "lcc" || proj.GetString("proj") == "utm") { if (GTIFSetFromProj4(gtif, proj4String.c_str()) == 0) { SetErrMsg("Unable to configure GeoTIFF using GTIFSetFromProj4(%s)", proj4String.c_str()); return -1; } } else { if (proj.GetString("proj") == "merc") { GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_Mercator); GTIFKeySet(gtif, ProjScaleAtNatOriginGeoKey, TYPE_DOUBLE, 1, proj.GetDouble("k", 1.0)); } else if (proj.GetString("proj") == "eqc") { GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_Equirectangular); } else if (proj.GetString("proj") == "stere") { GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_Stereographic); if (proj.HasKey("R")) { SetErrMsg("Arbitrary sphere projections not supporteds"); return -1; } } else { SetErrMsg("Unsupported projection \"%s\"", proj.GetString("proj").c_str()); return -1; } int ellipse = Proj4StringParser::Proj4EllipseStringToGeoTIFEnum(proj.GetString("ellps", "WGS84")); if (ellipse < 0) return -1; GTIFKeySet(gtif, GeogEllipsoidGeoKey, TYPE_SHORT, 1, ellipse); GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected); GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, KvUserDefined); GTIFKeySet(gtif, ProjectionGeoKey, TYPE_SHORT, 1, KvUserDefined); // Proj4 does not support lat_0 but some of our proj4 strings have this parameter in them // In the datasets I've tested, it appears to override lat_ts..? if (proj.HasKey("lat_0")) GTIFKeySet(gtif, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1, proj.GetDouble("lat_0", 0.0)); else GTIFKeySet(gtif, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1, proj.GetDouble("lat_ts", 0.0)); GTIFKeySet(gtif, ProjNatOriginLongGeoKey, TYPE_DOUBLE, 1, proj.GetDouble("lon_0", 0.0)); GTIFKeySet(gtif, ProjFalseEastingGeoKey, TYPE_DOUBLE, 1, proj.GetDouble("x_0", 0.0)); GTIFKeySet(gtif, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1, proj.GetDouble("y_0", 0.0)); } _geoTiffWasConfigured = true; return 0; } void GeoTIFWriter::SetTiePoint(double worldX, double worldY, double rasterX, double rasterY) { // http://geotiff.maptools.org/spec/geotiff2.6.html#2.6 double tiePoints[6] = { rasterX, rasterY, 0, // 3D I,J,K Raster coordinate space worldX, worldY, 0 // 3D X,Y,Z World coordinate space }; TIFFSetField(tif, TIFFTAG_GEOTIEPOINTS, 6, tiePoints); _hasTiePoint = true; } void GeoTIFWriter::SetPixelScale(double x, double y) { double pixelScale[3] = {x, y, 0}; TIFFSetField(tif, TIFFTAG_GEOPIXELSCALE, 3, pixelScale); _hasPixelScale = true; } ================================================ FILE: lib/render/GeoTile.cpp ================================================ #include #include #include #include #include "vapor/GeoTile.h" #include "vapor/MyBase.h" using namespace std; using namespace VAPoR; GeoTile::GeoTile(size_t tile_width, size_t tile_height, size_t pixel_size, double min_lon, double min_lat, double max_lon, double max_lat) { _tile_width = tile_width; _tile_height = tile_height; _pixel_size = pixel_size; _tiles.clear(); _MinLongitude = min_lon; _MinLatitude = min_lat; _MaxLongitude = max_lon; _MaxLatitude = max_lat; } GeoTile::~GeoTile() { std::map::iterator p; for (p = _tiles.begin(); p != _tiles.end(); ++p) { if (p->second) delete[] p->second; } } void GeoTile::PixelXYToTileXY(size_t pixelX, size_t pixelY, size_t &tileX, size_t &tileY, size_t &tilePixelX, size_t &tilePixelY) const { tileX = pixelX / _tile_width; tileY = pixelY / _tile_height; tilePixelX = pixelX % _tile_width; tilePixelY = pixelY % _tile_height; } void GeoTile::TileXYToPixelXY(size_t tileX, size_t tileY, size_t &pixelX, size_t &pixelY) const { pixelX = tileX * _tile_width; pixelY = tileY * _tile_height; } int GeoTile::Insert(std::string quadkey, const unsigned char *image) { size_t tileX, tileY; int lod; int rc = QuadKeyToTileXY(quadkey, tileX, tileY, lod); if (rc < 0) return (rc); // invalid quadkey std::map::iterator p = _tiles.find(quadkey); unsigned char * imgptr; if (p != _tiles.end()) { imgptr = p->second; // tile already exists; } else { imgptr = new unsigned char[_tile_width * _tile_height * _pixel_size]; _tiles[quadkey] = imgptr; } memcpy(imgptr, image, _tile_width * _tile_height * _pixel_size); return (0); } const unsigned char *GeoTile::GetTile(string quadkey) const { map::const_iterator p = _tiles.find(quadkey); if (p != _tiles.end()) { return (p->second); // tile already exists; } else { return (NULL); } } int GeoTile::GetMap(size_t pixelX0, size_t pixelY0, size_t pixelX1, size_t pixelY1, int lod, unsigned char *map_image) const { if (pixelX0 == pixelX1 || pixelY0 == pixelY1) { Wasp::MyBase::SetErrMsg("Data's geographic coordinates appear to be invalid."); return -1; } // // resolution of global map at requested lod // size_t nx_global, ny_global; MapSize(lod, nx_global, ny_global); // // resolution of requested sub region (map). Need to handle periodicity. // size_t map_width, map_height; int rc = MapSize(pixelX0, pixelY0, pixelX1, pixelY1, lod, map_width, map_height); if (rc < 0) return (rc); // coordinates of tile containing first (north-west) , and second // (south-east) pixel // size_t tileX0, tileY0; size_t tileX1, tileY1; // pixel coordinates in tile coordinate system // size_t tilePixelX0, tilePixelY0; size_t tilePixelX1, tilePixelY1; PixelXYToTileXY(pixelX0, pixelY0, tileX0, tileY0, tilePixelX0, tilePixelY0); PixelXYToTileXY(pixelX1, pixelY1, tileX1, tileY1, tilePixelX1, tilePixelY1); // Deal with wraparound // size_t ntiles = 1 << lod; size_t nxtiles, nytiles; if (pixelX0 < pixelX1) { nxtiles = tileX1 - tileX0 + 1; } else { nxtiles = (tileX1 == tileX0) ? ntiles + 1 : ntiles - (tileX0 - tileX1 - 1); } if (pixelY0 < pixelY1) { nytiles = tileY1 - tileY0 + 1; } else { nytiles = (tileY1 == tileY0) ? ntiles + 1 : ntiles - (tileY0 - tileY1 - 1); } size_t tpx0 = 0, tpy0 = 0; // pixel coord bounds in tile coordinate system size_t tpx1 = 0, tpy1 = 0; // Process tiles from north-west to south-east. // // N.B. because of periodicity tile{X,Y}0 may be >= tile{X,Y}1 // size_t map_py = 0; size_t map_px = 0; // // p{x,y}0 and p{x,y}1 define bounds of tile within map in global coords // size_t px0, py0; size_t px1, py1; size_t ty = tileY0; for (int j = 0; j < nytiles; j++) { map_px = 0; size_t tx = tileX0; size_t dummy; TileXYToPixelXY(tx, ty, dummy, py0); py1 = py0 + _tile_height - 1; // Handle boundary tiles // tpy0 = 0; tpy1 = _tile_height - 1; if (j == 0 && py0 < pixelY0) { size_t offset = pixelY0 - py0; py0 += offset; tpy0 += offset; } if (j == nytiles - 1 && py1 > pixelY1) { size_t offset = py1 - pixelY1; py1 -= offset; tpy1 -= offset; } for (int i = 0; i < nxtiles; i++) { const unsigned char *tile = GetTile(tx, ty, lod); if (!tile) return (-1); // tile doesn't exist at this lod TileXYToPixelXY(tx, ty, px0, dummy); px1 = px0 + _tile_width - 1; // Handle boundary tiles // tpx0 = 0; tpx1 = _tile_width - 1; if (i == 0 && px0 < pixelX0) { size_t offset = pixelX0 - px0; px0 += offset; tpx0 += offset; } if (i == nxtiles - 1 && px1 > pixelX1) { size_t offset = px1 - pixelX1; px1 -= offset; tpx1 -= offset; } _CopyTileToMap(tile, tpx0, tpy0, tpx1, tpy1, map_image, map_px, map_py, map_width, map_height); map_px += tpx1 - tpx0 + 1; tx = (tx + 1) % ntiles; } map_py += tpy1 - tpy0 + 1; ty = (ty + 1) % ntiles; } return (0); } string GeoTile::TileXYToQuadKey(size_t tileX, size_t tileY, int lod) { string quadKey = ""; // lod == 0 for (int i = lod; i > 0; i--) { ostringstream oss; char digit = '0'; size_t mask = 1 << (i - 1); if ((tileX & mask) != 0) { digit++; } if ((tileY & mask) != 0) { digit++; digit++; } oss << digit; quadKey.append(oss.str()); } return (quadKey); } int GeoTile::QuadKeyToTileXY(string quadKey, size_t &tileX, size_t &tileY, int &lod) { tileX = tileY = 0; lod = quadKey.length(); for (int i = lod; i > 0; i--) { int mask = 1 << (i - 1); switch (quadKey[lod - i]) { case '0': break; case '1': tileX |= mask; break; case '2': tileY |= mask; break; case '3': tileX |= mask; tileY |= mask; break; default: return (-1); // Invalid QuadKey digit sequence } } return (0); } void GeoTile::MapSize(int lod, size_t &nx, size_t &ny) const { nx = _tile_width << lod; ny = _tile_height << lod; } int GeoTile::MapSize(size_t pixelX0, size_t pixelY0, size_t pixelX1, size_t pixelY1, int lod, size_t &nx, size_t &ny) const { size_t nx_global, ny_global; MapSize(lod, nx_global, ny_global); if (pixelX0 > nx_global - 1) return (-1); if (pixelY0 > ny_global - 1) return (-1); if (pixelX1 > nx_global - 1) return (-1); if (pixelY1 > ny_global - 1) return (-1); if (pixelY0 > pixelY1) return (-1); // // resolution of requested sub region (map). Need to handle periodicity. // if (pixelX1 >= pixelX0) { nx = pixelX1 - pixelX0 + 1; } else { nx = nx_global - (pixelX0 - pixelX1 - 1); // map wraps around lon } ny = pixelY1 - pixelY0 + 1; return (0); } double GeoTile::_Clip(double n, double minValue, double maxValue) const { return std::min(std::max(n, minValue), maxValue); } void GeoTile::_CopyTileToMap(const unsigned char *tile, size_t tilePixelX0, size_t tilePixelY0, size_t tilePixelX1, size_t tilePixelY1, unsigned char *map, size_t pixelX0, size_t pixelY0, size_t nx, size_t ny) const { size_t px = pixelX0; size_t py = pixelY0; unsigned char * mapptr = map; const unsigned char *tileptr = tile; for (size_t tpy = tilePixelY0; tpy <= tilePixelY1; tpy++, py++) { mapptr = map + (py * nx + pixelX0) * _pixel_size; tileptr = tile + (tpy * _tile_width + tilePixelX0) * _pixel_size; for (size_t tpx = tilePixelX0; tpx <= tilePixelX1; tpx++, px++) { for (int i = 0; i < _pixel_size; i++) { mapptr[i] = tileptr[i]; } mapptr += _pixel_size; tileptr += _pixel_size; } } } void GeoTile::LatLongRectToPixelRect(const double geoSW[2], const double geoNE[2], int lod, size_t pixelSW[2], size_t pixelNE[2]) const { LatLongToPixelXY(geoSW[0], geoSW[1], lod, pixelSW[0], pixelSW[1]); LatLongToPixelXY(geoNE[0], geoNE[1], lod, pixelNE[0], pixelNE[1]); // Handle wraparound for longitude. I.e. if the S.W. and N.E. longitudes map to // same pixel coordinate, the region may span the entire globe, or they may simply span // a small region contained within a single pixel. To determine the case we pick a longitude point // between the geographic SW and NE corners, convert to pixels, and see if the midpoint is still // in the same pixel. // if (pixelSW[0] == pixelNE[0]) { // X pixel coordinate for SW and NE corners are the same. Determine if // longitude wraps around, or simply defines a small region residing entirely // within a single pixel. // double midpointGeo[2] = {(geoNE[0] + geoSW[0]) / 2.0, (geoNE[1] + geoSW[1]) / 2.0}; size_t midpointPixel[2]; LatLongToPixelXY(midpointGeo[0], midpointGeo[1], lod, midpointPixel[0], midpointPixel[1]); // If geographic midpoint resuls in a different pixel the region wraps around. // Correct the NE (or SW) pixel so we // don't have identical pixel coordinates for both corners // size_t nx_global, ny_global; MapSize(lod, nx_global, ny_global); if (pixelSW[0] != midpointPixel[0]) { if (pixelSW[0] == 0) pixelNE[0] = nx_global - 1; else pixelNE[0] = pixelSW[0] - 1; } } } ================================================ FILE: lib/render/GeoTileEquirectangular.cpp ================================================ #include "vapor/GeoTileEquirectangular.h" using namespace VAPoR; void GeoTileEquirectangular::LatLongToPixelXY(double lon, double lat, int lod, size_t &pixelX, size_t &pixelY) const { while (lon < _MinLongitude) lon += 360.0; while (lon > _MaxLongitude) lon -= 360.0; double x = (lon + 180) / 360.0; double y = (lat + 90) / 180.0; size_t nx, ny; MapSize(lod, nx, ny); pixelX = (int)_Clip(x * nx + 0.5, 0, nx - 1); pixelY = (int)_Clip(y * ny + 0.5, 0, ny - 1); } void GeoTileEquirectangular::PixelXYToLatLon(size_t pixelX, size_t pixelY, int lod, double &lon, double &lat) const { size_t nx, ny; MapSize(lod, nx, ny); double x = (_Clip(pixelX, 0, nx - 1) / (double)nx) - 0.5; double y = 0.5 - (_Clip(pixelY, 0, ny - 1) / (double)ny); lat = 180 * y; lon = 360 * x; } ================================================ FILE: lib/render/GeoTileMercator.cpp ================================================ #ifdef _WINDOWS #define _USE_MATH_DEFINES #pragma warning(disable : 4251 4100) #endif #include #include "vapor/GeoTileMercator.h" using namespace VAPoR; void GeoTileMercator::LatLongToPixelXY(double lon, double lat, int lod, size_t &pixelX, size_t &pixelY) const { while (lon < _MinLongitude) lon += 360.0; while (lon > _MaxLongitude) lon -= 360.0; lat = _Clip(lat, _MinLatitude, _MaxLatitude); lon = _Clip(lon, _MinLongitude, _MaxLongitude); double x = (lon + 180) / 360.0; double sinLat = sin(lat * M_PI / 180.0); double y = 0.5 - log((1 + sinLat) / (1 - sinLat)) / (4 * M_PI); // Flip Y coordinate. South most point is pixel 0 // y = 1.0 - y; size_t nx, ny; MapSize(lod, nx, ny); pixelX = (int)_Clip(x * nx + 0.5, 0, nx - 1); pixelY = (int)_Clip(y * ny + 0.5, 0, ny - 1); } void GeoTileMercator::PixelXYToLatLon(size_t pixelX, size_t pixelY, int lod, double &lon, double &lat) const { size_t nx, ny; MapSize(lod, nx, ny); double x = (_Clip(pixelX, 0, nx - 1) / (double)nx) - 0.5; double y = 0.5 - (_Clip(pixelY, 0, ny - 1) / ny); lon = 360 * x; lat = -1 * (90.0 - 360.0 * atan(exp(-y * 2 * M_PI)) / M_PI); } ================================================ FILE: lib/render/HelloRenderer.cpp ================================================ //-- HelloRenderer.cpp ---------------------------------------------------------- // // Copyright (C) 2015 // University Corporation for Atmospheric Research // All Rights Reserved // //---------------------------------------------------------------------------- // // File: HelloRenderer.cpp // // Author: Alan Norton // // Description: Implementation of HelloRenderer class // //---------------------------------------------------------------------------- #include // Must be included first!!! #include #include #include #include #ifndef WIN32 #include #endif #include #include #include #define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH #include using namespace VAPoR; using namespace Wasp; // // Register class with object factory!!! // static RendererRegistrar registrar(HelloRenderer::GetClassType(), HelloParams::GetClassType()); //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- HelloRenderer::HelloRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr) : Renderer(pm, winName, dataSetName, HelloParams::GetClassType(), HelloRenderer::GetClassType(), instName, dataMgr) { } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- HelloRenderer::~HelloRenderer() {} int HelloRenderer::_initializeGL() { return (0); } int HelloRenderer::_paintGL(bool) { HelloParams *rParams = (HelloParams *)GetActiveParams(); // Next we need to get a Grid for the data we are rendering. Grid *helloGrid; // To obtain the Grid, we need the refinement level, variable, LOD, and extents: int actualRefLevel = rParams->GetRefinementLevel(); int lod = rParams->GetCompressionLevel(); // Get the variable name string varname = rParams->GetVariableName(); // Determine the full vdc extents, in order to render // in local user coordinates. // Determine the data extents. // The extents of data needed are determined by the end points. // Get the end points from the Params: vector point1Vec = rParams->GetPoint1(); vector point2Vec = rParams->GetPoint2(); VAssert(point1Vec.size() == point2Vec.size()); VAssert(point1Vec.size() >= 2 && point1Vec.size() <= 3); CoordType point1 = {0.0, 0.0, 0.0}; CoordType point2 = {0.0, 0.0, 0.0}; Grid::CopyToArr3(point1Vec, point1); Grid::CopyToArr3(point2Vec, point2); cout << "helloParams point: " << endl; cout << "point1: " << point1[0] << " " << point1[1] << " " << point1[2] << endl; cout << "point2: " << point2[0] << " " << point2[1] << " " << point2[2] << endl; // Finally, obtain the Grid of the data for the specified region, at requested refinement and lod, // using Renderer::getGrids() size_t timestep = rParams->GetCurrentTimestep(); int rc = DataMgrUtils::GetGrids(_dataMgr, timestep, varname, point1, point2, true, &actualRefLevel, &lod, &helloGrid); if (rc < 0) { return rc; } // Set the grid to use nearest-point interpolation, to calculate actual (uninterpolated) data max and min helloGrid->SetInterpolationOrder(0); // In order to sample the data at the user-specified refinement level, need to determine the number of voxels // that the line crosses, which requires knowing the underlying grid. // size_t nsamples = 100; // nsamples is the number of samples along the line. // Divide the line into maxvox equal sections, sample the variable at each point along the line, to find // coordinates of min and max value double maxval = -DBL_MAX; double minval = DBL_MAX; vector minPoint, maxPoint; for (int i = 0; i < nsamples; i++) { vector coord; for (int j = 0; j < point1.size(); j++) { coord.push_back(point1[j] + i * (point2[j] - point1[j]) / (double)(nsamples - 1)); } double sampledVal = helloGrid->GetValue(coord); if (sampledVal == helloGrid->GetMissingValue()) continue; if (minval > sampledVal) { minval = sampledVal; minPoint = coord; } if (maxval < sampledVal) { maxval = sampledVal; maxPoint = coord; } } // Obtain the line width // float width = (float)rParams->GetLineThickness(); // Set up lighting and color. We will use the lighting settings from the viewpoint params for rendering the lines, // but lighting will be disabled for rendering the max and min points. ViewpointParams *vpParams = _paramsMgr->GetViewpointParams(_winName); int nLights = vpParams->getNumLights(); float fcolor[3]; rParams->GetConstantColor(fcolor); if (nLights == 0) { // glDisable(GL_LIGHTING); } else { // glShadeModel(GL_SMOOTH); // glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, fcolor); // glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, vpParams->getExponent()); // // The line geometry will get a white specular color: // float specColor[4]; // specColor[0] = specColor[1] = specColor[2] = 0.8f; // specColor[3] = 1.f; // glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specColor); // glEnable(GL_LIGHTING); // glEnable(GL_COLOR_MATERIAL); } // glColor3fv(fcolor); // glLineWidth(width); // Calculate the normal vector as orthogonal to the line and projected to the viewer direction // To do this, take the cross product of the line direction with the viewer direction, // And then cross the result with the line direction. // Find the direction vector along the line and the camera direction double m[16]; vpParams->GetModelViewMatrix(m); double posvec[3], upvec[3], dirvec[3]; bool status = vpParams->ReconstructCamera(m, posvec, upvec, dirvec); if (!status) { SetErrMsg("Failed to get camera parameters"); return (-1); } double lineDir[3], vdir[3], cross[3], normvec[3]; for (int i = 0; i < 3; i++) { lineDir[i] = point2[i] - point1[i]; vdir[i] = dirvec[i]; } float len = vlength(lineDir); if (len == 0.f) len = 1.; vscale(lineDir, 1. / len); vcross(vdir, lineDir, cross); len = vlength(cross); if (len == 0.f) len = 1.; vscale(cross, 1. / len); vcross(cross, lineDir, normvec); len = vlength(normvec); if (len == 0.f) len = 1.; vscale(normvec, 1. / len); // Now render the line // translate to as to render in local user coordinates // // glBegin(GL_LINES); // glNormal3dv(normvec); // glVertex3d(point1[0], point1[1], point1[2]); // glNormal3dv(normvec); // glVertex3d(point2[0], point2[1], point2[2]); // glEnd(); // // // Then render the Max and Min points: // glDisable(GL_LIGHTING); // glPointSize(4. * width); // // Max will be white // glColor3f(1.f, 1.f, 1.f); // glBegin(GL_POINTS); // glVertex3d(maxPoint[0], maxPoint[1], maxPoint[2]); // glEnd(); // // // Set min point to be yellow // glColor3f(1.f, 1.f, 0.f); // glBegin(GL_POINTS); // glVertex3d(minPoint[0], minPoint[1], minPoint[2]); // glEnd(); return 0; } ================================================ FILE: lib/render/Histo.cpp ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: Histo.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: November 2004 // // Description: Implementation of Histo class // #include #include #include #include using namespace VAPoR; using namespace Wasp; #define SAMPLE_RATE 30 #ifndef __FLT_EPSILON__ #define __FLT_EPSILON__ FLT_EPSILON #endif Histo::Histo(int numberBins, float mnData, float mxData, string var, int ts) { setProperties(mnData, mxData, var, ts); reset(numberBins); } Histo::Histo(int numberBins) { autoSetProperties = true; reset(numberBins); } Histo::Histo() : Histo(0) {} Histo::~Histo() { if (_binArray) delete[] _binArray; if (_below) delete[] _below; if (_above) delete[] _above; } void Histo::reset(int newNumBins) { if (newNumBins != _numBins && newNumBins != -1) { _numBins = newNumBins; if (_binArray) delete[] _binArray; _binArray = new unsigned int[_numBins]; if (_below) delete[] _below; if (_above) delete[] _above; _below = nullptr; _above = nullptr; _nBinsBelow = 0; _nBinsAbove = 0; } for (int i = 0; i < _numBins; i++) _binArray[i] = 0; if (_below) memset(_below, 0, _nBinsBelow * sizeof(*_below)); if (_above) memset(_above, 0, _nBinsAbove * sizeof(*_above)); _numSamplesBelow = 0; _numSamplesAbove = 0; _maxBinSize = -1; _populated = false; } void Histo::reset(int newNumBins, float mnData, float mxData) { reset(newNumBins); _minMapData = mnData; _maxMapData = mxData; if (_maxMapData < _minMapData) _maxMapData = _minMapData; _range = _maxMapData - _minMapData; } void Histo::setBins(const vector &bins) { VAssert(bins.size() == _numBins); for (int i = 0; i < _numBins; i++) _binArray[i] = bins[i]; } void Histo::addToBin(float val) { // The additional checks below are because // 1. The data min/max are imperfect, e.g. calculated max is 1 but E value of 1.1 // 2. Float precision errors, e.g. // > Range is 0 - 1, outer range is -1 - 2 // > val = -0.00000000001 so it is below // > -0.00000000001 - -1 = -1 // > 0 - -1 = 1 // > 1 * array size = out of bounds if (val < _minMapData) { _numSamplesBelow++; if (_below) { assert(_minMapData - _minData > 0); int index = (val - _minData) / (_minMapData - _minData) * _nBinsBelow; if (index >= _nBinsBelow) index = _nBinsBelow - 1; if (index >= 0) _below[index]++; } } else if (val > _maxMapData) { _numSamplesAbove++; if (_above) { assert(_maxData - _maxMapData > 0); int index = (val - _maxMapData) / (_maxData - _maxMapData) * _nBinsAbove; if (index < 0) index = 0; if (index < _nBinsAbove) _above[index]++; } } else { int intVal = 0; if (_range == 0.f) intVal = 0; else intVal = (int)((val - _minMapData) / _range * (float)_numBins); if (intVal < 0) intVal = 0; if (intVal >= _numBins) intVal = _numBins - 1; _binArray[intVal]++; } } int Histo::getMaxBinSize() { if (_maxBinSize == -1) // For legacy purposes. Can remove with new TF Editor calculateMaxBinSize(); if (_maxBinSize == 0) return 1; else return _maxBinSize; } int Histo::getMaxBinSizeBetweenIndices(const int start, const int end) const { int maxBin = 0; if (start < 0 && _below) for (int i = max(0, start + _nBinsBelow); i < min(end + _nBinsBelow, _nBinsBelow); i++) maxBin = maxBin < _below[i] ? _below[i] : maxBin; for (int i = max(start, 0); i < min(end, _numBins); i++) maxBin = maxBin < _binArray[i] ? _binArray[i] : maxBin; if (end >= _numBins && _above) for (int i = max(start - _numBins, 0); i < min(end - _numBins, _nBinsAbove); i++) maxBin = maxBin < _above[i] ? _above[i] : maxBin; if (maxBin == 0) return 1; else return maxBin; } int Histo::getNumBins() const { return _numBins; } int Histo::getBinSize(int index) const { if (index < 0) { index += _nBinsBelow; if (index < 0) return 0; return _below[index]; } else if (index >= _numBins) { index -= _numBins; if (index >= _nBinsAbove) return 0; return _above[index]; } else return _binArray[index]; } int Histo::getBinSize(int index, int stride) const { int max = 0; for (int i = index; i < index + stride; i++) max = std::max(max, getBinSize(i)); return max; } float Histo::getNormalizedBinSize(int bin) const { if (_maxBinSize == 0) return 0; return getBinSize(bin) / (float)_maxBinSize; } float Histo::getNormalizedBinSizeForValue(float v) const { float nv = (v - _minMapData) / _range; return getNormalizedBinSizeForNormalizedValue(nv); } float Histo::getNormalizedBinSizeForNormalizedValue(float v) const { if (v < 0) { float belowNormMin = 0 - (_minMapData - _minData) / _range; if (v < belowNormMin || !_below) return 0; int index = (v - belowNormMin) / (0 - belowNormMin) * _nBinsBelow; return std::min(1.0f, _below[index] / (float)_maxBinSize); } else if (v >= 1.0) { float aboveNormMax = 1 + (_maxData - _maxMapData) / _range; if (v >= aboveNormMax || !_above) return 0; int index = (v - 1) / (aboveNormMax - 1) * _nBinsAbove; return std::min(1.0f, _above[index] / (float)_maxBinSize); } else return getNormalizedBinSize(v * _numBins); } int Histo::getBinIndexForValue(float v) { return (v - _minMapData) / _range * _numBins; } int Histo::Populate(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp) { size_t ts = rp->GetCurrentTimestep(); int refLevel = rp->GetRefinementLevel(); int lod = rp->GetCompressionLevel(); vector minExtsVec, maxExtsVec; rp->GetBox()->GetExtents(minExtsVec, maxExtsVec); CoordType minExts = {0.0, 0.0, 0.0}; CoordType maxExts = {0.0, 0.0, 0.0}; Grid::CopyToArr3(minExtsVec, minExts); Grid::CopyToArr3(maxExtsVec, maxExts); if (autoSetProperties) { MapperFunction *mf = rp->GetMapperFunc(varName); setProperties(mf->getMinMapValue(), mf->getMaxMapValue(), varName, ts); _minExts = minExtsVec; _maxExts = maxExtsVec; _lod = lod; _refLevel = refLevel; } if (_below) { delete[] _below; _below = nullptr; _nBinsBelow = 0; } if (_above) { delete[] _above; _above = nullptr; _nBinsAbove = 0; } _getDataRange(varName, dm, rp, &_minData, &_maxData); #ifdef WIN32 if (_maxMapData - _minMapData > FLT_EPSILON) { #else if (_maxMapData - _minMapData > __FLT_EPSILON__) { #endif _nBinsBelow = std::min(10000.0f, _numBins / (_maxMapData - _minMapData) * (_minMapData - _minData)); _nBinsAbove = std::min(10000.0f, _numBins / (_maxMapData - _minMapData) * (_maxData - _maxMapData)); } else { _nBinsAbove = 0; _nBinsBelow = 0; } if (_nBinsBelow > 0) _below = new unsigned int[_nBinsBelow]; if (_nBinsAbove > 0) _above = new unsigned int[_nBinsAbove]; if (_below) memset(_below, 0, _nBinsBelow * sizeof(*_below)); if (_above) memset(_above, 0, _nBinsAbove * sizeof(*_above)); auto samples = GetDataSamples(varName, dm, rp); for (const auto &sample : samples) addToBin(sample); calculateMaxBinSize(); _populated = true; return 0; } vector Histo::GetDataSamples(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp) { size_t ts = rp->GetCurrentTimestep(); int refLevel = rp->GetRefinementLevel(); int lod = rp->GetCompressionLevel(); vector minExtsVec, maxExtsVec; rp->GetBox()->GetExtents(minExtsVec, maxExtsVec); CoordType minExts = {0.0, 0.0, 0.0}; CoordType maxExts = {0.0, 0.0, 0.0}; Grid::CopyToArr3(minExtsVec, minExts); Grid::CopyToArr3(maxExtsVec, maxExts); Grid *grid; int rc = DataMgrUtils::GetGrids(dm, ts, varName, minExts, maxExts, true, &refLevel, &lod, &grid); if (rc < 0) return vector(); grid->SetInterpolationOrder(1); vector samples; if (shouldUseSampling(varName, dm, rp)) samples = getDataSamplesSampling(grid, minExtsVec, maxExtsVec); else samples = getDataSamplesIterating(grid, calculateStride(varName, dm, rp)); dm->UnlockGrid(grid); delete grid; return samples; } bool Histo::NeedsUpdate(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp) { if (!dm || !rp) return false; if (!_populated) return true; MapperFunction *mf = rp->GetMapperFunc(varName); vector minExts, maxExts; rp->GetBox()->GetExtents(minExts, maxExts); if (_minMapData != mf->getMinMapValue()) return true; if (_maxMapData != mf->getMaxMapValue()) return true; if (_refLevel != rp->GetRefinementLevel()) return true; if (_lod != rp->GetCompressionLevel()) return true; if (_varnameOfUpdate != varName) return true; if (_timestepOfUpdate != rp->GetCurrentTimestep()) return true; if (_minExts != minExts) return true; if (_maxExts != maxExts) return true; return false; } int Histo::PopulateIfNeeded(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp) { if (!NeedsUpdate(varName, dm, rp)) return 0; reset(_numBins); return Populate(varName, dm, rp); } vector Histo::getDataSamplesIterating(const Grid *grid, const int stride) { VAssert(grid); vector samples; float missingValue = grid->GetMissingValue(); Grid::ConstIterator enditr = grid->cend(); for (auto itr = grid->cbegin(); itr != enditr; itr += stride) { float v = *itr; if (v != missingValue) samples.push_back(v); } return samples; } #define X 0 #define Y 1 #define Z 2 vector Histo::getDataSamplesSampling(const Grid *grid, const vector &minExts, const vector &maxExts) { VAssert(grid); VAssert(minExts.size() == 3 && maxExts.size() == 3); vector samples; double dx = (maxExts[X] - minExts[X]) / SAMPLE_RATE; double dy = (maxExts[Y] - minExts[Y]) / SAMPLE_RATE; double dz = (maxExts[Z] - minExts[Z]) / SAMPLE_RATE; std::vector deltas = {dx, dy, dz}; float varValue, missingValue; std::vector coords(3, 0.0); double xStartPoint = minExts[X] + deltas[X] / 2.f; double yStartPoint = minExts[Y] + deltas[Y] / 2.f; double zStartPoint = minExts[Z] + deltas[Z] / 2.f; coords[X] = xStartPoint; coords[Y] = yStartPoint; coords[Z] = zStartPoint; int iSamples = SAMPLE_RATE; int jSamples = SAMPLE_RATE; int kSamples = SAMPLE_RATE; if (deltas[X] == 0) iSamples = 1; if (deltas[Y] == 0) jSamples = 1; if (deltas[Z] == 0) kSamples = 1; for (int k = 0; k < kSamples; k++) { coords[Y] = yStartPoint; for (int j = 0; j < jSamples; j++) { coords[X] = xStartPoint; for (int i = 0; i < iSamples; i++) { varValue = grid->GetValue(coords); missingValue = grid->GetMissingValue(); if (varValue != missingValue) samples.push_back(varValue); coords[X] += deltas[X]; } coords[Y] += deltas[Y]; } coords[Z] += deltas[Z]; } return samples; } #undef X #undef Y #undef Z int Histo::calculateStride(const std::string &varName, VAPoR::DataMgr *dm, const VAPoR::RenderParams *rp) { return DataMgrUtils::GetDefaultMetaInfoStride(dm, varName, rp->GetRefinementLevel()); } bool Histo::shouldUseSampling(const std::string &varName, VAPoR::DataMgr *dm, const VAPoR::RenderParams *rp) { // TODO how does this handle with unstructured grids? int nDims = dm->GetNumDimensions(varName); if (nDims == 3) return true; return false; } void Histo::setProperties(float mnData, float mxData, string var, int ts) { _minMapData = mnData; _maxMapData = mxData; if (_maxMapData < _minMapData) _maxMapData = _minMapData; _range = _maxMapData - _minMapData; _varnameOfUpdate = var; _timestepOfUpdate = ts; } void Histo::calculateMaxBinSize() { int maxBinSize = 0; for (int i = 0; i < _numBins; i++) { maxBinSize = maxBinSize > _binArray[i] ? maxBinSize : _binArray[i]; } _maxBinSize = maxBinSize; } void Histo::_getDataRange(const std::string &varName, VAPoR::DataMgr *d, VAPoR::RenderParams *r, float *min, float *max) const { CoordType minExt = {0.0, 0.0, 0.0}; CoordType maxExt = {0.0, 0.0, 0.0}; r->GetBox()->GetExtents(minExt, maxExt); std::vector range; d->GetDataRange(r->GetCurrentTimestep(), varName, r->GetRefinementLevel(), r->GetCompressionLevel(), minExt, maxExt, range); *min = range[0]; *max = range[1]; } ================================================ FILE: lib/render/ImageRenderer.cpp ================================================ //************************************************************************ // // Copyright (C) 2008 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: ImagerRenderer.cpp // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // #include // Must be included first!!! #include #include #include #include #include #include #include #include #include using namespace VAPoR; namespace { // // Make mesh conformant. PCS coordinates may wrap around globe at boundaries :-( // void conform(GLfloat *verts, int nx, int ny) { if (nx<2 || ny<2) return; // x values // for (int j = 0; j < ny; j++) { // left side // if (verts[3 * (nx * j)] > verts[3 * (nx * j + 1)]) { verts[3 * (nx * j)] = verts[3 * (nx * j + 1)]; } // right side // if (verts[3 * ((nx * j) + (nx - 1))] < verts[3 * ((nx * j) + (nx - 2))]) { verts[3 * ((nx * j) + (nx - 1))] = verts[3 * ((nx * j) + (nx - 2))]; } } // y values // verts++; for (int i = 0; i < nx; i++) { // bottom row // if (verts[3 * i] > verts[3 * (nx + i)]) { verts[3 * i] = verts[3 * (nx + i)]; } // top row // if (verts[3 * (nx * (ny - 1) + i)] < verts[3 * (nx * (ny - 2) + i)]) { verts[3 * (nx * (ny - 1) + i)] = verts[3 * (nx * (ny - 2) + i)]; } } } }; // namespace // // Register class with object factory!!! // static RendererRegistrar registrar(ImageRenderer::GetClassType(), ImageParams::GetClassType()); ImageRenderer::ImageRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr) : TwoDRenderer(pm, winName, dataSetName, ImageParams::GetClassType(), ImageRenderer::GetClassType(), instName, dataMgr), _maxResamplingResolution(1024) { _geoImage = NULL; _cacheImgFileName.clear(); _twoDTex = NULL; _cacheTimes.clear(); _pcsExtentsData.clear(); for (int i = 0; i < 4; i++) { _pcsExtentsImg[i] = 0; } _proj4StringImg.clear(); _texWidth = 0; _texHeight = 0; _cacheTimestep = 0; _cacheTMSLOD = -1; _cacheRefLevel = 0; _cacheLod = 0; _cacheHgtVar = ""; _cacheGeoreferenced = -1; _cacheTimestepTex = 0; _cacheBoxExtentsTex.clear(); _vertsWidth = 0; _vertsHeight = 0; _nindices = 0; _nverts = 0; } ImageRenderer::~ImageRenderer() { if (_geoImage) { delete _geoImage; _geoImage = NULL; } } const GLvoid *ImageRenderer::GetTexture(DataMgr *dataMgr, GLsizei &width, GLsizei &height, GLint &internalFormat, GLenum &format, GLenum &type, size_t &texelSize, bool &gridAligned) { width = 0; height = 0; internalFormat = GL_RGBA; format = GL_RGBA; type = GL_UNSIGNED_BYTE; texelSize = 4; // RGBA * sizeof(type) gridAligned = false; ImageParams *myParams = (ImageParams *)GetActiveParams(); if (myParams->GetIgnoreTransparency()) internalFormat = GL_RGB; GLvoid *texture = (GLvoid *)_getTexture(dataMgr); if (!texture) return (NULL); width = _texWidth; height = _texHeight; return (texture); } int ImageRenderer::GetMesh(DataMgr *dataMgr, GLfloat **verts, GLfloat **normals, GLsizei &nverts, GLsizei &width, GLsizei &height, GLuint **indices, GLsizei &nindices, bool &structuredMesh) { width = 0; height = 0; nindices = 0; nverts = 0; structuredMesh = true; // See if already in cache // if (!_gridStateDirty() && _sb_verts.GetBuf()) { width = _vertsWidth; height = _vertsHeight; *verts = (GLfloat *)_sb_verts.GetBuf(); *normals = (GLfloat *)_sb_normals.GetBuf(); nverts = _nverts; *indices = (GLuint *)_sb_indices.GetBuf(); nindices = _nindices; return (0); } _gridStateClear(); ImageParams *myParams = (ImageParams *)GetActiveParams(); // Find box extents for ROI // vector minBoxReq, maxBoxReq; myParams->GetBox()->GetExtents(minBoxReq, maxBoxReq); int rc; // If we are terrain mapping the image or if both the image and the // data are geo-referenced // double defaultZ = GetDefaultZ(dataMgr, myParams->GetCurrentTimestep()); if (!myParams->GetHeightVariableName().empty() || (myParams->GetIsGeoRef() && !dataMgr->GetMapProjection().empty())) { // Get the width and height of the image texture. These // will be used to set the width and height of the mesh. // _getTexture(dataMgr); // Ugh, this function is more than a get method... _vertsWidth = min(_maxResamplingResolution, _texWidth); _vertsHeight = min(_maxResamplingResolution, _texHeight); rc = _getMeshDisplaced(dataMgr, _vertsWidth, _vertsHeight, minBoxReq, maxBoxReq, defaultZ); } else { _vertsWidth = 2; _vertsHeight = 2; rc = _getMeshPlane(minBoxReq, maxBoxReq, defaultZ); } if (rc < 0) { _vertsWidth = 0; _vertsHeight = 0; return (-1); } //_transformToLocal(_vertsWidth, _vertsHeight, stretchFac); _gridStateSet(); // Compute vertex normals // *verts = (GLfloat *)_sb_verts.GetBuf(); *normals = (GLfloat *)_sb_normals.GetBuf(); ComputeNormals(*verts, _vertsWidth, _vertsHeight, *normals); // Construct indices for a triangle strip covering one row // of the mesh // *indices = (GLuint *)_sb_indices.GetBuf(); for (GLuint i = 0; i < _vertsWidth; i++) (*indices)[2 * i] = i; for (GLuint i = 0; i < _vertsWidth; i++) (*indices)[2 * i + 1] = i + _vertsWidth; width = _vertsWidth; height = _vertsHeight; nindices = _nindices; nverts = _nverts; return (0); } // Sets _pcsExtentsImg, _pcsExtentsData, // _proj4StringImg, _texWidth, _texHeight // unsigned char *ImageRenderer::_getTexture(DataMgr *dataMgr) { ImageParams *myParams = (ImageParams *)GetActiveParams(); int currentTimestep = myParams->GetCurrentTimestep(); string imgFileName = myParams->GetImagePath(); vector times = dataMgr->GetTimeCoordinates(); // Initialize _geoImage if image file or user times have changed // if (_imageStateDirty(times)) { int rc = _reinit(imgFileName, times); if (rc < 0) return (NULL); } VAssert(_geoImage); // Get the ROI for the displayed image in PCS coordinates of // the data // vector _pcsExtentsData = _getPCSExtentsData(); // Get a new texture if any relevant parameters have changed // if (!_twoDTex || _imageStateDirty(times) || _texStateDirty(dataMgr)) { // Get pro4 string for data if georeferencing is requested // string proj4StringData; if (myParams->GetIsGeoRef()) { proj4StringData = dataMgr->GetMapProjection(); } double geoCornersImg[8]; // Coordinates of image corners in geo coords _twoDTex = _getImage(_geoImage, currentTimestep, proj4StringData, _pcsExtentsData, _pcsExtentsImg, geoCornersImg, _proj4StringImg, _texWidth, _texHeight); if (!_twoDTex) return (NULL); _texStateSet(dataMgr); // Force recompute of mesh // _gridStateClear(); } _imageStateSet(times); return (_twoDTex); } bool ImageRenderer::_gridStateDirty() const { ImageParams *myParams = (ImageParams *)GetActiveParams(); int refLevel = myParams->GetRefinementLevel(); int lod = myParams->GetCompressionLevel(); string hgtVar = myParams->GetHeightVariableName(); int ts = myParams->GetCurrentTimestep(); vector minExt, maxExt; myParams->GetBox()->GetExtents(minExt, maxExt); vector boxExtents(minExt); boxExtents.insert(boxExtents.end(), maxExt.begin(), maxExt.end()); return (refLevel != _cacheRefLevel || lod != _cacheLod || hgtVar != _cacheHgtVar || ts != _cacheTimestep || boxExtents != _cacheBoxExtents); } void ImageRenderer::_gridStateClear() { _cacheRefLevel = 0; _cacheLod = 0; _cacheHgtVar.clear(); _cacheTimestep = -1; _cacheBoxExtents.clear(); } void ImageRenderer::_gridStateSet() { ImageParams *myParams = (ImageParams *)GetActiveParams(); _cacheRefLevel = myParams->GetRefinementLevel(); _cacheLod = myParams->GetCompressionLevel(); _cacheHgtVar = myParams->GetHeightVariableName(); _cacheTimestep = myParams->GetCurrentTimestep(); vector minExt, maxExt; myParams->GetBox()->GetExtents(minExt, maxExt); _cacheBoxExtents = minExt; _cacheBoxExtents.insert(_cacheBoxExtents.end(), maxExt.begin(), maxExt.end()); } bool ImageRenderer::_imageStateDirty(const vector ×) const { ImageParams *myParams = (ImageParams *)GetActiveParams(); string imgFileName = myParams->GetImagePath(); return (_cacheImgFileName != imgFileName || _cacheTimes != times); } void ImageRenderer::_imageStateSet(const vector ×) { ImageParams *myParams = (ImageParams *)GetActiveParams(); string imgFileName = myParams->GetImagePath(); _cacheImgFileName = imgFileName; _cacheTimes = times; } void ImageRenderer::_imageStateClear() { _cacheImgFileName.clear(); _cacheTimes.clear(); } bool ImageRenderer::_texStateDirty(DataMgr *dataMgr) const { ImageParams *myParams = (ImageParams *)GetActiveParams(); int georeferenced = (int)myParams->GetIsGeoRef(); int ts = myParams->GetCurrentTimestep(); vector minExt, maxExt; myParams->GetBox()->GetExtents(minExt, maxExt); vector boxExtents(minExt); boxExtents.insert(boxExtents.end(), maxExt.begin(), maxExt.end()); int tmsLOD = myParams->GetTMSLOD(); return (_cacheTimestepTex != ts || _cacheTMSLOD != tmsLOD || _cacheBoxExtentsTex != boxExtents || _cacheGeoreferenced != georeferenced); } void ImageRenderer::_texStateSet(DataMgr *dataMgr) { ImageParams *myParams = (ImageParams *)GetActiveParams(); int georeferenced = (int)myParams->GetIsGeoRef(); _cacheTimestepTex = myParams->GetCurrentTimestep(); _cacheTMSLOD = myParams->GetTMSLOD(); _cacheGeoreferenced = georeferenced; vector minExt, maxExt; myParams->GetBox()->GetExtents(minExt, maxExt); _cacheBoxExtentsTex = minExt; _cacheBoxExtentsTex.insert(_cacheBoxExtentsTex.end(), maxExt.begin(), maxExt.end()); } void ImageRenderer::_texStateClear() { _cacheTimestepTex = -1; _cacheTMSLOD = -1; _cacheBoxExtentsTex.clear(); _cacheGeoreferenced = -1; } int ImageRenderer::_reinit(string path, vector times) { // Two forms of georeferenced images are cachely supported. // If path is a directory then we have a TMS database. Otherwise, // path must point to a tiff file // bool tms_flag = false; if (Wasp::TMSUtils::IsTMSFile(path)) { ifstream in; in.open(path.c_str()); if (!in) { SetErrMsg("fopen(%s) : %M", path.c_str()); return (-1); } string tiledir; in >> tiledir; in.close(); // Construct path to TMS tile directory // if (FileUtils::IsPathAbsolute(tiledir)) { path = tiledir; } else { string dir = FileUtils::Dirname(path); path = dir + FileUtils::Separator + tiledir; } tms_flag = true; } // If _geoImage already exists make sure the type matches // the cache path (TMS or Tiff). If they don't match delete // _geoImage // if (_geoImage) { if ((dynamic_cast(_geoImage)) && tms_flag) { delete _geoImage; _geoImage = NULL; } if ((dynamic_cast(_geoImage)) && !tms_flag) { delete _geoImage; _geoImage = NULL; } } // Create an appropriate instance of _geoImage for the cache path // if (!_geoImage) { if (tms_flag) { ImageParams *myParams = dynamic_cast(GetActiveParams()); _geoImage = new GeoImageTMS(); dynamic_cast(_geoImage)->SetLOD(myParams->GetTMSLOD()); } else _geoImage = new GeoImageGeoTiff(); } int rc = _geoImage->Initialize(path, times); if (rc < 0) { SetErrMsg("GeoImage::Initialize(%s,)", path.c_str()); return (-1); } return (0); } unsigned char *ImageRenderer::_getImage(GeoImage *geoimage, size_t ts, string proj4StringData, vector pcsExtentsDataVec, double pcsExtentsImg[4], double geoCornersImg[8], string &proj4StringImg, GLsizei &width, GLsizei &height) const { VAssert(geoimage); VAssert(pcsExtentsDataVec.size() >= 4); // Initialize out params // for (int i = 0; i < 4; i++) { pcsExtentsImg[i] = 0.0; geoCornersImg[i] = geoCornersImg[i + 4] = 0.0; } width = height = 0; const int maxWidthReq = 1024; const int maxHeightReq = 1024; ImageParams *myParams = (ImageParams *)GetActiveParams(); GeoImageTMS *geoImageTMS = dynamic_cast(geoimage); if (geoImageTMS != nullptr) { dynamic_cast(_geoImage)->SetLOD(myParams->GetTMSLOD()); } double pcsExtentsData[4]; for (int i = 0; i < 4; i++) { pcsExtentsData[i] = pcsExtentsDataVec[i]; } size_t my_width, my_height; unsigned char *tex; if (proj4StringData.empty()) { // Data aren't geo-referenced. // for (int i = 0; i < 4; i++) { pcsExtentsImg[i] = pcsExtentsData[i]; } tex = geoimage->GetImage(ts, my_width, my_height); } else { tex = geoimage->GetImage(ts, pcsExtentsData, proj4StringData, maxWidthReq, maxHeightReq, pcsExtentsImg, geoCornersImg, proj4StringImg, my_width, my_height); } width = my_width; height = my_height; return (tex); } int ImageRenderer::_getMeshDisplaced(DataMgr *dataMgr, GLsizei width, GLsizei height, const vector &minBox, const vector &maxBox, double defaultZ) { // Construct the displaced (terrain following) grid using // a map projection, if specified. // ImageParams *myParams = (ImageParams *)GetActiveParams(); int refLevel = myParams->GetRefinementLevel(); int lod = myParams->GetCompressionLevel(); // Get the height variable if one specified // Grid * hgtGrid = NULL; string hgtVar = myParams->GetHeightVariableName(); if (!hgtVar.empty()) { int rc = DataMgrUtils::GetGrids(dataMgr, myParams->GetCurrentTimestep(), hgtVar, false, &refLevel, &lod, &hgtGrid); if (rc < 0) { MyBase::SetErrMsg("height data unavailable for 2D rendering at timestep %d", myParams->GetCurrentTimestep()); return (rc); } } // (Re)allocate space for verts // _nverts = width * height * 3; _sb_verts.Alloc(_nverts * 3 * sizeof(GLfloat)); _sb_normals.Alloc(_nverts * 3 * sizeof(GLfloat)); _nindices = 2 * width; _sb_indices.Alloc(_nindices * sizeof(GLuint)); int rc; if (myParams->GetIsGeoRef()) { rc = _getMeshDisplacedGeo(dataMgr, hgtGrid, width, height, defaultZ); } else { rc = _getMeshDisplacedNoGeo(dataMgr, hgtGrid, width, height, minBox, maxBox, defaultZ); } if (hgtGrid) { delete hgtGrid; } return (rc); } // Compute verts for displayed, geo-referenced image // int ImageRenderer::_getMeshDisplacedGeo(DataMgr *dataMgr, Grid *hgtGrid, GLsizei width, GLsizei height, double defaultZ) { // Set up proj.4: // string proj4String = dataMgr->GetMapProjection(); // Delta between pixels in image in Image PCS coordinates // double deltax = (_pcsExtentsImg[2] - _pcsExtentsImg[0]) / (double)(width - 1); double deltay = (_pcsExtentsImg[3] - _pcsExtentsImg[1]) / (double)(height - 1); // Compute horizontal coordinates in Image PCS space. Ignore // vertical coordinate for now. // GLfloat *verts = (GLfloat *)_sb_verts.GetBuf(); for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { verts[j * width * 3 + i * 3] = _pcsExtentsImg[0] + (i * deltax); verts[j * width * 3 + i * 3 + 1] = _pcsExtentsImg[1] + (j * deltay); verts[j * width * 3 + i * 3 + 2] = 0.0; // ignored } } // apply proj4 to transform the points(in place), converting // from Image PCS to Data PCS // Proj4API proj4; int rc = proj4.Transform(_proj4StringImg, proj4String, verts, verts + 1, NULL, width * height, 3); if (rc < 0) { MyBase::SetErrMsg("Error in coordinate projection"); return (-1); } // Now find vertical coordinate // double mv = hgtGrid ? hgtGrid->GetMissingValue() : 0.0; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { float x = verts[j * width * 3 + i * 3]; float y = verts[j * width * 3 + i * 3 + 1]; float z = 0.0; // Lookup vertical coordinate as a data element from the // height variable. Note, missing values are possible if image // extents are out side of extents for height variable, or if // height variable itself contains missing values. // float deltaZ = (float)defaultZ; if (hgtGrid) { if (deltaZ == mv) deltaZ = defaultZ; else deltaZ = hgtGrid->GetValue(x, y, 0.0); } z = deltaZ; verts[j * width * 3 + i * 3 + 2] = z; } } // Take care of any boundary conditions to present meshes with // folds. Still needed? // conform(verts, width, height); return (0); } // Compute verts for displayed, non-georeferenced image // int ImageRenderer::_getMeshDisplacedNoGeo(DataMgr *dataMgr, Grid *hgtGrid, GLsizei width, GLsizei height, const vector &minExt, const vector &maxExt, double defaultZ) { // Delta between pixels in image in Image PCS coordinates // double deltax = (maxExt[0] - minExt[0]) / (double)(width - 1); double deltay = (maxExt[1] - minExt[1]) / (double)(height - 1); // Compute horizontal coordinates in Image PCS space. Ignore // vertical coordinate for now. // GLfloat *verts = (GLfloat *)_sb_verts.GetBuf(); double mv = hgtGrid ? hgtGrid->GetMissingValue() : 0.0; for (int j = 0; j < height; j++) { double y = minExt[1] + (j * deltay); for (int i = 0; i < width; i++) { double x = minExt[0] + (i * deltax); double z = 0.0; verts[j * width * 3 + i * 3] = x; verts[j * width * 3 + i * 3 + 1] = y; // Lookup vertical coordinate as a data element from the // height variable. Note, missing values are possible if image // extents are out side of extents for height variable, or if // height variable itself contains missing values. // float deltaZ = (float)defaultZ; if (hgtGrid) { if (deltaZ == mv) deltaZ = defaultZ; else deltaZ = hgtGrid->GetValue(x, y, 0.0); } z = deltaZ; verts[j * width * 3 + i * 3 + 2] = z; } } return (0); } int ImageRenderer::_getMeshPlane(const vector &minBox, const vector &maxBox, double defaultZ) { // determine the corners of the textured plane. // If it's X-Y (orientation = 2) // If it's X-Z (orientation = 1) // If it's Y-Z (orientation = 0) // ImageParams *myParams = (ImageParams *)GetActiveParams(); int orient = myParams->GetOrientation(); _nverts = 2 * 2; GLfloat *verts = (float *)_sb_verts.Alloc(_nverts * 3 * sizeof(*verts)); _sb_normals.Alloc(_nverts * 3 * sizeof(GLfloat)); _nindices = 2 * 2; _sb_indices.Alloc(_nindices * sizeof(GLuint)); if (orient == 2) { // X-Y verts[0] = minBox[0]; verts[1] = minBox[1]; verts[2] = defaultZ; verts[3] = maxBox[0]; verts[4] = minBox[1]; verts[5] = defaultZ; verts[6] = minBox[0]; verts[7] = maxBox[1]; verts[8] = defaultZ; verts[9] = maxBox[0]; verts[10] = maxBox[1]; verts[11] = defaultZ; } else { // X-Z SetErrMsg("Orientation == %d not supported", orient); return (-1); } return (0); } // Get the selected horizontal ROI in PCS data coordinates // vector ImageRenderer::_getPCSExtentsData() const { ImageParams *myParams = (ImageParams *)GetActiveParams(); // Find box extents for ROI // vector minBox; vector maxBox; myParams->GetBox()->GetExtents(minBox, maxBox); vector pcsExtentsData; pcsExtentsData.push_back(minBox[0]); pcsExtentsData.push_back(minBox[1]); pcsExtentsData.push_back(maxBox[0]); pcsExtentsData.push_back(maxBox[1]); return (pcsExtentsData); } #if 0 void ImageRenderer::_transformToLocal( size_t width, size_t height, const vector &scaleFac) const { size_t ts = GetCurrentTimestep(); vectorminExts,maxExts; GLfloat *verts = (GLfloat *) _sb_verts.GetBuf(); for (int j = 0; j ImageWriter::factories; ImageWriter::ImageWriter(const std::string &path) : format(Format::RGB), path(path), opened(false) {} ImageWriter *ImageWriter::CreateImageWriterForFile(const std::string &path) { std::string pathExtension = FileUtils::Extension(path); for (auto factory = factories.begin(); factory != factories.end(); ++factory) for (auto writerExtension = (*factory)->Extensions.begin(); writerExtension != (*factory)->Extensions.end(); ++writerExtension) if (*writerExtension == pathExtension) return (*factory)->Create(path); SetErrMsg("Unsupported image file type \"%s\"", FileUtils::Extension(path).c_str()); return nullptr; } void ImageWriter::RegisterFactory(ImageWriterFactory *factory) { factories.push_back(factory); } ================================================ FILE: lib/render/JPGWriter.cpp ================================================ #include "vapor/JPGWriter.h" #include "vapor/jpegapi.h" using namespace VAPoR; REGISTER_IMAGEWRITER(JPGWriter); int JPGWriter::DefaultQuality = 95; std::vector JPGWriter::GetFileExtensions() { return {"jpg", "jpeg"}; } JPGWriter::JPGWriter(const std::string &path) : ImageWriter(path), fp(nullptr), Quality(DefaultQuality) { fp = fopen(path.c_str(), "wb"); if (fp) opened = true; } JPGWriter::~JPGWriter() { if (fp) fclose(fp); fp = nullptr; } int JPGWriter::Write(const unsigned char *buffer, const unsigned int width, const unsigned int height) { if (!opened) { MyBase::SetErrMsg("Unable to open JPG file for writing: \"%s\"", path.c_str()); return -1; } return write_JPEG_file(fp, width, height, const_cast(buffer), Quality); } ================================================ FILE: lib/render/LegacyGL.cpp ================================================ #include "vapor/glutil.h" #include "vapor/LegacyGL.h" #include "vapor/VAssert.h" #include #include "vapor/GLManager.h" #include "vapor/ShaderProgram.h" #include using namespace VAPoR; using std::vector; LegacyGL::LegacyGL(GLManager *glManager) : _glManager(glManager), _mode(0), _emulateQuads(false), _firstQuadTriangle(true), _VAO(0), _VBO(0), _nx(0), _ny(0), _nz(0), _r(1), _g(1), _b(1), _a(1), _s(0), _t(0), _initialized(false), _insideBeginEndBlock(false), _lightingEnabled(false), _textureEnabled(false), _lightDir{0} { } LegacyGL::~LegacyGL() { if (_VAO) glDeleteVertexArrays(1, &_VAO); if (_VBO) glDeleteBuffers(1, &_VBO); } void LegacyGL::Initialize() { GL_ERR_BREAK(); VAssert(!_initialized); glGenVertexArrays(1, &_VAO); glGenBuffers(1, &_VBO); VAssert(_VAO); VAssert(_VBO); glBindVertexArray(_VAO); glBindBuffer(GL_ARRAY_BUFFER, _VBO); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), NULL); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void *)offsetof(struct VertexData, nx)); glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void *)offsetof(struct VertexData, r)); glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void *)offsetof(struct VertexData, s)); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); _emptyTexture.Generate(); float zero = 0; _emptyTexture.TexImage(GL_RGB, 1, 1, 0, GL_RGBA, GL_FLOAT, &zero); _initialized = true; GL_ERR_BREAK(); } void LegacyGL::Begin(unsigned int mode) { VAssert(!_insideBeginEndBlock); if (mode == LGL_QUADS) { _emulateQuads = true; mode = GL_TRIANGLES; } _mode = mode; _insideBeginEndBlock = true; } void LegacyGL::End() { if (!_initialized) Initialize(); VAssert(_insideBeginEndBlock); glBindVertexArray(_VAO); glBindBuffer(GL_ARRAY_BUFFER, _VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(VertexData) * _vertices.size(), _vertices.data(), GL_STREAM_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); ShaderProgram *_shader = _glManager->shaderManager->GetShader("Legacy"); _shader->Bind(); _shader->SetUniform("P", _glManager->matrixManager->GetProjectionMatrix()); _shader->SetUniform("MV", _glManager->matrixManager->GetModelViewMatrix()); _shader->SetUniform("lightingEnabled", _lightingEnabled); _shader->SetUniform("textureEnabled", _textureEnabled); _shader->SetUniform("lightDir", glm::make_vec3(_lightDir)); if (!_textureEnabled) _emptyTexture.Bind(); VAssert(glIsVertexArray(_VAO) == GL_TRUE); VAssert(glIsBuffer(_VBO) == GL_TRUE); glDrawArrays(_mode, 0, _vertices.size()); glBindVertexArray(0); _shader->UnBind(); if (!_textureEnabled) _emptyTexture.UnBind(); _emulateQuads = false; _insideBeginEndBlock = false; _vertices.clear(); } void LegacyGL::Vertex(glm::vec2 v) { Vertex2f(v.x, v.y); } void LegacyGL::Vertex(glm::vec3 v) { Vertex3f(v.x, v.y, v.z); } void LegacyGL::Vertex2f(float x, float y) { Vertex3f(x, y, 0); } extern bool PRINT_VERTS; void LegacyGL::Vertex3f(float x, float y, float z) { VAssert(_insideBeginEndBlock); _vertices.push_back({x, y, z, _nx, _ny, _nz, _r, _g, _b, _a, _s, _t}); if (_emulateQuads && _vertices.size() % 3 == 0) { if (_firstQuadTriangle) { VertexData v1 = _vertices[_vertices.size() - 3]; VertexData v3 = _vertices[_vertices.size() - 1]; _vertices.push_back(v1); _vertices.push_back(v3); _firstQuadTriangle = false; } else { _firstQuadTriangle = true; } } } void LegacyGL::Vertex3fv(const float *v) { Vertex3f(v[0], v[1], v[2]); } void LegacyGL::Vertex3dv(const double *v) { Vertex3f((float)v[0], (float)v[1], (float)v[2]); } void LegacyGL::Normal3f(float x, float y, float z) { _nx = x; _ny = y; _nz = z; } void LegacyGL::Normal3fv(const float *n) { Normal3f(n[0], n[1], n[2]); } void LegacyGL::Color(glm::vec3 v) { Color3f(v.r, v.g, v.b); } void LegacyGL::Color(glm::vec4 v) { Color4f(v.r, v.g, v.b, v.a); } void LegacyGL::Color3f(float r, float g, float b) { _r = r; _g = g; _b = b; _a = 1.0f; } void LegacyGL::Color3fv(const float *f) { Color3f(f[0], f[1], f[2]); } void LegacyGL::Color4f(float r, float g, float b, float a) { _r = r; _g = g; _b = b; _a = a; } void LegacyGL::Color4fv(const float *f) { Color4f(f[0], f[1], f[2], f[3]); } void LegacyGL::TexCoord(glm::vec2 st) { TexCoord2f(st.s, st.t); } void LegacyGL::TexCoord2f(float s, float t) { _s = s; _t = t; } void LegacyGL::EnableLighting() { _lightingEnabled = true; } void LegacyGL::DisableLighting() { _lightingEnabled = false; } void LegacyGL::LightDirectionfv(const float *f) { glm::vec3 dir = glm::make_vec3(f); // mimic legacy setlightdirectionfv // dir = _glManager->matrixManager->GetModelViewMatrix() * glm::vec4(dir, 0.f); _lightDir[0] = dir.x; _lightDir[1] = dir.y; _lightDir[2] = dir.z; } void LegacyGL::EnableTexture() { _textureEnabled = true; } void LegacyGL::DisableTexture() { _textureEnabled = false; } ================================================ FILE: lib/render/MatrixManager.cpp ================================================ #include #include "vapor/MatrixManager.h" #include "vapor/VAssert.h" #include #include #include #include using namespace VAPoR; using glm::mat4; using glm::vec3; using glm::vec4; using std::pair; MatrixManager::MatrixManager() { _modelviewStack.push(glm::mat4(1.0)); _projectionStack.push(glm::mat4(1.0)); _currentStack = &_modelviewStack; _mode = Mode::ModelView; } glm::mat4 MatrixManager::GetCurrentMatrix() const { return top(); } mat4 MatrixManager::GetProjectionMatrix() const { return _projectionStack.top(); } mat4 MatrixManager::GetModelViewMatrix() const { return _modelviewStack.top(); } mat4 MatrixManager::GetModelViewProjectionMatrix() const { return GetProjectionMatrix() * GetModelViewMatrix(); } void MatrixManager::SetCurrentMatrix(const glm::mat4 m) { top() = m; } void MatrixManager::MatrixModeModelView() { _currentStack = &_modelviewStack; _mode = Mode::ModelView; } void MatrixManager::MatrixModeProjection() { _currentStack = &_projectionStack; _mode = Mode::Projection; } void MatrixManager::PushMatrix() { _currentStack->push(top()); } void MatrixManager::PopMatrix() { _currentStack->pop(); } void MatrixManager::LoadMatrixd(const double *m) { top() = glm::make_mat4(m); } void MatrixManager::GetDoublev(Mode mode, double *m) const { const float *data = nullptr; if (mode == Mode::ModelView) data = glm::value_ptr(_modelviewStack.top()); else if (mode == Mode::Projection) data = glm::value_ptr(_projectionStack.top()); if (data) { for (int i = 0; i < 16; i++) m[i] = data[i]; } } void MatrixManager::LoadIdentity() { top() = glm::mat4(1.0); } void MatrixManager::Translate(float x, float y, float z) { top() = glm::translate(top(), vec3(x, y, z)); } void MatrixManager::Scale(float x, float y, float z) { top() = glm::scale(top(), vec3(x, y, z)); } void MatrixManager::Rotate(float angle, float x, float y, float z) { top() = glm::rotate(top(), angle, vec3(x, y, z)); } void MatrixManager::Perspective(float fovy, float aspect, float zNear, float zFar) { top() = glm::perspective(fovy, aspect, zNear, zFar); _projectionAspectRatio = aspect; Near = zNear; Far = zFar; FOV = fovy; Aspect = aspect; } void MatrixManager::Ortho(float left, float right, float bottom, float top) { this->top() = glm::ortho(left, right, bottom, top); _projectionAspectRatio = (right - left) / (top - bottom); } void MatrixManager::Ortho(float left, float right, float bottom, float top, float zNear, float zFar) { this->top() = glm::ortho(left, right, bottom, top, zNear, zFar); } glm::vec2 MatrixManager::ProjectToScreen(float x, float y, float z) const { return ProjectToScreen(vec3(x, y, z)); } glm::vec2 MatrixManager::ProjectToScreen(const glm::vec3 &v) const { vec4 vs = GetModelViewProjectionMatrix() * vec4(v, 1.0f); vs /= vs.w; return vs; } float MatrixManager::GetProjectionAspectRatio() const { VAssert(_projectionAspectRatio != 0); return _projectionAspectRatio; } #ifdef LEGACY_GL_DEBUG int MatrixManager::GetGLMatrixMode() { int mode; glGetIntegerv(GL_MATRIX_MODE, &mode); return mode; } const char *MatrixManager::GetGLMatrixModeStr() { int mode = GetGLMatrixMode(); switch (mode) { case GL_MODELVIEW: return "GL_MODELVIEW"; case GL_PROJECTION: return "GL_PROJECTION"; case GL_TEXTURE: return "GL_TEXTURE"; case GL_COLOR: return "GL_COLOR"; default: return "UNKNOWN_MODE"; } } int MatrixManager::GetGLModelViewStackDepth() { int depth; glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth); return depth; } int MatrixManager::GetGLProjectionStackDepth() { int depth; glGetIntegerv(GL_PROJECTION_STACK_DEPTH, &depth); return depth; } int MatrixManager::GetGLCurrentStackDepth() { if (GetGLMatrixMode() == GL_MODELVIEW) return GetGLModelViewStackDepth(); if (GetGLMatrixMode() == GL_PROJECTION) return GetGLProjectionStackDepth(); return -1; } const char *MatrixManager::GetMatrixModeStr() { if (_mode == Mode::ModelView) return "ModelView"; return "Projection"; } #endif glm::mat4 &MatrixManager::top() { return _currentStack->top(); } const glm::mat4 &MatrixManager::top() const { return _currentStack->top(); } ================================================ FILE: lib/render/ModelRenderer.cpp ================================================ //************************************************************************ // * // Copyright (C) 2018 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: ModelRenderer.cpp // // Author: Stas Jaroszynski // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: March 2018 // // Description: // Implementation of ModelRenderer // #include #include // Must be included first!!! #include #include #include #include #include #include #include #include #include #include #include #include using namespace VAPoR; static RendererRegistrar registrar(ModelRenderer::GetClassType(), ModelParams::GetClassType()); ModelRenderer::ModelRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr) : Renderer(pm, winName, dataSetName, ModelParams::GetClassType(), ModelRenderer::GetClassType(), instName, dataMgr) { } int ModelRenderer::_paintGL(bool fast) { RenderParams * rp = GetActiveParams(); int rc = 0; const std::string file = rp->GetValueString(ModelParams::FileTag, ""); if (file != _cachedFile) { rc = _scene.Load(file); if (rc < 0) { _cachedFile = ""; return rc; } _cachedFile = file; glm::vec3 center = _scene.Center(); rp->GetTransform()->SetOrigin({center.x, center.y, center.z}); } LegacyGL *lgl = _glManager->legacy; MatrixManager *mm = _glManager->matrixManager; mm->MatrixModeModelView(); lgl->EnableLighting(); lgl->DisableTexture(); ViewpointParams *viewpointParams = _paramsMgr->GetViewpointParams(_winName); Viewpoint * viewpoint = viewpointParams->getCurrentViewpoint(); double m[16]; double cameraPos[3], cameraUp[3], cameraDir[3]; _glManager->matrixManager->GetDoublev(MatrixManager::Mode::ModelView, m); viewpoint->ReconstructCamera(m, cameraPos, cameraUp, cameraDir); lgl->Color3f(1, 1, 1); float lightDir[3] = {(float)cameraDir[0], (float)cameraDir[1], (float)cameraDir[2]}; lgl->LightDirectionfv(lightDir); glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); _scene.Render(_glManager, rp->GetCurrentTimestep()); lgl->DisableLighting(); return rc; } int ModelRenderer::_initializeGL() { return 0; } void ModelRenderer::Model::renderNode(GLManager *gl, const aiNode *nd) const { LegacyGL * lgl = gl->legacy; MatrixManager *mm = gl->matrixManager; mm->PushMatrix(); mm->SetCurrentMatrix(mm->GetCurrentMatrix() * getMatrix(nd)); for (int m = 0; m < nd->mNumMeshes; m++) { const aiMesh *mesh = _scene->mMeshes[nd->mMeshes[m]]; const bool hasNormals = mesh->HasNormals(); const bool hasColor = mesh->GetNumColorChannels() > 0; if (mesh->HasNormals()) lgl->EnableLighting(); else lgl->DisableLighting(); lgl->Begin(GL_TRIANGLES); for (int f = 0; f < mesh->mNumFaces; f++) { const aiFace *face = &mesh->mFaces[f]; if (face->mNumIndices != 3) continue; for (int v = 0; v < face->mNumIndices; v++) { if (hasColor) lgl->Color3fv(&mesh->mColors[0][face->mIndices[v]].r); if (hasNormals) lgl->Normal3fv(&mesh->mNormals[face->mIndices[v]].x); lgl->Vertex3fv(&mesh->mVertices[face->mIndices[v]].x); } } lgl->End(); } for (int c = 0; c < nd->mNumChildren; c++) renderNode(gl, nd->mChildren[c]); mm->PopMatrix(); } void ModelRenderer::Model::calculateBounds(const aiNode *nd, glm::mat4 transform) { transform *= getMatrix(nd); for (int m = 0; m < nd->mNumMeshes; m++) { const aiMesh *mesh = _scene->mMeshes[nd->mMeshes[m]]; for (int f = 0; f < mesh->mNumFaces; f++) { const aiFace *face = &mesh->mFaces[f]; if (face->mNumIndices != 3) continue; for (int v = 0; v < face->mNumIndices; v++) { glm::vec3 gv = glm::make_vec3(&mesh->mVertices[face->mIndices[v]].x); gv = transform * glm::vec4(gv, 1.0f); _min = glm::min(_min, gv); _max = glm::max(_max, gv); } } } for (int c = 0; c < nd->mNumChildren; c++) calculateBounds(nd->mChildren[c], transform); } glm::mat4 ModelRenderer::Model::getMatrix(const aiNode *nd) const { // Ignore root transform. This is created by assimp to change the up axis if (nd == _scene->mRootNode) return glm::identity(); aiMatrix4x4 m = nd->mTransformation; m.Transpose(); return glm::make_mat4((float *)&m); } void ModelRenderer::Model::Render(GLManager *gl) const { gl->legacy->Color3f(1, 1, 1); gl->legacy->DisableTexture(); VAssert(_scene); renderNode(gl, _scene->mRootNode); } void ModelRenderer::Model::DrawBoundingBox(GLManager *gl) const { LegacyGL *lgl = gl->legacy; lgl->DisableLighting(); lgl->Begin(GL_LINES); lgl->Color3f(1, 0, 0); lgl->Vertex3f(_min.x, _min.y, _min.z); lgl->Vertex3f(_max.x, _min.y, _min.z); lgl->Color3f(0, 1, 0); lgl->Vertex3f(_min.x, _min.y, _min.z); lgl->Vertex3f(_min.x, _max.y, _min.z); lgl->Color3f(0, 0, 1); lgl->Vertex3f(_min.x, _min.y, _min.z); lgl->Vertex3f(_min.x, _min.y, _max.z); lgl->End(); } int ModelRenderer::Model::Load(const std::string &path) { if (!FileUtils::Exists(path)) { MyBase::SetErrMsg("File not found \"%s\"", path.c_str()); return -1; } if (_importer.GetScene()) _importer.FreeScene(); _scene = _importer.ReadFile(path, aiProcessPreset_TargetRealtime_Quality | aiProcess_Triangulate); if (!_scene) { MyBase::SetErrMsg("3D File Error: %s", _importer.GetErrorString()); return -1; } _min = glm::vec3(FLT_MAX); _max = glm::vec3(FLT_MIN); calculateBounds(_scene->mRootNode); return 0; } ModelRenderer::Scene::~Scene() { for (auto it : _models) delete it.second; } int ModelRenderer::Scene::Load(const std::string &path) { for (auto it : _models) delete it.second; _keyframes.clear(); _models.clear(); _instances.clear(); int rc; if (FileUtils::Extension(path) == "vms") rc = loadSceneFile(path); else rc = createSceneFromModelFile(path); return rc; } void ModelRenderer::Scene::Render(GLManager *gl, const int ts) { MatrixManager * mm = gl->matrixManager; const vector &keyframe = getInstances(ts); for (const auto &instance : keyframe) { mm->PushMatrix(); const glm::vec3 translate = instance.translate; const glm::vec3 rotate = instance.rotate; const glm::vec3 scale = instance.scale; const glm::vec3 origin = instance.origin; mm->Translate(translate.x, translate.y, translate.z); mm->Translate(origin.x, origin.y, origin.z); mm->Rotate(glm::radians(rotate.x), 1, 0, 0); mm->Rotate(glm::radians(rotate.y), 0, 1, 0); mm->Rotate(glm::radians(rotate.z), 0, 0, 1); mm->Scale(scale.x, scale.y, scale.z); mm->Translate(-origin.x, -origin.y, -origin.z); _models[instance.file]->Render(gl); mm->PopMatrix(); } } glm::vec3 ModelRenderer::Scene::Center() const { glm::vec3 accum(0.f); for (const auto &it : _models) accum += it.second->Center(); if (!_models.empty()) accum /= (float)_models.size(); return accum; } std::vector ModelRenderer::Scene::getInstances(const int ts) const { VAssert(ts >= 0); int lastValidFrame = -1; for (auto frame : _keyframes) { const int frameTime = frame.first; if (frameTime == ts) return frame.second; if (frameTime < ts && frameTime > lastValidFrame) lastValidFrame = frameTime; } if (lastValidFrame != -1) return _keyframes.at(lastValidFrame); else return vector(); } int ModelRenderer::Scene::createSceneFromModelFile(const std::string &path) { Model *model = new Model; int rc = model->Load(path); if (rc < 0) return rc; _models[path] = model; ModelInstance defaultInstance; defaultInstance.file = path; _keyframes[0] = {defaultInstance}; return 0; } #define TAG_INSTANCE "instance_" #define TAG_TIME "time_" int ModelRenderer::Scene::loadSceneFile(const std::string &sceneFilePath) { XmlNode root; XmlParser xmlParser; int rc = xmlParser.LoadFromFile(&root, sceneFilePath); if (rc < 0) return rc; for (int i = 0; i < root.GetNumChildren(); i++) { XmlNode *node = root.GetChild(i); if (STLUtils::BeginsWith(node->Tag(), TAG_INSTANCE)) { ModelInstance instance; rc = handleInstanceNode(node, &instance); } else if (STLUtils::BeginsWith(node->Tag(), TAG_TIME)) { rc = handleTimeNode(node); } else { MyBase::SetErrMsg("Unknown tag \"%s\"", node->Tag().c_str()); rc = -1; } if (rc < 0) { MyBase::SetErrMsg("%s ->", root.Tag().c_str()); break; } } if (rc < 0) return rc; for (const ModelInstance &instance : _instances) { if (!isModelCached(instance.file)) { string filePath = instance.file; if (!FileUtils::IsPathAbsolute(filePath)) filePath = FileUtils::JoinPaths({FileUtils::Dirname(sceneFilePath), filePath}); Model *model = new Model; int rc = model->Load(filePath); if (rc < 0) return rc; _models[instance.file] = model; } } return rc; } int ModelRenderer::Scene::handleInstanceNode(XmlNode *node, ModelInstance *instance) { string name = node->Tag(); if (name == TAG_INSTANCE) { MyBase::SetErrMsg("Invalid instance \"%s\"", node->Tag().c_str()); return -1; } instance->name = name; if (node->Attrs().find("file") != node->Attrs().end()) instance->file = node->Attrs()["file"]; if (node->HasChild("translate")) if (handleVectorNode(node->GetChild("translate"), &instance->translate) < 0) return -1; if (node->HasChild("rotate")) if (handleVectorNode(node->GetChild("rotate"), &instance->rotate) < 0) return -1; if (node->HasChild("scale")) if (handleVectorNode(node->GetChild("scale"), &instance->scale) < 0) return -1; if (node->HasChild("origin")) { if (handleVectorNode(node->GetChild("origin"), &instance->origin) < 0) return -1; } else if (doesInstanceExist(instance->name)) { instance->origin = getInitInstance(instance->name).origin; } if (doesInstanceExist(instance->name)) { if (!instance->file.empty()) { MyBase::SetErrMsg("Instance \"%s\" file specified more than once", node->Tag().c_str()); return -1; } else { instance->file = getInitInstance(instance->name).file; } } else { if (instance->file.empty()) { MyBase::SetErrMsg("Instance \"%s\" defined without an associated file", node->Tag().c_str()); return -1; } _instances.push_back(*instance); } return 0; } int ModelRenderer::Scene::handleTimeNode(XmlNode *node) { int rc = 0; int ts; string tsString = node->Tag().substr(strlen(TAG_TIME)); if (tsString.empty() || parseIntString(tsString, &ts)) { MyBase::SetErrMsg("Invalid time tag \"%s\"", node->Tag().c_str()); return -1; } vector instances; for (int i = 0; i < node->GetNumChildren(); i++) { XmlNode *child = node->GetChild(i); if (STLUtils::BeginsWith(child->Tag(), TAG_INSTANCE)) { ModelInstance instance; rc = handleInstanceNode(child, &instance); if (rc < 0) break; instances.push_back(instance); } else { MyBase::SetErrMsg("Unknown tag \"%s\"", child->Tag().c_str()); rc = -1; } if (rc < 0) { MyBase::SetErrMsg("%s ->", node->Tag().c_str()); break; } } _keyframes[ts] = instances; return rc; } int ModelRenderer::Scene::handleVectorNode(XmlNode *node, glm::vec3 *v) { int rc = 0; rc -= handleFloatAttribute(node, "x", &v->x); rc -= handleFloatAttribute(node, "y", &v->y); rc -= handleFloatAttribute(node, "z", &v->z); return rc; } int ModelRenderer::Scene::handleFloatAttribute(XmlNode *node, const std::string &name, float *f) { if (node->Attrs().find(name) == node->Attrs().end()) return 0; string valueString = node->Attrs()[name]; size_t charsRead; try { *f = std::stof(valueString, &charsRead); } catch (invalid_argument const&) { MyBase::SetErrMsg("Invalid float attribute %s=\"%s\"", name.c_str(), valueString.c_str()); return -1; } catch (out_of_range const&) { MyBase::SetErrMsg("Float attribute out of range %s=\"%s\"", name.c_str(), valueString.c_str()); return -1; } if (charsRead != valueString.size()) { MyBase::SetErrMsg("Invalid float attribute %s=\"%s\"", name.c_str(), valueString.c_str()); return -1; } return 0; } int ModelRenderer::Scene::parseIntString(const std::string &str, int *i) const { size_t charsRead; try { *i = std::stof(str, &charsRead); } catch (invalid_argument const&) { MyBase::SetErrMsg("Invalid integer \"%s\"", str.c_str()); return -1; } catch (out_of_range const&) { MyBase::SetErrMsg("Integer out of range \"%s\"", str.c_str()); return -1; } if (charsRead != str.size()) { MyBase::SetErrMsg("Invalid integer \"%s\"", str.c_str()); return -1; } return 0; } ModelRenderer::Scene::ModelInstance ModelRenderer::Scene::getInitInstance(const std::string &name) const { assert(doesInstanceExist(name)); for (const ModelInstance &inst : _instances) if (inst.name == name) return inst; return ModelInstance(); } bool ModelRenderer::Scene::doesInstanceExist(const std::string &name) const { for (const ModelInstance &instance : _instances) if (instance.name == name) return true; return false; } bool ModelRenderer::Scene::isModelCached(const std::string &file) const { for (const auto &it : _models) if (it.first == file) return true; return false; } ================================================ FILE: lib/render/MyPython.cpp ================================================ // * // Copyright (C) 2016 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: MyPython.cpp // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: Thu Sep 29 13:29:44 MDT 2016 // // Description: // #include #include #include #include #include #include #include #ifndef WIN32 #include #endif #include #include #include "vapor/VAssert.h" using namespace Wasp; #ifdef VAPOR3_0_0 namespace { bool pyIntFailed = false; static void signal_handler(int sig) { if (sig == SIGINT) { cerr << "Caught SIGINT\n"; pyIntFailed = true; } } void init_signals(void) { struct sigaction sigact; sigact.sa_handler = signal_handler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(SIGINT, &sigact, (struct sigaction *)NULL); } } // namespace #endif MyPython * MyPython::m_instance = NULL; bool MyPython::m_isInitialized = false; std::string MyPython::m_pyHome = ""; bool MyPython::IsRunningFromPython = false; MyPython *MyPython::Instance() { if (!m_instance) { m_instance = new MyPython(); } return (m_instance); } int MyPython::Initialize() { if (m_isInitialized) return (0); m_pyHome.clear(); char *s = getenv("VAPOR3_HOME"); if (s) m_pyHome = s; if (m_pyHome.empty()) { // On windows use VAPOR_HOME/lib/python2.7; VAPOR_HOME works // on Linux and Mac m_pyHome = GetPythonDir(); } if (!m_pyHome.empty()) { #ifdef WIN32 std::string version = GetPythonVersion(); version.erase(std::remove(version.begin(), version.end(), '.'), version.end()); std::string pythonPath = m_pyHome + "\\Python" + version + ";"; pythonPath = pythonPath + m_pyHome + "\\Python" + version + "\\Lib;"; pythonPath = pythonPath + m_pyHome + "\\Python" + version + "\\Lib\\site-packages"; _putenv_s("PYTHONPATH", pythonPath.c_str()); std::wstring widestr = std::wstring(m_pyHome.begin(), m_pyHome.end()); const wchar_t *widecstr = widestr.c_str(); Py_SetPythonHome((wchar_t *)widecstr); MyBase::SetDiagMsg("Setting PYTHONHOME in the vaporgui app to %s\n", m_pyHome.c_str()); #endif } // Prevent python from attempting to write a .pyc file on disk. // const char *env = "PYTHONDONTWRITEBYTECODE=1"; char env2[256]; strcpy(env2, env); // All this trouble is to eliminate a compiler warning putenv(env2); #ifdef VAPOR3_0_0 init_signals(); #endif // This is dependent on the environmental variable PYTHONHOME which is // set in vaporgui/main.cpp Py_InitializeEx(0); #ifdef VAPOR3_0_0 if (pyIntFailed) { SetErrMsg("Failed to initialize python : Py_Initialize() Failed"); return (-1); } #endif #ifdef PYTHON_API_DEBUG printf("Vapor Linked Python Version = %s (%s)\n", GetPythonVersion().c_str(), GetPythonPath().c_str()); PyRun_SimpleString("import sys; print(f\"Vapor Runtime Python Version = {sys.version.split(' ')[0]} ({sys.prefix})\")"); #endif int rc; if (!IsRunningFromPython) { MyBase::SetErrMsg("Redirecting Python IO"); rc = rerouteSTDIO(); if (rc < 0) return rc; } if ((rc = pyImport("sys")) < 0) return rc; #ifndef DISABLE_EXTRA_PYTHON_MATH_IMPORTS if ((rc = pyImport("matplotlib")) < 0) return rc; #else fprintf(stderr, "WARNING Vapor python matplotlib import disabled\n"); #endif // Add vapor modules to search path // std::string path = Wasp::GetSharePath("python"); path = "sys.path.append('" + path + "')\n"; rc = PyRun_SimpleString(path.c_str()); if (rc < 0) { MyBase::SetErrMsg("PyRun_SimpleString() : %s", PyErr().c_str()); return (-1); } m_isInitialized = true; return (0); } int MyPython::pyImport(string lib) { std::string importMPL = string() + "try:\n" " import "+lib+"\n" "except: \n" " print('Failed to import "+lib+"', file=sys.stderr)\n" " raise\n"; int rc = PyRun_SimpleString(importMPL.c_str()); if (rc < 0) { MyBase::SetErrMsg("PyRun_SimpleString() : %s", PyErr().c_str()); } return rc; } int MyPython::rerouteSTDIO() { // Ugh. Have to define a python object to enable capturing of // stderr to a string. Python API doesn't support a version of // PyErr_Print() that fetches the error to a C++ string. Give me // a break! // std::string stdErr = "try:\n" " import sys\n" "except: \n" " print('Failed to import sys')\n" " raise\n" "class CatchErr:\n" " def __init__(self):\n" " self.value = 'VAPOR_PY: '\n" " def write(self, txt):\n" " self.value += txt\n" " def flush(self): pass\n" "catchErr = CatchErr()\n" "sys.stderr = catchErr\n" ; // Catch stderr from Python to a string. // int rc = PyRun_SimpleString(stdErr.c_str()); if (rc < 0) { MyBase::SetErrMsg("PyRun_SimpleString() : %s", PyErr().c_str()); return (-1); } std::string stdOut = "try:\n" " import sys\n" "except: \n" " print('Failed to import sys')\n" " raise\n" "class CatchOut:\n" " def __init__(self):\n" " self.value = ''\n" " def write(self, txt):\n" " self.value += txt\n" " def flush(self): pass\n" "catchOut = CatchOut()\n" "sys.stdout = catchOut\n" ; // Catch stdout from Python to a string. // rc = PyRun_SimpleString(stdOut.c_str()); if (rc < 0) { MyBase::SetErrMsg("PyRun_SimpleString() : %s", PyErr().c_str()); return (-1); } return 0; } // Fetch an error message genereated by Python API. // string MyPython::PyErr() { PyErr_Print(); PyObject *pMain = PyImport_AddModule("__main__"); PyObject *catcher = NULL; if (pMain && PyObject_HasAttrString(pMain, "catchErr")) { catcher = PyObject_GetAttrString(pMain, "catchErr"); } // If catcher is NULL the Python message will be written // to stderr. Otherwise it is writter to the catchErr object. // if (!catcher) { return ("Failed to initialize Python error catcher!!!"); } PyObject *output = PyObject_GetAttrString(catcher, "value"); const char * s = PyUnicode_AsUTF8(output); // Erase the string // PyObject *eStr = PyUnicode_FromString(""); PyObject_SetAttrString(catcher, "value", eStr); Py_DECREF(eStr); return (s ? string(s) : string()); } // Fetch an error message genereated by Python API. // string MyPython::PyOut() { PyObject *pMain = PyImport_AddModule("__main__"); PyObject *catcher = NULL; if (pMain && PyObject_HasAttrString(pMain, "catchOut")) { catcher = PyObject_GetAttrString(pMain, "catchOut"); } if (!catcher) { return (""); } PyObject *output = PyObject_GetAttrString(catcher, "value"); const char * s = PyUnicode_AsUTF8(output); // Erase the string // PyObject *eStr = PyUnicode_FromString(""); PyObject_SetAttrString(catcher, "value", eStr); Py_DECREF(eStr); return (s ? string(s) : string()); } PyObject *MyPython::CreatePyFunc(string moduleName, string funcName, string script) { PyObject *pMain = PyImport_AddModule("__main__"); if (!pMain) { return (NULL); } PyObject *pModule = PyImport_AddModule(moduleName.c_str()); if (!pModule) { return (NULL); } // Get the dictionary object from my module so I can pass this // to PyRun_String // PyObject *pLocal = PyModule_GetDict(pModule); VAssert(pLocal != NULL); // no fail PyObject *pGlobal = PyModule_GetDict(pMain); VAssert(pGlobal != NULL); // no fail PyObject *pValue = PyRun_String(script.c_str(), Py_file_input, pGlobal, pLocal); if (!pValue) { return (NULL); } Py_DECREF(pValue); PyObject *pFunc = PyObject_GetAttrString(pModule, funcName.c_str()); VAssert(pFunc != NULL); int rc = PyCallable_Check(pFunc); if (rc != 1) { // Yes, this API call returns a 1 on success. Py_DECREF(pFunc); return (NULL); } return (pFunc); } ================================================ FILE: lib/render/NavigationUtils.cpp ================================================ #include #include #include #define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH #include #include #include #include #include #include #include #include using namespace VAPoR; using glm::vec3; void NavigationUtils::SetHomeViewpoint(ControlExec *ce) { ParamsMgr * paramsMgr = ce->GetParamsMgr(); ViewpointParams *vpParams = GetActiveViewpointParams(ce); GUIStateParams * guiParams = GetGUIStateParams(ce); assert(vpParams); assert(guiParams); // Get the current model view matrix and it home // vector m = vpParams->GetModelViewMatrix(); vector c = vpParams->GetRotationCenter(); paramsMgr->BeginSaveStateGroup("Set home viewpoint"); guiParams->SetValueDoubleVec("HomeModelViewMatrix", "Modelview matrix", m); guiParams->SetValueDoubleVec("HomeRotationCenter", "Camera rotation center", c); paramsMgr->EndSaveStateGroup(); } void NavigationUtils::UseHomeViewpoint(ControlExec *ce) { GUIStateParams *guiParams = GetGUIStateParams(ce); // Get the home matrix and make it the current model view matrix // vector defaultV(16, 0.0); defaultV[0] = defaultV[5] = defaultV[10] = defaultV[15] = 1.0; vector m = guiParams->GetValueDoubleVec("HomeModelViewMatrix", defaultV); vector defaultC(3, 0.0); vector c = guiParams->GetValueDoubleVec("HomeRotationCenter", defaultC); SetAllCameras(ce, m, c); } void NavigationUtils::ViewAll(ControlExec *ce) { DataStatus *dataStatus = ce->GetDataStatus(); ParamsMgr * paramsMgr = ce->GetParamsMgr(); size_t ts = GetCurrentTimeStep(ce); CoordType minExts, maxExts; dataStatus->GetActiveExtents(paramsMgr, ts, minExts, maxExts); double maxSide = max(maxExts[2] - minExts[2], max(maxExts[1] - minExts[1], maxExts[0] - minExts[0])); // calculate the camera position: center - 1.5*dirvec*maxSide; // Position the camera 1.5*maxSide units away from the center, aimed // at the center. // // Make sure the dirvec is normalized: double dirvec[] = {0.0, 0.0, -1.0}; // vnormal(dirvec); double upvec[] = {0.0, 1.0, 0.0}; double posvec[3], center[3]; for (int i = 0; i < 3; i++) { center[i] = 0.5f * (maxExts[i] + minExts[i]); posvec[i] = center[i] - 1.5 * maxSide * dirvec[i]; } SetAllCameras(ce, posvec, dirvec, upvec, center); } void NavigationUtils::AlignView(ControlExec *ce, int axis) { // This fixes a bug in this legacy function where the up dir is occationally wrong if (axis != 3 && axis != 1) AlignView(ce, 3); float axes[3][3] = {{1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {0.f, 0.f, 1.f}}; double dirvec[3] = {0.0, 0.0, 0.0}; double upvec[3] = {0.0, 1.0, 0.0}; (void)(upvec); ViewpointParams *vpParams = GetActiveViewpointParams(ce); assert(vpParams); if (!vpParams) return; double m[16], curPosVec[3], curViewDir[3], curUpVec[3], curCenter[3]; vpParams->GetModelViewMatrix(m); bool status = vpParams->ReconstructCamera(m, curPosVec, curUpVec, curViewDir); vpParams->GetRotationCenter(curCenter); if (!status) return; #define V3S(v) (string("[")+to_string(v[0])+","+to_string(v[1])+","+to_string(v[2])+"]").c_str() if (axis == 1) { // Special case to align to closest axis. // determine the closest view direction and up vector to the current viewpoint. // Check the dot product with all axes float maxVDot = -1.f; int bestVDir = 0; float maxUDot = -1.f; int bestUDir = 0; for (int i = 0; i < 3; i++) { double dotVProd = 0.; double dotUProd = 0.; for (int j = 0; j < 3; j++) { dotUProd += (axes[i][j] * curViewDir[j]); dotVProd += (axes[i][j] * curUpVec[j]); } if (abs(dotVProd) > maxVDot) { maxVDot = abs(dotVProd); bestVDir = i + 1; if (dotVProd < 0.f) bestVDir = -i - 1; } if (abs(dotUProd) > maxUDot) { maxUDot = abs(dotUProd); bestUDir = i + 1; if (dotUProd < 0.f) bestUDir = -i - 1; } } for (int i = 0; i < 3; i++) { if (bestUDir > 0) dirvec[i] = axes[bestUDir - 1][i]; else dirvec[i] = -axes[-1 - bestUDir][i]; if (bestVDir > 0) upvec[i] = axes[bestVDir - 1][i]; else upvec[i] = -axes[-1 - bestVDir][i]; } } else { // establish view direction, up vector: switch (axis) { case (2): dirvec[0] = 1.f; break; case (3): dirvec[1] = 1.f; upvec[1] = 0.f; upvec[0] = 1.f; break; case (4): dirvec[2] = 1.f; break; case (5): dirvec[0] = -1.f; break; case (6): dirvec[1] = -1.f; upvec[1] = 0.f; upvec[0] = 1.f; break; case (7): dirvec[2] = -1.f; break; default: return; } } vector stretch = vpParams->GetStretchFactors(); // Determine distance from center to camera, in stretched coordinates // determine the relative position in stretched coords: vsub(curPosVec, curCenter, curPosVec); float viewDist = vlength(curPosVec); // Position the camera the same distance from the center but down the -axis direction for (int i = 0; i < 3; i++) { dirvec[i] = dirvec[i] * viewDist; curPosVec[i] = (curCenter[i] - dirvec[i]); } SetAllCameras(ce, curPosVec, dirvec, upvec, curCenter); } void NavigationUtils::SetAllCameras(ControlExec *ce, const double position[3], const double direction[3], const double up[3], const double origin[3]) { Trackball trackball; bool ok = trackball.setFromFrame(position, direction, up, origin, true); if (!ok) { MyBase::SetErrMsg("Invalid camera settings"); return; } trackball.TrackballSetMatrix(); const double *m = trackball.GetModelViewMatrix(); SetAllCameras(ce, m, origin); } void NavigationUtils::SetAllCameras(ControlExec *ce, const double position[3], const double direction[3], const double up[3]) { ViewpointParams *vpParams = GetActiveViewpointParams(ce); assert(vpParams); if (!vpParams) return; double curCenter[3]; vpParams->GetRotationCenter(curCenter); SetAllCameras(ce, position, direction, up, curCenter); } void NavigationUtils::SetAllCameras(ControlExec *ce, const vector &position, const vector &direction, const vector &up, const vector &origin) { SetAllCameras(ce, position.data(), direction.data(), up.data(), origin.data()); } void NavigationUtils::SetAllCameras(ControlExec *ce, const vector &position, const vector &direction, const vector &up) { SetAllCameras(ce, position.data(), direction.data(), up.data()); } void NavigationUtils::SetAllCameras(ControlExec *ce, const double matrix[16], const double origin[3]) { ParamsMgr *pm = ce->GetParamsMgr(); auto vizNames = pm->GetVisualizerNames(); pm->BeginSaveStateGroup("Set Camera"); for (auto &viz : vizNames) { ViewpointParams *vp = pm->GetViewpointParams(viz); vp->SetModelViewMatrix(matrix); vp->SetRotationCenter(origin); } pm->EndSaveStateGroup(); } void NavigationUtils::SetAllCameras(ControlExec *ce, const vector &m, const vector &origin) { assert(m.size() == 16); SetAllCameras(ce, m.data(), origin.data()); } void NavigationUtils::SetAllCameras(ControlExec *ce, const Trackball &trackball) { double center[3]; trackball.GetCenter(center); const double *m = trackball.GetModelViewMatrix(); NavigationUtils::SetAllCameras(ce, m, center); } void NavigationUtils::ConfigureTrackball(ControlExec *ce, Trackball &trackball) { vector pos, dir, up, tgt; GetCameraProperties(ce, &pos, &dir, &up, &tgt); trackball.setFromFrame(pos, dir, up, tgt, true); if (ce->GetDataNames().size() == 0) return; DataStatus *dataStatus = ce->GetDataStatus(); ParamsMgr *paramsMgr = ce->GetParamsMgr(); size_t ts = GetAnimationParams(ce)->GetCurrentTimestep(); VAPoR::CoordType minExts, maxExts; dataStatus->GetActiveExtents(paramsMgr, ts, minExts, maxExts); double scale[3]; scale[0] = scale[1] = scale[2] = max(maxExts[0] - minExts[0], (maxExts[1] - minExts[1])); trackball.SetScale(scale); } void NavigationUtils::LookAt(ControlExec *ce, const vector &position, const vector &target, const vector &up) { vec3 pos(position[0], position[1], position[2]); vec3 tar(target[0], target[1], target[2]); vec3 dir = glm::normalize(tar - pos); vector direction = {dir.x, dir.y, dir.z}; SetAllCameras(ce, position, direction, up, target); } void NavigationUtils::SetTimestep(ControlExec *ce, size_t ts) { AnimationParams *aParams = GetAnimationParams(ce); size_t ots = aParams->GetCurrentTimestep(); propagateTimestep(ce, ts); handleMovingDomainAdjustments(ce, ots, ts); } void NavigationUtils::propagateTimestep(ControlExec *ce, size_t ts) { DataStatus *dataStatus = ce->GetDataStatus(); ParamsMgr * paramsMgr = ce->GetParamsMgr(); paramsMgr->BeginSaveStateGroup("Set Timestep " + std::to_string(ts)); // First set current *global* timestep in AnimationParams // AnimationParams *aParams = GetAnimationParams(ce); aParams->SetCurrentTimestep(ts); // Now set *local* time step for each RenderParams instance // vector winNames = paramsMgr->GetVisualizerNames(); for (int i = 0; i < winNames.size(); i++) { vector dataSetNames = dataStatus->GetDataMgrNames(); for (int j = 0; j < dataSetNames.size(); j++) { vector rParams; paramsMgr->GetRenderParams(winNames[i], dataSetNames[j], rParams); if (!rParams.size()) continue; size_t local_ts = dataStatus->MapGlobalToLocalTimeStep(dataSetNames[j], ts); for (int k = 0; k < rParams.size(); k++) { RenderParams *rp = rParams[k]; rp->SetCurrentTimestep(local_ts); // If variable was not initialzed but now is, reset the TF mapping range std::string varNames[2] = {rp->GetVariableName(), rp->GetActualColorMapVariableName()}; for (int l = 0; l < 2; l++) { if (varNames[i].empty()) continue; MapperFunction *tf = rp->GetMapperFunc(varNames[i]); vector range = tf->getMinMaxMapValue(); if (abs(range[1] - range[0]) > FLT_EPSILON * max(abs(range[0]), abs(range[1]))) continue; DataMgr *dm = dataStatus->GetDataMgr(dataSetNames[j]); if (!dm) continue; if (!dm->VariableExists(local_ts, varNames[i], 0, 0)) continue; if (dm->GetDataRange(local_ts, varNames[i], 0, 0, range) < 0) continue; bool SSE = paramsMgr->GetSaveStateEnabled(); paramsMgr->SetSaveStateEnabled(false); tf->setMinMaxMapValue(range[0], range[1]); paramsMgr->SetSaveStateEnabled(SSE); } } } } paramsMgr->EndSaveStateGroup(); } static vector DoubleArr3ToVector(double a[3]) { vector v(3); v[0] = a[0]; v[1] = a[1]; v[2] = a[2]; return v; } void NavigationUtils::GetCameraProperties(ControlExec *ce, vector *position, vector *direction, vector *up, vector *target) { position->resize(3, 0); direction->resize(3, 0); up->resize(3, 0); target->resize(3, 0); ViewpointParams *vpParams = GetActiveViewpointParams(ce); assert(vpParams); if (!vpParams) return; double m[16], posD[3] = {0}, dirD[3] = {0}, upD[3] = {0}, targetD[3] = {0}; vpParams->GetModelViewMatrix(m); vpParams->ReconstructCamera(m, posD, upD, dirD); vpParams->GetRotationCenter(targetD); *position = DoubleArr3ToVector(posD); *direction = DoubleArr3ToVector(dirD); *up = DoubleArr3ToVector(upD); *target = DoubleArr3ToVector(targetD); } vector NavigationUtils::GetCameraPosition(ControlExec *ce) { vector pos, dir, up, tgt; GetCameraProperties(ce, &pos, &dir, &up, &tgt); return pos; } vector NavigationUtils::GetCameraDirection(ControlExec *ce) { vector pos, dir, up, tgt; GetCameraProperties(ce, &pos, &dir, &up, &tgt); return dir; } vector NavigationUtils::GetCameraUp(ControlExec *ce) { vector pos, dir, up, tgt; GetCameraProperties(ce, &pos, &dir, &up, &tgt); return up; } vector NavigationUtils::GetCameraTarget(ControlExec *ce) { vector pos, dir, up, tgt; GetCameraProperties(ce, &pos, &dir, &up, &tgt); return tgt; } void NavigationUtils::SetCameraPosition(ControlExec *ce, const vector &v) { vector pos, dir, up, tgt; GetCameraProperties(ce, &pos, &dir, &up, &tgt); SetAllCameras(ce, v, dir, up, tgt); } void NavigationUtils::SetCameraDirection(ControlExec *ce, const vector &v) { vector pos, dir, up, tgt; GetCameraProperties(ce, &pos, &dir, &up, &tgt); SetAllCameras(ce, pos, v, up, tgt); } void NavigationUtils::SetCameraUp(ControlExec *ce, const vector &v) { vector pos, dir, up, tgt; GetCameraProperties(ce, &pos, &dir, &up, &tgt); SetAllCameras(ce, pos, dir, v, tgt); } void NavigationUtils::SetCameraTarget(ControlExec *ce, const vector &v) { vector pos, dir, up, tgt; GetCameraProperties(ce, &pos, &dir, &up, &tgt); SetAllCameras(ce, pos, dir, up, v); } long NavigationUtils::GetCurrentTimeStep(VAPoR::ControlExec *ce) { AnimationParams *aParams = (AnimationParams *)ce->GetParamsMgr()->GetParams(AnimationParams::GetClassType()); VAssert(aParams); return aParams->GetCurrentTimestep(); } VAPoR::ViewpointParams *NavigationUtils::GetActiveViewpointParams(ControlExec *ce) { ParamsMgr * pm = ce->GetParamsMgr(); auto activeViz = GetGUIStateParams(ce)->GetActiveVizName(); ViewpointParams *vp = pm->GetViewpointParams(activeViz); return vp; } GUIStateParams *NavigationUtils::GetGUIStateParams(ControlExec *ce) { ParamsMgr *pm = ce->GetParamsMgr(); return ((GUIStateParams *)pm->GetParams(GUIStateParams::GetClassType())); } AnimationParams *NavigationUtils::GetAnimationParams(ControlExec *ce) { return ((AnimationParams *)ce->GetParamsMgr()->GetParams(AnimationParams::GetClassType())); } static vec3 CoordTypeToVec3(const CoordType &c) { return vec3(c[0], c[1], c[2]); } static CoordType Vec3ToCoordType(const vec3 &c) { return CoordType {c[0], c[1], c[2]}; } void NavigationUtils::handleMovingDomainAdjustments(ControlExec *ce, size_t ts_from, size_t ts_to) { auto paramsMgr = ce->GetParamsMgr(); auto guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType()); bool trackCamera = guiParams->GetValueLong(GUIStateParams::MovingDomainTrackCameraTag, false); bool trackDomain = guiParams->GetValueLong(GUIStateParams::MovingDomainTrackRenderRegionsTag, false); if (trackCamera) movingDomainTrackCamera(ce, ts_from, ts_to); if (trackDomain) movingDomainTrackRenderRegions(ce, ts_from, ts_to); if (trackDomain) movingDomainTrackParticleRenderRegions(ce, ts_from, ts_to); } std::tuple NavigationUtils::getDomainExtentsAtTimestep(ControlExec *ce, const std::string &dataset, size_t ts) { auto paramsMgr = ce->GetParamsMgr(); auto dataStatus = ce->GetDataStatus(); auto guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType()); string viz = guiParams->GetActiveVizName(); CoordType minExts_, maxExts_; dataStatus->GetActiveExtents(paramsMgr, viz, dataset, ts, minExts_, maxExts_); vec3 minExts = CoordTypeToVec3(minExts_); vec3 maxExts = CoordTypeToVec3(maxExts_); return std::make_tuple(minExts, maxExts); } glm::vec3 NavigationUtils::getDomainMovementBetweenTimesteps(ControlExec *ce, string dataset, size_t from, size_t to) { vec3 oldMinExts, oldMaxExts, newMinExts, newMaxExts; std::tie(oldMinExts, oldMaxExts) = getDomainExtentsAtTimestep(ce, dataset, from); std::tie(newMinExts, newMaxExts) = getDomainExtentsAtTimestep(ce, dataset, to); vec3 oldDomainCenter = (oldMinExts+oldMaxExts)/2.f; vec3 newDomainCenter = (newMinExts+newMaxExts)/2.f; vec3 domainMove = newDomainCenter - oldDomainCenter; return domainMove; } std::tuple NavigationUtils::getRendererExtents(const RenderParams *rp) { CoordType minExts_, maxExts_; rp->GetBox()->GetExtents(minExts_, maxExts_); return std::make_tuple(CoordTypeToVec3(minExts_), CoordTypeToVec3(maxExts_)); } void NavigationUtils::setRendererExtents(const RenderParams *rp, const glm::vec3 &minExts, const glm::vec3 &maxExts) { rp->GetBox()->SetExtents(Vec3ToCoordType(minExts), Vec3ToCoordType(maxExts)); } void NavigationUtils::movingDomainTrackCamera(ControlExec *ce, size_t from, size_t to) { auto paramsMgr = ce->GetParamsMgr(); auto dataStatus = ce->GetDataStatus(); GUIStateParams *guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType()); string viz = guiParams->GetActiveVizName(); auto viewpointParams = paramsMgr->GetViewpointParams(guiParams->GetActiveVizName()); auto datasets = guiParams->GetOpenDataSetNames(); vec3 domainMoveSum = vec3(0); int nDomainsMoved = 0; for (const auto &dataset : datasets) { if (!dataStatus->GetDataMgr(dataset)->HasMovingDomain()) continue; auto domainMove = getDomainMovementBetweenTimesteps(ce, dataset, from, to); domainMoveSum += domainMove; nDomainsMoved++; } if (nDomainsMoved) { vec3 domainMove = domainMoveSum / (float)nDomainsMoved; double camMat[16], camPos[3], camDir[3], camUp[3]; viewpointParams->GetModelViewMatrix(camMat); viewpointParams->ReconstructCamera(camMat, camPos, camUp, camDir); for (int i = 0; i < 3; i++) camPos[i] += domainMove[i]; NavigationUtils::SetAllCameras(ce, camPos, camDir, camUp); } } void NavigationUtils::movingDomainTrackRenderRegions(ControlExec *ce, size_t from, size_t to) { auto paramsMgr = ce->GetParamsMgr(); auto dataStatus = ce->GetDataStatus(); GUIStateParams *guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType()); string viz = guiParams->GetActiveVizName(); auto datasets = guiParams->GetOpenDataSetNames(); for (const auto &dataset : datasets) { if (!dataStatus->GetDataMgr(dataset)->HasMovingDomain()) continue; auto domainMove = getDomainMovementBetweenTimesteps(ce, dataset, from, to); vector renderers; paramsMgr->GetRenderParamNames(viz, dataset, renderers); for (const auto &renderer : renderers) { string _1, _2, className; paramsMgr->RenderParamsLookup(renderer, _1, _2, className); if (className == ParticleParams::GetClassType()) continue; RenderParams *rp = paramsMgr->GetRenderParams(viz, dataset, className, renderer); vec3 minExts, maxExts; std::tie(minExts, maxExts) = getRendererExtents(rp); setRendererExtents(rp, domainMove+minExts, domainMove+maxExts); } } } void NavigationUtils::movingDomainTrackParticleRenderRegions(ControlExec *ce, size_t from, size_t to) { auto paramsMgr = ce->GetParamsMgr(); GUIStateParams *guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType()); string viz = guiParams->GetActiveVizName(); auto datasets = guiParams->GetOpenDataSetNames(); for (const auto &dataset : datasets) { vector renderers; paramsMgr->GetRenderParamNames(viz, dataset, renderers); for (const auto &renderer : renderers) { string _1, _2, className; paramsMgr->RenderParamsLookup(renderer, _1, _2, className); if (className != ParticleParams::GetClassType()) continue; RenderParams *rp = paramsMgr->GetRenderParams(viz, dataset, className, renderer); vec3 dataExtentsFromMin, dataExtentsFromMax, dataExtentsToMin, dataExtentsToMax, rendererExtentsFromMin, rendererExtentsFromMax; std::tie(dataExtentsFromMin, dataExtentsFromMax) = getDomainExtentsAtTimestep(ce, dataset, from); std::tie(dataExtentsToMin, dataExtentsToMax) = getDomainExtentsAtTimestep(ce, dataset, to); std::tie(rendererExtentsFromMin, rendererExtentsFromMax) = getRendererExtents(rp); vec3 rendererExtentsFromMinNorm = (rendererExtentsFromMin - dataExtentsFromMin) / (dataExtentsFromMax - dataExtentsFromMin); vec3 rendererExtentsFromMaxNorm = (rendererExtentsFromMax - dataExtentsFromMin) / (dataExtentsFromMax - dataExtentsFromMin); vec3 rendererExtentsToMin = (dataExtentsToMax - dataExtentsToMin) * rendererExtentsFromMinNorm + dataExtentsToMin; vec3 rendererExtentsToMax = (dataExtentsToMax - dataExtentsToMin) * rendererExtentsFromMaxNorm + dataExtentsToMin; setRendererExtents(rp, rendererExtentsToMin, rendererExtentsToMax); } } } // This is some code that someone decided is worth keeping for future reference. // It allegedly worked at some point. // I don't want to have to write any camera code without refactoring the entire // system so I am leaving it here in case the functionality is needed again. #ifdef VAPOR3_0_0_ALPHA void NavigationEventRouter::CenterSubRegion() { cout << "NavigationEventRouter::CenterSubRegion not implemented" << endl; ViewpointParams *vpParams = _getActiveParams(); if (!vpParams) return; // Find the largest of the dimensions of the current region, projected orthogonal to view // direction: // Make sure the dirvec is normalized: double dirvec[3]; vpParams->GetCameraViewDir(dirvec); double upvec[3]; vpParams->GetCameraUpVec(upvec); vnormal(dirvec); float regionSideVector[3], compVec[3], projvec[3]; float maxProj = -1.f; vector stretch = vpParams->GetStretchFactors(); vector minExts, maxExts; rParams->GetBox()->GetExtents(minExts, maxExts); for (int i = 0; i < 3; i++) { // Make a vector that points along side(i) of subregion, for (int j = 0; j < 3; j++) { regionSideVector[j] = 0.f; if (j == i) { regionSideVector[j] = maxExts[j] - minExts[j]; } } // Now find its component orthogonal to view direction: double dotprod = 0.; for (int j = 0; j < 3; j++) dotprod += (dirvec[j] * regionSideVector[j]); for (int j = 0; j < 3; j++) compVec[j] = dotprod * dirvec[j]; // projvec is projection orthogonal to view dir: vsub(regionSideVector, compVec, projvec); float proj = vlength(projvec); if (proj > maxProj) maxProj = proj; } // calculate the camera position: center - 1.5*dirvec*maxSide; // Position the camera 1.5*maxSide units away from the center, aimed // at the center double posvec[3], center[3]; vector rotCtr; for (int i = 0; i < 3; i++) { center[i] = 0.5 * (minExts[i] + maxExts[i]); posvec[i] = center[i] - (1.5 * maxProj * dirvec[i] / stretch[i]); } _setViewpointParams(center, posvec, dirvec, upvec); } #endif #ifdef VAPOR3_0_0_ALPHA // Reset the center of view. Leave the camera where it is void NavigationEventRouter::SetCenter(const double *coords) { double vdir[3]; vector nvdir; ViewpointParams *vpParams = _getActiveParams(); if (!vpParams) return; vector stretch = _dataStatus->getStretchFactors(); // Determine the new viewDir in stretched world coords vcopy(coords, vdir); // Stretch the new view center coords for (int i = 0; i < 3; i++) vdir[i] *= stretch[i]; double campos[3]; vpParams->getStretchedCamPosLocal(campos); vsub(vdir, campos, vdir); vnormal(vdir); vector vvdir; #ifdef VAPOR3_0_0_ALPHA Command *cmd = Command::CaptureStart(vpParams, "re-center view"); #endif for (int i = 0; i < 3; i++) vvdir.push_back(vdir[i]); vpParams->setViewDir(vvdir); vector rotCtr; for (int i = 0; i < 3; i++) { rotCtr.push_back(coords[i]); } vpParams->setRotationCenterLocal(rotCtr); #ifdef VAPOR3_0_0_ALPHA Command::CaptureEnd(cmd, vpParams); #endif updateTab(); } #endif ================================================ FILE: lib/render/OSPRay.cpp ================================================ #ifdef WIN32 #define _USE_MATH_DEFINES #include #endif #include #include #include using namespace VOSP; #ifdef BUILD_OSPRAY static int _initialized = false; void ospErrorCallback(OSPError error, const char *msg) { fprintf(stderr, "OSP error "); switch (error) { #define STRINGIFY(x) \ case x: fprintf(stderr, #x); break; STRINGIFY(OSP_NO_ERROR) STRINGIFY(OSP_UNKNOWN_ERROR) STRINGIFY(OSP_INVALID_ARGUMENT) STRINGIFY(OSP_INVALID_OPERATION) STRINGIFY(OSP_OUT_OF_MEMORY) STRINGIFY(OSP_UNSUPPORTED_CPU) STRINGIFY(OSP_VERSION_MISMATCH) #undef STRINGIFY } fprintf(stderr, ": %s\n", msg); // exit(1); } #endif int VOSP::Initialize(int *argc, char **argv) { #ifdef BUILD_OSPRAY if (_initialized) return 0; OSPError init_error = ospInit(argc, (const char **)argv); if (init_error != OSP_NO_ERROR) return init_error; // Hide deprecated warning. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" // If this is not set, OSPRay will crash upon shutdown ospDeviceSetErrorFunc(ospGetCurrentDevice(), ospErrorCallback); #pragma GCC diagnostic pop _initialized = true; return 0; #else return 0; #endif } int VOSP::Shutdown() { // ospShutdown(); // Broken. Do not use. return 0; } std::string VOSP::Version() { #ifdef BUILD_OSPRAY long major = ospDeviceGetProperty(ospGetCurrentDevice(), OSP_DEVICE_VERSION_MAJOR); long minor = ospDeviceGetProperty(ospGetCurrentDevice(), OSP_DEVICE_VERSION_MINOR); long patch = ospDeviceGetProperty(ospGetCurrentDevice(), OSP_DEVICE_VERSION_PATCH); return std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(patch); #else return "0.0.0"; #endif } bool VOSP::IsVersionAtLeast(int testMajor, int testMinor) { #ifdef BUILD_OSPRAY long major = ospDeviceGetProperty(ospGetCurrentDevice(), OSP_DEVICE_VERSION_MAJOR); long minor = ospDeviceGetProperty(ospGetCurrentDevice(), OSP_DEVICE_VERSION_MINOR); if (major > testMajor || (major == testMajor && minor >= testMinor)) return true; return false; #else return false; #endif } #ifdef BUILD_OSPRAY OSPData VOSP::NewCopiedData(const void *data, OSPDataType type, uint64_t numItems1, uint64_t numItems2, uint64_t numItems3) { OSPData shared = ospNewSharedData(data, type, numItems1, 0, numItems2, 0, numItems3, 0); ospCommit(shared); OSPData opaque = ospNewData(type, numItems1, numItems2, numItems3); ospCommit(opaque); ospCopyData(shared, opaque); ospCommit(opaque); ospRelease(shared); return opaque; } OSPTexture VOSP::OSPDepthFromGLPerspective(float fovy, float aspect, float zNear, float zFar, glm::vec3 cameraDir, glm::vec3 cameraUp, const float *glDepthBuffer, int width, int height) { float *ospDepth = new float[width * height]; // transform OpenGL depth to linear depth for (size_t i = 0; i < width * height; i++) { const double z_n = 2.0 * glDepthBuffer[i] - 1.0; ospDepth[i] = 2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear)); } // transform from orthogonal Z depth to ray distance t glm::vec3 dir_du = normalize(cross(cameraDir, cameraUp)); glm::vec3 dir_dv = normalize(cross(dir_du, cameraDir)); const float imagePlaneSizeY = 2.f * tanf(fovy / 2.f * M_PI / 180.f); const float imagePlaneSizeX = imagePlaneSizeY * aspect; dir_du *= imagePlaneSizeX; dir_dv *= imagePlaneSizeY; const glm::vec3 dir_00 = cameraDir - .5f * dir_du - .5f * dir_dv; for (size_t j = 0; j < height; j++) { for (size_t i = 0; i < width; i++) { const glm::vec3 dir_ij = normalize(dir_00 + float(i) / float(width - 1) * dir_du + float(j) / float(height - 1) * dir_dv); const float t = ospDepth[j * width + i] / dot(cameraDir, dir_ij); ospDepth[j * width + i] = t; } } OSPTexture depthTexture = ospNewTexture("texture2d"); ospSetInt(depthTexture, "format", OSP_TEXTURE_R32F); ospSetInt(depthTexture, "filter", OSP_TEXTURE_FILTER_NEAREST); OSPData data = VOSP::NewCopiedData(ospDepth, OSP_FLOAT, width, height); ospCommit(data); ospSetObject(depthTexture, "data", data); ospRelease(data); delete[] ospDepth; ospCommit(depthTexture); return depthTexture; } // triangle mesh data namespace TriData { float translation[] = {0, 0, 0}; float vertex[] = {-1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f}; float color[] = {0.9f, 0.5f, 0.5f, 1.0f, 0.8f, 0.8f, 0.8f, 1.0f, 0.8f, 0.8f, 0.8f, 1.0f, 0.5f, 0.9f, 0.5f, 1.0f}; int32_t index[] = {0, 1, 2, 1, 2, 3}; } // namespace TriData OSPGeometricModel Test::LoadTriangle(glm::vec3 scale, const std::string &rendererType) { // Translate Triangle float pos[4 * 3]; for (int i = 0; i < 4 * 3; i++) { pos[i] = TriData::vertex[i] * scale[i % 3] + TriData::translation[i % 3]; } // create and setup model and mesh OSPGeometry mesh = ospNewGeometry("mesh"); OSPData data = NewCopiedData(pos, OSP_VEC3F, 4); // alternatively with an OSPRay managed OSPData // OSPData managed = ospNewData1D(OSP_VEC3F, 4); // ospCopyData1D(data, managed, 0); ospCommit(data); ospSetObject(mesh, "vertex.position", data); ospRelease(data); // we are done using this handle data = ospNewSharedData1D(TriData::color, OSP_VEC4F, 4); ospCommit(data); ospSetObject(mesh, "vertex.color", data); ospRelease(data); data = ospNewSharedData1D(TriData::index, OSP_VEC3UI, 2); ospCommit(data); ospSetObject(mesh, "index", data); ospRelease(data); ospCommit(mesh); OSPMaterial mat = ospNewMaterial(rendererType.c_str(), "obj"); ospCommit(mat); // put the mesh into a model OSPGeometricModel model = ospNewGeometricModel(mesh); ospSetObject(model, "material", mat); ospCommit(model); ospRelease(mesh); ospRelease(mat); return model; } #endif ================================================ FILE: lib/render/PNGWriter.cpp ================================================ #include "vapor/PNGWriter.h" #include "vapor/VAssert.h" #define USE_PYTHON_PNG 1 #if USE_PYTHON_PNG #include "vapor/MyPython.h" #else #include #endif using namespace VAPoR; using namespace Wasp; REGISTER_IMAGEWRITER(PNGWriter); std::vector PNGWriter::GetFileExtensions() { return {"png"}; } PNGWriter::PNGWriter(const string &path) : ImageWriter(path) {} int PNGWriter::Write(const unsigned char *buffer, const unsigned int width, const unsigned int height) { #if USE_PYTHON_PNG VAssert(format == Format::RGB); PyObject *pName, *pModule, *pFunc, *pArgs, *pValue; int rc = Wasp::MyPython::Instance()->Initialize(); if (rc < 0) { MyBase::SetErrMsg("Failed to initialize python : %s", MyPython::Instance()->PyErr().c_str()); return (-1); } pName = PyUnicode_FromString("imagewriter"); pModule = PyImport_Import(pName); if (pModule == NULL) { PyErr_Print(); MyBase::SetErrMsg("pModule (drawpng) NULL : %s", MyPython::Instance()->PyErr().c_str()); return -1; } pFunc = PyObject_GetAttrString(pModule, "drawpng"); if (pFunc && PyCallable_Check(pFunc)) { pArgs = PyTuple_New(4); // The 1st argument: output filename pValue = PyUnicode_FromString(path.c_str()); PyTuple_SetItem(pArgs, 0, pValue); // The 2nd argument: width pValue = PyLong_FromLong((long)width); PyTuple_SetItem(pArgs, 1, pValue); // The 3rd argument: height pValue = PyLong_FromLong((long)height); PyTuple_SetItem(pArgs, 2, pValue); // The 4th argument: RGB buffer long nChars = width * height * 3; PyObject *pListOfChars = PyList_New(nChars); VAssert(pListOfChars); for (long i = 0; i < nChars; i++) { int rt = PyList_SetItem(pListOfChars, i, PyLong_FromLong((long)buffer[i])); VAssert(rt == 0); } PyTuple_SetItem(pArgs, 3, pListOfChars); // Call the python routine pValue = PyObject_CallObject(pFunc, pArgs); if (pValue == NULL) { PyErr_Print(); MyBase::SetErrMsg("pFunc (drawpng) failed to execute : %s", MyPython::Instance()->PyErr().c_str()); return -1; } } else { PyErr_Print(); MyBase::SetErrMsg("pFunc (drawpng) NULL : %s", MyPython::Instance()->PyErr().c_str()); return -1; } Py_XDECREF(pName); Py_XDECREF(pArgs); Py_XDECREF(pValue); Py_XDECREF(pFunc); Py_XDECREF(pModule); return 0; #else int code = 0; FILE * fp = NULL; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_bytep row = NULL; fp = fopen(file, "wb"); if (!fp) return -1; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) VAssert(0); info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) VAssert(0); png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); #error Functionality Not Finished png_write_end(png_ptr, NULL); if (fp) fclose(fp); if (info_ptr) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); if (png_ptr) png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return 0; #endif } ================================================ FILE: lib/render/ParticleRenderer.cpp ================================================ //************************************************************************ // * // Copyright (C) 2018 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: ParticleRenderer.cpp // // Author: Stas Jaroszynski // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: March 2018 // // Description: // Implementation of ParticleRenderer // #include #include #include #include // Must be included first!!! #include #include #include #include #include #include #include #include #include #include "vapor/ShaderManager.h" #include "vapor/debug.h" #include #include #include "vapor/GLManager.h" #include using namespace VAPoR; #pragma pack(push, 4) // struct ParticleRenderer::VertexData { // float x, y, z; // float v; //}; #pragma pack(pop) using glm::vec3; static inline vec3 CoordTypeToVec3(const CoordType &c) { return vec3(c[0], c[1], c[2]); } static RendererRegistrar registrar(ParticleRenderer::GetClassType(), ParticleParams::GetClassType()); ParticleRenderer::ParticleRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr) : Renderer(pm, winName, dataSetName, ParticleParams::GetClassType(), ParticleRenderer::GetClassType(), instName, dataMgr), _colorMapTexOffset(0) { _cacheParams.ts=0; _cacheParams.rLevel=0; _cacheParams.cLevel=0; _cacheParams.stride=0; _cacheParams.radius=8.0; _cacheParams.direction=false; } ParticleRenderer::~ParticleRenderer() { if (_vertexArrayId) { glDeleteVertexArrays(1, &_vertexArrayId); _vertexArrayId = 0; } if (_vertexBufferId) { glDeleteBuffers(1, &_vertexBufferId); _vertexBufferId = 0; } if (_colorMapTexId) { glDeleteTextures(1, &_colorMapTexId); _colorMapTexId = 0; } } int ParticleRenderer::_paintGL(bool) { #ifdef DEBUG auto start = chrono::steady_clock::now(); #endif glDepthMask(true); glEnable(GL_DEPTH_TEST); bool regenerateParticles = false; bool recomputeBaseRadius = false; if (_particleBaseSizeIsDirty()) recomputeBaseRadius = true; if (_particleCacheIsDirty()) { _resetParticleCache(); regenerateParticles = true; } if (_colormapCacheIsDirty()) { _resetColormapCache(); _prepareColormap(); } Grid* grid = nullptr; std::vector vecGrids; int rc = _getGrids(grid, vecGrids); if (rc != 0) { SetErrMsg("Could not get scalar and field grids for ParticleRenderer"); return rc; } bool renderLegacy = GetActiveParams()->GetValueLong(ParticleParams::RenderLegacyTag, false); if (renderLegacy) { _renderParticlesLegacy(grid, vecGrids); _cacheParams.varName = ""; } else { if (regenerateParticles) _generateTextureData(grid, vecGrids); if (recomputeBaseRadius) _computeBaseRadius(); _renderParticlesHelper(); } _dataMgr->UnlockGrid(grid); delete grid; for (auto g : vecGrids) { _dataMgr->UnlockGrid(g); delete g; } #ifdef DEBUG auto end = chrono::steady_clock::now(); cout << "Glyph time in milliseconds: " << chrono::duration_cast(end - start).count() << " ms" << endl; #endif return 0; } int ParticleRenderer::_initializeGL() { glGenVertexArrays(1, &_vertexArrayId); glGenBuffers(1, &_vertexBufferId); /* Generate and configure 1D texture: _colorMapTexId */ glGenTextures(1, &_colorMapTexId); glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset); glBindTexture(GL_TEXTURE_1D, _colorMapTexId); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glBindTexture(GL_TEXTURE_1D, 0); glGenVertexArrays(1, &_VAO); glGenBuffers(1, &_VBO); assert(_VAO); assert(_VBO); return 0; } static void SetupParticlePointGL(const int VAO, const int VBO, const bool dynamicSize) { glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); int elSize = sizeof(glm::vec4); if (dynamicSize) elSize += sizeof(float); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, elSize, NULL); glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, elSize, (void *)sizeof(glm::vec3)); if (dynamicSize) glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, elSize, (void *)sizeof(glm::vec4)); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); if (dynamicSize) glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } static void SetupParticleDirectionGL(const int VAO, const int VBO, const bool dynamicSize) { glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); int elSize = sizeof(float)*7; if (dynamicSize) elSize += sizeof(float); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, elSize, NULL); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, elSize, (void *)sizeof(glm::vec3)); glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, elSize, (void *)(2*sizeof(glm::vec3))); if (dynamicSize) glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, elSize, (void *)(sizeof(float)*7)); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); if (dynamicSize) glEnableVertexAttribArray(3); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } bool ParticleRenderer::_particleBaseSizeIsDirty() const { auto p = GetActiveParams(); if (p->GetValueLong(ParticleParams::RecalculateRadiusBaseRequestTag, false)) { p->SetValueLong(ParticleParams::RecalculateRadiusBaseRequestTag, "", false); return true; } if (_cacheParams.varName != p->GetVariableName()) return true; if (_cacheParams.radiusVarName != p->GetValueString( ParticleParams::RenderRadiusVariableTag, "")) return true; if (_cacheParams.stride != p->GetValueLong( ParticleParams::StrideTag, 1)) return true; return false; } bool ParticleRenderer::_particleCacheIsDirty() const { auto p = GetActiveParams(); if (_cacheParams.ts != p->GetCurrentTimestep() ) return true; if (_cacheParams.rLevel != p->GetRefinementLevel() ) return true; if (_cacheParams.cLevel != p->GetCompressionLevel() ) return true; VAPoR::CoordType min, max; p->GetBox()->GetExtents(min, max); if (_cacheParams.boxMin != min) return true; if (_cacheParams.boxMax != max) return true; if (_cacheParams.stride != p->GetValueLong( ParticleParams::StrideTag, 1)) return true; if (_cacheParams.varName != p->GetVariableName() ) return true; if (_cacheParams.fieldVars != p->GetFieldVariableNames() ) return true; if (_cacheParams.radiusVarName != p->GetValueString( ParticleParams::RenderRadiusVariableTag, "")) return true; if (_cacheParams.direction != (bool)p->GetValueLong( ParticleParams::ShowDirectionTag, false)) return true; return false; } void ParticleRenderer::_resetParticleCache() { auto p = GetActiveParams(); _cacheParams.ts = p->GetCurrentTimestep(); _cacheParams.rLevel = p->GetRefinementLevel(); _cacheParams.cLevel = p->GetCompressionLevel(); VAPoR::CoordType min, max; p->GetBox()->GetExtents(min, max); _cacheParams.boxMin = min; _cacheParams.boxMax = max; _cacheParams.direction = (bool)p->GetValueLong(ParticleParams::ShowDirectionTag, false); _cacheParams.stride = p->GetValueLong(ParticleParams::StrideTag, 1); _cacheParams.varName = p->GetVariableName(); _cacheParams.fieldVars = p->GetFieldVariableNames(); _cacheParams.radiusVarName = p->GetValueString( ParticleParams::RenderRadiusVariableTag, ""); } bool ParticleRenderer::_colormapCacheIsDirty() const { auto p = GetActiveParams(); std::vector tf_lut; MapperFunction *tf = p->GetMapperFunc(_cacheParams.varName); tf->makeLut(tf_lut); if (_cacheParams.tf_lut != tf_lut) return true; if (_cacheParams.tf_minMax != tf->getMinMaxMapValue()) return true; return false; } void ParticleRenderer::_resetColormapCache() { auto p = GetActiveParams(); MapperFunction *tf = p->GetMapperFunc(_cacheParams.varName); std::vector tf_lut; tf->makeLut(tf_lut); std::vector minMax = tf->getMinMaxMapValue(); _cacheParams.tf_lut = tf_lut; _cacheParams.tf_minMax = minMax; } int ParticleRenderer::_renderParticlesHelper() { auto rp = GetActiveParams(); float radiusBase = rp->GetValueDouble(ParticleParams::RenderRadiusBaseTag, -1); float radius = radiusBase * rp->GetValueDouble(ParticleParams::RenderRadiusScalarTag, 1.); string shaderKey; if (_cacheParams.direction) shaderKey = "ParticleDirection"; else shaderKey = "ParticlePoint"; if (!_cacheParams.radiusVarName.empty()) shaderKey += ":DYNAMIC_RADIUS"; ShaderProgram *shader = _glManager->shaderManager->GetShader(shaderKey); if (!shader) return -1; double m[16]; double cameraPosD[3], cameraUpD[3], cameraDirD[3]; _paramsMgr->GetViewpointParams(_winName)->GetModelViewMatrix(m); _paramsMgr->GetViewpointParams(_winName)->ReconstructCamera(m, cameraPosD, cameraUpD, cameraDirD); glm::vec3 cameraDir = glm::vec3(cameraDirD[0], cameraDirD[1], cameraDirD[2]); glm::vec3 cameraPos = glm::vec3(cameraPosD[0], cameraPosD[1], cameraPosD[2]); shader->Bind(); shader->SetUniform("P", _glManager->matrixManager->GetProjectionMatrix()); shader->SetUniform("MV", _glManager->matrixManager->GetModelViewMatrix()); shader->SetUniform("aspect", _glManager->matrixManager->GetProjectionAspectRatio()); shader->SetUniform("radius", radius); shader->SetUniform("dirScale", (float)rp->GetValueDouble(ParticleParams::DirectionScaleTag, 1.)); shader->SetUniform("lightingEnabled", (bool)rp->GetValueLong(ParticleParams::LightingEnabledTag, true)); shader->SetUniform("scales", _getScales()); shader->SetUniform("cameraPos", cameraPos); shader->SetUniform("lightDir", cameraDir); shader->SetUniform("phongAmbient", (float)rp->GetValueDouble(ParticleParams::PhongAmbientTag, 0.4)); shader->SetUniform("phongDiffuse", (float)rp->GetValueDouble(ParticleParams::PhongDiffuseTag, 0.8)); shader->SetUniform("phongSpecular", (float)rp->GetValueDouble(ParticleParams::PhongSpecularTag, 0.0)); shader->SetUniform("phongShininess", (float)(100 * powf(rp->GetValueDouble(ParticleParams::PhongShininessTag, 0.01), 2))); shader->SetUniform("mapRange", glm::make_vec2(_colorMapRange)); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, _colorMapTexId); shader->SetUniform("LUT", 0); glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glEnable(GL_BLEND); glBindVertexArray(_VAO); glDrawArrays(GL_POINTS, 0, _particlesCount); GL_ERR_BREAK(); glDepthMask(GL_TRUE); glDisable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glBindVertexArray(0); glDisable(GL_CULL_FACE); shader->UnBind(); DisableClippingPlanes(); return 0; } int ParticleRenderer::_getGrids(Grid*& grid, std::vector& vecGrids) const { #define PD3(v) printf("%s = %f, %f, %f\n", #v, v[0], v[1], v[2]) string varName = _cacheParams.varName; grid = _dataMgr->GetVariable(_cacheParams.ts, _cacheParams.varName, _cacheParams.rLevel, _cacheParams.cLevel, _cacheParams.boxMin, _cacheParams.boxMax, true); if (!grid) { SetErrMsg("Cannot acquire grid for variable \"%s\"", _cacheParams.varName.c_str()); return -1; } vector vecNames = _cacheParams.fieldVars; vector mainVarCoords; _dataMgr->GetVarCoordVars(_cacheParams.varName, true, mainVarCoords); if (_cacheParams.direction) { for (auto var : vecNames) { vector varCoords; _dataMgr->GetVarCoordVars(var, true, varCoords); if (mainVarCoords != varCoords) { if (grid) { _dataMgr->UnlockGrid(grid); delete grid; } for (auto g : vecGrids) { _dataMgr->UnlockGrid(g); delete g; } SetErrMsg("Variable \"%s\" on different grid from main variable", var.c_str()); return -1; } Grid *ng = _dataMgr->GetVariable(_cacheParams.ts, var, _cacheParams.rLevel, _cacheParams.cLevel, _cacheParams.boxMin, _cacheParams.boxMax, true); if (!ng) { if (grid) { _dataMgr->UnlockGrid(grid); delete grid; } for (auto g : vecGrids) { _dataMgr->UnlockGrid(g); delete g; } SetErrMsg("Cannot read var \"%s\"", var.c_str()); return -1; } vecGrids.push_back(ng); } } if (!_cacheParams.radiusVarName.empty()) { vecGrids.push_back(_dataMgr->GetVariable(_cacheParams.ts, _cacheParams.radiusVarName, _cacheParams.rLevel, _cacheParams.cLevel, _cacheParams.boxMin, _cacheParams.boxMax, true)); } return 0; } template void ParticleRenderer::UploadDataBuffer(vector buffer) { glBufferData(GL_ARRAY_BUFFER, sizeof(T) * buffer.size(), buffer.data(), GL_STATIC_DRAW); _particlesCount = buffer.size(); } void ParticleRenderer::_generateTextureData(const Grid* grid, const std::vector& vecGrids) { bool showDir = _cacheParams.direction; bool dynamicSize = !_cacheParams.radiusVarName.empty(); size_t stride = max(1L, (long)_cacheParams.stride); auto node = grid->ConstNodeBegin(_cacheParams.boxMin, _cacheParams.boxMax); auto nodeEnd = grid->ConstNodeEnd(); CoordType coordsBuf; struct PointDataT {vec3 pos; float val;}; vector pointData; struct DirectionDataT {vec3 pos; vec3 norm; float val;}; vector directionData; struct PointDynSizeDataT {vec3 pos; float val; float radius;}; vector pointDynSizeData; struct DirectionDynSizeDataT {vec3 pos; vec3 norm; float val; float radius;}; vector directionDynSizeData; if (showDir) { SetupParticleDirectionGL(_VAO, _VBO, dynamicSize); directionData.reserve(grid->GetDimensions()[0]/stride+1); } else { SetupParticlePointGL(_VAO, _VBO, dynamicSize); pointData.reserve(grid->GetDimensions()[0]/stride+1); } assert(glIsVertexArray(_VAO) == GL_TRUE); assert(glIsBuffer(_VBO) == GL_TRUE); for (size_t i = 0; node != nodeEnd;) { if (i % stride) goto step; { const float value = grid->GetValueAtIndex(*node); grid->GetUserCoordinates(*node, coordsBuf); const vec3 p = CoordTypeToVec3(coordsBuf); if (showDir){ const glm::vec3 norm( vecGrids[0]->GetValueAtIndex(*node), vecGrids[1]->GetValueAtIndex(*node), vecGrids[2]->GetValueAtIndex(*node) ); if (dynamicSize) directionDynSizeData.push_back({p, norm, value, vecGrids[vecGrids.size()-1]->GetValueAtIndex(*node)}); else directionData.push_back({p, norm, value}); } else { if (dynamicSize) // pointDynSizeData.push_back({p, value, *(dirs[dirs.size()-1])}); pointDynSizeData.push_back({p, value, vecGrids[vecGrids.size()-1]->GetValueAtIndex(*node)}); else pointData.push_back({p, value}); } } step: ++node, ++i; } glBindVertexArray(_VAO); glBindBuffer(GL_ARRAY_BUFFER, _VBO); if (dynamicSize) { if (showDir) UploadDataBuffer(directionDynSizeData); else UploadDataBuffer(pointDynSizeData); } else { if (showDir) UploadDataBuffer(directionData); else UploadDataBuffer(pointData); } glBindBuffer(GL_ARRAY_BUFFER, 0); } void ParticleRenderer::_computeBaseRadius() { auto rp = GetActiveParams(); CoordType mind, maxd; // Need to find a non-empty variable from color mapping or velocity variables. std::string nonEmptyVarName = rp->GetColorMapVariableName(); assert(!nonEmptyVarName.empty()); _dataMgr->GetVariableExtents(_cacheParams.ts, nonEmptyVarName, _cacheParams.rLevel, _cacheParams.cLevel, mind, maxd); glm::vec3 min(mind[0], mind[1], mind[2]); glm::vec3 max(maxd[0], maxd[1], maxd[2]); glm::vec3 lens = max - min; float largestDim = glm::max(lens.x, glm::max(lens.y, lens.z)); float radiusBase = largestDim / 560.f; if (!_cacheParams.radiusVarName.empty()) { vector dataRange; _dataMgr->GetDataRange(_cacheParams.ts, _cacheParams.radiusVarName, _cacheParams.rLevel, _cacheParams.cLevel, _cacheParams.boxMin, _cacheParams.boxMax, dataRange); radiusBase /= (dataRange[0]+dataRange[1])/2; } rp->SetValueDouble(ParticleParams::RenderRadiusBaseTag, "", radiusBase); } void ParticleRenderer::_renderParticlesLegacy(const Grid* grid, const std::vector& vecGrids) const { auto p = GetActiveParams(); MapperFunction* mf = p->GetMapperFunc(p->GetVariableName()); float LUT[256*4]; mf->makeLut(LUT); float mapMin = mf->getMinMapValue(); float mapMax = mf->getMaxMapValue(); float mapDif = mapMax - mapMin; bool showDir = _cacheParams.direction; LegacyGL* lgl = _glManager->legacy; glDepthMask(true); glEnable(GL_DEPTH_TEST); lgl->Color3f(1, 1, 1); lgl->Begin(showDir ? GL_LINES : GL_POINTS); auto node = grid->ConstNodeBegin(_cacheParams.boxMin, _cacheParams.boxMax); auto nodeEnd = grid->ConstNodeEnd(); CoordType coordsBuf; vector dirs; for (auto g : vecGrids) dirs.push_back(g->cbegin(_cacheParams.boxMin, _cacheParams.boxMax)); size_t stride = max(1L, (long)_cacheParams.stride); float dirScale = p->GetValueDouble(ParticleParams::DirectionScaleTag, 1.); for (size_t i = 0; node != nodeEnd; ++node, ++i) { if (i % stride) { if (showDir) for (auto &it : dirs) ++it; continue; } const float value = grid->GetValueAtIndex(*node); grid->GetUserCoordinates(*node, coordsBuf); const glm::vec3 p(coordsBuf[0], coordsBuf[1], coordsBuf[2]); lgl->Color4fv(&LUT[4 * glm::clamp((int)(255 * (value - mapMin) / mapDif), 0, 255)]); lgl->Vertex3fv((float *)&p); if (showDir) { const glm::vec3 n(*(dirs[0]), *(dirs[1]), *(dirs[2])); const glm::vec3 p2 = p + n * dirScale; lgl->Vertex3fv((float *)&p2); for (auto &it : dirs) ++it; } } lgl->End(); } void ParticleRenderer::_prepareColormap() { assert(_cacheParams.tf_lut.size() % 4 == 0); _colorMapRange[0] = _cacheParams.tf_minMax[0]; _colorMapRange[1] = _cacheParams.tf_minMax[1]; _colorMapRange[2] = (_colorMapRange[1] - _colorMapRange[0]) > 1e-5f ? (_colorMapRange[1] - _colorMapRange[0]) : 1e-5f; glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset); glBindTexture(GL_TEXTURE_1D, _colorMapTexId); glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, _cacheParams.tf_lut.size() / 4, 0, GL_RGBA, GL_FLOAT, _cacheParams.tf_lut.data()); } glm::vec3 ParticleRenderer::_getScales() { string myVisName = GetVisualizer(); // This is the line that's not const VAPoR::ViewpointParams *vpp = _paramsMgr->GetViewpointParams(myVisName); string datasetName = GetMyDatasetName(); Transform * tDataset = vpp->GetTransform(datasetName); Transform * tRenderer = GetActiveParams()->GetTransform(); vector scales = tDataset->GetScales(); vector rendererScales = tRenderer->GetScales(); scales[0] *= rendererScales[0]; scales[1] *= rendererScales[1]; scales[2] *= rendererScales[2]; return glm::vec3(scales[0], scales[1], scales[2]); } ================================================ FILE: lib/render/Proj4StringParser.cpp ================================================ #include "vapor/Proj4StringParser.h" #ifdef WIN32 #include #else #include #endif using namespace VAPoR; using std::map; using std::pair; using std::string; Proj4StringParser::Proj4StringParser(const std::string &projString) : _string(projString), _tokens(Proj4StringToParameterMap(projString)) {} pair Proj4StringParser::Proj4ParameterToKeyValuePair(string proj) { if (proj[0] != '+') { return pair("NULL", "NULL"); } proj = proj.substr(1); string key = proj.substr(0, proj.find("=")); string value = proj.substr(proj.find("=") + 1); return pair(key, value); } map Proj4StringParser::Proj4StringToParameterMap(string proj) { const string delimeter = " "; size_t index; string token; map tokens; while ((index = proj.find(delimeter)) != string::npos) { token = proj.substr(0, index); proj.erase(0, index + delimeter.length()); tokens.insert(Proj4ParameterToKeyValuePair(token)); } tokens.insert(Proj4ParameterToKeyValuePair(proj)); return tokens; } bool Proj4StringParser::HasKey(const std::string &key) const { return _tokens.find(key) != _tokens.end(); } std::string Proj4StringParser::GetString(const std::string &key, const std::string &defaultValue) const { auto it = _tokens.find(key); if (it == _tokens.end()) return defaultValue; return it->second; } double Proj4StringParser::GetDouble(const std::string &key, const double defaultValue) const { auto it = _tokens.find(key); if (it == _tokens.end()) return defaultValue; return std::stod(it->second); } int Proj4StringParser::Proj4EllipseStringToGeoTIFEnum(const std::string &proj) { if (0) ; else if (proj == "NWL9D") return Ellipse_NWL_9D; else if (proj == "WGS84") return Ellipse_WGS_84; else if (proj == "airy") return Ellipse_Airy_1830; else if (proj == "bess_nam") return Ellipse_Bessel_Namibia; else if (proj == "bessel") return Ellipse_Bessel_1841; else if (proj == "clrk66") return Ellipse_Clarke_1866; else if (proj == "clrk80") return Ellipse_Clarke_1880; else if (proj == "clrk80ign") return Ellipse_Clarke_1880_IGN; else if (proj == "helmert") return Ellipse_Helmert_1906; else if (proj == "krass") return Ellipse_Krassowsky_1940; else if (proj == "plessis") return Ellipse_Plessis_1817; else if (proj == "sphere") return Ellipse_Sphere; SetErrMsg("Unsupported Proj4 ellipse parameter \"%s\"", proj.c_str()); return -1; } ================================================ FILE: lib/render/PyEngine.cpp ================================================ #include #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; #define NPY_NO_DEPRECATED_API NPY_API_VERSION #include namespace { struct varinfo_t { varinfo_t() { _g = NULL; _name.clear(); _dims = {1, 1, 1}; _coordNames.clear(); _coordAxes.clear(); _coordDims.clear(); } Grid * _g; string _name; DimsType _dims; vector _coordNames; vector _coordAxes; vector _coordDims; }; void free_arrays(vector &arrays) { for (int i = 0; i < arrays.size(); i++) { if (arrays[i]) { delete[] arrays[i]; } } } void free_arrays(vector &inputVarArrays, vector &outputVarArrays) { free_arrays(inputVarArrays); free_arrays(outputVarArrays); } int alloc_arrays(const vector &dimsVectors, vector &arrays) { arrays.clear(); for (int i = 0; i < dimsVectors.size(); i++) { size_t nElements = VProduct(dimsVectors[i].data(), dimsVectors[i].size()); float *buf = new (nothrow) float[nElements]; if (!buf) { free_arrays(arrays); return (-1); } arrays.push_back(buf); } return (0); } int alloc_arrays(const vector &inputVarDims, const vector &outputVarDims, vector &inputVarArrays, vector &outputVarArrays) { inputVarArrays.clear(); outputVarArrays.clear(); int rc = alloc_arrays(inputVarDims, inputVarArrays); if (rc < 0) return (rc); rc = alloc_arrays(outputVarDims, outputVarArrays); if (rc < 0) { free_arrays(inputVarArrays); return (rc); } return (0); } void copy_region(const float *src, float *dst, const DimsType &min, const DimsType &max, const DimsType &dims) { DimsType coord = min; for (size_t i = 0; i < VProduct(Grid::Dims(min, max).data(), min.size()); i++) { size_t offset = LinearizeCoords(coord.data(), dims.data(), coord.size()); dst[i] = src[offset]; IncrementCoords(min.data(), max.data(), coord.data(), min.size(), 0); } } void copy_coord(const Grid *g, int axis, float *dst) { DimsType dims = g->GetCoordDimensions(axis); DimsType min = {0, 0, 0}; DimsType max = {dims[0] - 1, dims[1] - 1, dims[2] - 1}; // Fetch user coordinates from grid. Note: assumes that if coordinate // dimensions are less than grid dimensions than the coordinate DimsType index = min; CoordType coord; for (size_t i = 0; i < VProduct(Grid::Dims(min, max).data(), min.size()); i++) { g->GetUserCoordinates(index, coord); dst[i] = coord[axis]; IncrementCoords(min.data(), max.data(), index.data(), index.size(), 0); } } void grid2c(const vector &varInfoVec, const vector &inputVarArrays) { int idx = 0; for (int i = 0; i < varInfoVec.size(); i++) { const varinfo_t &vref = varInfoVec[i]; Grid *g = vref._g; Grid::ConstIterator itr = g->cbegin(); Grid::ConstIterator enditr = g->cend(); VAssert(idx < inputVarArrays.size()); float *bufptr = inputVarArrays[idx]; // Copy data. Missing values are always set to infinity for // easier Python handling // float mv = g->GetMissingValue(); for (; itr != enditr; ++itr) { if (g->HasMissingData() && *itr == mv) { *bufptr = std::numeric_limits::infinity(); } else { *bufptr = *itr; } bufptr++; } idx++; for (int j = 0; j < vref._coordNames.size(); j++) { VAssert(idx < inputVarArrays.size()); float *bufptr = inputVarArrays[idx]; copy_coord(g, vref._coordAxes[j], bufptr); idx++; } } } void get_var_info(DataMgr *dataMgr, const vector &gs, const vector &varNames, bool coordFlag, vector &varinfoVec) { varinfoVec.clear(); VAssert(gs.size() == varNames.size()); // Need to keep track of all coordinate variables. We generate a // unique list // vector allCoordVars; // Build a vector of grids and *unique* coordinate variables // for (int i = 0; i < gs.size(); i++) { varinfo_t varinfo; varinfo._g = gs[i]; varinfo._name = varNames[i]; varinfo._dims = gs[i]->GetDimensions(); varinfo._coordNames.clear(); varinfo._coordAxes.clear(); varinfo._coordDims.clear(); if (!coordFlag) { varinfoVec.push_back(varinfo); continue; } DC::DataVar dvar; bool ok = dataMgr->GetDataVarInfo(varNames[i], dvar); VAssert(ok); DC::Mesh m; ok = dataMgr->GetMesh(dvar.GetMeshName(), m); VAssert(ok); vector coordNames = m.GetCoordVars(); for (int j = 0; j < coordNames.size(); j++) { vector::iterator itr; itr = find(allCoordVars.begin(), allCoordVars.end(), coordNames[j]); if (itr != allCoordVars.end()) continue; DC::CoordVar cvar; ok = dataMgr->GetCoordVarInfo(coordNames[j], cvar); VAssert(ok); varinfo._coordNames.push_back(coordNames[j]); varinfo._coordAxes.push_back(cvar.GetAxis()); varinfo._coordDims.push_back(gs[i]->GetCoordDimensions(cvar.GetAxis())); } varinfoVec.push_back(varinfo); } } // Remove trailing, degenerate unit dimensions // size_t number_of_dims(DimsType dims) { size_t n = dims.size(); while (n > 1 && dims[n - 1] <= 1) n--; return (n); } }; // namespace using namespace VAPoR; using namespace Wasp; int PyEngine::Initialize() { int rc = MyPython::Instance()->Initialize(); if (rc < 0) return (rc); // Secret numpy incantation required to use NumPy's C API. Hope this // crap works. // #ifndef DISABLE_EXTRA_PYTHON_MATH_IMPORTS if (PyArray_API == NULL) { import_array1(-1) } #else fprintf(stderr, "WARNING Vapor python array import disabled\n"); #endif return (0); } int PyEngine::AddFunction(string name, string script, const vector &inputVarNames, const vector &outputVarNames, const vector &outputVarMeshes, bool coordFlag) { VAssert(outputVarNames.size() == outputVarMeshes.size()); // cout << "PyEngine::AddFunction() " << name << endl; // cout << " " << script << endl; // No-op if not defined // RemoveFunction(name); // Output variables can't already be defined (either derived or native vars) // if (_checkOutVars(outputVarNames) < 0) return (-1); // Mesh name must be defined // if (_checkOutMeshes(outputVarMeshes) < 0) return (-1); // Test the script syntatical correctness. Only way to do this // with crappy Python API is to compile the string to an // object :-( // PyObject *retObj = Py_CompileString(script.c_str(), "", Py_file_input); if (!retObj) { SetErrMsg("Py_CompileString() : %s", MyPython::Instance()->PyErr().c_str()); return -1; } Py_DECREF(retObj); const string timeCoordVarName = _getTimeCoordVarName(inputVarNames); vector dvars; for (int i = 0; i < outputVarNames.size(); i++) { string vname = outputVarNames[i]; DerivedPythonVar *dvar = new DerivedPythonVar(vname, "", DC::XType::FLOAT, outputVarMeshes[i], timeCoordVarName, true, inputVarNames, script, _dataMgr, coordFlag); dvars.push_back(dvar); if (dvar->Initialize() < 0) { for (int i = 0; i < dvars.size(); i++) delete dvars[i]; SetErrMsg("Failed to initialized derived variable %s", vname.c_str()); return (-1); } (void)_dataMgr->AddDerivedVar(dvar); } _functions[name] = func_c(name, script, inputVarNames, outputVarNames, outputVarMeshes, dvars, coordFlag); return (0); } void PyEngine::RemoveFunction(string name) { map::iterator itr = _functions.find(name); if (itr == _functions.end()) return; const func_c & func = itr->second; const vector & outputVarNames = func._outputVarNames; const vector &dvars = func._derivedVars; VAssert(outputVarNames.size() == dvars.size()); for (int i = 0; i < outputVarNames.size(); i++) { _dataMgr->RemoveDerivedVar(outputVarNames[i]); if (dvars[i]) delete dvars[i]; } _functions.erase(itr); } vector PyEngine::GetFunctionNames() const { map::const_iterator itr; vector names; for (itr = _functions.cbegin(); itr != _functions.cend(); ++itr) { names.push_back(itr->first); } return (names); } string PyEngine::GetFunctionScript(string name) const { map::const_iterator itr = _functions.find(name); if (itr == _functions.cend()) return (""); const func_c &func = itr->second; return (func._script); } bool PyEngine::GetFunctionScript(string name, string &script, std::vector &inputVarNames, std::vector &outputVarNames, std::vector &outputMeshNames, bool &coordFlag) const { script.clear(); inputVarNames.clear(); outputVarNames.clear(); outputMeshNames.clear(); map::const_iterator itr = _functions.find(name); if (itr == _functions.cend()) return (false); const func_c &func = itr->second; script = func._script; inputVarNames = func._inputVarNames; outputVarNames = func._outputVarNames; outputMeshNames = func._outputMeshNames; coordFlag = func._coordFlag; return (true); } string PyEngine::GetFunctionStdout(string name) const { map::const_iterator itr = _functions.find(name); if (itr == _functions.cend()) return (""); const func_c &func = itr->second; string s; for (int i = 0; i < func._derivedVars.size(); i++) { s += func._derivedVars[i]->GetScriptStdout(); } return (s); } PyEngine::~PyEngine() { map::iterator itr; while ((itr = _functions.begin()) != _functions.end()) { RemoveFunction(itr->first); } } int PyEngine::Calculate(const string &script, vector inputVarNames, vector inputVarDims, vector inputVarArrays, vector outputVarNames, vector outputVarDims, vector outputVarArrays) { VAssert(inputVarNames.size() == inputVarDims.size()); VAssert(inputVarNames.size() == inputVarArrays.size()); VAssert(outputVarNames.size() == outputVarDims.size()); VAssert(outputVarNames.size() == outputVarArrays.size()); vector allNames = inputVarNames; allNames.insert(allNames.end(), outputVarNames.begin(), outputVarNames.end()); // cout << "PyEngine::Calculate() " << script << endl; // Convert the input arrays and put into dictionary: // PyObject *mainModule = PyImport_AddModule("__main__"); if (!mainModule) { SetErrMsg("PyImport_AddModule(\"__main__\") : %s", MyPython::Instance()->PyErr().c_str()); return -1; } PyObject *mainDict = PyModule_GetDict(mainModule); VAssert(mainDict != NULL); // Copy arrays into python environment // int rc = _c2python(mainDict, inputVarNames, inputVarDims, inputVarArrays); if (rc < 0) { _cleanupDict(mainDict, inputVarNames); return (-1); } // Run the script // PyObject *retObj = PyRun_String(script.c_str(), Py_file_input, mainDict, mainDict); if (!retObj) { SetErrMsg("PyRun_String() : %s", MyPython::Instance()->PyErr().c_str()); _cleanupDict(mainDict, inputVarNames); return -1; } // Retrieve calculated arrays from python environment // rc = _python2c(mainDict, outputVarNames, outputVarDims, outputVarArrays); if (rc < 0) { _cleanupDict(mainDict, allNames); return (-1); } _cleanupDict(mainDict, allNames); return (0); } void PyEngine::_cleanupDict(PyObject *mainDict, vector keynames) { for (int i = 0; i < keynames.size(); i++) { PyObject *key = PyUnicode_FromString(keynames[i].c_str()); if (!key) continue; if (PyDict_Contains(mainDict, key)) { PyObject_DelItem(mainDict, key); } Py_DECREF(key); } } int PyEngine::_c2python(PyObject *dict, vector inputVarNames, vector inputVarDims, vector inputVarArrays) { npy_intp pyDims[3] = {1, 1, 1}; for (int i = 0; i < inputVarNames.size(); i++) { const DimsType &dims = inputVarDims[i]; for (int j = 0; j < number_of_dims(dims); j++) { pyDims[number_of_dims(dims) - j - 1] = dims[j]; } PyObject *pyArray = PyArray_SimpleNewFromData(number_of_dims(dims), pyDims, NPY_FLOAT32, inputVarArrays[i]); PyObject *ky = Py_BuildValue("s", inputVarNames[i].c_str()); PyObject_SetItem(dict, ky, pyArray); Py_DECREF(ky); Py_DECREF(pyArray); } return (0); } int PyEngine::_python2c(PyObject *dict, vector outputVarNames, vector outputVarDims, vector outputVarArrays) { for (int i = 0; i < outputVarNames.size(); i++) { const string &vname = outputVarNames[i]; PyObject *ky = Py_BuildValue("s", vname.c_str()); PyObject *o = PyDict_GetItem(dict, ky); if (!o || !PyArray_CheckExact(o)) { SetErrMsg("Output variable named %s, of type numpy.ndarray expected, but not produced by script", vname.c_str()); return -1; } PyArrayObject *varArray = (PyArrayObject *)o; if (PyArray_TYPE(varArray) != NPY_FLOAT) { ; SetErrMsg("Variable %s is not of type float32", vname.c_str()); return -1; } const DimsType & dims = outputVarDims[i]; int nd = PyArray_NDIM(varArray); if (nd != number_of_dims(dims)) { SetErrMsg("Shape of %s array does not match", vname.c_str()); return -1; } npy_intp *pyDims = PyArray_DIMS(varArray); for (int j = 0; j < nd; j++) { if (pyDims[number_of_dims(dims) - j - 1] != dims[j]) { SetErrMsg("Shape of %s array does not match", vname.c_str()); return -1; } } float *dataArray = (float *)PyArray_DATA(varArray); size_t nelements = VProduct(dims.data(), dims.size()); float *outArray = outputVarArrays[i]; for (size_t j = 0; j < nelements; j++) { outArray[j] = dataArray[j]; } } return (0); } PyEngine::DerivedPythonVar::DerivedPythonVar(string varName, string units, DC::XType type, string mesh, string time_coord_var, bool hasMissing, std::vector inNames, string script, DataMgr *dataMgr, bool coordFlag) : DerivedDataVar(varName), _varInfo(varName, units, type, "", std::vector(), std::vector(), mesh, time_coord_var, DC::Mesh::NODE) { _inNames = inNames; _script = script; _dataMgr = dataMgr; _coordFlag = coordFlag; _dims = {1, 1, 1}; _meshMatchFlag = false; _stdoutString.clear(); if (hasMissing) { _varInfo.SetHasMissing(true); _varInfo.SetMissingValue(std::numeric_limits::infinity()); } }; int PyEngine::DerivedPythonVar::Initialize() { DC::Mesh m; bool status = _dataMgr->GetMesh(_varInfo.GetMeshName(), m); if (!status) { SetErrMsg("Invalid mesh : %s", _varInfo.GetMeshName().c_str()); return (-1); } vector dimNames = m.GetDimNames(); VAssert(dimNames.size() <= _dims.size()); for (int i = 0; i < dimNames.size(); i++) { DC::Dimension dim; status = _dataMgr->GetDimension(dimNames[i], dim, -1); VAssert(status); _dims[i] = dim.GetLength(); } string mesh = _varInfo.GetMeshName(); // If all of the input variables and the output (derived) variable // are on the same mesh we can optimize by only calculating the // derived variable over the requested ROI (min and max extents) // _meshMatchFlag = true; for (int i = 0; i < _inNames.size(); i++) { DC::DataVar dvar; bool ok = _dataMgr->GetDataVarInfo(_inNames[i], dvar); if (!ok || dvar.GetMeshName() != mesh) { _meshMatchFlag = false; break; } } if (_meshMatchFlag && _inNames.size()) { DC::DataVar dvar; bool ok = _dataMgr->GetDataVarInfo(_inNames[0], dvar); VAssert(ok); _varInfo.SetCRatios(dvar.GetCRatios()); } return (0); } bool PyEngine::DerivedPythonVar::GetBaseVarInfo(DC::BaseVar &var) const { var = _varInfo; return (true); } int PyEngine::DerivedPythonVar::GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); if (_meshMatchFlag && _inNames.size()) { int rc = _dataMgr->GetDimLensAtLevel(_inNames[0], level, dims_at_level, -1); VAssert(rc >= 0); } else { for (int i = 0; i < number_of_dims(_dims) && i < _dims.size(); i++) { dims_at_level.push_back(_dims[i]); } } // No blocking // bs_at_level = vector(dims_at_level.size(), 1); return (0); } size_t PyEngine::DerivedPythonVar::GetNumRefLevels() const { if (_meshMatchFlag && _inNames.size()) { return (_dataMgr->GetNumRefLevels(_inNames[0])); } return (1); } int PyEngine::DerivedPythonVar::OpenVariableRead(size_t ts, int level, int lod) { if (level < 0) level = GetNumRefLevels() + level; if (lod < 0) lod = _varInfo.GetCRatios().size() + lod; DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod); return (_fileTable.AddEntry(f)); } int PyEngine::DerivedPythonVar::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } _fileTable.RemoveEntry(fd); delete f; return (0); } int PyEngine::DerivedPythonVar::_readRegionAll(int fd, const DimsType &min, const DimsType &max, float *region) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); vector variables; size_t ts = f->GetTS(); int level = f->GetLevel(); int lod = f->GetLOD(); int rc = DataMgrUtils::GetGrids(_dataMgr, ts, _inNames, false, &level, &lod, variables); if (rc < 0) return (-1); vector varInfoVec; get_var_info(_dataMgr, variables, _inNames, _coordFlag, varInfoVec); vector inputVarDims; vector inputNames; for (int i = 0; i < varInfoVec.size(); i++) { const varinfo_t &vref = varInfoVec[i]; inputNames.push_back(vref._name); inputVarDims.push_back(vref._dims); for (int j = 0; j < vref._coordNames.size(); j++) { inputNames.push_back(vref._coordNames[j]); inputVarDims.push_back(vref._coordDims[j]); } } vector dims_vec, dummy; (void)GetDimLensAtLevel(level, dims_vec, dummy); DimsType dims = {1, 1, 1}; Grid::CopyToArr3(dims_vec, dims); vector outputVarDims = {dims}; vector inputVarArrays; vector outputVarArrays; rc = alloc_arrays(inputVarDims, outputVarDims, inputVarArrays, outputVarArrays); if (rc < 0) { SetErrMsg("Error allocating memory"); return (-1); } grid2c(varInfoVec, inputVarArrays); // // clear stdout from static class // (void)MyPython::Instance()->PyOut(); vector outputVarNames = {_derivedVarName}; rc = PyEngine::Calculate(_script, inputNames, inputVarDims, inputVarArrays, outputVarNames, outputVarDims, outputVarArrays); // // Capture any stdout // _stdoutString = MyPython::Instance()->PyOut().c_str(); if (rc < 0) { free_arrays(inputVarArrays, outputVarArrays); return (-1); } copy_region(outputVarArrays[0], region, min, max, outputVarDims[0]); free_arrays(inputVarArrays, outputVarArrays); return (0); } int PyEngine::DerivedPythonVar::_readRegionSubset(int fd, const DimsType &min, const DimsType &max, float *region) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); vector variables; size_t ts = f->GetTS(); int level = f->GetLevel(); int lod = f->GetLOD(); int rc = DataMgrUtils::GetGrids(_dataMgr, ts, _inNames, min, max, false, &level, &lod, variables); if (rc < 0) return (-1); vector varInfoVec; get_var_info(_dataMgr, variables, _inNames, _coordFlag, varInfoVec); vector inputVarDims; vector inputNames; for (int i = 0; i < varInfoVec.size(); i++) { const varinfo_t &vref = varInfoVec[i]; inputNames.push_back(vref._name); inputVarDims.push_back(vref._dims); for (int j = 0; j < vref._coordNames.size(); j++) { inputNames.push_back(vref._coordNames[j]); inputVarDims.push_back(vref._coordDims[j]); } } // output and input variable(s) (if they exist) are all defined // on the same mesh (they have same dimensions) // vector outputVarDims; DimsType minAbs = {0, 0, 0}; if (inputVarDims.size()) { outputVarDims.push_back(inputVarDims[0]); minAbs = variables[0]->GetMinAbs(); } else { outputVarDims.push_back(Grid::Dims(min, max)); } vector inputVarArrays; vector outputVarArrays; rc = alloc_arrays(inputVarDims, outputVarDims, inputVarArrays, outputVarArrays); if (rc < 0) { SetErrMsg("Error allocating memory"); return (-1); } grid2c(varInfoVec, inputVarArrays); // // clear stdout from static class // (void)MyPython::Instance()->PyOut(); vector outputVarNames = {_derivedVarName}; rc = PyEngine::Calculate(_script, inputNames, inputVarDims, inputVarArrays, outputVarNames, outputVarDims, outputVarArrays); // // Capture any stdout // _stdoutString = MyPython::Instance()->PyOut().c_str(); if (rc < 0) { free_arrays(inputVarArrays, outputVarArrays); return (-1); } // The min and max coordinates input to this method are relative to // the entire domain. We need to correct them by substracting off the // origin of the ROI contained in the Grid objects // DimsType min_roi, max_roi; for (int i = 0; i < min.size(); i++) { min_roi[i] = (min[i] - minAbs[i]); max_roi[i] = (max[i] - minAbs[i]); } copy_region(outputVarArrays[0], region, min_roi, max_roi, outputVarDims[0]); free_arrays(inputVarArrays, outputVarArrays); return (0); } int PyEngine::DerivedPythonVar::ReadRegion(int fd, const std::vector &minVec, const std::vector &maxVec, float *region) { DimsType min = {0, 0, 0}; Grid::CopyToArr3(minVec, min); DimsType max = {0, 0, 0}; Grid::CopyToArr3(maxVec, max); if (_meshMatchFlag) { return (_readRegionSubset(fd, min, max, region)); } else { return (_readRegionAll(fd, min, max, region)); } } bool PyEngine::DerivedPythonVar::VariableExists(size_t ts, int reflevel, int lod) const { for (int i = 0; i < _inNames.size(); i++) { if (!_dataMgr->VariableExists(ts, _inNames[i], reflevel, lod)) { return (false); } } return (true); } bool PyEngine::DerivedPythonVar::GetDataVarInfo(DC::DataVar &cvar) const { cvar = _varInfo; return (true); } bool PyEngine::_validOutputVar(string name) const { vector vars = _dataMgr->GetDataVarNames(); if (find(vars.begin(), vars.end(), name) != vars.end()) return (false); vars = _dataMgr->GetCoordVarNames(); if (find(vars.begin(), vars.end(), name) != vars.end()) return (false); return (true); } int PyEngine::_checkOutVars(const vector &outputVarNames) const { for (int i = 0; i < outputVarNames.size(); i++) { string vname = outputVarNames[i]; if (!XmlNode::IsValidXMLElement(vname)) { SetErrMsg("Invalid variable name: %s ", vname.c_str()); return (-1); } if (!_validOutputVar(outputVarNames[i])) { SetErrMsg("Invalid derived variable name %s. Already in use.", vname.c_str()); return (-1); } } return (0); } bool PyEngine::_validOutputMesh(string name) const { vector meshes = _dataMgr->GetMeshNames(); return (find(meshes.begin(), meshes.end(), name) != meshes.end()); } int PyEngine::_checkOutMeshes(const vector &outputMeshNames) const { for (int i = 0; i < outputMeshNames.size(); i++) { string name = outputMeshNames[i]; if (!_validOutputMesh(outputMeshNames[i])) { SetErrMsg("Invalid derived variable mesh name %s", name.c_str()); return (-1); } } return (0); } string PyEngine::_getTimeCoordVarName(const vector &varNames) const { string timeCoordVarName = _dataMgr->GetTimeCoordVarName(); if (timeCoordVarName.empty()) return (""); for (int i = 0; i < varNames.size(); i++) { if (_dataMgr->IsTimeVarying(varNames[i])) return (timeCoordVarName); } return (""); } ================================================ FILE: lib/render/RayCaster.cpp ================================================ #include "vapor/glutil.h" #include "vapor/RayCaster.h" #include #include #include #include #include #include #ifdef WIN32 #include #else #include #endif #define OUTOFDATE 1 #define GLNOTREADY 2 #define GRIDERROR -1 #define JUSTERROR -2 #define PARAMSERROR -3 #define MEMERROR -4 #define GLERROR -5 using namespace VAPoR; /* GLenum glCheckError_(const char *file, int line) { GLenum errorCode; while ((errorCode = glGetError()) != GL_NO_ERROR) { std::string error; switch (errorCode) { case GL_INVALID_ENUM: error = "INVALID_ENUM"; break; case GL_INVALID_VALUE: error = "INVALID_VALUE"; break; case GL_INVALID_OPERATION: error = "INVALID_OPERATION"; break; case GL_STACK_OVERFLOW: error = "STACK_OVERFLOW"; break; case GL_STACK_UNDERFLOW: error = "STACK_UNDERFLOW"; break; case GL_OUT_OF_MEMORY: error = "OUT_OF_MEMORY"; break; case GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION"; break; } std::cout << error << " | " << file << " (" << line << ")" << std::endl; } return errorCode; } #define glCheckError() glCheckError_(__FILE__, __LINE__) void glCheckError() { } */ // Constructor RayCaster::RayCaster(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string paramsType, std::string classType, std::string &instName, DataMgr *dataMgr) : Renderer(pm, winName, dataSetName, paramsType, classType, instName, dataMgr), _backFaceTexOffset(1), _frontFaceTexOffset(2), _volumeTexOffset(3), _colorMapTexOffset(4), _missingValueTexOffset(5), _vertCoordsTexOffset(6), _depthTexOffset(7), _2ndVarDataTexOffset(8), _2ndVarMaskTexOffset(9) { _backFaceTextureId = 0; _frontFaceTextureId = 0; _volumeTextureId = 0; _missingValueTextureId = 0; _colorMapTextureId = 0; _vertCoordsTextureId = 0; _depthTextureId = 0; _frameBufferId = 0; _2ndVarDataTexId = 0; _2ndVarMaskTexId = 0; _vertexArrayId = 0; _vertexBufferId = 0; _indexBufferId = 0; _vertexAttribId = 0; _1stPassShader = nullptr; _2ndPassShader = nullptr; _3rdPassShader = nullptr; _3rdPassMode1Shader = nullptr; _3rdPassMode2Shader = nullptr; for (int i = 0; i < 4; i++) _currentViewport[i] = 0; _currentMV = glm::mat4(0.0f); // Detect if it's INTEL graphics card. If so, give a magic value to the params const unsigned char *vendorC = glGetString(GL_VENDOR); std::string vendor((char *)vendorC); for (int i = 0; i < vendor.size(); i++) vendor[i] = std::tolower(vendor[i]); std::string::size_type n = vendor.find("intel"); if (n == std::string::npos) _isIntel = false; else _isIntel = true; // Set the default ray casting method upon creation of the RayCaster. _selectDefaultCastingMethod(); } // Destructor RayCaster::~RayCaster() { // Delete framebuffers if (_frameBufferId) { glDeleteFramebuffers(1, &_frameBufferId); _frameBufferId = 0; } // Delete textures if (_backFaceTextureId) { glDeleteTextures(1, &_backFaceTextureId); _backFaceTextureId = 0; } if (_frontFaceTextureId) { glDeleteTextures(1, &_frontFaceTextureId); _frontFaceTextureId = 0; } if (_volumeTextureId) { glDeleteTextures(1, &_volumeTextureId); _volumeTextureId = 0; } if (_missingValueTextureId) { glDeleteTextures(1, &_missingValueTextureId); _missingValueTextureId = 0; } if (_colorMapTextureId) { glDeleteTextures(1, &_colorMapTextureId); _colorMapTextureId = 0; } if (_vertCoordsTextureId) { glDeleteTextures(1, &_vertCoordsTextureId); _vertCoordsTextureId = 0; } if (_depthTextureId) { glDeleteTextures(1, &_depthTextureId); _depthTextureId = 0; } if (_2ndVarDataTexId) { glDeleteTextures(1, &_2ndVarDataTexId); _2ndVarDataTexId = 0; } if (_2ndVarMaskTexId) { glDeleteTextures(1, &_2ndVarMaskTexId); _2ndVarMaskTexId = 0; } // Delete vertex arrays if (_vertexArrayId) { glDeleteVertexArrays(1, &_vertexArrayId); _vertexArrayId = 0; } if (_vertexBufferId) { glDeleteBuffers(1, &_vertexBufferId); _vertexBufferId = 0; } if (_indexBufferId) { glDeleteBuffers(1, &_indexBufferId); _indexBufferId = 0; } if (_vertexAttribId) { glDeleteBuffers(1, &_vertexAttribId); _vertexAttribId = 0; } } // Constructor RayCaster::UserCoordinates::UserCoordinates() { frontFace = nullptr; backFace = nullptr; rightFace = nullptr; leftFace = nullptr; topFace = nullptr; bottomFace = nullptr; dataField = nullptr; vertCoords = nullptr; secondVarData = nullptr; missingValueMask = nullptr; secondVarMask = nullptr; for (int i = 0; i < 3; i++) { myGridMin[i] = 0; myGridMax[i] = 0; dims[i] = 0; } myCurrentTimeStep = 0; myVariableName = ""; my2ndVarName = ""; myRefinementLevel = -1; myCompressionLevel = -1; dataFieldUpToDate = false; vertCoordsUpToDate = false; secondVarUpToDate = false; } // Destructor RayCaster::UserCoordinates::~UserCoordinates() { if (frontFace) { delete[] frontFace; frontFace = nullptr; } if (backFace) { delete[] backFace; backFace = nullptr; } if (rightFace) { delete[] rightFace; rightFace = nullptr; } if (leftFace) { delete[] leftFace; leftFace = nullptr; } if (topFace) { delete[] topFace; topFace = nullptr; } if (bottomFace) { delete[] bottomFace; bottomFace = nullptr; } if (dataField) { delete[] dataField; dataField = nullptr; } if (vertCoords) { delete[] vertCoords; vertCoords = nullptr; } if (missingValueMask) { delete[] missingValueMask; missingValueMask = nullptr; } if (secondVarData) { delete[] secondVarData; secondVarData = nullptr; } if (secondVarMask) { delete[] secondVarMask; secondVarMask = nullptr; } } int RayCaster::UserCoordinates::GetCurrentGrid(const RayCasterParams *params, DataMgr *dataMgr, StructuredGrid **gridpp) const { CoordType extMin, extMax; params->GetBox()->GetExtents(extMin, extMax); StructuredGrid *grid = dynamic_cast(dataMgr->GetVariable(params->GetCurrentTimestep(), params->GetVariableName(), params->GetRefinementLevel(), params->GetCompressionLevel(), extMin, extMax)); if (grid == nullptr) { MyBase::SetErrMsg("UserCoordinates::GetCurrentGrid() isn't on a StructuredGrid; " "the behavior is undefined in this case."); return GRIDERROR; } else { *gridpp = grid; return 0; } } void RayCaster::UserCoordinates::CheckUpToDateStatus(const RayCasterParams *params, const StructuredGrid *grid, DataMgr *dataMgr, bool use2ndVar) { // First, if any of the metadata is changed, all data fields are not up-to-date if ((myCurrentTimeStep != params->GetCurrentTimestep()) || (myRefinementLevel != params->GetRefinementLevel()) || (myCompressionLevel != params->GetCompressionLevel())) { dataFieldUpToDate = false; vertCoordsUpToDate = false; secondVarUpToDate = false; return; } // Second, if the grid extents are changed, all data fields are not up-to-date std::vector newMin, newMax; grid->GetUserExtents(newMin, newMax); VAssert(newMin.size() == 3 || newMax.size() == 3); for (int i = 0; i < 3; i++) if ((myGridMin[i] != (float)newMin[i]) || (myGridMax[i] != (float)newMax[i])) { dataFieldUpToDate = false; vertCoordsUpToDate = false; secondVarUpToDate = false; return; } // Third, let's compare the primary variable name if (myVariableName != params->GetVariableName()) { dataFieldUpToDate = false; } // Fourth, let's check the vertex coordinates. // Actually, the only way vertex coordinates go out of date is changing the metadata // and user extents, which is already checked. We don't need to do anything here! // Fifth, let check if second variable data is up to date if (use2ndVar && (my2ndVarName != params->GetColorMapVariableName())) { secondVarUpToDate = false; } } int RayCaster::UserCoordinates::UpdateFaceAndData(const RayCasterParams *params, const StructuredGrid *grid, DataMgr *dataMgr) { /* Update meta data */ std::vector newMin, newMax; grid->GetUserExtents(newMin, newMax); VAssert(newMin.size() == 3 || newMax.size() == 3); for (int i = 0; i < 3; i++) { myGridMin[i] = (float)newMin[i]; myGridMax[i] = (float)newMax[i]; } myCurrentTimeStep = params->GetCurrentTimestep(); myVariableName = params->GetVariableName(); myRefinementLevel = params->GetRefinementLevel(); myCompressionLevel = params->GetCompressionLevel(); /* Update member variables */ auto gridDims = grid->GetDimensions(); dims[0] = gridDims[0]; dims[1] = gridDims[1]; dims[2] = gridDims[2]; // Save front face user coordinates ( z == dims[2] - 1 ) if (frontFace) delete[] frontFace; frontFace = new float[dims[0] * dims[1] * 3]; this->FillCoordsXYPlane(grid, dims[2] - 1, frontFace); // Save back face user coordinates ( z == 0 ) if (backFace) delete[] backFace; backFace = new float[dims[0] * dims[1] * 3]; this->FillCoordsXYPlane(grid, 0, backFace); // Save right face user coordinates ( x == dims[0] - 1 ) if (rightFace) delete[] rightFace; rightFace = new float[dims[1] * dims[2] * 3]; this->FillCoordsYZPlane(grid, dims[0] - 1, rightFace); // Save left face user coordinates ( x == 0 ) if (leftFace) delete[] leftFace; leftFace = new float[dims[1] * dims[2] * 3]; this->FillCoordsYZPlane(grid, 0, leftFace); // Save top face user coordinates ( y == dims[1] - 1 ) if (topFace) delete[] topFace; topFace = new float[dims[0] * dims[2] * 3]; this->FillCoordsXZPlane(grid, dims[1] - 1, topFace); // Save bottom face user coordinates ( y == 0 ) if (bottomFace) delete[] bottomFace; bottomFace = new float[dims[0] * dims[2] * 3]; this->FillCoordsXZPlane(grid, 0, bottomFace); // Save the data field values and missing values size_t numOfVertices = dims[0] * dims[1] * dims[2]; if (dataField) { delete[] dataField; dataField = nullptr; } try { dataField = new float[numOfVertices]; } catch (const std::bad_alloc &e) { MyBase::SetErrMsg(e.what()); return MEMERROR; } if (missingValueMask) { delete[] missingValueMask; missingValueMask = nullptr; } if (grid->HasMissingData()) { try { missingValueMask = new unsigned char[numOfVertices]; } catch (const std::bad_alloc &e) { MyBase::SetErrMsg(e.what()); return MEMERROR; } } // Now iterate the current grid this->IterateAGrid(grid, numOfVertices, dataField, missingValueMask); dataFieldUpToDate = true; return 0; } int RayCaster::UserCoordinates::Update2ndVariable(const RayCasterParams *params, DataMgr *dataMgr) { VAssert(dataFieldUpToDate); // Update 2nd variable name my2ndVarName = params->GetColorMapVariableName(); // Retrieve grid for the 2nd variable CoordType extMin, extMax; params->GetBox()->GetExtents(extMin, extMax); StructuredGrid *grid = dynamic_cast(dataMgr->GetVariable(myCurrentTimeStep, my2ndVarName, myRefinementLevel, myCompressionLevel, extMin, extMax)); if (grid == nullptr) { MyBase::SetErrMsg("The secondary variable isn't on a StructuredGrid; " "the behavior is undefined in this case."); return GRIDERROR; } // Make sure the secondary grid shares the same dimention as the primary grid auto seconDims = grid->GetDimensions(); for (int i = 0; i < 3; i++) if (seconDims[i] != dims[i]) { MyBase::SetErrMsg("The secondary and primary variable grids have different dimensions; " "the behavior is undefined in this case."); delete grid; return GRIDERROR; } // Allocate memory size_t numOfVertices = dims[0] * dims[1] * dims[2]; if (secondVarData) { delete[] secondVarData; secondVarData = nullptr; } try { secondVarData = new float[numOfVertices]; } catch (const std::bad_alloc &e) { MyBase::SetErrMsg(e.what()); delete grid; return MEMERROR; } if (secondVarMask) { delete[] secondVarMask; secondVarMask = nullptr; } if (grid->HasMissingData()) { try { secondVarMask = new unsigned char[numOfVertices]; } catch (const std::bad_alloc &e) { MyBase::SetErrMsg(e.what()); delete grid; return MEMERROR; } } // Now iterate the current grid this->IterateAGrid(grid, numOfVertices, secondVarData, secondVarMask); delete grid; secondVarUpToDate = true; return 0; } void RayCaster::UserCoordinates::IterateAGrid(const StructuredGrid *grid, size_t numOfVert, float *dataBuf, unsigned char *maskBuf) { StructuredGrid::ConstIterator valItr = grid->cbegin(); if (grid->HasMissingData()) { float missingValue = grid->GetMissingValue(); float dataValue; for (size_t i = 0; i < numOfVert; i++) { dataValue = *valItr; if (dataValue == missingValue) { dataBuf[i] = 0.0f; maskBuf[i] = 127u; } else { dataBuf[i] = dataValue; maskBuf[i] = 0u; } ++valItr; } } else { for (size_t i = 0; i < numOfVert; i++) { dataBuf[i] = *valItr; ++valItr; } } } void RayCaster::UserCoordinates::FillCoordsXYPlane(const StructuredGrid *grid, size_t planeIdx, float *coords) { size_t idx = 0; double buf[3]; for (size_t y = 0; y < dims[1]; y++) for (size_t x = 0; x < dims[0]; x++) { grid->GetUserCoordinates(x, y, planeIdx, buf[0], buf[1], buf[2]); coords[idx++] = (float)buf[0]; coords[idx++] = (float)buf[1]; coords[idx++] = (float)buf[2]; } } void RayCaster::UserCoordinates::FillCoordsYZPlane(const StructuredGrid *grid, size_t planeIdx, float *coords) { size_t idx = 0; double buf[3]; for (size_t z = 0; z < dims[2]; z++) for (size_t y = 0; y < dims[1]; y++) { grid->GetUserCoordinates(planeIdx, y, z, buf[0], buf[1], buf[2]); coords[idx++] = (float)buf[0]; coords[idx++] = (float)buf[1]; coords[idx++] = (float)buf[2]; } } void RayCaster::UserCoordinates::FillCoordsXZPlane(const StructuredGrid *grid, size_t planeIdx, float *coords) { size_t idx = 0; double buf[3]; for (size_t z = 0; z < dims[2]; z++) for (size_t x = 0; x < dims[0]; x++) { grid->GetUserCoordinates(x, planeIdx, z, buf[0], buf[1], buf[2]); coords[idx++] = (float)buf[0]; coords[idx++] = (float)buf[1]; coords[idx++] = (float)buf[2]; } } int RayCaster::UserCoordinates::UpdateVertCoords(const RayCasterParams *params, const StructuredGrid *grid, DataMgr *dataMgr) { VAssert(dataFieldUpToDate); size_t numOfVertices = dims[0] * dims[1] * dims[2]; if (vertCoords) delete[] vertCoords; try { vertCoords = new float[3 * numOfVertices]; } catch (const std::bad_alloc &e) { MyBase::SetErrMsg(e.what()); return MEMERROR; } // Gather the vertex coordinates from grid StructuredGrid::ConstCoordItr coordItr = grid->ConstCoordBegin(); for (int i = 0; i < numOfVertices; i++) { vertCoords[3 * i] = float((*coordItr)[0]); vertCoords[3 * i + 1] = float((*coordItr)[1]); vertCoords[3 * i + 2] = float((*coordItr)[2]); ++coordItr; } vertCoordsUpToDate = true; return 0; } int RayCaster::_initializeGL() { // Load 1st and 2nd pass shaders ShaderProgram *shader = nullptr; if ((shader = _glManager->shaderManager->GetShader("RayCaster1stPass"))) _1stPassShader = shader; else return GLERROR; if ((shader = _glManager->shaderManager->GetShader("RayCaster2ndPass"))) _2ndPassShader = shader; else return GLERROR; // Load 3rd pass shaders if (_load3rdPassShaders() != 0) { MyBase::SetErrMsg("Failed to load shaders!"); return GLERROR; } // Get the current viewport GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); std::memcpy(_currentViewport, viewport, 4 * sizeof(GLint)); // // Retrieved viewport may contain zero width and height sometimes. // Need to make these dimensions positive, so the initialization routine, // including the step of attaching textures to framebuffers, could complete. // Later, paintGL() will have another chance to set the correct dimensions. // The bottom line is, the rest of the class can safely assume that // _currentViewport[4] always contains non-zero dimensions. // for (int i = 2; i < 4; i++) if (_currentViewport[i] < 1) _currentViewport[i] = 8; // Create any textures, framebuffers, etc. if (_initializeFramebufferTextures() != 0) { MyBase::SetErrMsg("Failed to Create Framebuffer and Textures!"); return GLERROR; } return 0; // Success } int RayCaster::_paintGL(bool fast) { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); // When viewport has zero dimensions, bail immediately. // This happens when undo/redo is issued. if (viewport[2] < 1 || viewport[3] < 1) return 0; _updateViewportWhenNecessary(viewport); glDisable(GL_POLYGON_SMOOTH); // Collect params and grid that will be used repeatedly RayCasterParams *params = dynamic_cast(GetActiveParams()); if (!params) { MyBase::SetErrMsg("Error occured during retrieving RayCaster parameters!"); return PARAMSERROR; } // Return when there's no variable selected. if (params->GetVariableName().empty()) { MyBase::SetErrMsg("Please select a valid 3D variable for operation!"); return PARAMSERROR; } // Do not perform any fast rendering in cell traverse mode int castingMode = int(params->GetCastingMode()); if (castingMode == CellTraversal && fast) return 0; // Force casting mode to be FixedStep if on Intel GPU. if (_isIntel) { castingMode = FixedStep; params->SetCastingMode(FixedStep); } StructuredGrid *grid = nullptr; if (_userCoordinates.GetCurrentGrid(params, _dataMgr, &grid) != 0) { MyBase::SetErrMsg("Failed to retrieve a StructuredGrid"); return GRIDERROR; } if (_load3rdPassShaders() != 0) { MyBase::SetErrMsg("Failed to load shaders"); delete grid; return GLERROR; } // Use the correct shader for 3rd pass rendering if (castingMode == FixedStep) _3rdPassShader = _3rdPassMode1Shader; else if (castingMode == CellTraversal) _3rdPassShader = _3rdPassMode2Shader; else { MyBase::SetErrMsg("RayCasting Mode not supported!"); delete grid; return JUSTERROR; } // Retrieve if we're using secondary variable bool use2ndVar = _use2ndVariable(params); // Check if there is an update event _userCoordinates.CheckUpToDateStatus(params, grid, _dataMgr, use2ndVar); // Update primary variable data field if (!_userCoordinates.dataFieldUpToDate) { int success = _userCoordinates.UpdateFaceAndData(params, grid, _dataMgr); if (success != 0) { MyBase::SetErrMsg("Error occured during updating face and volume data!"); delete grid; return JUSTERROR; } // Texture for primary variable data is updated only when data changes _updateDataTextures(); } // Update vertex coordinates field only when using CellTraversal method. glm::mat4 ModelView = Renderer::_glManager->matrixManager->GetModelViewMatrix(); if (castingMode == CellTraversal) { if (!_userCoordinates.vertCoordsUpToDate) { int success = _userCoordinates.UpdateVertCoords(params, grid, _dataMgr); if (success != 0) { MyBase::SetErrMsg("Error occured during updating curvilinear coordinates!"); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, 0); glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_3D, 0); delete grid; return JUSTERROR; } } // Transform vertex coordinate data to eye space, and then send to GPU. // This step takes place at every loop. if (_updateVertCoordsTexture(ModelView) != 0) { MyBase::SetErrMsg("Error occured during calculating eye coordinates!"); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, 0); glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_3D, 0); delete grid; return MEMERROR; } } // Update secondary variable if (use2ndVar && !_userCoordinates.secondVarUpToDate) { int success = _userCoordinates.Update2ndVariable(params, _dataMgr); if (success != 0) { MyBase::SetErrMsg("Error occured during updating secondary variable!"); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, 0); glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_3D, 0); delete grid; return JUSTERROR; } } // This function has no effect for DVR. It's only usable for IsoSurface // with 2nd variable enabled. _update2ndVarTextures(); glBindVertexArray(_vertexArrayId); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferId); glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferId); glViewport(0, 0, _currentViewport[2], _currentViewport[3]); // 1st pass: render back facing polygons to texture0 of the framebuffer std::vector cameraCellIdx(0); _drawVolumeFaces(1, castingMode, cameraCellIdx); // Detect if we're inside the volume glm::mat4 InversedMV = glm::inverse(ModelView); std::vector cameraUser(4, 1.0); // current camera position in user coordinates cameraUser[0] = InversedMV[3][0]; cameraUser[1] = InversedMV[3][1]; cameraUser[2] = InversedMV[3][2]; bool insideACell = grid->GetIndicesCell(cameraUser, cameraCellIdx); if (!insideACell) cameraCellIdx.clear(); // Make sure size 0 to indicate outside of the volume // 2nd pass, render front facing polygons _drawVolumeFaces(2, castingMode, cameraCellIdx); // Update color map texture _updateColormap(params); glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset); glBindTexture(GL_TEXTURE_1D, _colorMapTextureId); glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, _colorMap.size() / 4, 0, GL_RGBA, GL_FLOAT, _colorMap.data()); glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, 0, _currentViewport[2], _currentViewport[3]); // 3rd pass, perform ray casting _drawVolumeFaces(3, castingMode, cameraCellIdx, InversedMV, fast); // Restore OpenGL values changed in this function. glBindVertexArray(0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, 0); glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_3D, 0); delete grid; return 0; } int RayCaster::_initializeFramebufferTextures() { /* Create Vertex Array Object (VAO) */ glGenVertexArrays(1, &_vertexArrayId); glGenBuffers(1, &_vertexBufferId); glGenBuffers(1, &_indexBufferId); if (!_isIntel) glGenBuffers(1, &_vertexAttribId); /* Generate and configure 2D back-facing texture */ glGenTextures(1, &_backFaceTextureId); glActiveTexture(GL_TEXTURE0 + _backFaceTexOffset); glBindTexture(GL_TEXTURE_2D, _backFaceTextureId); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, _currentViewport[2], _currentViewport[3], 0, GL_RGBA, GL_FLOAT, nullptr); this->_configure2DTextureLinearInterpolation(); /* Generate and configure 2D front-facing texture */ glGenTextures(1, &_frontFaceTextureId); glActiveTexture(GL_TEXTURE0 + _frontFaceTexOffset); glBindTexture(GL_TEXTURE_2D, _frontFaceTextureId); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, _currentViewport[2], _currentViewport[3], 0, GL_RGBA, GL_FLOAT, nullptr); this->_configure2DTextureLinearInterpolation(); /* Create an Frame Buffer Object for the front and back side of the volume. */ glGenFramebuffers(1, &_frameBufferId); glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferId); /* Set "_backFaceTextureId" as color attachement #0, and "_frontFaceTextureId" as color attachement #1. */ glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _backFaceTextureId, 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, _frontFaceTextureId, 0); GLenum drawBuffers[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; glDrawBuffers(2, drawBuffers); /* Check if framebuffer is complete */ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { MyBase::SetErrMsg("_openGLInitialization(): Framebuffer failed; " "the behavior is then undefined."); return GLERROR; } /* Bind the default frame buffer */ glBindFramebuffer(GL_FRAMEBUFFER, 0); /* Generate and configure 3D texture: _volumeTextureId */ glGenTextures(1, &_volumeTextureId); glActiveTexture(GL_TEXTURE0 + _volumeTexOffset); glBindTexture(GL_TEXTURE_3D, _volumeTextureId); this->_configure3DTextureLinearInterpolation(); /* Generate and configure 3D texture: _2ndVarDataTexId */ glGenTextures(1, &_2ndVarDataTexId); glActiveTexture(GL_TEXTURE0 + _2ndVarDataTexOffset); glBindTexture(GL_TEXTURE_3D, _2ndVarDataTexId); this->_configure3DTextureLinearInterpolation(); /* Generate and configure 1D texture: _colorMapTextureId */ glGenTextures(1, &_colorMapTextureId); glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset); glBindTexture(GL_TEXTURE_1D, _colorMapTextureId); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); /* Generate and configure 3D texture: _missingValueTextureId */ glGenTextures(1, &_missingValueTextureId); glActiveTexture(GL_TEXTURE0 + _missingValueTexOffset); glBindTexture(GL_TEXTURE_3D, _missingValueTextureId); this->_configure3DTextureNearestInterpolation(); /* Generate and configure 3D texture: _2ndVarMaskTexId */ glGenTextures(1, &_2ndVarMaskTexId); glActiveTexture(GL_TEXTURE0 + _2ndVarMaskTexOffset); glBindTexture(GL_TEXTURE_3D, _2ndVarMaskTexId); this->_configure3DTextureNearestInterpolation(); if (!_isIntel) { /* Generate 3D texture: _vertCoordsTextureId */ glGenTextures(1, &_vertCoordsTextureId); glActiveTexture(GL_TEXTURE0 + _vertCoordsTexOffset); glBindTexture(GL_TEXTURE_3D, _vertCoordsTextureId); this->_configure3DTextureNearestInterpolation(); } /* Generate and configure 2D depth texture */ glGenTextures(1, &_depthTextureId); glActiveTexture(GL_TEXTURE0 + _depthTexOffset); glBindTexture(GL_TEXTURE_2D, _depthTextureId); this->_configure2DTextureLinearInterpolation(); return 0; } void RayCaster::_configure3DTextureNearestInterpolation() const { glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); } void RayCaster::_configure3DTextureLinearInterpolation() const { glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); } void RayCaster::_configure2DTextureLinearInterpolation() const { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } void RayCaster::_drawVolumeFaces(int whichPass, int castingMode, const std::vector &cameraCellIdx, const glm::mat4 &InversedMV, bool fast) const { VAssert(cameraCellIdx.size() == 0 || cameraCellIdx.size() == 3); bool insideVolume = (cameraCellIdx.size() == 3); glm::mat4 modelview = _glManager->matrixManager->GetModelViewMatrix(); glm::mat4 projection = _glManager->matrixManager->GetProjectionMatrix(); if (whichPass == 1) { _1stPassShader->Bind(); _1stPassShader->SetUniform("MV", modelview); _1stPassShader->SetUniform("Projection", projection); glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); glEnable(GL_DEPTH_TEST); glClearDepth(0.0); glClear(GL_DEPTH_BUFFER_BIT); glDepthFunc(GL_GEQUAL); const GLfloat black[] = {0.0f, 0.0f, 0.0f, 0.0f}; glClearBufferfv(GL_COLOR, 0, black); // clear GL_COLOR_ATTACHMENT0 glDisable(GL_BLEND); // Render the back side of the volume. _renderTriangleStrips(1, castingMode); } else if (whichPass == 2) { _2ndPassShader->Bind(); _2ndPassShader->SetUniform("MV", modelview); _2ndPassShader->SetUniform("Projection", projection); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glEnable(GL_DEPTH_TEST); glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT); glDepthFunc(GL_LEQUAL); const GLfloat black[] = {0.0f, 0.0f, 0.0f, 0.0f}; glClearBufferfv(GL_COLOR, 1, black); // clear GL_COLOR_ATTACHMENT1 glDisable(GL_BLEND); // Render the front side of the volume if not inside it. // Do nothing if inside the volume. if (!insideVolume) _renderTriangleStrips(2, castingMode); } else // 3rd pass { _3rdPassShader->Bind(); _3rdPassShader->SetUniform("MV", modelview); _3rdPassShader->SetUniform("Projection", projection); _3rdPassShader->SetUniform("inversedMV", InversedMV); if (castingMode == CellTraversal) { // Upload entryCellIdx, no matter inside or outside of the volume glm::ivec3 entryCellIdx(0); if (insideVolume) { entryCellIdx.x = int(cameraCellIdx[0]); entryCellIdx.y = int(cameraCellIdx[1]); entryCellIdx.z = int(cameraCellIdx[2]); } _3rdPassShader->SetUniform("entryCellIdx", entryCellIdx); } _load3rdPassUniforms(castingMode, fast, insideVolume); _3rdPassSpecialHandling(fast, castingMode); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); // When DVR is rendered the last, it blends with previous rendering. glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Renders the near clipping plane if inside the volume. // Otherwise, render the front side of the volume. if (insideVolume) { // Transform the near clipping plane to model coordinate // 0---------2 // | | // | | // | | // 1|_______|3 GLfloat nearCoords[12]; glm::mat4 MVP = _glManager->matrixManager->GetModelViewProjectionMatrix(); glm::mat4 InversedMVP = glm::inverse(MVP); glm::vec4 topLeftNDC(-1.0f, 1.0f, -0.999f, 1.0f); glm::vec4 bottomLeftNDC(-1.0f, -1.0f, -0.999f, 1.0f); glm::vec4 topRightNDC(1.0f, 1.0f, -0.999f, 1.0f); glm::vec4 bottomRightNDC(1.0f, -1.0f, -0.999f, 1.0f); glm::vec4 nearP[4]; nearP[0] = InversedMVP * topLeftNDC; nearP[1] = InversedMVP * bottomLeftNDC; nearP[2] = InversedMVP * topRightNDC; nearP[3] = InversedMVP * bottomRightNDC; for (int i = 0; i < 4; i++) { nearP[i] /= nearP[i].w; std::memcpy(nearCoords + i * 3, glm::value_ptr(nearP[i]), 3 * sizeof(GLfloat)); } glEnableVertexAttribArray(0); // attribute 0 is vertex coordinates glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), nearCoords, GL_DYNAMIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableVertexAttribArray(0); } else { _renderTriangleStrips(3, castingMode); } } // Let's also do some clean up. glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glUseProgram(0); } void RayCaster::_load3rdPassUniforms(int castingMode, bool fast, bool insideVolume) const { ShaderProgram *shader = _3rdPassShader; shader->SetUniform("colorMapRange", glm::make_vec3(_colorMapRange)); shader->SetUniform("viewportDims", glm::ivec2(_currentViewport[2], _currentViewport[3])); const size_t *cdims = _userCoordinates.dims; glm::ivec3 volumeDims((int)cdims[0], (int)cdims[1], (int)cdims[2]); shader->SetUniform("volumeDims", volumeDims); float planes[24]; // 6 planes, each with 4 elements Renderer::GetClippingPlanes(planes); shader->SetUniformArray("clipPlanes", 6, (glm::vec4 *)planes); glm::vec3 gridMin, gridMax; for (int i = 0; i < 3; i++) { gridMin[i] = _userCoordinates.myGridMin[i]; gridMax[i] = _userCoordinates.myGridMax[i]; } if (castingMode == FixedStep) { shader->SetUniform("boxMin", gridMin); shader->SetUniform("boxMax", gridMax); } // Get light settings from params. RayCasterParams *params = dynamic_cast(GetActiveParams()); bool lighting = params->GetLighting(); if (lighting) { std::vector coeffsD = params->GetLightingCoeffs(); float coeffsF[4] = {float(coeffsD[0]), float(coeffsD[1]), float(coeffsD[2]), float(coeffsD[3])}; shader->SetUniformArray("lightingCoeffs", 4, coeffsF); } // Pack four booleans together, so there's one data transmission // to the GPU, instead of four. int flags[4] = {int(fast), int(lighting), int(insideVolume), int(_userCoordinates.missingValueMask != nullptr)}; shader->SetUniformArray("flags", 4, flags); // Calculate the step size with sample rate multiplier taken into account. float stepSize1D, multiplier = 1.0f; if (castingMode == FixedStep) switch (params->GetSampleRateMultiplier()) { case 0: multiplier = 1.0f; break; // These values need to be in sync with case 1: multiplier = 2.0f; break; // the multiplier values in the GUI. case 2: multiplier = 4.0f; break; case 3: multiplier = 0.5f; break; case 4: multiplier = 0.25f; break; case 5: multiplier = 0.125f; break; default: multiplier = 1.0f; break; } glm::vec3 dimsf((float)cdims[0], (float)cdims[1], (float)cdims[2]); float numCells = glm::length(dimsf); glm::mat4 modelview = _glManager->matrixManager->GetModelViewMatrix(); glm::vec4 tmpVec4 = modelview * glm::vec4(gridMin, 1.0); glm::vec3 gridMinEye(tmpVec4.x, tmpVec4.y, tmpVec4.z); tmpVec4 = modelview * glm::vec4(gridMax, 1.0); glm::vec3 gridMaxEye(tmpVec4.x, tmpVec4.y, tmpVec4.z); glm::vec3 diagonal = gridMaxEye - gridMinEye; if (numCells < 50.0f) // Make sure at least 100 steps stepSize1D = glm::length(diagonal) / 100.0f * multiplier; else // Use Nyquist frequency stepSize1D = glm::length(diagonal) / (numCells * 2.0f) * multiplier; if (fast && castingMode == FixedStep) stepSize1D *= 8.0f; // Increase step size, when fast rendering shader->SetUniform("stepSize1D", stepSize1D); // Pass in textures glActiveTexture(GL_TEXTURE0 + _backFaceTexOffset); glBindTexture(GL_TEXTURE_2D, _backFaceTextureId); shader->SetUniform("backFaceTexture", _backFaceTexOffset); glActiveTexture(GL_TEXTURE0 + _frontFaceTexOffset); glBindTexture(GL_TEXTURE_2D, _frontFaceTextureId); shader->SetUniform("frontFaceTexture", _frontFaceTexOffset); glActiveTexture(GL_TEXTURE0 + _volumeTexOffset); glBindTexture(GL_TEXTURE_3D, _volumeTextureId); shader->SetUniform("volumeTexture", _volumeTexOffset); glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset); glBindTexture(GL_TEXTURE_1D, _colorMapTextureId); shader->SetUniform("colorMapTexture", _colorMapTexOffset); glActiveTexture(GL_TEXTURE0 + _missingValueTexOffset); glBindTexture(GL_TEXTURE_3D, _missingValueTextureId); shader->SetUniform("missingValueMaskTexture", _missingValueTexOffset); if (castingMode == CellTraversal) { glActiveTexture(GL_TEXTURE0 + _vertCoordsTexOffset); glBindTexture(GL_TEXTURE_3D, _vertCoordsTextureId); shader->SetUniform("vertCoordsTexture", _vertCoordsTexOffset); } } void RayCaster::_3rdPassSpecialHandling(bool fast, int castingMode) const { // Left empty intentially. // Derived classes feel free to put stuff here. } void RayCaster::_renderTriangleStrips(int whichPass, int castingMode) const { /* Give bx, by, bz type of "unsigned int" for indexBuffer */ unsigned int bx = (unsigned int)_userCoordinates.dims[0]; unsigned int by = (unsigned int)_userCoordinates.dims[1]; unsigned int bz = (unsigned int)_userCoordinates.dims[2]; size_t idx; // Each strip will have the same numOfVertices for the first 4 faces size_t numOfVertices = bx * 2; unsigned int *indexBuffer = new unsigned int[numOfVertices]; std::memset(indexBuffer, 0, numOfVertices * sizeof(unsigned int)); // Create buffer object to keep indices glBufferData(GL_ELEMENT_ARRAY_BUFFER, numOfVertices * sizeof(unsigned int), indexBuffer, GL_DYNAMIC_DRAW); bool attrib1Enabled = false; // Attribute to hold provoking index of each triangle. int *attrib1Buffer = nullptr; if (castingMode == CellTraversal && whichPass == 3) { attrib1Enabled = true; attrib1Buffer = new int[bx * by * 4]; // Buffer for front and back face std::memset(attrib1Buffer, 0, bx * by * 4 * sizeof(int)); glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId); // Create buffer object to keep attributes glBufferData(GL_ARRAY_BUFFER, bx * by * 4 * sizeof(int), attrib1Buffer, GL_DYNAMIC_DRAW); } // // Render front face: // // Attribute 0 keeps all the vertex indices of the entire front face. glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); glBufferData(GL_ARRAY_BUFFER, bx * by * 3 * sizeof(float), _userCoordinates.frontFace, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); for (unsigned int y = 0; y < by - 1; y++) // Looping over every TriangleStrip { idx = 0; // // This loop controls rendering order of the triangle strip. It // provides the indices for each vertex in the current strip. // for (unsigned int x = 0; x < bx; x++) // Filling indices for vertices of this TriangleStrip { indexBuffer[idx++] = (y + 1) * bx + x; indexBuffer[idx++] = y * bx + x; } // // In cell-traverse ray casting mode we need a cell index for the // two triangles forming the face of a cell. Use the OpenGL "provoking" // vertex to provide this information. // if (attrib1Enabled) // Also specify attrib1 values { for (unsigned int x = 0; x < bx; x++) // Fill attrib1 value for each vertex { unsigned int attribIdx = ((y + 1) * bx + x) * 4; attrib1Buffer[attribIdx] = int(x) - 1; attrib1Buffer[attribIdx + 1] = int(y); attrib1Buffer[attribIdx + 2] = int(bz) - 2; attrib1Buffer[attribIdx + 3] = 0; attribIdx = (y * bx + x) * 4; attrib1Buffer[attribIdx] = int(x) - 1; attrib1Buffer[attribIdx + 1] = int(y); attrib1Buffer[attribIdx + 2] = int(bz) - 2; attrib1Buffer[attribIdx + 3] = 0; } // Update attribute 1 glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId); glBufferSubData(GL_ARRAY_BUFFER, y * bx * 4 * sizeof(int), 2 * bx * 4 * sizeof(int), (attrib1Buffer + y * bx * 4)); glVertexAttribIPointer(1, 4, GL_INT, 0, (void *)0); } // Update indices buffer glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numOfVertices * sizeof(unsigned int), indexBuffer); glDrawElements(GL_TRIANGLE_STRIP, numOfVertices, GL_UNSIGNED_INT, (void *)0); } // // Render back face: // glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); glBufferData(GL_ARRAY_BUFFER, bx * by * 3 * sizeof(float), _userCoordinates.backFace, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); for (unsigned int y = 0; y < by - 1; y++) // strip by strip { idx = 0; for (unsigned int x = 0; x < bx; x++) { indexBuffer[idx++] = y * bx + x; indexBuffer[idx++] = (y + 1) * bx + x; } if (attrib1Enabled) { for (unsigned int x = 0; x < bx; x++) { unsigned int attribIdx = (y * bx + x) * 4; attrib1Buffer[attribIdx] = int(x) - 1; attrib1Buffer[attribIdx + 1] = int(y); attrib1Buffer[attribIdx + 2] = 0; attrib1Buffer[attribIdx + 3] = 1; attribIdx = ((y + 1) * bx + x) * 4; attrib1Buffer[attribIdx] = int(x) - 1; attrib1Buffer[attribIdx + 1] = int(y); attrib1Buffer[attribIdx + 2] = 0; attrib1Buffer[attribIdx + 3] = 1; } glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId); glBufferSubData(GL_ARRAY_BUFFER, y * bx * 4 * sizeof(int), 2 * bx * 4 * sizeof(int), (attrib1Buffer + y * bx * 4)); glVertexAttribIPointer(1, 4, GL_INT, 0, (void *)0); } glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numOfVertices * sizeof(unsigned int), indexBuffer); glDrawElements(GL_TRIANGLE_STRIP, numOfVertices, GL_UNSIGNED_INT, (void *)0); } if (attrib1Enabled) { delete[] attrib1Buffer; attrib1Buffer = new int[bx * bz * 4]; // For top and bottom faces std::memset(attrib1Buffer, 0, bx * bz * 4 * sizeof(int)); glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId); // Create a new buffer object with the new size. glBufferData(GL_ARRAY_BUFFER, bx * bz * 4 * sizeof(int), attrib1Buffer, GL_DYNAMIC_DRAW); } // // Render top face: // glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); glBufferData(GL_ARRAY_BUFFER, bx * bz * 3 * sizeof(float), _userCoordinates.topFace, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); for (unsigned int z = 0; z < bz - 1; z++) { idx = 0; for (unsigned int x = 0; x < bx; x++) { indexBuffer[idx++] = z * bx + x; indexBuffer[idx++] = (z + 1) * bx + x; } if (attrib1Enabled) { for (unsigned int x = 0; x < bx; x++) { unsigned int attribIdx = (z * bx + x) * 4; attrib1Buffer[attribIdx] = int(x) - 1; attrib1Buffer[attribIdx + 1] = int(by) - 2; attrib1Buffer[attribIdx + 2] = int(z); attrib1Buffer[attribIdx + 3] = 2; attribIdx = ((z + 1) * bx + x) * 4; attrib1Buffer[attribIdx] = int(x) - 1; attrib1Buffer[attribIdx + 1] = int(by) - 2; attrib1Buffer[attribIdx + 2] = int(z); attrib1Buffer[attribIdx + 3] = 2; } glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId); glBufferSubData(GL_ARRAY_BUFFER, z * bx * 4 * sizeof(int), 2 * bx * 4 * sizeof(int), (attrib1Buffer + z * bx * 4)); glVertexAttribIPointer(1, 4, GL_INT, 0, (void *)0); } glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numOfVertices * sizeof(unsigned int), indexBuffer); glDrawElements(GL_TRIANGLE_STRIP, numOfVertices, GL_UNSIGNED_INT, (void *)0); } // // Render bottom face: // glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); glBufferData(GL_ARRAY_BUFFER, bx * bz * 3 * sizeof(float), _userCoordinates.bottomFace, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); for (unsigned int z = 0; z < bz - 1; z++) { idx = 0; for (unsigned int x = 0; x < bx; x++) { indexBuffer[idx++] = (z + 1) * bx + x; indexBuffer[idx++] = z * bx + x; } if (attrib1Enabled) { for (unsigned int x = 0; x < bx; x++) { unsigned int attribIdx = ((z + 1) * bx + x) * 4; attrib1Buffer[attribIdx] = int(x) - 1; attrib1Buffer[attribIdx + 1] = 0; attrib1Buffer[attribIdx + 2] = int(z); attrib1Buffer[attribIdx + 3] = 3; attribIdx = (z * bx + x) * 4; attrib1Buffer[attribIdx] = int(x) - 1; attrib1Buffer[attribIdx + 1] = 0; attrib1Buffer[attribIdx + 2] = int(z); attrib1Buffer[attribIdx + 3] = 3; } glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId); glBufferSubData(GL_ARRAY_BUFFER, z * bx * 4 * sizeof(int), 2 * bx * 4 * sizeof(int), (attrib1Buffer + z * bx * 4)); glVertexAttribIPointer(1, 4, GL_INT, 0, (void *)0); } glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numOfVertices * sizeof(unsigned int), indexBuffer); glDrawElements(GL_TRIANGLE_STRIP, numOfVertices, GL_UNSIGNED_INT, (void *)0); } // Each strip will have the same numOfVertices for the rest 2 faces. numOfVertices = by * 2; delete[] indexBuffer; indexBuffer = new unsigned int[numOfVertices]; std::memset(indexBuffer, 0, numOfVertices * sizeof(unsigned int)); // Re-create the index buffer object with the new size. glBufferData(GL_ELEMENT_ARRAY_BUFFER, numOfVertices * sizeof(unsigned int), indexBuffer, GL_DYNAMIC_DRAW); if (attrib1Enabled) { delete[] attrib1Buffer; attrib1Buffer = new int[by * bz * 4]; // For right and left faces std::memset(attrib1Buffer, 0, by * bz * 4 * sizeof(int)); glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId); glBufferData(GL_ARRAY_BUFFER, by * bz * 4 * sizeof(int), attrib1Buffer, GL_DYNAMIC_DRAW); } // // Render right face: // glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); glBufferData(GL_ARRAY_BUFFER, by * bz * 3 * sizeof(float), _userCoordinates.rightFace, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); for (unsigned int z = 0; z < bz - 1; z++) { idx = 0; for (unsigned int y = 0; y < by; y++) { indexBuffer[idx++] = (z + 1) * by + y; indexBuffer[idx++] = z * by + y; } if (attrib1Enabled) { for (unsigned int y = 0; y < by; y++) { unsigned int attribIdx = ((z + 1) * by + y) * 4; attrib1Buffer[attribIdx] = int(bx) - 2; attrib1Buffer[attribIdx + 1] = int(y) - 1; attrib1Buffer[attribIdx + 2] = int(z); attrib1Buffer[attribIdx + 3] = 4; attribIdx = (z * by + y) * 4; attrib1Buffer[attribIdx] = int(bx) - 2; attrib1Buffer[attribIdx + 1] = int(y) - 1; attrib1Buffer[attribIdx + 2] = int(z); attrib1Buffer[attribIdx + 3] = 4; } glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId); glBufferSubData(GL_ARRAY_BUFFER, z * by * 4 * sizeof(int), 2 * by * 4 * sizeof(int), (attrib1Buffer + z * by * 4)); glVertexAttribIPointer(1, 4, GL_INT, 0, (void *)0); } glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numOfVertices * sizeof(unsigned int), indexBuffer); glDrawElements(GL_TRIANGLE_STRIP, numOfVertices, GL_UNSIGNED_INT, (void *)0); } // // Render left face // glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); glBufferData(GL_ARRAY_BUFFER, by * bz * 3 * sizeof(float), _userCoordinates.leftFace, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); for (unsigned int z = 0; z < bz - 1; z++) { idx = 0; for (unsigned int y = 0; y < by; y++) { indexBuffer[idx++] = z * by + y; indexBuffer[idx++] = (z + 1) * by + y; } if (attrib1Enabled) { for (unsigned int y = 0; y < by; y++) { unsigned int attribIdx = (z * by + y) * 4; attrib1Buffer[attribIdx] = 0; attrib1Buffer[attribIdx + 1] = int(y) - 1; attrib1Buffer[attribIdx + 2] = int(z); attrib1Buffer[attribIdx + 3] = 5; attribIdx = ((z + 1) * by + y) * 4; attrib1Buffer[attribIdx] = 0; attrib1Buffer[attribIdx + 1] = int(y) - 1; attrib1Buffer[attribIdx + 2] = int(z); attrib1Buffer[attribIdx + 3] = 5; } glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId); glBufferSubData(GL_ARRAY_BUFFER, z * by * 4 * sizeof(int), 2 * by * 4 * sizeof(int), (attrib1Buffer + z * by * 4)); glVertexAttribIPointer(1, 4, GL_INT, 0, (void *)0); } glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numOfVertices * sizeof(unsigned int), indexBuffer); glDrawElements(GL_TRIANGLE_STRIP, numOfVertices, GL_UNSIGNED_INT, (void *)0); } if (attrib1Enabled) delete[] attrib1Buffer; delete[] indexBuffer; glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, 0); } #ifndef WIN32 double RayCaster::_getElapsedSeconds(const struct timeval *begin, const struct timeval *end) const { return (end->tv_sec - begin->tv_sec) + ((end->tv_usec - begin->tv_usec) / 1000000.0); } #endif void RayCaster::_updateViewportWhenNecessary(const GLint *viewport) { if ((std::memcmp(viewport, _currentViewport, 4 * sizeof(GLint)) != 0)) { std::memcpy(_currentViewport, viewport, 4 * sizeof(GLint)); // Re-size 1st and 2nd pass rendering 2D textures glActiveTexture(GL_TEXTURE0 + _backFaceTexOffset); glBindTexture(GL_TEXTURE_2D, _backFaceTextureId); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, _currentViewport[2], _currentViewport[3], 0, GL_RGBA, GL_FLOAT, nullptr); glActiveTexture(GL_TEXTURE0 + _frontFaceTexOffset); glBindTexture(GL_TEXTURE_2D, _frontFaceTextureId); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, _currentViewport[2], _currentViewport[3], 0, GL_RGBA, GL_FLOAT, nullptr); } } void RayCaster::_updateColormap(RayCasterParams *params) { if (params->UseSingleColor()) { float singleColor[4]; params->GetConstantColor(singleColor); singleColor[3] = 1.0f; // 1.0 in alpha channel _colorMap.resize(8); // _colorMap will have 2 RGBA values for (int i = 0; i < 8; i++) _colorMap[i] = singleColor[i % 4]; _colorMapRange[0] = 0.0f; // min value of the color map _colorMapRange[1] = 0.0f; // max value of the color map _colorMapRange[2] = 1e-5f; // diff of color map. Has to be non-zero though. } else { // Subclasses will have a chance here to use their own colormaps. _colormapSpecialHandling(); } } void RayCaster::_colormapSpecialHandling() { // Left empty intentionally. // Subclasses, e.g., IsoSurfaceRenderer and DVRenderer, feel free to implement it. } bool RayCaster::_use2ndVariable(const RayCasterParams *params) const { // By default a ray caster does not use a secondary variable. // Subclasses can take advantage of it, for example, an IsoSurface Renderer. return false; } void RayCaster::_update2ndVarTextures() { // Intentionally left empty } void RayCaster::_updateDataTextures() { const size_t *dims = _userCoordinates.dims; glActiveTexture(GL_TEXTURE0 + _volumeTexOffset); glBindTexture(GL_TEXTURE_3D, _volumeTextureId); #ifdef Darwin // // Intel driver on MacOS seems to not able to correctly update the texture content // when the texture is moderately big. This workaround of loading a dummy texture // to force it to update seems to resolve this issue. // float dummyVolume[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, 2, 2, 2, 0, GL_RED, GL_FLOAT, dummyVolume); #endif glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, dims[0], dims[1], dims[2], 0, GL_RED, GL_FLOAT, _userCoordinates.dataField); // Now we HAVE TO attach a missing value mask texture, because // Intel driver on Mac doesn't like leaving the texture empty... glActiveTexture(GL_TEXTURE0 + _missingValueTexOffset); glBindTexture(GL_TEXTURE_3D, _missingValueTextureId); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Alignment adjustment. Stupid OpenGL thing. if (_userCoordinates.missingValueMask) { glTexImage3D(GL_TEXTURE_3D, 0, GL_R8UI, dims[0], dims[1], dims[2], 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, _userCoordinates.missingValueMask); } else { unsigned char dummyMask[8] = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}; glTexImage3D(GL_TEXTURE_3D, 0, GL_R8UI, 2, 2, 2, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dummyMask); } glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // Restore default alignment. } int RayCaster::_updateVertCoordsTexture(const glm::mat4 &MV) { // Step zero: see if MV is the same as it was from the last iteration. // If so, return directly without updating these coordinates. glm::bvec4 columeEqual = glm::equal(_currentMV, MV); if (glm::all(columeEqual)) return 0; // Now we need to calculate and upload the new vertex coordinates // First, transform every vertex coordinate to the eye space size_t numOfVertices = _userCoordinates.dims[0] * _userCoordinates.dims[1] * _userCoordinates.dims[2]; float *coordEye = nullptr; try { coordEye = new float[3 * numOfVertices]; } catch (const std::bad_alloc &e) { MyBase::SetErrMsg(e.what()); return MEMERROR; } glm::vec4 posModel(1.0f); float * posModelPtr = glm::value_ptr(posModel); for (size_t i = 0; i < numOfVertices; i++) { std::memcpy(posModelPtr, _userCoordinates.vertCoords + 3 * i, 3 * sizeof(float)); glm::vec4 posEye = MV * posModel; std::memcpy(coordEye + 3 * i, glm::value_ptr(posEye), 3 * sizeof(float)); } posModelPtr = nullptr; // Second, send these eye coordinates to the GPU glActiveTexture(GL_TEXTURE0 + _vertCoordsTexOffset); glBindTexture(GL_TEXTURE_3D, _vertCoordsTextureId); #ifdef Darwin // Apply a dummy texture float dummyVolume[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, 2, 2, 2, 0, GL_RED, GL_FLOAT, dummyVolume); #endif // Test if the existing texture has the same dimensions. // If so, simply substitute its content. // If not, create a new object. int width, height, depth; glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &width); glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &height); glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &depth); if ((size_t)width == _userCoordinates.dims[0] && (size_t)height == _userCoordinates.dims[1] && (size_t)depth == _userCoordinates.dims[2]) { glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, width, height, depth, GL_RGB, GL_FLOAT, coordEye); } else { glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB32F, _userCoordinates.dims[0], _userCoordinates.dims[1], _userCoordinates.dims[2], 0, GL_RGB, GL_FLOAT, coordEye); } // Don't forget to update the cached model view matrix _currentMV = MV; delete[] coordEye; return 0; } int RayCaster::_selectDefaultCastingMethod() const { RayCasterParams *params = dynamic_cast(GetActiveParams()); if (!params) { MyBase::SetErrMsg("Error occured during retrieving RayCaster parameters!"); return PARAMSERROR; } if (_isIntel) { params->SetCastingMode(FixedStep); return 0; } // If params already contain a value of mode 1 or 2, then do nothing. // This case happens when loading params from a session file. int castingMode = int(params->GetCastingMode()); if (castingMode == FixedStep || castingMode == CellTraversal) return 0; // castingMode == 0 if not initialized before. Let's figure out what value it should have. StructuredGrid *grid = nullptr; if (_userCoordinates.GetCurrentGrid(params, _dataMgr, &grid) != 0) { MyBase::SetErrMsg("Failed to retrieve a StructuredGrid"); return GRIDERROR; } // // In case of a regular grid, use "fixed step" ray casting. // In other cases, use "cell traversal" ray casting. // RegularGrid *regular = dynamic_cast(grid); if (regular) params->SetCastingMode(FixedStep); else params->SetCastingMode(CellTraversal); delete grid; return 0; } void RayCaster::_sleepAWhile() const { #ifdef WIN32 glFinish(); Sleep(1); // 1 milliseconds #else struct timespec req, rem; req.tv_sec = 0; req.tv_nsec = 1000000L; // 1 milliseconds glFinish(); nanosleep(&req, &rem); #endif } ================================================ FILE: lib/render/Renderer.cpp ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: Renderer.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: September 2004 // // Description: Implements the Renderer class. // A pure virtual class that is implemented for each renderer. // Methods are called by the Visualizer class as needed. // #include #include #include #include #include #include // Must be included first!!! #include #include #include #include "vapor/GLManager.h" #include "vapor/FontManager.h" #include "vapor/LegacyGL.h" #include "vapor/TextLabel.h" #include #include #include #include using namespace VAPoR; const int Renderer::_imgWid = 256; const int Renderer::_imgHgt = 256; Renderer::Renderer(const ParamsMgr *pm, string winName, string dataSetName, string paramsType, string classType, string instName, DataMgr *dataMgr) : RendererBase(pm, winName, dataSetName, paramsType, classType, instName, dataMgr) { // Establish the data sources for the rendering: // _colorbarTexture = 0; _timestep = 0; _fontName = "arimo"; } RendererBase::RendererBase(const ParamsMgr *pm, string winName, string dataSetName, string paramsType, string classType, string instName, DataMgr *dataMgr) { // Establish the data sources for the rendering: // _paramsMgr = pm; _winName = winName; _dataSetName = dataSetName; _paramsType = paramsType; _classType = classType; _instName = instName; _dataMgr = dataMgr; _glManager = nullptr; _glInitialized = false; _flaggedForDeletion = false; } // Destructor RendererBase::~RendererBase() {} void RendererBase::FlagForDeletion() { _flaggedForDeletion = true; } bool RendererBase::IsFlaggedForDeletion() const { return _flaggedForDeletion; } // Destructor Renderer::~Renderer() { if (_colorbarTexture) delete _colorbarTexture; } int RendererBase::initializeGL(GLManager *glManager) { _glManager = glManager; int rc = _initializeGL(); if (rc < 0) { return (rc); } vector status; bool ok = oglStatusOK(status); if (!ok) { SetErrMsg("OpenGL error : %s", oglGetErrMsg(status).c_str()); return (-1); } _glInitialized = true; return (0); } double Renderer::GetDefaultZ(DataMgr *dataMgr, size_t ts) const { const RenderParams *rParams = GetActiveParams(); int refLevel = rParams->GetRefinementLevel(); int lod = rParams->GetCompressionLevel(); return DataMgrUtils::Get2DRendererDefaultZ(dataMgr, ts, refLevel, lod); } int Renderer::paintGL(bool fast) { const RenderParams *rParams = GetActiveParams(); MatrixManager * mm = _glManager->matrixManager; if (!rParams->IsEnabled()) return (0); _timestep = rParams->GetCurrentTimestep(); mm->MatrixModeModelView(); mm->PushMatrix(); ApplyTransform(_glManager->matrixManager); int rc = _paintGL(fast); mm->PopMatrix(); if (rc < 0) { return (-1); } vector status; bool ok = oglStatusOK(status); if (!ok) { SetErrMsg("%s", oglGetErrMsg(status).c_str()); return (-1); } return (0); } void Renderer::ApplyTransform(MatrixManager *mm) const { ApplyTransform(mm, GetDatasetTransform(), GetActiveParams()->GetTransform()); } void Renderer::ApplyTransform(MatrixManager *mm, const Transform *dataset, const Transform *renderer) { vector translate = renderer->GetTranslations(); vector rotate = renderer->GetRotations(); vector scale = renderer->GetScales(); vector origin = renderer->GetOrigin(); VAssert(translate.size() == 3); VAssert(rotate.size() == 3); VAssert(scale.size() == 3); VAssert(origin.size() == 3); vector datasetScales = dataset->GetScales(); mm->Translate(translate[0], translate[1], translate[2]); mm->Scale(1 / datasetScales[0], 1 / datasetScales[1], 1 / datasetScales[2]); mm->Translate(origin[0], origin[1], origin[2]); mm->Rotate(glm::radians(rotate[0]), 1, 0, 0); mm->Rotate(glm::radians(rotate[1]), 0, 1, 0); mm->Rotate(glm::radians(rotate[2]), 0, 0, 1); mm->Scale(scale[0], scale[1], scale[2]); mm->Translate(-origin[0], -origin[1], -origin[2]); mm->Scale(datasetScales[0], datasetScales[1], datasetScales[2]); } void Renderer::ApplyDatasetTransform(GLManager *gl, const Transform *t) { MatrixManager *mm = gl->matrixManager; vector scales, rotations, translations, origin; VAssert(t); scales = t->GetScales(); rotations = t->GetRotations(); translations = t->GetTranslations(); origin = t->GetOrigin(); mm->Translate(origin[0], origin[1], origin[2]); mm->Rotate(glm::radians(rotations[0]), 1, 0, 0); mm->Rotate(glm::radians(rotations[1]), 0, 1, 0); mm->Rotate(glm::radians(rotations[2]), 0, 0, 1); mm->Scale(scales[0], scales[1], scales[2]); mm->Translate(-origin[0], -origin[1], -origin[2]); mm->Translate(translations[0], translations[1], translations[2]); } void Renderer::EnableClipToBox(ShaderProgram *shader, float haloFrac) const { shader->Bind(); VAssert(shader->HasUniform("clippingPlanes")); float x0Plane[] = {1.0, 0.0, 0.0, 0.0}; float x1Plane[] = {-1.0, 0.0, 0.0, 0.0}; float y0Plane[] = {0.0, 1.0, 0.0, 0.0}; float y1Plane[] = {0.0, -1.0, 0.0, 0.0}; float z0Plane[] = {0.0, 0.0, 1.0, 0.0}; float z1Plane[] = {0.0, 0.0, -1.0, 0.0}; // z largest const RenderParams *rParams = GetActiveParams(); vector minExts, maxExts; rParams->GetBox()->GetExtents(minExts, maxExts); VAssert(minExts.size() == maxExts.size()); VAssert(minExts.size() > 0 && minExts.size() < 4); int orientation = rParams->GetBox()->GetOrientation(); for (int i = 0; i < minExts.size(); i++) { double range = maxExts[i] - minExts[i]; if (fabs(range) <= FLT_EPSILON) range = 1.0; float halo = range * haloFrac; minExts[i] -= halo; maxExts[i] += halo; } if (minExts.size() == 3 || orientation != Box::YZ) { x0Plane[3] = -minExts[0]; x1Plane[3] = maxExts[0]; glEnable(GL_CLIP_DISTANCE0); glEnable(GL_CLIP_DISTANCE1); shader->SetUniform("clippingPlanes[0]", glm::make_vec4(x0Plane)); shader->SetUniform("clippingPlanes[1]", glm::make_vec4(x1Plane)); } if (minExts.size() == 3 || orientation != Box::XZ) { y0Plane[3] = -minExts[1]; y1Plane[3] = maxExts[1]; glEnable(GL_CLIP_DISTANCE2); glEnable(GL_CLIP_DISTANCE3); shader->SetUniform("clippingPlanes[2]", glm::make_vec4(y0Plane)); shader->SetUniform("clippingPlanes[3]", glm::make_vec4(y1Plane)); } if (minExts.size() == 3 || orientation != Box::XY) { z0Plane[3] = -minExts[2]; z1Plane[3] = maxExts[2]; glEnable(GL_CLIP_DISTANCE4); glEnable(GL_CLIP_DISTANCE5); shader->SetUniform("clippingPlanes[4]", glm::make_vec4(z0Plane)); shader->SetUniform("clippingPlanes[5]", glm::make_vec4(z1Plane)); } } void Renderer::DisableClippingPlanes() { glDisable(GL_CLIP_DISTANCE0); glDisable(GL_CLIP_DISTANCE1); glDisable(GL_CLIP_DISTANCE2); glDisable(GL_CLIP_DISTANCE3); glDisable(GL_CLIP_DISTANCE4); glDisable(GL_CLIP_DISTANCE5); } bool Renderer::VariableExists(size_t ts, std::vector &varnames, int level, int lod, bool zeroOK) const { for (int i = 0; i < varnames.size(); i++) { if (zeroOK && (varnames[i] == "" || varnames[i] == "")) { continue; } if (!_dataMgr->VariableExists(ts, varnames[i], level, lod)) { return (false); } } return (true); } #ifdef VAPOR3_0_0_ALPHA void Renderer::buildLocal2DTransform(int dataOrientation, float a[2], float b[2], float *constVal, int mappedDims[3]) { mappedDims[2] = dataOrientation; mappedDims[0] = (dataOrientation == 0) ? 1 : 0; // x or y mappedDims[1] = (dataOrientation < 2) ? 2 : 1; // z or y const RenderParams *rParams = GetActiveParams(); const vector &exts = rParams->GetBox()->GetLocalExtents(); *constVal = exts[dataOrientation]; // constant terms go to middle b[0] = 0.5 * (exts[mappedDims[0]] + exts[3 + mappedDims[0]]); b[1] = 0.5 * (exts[mappedDims[1]] + exts[3 + mappedDims[1]]); // linear terms send -1,1 to box min,max a[0] = b[0] - exts[mappedDims[0]]; a[1] = b[1] - exts[mappedDims[1]]; } void Renderer::getLocalContainingRegion(float regMin[3], float regMax[3]) { // Determine the smallest axis-aligned cube that contains the rotated box local coordinates. This is // obtained by mapping all 8 corners into the space. double transformMatrix[12]; // Set up to transform from probe (coords [-1,1]) into volume: GetActiveParams()->GetBox()->buildLocalCoordTransform(transformMatrix, 0.f, -1); const double *sizes = _dataStatus->getFullSizes(); // Calculate the normal vector to the probe plane: double zdir[3] = {0.f, 0.f, 1.f}; double normEnd[3]; // This will be the unit normal double normBeg[3]; double zeroVec[3] = {0.f, 0.f, 0.f}; vtransform(zdir, transformMatrix, normEnd); vtransform(zeroVec, transformMatrix, normBeg); vsub(normEnd, normBeg, normEnd); vnormal(normEnd); // Start by initializing extents, and variables that will be min,max for (int i = 0; i < 3; i++) { regMin[i] = FLT_MAX; regMax[i] = -FLT_MAX; } for (int corner = 0; corner < 8; corner++) { int intCoord[3]; double startVec[3], resultVec[3]; intCoord[0] = corner % 2; intCoord[1] = (corner / 2) % 2; intCoord[2] = (corner / 4) % 2; for (int i = 0; i < 3; i++) startVec[i] = -1.f + (float)(2.f * intCoord[i]); // calculate the mapping of this corner, vtransform(startVec, transformMatrix, resultVec); // force mapped corner to lie in the local extents // and then force box to contain the corner: for (int i = 0; i < 3; i++) { // force to lie in domain if (resultVec[i] < 0.) resultVec[i] = 0.; if (resultVec[i] > sizes[i]) resultVec[i] = sizes[i]; if (resultVec[i] < regMin[i]) regMin[i] = resultVec[i]; if (resultVec[i] > regMax[i]) regMax[i] = resultVec[i]; } } return; } #endif std::string Renderer::_getColorbarVariableName() const { RenderParams *rParams = GetActiveParams(); return rParams->GetVariableName(); } void Renderer::renderColorbar() { RenderParams *rParams = GetActiveParams(); if (!rParams->IsEnabled()) return; // If constant color, no valid colorbar VolumeIsoParams *vip; if ((vip = dynamic_cast(rParams))) if (!vip->GetValueLong(VolumeParams::UseColormapVariableTag, 0)) return; ColorbarRenderer::Render(_glManager, rParams); } ////////////////////////////////////////////////////////////////////////// // // RendererFactory Class // ///////////////////////////////////////////////////////////////////////// RendererFactory *RendererFactory::Instance() { static RendererFactory instance; return &instance; } void RendererFactory::RegisterFactoryFunction(string myName, string myParamsName, function classFactoryFunction) { // register the class factory function _factoryFunctionRegistry[myName] = classFactoryFunction; _factoryMapRegistry[myName] = myParamsName; } Renderer *RendererFactory::CreateInstance(const ParamsMgr *pm, string winName, string dataSetName, string classType, string instName, DataMgr *dataMgr) { Renderer *instance = NULL; // find classType in the registry and call factory method. // auto it = _factoryFunctionRegistry.find(classType); if (it != _factoryFunctionRegistry.end()) { instance = it->second(pm, winName, dataSetName, classType, instName, dataMgr); } if (instance != NULL) return instance; else return NULL; } string RendererFactory::GetRenderClassFromParamsClass(string paramsClass) const { map::const_iterator itr; for (itr = _factoryMapRegistry.begin(); itr != _factoryMapRegistry.end(); ++itr) { if (itr->second == paramsClass) return (itr->first); } return (""); } string RendererFactory::GetParamsClassFromRenderClass(string renderClass) const { map::const_iterator itr; for (itr = _factoryMapRegistry.begin(); itr != _factoryMapRegistry.end(); ++itr) { if (itr->first == renderClass) return (itr->second); } return (""); } vector RendererFactory::GetFactoryNames() const { vector names; map>::const_iterator itr; for (itr = _factoryFunctionRegistry.begin(); itr != _factoryFunctionRegistry.end(); ++itr) { names.push_back(itr->first); } return (names); } void Renderer::GetClippingPlanes(float planes[24]) const { float x0Plane[4] = {1.0, 0.0, 0.0, 0.0}; float x1Plane[4] = {-1.0, 0.0, 0.0, 0.0}; float y0Plane[4] = {0.0, 1.0, 0.0, 0.0}; float y1Plane[4] = {0.0, -1.0, 0.0, 0.0}; float z0Plane[4] = {0.0, 0.0, 1.0, 0.0}; float z1Plane[4] = {0.0, 0.0, -1.0, 0.0}; const RenderParams *rParams = GetActiveParams(); std::vector minExts, maxExts; rParams->GetBox()->GetExtents(minExts, maxExts); VAssert(minExts.size() == maxExts.size()); VAssert(minExts.size() == 2 || minExts.size() == 3); x0Plane[3] = float(-minExts[0]); x1Plane[3] = float(maxExts[0]); y0Plane[3] = float(-minExts[1]); y1Plane[3] = float(maxExts[1]); if (minExts.size() == 3) // Fill normal Z extents { z0Plane[3] = float(-minExts[2]); z1Plane[3] = float(maxExts[2]); } else // Fill a thin layer around DefaultZ { const auto dfz = this->GetDefaultZ(_dataMgr, rParams->GetCurrentTimestep()); const auto z1 = dfz * 1.0001; const auto z2 = dfz * 0.9999; z0Plane[3] = -std::min(z1, z2); z1Plane[3] = std::max(z1, z2); } size_t planeSize = sizeof(x0Plane); std::memcpy(planes, x0Plane, planeSize); std::memcpy(planes + 4, x1Plane, planeSize); std::memcpy(planes + 8, y0Plane, planeSize); std::memcpy(planes + 12, y1Plane, planeSize); std::memcpy(planes + 16, z0Plane, planeSize); std::memcpy(planes + 20, z1Plane, planeSize); } RendererFactory::RendererFactory() {} RendererFactory::RendererFactory(const RendererFactory &) {} RendererFactory &RendererFactory::operator=(const RendererFactory &) { return *this; } ================================================ FILE: lib/render/Shader.cpp ================================================ #include "vapor/glutil.h" #include #include #include "vapor/VAssert.h" #include "vapor/Shader.h" using namespace VAPoR; Shader::Shader(unsigned int type) : _id(0), _successStatus(0), _compiled(false), _type(type) {} Shader::~Shader() { if (_id) glDeleteShader(_id); } int Shader::CompileFromSource(const std::string &source_) { string source = source_; #ifndef NDEBUG // Prevent caching source += "\n// " + std::to_string(time(NULL)); #endif VAssert(!_compiled); char *buffer = new char[source.length() + 1]; strcpy(buffer, source.c_str()); _id = glCreateShader(_type); glShaderSource(_id, 1, &buffer, NULL); glCompileShader(_id); glGetShaderiv(_id, GL_COMPILE_STATUS, &_successStatus); _compiled = true; delete[] buffer; if (!_successStatus) { SetErrMsg("--------------- Shader Compilation Failed ---------------\n" "%s" "---------------------------------------------------------\n", GetLog().c_str()); return -1; } return 1; } std::string Shader::GetLog() const { char buf[512]; glGetShaderInfoLog(_id, 512, NULL, buf); return std::string(buf); } unsigned int Shader::GetID() const { return _id; } unsigned int Shader::GetType() const { return _type; } bool Shader::WasCompilationSuccessful() const { return _successStatus; } ================================================ FILE: lib/render/ShaderManager.cpp ================================================ #include "vapor/glutil.h" #include "vapor/ShaderManager.h" #include #include "vapor/FileUtils.h" #include #include using namespace VAPoR; using namespace Wasp; using namespace STLUtils; using std::map; using std::pair; using std::string; using std::vector; #define SHADER_AUTORELOAD 1 #ifdef NDEBUG #if SHADER_AUTORELOAD #ifndef WIN32 //#warning Disabling shader autoreloading #endif #undef SHADER_AUTORELOAD #endif #endif std::vector ShaderManager::_getSourceFilePaths(const std::string &name) const { vector paths; paths.push_back(GetSharePath("shaders/" + name + ".vert")); paths.push_back(GetSharePath("shaders/" + name + ".frag")); string geomPath = GetSharePath("shaders/" + name + ".geom"); if (FileUtils::Exists(geomPath)) paths.push_back(geomPath); return paths; } bool ShaderManager::_wasFileModified(const std::string &path) const { return false; } std::string ShaderManager::_getNameFromKey(const std::string &key) { return Split(key, ":")[0]; } std::vector ShaderManager::_getDefinesFromKey(const std::string &key) { vector defines = Split(key, ":"); defines.erase(defines.begin()); return defines; } ShaderProgram *ShaderManager::GetShader(const std::string &key) { #if SHADER_AUTORELOAD if (!_dependencyModifiedTimes.count(key)) { vector paths = _getSourceFilePaths(_getNameFromKey(key)); vector deps; map times; for (const string &path : paths) STLUtils::AppendTo(deps, GetShaderDependencies(path)); for (const string &path : deps) times[path] = FileUtils::GetFileModifiedTime(path); _dependencyModifiedTimes[key] = times; } bool reload = false; for (auto &pair : _dependencyModifiedTimes[key]) { long mtime = FileUtils::GetFileModifiedTime(pair.first); if (mtime > pair.second) { // printf("Reload \"%s\"\n", pair.first.c_str()); pair.second = mtime; reload = true; } } if (HasResource(key)) { bool rebind = false; int boundProgram; glGetIntegerv(GL_CURRENT_PROGRAM, &boundProgram); if (reload && GetResource(key)->GetID() == boundProgram) rebind = true; if (reload) DeleteResource(key); ShaderProgram *shader = GetResource(key); if (rebind) shader->Bind(); return shader; } #endif return GetResource(key); } SmartShaderProgram ShaderManager::GetSmartShader(const std::string &name) { return SmartShaderProgram(GetShader(name)); } #include int ShaderManager::LoadResourceByKey(const std::string &key) { // printf("Begin Compile %s\n", key.c_str()); // void *t = GLManager::BeginTimer(); if (HasResource(key)) { VAssert(!"Shader already loaded"); return -1; } const vector defines = _getDefinesFromKey(key); ShaderProgram * program = new ShaderProgram; const vector paths = _getSourceFilePaths(_getNameFromKey(key)); for (auto it = paths.begin(); it != paths.end(); ++it) { program->AddShader(CompileNewShaderFromFile(*it, defines)); } program->Link(); if (!program->WasLinkingSuccessful()) { SetErrMsg("Failed to link shader:\n%s", program->GetLog().c_str()); delete program; return -1; } AddResource(key, program); // printf("End Compile %f\n", GLManager::EndTimer(t)); return 1; } Shader *ShaderManager::CompileNewShaderFromFile(const std::string &path, const std::vector &defines) { unsigned int shaderType = GetShaderTypeFromPath(path); if (shaderType == GL_INVALID_ENUM) { SetErrMsg("File \"%s\" does not have a valid shader file extension", FileUtils::Basename(path).c_str()); return nullptr; } if (!FileUtils::IsRegularFile(path)) { SetErrMsg("Path \"%s\" is not a valid file", path.c_str()); return nullptr; } Shader *shader = new Shader(shaderType); int compilationSuccess = shader->CompileFromSource(PreProcessShader(path, defines)); if (compilationSuccess < 0) { SetErrMsg("Shader \"%s\" failed to compile", FileUtils::Basename(path).c_str()); delete shader; return nullptr; } return shader; } unsigned int ShaderManager::GetShaderTypeFromPath(const std::string &path) { string ext = FileUtils::Extension(path); if (ext == "vert") return GL_VERTEX_SHADER; if (ext == "frag") return GL_FRAGMENT_SHADER; if (ext == "geom") return GL_GEOMETRY_SHADER; return GL_INVALID_ENUM; } std::string ShaderManager::PreProcessShader(const std::string &path, const std::vector &defines) { string source = FileUtils::ReadFileToString(path); auto lines = Split(source, "\n"); int lineNum = 1; for (string &line : lines) { if (BeginsWith(line, "#")) { if (BeginsWith(line, "#pragma auto_version")) { line = "#version "; line += std::to_string(GLManager::GetGLSLVersion()); line += " core"; } if (!defines.empty() && BeginsWith(line, "#version ")) { line += "\n"; for (const string &define : defines) { line += "#define " + define + "\n"; } line += "#line " + std::to_string(lineNum + 1) + " 0"; } if (BeginsWith(line, "#include ")) { VAssert(Split(line, " ").size() == 2); line = "#line 1 1\n" + PreProcessShader(GetSharePath("shaders/" + Split(line, " ")[1])); // Sometimes, the reported line number for a syntax error will be incorrect. // This is a bug in the glsl compiler. line += "\n#line " + std::to_string(lineNum + 1) + " 0"; } } lineNum++; } return Join(lines, "\n"); } std::vector ShaderManager::GetShaderDependencies(const std::string &path) { vector deps = {path}; string source = FileUtils::ReadFileToString(path); auto lines = Split(source, "\n"); for (const string &line : lines) { if (BeginsWith(line, "#include ")) { auto args = Split(line, " "); VAssert(args.size() == 2); string include = args[1]; STLUtils::AppendTo(deps, GetShaderDependencies(GetSharePath("shaders/" + include))); } } return deps; } ================================================ FILE: lib/render/ShaderProgram.cpp ================================================ #include "vapor/glutil.h" // Must be included first!!! #include "vapor/ShaderProgram.h" #include "vapor/FileUtils.h" #include "vapor/VAssert.h" #include #include #include #include using namespace VAPoR; using std::string; using std::vector; ShaderProgram::Policy ShaderProgram::UniformNotFoundPolicy = ShaderProgram::Policy::Relaxed; ShaderProgram::ShaderProgram() : _linked(false), _successStatus(false) {} ShaderProgram::~ShaderProgram() { if (_id) glDeleteProgram(_id); for (int i = 0; i < _shaders.size(); i++) if (_shaders[i]) delete _shaders[i]; } int ShaderProgram::Link() { if (_linked) { return 1; } _id = glCreateProgram(); VAssert(_id); for (auto it = _shaders.begin(); it != _shaders.end(); it++) { if (*it == nullptr || !(*it)->WasCompilationSuccessful()) { return -1; } glAttachShader(_id, (*it)->GetID()); } glLinkProgram(_id); glGetProgramiv(_id, GL_LINK_STATUS, &_successStatus); _linked = true; for (int i = 0; i < _shaders.size(); i++) { delete _shaders[i]; } _shaders.clear(); if (!_successStatus) return -1; ComputeSamplerLocations(); return 1; } void ShaderProgram::Bind() { if (WasLinkingSuccessful()) glUseProgram(_id); } bool ShaderProgram::IsBound() const { return _id == GetBoundProgramID(); } void ShaderProgram::UnBind() { glUseProgram(0); } int ShaderProgram::GetBoundProgramID() { int currentlyBoundProgramId; glGetIntegerv(GL_CURRENT_PROGRAM, ¤tlyBoundProgramId); return currentlyBoundProgramId; } void ShaderProgram::AddShader(Shader *s) { if (_linked) { SetErrMsg("Program already linked"); return; } _shaders.push_back(s); } int ShaderProgram::AddShaderFromSource(unsigned int type, const char *source) { Shader *s = new Shader(type); int ret = s->CompileFromSource(source); _shaders.push_back(s); return ret; } /* bool ShaderProgram::AddShaderFromFile(unsigned int type, const std::string path) { Shader *s = new Shader(type); bool ret = s->CompileFromSource(FileUtils::ReadFileToString(path)); _shaders.push_back(s); return ret; } */ unsigned int ShaderProgram::GetID() const { return _id; } unsigned int ShaderProgram::WasLinkingSuccessful() const { return _successStatus; } int ShaderProgram::GetAttributeLocation(const std::string &name) const { return glGetAttribLocation(_id, name.c_str()); } int ShaderProgram::GetUniformLocation(const std::string &name) const { return glGetUniformLocation(_id, name.c_str()); } bool ShaderProgram::HasUniform(const std::string &name) const { return GetUniformLocation(name) != -1; } template bool ShaderProgram::SetUniform(const std::string &name, const T &value) const { // if ((typeid(T) == typeid(int)) && _samplerLocations.count(name)) printf("%s set to %i\n", name.c_str(), *(int*)((void*)&value)); if (!IsBound()) { VAssert(!"Program not bound"); return false; } const int location = glGetUniformLocation(_id, name.c_str()); if (location == -1) { // printf("Uniform \"%s\" not found\n", name.c_str()); if (UniformNotFoundPolicy == Policy::Strict) VAssert(!"Uniform name not found"); return false; } SetUniform(location, value); return true; } template bool ShaderProgram::SetUniform(const std::string &name, const int &value) const; template bool ShaderProgram::SetUniform(const std::string &name, const bool &value) const; template bool ShaderProgram::SetUniform(const std::string &name, const float &value) const; template bool ShaderProgram::SetUniform(const std::string &name, const glm::vec2 &value) const; template bool ShaderProgram::SetUniform(const std::string &name, const glm::vec3 &value) const; template bool ShaderProgram::SetUniform(const std::string &name, const glm::vec4 &value) const; template bool ShaderProgram::SetUniform(const std::string &name, const glm::mat4 &value) const; template bool ShaderProgram::SetUniform(const std::string &name, const glm::ivec2 &value) const; template bool ShaderProgram::SetUniform(const std::string &name, const glm::ivec3 &value) const; template bool ShaderProgram::SetUniform>(const std::string &name, const vector &value) const; void ShaderProgram::SetUniform(int location, const int &value) const { glUniform1i(location, value); } void ShaderProgram::SetUniform(int location, const float &value) const { glUniform1f(location, value); } void ShaderProgram::SetUniform(int location, const glm::vec2 &value) const { glUniform2fv(location, 1, glm::value_ptr(value)); } void ShaderProgram::SetUniform(int location, const glm::vec3 &value) const { glUniform3fv(location, 1, glm::value_ptr(value)); } void ShaderProgram::SetUniform(int location, const glm::vec4 &value) const { glUniform4fv(location, 1, glm::value_ptr(value)); } void ShaderProgram::SetUniform(int location, const glm::mat4 &value) const { glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value)); } void ShaderProgram::SetUniform(int location, const glm::ivec2 &value) const { glUniform2iv(location, 1, glm::value_ptr(value)); } void ShaderProgram::SetUniform(int location, const glm::ivec3 &value) const { glUniform3iv(location, 1, glm::value_ptr(value)); } void ShaderProgram::SetUniform(int location, const vector &value) const { glUniform1fv(location, value.size(), value.data()); } template void ShaderProgram::SetUniformArray(const std::string &name, int count, const T *values) const { SetUniformArray(GetUniformLocation(name), count, values); } template void ShaderProgram::SetUniformArray(const std::string &name, int count, const int *values) const; template void ShaderProgram::SetUniformArray(const std::string &name, int count, const float *values) const; template void ShaderProgram::SetUniformArray(const std::string &name, int count, const glm::vec3 *values) const; template void ShaderProgram::SetUniformArray(const std::string &name, int count, const glm::vec4 *values) const; void ShaderProgram::SetUniformArray(int location, int count, const int *values) const { glUniform1iv(location, count, values); } void ShaderProgram::SetUniformArray(int location, int count, const float *values) const { glUniform1fv(location, count, values); } void ShaderProgram::SetUniformArray(int location, int count, const glm::vec3 *values) const { glUniform3fv(location, count, (float *)values); } void ShaderProgram::SetUniformArray(int location, int count, const glm::vec4 *values) const { glUniform4fv(location, count, (float *)values); } template bool ShaderProgram::SetSampler(const std::string &name, const T &value) const { auto itr = _samplerLocations.find(name); if (itr == _samplerLocations.end()) return false; int textureUnit = itr->second; glActiveTexture(GL_TEXTURE0 + textureUnit); value.Bind(); SetUniform(name, textureUnit); glActiveTexture(GL_TEXTURE0); return true; } template bool ShaderProgram::SetSampler(const std::string &name, const Texture1D &value) const; template bool ShaderProgram::SetSampler(const std::string &name, const Texture2D &value) const; template bool ShaderProgram::SetSampler(const std::string &name, const Texture3D &value) const; template bool ShaderProgram::SetSampler(const std::string &name, const Texture2DArray &value) const; std::string ShaderProgram::GetLog() const { if (_linked) { char buf[512]; glGetProgramInfoLog(_id, 512, NULL, buf); return std::string(buf); } else { if (_shaders.empty()) return "Cannot linked because there are no shaders"; else return "Cannot link because shader failed to compile"; } } void ShaderProgram::PrintUniforms() const { GLint count; GLint size; GLenum type; char name[64]; int nameLength; glGetProgramiv(_id, GL_ACTIVE_UNIFORMS, &count); for (int i = 0; i < count; i++) { glGetActiveUniform(_id, i, 64, &nameLength, &size, &type, name); printf("%s %s\n", GLTypeToString(type), name); } } void ShaderProgram::ComputeSamplerLocations() { GLint count; GLint size; GLenum type; char name[128]; int nameLength; int samplerId = 1; // Starting at 1 fixes some super weird GL bug glGetProgramiv(_id, GL_ACTIVE_UNIFORMS, &count); for (int i = 0; i < count; i++) { glGetActiveUniform(_id, i, 128, &nameLength, &size, &type, name); if (IsGLTypeSampler(type)) _samplerLocations[string(name)] = samplerId++; } VAssert(samplerId <= GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1); } const char *ShaderProgram::GLTypeToString(const unsigned int type) { switch (type) { case GL_FLOAT: return "float"; case GL_FLOAT_VEC2: return "vec2"; case GL_FLOAT_VEC3: return "vec3"; case GL_FLOAT_VEC4: return "vec4"; case GL_DOUBLE: return "double"; case GL_DOUBLE_VEC2: return "dvec2"; case GL_DOUBLE_VEC3: return "dvec3"; case GL_DOUBLE_VEC4: return "dvec4"; case GL_INT: return "int"; case GL_INT_VEC2: return "ivec2"; case GL_INT_VEC3: return "ivec3"; case GL_INT_VEC4: return "ivec4"; case GL_UNSIGNED_INT: return "unsigned int"; case GL_UNSIGNED_INT_VEC2: return "uvec2"; case GL_UNSIGNED_INT_VEC3: return "uvec3"; case GL_UNSIGNED_INT_VEC4: return "uvec4"; case GL_BOOL: return "bool"; case GL_BOOL_VEC2: return "bvec2"; case GL_BOOL_VEC3: return "bvec3"; case GL_BOOL_VEC4: return "bvec4"; case GL_FLOAT_MAT2: return "mat2"; case GL_FLOAT_MAT3: return "mat3"; case GL_FLOAT_MAT4: return "mat4"; case GL_FLOAT_MAT2x3: return "mat2x3"; case GL_FLOAT_MAT2x4: return "mat2x4"; case GL_FLOAT_MAT3x2: return "mat3x2"; case GL_FLOAT_MAT3x4: return "mat3x4"; case GL_FLOAT_MAT4x2: return "mat4x2"; case GL_FLOAT_MAT4x3: return "mat4x3"; case GL_DOUBLE_MAT2: return "dmat2"; case GL_DOUBLE_MAT3: return "dmat3"; case GL_DOUBLE_MAT4: return "dmat4"; case GL_DOUBLE_MAT2x3: return "dmat2x3"; case GL_DOUBLE_MAT2x4: return "dmat2x4"; case GL_DOUBLE_MAT3x2: return "dmat3x2"; case GL_DOUBLE_MAT3x4: return "dmat3x4"; case GL_DOUBLE_MAT4x2: return "dmat4x2"; case GL_DOUBLE_MAT4x3: return "dmat4x3"; case GL_SAMPLER_1D: return "sampler1D"; case GL_SAMPLER_2D: return "sampler2D"; case GL_SAMPLER_3D: return "sampler3D"; case GL_SAMPLER_CUBE: return "samplerCube"; case GL_SAMPLER_1D_SHADOW: return "sampler1DShadow"; case GL_SAMPLER_2D_SHADOW: return "sampler2DShadow"; case GL_SAMPLER_1D_ARRAY: return "sampler1DArray"; case GL_SAMPLER_2D_ARRAY: return "sampler2DArray"; case GL_SAMPLER_1D_ARRAY_SHADOW: return "sampler1DArrayShadow"; case GL_SAMPLER_2D_ARRAY_SHADOW: return "sampler2DArrayShadow"; case GL_SAMPLER_2D_MULTISAMPLE: return "sampler2DMS"; case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return "sampler2DMSArray"; case GL_SAMPLER_CUBE_SHADOW: return "samplerCubeShadow"; case GL_SAMPLER_BUFFER: return "samplerBuffer"; case GL_SAMPLER_2D_RECT: return "sampler2DRect"; case GL_SAMPLER_2D_RECT_SHADOW: return "sampler2DRectShadow"; case GL_INT_SAMPLER_1D: return "isampler1D"; case GL_INT_SAMPLER_2D: return "isampler2D"; case GL_INT_SAMPLER_3D: return "isampler3D"; case GL_INT_SAMPLER_CUBE: return "isamplerCube"; case GL_INT_SAMPLER_1D_ARRAY: return "isampler1DArray"; case GL_INT_SAMPLER_2D_ARRAY: return "isampler2DArray"; case GL_INT_SAMPLER_2D_MULTISAMPLE: return "isampler2DMS"; case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return "isampler2DMSArray"; case GL_INT_SAMPLER_BUFFER: return "isamplerBuffer"; case GL_INT_SAMPLER_2D_RECT: return "isampler2DRect"; case GL_UNSIGNED_INT_SAMPLER_1D: return "usampler1D"; case GL_UNSIGNED_INT_SAMPLER_2D: return "usampler2D"; case GL_UNSIGNED_INT_SAMPLER_3D: return "usampler3D"; case GL_UNSIGNED_INT_SAMPLER_CUBE: return "usamplerCube"; case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return "usampler2DArray"; case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return "usampler2DArray"; case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return "usampler2DMS"; case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return "usampler2DMSArray"; case GL_UNSIGNED_INT_SAMPLER_BUFFER: return "usamplerBuffer"; case GL_UNSIGNED_INT_SAMPLER_2D_RECT: return "usampler2DRect"; #ifdef GL_IMAGE_1D case GL_IMAGE_1D: return "image1D"; case GL_IMAGE_2D: return "image2D"; case GL_IMAGE_3D: return "image3D"; case GL_IMAGE_2D_RECT: return "image2DRect"; case GL_IMAGE_CUBE: return "imageCube"; case GL_IMAGE_BUFFER: return "imageBuffer"; case GL_IMAGE_1D_ARRAY: return "image1DArray"; case GL_IMAGE_2D_ARRAY: return "image2DArray"; case GL_IMAGE_2D_MULTISAMPLE: return "image2DMS"; case GL_IMAGE_2D_MULTISAMPLE_ARRAY: return "image2DMSArray"; case GL_INT_IMAGE_1D: return "iimage1D"; case GL_INT_IMAGE_2D: return "iimage2D"; case GL_INT_IMAGE_3D: return "iimage3D"; case GL_INT_IMAGE_2D_RECT: return "iimage2DRect"; case GL_INT_IMAGE_CUBE: return "iimageCube"; case GL_INT_IMAGE_BUFFER: return "iimageBuffer"; case GL_INT_IMAGE_1D_ARRAY: return "iimage1DArray"; case GL_INT_IMAGE_2D_ARRAY: return "iimage2DArray"; case GL_INT_IMAGE_2D_MULTISAMPLE: return "iimage2DMS"; case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY: return "iimage2DMSArray"; case GL_UNSIGNED_INT_IMAGE_1D: return "uimage1D"; case GL_UNSIGNED_INT_IMAGE_2D: return "uimage2D"; case GL_UNSIGNED_INT_IMAGE_3D: return "uimage3D"; case GL_UNSIGNED_INT_IMAGE_2D_RECT: return "uimage2DRect"; case GL_UNSIGNED_INT_IMAGE_CUBE: return "uimageCube"; case GL_UNSIGNED_INT_IMAGE_BUFFER: return "uimageBuffer"; case GL_UNSIGNED_INT_IMAGE_1D_ARRAY: return "uimage1DArray"; case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: return "uimage2DArray"; case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE: return "uimage2DMS"; case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: return "uimage2DMSArray"; case GL_UNSIGNED_INT_ATOMIC_COUNTER: return "atomic_uint"; #endif default: return "INVALID ENUM"; } } bool ShaderProgram::IsGLTypeSampler(const unsigned int type) { switch (type) { case GL_SAMPLER_1D: case GL_SAMPLER_2D: case GL_SAMPLER_3D: case GL_SAMPLER_CUBE: case GL_SAMPLER_1D_SHADOW: case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_1D_ARRAY: case GL_SAMPLER_2D_ARRAY: case GL_SAMPLER_1D_ARRAY_SHADOW: case GL_SAMPLER_2D_ARRAY_SHADOW: case GL_SAMPLER_2D_MULTISAMPLE: case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_SAMPLER_CUBE_SHADOW: case GL_SAMPLER_BUFFER: case GL_SAMPLER_2D_RECT: case GL_SAMPLER_2D_RECT_SHADOW: case GL_INT_SAMPLER_1D: case GL_INT_SAMPLER_2D: case GL_INT_SAMPLER_3D: case GL_INT_SAMPLER_CUBE: case GL_INT_SAMPLER_1D_ARRAY: case GL_INT_SAMPLER_2D_ARRAY: case GL_INT_SAMPLER_2D_MULTISAMPLE: case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_INT_SAMPLER_BUFFER: case GL_INT_SAMPLER_2D_RECT: case GL_UNSIGNED_INT_SAMPLER_1D: case GL_UNSIGNED_INT_SAMPLER_2D: case GL_UNSIGNED_INT_SAMPLER_3D: case GL_UNSIGNED_INT_SAMPLER_CUBE: case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_UNSIGNED_INT_SAMPLER_BUFFER: case GL_UNSIGNED_INT_SAMPLER_2D_RECT: return true; default: return false; } } SmartShaderProgram::SmartShaderProgram(ShaderProgram *program) : _program(program) { if (_program) _program->Bind(); } SmartShaderProgram::~SmartShaderProgram() { if (_program) _program->UnBind(); } bool SmartShaderProgram::IsValid() const { return _program; } ================================================ FILE: lib/render/SliceRenderer.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include #define X 0 #define Y 1 #define Z 2 #define XY 0 #define XZ 1 #define YZ 2 using namespace VAPoR; static vector ToDoubleVec(const glm::vec3 &v) { vector c(v.length()); for (int i = 0; i < v.length(); i++) c[i] = v[i]; return c; } static RendererRegistrar registrar(SliceRenderer::GetClassType(), SliceParams::GetClassType()); SliceRenderer::SliceRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instanceName, DataMgr *dataMgr) : Renderer(pm, winName, dataSetName, SliceParams::GetClassType(), SliceRenderer::GetClassType(), instanceName, dataMgr) { _initialized = false; _windingOrder = {0.0f, 0.0f, 0.f, 1.0f, 0.0f, 0.f, 0.0f, 1.0f, 0.f, 1.0f, 0.0f, 0.f, 1.0f, 1.0f, 0.f, 0.0f, 1.0f, 0.f}; _rectangle3D = {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}; _VAO = 0; _vertexVBO = 0; _texCoordVBO = 0; _colorMapTextureID = 0; _dataValueTextureID = 0; _cacheParams.textureSampleRate = 200; SliceParams *p = dynamic_cast(GetActiveParams()); VAssert(p); MapperFunction *tf = p->GetMapperFunc(_cacheParams.varName); _colorMapSize = tf->getNumEntries(); } SliceRenderer::~SliceRenderer() { if (_VAO != 0) { glDeleteVertexArrays(1, &_VAO); _VAO = 0; } if (_vertexVBO != 0) { glDeleteBuffers(1, &_vertexVBO); _vertexVBO = 0; } if (_texCoordVBO != 0) { glDeleteBuffers(1, &_texCoordVBO); _texCoordVBO = 0; } if (_colorMapTextureID != 0) { glDeleteTextures(1, &_colorMapTextureID); _colorMapTextureID = 0; } if (_dataValueTextureID != 0) { glDeleteTextures(1, &_dataValueTextureID); _dataValueTextureID = 0; } } int SliceRenderer::_initializeGL() { _initVAO(); _initTexCoordVBO(); _initVertexVBO(); _initialized = true; return 0; } void SliceRenderer::_initVAO() { glGenVertexArrays(1, &_VAO); glBindVertexArray(_VAO); } void SliceRenderer::_initTexCoordVBO() { if (_texCoordVBO != 0) glDeleteBuffers(1, &_texCoordVBO); glGenBuffers(1, &_texCoordVBO); glBindBuffer(GL_ARRAY_BUFFER, _texCoordVBO); glVertexAttribPointer(1, 2, GL_DOUBLE, GL_FALSE, 0, (void *)0); glEnableVertexAttribArray(1); glBufferData(GL_ARRAY_BUFFER, sizeof(double) * _rectangle3D.size(), _rectangle3D.data(), GL_DYNAMIC_DRAW); } void SliceRenderer::_initVertexVBO() { if (_vertexVBO != 0) glDeleteBuffers(1, &_vertexVBO); glGenBuffers(1, &_vertexVBO); glBindBuffer(GL_ARRAY_BUFFER, _vertexVBO); glVertexAttribPointer(0, 3, GL_DOUBLE, GL_FALSE, 0, (void *)0); glEnableVertexAttribArray(0); glBufferData(GL_ARRAY_BUFFER, 6 * 3 * sizeof(double), _windingOrder.data(), GL_STATIC_DRAW); } void SliceRenderer::_resetCache() { SliceParams *p = dynamic_cast(GetActiveParams()); VAssert(p); _cacheParams.varName = p->GetVariableName(); _cacheParams.heightVarName = p->GetHeightVariableName(); _cacheParams.ts = p->GetCurrentTimestep(); _cacheParams.refinementLevel = p->GetRefinementLevel(); _cacheParams.compressionLevel = p->GetCompressionLevel(); _cacheParams.orientation = p->GetBox()->GetOrientation(); _cacheParams.xRotation = p->GetValueDouble(RenderParams::XSlicePlaneRotationTag, 0); _cacheParams.yRotation = p->GetValueDouble(RenderParams::YSlicePlaneRotationTag, 0); _cacheParams.zRotation = p->GetValueDouble(RenderParams::ZSlicePlaneRotationTag, 0); _cacheParams.xOrigin = p->GetXSlicePlaneOrigin(); _cacheParams.yOrigin = p->GetYSlicePlaneOrigin(); _cacheParams.zOrigin = p->GetZSlicePlaneOrigin(); _cacheParams.textureSampleRate = p->GetValueDouble(RenderParams::SampleRateTag, 200); _cacheParams.sliceOrientationMode = p->GetValueLong(RenderParams::SlicePlaneOrientationModeTag, 0); _cacheParams.sliceRotation = p->GetSlicePlaneRotation(); _cacheParams.sliceNormal = p->GetSlicePlaneNormal(); _cacheParams.sliceOffset = p->GetValueDouble(p->SliceOffsetTag, 0); _getExtents(_cacheParams.boxMin, _cacheParams.boxMax); // clang-format off _dataMgr->GetVariableExtents(_cacheParams.ts, _cacheParams.varName, _cacheParams.refinementLevel, _cacheParams.compressionLevel, _cacheParams.domainMin, _cacheParams.domainMax ); // clang-format on } void SliceRenderer::_resetColormapCache() { SliceParams *p = dynamic_cast(GetActiveParams()); VAssert(p); MapperFunction *tf = p->GetMapperFunc(_cacheParams.varName); tf->makeLut(_cacheParams.tf_lut); _cacheParams.tf_minMax = tf->getMinMaxMapValue(); if (_colorMapTextureID != 0) glDeleteTextures(1, &_colorMapTextureID); glGenTextures(1, &_colorMapTextureID); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, _colorMapTextureID); #ifdef DEBUG glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); #else glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); #endif glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA8, _colorMapSize, 0, GL_RGBA, GL_FLOAT, &_cacheParams.tf_lut[0]); } // clang-format off int SliceRenderer::_regenerateSlice() { Grid *grid3d = nullptr; int rc = _getGrid3D(grid3d); if (rc < 0) return -1; // Get data values from a slice std::shared_ptr dataValues(new float[_textureSideSize * _textureSideSize]); planeDescription pd; pd.sideSize = _textureSideSize; if (_cacheParams.sliceOrientationMode == (int)RenderParams::SlicePlaneOrientationMode::Normal) pd.normal = _cacheParams.sliceNormal; else pd.normal = ToDoubleVec(ArbitrarilyOrientedRegularGrid::GetNormalFromRotations(_cacheParams.sliceRotation)); glm::vec3 o = {_cacheParams.xOrigin, _cacheParams.yOrigin, _cacheParams.zOrigin}; glm::vec3 n = {pd.normal[0], pd.normal[1], pd.normal[2]}; glm::vec3 offsetOrigin = o + n * (float)_cacheParams.sliceOffset; pd.origin = ToDoubleVec(offsetOrigin); pd.boxMin = _cacheParams.boxMin; pd.boxMax = _cacheParams.boxMax; VAPoR::DimsType dims = { (size_t)_textureSideSize, (size_t)_textureSideSize, 1 }; ArbitrarilyOrientedRegularGrid* slice = new ArbitrarilyOrientedRegularGrid( grid3d, pd, dims ); CoordType corner1, corner2, corner3, corner4; slice->GetUserCoordinates( {0, 0, 0}, corner1); slice->GetUserCoordinates( {0, _textureSideSize-1, 0}, corner2); slice->GetUserCoordinates( {_textureSideSize-1, 0, 0}, corner3); slice->GetUserCoordinates( {_textureSideSize-1, _textureSideSize-1, 0}, corner4); _windingOrder = {corner1[0], corner1[1], corner1[2], corner3[0], corner3[1], corner3[2], corner2[0], corner2[1], corner2[2], corner3[0], corner3[1], corner3[2], corner4[0], corner4[1], corner4[2], corner2[0], corner2[1], corner2[2]}; _rectangle3D = {corner1[0], corner1[1], corner1[2], corner3[0], corner3[1], corner3[2], corner4[0], corner4[1], corner4[2], corner2[0], corner2[1], corner2[2]}; SliceParams *p = dynamic_cast(GetActiveParams()); std::vector sliceQuad = { {corner1[0], corner1[1], corner1[2]}, {corner3[0], corner3[1], corner3[2]}, {corner4[0], corner4[1], corner4[2]}, {corner2[0], corner2[1], corner2[2]}}; p->SetSlicePlaneQuad(sliceQuad); delete grid3d; if (slice == nullptr) { Wasp::MyBase::SetErrMsg("Unable to perform SliceGridAlongPlane() with current Grid"); return -1; } // Apply opacity to missing values float missingValue = slice->GetMissingValue(); int textureSize = 2 * _textureSideSize * _textureSideSize; std::unique_ptr textureValues(new float[textureSize]); for (size_t i = 0; i < textureSize / 2; i++) { DimsType dim = {i%_textureSideSize, i/_textureSideSize, 0}; float dataValue = slice->GetValueAtIndex( dim ); if (dataValue == missingValue) textureValues.get()[i * 2 + 1] = 1.f; else textureValues.get()[i * 2 + 1] = 0.f; textureValues.get()[i * 2] = dataValue; } _createDataTexture(textureValues); delete slice; return 0; } // clang-format on int SliceRenderer::_getGrid3D(Grid *&grid3d) const { SliceParams *p = dynamic_cast(GetActiveParams()); int rLevel = p->GetRefinementLevel(); int cLevel = p->GetCompressionLevel(); int rc = DataMgrUtils::GetGrids(_dataMgr, p->GetCurrentTimestep(), p->GetVariableName(), _cacheParams.boxMin, _cacheParams.boxMax, true, &rLevel, &cLevel, &grid3d); if (rc < 0) { Wasp::MyBase::SetErrMsg("Unable to acquire Grid for Slice texture"); return rc; } VAssert(grid3d); grid3d->SetInterpolationOrder(1); return 0; } void SliceRenderer::_createDataTexture(std::unique_ptr &dataValues) { if (_dataValueTextureID != 0) glDeleteTextures(1, &_dataValueTextureID); glGenTextures(1, &_dataValueTextureID); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _dataValueTextureID); #ifdef DEBUG glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); #else glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); #endif glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, _textureSideSize, _textureSideSize, 0, GL_RG, GL_FLOAT, dataValues.get()); glBindBuffer(GL_ARRAY_BUFFER, _vertexVBO); glBufferSubData(GL_ARRAY_BUFFER, 0, 6 * 3 * sizeof(double), _windingOrder.data()); } bool SliceRenderer::_isDataCacheDirty() const { SliceParams *p = dynamic_cast(GetActiveParams()); VAssert(p); if (_cacheParams.varName != p->GetVariableName()) return true; if (_cacheParams.heightVarName != p->GetHeightVariableName()) return true; if (_cacheParams.ts != p->GetCurrentTimestep()) return true; if (_cacheParams.refinementLevel != p->GetRefinementLevel()) return true; if (_cacheParams.compressionLevel != p->GetCompressionLevel()) return true; if (_cacheParams.xRotation != p->GetValueDouble(RenderParams::XSlicePlaneRotationTag, 0)) return true; if (_cacheParams.yRotation != p->GetValueDouble(RenderParams::YSlicePlaneRotationTag, 0)) return true; if (_cacheParams.zRotation != p->GetValueDouble(RenderParams::ZSlicePlaneRotationTag, 0)) return true; if (_cacheParams.xOrigin != p->GetXSlicePlaneOrigin()) return true; if (_cacheParams.yOrigin != p->GetYSlicePlaneOrigin()) return true; if (_cacheParams.zOrigin != p->GetZSlicePlaneOrigin()) return true; if (_cacheParams.sliceOffset != p->GetValueDouble(p->SliceOffsetTag, 0)) return true; if (_cacheParams.sliceNormal != p->GetSlicePlaneNormal()) return true; if (_cacheParams.sliceOrientationMode != p->GetValueLong(RenderParams::SlicePlaneOrientationModeTag, 0)) return true; if (_cacheParams.textureSampleRate != p->GetValueDouble(RenderParams::SampleRateTag, 200)) return true; return false; } bool SliceRenderer::_isColormapCacheDirty() const { SliceParams *p = dynamic_cast(GetActiveParams()); VAssert(p); MapperFunction *tf = p->GetMapperFunc(_cacheParams.varName); vector tf_lut; tf->makeLut(tf_lut); if (_cacheParams.tf_lut != tf_lut) return true; if (_cacheParams.tf_minMax != tf->getMinMaxMapValue()) return true; return false; } bool SliceRenderer::_isBoxCacheDirty() const { VAPoR::CoordType min, max; _getExtents(min, max); if (_cacheParams.boxMin != min) return true; if (_cacheParams.boxMax != max) return true; return false; } void SliceRenderer::_getExtents(VAPoR::CoordType &min, VAPoR::CoordType &max) const { SliceParams *p = dynamic_cast(GetActiveParams()); VAssert(p); Box *box = p->GetBox(); box->GetExtents(min, max); VAssert(min.size() == 3); VAssert(max.size() == 3); } int SliceRenderer::_paintGL(bool fast) { int rc = 0; glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); #ifdef DEBUG _drawDebugPolygons(); #endif glEnable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); _initializeState(); if (_isDataCacheDirty() || _isBoxCacheDirty()) { _resetCache(); // If we're in fast mode, degrade the quality of the slice for better interactivity if (fast) { _textureSideSize = 50; } else { _textureSideSize = _cacheParams.textureSampleRate; } int rc = _regenerateSlice(); if (rc < 0) return -1; } if (_isColormapCacheDirty()) _resetColormapCache(); _configureShader(); if (CheckGLError() != 0) { _resetState(); return -1; } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, _colorMapTextureID); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _dataValueTextureID); glBindVertexArray(_VAO); glDrawArrays(GL_TRIANGLES, 0, 6); _resetState(); if (CheckGLError() != 0) { return -1; } return rc; } #ifdef DEBUG void SliceRenderer::_drawDebugPolygons() { // 3D yellow enclosing rectangle that defines the perimeter of our texture // This can and often will extend beyond the Box // std::vector rectangle = _slicer->GetRectangle(); LegacyGL *lgl = _glManager->legacy; lgl->Begin(GL_LINES); lgl->Color4f(1., 1., 0., 1.); lgl->Vertex3f(_rectangle3D[0], _rectangle3D[1], _rectangle3D[2]); lgl->Vertex3f(_rectangle3D[3], _rectangle3D[4], _rectangle3D[5]); lgl->Vertex3f(_rectangle3D[3], _rectangle3D[4], _rectangle3D[5]); lgl->Vertex3f(_rectangle3D[6], _rectangle3D[7], _rectangle3D[8]); lgl->Vertex3f(_rectangle3D[6], _rectangle3D[7], _rectangle3D[8]); lgl->Vertex3f(_rectangle3D[9], _rectangle3D[10], _rectangle3D[11]); lgl->Vertex3f(_rectangle3D[9], _rectangle3D[10], _rectangle3D[11]); lgl->Vertex3f(_rectangle3D[0], _rectangle3D[1], _rectangle3D[2]); lgl->End(); // Winding order double *wo = _windingOrder.data(); lgl = _glManager->legacy; lgl->Begin(GL_LINES); lgl->Color4f(0., 1., 0., 1.); // green lgl->Vertex3f(wo[0], wo[1], wo[2]); lgl->Vertex3f(wo[3], wo[4], wo[5]); lgl->Color4f(0., 1., 1., 1.); // teal lgl->Vertex3f(wo[3], wo[4], wo[5]); lgl->Vertex3f(wo[6], wo[7], wo[8]); lgl->Color4f(1., 1., 1., 1.); // white lgl->Vertex3f(wo[6], wo[7], wo[8]); lgl->Vertex3f(wo[0], wo[1], wo[2]); lgl->Color4f(.9, .9, 1., 1.); // purple lgl->Vertex3f(wo[9], wo[10], wo[11]); lgl->Vertex3f(wo[12], wo[13], wo[14]); lgl->Color4f(1., 0., 0., 1.); // red lgl->Vertex3f(wo[12], wo[13], wo[14]); lgl->Vertex3f(wo[15], wo[16], wo[17]); lgl->Color4f(0., 1., 1., 1.); // yellow lgl->Vertex3f(wo[15], wo[16], wo[17]); lgl->Vertex3f(wo[9], wo[10], wo[11]); lgl->End(); } #endif void SliceRenderer::_configureShader() { ShaderProgram *s = _glManager->shaderManager->GetShader("Slice"); s->Bind(); // One vertex shader uniform vec4 s->SetUniform("MVP", _glManager->matrixManager->GetModelViewProjectionMatrix()); // Remaining fragment shader uniform floats SliceParams *p = dynamic_cast(GetActiveParams()); VAssert(p); float opacity = p->GetConstantOpacity(); s->SetUniform("constantOpacity", opacity); s->SetUniform("minLUTValue", (float)_cacheParams.tf_minMax[0]); s->SetUniform("maxLUTValue", (float)_cacheParams.tf_minMax[1]); // And finally our uniform samplers GLint colormapLocation; colormapLocation = s->GetUniformLocation("colormap"); glUniform1i(colormapLocation, 0); GLint dataValuesLocation; dataValuesLocation = s->GetUniformLocation("dataValues"); glUniform1i(dataValuesLocation, 1); } void SliceRenderer::_initializeState() { _glManager->matrixManager->MatrixModeModelView(); glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(GL_TRUE); } void SliceRenderer::_resetState() { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, 0); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); ShaderProgram::UnBind(); glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); } ================================================ FILE: lib/render/TIFWriter.cpp ================================================ #include "vapor/TIFWriter.h" #ifdef WIN32 #include #endif using namespace VAPoR; REGISTER_IMAGEWRITER(TIFWriter); std::vector TIFWriter::GetFileExtensions() { return {"tif", "tiff"}; } int TIFWriter::ConfigureWithFormat(ImageWriter::Format f) { TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); switch (f) { case Format::RGB: TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); return 0; default: MyBase::SetErrMsg("Unsupported format"); return -1; } } TIFWriter::TIFWriter(const std::string &path) : ImageWriter(path), tif(nullptr) { tif = XTIFFOpen(path.c_str(), "w"); if (tif) opened = true; } TIFWriter::~TIFWriter() { if (tif) XTIFFClose(tif); tif = nullptr; } int TIFWriter::Write(const unsigned char *buffer, const unsigned int width, const unsigned int height) { if (!opened) { MyBase::SetErrMsg("Unable to open TIF file for writing: \"%s\"", path.c_str()); return -1; } ConfigureWithFormat(format); TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); int writeSuccess = TIFFWriteRawStrip(tif, 0, const_cast(buffer), width * height * 3); if (writeSuccess < 0) { SetErrMsg("TIFF write routine failed"); return -1; } return 0; } ================================================ FILE: lib/render/TODO.txt ================================================ TwoDDataRender -------------- + add support for lighting, currently hard-coded to disabled ControlExec ----------- GetDataMgr() should return const ================================================ FILE: lib/render/TextLabel.cpp ================================================ #include "vapor/glutil.h" #include "vapor/TextLabel.h" #include "vapor/GLManager.h" #include #include "vapor/LegacyGL.h" using namespace VAPoR; using glm::vec2; using glm::vec3; using glm::vec4; using std::string; TextLabel::TextLabel(GLManager *glManager, const std::string &fontName, unsigned int fontSize) : _glManager(glManager), FontName(fontName), FontSize(fontSize), BackgroundColor(0.f), ForegroundColor(1.f), HorizontalAlignment(Left), VerticalAlignment(Bottom), Padding(0) { } void TextLabel::DrawText(const glm::vec2 &position, const std::string &text) { DrawText(vec3(position, 0.f), text); } void TextLabel::DrawText(const glm::vec3 &position, const std::string &text) { Font * font = _glManager->fontManager->GetFont(FontName, FontSize); MatrixManager *mm = _glManager->matrixManager; LegacyGL * lgl = _glManager->legacy; glm::vec2 p = mm->ProjectToScreen(position); GLint viewport[4] = {0}; glGetIntegerv(GL_VIEWPORT, viewport); vec4 ndc = mm->GetModelViewProjectionMatrix() * vec4(position, 1.f); float z = ndc.z / ndc.w; mm->MatrixModeProjection(); mm->PushMatrix(); mm->Ortho(0, viewport[2], 0, viewport[3]); mm->MatrixModeModelView(); mm->PushMatrix(); mm->LoadIdentity(); float x = (p.x + 1) / 2 * viewport[2]; float y = (p.y + 1) / 2 * viewport[3]; vec2 textDimensions = font->TextDimensions(text); switch (HorizontalAlignment) { case Alignment::Left: break; case Alignment::Center: x -= textDimensions.x / 2.f; break; case Alignment::Right: x -= textDimensions.x; break; default: break; } switch (VerticalAlignment) { case Alignment::Bottom: break; case Alignment::Center: y -= textDimensions.y / 2.f; break; case Alignment::Top: y -= textDimensions.y; break; default: break; } glDepthMask(true); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); mm->Translate((int)x, (int)y, -z); if (BackgroundColor.a > 0) { lgl->Color(BackgroundColor); lgl->Begin(LGL_QUADS); lgl->Vertex2f(-Padding, -Padding); lgl->Vertex2f(textDimensions.x + Padding, -Padding); lgl->Vertex2f(textDimensions.x + Padding, textDimensions.y + Padding); lgl->Vertex2f(-Padding, textDimensions.y + Padding); lgl->End(); } font->DrawText(text, ForegroundColor); glDepthFunc(GL_LESS); mm->PopMatrix(); mm->MatrixModeProjection(); mm->PopMatrix(); mm->MatrixModeModelView(); } Font *TextLabel::GetFont() const { return _glManager->fontManager->GetFont(FontName, FontSize); } ================================================ FILE: lib/render/Texture.cpp ================================================ #include #include #include #include using namespace VAPoR; Texture::Texture(unsigned int type) : _type(type), _nDims(GetDimsCount(type)) {} Texture::~Texture() { Delete(); } int Texture::Generate() { return Generate(GL_LINEAR); } int Texture::Generate(int filter) { VAssert(!Initialized()); glGenTextures(1, &_id); glBindTexture(_type, _id); glTexParameteri(_type, GL_TEXTURE_MIN_FILTER, filter); glTexParameteri(_type, GL_TEXTURE_MAG_FILTER, filter); if (_nDims >= 1) glTexParameteri(_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); if (_nDims >= 2) glTexParameteri(_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (_nDims >= 3) glTexParameteri(_type, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glBindTexture(_type, 0); return 0; } void Texture::Delete() { if (_id) glDeleteTextures(1, &_id); _id = 0; _width = 0; _height = 0; _depth = 0; } bool Texture::Initialized() const { return _id; } void Texture::Bind() const { VAssert(Initialized()); glBindTexture(_type, _id); } void Texture::UnBind() const { glBindTexture(_type, 0); } // glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, dims[0], dims[1], dims[2], 0, GL_RED, GL_FLOAT, data); int Texture::TexImage(int internalFormat, int width, int height, int depth, unsigned int format, unsigned int type, const void *data, int level) { VAssert(Initialized()); VAssert(_nDims >= 2 || height == 0); VAssert(_nDims >= 3 || depth == 0); if (_nDims == 3) { GLint max3DTexDim; glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3DTexDim); if (width > max3DTexDim || height > max3DTexDim || depth > max3DTexDim) { Wasp::MyBase::SetErrMsg("Texture size (%lix%lix%li) not supported by GPU (max supported size per dim is %i)\n", width, height, depth, max3DTexDim); return -1; } } else { GLint max2DTexDim; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max2DTexDim); if (width > max2DTexDim || height > max2DTexDim) { Wasp::MyBase::SetErrMsg("Texture size (%lix%li) not supported by GPU (max supported size per dim is %i)\n", width, height, max2DTexDim); return -1; } } _width = width; _height = height; _depth = depth; Bind(); if (_nDims == 1) glTexImage1D(_type, level, internalFormat, width, 0, format, type, data); else if (_nDims == 2) glTexImage2D(_type, level, internalFormat, width, height, 0, format, type, data); else if (_nDims == 3) { glTexImage3D(_type, level, internalFormat, 0, 0, 0, 0, format, type, NULL); // Fix driver bug with re-uploading large textures glTexImage3D(_type, level, internalFormat, width, height, depth, 0, format, type, data); } UnBind(); return 0; } unsigned int Texture::GetDimsCount(unsigned int glTextureEnum) { switch (glTextureEnum) { case GL_TEXTURE_1D: return 1; case GL_TEXTURE_2D: return 2; case GL_TEXTURE_3D: return 3; case GL_TEXTURE_2D_ARRAY: return 3; default: VAssert(0); return -1; } } Texture1D::Texture1D() : Texture(GL_TEXTURE_1D) {} Texture2D::Texture2D() : Texture(GL_TEXTURE_2D) {} Texture3D::Texture3D() : Texture(GL_TEXTURE_3D) {} Texture2DArray::Texture2DArray() : Texture(GL_TEXTURE_2D_ARRAY) {} void Texture2D::CopyDepthBuffer() { GLint viewport[4] = {0}; glGetIntegerv(GL_VIEWPORT, viewport); Bind(); glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, viewport[0], viewport[1], viewport[2], viewport[3], 0); _width = viewport[2] - viewport[0]; _height = viewport[3] - viewport[1]; UnBind(); } ================================================ FILE: lib/render/TrackBall.cpp ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: TrackBall.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: July 2004 // // Description: Implements the Trackball class: // This was implemented from Ken Purcell's TrackBall // methods. Additional methods provided to set the TrackBall // based on a viewing frame // /* Copyright (C) 1992 AHPCRC, Univeristy of Minnesota * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program in a file named 'Copying'; if not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139. */ /* Author: * Ken Chin-Purcell (ken@ahpcrc.umn.edu) * Army High Performance Computing Research Center (AHPCRC) * Univeristy of Minnesota * * This class was extracted from glutil.c See glutil.cpp for the revision history */ /* Trackball interface for 3D rotation: * * The TrackBall is simualted as a globe rotating about its center. * Mouse movement is mapped to a spot on the globe, which when moved * effects a rotation. * * In addition, this Trackball also keeps track of translation, * in the form of panning and zooming. * * To use: * At the start of the program, call Trackball constructor to * create a Trackball object. You will want a separate * Trackball for each rotatable scene. * On a Button or Motion event, call * MouseOnTrackball * When you want to draw, call * TrackballSetMatrix to modify the matrix. * Misc. functions: * TrackballReset to come to home position * TrackballFlip to flip about an axis * TrackballSpin to keep rotating by last increment * TrackballStopSpinning to set increment to zero * * To change how TrackBall feels: * tball->_scale[0] : modify translation (pan) in x direction * tball->_scale[1] : modify translation (pan) in y direction * tball->_scale[2] : modify translation (zoom) in z direction * tball->_ballsize : a bigger ball gives finer rotations * (default = 0.65) */ #include #include #include #include #include #include #include #define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH #include #include #include using namespace VAPoR; void Trackball::TrackballReset() { /* Bring trackball to home position, no translation, zero rotation. */ qzero(_qrot); qzero(_qinc); vzero(_trans); vset(_scale, 1000000.0, 1000000.0, 1000000.0); // Default center of rotation: _center[0] = 0.5f; _center[1] = 0.5f; _center[2] = 0.5f; } Trackball::Trackball(void) { _ballsize = 0.65f; vset(_scale, 1.0, 1.0, 1.0); TrackballReset(); } Trackball::Trackball(float scale[3]) { _ballsize = 0.65f; vset(_scale, scale[0], scale[1], scale[2]); TrackballReset(); } void Trackball::TrackballSetMatrix() // Note perspective must be set previously in setFromFrame. { /* Modify the modelview matrix by the trackball * rotation and translation. */ if (_perspective) { glm::mat4 m(1.0); m = glm::translate(m, glm::vec3(_center[0], _center[1], _center[2])); m = glm::translate(m, glm::vec3(_trans[0], _trans[1], _trans[2])); // Copying over because qmatrix is row major (it should be column major). // I have no idea why this works because the surrounding functions that // were here originaly were column major too. If I replace the current // quat functions with the correct column major ones the rotations are correct // every other rotation. // // Also for future reference since qmatrix has no documentation: // qmatrix parameters are x,y,z,w while glm parameters are w,x,y,z double m3[16]; qmatrix(_qrot, m3); glm::mat4 mrot_row_major; for (int i = 0; i < 16; i++) glm::value_ptr(mrot_row_major)[i] = m3[i]; m *= mrot_row_major; m = glm::translate(m, -glm::vec3(_center[0], _center[1], _center[2])); for (int i = 0; i < 16; i++) _modelViewMatrix[i] = glm::value_ptr(m)[i]; } else { glm::mat4 m(1.0); m = glm::translate(m, glm::vec3(_center[0], _center[1], _center[2])); m = glm::translate(m, glm::vec3(_trans[0], _trans[1], _trans[2])); double m3[16]; qmatrix(_qrot, m3); glm::mat4 mrot_row_major; for (int i = 0; i < 16; i++) glm::value_ptr(mrot_row_major)[i] = m3[i]; m *= mrot_row_major; // Cannot scale due to how camera params are extracted from final matrix // m = glm::scale(m, glm::vec3(scale_factor, scale_factor, scale_factor)); // SetFloat("Scale", scale_factor); m = glm::translate(m, -glm::vec3(_center[0], _center[1], _center[2])); for (int i = 0; i < 16; i++) _modelViewMatrix[i] = glm::value_ptr(m)[i]; } } double Trackball::GetOrthoSize() const { double scale_factor = 1.0; if (_trans[2] < 0.0) { scale_factor = 5.0 / (1 - _trans[2]); } else { scale_factor = 5.0 + _trans[2]; } return 1 / scale_factor * 2.9; } #ifndef M_SQRT1_2 #define M_SQRT1_2 0.707106781186547524401f #endif static double q90[3][4] = { {M_SQRT1_2, 0.0, 0.0, M_SQRT1_2}, {0.0, M_SQRT1_2, 0.0, M_SQRT1_2}, {0.0, 0.0, -M_SQRT1_2, M_SQRT1_2}, }; void Trackball::TrackballFlip(int axis) { /* Rotate by 90 deg about the given axis. */ if (axis >= 0 && axis < 3) qmult(q90[axis], _qrot, _qrot); } void Trackball::TrackballSpin() { /* Rotationaly spin the trackball by the current increment. * Use this to implement rotational glide. */ qmult(_qinc, _qrot, _qrot); } void Trackball::TrackballStopSpinning() { /* Cease any rotational glide by zeroing the increment. */ qzero(_qinc); } int Trackball::TrackballSpinning() { /* If the trackball is gliding then the increment's angle * will be non-zero, and cos(theta) != 1, hence q[3] != 1. */ return (_qinc[3] != 1); } void Trackball::TrackballSetPosition(double newx, double newy) { /* Call this when the user does a mouse down. * Stop the trackball glide, then remember the mouse * down point (for a future rotate, pan or zoom). */ TrackballStopSpinning(); _lastx = newx; _lasty = newy; } void Trackball::TrackballRotate(double newx, double newy) { CalcRotation(_qinc, newx, newy, _lastx, _lasty, _ballsize); TrackballSpin(); _lastx = newx; /* remember for next time */ _lasty = newy; } void Trackball::TrackballPan(double newx, double newy) { _trans[0] += (newx - _lastx) * _scale[0]; _trans[1] += (newy - _lasty) * _scale[1]; _lastx = newx; /* remember for next time */ _lasty = newy; } void Trackball::TrackballZoom(double newx, double newy) { _trans[2] += (newy - _lasty) * _scale[2]; _lastx = newx; /* remember for next time */ _lasty = newy; } void Trackball::TrackballCopyTo(Trackball *dst) { /* Copy the current roation of the trackball */ qcopy(_qrot, dst->_qrot); } /* * eventNum is 0, 1, or 2 for press, move, or release * thisButton is Qt:LeftButton, RightButton, or MidButton */ void Trackball::MouseOnTrackball(int eventNum, int thisButton, int xcrd, int ycrd, int width, int height) { /* Alter a Trackball structure given mouse event. * This routine *assumes* button 1 rotates, button 2 pans, * and button 3 zooms! * * event : ButtonPress, MotionNotify or ButtonRelease * width, height : of event window * tball : trackball to modify */ double x, y; static int button; // Ignore time: Qt doesn't provide time with events (may need to revisit this later????) // static Time downTime; switch (eventNum) { case 0: // ButtonPress: x = ScalePoint(xcrd, 0, width); y = ScalePoint(ycrd, height, -((long)height)); TrackballSetPosition(x, y); // Remember the last button pressed: button = thisButton; // downTime = event->xbutton.time; break; case 1: // MotionNotify: x = ScalePoint(xcrd, 0, width); y = ScalePoint(ycrd, height, -((long)height)); switch (button) { case 1: // left button TrackballRotate(x, y); break; case 2: // middle button TrackballPan(x, y); break; case 3: // right button TrackballZoom(x, y); break; default: break; } // downTime = event->xmotion.time; break; case 2: // ButtonRelease: button = 1; // left // if (event->xbutton.time - downTime > 250) //??? if (event->xbutton.time - downTime > 100) //??? TrackballStopSpinning(tball); break; } } bool Trackball::ReconstructCamera(double position[3], double upVec[3], double viewDir[3]) const { double minv[16]; int rc = minvert(_modelViewMatrix, minv); if (rc < 0) return (false); vscale(minv + 8, -1.0); for (int i = 0; i < 3; i++) { position[i] = minv[12 + i]; // position vector is minv[12..14] upVec[i] = minv[4 + i]; // up vector is minv[4..6] viewDir[i] = minv[8 + i]; // view direction is minv[8..10] } vnormal(upVec); vnormal(viewDir); return (true); } // Set the quaternion and translation from a viewer frame // Also happens to construct modelview matrix, but we don't use its translation bool Trackball::setFromFrame(const std::vector &posvec, const std::vector &dirvec, const std::vector &upvec, const std::vector ¢erRot, bool persp) { VAssert(posvec.size() == 3); VAssert(dirvec.size() == 3); VAssert(upvec.size() == 3); VAssert(centerRot.size() == 3); // Check for valid up vector and view direction if (upvec[0] == 0 && upvec[1] == 0 && upvec[2] == 0) { return false; } if (dirvec[0] == 0 && dirvec[1] == 0 && dirvec[2] == 0) { return false; } // First construct the rotation matrix: double mtrx1[16]; double trnsMtrx[16]; double mtrx[16]; setCenter(centerRot); makeTransMatrix(centerRot, trnsMtrx); makeModelviewMatrixD(posvec, dirvec, upvec, mtrx); // Translate on both sides by translation // first on left, mmult(trnsMtrx, mtrx, mtrx1); // then on right by negative: trnsMtrx[12] = -trnsMtrx[12]; trnsMtrx[13] = -trnsMtrx[13]; trnsMtrx[14] = -trnsMtrx[14]; mmult(mtrx1, trnsMtrx, mtrx); double qrotd[4]; // convert rotation part to quaternion: rotmatrix2q(mtrx, qrotd); for (int i = 0; i < 4; i++) _qrot[i] = (double)qrotd[i]; // set the translation? // If parallel (ortho) transform, z used for translation _perspective = persp; // vcopy(posvec, trans); for (int i = 0; i < 3; i++) _trans[i] = (double)mtrx[i + 12]; return true; } ================================================ FILE: lib/render/TwoDDataRenderer.cpp ================================================ //************************************************************************ // Copyright (C) 2008 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: TwoDDataRenderer.cpp // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: March 2016 // // Description: Implementation of the twoDImageRenderer class // #include // Must be included first!!! #include #include #include #include #include #include #include #include #include #include "vapor/GLManager.h" using namespace VAPoR; // // Register class with object factory!!! // static RendererRegistrar registrar(TwoDDataRenderer::GetClassType(), TwoDDataParams::GetClassType()); namespace { // Set to true to force structured grids to be renderered as // unstructured grids. // const bool ForceUnstructured = false; // GLSL shader constants // const string EffectBaseName = "2DData"; const string EffectName = "2DData"; const string EffectNameAttr = "2DDataAttr"; const string VertexDataAttr = "vertexDataAttr"; // Rendering primitives will be aligned with grid points // const bool GridAligned = true; // Texture units. Only use data texture if GridAligned is false // // const int dataTexUnit = 0; // GL_TEXTURE0 // const int colormapTexUnit = 1; // GL_TEXTURE1 // Return name of GLSL shader instance to use // string getEffectInstance(bool useVertAttr) { if (useVertAttr) return (EffectNameAttr); else return (EffectName); } // Compute surface normal (gradient) for point (x,y) using 1st order // central differences. 'hgtGrid' is a displacement map for Z coordinate. // void computeNormal(const Grid *hgtGrid, float x, float y, float dx, float dy, float mv, float &nx, float &ny, float &nz) { nx = ny = 0.0; nz = 1.0; if (!hgtGrid) return; // Missing value? // if ((hgtGrid->GetValue(x, y)) == mv) return; float z_xpdx = hgtGrid->GetValue(x + dx, y); if (z_xpdx == mv) { z_xpdx = x; } float z_xmdx = hgtGrid->GetValue(x - dx, y); if (z_xmdx == mv) { z_xmdx = x; } float z_ypdy = hgtGrid->GetValue(x, y + dy); if (z_ypdy == mv) { z_ypdy = y; } float z_ymdy = hgtGrid->GetValue(x, y - dy); if (z_ymdy == mv) { z_ymdy = x; } float dzx = z_xpdx - z_xmdx; float dzy = z_ypdy - z_ymdy; nx = dy * dzx; ny = dx * dzy; nz = 1.0; } } // namespace TwoDDataRenderer::TwoDDataRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr) : TwoDRenderer(pm, winName, dataSetName, TwoDDataParams::GetClassType(), TwoDDataRenderer::GetClassType(), instName, dataMgr) { _grid_state.clear(); _tex_state.clear(); _texWidth = 0; _texHeight = 0; _texelSize = 8; _vertsWidth = 0; _vertsHeight = 0; _nindices = 0; _nverts = 0; _colormap = NULL; _colormapsize = 0; _cMapTexID = 0; TwoDDataParams *rp = (TwoDDataParams *)GetActiveParams(); MapperFunction *tf = rp->GetMapperFunc(rp->GetVariableName()); _colormapsize = tf->getNumEntries(); _colormap = new GLfloat[_colormapsize * 4]; for (int i = 0; i < _colormapsize; i++) { _colormap[i * 4 + 0] = (float)i / (float)(_colormapsize - 1); _colormap[i * 4 + 1] = (float)i / (float)(_colormapsize - 1); _colormap[i * 4 + 2] = (float)i / (float)(_colormapsize - 1); _colormap[i * 4 + 3] = 1.0; } } TwoDDataRenderer::~TwoDDataRenderer() { if (_cMapTexID) glDeleteTextures(1, &_cMapTexID); if (_colormap) delete[] _colormap; } int TwoDDataRenderer::_initializeGL() { glGenTextures(1, &_cMapTexID); // // Standard colormap // glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_1D, _cMapTexID); glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, _colormapsize, 0, GL_RGBA, GL_FLOAT, _colormap); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, 0); return (TwoDRenderer::_initializeGL()); } int TwoDDataRenderer::_paintGL(bool fast) { if (CheckGLError() != 0) return (-1); TwoDDataParams *rp = (TwoDDataParams *)GetActiveParams(); MapperFunction *tf = rp->GetMapperFunc(rp->GetVariableName()); tf->makeLut(_colormap); vector crange = tf->getMinMaxMapValue(); int rc; #ifndef NOSHADER string effect = getEffectInstance(GridAligned); // 2D Data LIGHT parameters hard coded // // _shaderMgr->UploadEffectData(effect, "lightingEnabled", (int) false); // _shaderMgr->UploadEffectData(effect, "kd", (float) 0.6); // _shaderMgr->UploadEffectData(effect, "ka", (float) 0.3); // _shaderMgr->UploadEffectData(effect, "ks", (float) 0.1); // _shaderMgr->UploadEffectData(effect, "expS", (float) 16.0); // _shaderMgr->UploadEffectData( effect, "lightDirection", (float) 0.0, (float) 0.0, (float) 1.0); #endif ShaderProgram *s = _glManager->shaderManager->GetShader("2DData"); if (s == nullptr) return -1; s->Bind(); s->SetUniform("minLUTValue", (float)crange[0]); s->SetUniform("maxLUTValue", (float)crange[1]); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, _cMapTexID); // Really only need to reload colormap texture if it changes // glTexSubImage1D(GL_TEXTURE_1D, 0, 0, _colormapsize, GL_RGBA, GL_FLOAT, _colormap); glActiveTexture(GL_TEXTURE0); rc = TwoDRenderer::_paintGL(fast); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, 0); return (rc); } const GLvoid *TwoDDataRenderer::GetTexture(DataMgr *dataMgr, GLsizei &width, GLsizei &height, GLint &internalFormat, GLenum &format, GLenum &type, size_t &texelSize, bool &gridAligned) { internalFormat = GL_RG32F; format = GL_RG; type = GL_FLOAT; texelSize = _texelSize; gridAligned = GridAligned; GLvoid *texture = (GLvoid *)_getTexture(dataMgr); if (!texture) return (NULL); width = _texWidth; height = _texHeight; return (texture); } int TwoDDataRenderer::GetMesh(DataMgr *dataMgr, GLfloat **verts, GLfloat **normals, GLsizei &nverts, GLsizei &width, GLsizei &height, GLuint **indices, GLsizei &nindices, bool &structuredMesh) { width = 0; height = 0; nindices = 0; nverts = 0; // See if already in cache // if (!_gridStateDirty() && _sb_verts.GetBuf()) { width = _vertsWidth; height = _vertsHeight; *verts = (GLfloat *)_sb_verts.GetBuf(); *normals = (GLfloat *)_sb_normals.GetBuf(); nverts = _nverts; nindices = _nindices; *indices = (GLuint *)_sb_indices.GetBuf(); return (0); } _gridStateClear(); TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams(); int refLevel = rParams->GetRefinementLevel(); int lod = rParams->GetCompressionLevel(); // Find box extents for ROI // size_t ts = rParams->GetCurrentTimestep(); CoordType minBoxReq = {0.0, 0.0, 0.0}; CoordType maxBoxReq = {0.0, 0.0, 0.0}; rParams->GetBox()->GetExtents(minBoxReq, maxBoxReq); string varname = rParams->GetVariableName(); int orientation = _getOrientation(dataMgr, varname); if (orientation != 2) { SetErrMsg("Only XY plane orientations currently supported"); return (-1); } Grid *g = NULL; int rc = DataMgrUtils::GetGrids(dataMgr, ts, varname, minBoxReq, maxBoxReq, true, &refLevel, &lod, &g); if (rc < 0) return (-1); VAssert(g); double defaultZ = GetDefaultZ(dataMgr, rParams->GetCurrentTimestep()); if (dynamic_cast(g) && !ForceUnstructured) { rc = _getMeshStructured(dataMgr, dynamic_cast(g), defaultZ); structuredMesh = true; } else { rc = _getMeshUnStructured(dataMgr, g, defaultZ); structuredMesh = false; } delete g; if (rc < 0) return (-1); _gridStateSet(); *verts = (GLfloat *)_sb_verts.GetBuf(); *normals = (GLfloat *)_sb_normals.GetBuf(); nverts = _nverts; *indices = (GLuint *)_sb_indices.GetBuf(); width = _vertsWidth; height = _vertsHeight; nindices = _nindices; return (0); } bool TwoDDataRenderer::_gridStateDirty() const { TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams(); DC::DataVar dvar; _dataMgr->GetDataVarInfo(rParams->GetVariableName(), dvar); vector minExts, maxExts; rParams->GetBox()->GetExtents(minExts, maxExts); _grid_state_c current_state(_dataMgr->GetNumRefLevels(rParams->GetVariableName()), rParams->GetRefinementLevel(), rParams->GetCompressionLevel(), rParams->GetHeightVariableName(), dvar.GetMeshName(), rParams->GetCurrentTimestep(), minExts, maxExts); return (_grid_state != current_state); } void TwoDDataRenderer::_gridStateClear() { _grid_state.clear(); } void TwoDDataRenderer::_gridStateSet() { TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams(); DC::DataVar dvar; _dataMgr->GetDataVarInfo(rParams->GetVariableName(), dvar); vector minExts, maxExts; rParams->GetBox()->GetExtents(minExts, maxExts); string meshName; _grid_state = _grid_state_c(_dataMgr->GetNumRefLevels(rParams->GetVariableName()), rParams->GetRefinementLevel(), rParams->GetCompressionLevel(), rParams->GetHeightVariableName(), dvar.GetMeshName(), rParams->GetCurrentTimestep(), minExts, maxExts); } bool TwoDDataRenderer::_texStateDirty(DataMgr *dataMgr) const { TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams(); vector minExts, maxExts; rParams->GetBox()->GetExtents(minExts, maxExts); _tex_state_c current_state(rParams->GetRefinementLevel(), rParams->GetCompressionLevel(), rParams->GetVariableName(), rParams->GetCurrentTimestep(), minExts, maxExts); return (_tex_state != current_state); } void TwoDDataRenderer::_texStateSet(DataMgr *dataMgr) { TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams(); vector minExts, maxExts; rParams->GetBox()->GetExtents(minExts, maxExts); _tex_state = _tex_state_c(rParams->GetRefinementLevel(), rParams->GetCompressionLevel(), rParams->GetVariableName(), rParams->GetCurrentTimestep(), minExts, maxExts); } void TwoDDataRenderer::_texStateClear() { _tex_state.clear(); } // Get mesh for a structured grid // int TwoDDataRenderer::_getMeshStructured(DataMgr *dataMgr, const StructuredGrid *g, double defaultZ) { TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams(); auto dims = g->GetDimensions(); VAssert(dims[2] == 1); _vertsWidth = dims[0]; _vertsHeight = dims[1]; _nindices = _vertsWidth * 2; // (Re)allocate space for verts // _nverts = _vertsWidth * _vertsHeight; _sb_verts.Alloc(_nverts * 3 * sizeof(GLfloat)); _sb_normals.Alloc(_nverts * 3 * sizeof(GLfloat)); _sb_indices.Alloc(2 * _vertsWidth * sizeof(GLuint)); int rc; if (!rParams->GetHeightVariableName().empty()) { rc = _getMeshStructuredDisplaced(dataMgr, g, defaultZ); } else { rc = _getMeshStructuredPlane(dataMgr, g, defaultZ); } if (rc < 0) return (rc); // Compute vertex normals // GLfloat *verts = (GLfloat *)_sb_verts.GetBuf(); GLfloat *normals = (GLfloat *)_sb_normals.GetBuf(); ComputeNormals(verts, _vertsWidth, _vertsHeight, normals); // Construct indices for a triangle strip covering one row // of the mesh // GLuint *indices = (GLuint *)_sb_indices.GetBuf(); for (GLuint i = 0; i < _vertsWidth; i++) indices[2 * i] = i; for (GLuint i = 0; i < _vertsWidth; i++) indices[2 * i + 1] = i + _vertsWidth; return (0); } // Get mesh for an unstructured grid // int TwoDDataRenderer::_getMeshUnStructured(DataMgr *dataMgr, const Grid *g, double defaultZ) { VAssert(g->GetTopologyDim() == 2); auto dims = g->GetDimensions(); // Unstructured 2d grids are stored in 1d // _vertsWidth = std::accumulate(dims.begin(), dims.end(), 1ul, std::multiplies()); _vertsHeight = 1; // Count the number of triangle vertex indices needed // size_t maxVertexPerCell = g->GetMaxVertexPerCell(); vector nodes(maxVertexPerCell); _nindices = 0; Grid::ConstCellIterator citr; Grid::ConstCellIterator endcitr = g->ConstCellEnd(); for (citr = g->ConstCellBegin(); citr != endcitr; ++citr) { const DimsType &cell = *citr; g->GetCellNodes(DimsType{cell[0], 0, 0}, nodes); if (nodes.size() < 3) continue; // degenerate _nindices += 3 * (nodes.size() - 2); } // (Re)allocate space for verts // _nverts = _vertsWidth; _sb_verts.Alloc(_nverts * 3 * sizeof(GLfloat)); _sb_normals.Alloc(_nverts * 3 * sizeof(GLfloat)); _sb_indices.Alloc(_nindices * sizeof(GLuint)); return (_getMeshUnStructuredHelper(dataMgr, g, defaultZ)); return 0; } int TwoDDataRenderer::_getMeshUnStructuredHelper(DataMgr *dataMgr, const Grid *g, double defaultZ) { TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams(); // Construct the displaced (terrain following) grid using // a map projection, if specified. // size_t ts = rParams->GetCurrentTimestep(); int refLevel = rParams->GetRefinementLevel(); int lod = rParams->GetCompressionLevel(); // Find box extents for ROI // CoordType minExts, maxExts; g->GetUserExtents(minExts, maxExts); // Try to get requested refinement level or the nearest acceptable level: // string hgtvar = rParams->GetHeightVariableName(); Grid *hgtGrid = NULL; if (!hgtvar.empty()) { int rc = DataMgrUtils::GetGrids(dataMgr, ts, hgtvar, minExts, maxExts, true, &refLevel, &lod, &hgtGrid); if (rc < 0) return (rc); VAssert(hgtGrid); } VAssert(g->GetTopologyDim() == 2); GLfloat *verts = (GLfloat *)_sb_verts.GetBuf(); GLfloat *normals = (GLfloat *)_sb_normals.GetBuf(); GLuint * indices = (GLuint *)_sb_indices.GetBuf(); double mv = hgtGrid ? hgtGrid->GetMissingValue() : 0.0; // Hard-code dx and dy for gradient calculation :-( // float dx = (maxExts[0] - minExts[0]) / 1000.0; float dy = (maxExts[1] - minExts[1]) / 1000.0; // // Visit each node in the grid, build a list of vertices // Grid::ConstNodeIterator nitr; Grid::ConstNodeIterator endnitr = g->ConstNodeEnd(); size_t voffset = 0; for (nitr = g->ConstNodeBegin(); nitr != endnitr; ++nitr) { CoordType coords; g->GetUserCoordinates(*nitr, coords); // Lookup vertical coordinate displacement as a data element // from the // height variable. Note, missing values are possible if image // extents are out side of extents for height variable, or if // height variable itself contains missing values. // double deltaZ = hgtGrid ? hgtGrid->GetValue(coords) : 0.0; if (deltaZ == mv) deltaZ = 0.0; verts[voffset + 0] = coords[0]; verts[voffset + 1] = coords[1]; verts[voffset + 2] = deltaZ - defaultZ; // Compute the surface normal using central differences // computeNormal(hgtGrid, coords[0], coords[1], dx, dy, mv, normals[voffset + 0], normals[voffset + 1], normals[voffset + 2]); voffset += 3; } // // Visit each cell in the grid. For each cell triangulate it and // and compute an index // array for the triangle list // size_t maxVertexPerCell = g->GetMaxVertexPerCell(); vector nodes(maxVertexPerCell); Grid::ConstCellIterator citr; Grid::ConstCellIterator endcitr = g->ConstCellEnd(); size_t index = 0; for (citr = g->ConstCellBegin(); citr != endcitr; ++citr) { const DimsType &cell = *citr; g->GetCellNodes(DimsType{cell[0], 0, 0}, nodes); if (nodes.size() < 3) continue; // degenerate // Compute triangle node indices, with common vertex at // nodes[0] // for (int i = 0; i < nodes.size() - 2; i++) { indices[index++] = nodes[0][0]; indices[index++] = nodes[i + 1][0]; indices[index++] = nodes[i + 2][0]; } } if (hgtGrid) { delete hgtGrid; } return (0); } // Get mesh for a structured grid displaced by a height field // int TwoDDataRenderer::_getMeshStructuredDisplaced(DataMgr *dataMgr, const StructuredGrid *g, double defaultZ) { TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams(); // Construct the displaced (terrain following) grid using // a map projection, if specified. // size_t ts = rParams->GetCurrentTimestep(); int refLevel = rParams->GetRefinementLevel(); int lod = rParams->GetCompressionLevel(); // Find box extents for ROI // CoordType minExtsReq = {0.0, 0.0, 0.0}; CoordType maxExtsReq = {0.0, 0.0, 0.0}; rParams->GetBox()->GetExtents(minExtsReq, maxExtsReq); // Try to get requested refinement level or the nearest acceptable level: // string hgtvar = rParams->GetHeightVariableName(); VAssert(!hgtvar.empty()); Grid *hgtGrid = NULL; int rc = DataMgrUtils::GetGrids(dataMgr, ts, hgtvar, minExtsReq, maxExtsReq, true, &refLevel, &lod, &hgtGrid); if (rc < 0) return (rc); VAssert(hgtGrid); auto dims = g->GetDimensions(); VAssert(dims[2] == 1); size_t width = dims[0]; size_t height = dims[1]; GLfloat *verts = (GLfloat *)_sb_verts.GetBuf(); double mv = hgtGrid->GetMissingValue(); for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { double x, y, zdummy; g->GetUserCoordinates(i, j, x, y, zdummy); // Lookup vertical coordinate displacement as a data element from the // height variable. Note, missing values are possible if image // extents are out side of extents for height variable, or if // height variable itself contains missing values. // double deltaZ = hgtGrid->GetValue(x, y, 0.0); if (deltaZ == mv) deltaZ = 0.0; double z = deltaZ - defaultZ; verts[j * width * 3 + i * 3] = x; verts[j * width * 3 + i * 3 + 1] = y; verts[j * width * 3 + i * 3 + 2] = z; } } delete hgtGrid; return (rc); } // Get mesh for a structured grid that is NOT displaced by a height field. // I.e. it's planar. // int TwoDDataRenderer::_getMeshStructuredPlane(DataMgr *dataMgr, const StructuredGrid *g, double defaultZ) { auto dims = g->GetDimensions(); VAssert(dims[2] == 1); size_t width = dims[0]; size_t height = dims[1]; GLfloat *verts = (GLfloat *)_sb_verts.GetBuf(); for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { double x, y, zdummy; g->GetUserCoordinates(i, j, x, y, zdummy); double z = defaultZ; verts[j * width * 3 + i * 3] = x; verts[j * width * 3 + i * 3 + 1] = y; verts[j * width * 3 + i * 3 + 2] = z; } } return (0); } int TwoDDataRenderer::_getOrientation(DataMgr *dataMgr, string varname) { vector coordvars; bool ok = dataMgr->GetVarCoordVars(varname, true, coordvars); if (!ok) return -1; VAssert(coordvars.size() == 2); vector axes; // order list of coordinate axes for (int i = 0; i < coordvars.size(); i++) { DC::CoordVar cvar; dataMgr->GetCoordVarInfo(coordvars[i], cvar); axes.push_back(cvar.GetAxis()); } if (axes[0] == 0) { if (axes[1] == 1) return (2); // X-Y else return (1); // X-Z } VAssert(axes[0] == 1 && axes[2] == 2); return (0); // Y-Z } // Sets _texWidth, _texHeight, _sb_texture // const GLvoid *TwoDDataRenderer::_getTexture(DataMgr *dataMgr) { // See if already in cache // if (!_texStateDirty(dataMgr) && _sb_texture.GetBuf()) { return ((const GLvoid *)_sb_texture.GetBuf()); } _texStateClear(); TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams(); size_t ts = rParams->GetCurrentTimestep(); int refLevel = rParams->GetRefinementLevel(); int lod = rParams->GetCompressionLevel(); string varname = rParams->GetVariableName(); if (varname.empty()) { SetErrMsg("No variable name specified"); return (NULL); } // Find box extents for ROI // CoordType minBoxReq = {0.0, 0.0, 0.0}; CoordType maxBoxReq = {0.0, 0.0, 0.0}; rParams->GetBox()->GetExtents(minBoxReq, maxBoxReq); Grid *g = NULL; int rc = DataMgrUtils::GetGrids(dataMgr, ts, varname, minBoxReq, maxBoxReq, true, &refLevel, &lod, &g); if (rc < 0) return (NULL); if (g->GetTopologyDim() != 2) { SetErrMsg("Invalid variable: %s ", varname.c_str()); return (NULL); } // For structured grid variable data are stored in a 2D array. // For structured grid variable data are stored in a 1D array. // auto dims = g->GetDimensions(); if (dynamic_cast(g) && !ForceUnstructured) { _texWidth = dims[0]; _texHeight = dims[1]; } else { _texWidth = std::accumulate(dims.begin(), dims.end(), 1, std::multiplies()); _texHeight = 1; } size_t texSize = _texWidth * _texHeight; GLfloat * texture = (float *)_sb_texture.Alloc(texSize * _texelSize); GLfloat * texptr = texture; Grid::Iterator itr; Grid::Iterator enditr = g->end(); // for (itr = g->begin(minBoxReq, maxBoxReq); itr != enditr; ++itr) { for (itr = g->begin(); itr != enditr; ++itr) { float v = *itr; if (v == g->GetMissingValue()) { *texptr++ = 0.0; // Data value *texptr++ = 1.0; // Missing value flag } else { *texptr++ = v; *texptr++ = 0; } } _texStateSet(dataMgr); return (texture); } ================================================ FILE: lib/render/TwoDRenderer.cpp ================================================ //--------------------------------------------------------------------------- // // Copyright (C) 2011 // University Corporation for Atmospheric Research // All Rights Reserved // //---------------------------------------------------------------------------- #include // Must be included first!!! #include #include #include #include #include #include "vapor/GLManager.h" using namespace VAPoR; using namespace Wasp; //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- TwoDRenderer::TwoDRenderer(const ParamsMgr *pm, string winName, string dataSetName, string paramsType, string classType, string instName, DataMgr *dataMgr) : Renderer(pm, winName, dataSetName, paramsType, classType, instName, dataMgr) { _textureID = 0; _texture = NULL; _texCoords = NULL; _texWidth = 0; _texHeight = 0; _texInternalFormat = 0; _texFormat = GL_RGBA; _texType = GL_UNSIGNED_BYTE; _texelSize = 0; _gridAligned = false; _structuredMesh = false; _verts = NULL; _normals = NULL; _meshWidth = 0; _meshHeight = 0; _VAO = (int)NULL; _VBO = (int)NULL; _dataVBO = (int)NULL; _EBO = (int)NULL; } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- TwoDRenderer::~TwoDRenderer() { if (_textureID) glDeleteTextures(1, &_textureID); if (_VAO) glDeleteVertexArrays(1, &_VAO); if (_VBO) glDeleteBuffers(1, &_VBO); if (_dataVBO) glDeleteBuffers(1, &_dataVBO); if (_EBO) glDeleteBuffers(1, &_EBO); } int TwoDRenderer::_initializeGL() { glGenTextures(1, &_textureID); glGenVertexArrays(1, &_VAO); glGenBuffers(1, &_VBO); glGenBuffers(1, &_dataVBO); glGenBuffers(1, &_EBO); glBindVertexArray(_VAO); glBindBuffer(GL_ARRAY_BUFFER, _VBO); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), NULL); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, _dataVBO); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), NULL); glEnableVertexAttribArray(1); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); return (0); } int TwoDRenderer::_paintGL(bool) { // Get the 2D texture // _texture = GetTexture(_dataMgr, _texWidth, _texHeight, _texInternalFormat, _texFormat, _texType, _texelSize, _gridAligned); if (!_texture) { return (-1); } VAssert(_texWidth >= 1); VAssert(_texHeight >= 1); // Get the proxy geometry used to render the 2D surface (vertices and // normals) // int rc = GetMesh(_dataMgr, &_verts, &_normals, _nverts, _meshWidth, _meshHeight, &_indices, _nindices, _structuredMesh); if (rc < 0) { return (-1); } if (!_gridAligned) { VAssert(_structuredMesh); if (_meshWidth<2 || _meshHeight<2) return 0; // If mesh with or height is too small for a texture, harmlessly return _texCoords = (GLfloat *)_sb_texCoords.Alloc(_meshWidth * _meshHeight * 2 * sizeof(*_texCoords)); _computeTexCoords(_texCoords, _meshWidth, _meshHeight); _renderMeshUnAligned(); } else { VAssert(_meshWidth == _texWidth); VAssert(_meshHeight == _texHeight); _renderMeshAligned(); } GL_ERR_BREAK(); return (0); } void TwoDRenderer::_openGLInit() { if (!_gridAligned) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _textureID); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, _texInternalFormat, _texWidth, _texHeight, 0, _texFormat, _texType, _texture); } _glManager->matrixManager->MatrixModeModelView(); glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(GL_TRUE); } void TwoDRenderer::_openGLRestore() { glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); } void TwoDRenderer::_renderMeshUnAligned() { // This appears to be pretty much the Image Renderer code RenderParams *myParams = (RenderParams *)GetActiveParams(); float opacity = myParams->GetConstantOpacity(); ShaderProgram *shader = _glManager->shaderManager->GetShader("Image"); if (shader == nullptr) return; shader->Bind(); shader->SetUniform("MVP", _glManager->matrixManager->GetModelViewProjectionMatrix()); shader->SetUniform("constantOpacity", opacity); EnableClipToBox(shader); _openGLInit(); int W = _meshWidth; int H = _meshHeight; glBindVertexArray(_VAO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2 * W * sizeof(GLuint), _indices, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, _VBO); glBufferData(GL_ARRAY_BUFFER, H * W * 3 * sizeof(float), _verts, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, _dataVBO); glBufferData(GL_ARRAY_BUFFER, H * W * 2 * sizeof(float), _texCoords, GL_DYNAMIC_DRAW); for (int j = 0; j < H - 1; j++) glDrawElementsBaseVertex(GL_TRIANGLE_STRIP, 2 * W, GL_UNSIGNED_INT, 0, j * W); glBindVertexArray(0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); _openGLRestore(); DisableClippingPlanes(); } void TwoDRenderer::_renderMeshAligned() { RenderParams *myParams = (RenderParams *)GetActiveParams(); float opacity = myParams->GetConstantOpacity(); ShaderProgram *shader = _glManager->shaderManager->GetShader("2DData"); if (shader == nullptr) return; shader->Bind(); shader->SetUniform("MVP", _glManager->matrixManager->GetModelViewProjectionMatrix()); shader->SetUniform("constantOpacity", opacity); EnableClipToBox(shader); _openGLInit(); // Ugh. For aligned data the type must be GLfloat. // VAssert(_texType == GL_FLOAT); VAssert(_texelSize == 8); const GLfloat *data = (GLfloat *)_texture; if (_structuredMesh) { // Draw triangle strips one row at a time // glBindVertexArray(_VAO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2 * _meshWidth * sizeof(GLuint), _indices, GL_DYNAMIC_DRAW); for (int j = 0; j < _meshHeight - 1; j++) { glBindBuffer(GL_ARRAY_BUFFER, _VBO); glBufferData(GL_ARRAY_BUFFER, _meshWidth * 6 * sizeof(float), &_verts[j * _meshWidth * 3], GL_STREAM_DRAW); glBindBuffer(GL_ARRAY_BUFFER, _dataVBO); glBufferData(GL_ARRAY_BUFFER, _meshWidth * 4 * sizeof(float), &data[j * _meshWidth * 2], GL_STREAM_DRAW); glDrawElements(GL_TRIANGLE_STRIP, 2 * _meshWidth, GL_UNSIGNED_INT, 0); } } else { VAssert(_meshWidth >= 3); VAssert(_meshHeight == 1); VAssert((_nindices % 3) == 0); glBindVertexArray(_VAO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, _nindices * sizeof(GLsizei), _indices, GL_STREAM_DRAW); glBindBuffer(GL_ARRAY_BUFFER, _VBO); glBufferData(GL_ARRAY_BUFFER, _nverts * 3 * sizeof(float), _verts, GL_STREAM_DRAW); glBindBuffer(GL_ARRAY_BUFFER, _dataVBO); glBufferData(GL_ARRAY_BUFFER, _nverts * 2 * sizeof(float), data, GL_STREAM_DRAW); // glNormalPointer(GL_FLOAT, 0, _normals); glDrawElements(GL_TRIANGLES, _nindices, GL_UNSIGNED_INT, 0); } glBindVertexArray(0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); _openGLRestore(); DisableClippingPlanes(); } void TwoDRenderer::ComputeNormals(const GLfloat *verts, GLsizei w, GLsizei h, GLfloat *normals) { // Go over the grid of vertices, calculating normals // by looking at adjacent x,y,z coords. // for (int j = 0; j < h; j++) { for (int i = 0; i < w; i++) { const GLfloat *point = verts + 3 * (i + w * j); GLfloat * norm = normals + 3 * (i + w * j); // do differences of right point vs left point, // except at edges of grid just do differences // between current point and adjacent point: float dx = 0.f, dy = 0.f, dzx = 0.f, dzy = 0.f; if (i > 0 && i < w - 1) { dx = *(point + 3) - *(point - 3); dzx = *(point + 5) - *(point - 1); } else if (i == 0) { dx = *(point + 3) - *(point); dzx = *(point + 5) - *(point + 2); } else if (i == w - 1) { dx = *(point) - *(point - 3); dzx = *(point + 2) - *(point - 1); } if (j > 0 && j < h - 1) { dy = *(point + 1 + 3 * w) - *(point + 1 - 3 * w); dzy = *(point + 2 + 3 * w) - *(point + 2 - 3 * w); } else if (j == 0) { dy = *(point + 1 + 3 * w) - *(point + 1); dzy = *(point + 2 + 3 * w) - *(point + 2); } else if (j == h - 1) { dy = *(point + 1) - *(point + 1 - 3 * w); dzy = *(point + 2) - *(point + 2 - 3 * w); } norm[0] = dy * dzx; norm[1] = dx * dzy; norm[2] = 1.0; // vnormal(norm); } } } void TwoDRenderer::_computeTexCoords(GLfloat *tcoords, size_t w, size_t h) const { if (_meshWidth<2 || _meshHeight<2) return; double deltax = 1.0 / (_meshWidth - 1); double deltay = 1.0 / (_meshHeight - 1); for (int j = 0; j < h; j++) { for (int i = 0; i < w; i++) { tcoords[(2 * j * w) + (2 * i + 0)] = i * deltax; tcoords[(2 * j * w) + (2 * i + 1)] = j * deltay; } } } ================================================ FILE: lib/render/Visualizer.cpp ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: Visualizer.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: September, 2013 // #include // Must be included first!!! #include #include #include #include #include "vapor/VAssert.h" #ifdef WIN32 #include #else #include #include #endif #ifdef WIN32 #pragma warning(disable : 4996) #endif #include "vapor/ContourRenderer.h" #include #include #include #include #include #include #include #include #include #include "vapor/GLManager.h" #include "vapor/LegacyGL.h" #include #include "vapor/ImageWriter.h" #include "vapor/GeoTIFWriter.h" #include "vapor/ImageRenderer.h" #include "vapor/VolumeRenderer.h" #include "vapor/WireFrameRenderer.h" using namespace VAPoR; Visualizer::Visualizer(const ParamsMgr *pm, const DataStatus *dataStatus, string winName) { MyBase::SetDiagMsg("Visualizer::Visualizer() begin"); _paramsMgr = pm; _dataStatus = dataStatus; _winName = winName; _glManager = nullptr; _vizFeatures = new AnnotationRenderer(_paramsMgr, _dataStatus, _winName); _insideGLContext = false; _imageCaptureEnabled = false; _animationCaptureEnabled = false; _renderers.clear(); _renderersToDestroy.clear(); MyBase::SetDiagMsg("Visualizer::Visualizer() end"); } Visualizer::~Visualizer() { #ifdef VAPOR_3_1_0 // Can't call renderer destructors because these free OpenGL resources that // may require the OpenGL context to be current :-( // for (int i = 0; i < _renderers.size(); i++) delete _renderers[i]; _renderers.clear(); #endif if (_vizFeatures) delete _vizFeatures; if (_screenQuadVAO) glDeleteVertexArrays(1, &_screenQuadVAO); if (_screenQuadVBO) glDeleteBuffers(1, &_screenQuadVBO); } int Visualizer::resizeGL(int wid, int ht) { return 0; } int Visualizer::_getCurrentTimestep() const { vector dataSetNames = _dataStatus->GetDataMgrNames(); bool first = true; size_t min_ts = 0; size_t max_ts = 0; for (int i = 0; i < dataSetNames.size(); i++) { vector rParams; _paramsMgr->GetRenderParams(_winName, dataSetNames[i], rParams); if (rParams.size()) { // Use local time of first RenderParams instance on window // for current data set. I.e. it is assumed that every // RenderParams instance for a data set has same current // time step. // size_t local_ts = rParams[0]->GetCurrentTimestep(); size_t my_min_ts, my_max_ts; _dataStatus->MapLocalToGlobalTimeRange(dataSetNames[i], local_ts, my_min_ts, my_max_ts); if (first) { min_ts = my_min_ts; max_ts = my_max_ts; first = false; } else { if (my_min_ts > min_ts) min_ts = my_min_ts; if (my_max_ts < max_ts) max_ts = my_max_ts; } } } if (min_ts > max_ts) return (-1); return (min_ts); } void Visualizer::_applyDatasetTransformsForRenderer(Renderer *r) { string datasetName = r->GetMyDatasetName(); Transform *t = getActiveViewpointParams()->GetTransform(datasetName); VAssert(t); Renderer::ApplyDatasetTransform(_glManager, t); } void Visualizer::syncWithParams() { _deleteFlaggedRenderers(); vector toRemove; for (const auto &r : _renderers) if (r->GetActiveParams() == nullptr) toRemove.push_back(r); if (_dataStatus->WasCacheDirty()) toRemove = _renderers; for (const auto &r : toRemove) { _renderers.erase(std::find(_renderers.begin(), _renderers.end(), r)); delete r; } vector populatedRenderParams; for (const auto &r : _renderers) populatedRenderParams.push_back(r->GetActiveParams()); vector rendererParams; _paramsMgr->GetRenderParams(_winName, rendererParams); for (const auto &rp : rendererParams) { if (!STLUtils::Contains(populatedRenderParams, rp)) { string win, dataset, Class, name; _paramsMgr->RenderParamsLookup(rp, name, win, dataset, Class); CreateRenderer(dataset, RendererFactory::Instance()->GetRenderClassFromParamsClass(Class), name); } } } int Visualizer::renderRenderer(Renderer* renderer, bool fast) { _glManager->matrixManager->MatrixModeModelView(); _glManager->matrixManager->PushMatrix(); if (renderer->IsGLInitialized()) { _applyDatasetTransformsForRenderer(renderer); // void *t = _glManager->BeginTimer(); int myrc = renderer->paintGL(fast); // printf("%s: %f\n", _renderers[i]->GetMyName().c_str(), _glManager->EndTimer(t)); GL_ERR_BREAK(); if (myrc < 0) myrc = -1; } MatrixManager *mm = _glManager->matrixManager; mm->MatrixModeModelView(); mm->PopMatrix(); int myrc = CheckGLErrorMsg(renderer->GetMyName().c_str()); if (myrc < 0) myrc = -1; return myrc; } glm::vec3 box_min(const Box* b) { CoordType min, max; b->GetExtents(min, max); return glm::make_vec3(min.data()); } glm::vec3 box_max(const Box* b) { CoordType min, max; b->GetExtents(min, max); return glm::make_vec3(max.data()); } struct AABB { glm::vec3 min, max; AABB() : min(0.f), max(0.f) {} AABB(const glm::vec3 &min, const glm::vec3 &max) : min(min), max(max) {} AABB(const Box *b) : AABB(box_min(b), box_max(b)) {} AABB(const vector &pts) : min(pts[0]), max(pts[0]) { for (const auto &p : pts) add(p); } void add(const glm::vec3 p) { min = glm::min(min, p); max = glm::max(max, p); } glm::vec3 center() const { return (min+max)*0.5f; } bool intersects(const AABB &b) const { return intersects(*this, b); } static bool intersects(const AABB &a, const AABB &b) { auto al = a.min; auto ah = a.max; auto bl = b.min; auto bh = b.max; return !( bl.x > ah.x || bh.x < al.x || bl.y > ah.y || bh.y < al.y || bl.z > ah.z || bh.z < al.z ); } string str() const { return "{ " + std::to_string(min.x) + "->" + std::to_string(max.x) + " " + std::to_string(min.y) + "->" + std::to_string(max.y) + " " + std::to_string(min.z) + "->" + std::to_string(max.z) + " }"; } }; AABB operator*(const glm::mat4 &m, const AABB &b) { vector pts = { {b.min.x, b.min.y, b.min.z}, {b.max.x, b.min.y, b.min.z}, {b.min.x, b.max.y, b.min.z}, {b.max.x, b.max.y, b.min.z}, {b.min.x, b.min.y, b.max.z}, {b.max.x, b.min.y, b.max.z}, {b.min.x, b.max.y, b.max.z}, {b.max.x, b.max.y, b.max.z}, }; for (int i = 0; i < pts.size(); i++) pts[i] = m * glm::vec4(pts[i], 1.0f); return {pts}; } AABB rendererTransformedBB(const Renderer *r) { MatrixManager mm; AABB b = r->GetActiveParams()->GetBox(); r->ApplyTransform(&mm); return mm.GetModelViewMatrix() * b; } glm::vec3 rendererTransformedCenter(const Renderer *r) { MatrixManager mm; AABB b = r->GetActiveParams()->GetBox(); r->ApplyTransform(&mm); return mm.GetModelViewMatrix() * glm::vec4(b.center(), 1.0f); } double rendererDistanceToCamera(const Renderer *r) { const auto vp = r->GetViewpointParams(); glm::vec3 cameraPos; { double cameraPosD[3], _[3]; vp->ReconstructCamera(vp->GetModelViewMatrix().data(), cameraPosD, _, _); cameraPos = glm::make_vec3(cameraPosD); } glm::vec3 c = rendererTransformedCenter(r); return glm::length(cameraPos - c); } template bool approxEqual(T a, T b) { return abs(b-a) <= max(a,b) * std::numeric_limits::epsilon(); } auto rankRendererTypeOrder(const Renderer *r) { if (dynamic_cast(r)) return 0; if (dynamic_cast(r)) return 1; auto w = dynamic_cast(r); if (w && w->GetActiveParams()->GetRenderDim() == 2) return 2; if (dynamic_cast(r)) return 3; return 4; }; std::pair>, vector> autoOrder2DRenderers(const vector &in) { if (in.empty()) return {}; auto ret = in; std::sort(ret.begin(), ret.end(), [](const Renderer *a, const Renderer *b) { float az = rendererTransformedCenter(a).z; float bz = rendererTransformedCenter(b).z; if (!approxEqual(az, bz)) return az < bz; if (!rendererTransformedBB(a).intersects(rendererTransformedBB(b))) return rendererTransformedCenter(a).x < rendererTransformedCenter(b).x; if (rankRendererTypeOrder(a) != rankRendererTypeOrder(b)) return rankRendererTypeOrder(a) < rankRendererTypeOrder(b); return a->GetInstanceName() < b->GetInstanceName(); }); map> ogTrans; int starti = 0; // string startData = in[0]->GetMyDatasetName(); double offsetCum = 0; for (int i = 0; i <= ret.size(); i++) { if (i == ret.size() || ret[i]->GetActiveParams()->GetTransform()->GetTranslations()[2] != 0) { for (int j = starti; j < i && i-starti>1; j++) { ogTrans[ret[j]] = ret[j]->GetActiveParams()->GetTransform()->GetTranslations(); double offset = rendererDistanceToCamera(ret[j]) / ret[j]->GetDatasetTransform()->GetScales()[2] * 0.0003; ret[j]->GetActiveParams()->GetTransform()->SetTranslations({ogTrans[ret[j]][0], ogTrans[ret[j]][1], offsetCum + offset}); offsetCum += offset; } starti = i; // startData = i==ret.size() ? "" : in[i]->GetMyDatasetName(); } } return std::make_pair(ogTrans, ret); } vector getRenderOrder(const vector &in) { if (in.empty()) return {}; const auto vp = in[0]->GetViewpointParams(); glm::vec3 cameraPos; { double cameraPosD[3], _[3]; vp->ReconstructCamera(vp->GetModelViewMatrix().data(), cameraPosD, _, _); cameraPos = glm::make_vec3(cameraPosD); } // Not accounting for slice planes since those are currently not considered planar by the code list> order; auto transformedRenderer = [](Renderer *r) { MatrixManager mm; AABB b = r->GetActiveParams()->GetBox(); r->ApplyTransform(&mm); glm::vec3 c = mm.GetModelViewMatrix() * glm::vec4(b.center(), 1.0f); b = mm.GetModelViewMatrix() * b; return make_tuple(r, c, b); }; for (auto r : in) { if (dynamic_cast(r)) continue; const auto tr = transformedRenderer(r); float cameraDist = glm::length(cameraPos - std::get<1>(tr)); for (auto it = order.begin();; ++it) { if (it == order.end()) { order.insert(it, tr); break; } float itCameraDist = glm::length(cameraPos - std::get<1>(*it)); if (cameraDist > itCameraDist) { order.insert(it, tr); break; } } } for (auto r : in) { if (!dynamic_cast(r)) continue; const auto tr = transformedRenderer(r); float cameraDist = glm::length(cameraPos - std::get<1>(tr)); for (auto it = order.begin();; ++it) { if (it == order.end()) { order.insert(it, tr); break; } float itCameraDist = glm::length(cameraPos - std::get<1>(*it)); if (cameraDist > itCameraDist && !std::get<2>(tr).intersects(std::get<2>(*it))) { order.insert(it, tr); break; } } } vector ret; for (auto tr : order) ret.push_back(std::get<0>(tr)); return ret; } int Visualizer::paintEvent(bool fast) { _insideGLContext = true; MyBase::SetDiagMsg("Visualizer::paintGL()"); GL_ERR_BREAK(); // Do not proceed if there is no DataMgr if (!_paramsMgr->GetDataMgrNames().size()) return (0); syncWithParams(); if (_initializeNewRenderers() < 0) return -1; // Do not proceed with invalid viewport // This can occur sometimes on Qt startup int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); if (viewport[2] <= 0) return 0; if (viewport[3] <= 0) return 0; assert(_framebuffer.IsComplete()); _clearActiveFramebuffer(0.3, 0.3, 0.3); GL_ERR_BREAK(); int fbWidth = viewport[2]; int fbHeight = viewport[3]; ViewpointParams *vp = getActiveViewpointParams(); if (vp->GetValueLong(ViewpointParams::UseCustomFramebufferTag, 0)) { fbWidth = vp->GetValueLong(ViewpointParams::CustomFramebufferWidthTag, 0); fbHeight = vp->GetValueLong(ViewpointParams::CustomFramebufferHeightTag, 0); } _framebuffer.SetSize(fbWidth, fbHeight); GLint destFbId; glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &destFbId); _framebuffer.MakeRenderTarget(); GL_ERR_BREAK(); double clr[3]; getActiveAnnotationParams()->GetBackgroundColor(clr); _clearActiveFramebuffer(clr[0], clr[1], clr[2]); _loadMatricesFromViewpointParams(); if (_configureLighting()) return -1; glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Draw the domain frame and other in-scene features _vizFeatures->InScenePaint(_getCurrentTimestep()); GL_ERR_BREAK(); auto ret = autoOrder2DRenderers(_renderers); auto rendererTransOg = ret.first; auto renderersOrdered = ret.second; renderersOrdered = getRenderOrder(renderersOrdered); std::vector topRenderers; int rc = 0; for (int i = 0; i < renderersOrdered.size(); i++) { RenderParams* rp = _paramsMgr->GetRenderParams(_winName, renderersOrdered[i]->GetMyDatasetName(), renderersOrdered[i]->GetMyParamsType(), renderersOrdered[i]->GetMyName()); if (rp != nullptr && rp->GetDrawInFront()) { topRenderers.push_back(renderersOrdered[i]); continue; } rc = renderRenderer(renderersOrdered[i], fast); } glDepthFunc(GL_ALWAYS); glDisable(GL_DEPTH_TEST); for (int i=0; iGetActiveParams()->GetTransform()->SetTranslations(it.second); } _vizFeatures->DrawText(); GL_ERR_BREAK(); _renderColorbars(_getCurrentTimestep()); GL_ERR_BREAK(); _vizFeatures->DrawAxisArrows(); GL_ERR_BREAK(); // _glManager->ShowDepthBuffer(); glFlush(); int captureImageSuccess = 0; if (_imageCaptureEnabled) { captureImageSuccess = _captureImage(_captureImageFile); } else if (_animationCaptureEnabled) { captureImageSuccess = _captureImage(_captureImageFile); _incrementPath(_captureImageFile); } if (captureImageSuccess < 0) { SetErrMsg("Failed to save image"); return -1; } GL_ERR_BREAK(); if (CheckGLError()) return -1; _framebuffer.UnBind(); glBindFramebuffer(GL_FRAMEBUFFER, destFbId); glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); glBindVertexArray(_screenQuadVAO); SmartShaderProgram shader = _glManager->shaderManager->GetSmartShader("Framebuffer"); if (!shader.IsValid()) return -1; shader->SetSampler("colorBuffer", *_framebuffer.GetColorTexture()); shader->SetSampler("depthBuffer", *_framebuffer.GetDepthTexture()); glDepthFunc(GL_LEQUAL); glDepthMask(true); glEnable(GL_DEPTH_TEST); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); glDepthFunc(GL_LESS); _insideGLContext = false; return rc; } void Visualizer::_loadMatricesFromViewpointParams() { ViewpointParams *const vpParams = getActiveViewpointParams(); MatrixManager *const mm = _glManager->matrixManager; double m[16]; vpParams->GetProjectionMatrix(m); mm->MatrixModeProjection(); mm->LoadMatrixd(m); vpParams->GetModelViewMatrix(m); mm->MatrixModeModelView(); mm->LoadMatrixd(m); } int Visualizer::InitializeGL(GLManager *glManager) { if (!glManager->IsCurrentOpenGLVersionSupported()) return -1; _glManager = glManager; _vizFeatures->InitializeGL(glManager); if (GetVendor() == MESA) { SetErrMsg( "Your device appears to either not have hardware graphics support, or not have graphics drivers configured correctly for your device.\n" "Rendering performance may be significantly diminished, or in the case of some renderers, may not function at all." ); } _framebuffer.EnableDepthBuffer(); _framebuffer.Generate(); static float data[] = {-1, -1, 0, 0, 1, -1, 1, 0, -1, 1, 0, 1, -1, 1, 0, 1, 1, -1, 1, 0, 1, 1, 1, 1}; glGenVertexArrays(1, &_screenQuadVAO); glGenBuffers(1, &_screenQuadVBO); glBindVertexArray(_screenQuadVAO); glBindBuffer(GL_ARRAY_BUFFER, _screenQuadVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float))); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); return 0; } // Move to back of rendering list void Visualizer::MoveRendererToFront(string renderType, string renderName) { Renderer *ren = _getRenderer(renderType, renderName); if (!ren) return; auto it = std::find(_renderers.begin(), _renderers.end(), ren); VAssert(it != _renderers.end()); _renderers.erase(it); _renderers.push_back(ren); } void Visualizer::MoveRenderersOfTypeToFront(const std::string &type) { Renderer *firstRendererMoved = nullptr; auto rendererPointersCopy = _renderers; for (auto it = rendererPointersCopy.rbegin(); it != rendererPointersCopy.rend(); ++it) { if (*it == firstRendererMoved) break; if ((*it)->GetMyType() == type) { MoveRendererToFront((*it)->GetMyType(), (*it)->GetMyName()); if (firstRendererMoved == nullptr) firstRendererMoved = *it; } } } int Visualizer::CreateRenderer(string dataSetName, string renderType, string renderName) { if (HasRenderer(renderType, renderName)) return (0); Renderer *ren = RendererFactory::Instance()->CreateInstance(_paramsMgr, _winName, dataSetName, renderType, renderName, _dataStatus->GetDataMgr(dataSetName)); if (!ren) { SetErrMsg("Invalid renderer of type \"%s\"", renderType.c_str()); return (-1); } _renderers.push_back(ren); return (0); } void Visualizer::DestroyRenderer(string renderType, string renderName, bool haveOpenGLContext) { Renderer *ren = _getRenderer(renderType, renderName); if (!ren) return; _renderers.erase(std::find(_renderers.begin(), _renderers.end(), ren)); // If we have an active OpenGL context destroy the renderer immediately. Else // queue for later destruction // if (haveOpenGLContext) { delete ren; return; } // Don't add to queue if already there // for (auto it = _renderersToDestroy.begin(); it != _renderersToDestroy.end(); ++it) { if (*it == ren) return; } _renderersToDestroy.push_back(ren); } void Visualizer::DestroyAllRenderers(bool hasOpenGLContext) { vector renderersCopy = _renderers; for (auto it = renderersCopy.begin(); it != renderersCopy.end(); ++it) { Renderer *ren = *it; DestroyRenderer(ren->GetMyType(), ren->GetMyName(), hasOpenGLContext); } } bool Visualizer::HasRenderer(string renderType, string renderName) const { return (_getRenderer(renderType, renderName) != nullptr); } void Visualizer::ClearRenderCache() { for (int i = 0; i < _renderers.size(); i++) { _renderers[i]->ClearCache(); } } void Visualizer::ClearRenderCache(const string &inst) { for (int i = 0; i < _renderers.size(); i++) if (_renderers[i]->GetInstanceName() == inst) _renderers[i]->ClearCache(); } Renderer *Visualizer::_getRenderer(string type, string instance) const { for (auto it = _renderers.begin(); it != _renderers.end(); ++it) { Renderer *ren = *it; if (ren->GetMyType() == type && ren->GetMyName() == instance) { return (ren); } } return (NULL); } int Visualizer::_configureLighting() { const ViewpointParams *vpParams = getActiveViewpointParams(); size_t nLights = vpParams->getNumLights(); VAssert(nLights <= 1); LegacyGL *lgl = _glManager->legacy; float lightDir[4]; for (int i = 0; i < 4; i++) { lightDir[i] = vpParams->getLightDirection(0, i); } if (nLights > 0) { // TODO GL // GL_SHININESS = vpParams->getExponent()) // vpParams->getSpecularCoeff(0) // vpParams->getDiffuseCoeff(0) // vpParams->getAmbientCoeff() // All the geometry will get a white specular color: lgl->LightDirectionfv(lightDir); } if (CheckGLError()) return -1; return 0; } Visualizer::GLVendorType Visualizer::GetVendor() { string ven_str((const char *)glGetString(GL_VENDOR)); string ren_str((const char *)glGetString(GL_RENDERER)); for (int i = 0; i < ven_str.size(); i++) { if (isupper(ven_str[i])) ven_str[i] = tolower(ven_str[i]); } for (int i = 0; i < ren_str.size(); i++) { if (isupper(ren_str[i])) ren_str[i] = tolower(ren_str[i]); } if ((ven_str.find("mesa") != string::npos) || (ren_str.find("mesa") != string::npos)) { return (MESA); } else if ((ven_str.find("nvidia") != string::npos) || (ren_str.find("nvidia") != string::npos)) { return (NVIDIA); } else if ((ven_str.find("ati") != string::npos) || (ren_str.find("ati") != string::npos)) { return (ATI); } else if ((ven_str.find("intel") != string::npos) || (ren_str.find("intel") != string::npos)) { return (INTEL); } return (UNKNOWN); } double Visualizer::getPixelSize() const { #ifdef VAPOR3_0_0_ALPHA double temp[3]; // Window height is subtended by viewing angle (45 degrees), // at viewer distance (dist from camera to view center) const AnnotationParams *vfParams = getActiveAnnotationParams(); const ViewpointParams * vpParams = getActiveViewpointParams(); size_t width, height; vpParams->GetWindowSize(width, height); double center[3], pos[3]; vpParams->GetRotationCenter(center); vpParams->GetCameraPos(pos); vsub(center, pos, temp); // Apply stretch factor: vector stretch = vpParams->GetStretchFactors(); for (int i = 0; i < 3; i++) temp[i] = stretch[i] * temp[i]; float distToScene = vlength(temp); // tan(45 deg *0.5) is ratio between half-height and dist to scene double halfHeight = tan(M_PI * 0.125) * distToScene; return (2.f * halfHeight / (double)height); #endif return (0.0); } ViewpointParams *Visualizer::getActiveViewpointParams() const { return _paramsMgr->GetViewpointParams(_winName); } RegionParams *Visualizer::getActiveRegionParams() const { return _paramsMgr->GetRegionParams(_winName); } AnnotationParams *Visualizer::getActiveAnnotationParams() const { return _paramsMgr->GetAnnotationParams(_winName); } #include int Visualizer::_captureImage(std::string path) { // Turn off the single capture flag _imageCaptureEnabled = false; ViewpointParams *vpParams = getActiveViewpointParams(); int width, height; // vpParams->GetWindowSize(width, height); _framebuffer.GetSize(&width, &height); vector framebuffer(3 * width * height); int writeReturn = -1; _getPixelData(framebuffer.data()); if (STLUtils::BeginsWith(path, ":RAM:")) { void *ptr; sscanf(path.c_str(), ":RAM:%p", &ptr); memcpy(ptr, framebuffer.data(), sizeof(framebuffer[0]) * 3 * width * height); return 0; } if (FileUtils::Extension(path) == "") path += ".png"; bool geoTiffOutput = vpParams->GetProjectionType() == ViewpointParams::MapOrthographic && (FileUtils::Extension(path) == "tif" || FileUtils::Extension(path) == "tiff"); ImageWriter *writer = nullptr; if (geoTiffOutput) writer = new GeoTIFWriter(path); else writer = ImageWriter::CreateImageWriterForFile(path); if (writer == nullptr) goto captureImageEnd; if (geoTiffOutput) { VAssert(_dataStatus->GetDataMgrNames().size()); string projString = _dataStatus->GetDataMgr(_dataStatus->GetDataMgrNames()[0])->GetMapProjection(); CoordType dataMinExtents, dataMaxExtents; _dataStatus->GetActiveExtents(_paramsMgr, _winName, _getCurrentTimestep(), dataMinExtents, dataMaxExtents); double m[16]; vpParams->GetModelViewMatrix(m); double posvec[3], upvec[3], dirvec[3]; vpParams->ReconstructCamera(m, posvec, upvec, dirvec); float s = vpParams->GetOrthoProjectionSize(); float x = posvec[0]; float y = posvec[1]; float aspect = width / (float)height; float pixelScale[2] = {s * aspect * 2 / (float)width, s * 2 / (float)height}; // Crop to data extents double cameraMinExtents[2] = {x - s * aspect, y - s}; double cameraMaxExtents[2] = {x + s * aspect, y + s}; int cropMin[2] = {0, 0}; double newCameraMinExtents[2] = {cameraMinExtents[0], cameraMinExtents[1]}; for (int i = 0; i < 2; i++) { if (cameraMinExtents[i] < dataMinExtents[i]) { newCameraMinExtents[i] = dataMinExtents[i]; cropMin[i] = (dataMinExtents[i] - cameraMinExtents[i]) / pixelScale[i]; } } int cropMax[2] = {(int)width, (int)height}; double newCameraMaxExtents[2] = {cameraMaxExtents[0], cameraMaxExtents[1]}; for (int i = 0; i < 2; i++) { if (cameraMaxExtents[i] > dataMaxExtents[i]) { newCameraMaxExtents[i] = dataMaxExtents[i]; cropMax[i] = cropMax[i] - (cameraMaxExtents[i] - dataMaxExtents[i]) / pixelScale[i]; } } int croppedWidth = cropMax[0] - cropMin[0]; int croppedHeight = cropMax[1] - cropMin[1]; if (croppedWidth <= 0 || croppedHeight <= 0) { MyBase::SetErrMsg("Dataset not visible"); writeReturn = -1; goto captureImageEnd; } // flip Y int temp = cropMin[1]; cropMin[1] = height - cropMax[1]; cropMax[1] = height - temp; vector croppedFB(3 * croppedWidth * croppedHeight); for (int y = 0; y < croppedHeight; y++) memcpy(&croppedFB[3 * y * croppedWidth], &framebuffer[3 * ((y + cropMin[1]) * width + cropMin[0])], 3 * croppedWidth); framebuffer = croppedFB; s *= croppedHeight / (float)height; x = (newCameraMaxExtents[0] - newCameraMinExtents[0]) / 2 + newCameraMinExtents[0]; y = (newCameraMaxExtents[1] - newCameraMinExtents[1]) / 2 + newCameraMinExtents[1]; width = croppedWidth; height = croppedHeight; aspect = width / (float)height; GeoTIFWriter *geo = (GeoTIFWriter *)writer; geo->SetTiePoint(x, y, width / 2.f, height / 2.f); geo->SetPixelScale(s * aspect * 2 / (float)width, s * 2 / (float)height); if (geo->ConfigureFromProj4(projString) < 0) { writeReturn = -1; goto captureImageEnd; } } writeReturn = writer->Write(framebuffer.data(), width, height); captureImageEnd: if (writer) delete writer; return writeReturn; } bool Visualizer::_getPixelData(unsigned char *data) const { int width, height; // vpParams->GetWindowSize(width, height); _framebuffer.GetSize(&width, &height); // Must clear previous errors first. while (glGetError() != GL_NO_ERROR) ; // glReadBuffer(GL_BACK); // glDisable(GL_SCISSOR_TEST); // Calling pack alignment ensures that we can grab the any size window glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data); if (glGetError() != GL_NO_ERROR) { SetErrMsg("Error obtaining GL framebuffer data"); return false; } // Unfortunately gl reads these in the reverse order that jpeg expects, so // Now we need to swap top and bottom! unsigned char val; for (int j = 0; j < height / 2; j++) { for (int i = 0; i < width * 3; i++) { val = data[i + width * 3 * j]; data[i + width * 3 * j] = data[i + width * 3 * (height - j - 1)]; data[i + width * 3 * (height - j - 1)] = val; } } return true; } void Visualizer::_deleteFlaggedRenderers() { VAssert(_insideGLContext); for (auto it = _renderersToDestroy.begin(); it != _renderersToDestroy.end(); ++it) { Renderer *ren = *it; if (ren) delete ren; } _renderersToDestroy.clear(); } int Visualizer::_initializeNewRenderers() { VAssert(_insideGLContext); for (Renderer *r : _renderers) { if (!r->IsGLInitialized() && r->initializeGL(_glManager) < 0) { MyBase::SetErrMsg("Failed to initialize renderer %s", r->GetInstanceName().c_str()); return -1; } GL_ERR_BREAK(); } return 0; } void Visualizer::_clearActiveFramebuffer(float r, float g, float b) const { VAssert(_insideGLContext); glDepthMask(GL_TRUE); glClearColor(r, g, b, 1.f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); } void Visualizer::_renderColorbars(int timeStep) { MatrixManager *mm = _glManager->matrixManager; mm->MatrixModeModelView(); mm->PushMatrix(); mm->LoadIdentity(); mm->MatrixModeProjection(); mm->PushMatrix(); mm->LoadIdentity(); for (int i = 0; i < _renderers.size(); i++) { // If a renderer is not initialized, or if its bypass flag is set, then don't render. // Otherwise push and pop the GL matrix stack, and all attribs _renderers[i]->renderColorbar(); } mm->MatrixModeProjection(); mm->PopMatrix(); mm->MatrixModeModelView(); mm->PopMatrix(); } void Visualizer::_incrementPath(string &s) { // truncate the last 4 characters (remove .tif or .jpg) string s1 = s.substr(0, s.length() - 4); string s_end = s.substr(s.length() - 4); if (s_end == "jpeg" || s_end == "tiff") { s1 = s.substr(0, s.length() - 5); s_end = s.substr(s.length() - 5); } // Find digits (before .tif or .jpg) size_t lastpos = s1.find_last_not_of("0123456789"); VAssert(lastpos < s1.length()); string s2 = s1.substr(lastpos + 1); int val = stol(s2); // Convert val+1 to a string, with leading zeroes, of same length as s2. // Except, if val+1 has more digits than s2, increase it. int numDigits = 1 + (int)log10((float)(val + 1)); int len = s2.length(); if (len < numDigits) len = numDigits; if (len > 9) len = 9; char format[5] = {"%04d"}; char result[100]; char c = '0' + len; format[2] = c; snprintf(result, 100, format, val + 1); string sval = string(result); string newbody = s.substr(0, lastpos + 1); s = newbody + sval + s_end; } ================================================ FILE: lib/render/VolumeAlgorithm.cpp ================================================ #include #include #include #include using namespace VAPoR; using std::string; using std::vector; VolumeAlgorithm::VolumeAlgorithm(GLManager *gl, VolumeRenderer *renderer) : _glManager(gl), _renderer(renderer) {} VolumeAlgorithm *VolumeAlgorithm::NewAlgorithm(const std::string &name, GLManager *gl, VolumeRenderer *renderer) { if (factories.count(name)) { return factories[name]->Create(gl, renderer); } Wasp::MyBase::SetErrMsg("Invalid volume rendering algorithm: \"%s\"\n", name.c_str()); return nullptr; } VolumeParams *VolumeAlgorithm::GetParams() const { return (VolumeParams *)_renderer->GetActiveParams(); } ViewpointParams *VolumeAlgorithm::GetViewpointParams() const { return _renderer->GetViewpointParams(); } AnnotationParams *VolumeAlgorithm::GetAnnotationParams() const { return _renderer->GetAnnotationParams(); } Transform *VolumeAlgorithm::GetDatasetTransform() const { return _renderer->GetDatasetTransform(); } void VolumeAlgorithm::GetExtents(glm::vec3 *dataMin_, glm::vec3 *dataMax_, glm::vec3 *userMin_, glm::vec3 *userMax_) const { vector minRendererExtents, maxRendererExtents; GetParams()->GetBox()->GetExtents(minRendererExtents, maxRendererExtents); CoordType minDataExtents, maxDataExtents; auto p = GetParams(); _renderer->_dataMgr->GetVariableExtents(p->GetCurrentTimestep(), p->GetVariableName(), p->GetRefinementLevel(), p->GetCompressionLevel(), minDataExtents, maxDataExtents); glm::vec3 userMin = glm::vec3(minRendererExtents[0], minRendererExtents[1], minRendererExtents[2]); glm::vec3 userMax = glm::vec3(maxRendererExtents[0], maxRendererExtents[1], maxRendererExtents[2]); glm::vec3 dataMin = glm::vec3(minDataExtents[0], minDataExtents[1], minDataExtents[2]); glm::vec3 dataMax = glm::vec3(maxDataExtents[0], maxDataExtents[1], maxDataExtents[2]); if (dataMin_) *dataMin_ = dataMin; if (dataMax_) *dataMax_ = dataMax; // Moving domain allows area outside of data to be selected if (userMin_) *userMin_ = glm::max(userMin, dataMin); if (userMax_) *userMax_ = glm::min(userMax, dataMax); } std::map VolumeAlgorithm::factories; void VolumeAlgorithm::Register(VolumeAlgorithmFactory *f) { VolumeParams::Type type = VolumeParams::Type::Any; if (f->type == Type::Iso) type = VolumeParams::Type::Iso; else if (f->type == Type::DVR) type = VolumeParams::Type::DVR; factories[f->name] = f; VolumeParams::Register(f->name, type); } static VolumeAlgorithmRegistrar registration; ================================================ FILE: lib/render/VolumeCellTraversal.cpp ================================================ #include #include #include #include #include #include #include #include #include #ifndef FLT16_MAX #define FLT16_MAX 6.55E4 #endif using glm::ivec2; using glm::ivec3; using glm::vec3; using std::array; using std::vector; using namespace VAPoR; static VolumeAlgorithmRegistrar registration; static VolumeAlgorithmRegistrar registration2; #define MAX_LEVELS 12 #define FI_LEFT 0 #define FI_RIGHT 1 #define FI_UP 2 #define FI_DOWN 3 #define FI_FRONT 4 #define FI_BACK 5 #define F_LEFT ivec3(-1, 0, 0) #define F_RIGHT ivec3(1, 0, 0) #define F_UP ivec3(0, 0, 1) #define F_DOWN ivec3(0, 0, -1) #define F_FRONT ivec3(0, -1, 0) #define F_BACK ivec3(0, 1, 0) static int GetFaceIndexFromFace(const ivec3 &face) { if (face == F_LEFT) return FI_LEFT; if (face == F_RIGHT) return FI_RIGHT; if (face == F_UP) return FI_UP; if (face == F_DOWN) return FI_DOWN; if (face == F_FRONT) return FI_FRONT; if (face == F_BACK) return FI_BACK; VAssert(0); return 0; } static void GetFaceCoordinateIndices(const ivec3 &cell, const ivec3 &face, ivec3 &i0, ivec3 &i1, ivec3 &i2, ivec3 &i3) { // CCW if (face == F_DOWN) { i0 = cell + ivec3(0, 0, 0); i1 = cell + ivec3(0, 1, 0); i2 = cell + ivec3(1, 1, 0); i3 = cell + ivec3(1, 0, 0); } else if (face == F_UP) { i0 = cell + ivec3(0, 0, 1); i1 = cell + ivec3(1, 0, 1); i2 = cell + ivec3(1, 1, 1); i3 = cell + ivec3(0, 1, 1); } else if (face == F_LEFT) { i0 = cell + ivec3(0, 0, 0); i1 = cell + ivec3(0, 0, 1); i2 = cell + ivec3(0, 1, 1); i3 = cell + ivec3(0, 1, 0); } else if (face == F_RIGHT) { i0 = cell + ivec3(1, 0, 0); i1 = cell + ivec3(1, 1, 0); i2 = cell + ivec3(1, 1, 1); i3 = cell + ivec3(1, 0, 1); } else if (face == F_FRONT) { i0 = cell + ivec3(0, 0, 0); i1 = cell + ivec3(1, 0, 0); i2 = cell + ivec3(1, 0, 1); i3 = cell + ivec3(0, 0, 1); } else if (face == F_BACK) { i0 = cell + ivec3(0, 1, 0); i1 = cell + ivec3(0, 1, 1); i2 = cell + ivec3(1, 1, 1); i3 = cell + ivec3(1, 1, 0); } else { VAssert(!"Invalid face enum"); i0 = ivec3(0); i1 = ivec3(0); i2 = ivec3(0); i3 = ivec3(0); } } static vec3 GetCoordAtIndex(const ivec3 &index, const float *data, const ivec3 &dims) { const int w = dims.x; const int h = dims.y; const int d = dims.z; const int x = index.x; const int y = index.y; const int z = index.z; VAssert(x >= 0 && x < w && y >= 0 && y < h && z >= 0 && z < d); return vec3( data[3 * ((long)z * w * h + y * w + x)], data[3 * ((long)z * w * h + y * w + x) + 1], data[3 * ((long)z * w * h + y * w + x) + 2] ); } static void GetFaceVertices(const ivec3 &cellIndex, const ivec3 &face, const float *data, const ivec3 &dims, vec3 &v0, vec3 &v1, vec3 &v2, vec3 &v3) { ivec3 i0, i1, i2, i3; GetFaceCoordinateIndices(cellIndex, face, i0, i1, i2, i3); v0 = GetCoordAtIndex(i0, data, dims); v1 = GetCoordAtIndex(i1, data, dims); v2 = GetCoordAtIndex(i2, data, dims); v3 = GetCoordAtIndex(i3, data, dims); } static bool ComputeSideBBoxes(ivec3 side, int fastDim, int slowDim, vec3 *boxMins, vec3 *boxMaxs, float *coordData, const ivec3 &cellDims, const ivec3 &coordDims, const int bd, const int sd) { ivec3 index = (side + 1) / 2 * (cellDims - 1); int sideID = GetFaceIndexFromFace(side); for (index[slowDim] = 0; index[slowDim] < cellDims[slowDim]; index[slowDim]++) { for (index[fastDim] = 0; index[fastDim] < cellDims[fastDim]; index[fastDim]++) { vec3 v0, v1, v2, v3; GetFaceVertices(index, side, coordData, coordDims, v0, v1, v2, v3); boxMins[sideID * bd * sd + index[slowDim] * sd + index[fastDim]] = glm::min(v0, glm::min(v1, glm::min(v2, v3))); boxMaxs[sideID * bd * sd + index[slowDim] * sd + index[fastDim]] = glm::max(v0, glm::max(v1, glm::max(v2, v3))); } } return false; } VolumeCellTraversal::VolumeCellTraversal(GLManager *gl, VolumeRenderer *renderer) : VolumeRegular(gl, renderer), _useHighPrecisionTriangleRoutine(false) { _coordTexture.Generate(GL_NEAREST); _minTexture.Generate(GL_NEAREST); _maxTexture.Generate(GL_NEAREST); _BBLevelDimTexture.Generate(GL_NEAREST); } VolumeCellTraversal::~VolumeCellTraversal() {} int VolumeCellTraversal::LoadData(const Grid *grid) { if (VolumeRegular::LoadData(grid) < 0) return -1; _useHighPrecisionTriangleRoutine = _needsHighPrecisionTriangleRoutine(grid); _gridHasInvertedCoordinateSystemHandiness = !grid->HasInvertedCoordinateSystemHandiness(); const auto dims = grid->GetDimensions(); const auto w = dims[0], h = dims[1], d = dims[2]; const auto nCoords = w * h * d; _coordDims[0] = w; _coordDims[1] = h; _coordDims[2] = d; float *data = new float[nCoords * 3]; if (!data) { Wasp::MyBase::SetErrMsg("Could not allocate enough RAM to load data coordinates"); return -1; } Progress::Start("Load coord data", nCoords); auto coord = grid->ConstCoordBegin(); for (size_t i = 0; i < nCoords; ++i, ++coord) { Progress::Update(i); data[i * 3] = (*coord)[0]; data[i * 3 + 1] = (*coord)[1]; data[i * 3 + 2] = (*coord)[2]; } Progress::Finish(); _coordTexture.TexImage(GL_RGB32F, dims[0], dims[1], dims[2], GL_RGB, GL_FLOAT, data); // --------------------------------------- // Compute bounding boxes for outside faces // --------------------------------------- vector cellDims = {dims[0] - 1, dims[1] - 1, dims[2] - 1}; vector cellDimsSorted = cellDims; std::sort(cellDimsSorted.begin(), cellDimsSorted.end()); int bbDim = cellDimsSorted[2]; int bd = bbDim; int sd = bbDim; vec3 *boxMins = new vec3[bd * sd * 6]; vec3 *boxMaxs = new vec3[bd * sd * 6]; memset(boxMins, 0, sizeof(vec3) * bd * sd * 6); memset(boxMaxs, 0, sizeof(vec3) * bd * sd * 6); int cw = w - 1; int ch = h - 1; int cd = d - 1; Progress::Start("Compute acceleration data", 6); ComputeSideBBoxes(F_LEFT, 1, 2, boxMins, boxMaxs, data, ivec3(cw, ch, cd), ivec3(w, h, d), bd, sd); Progress::Update(1); ComputeSideBBoxes(F_RIGHT, 1, 2, boxMins, boxMaxs, data, ivec3(cw, ch, cd), ivec3(w, h, d), bd, sd); Progress::Update(2); ComputeSideBBoxes(F_UP, 0, 1, boxMins, boxMaxs, data, ivec3(cw, ch, cd), ivec3(w, h, d), bd, sd); Progress::Update(3); ComputeSideBBoxes(F_DOWN, 0, 1, boxMins, boxMaxs, data, ivec3(cw, ch, cd), ivec3(w, h, d), bd, sd); Progress::Update(4); ComputeSideBBoxes(F_FRONT, 0, 2, boxMins, boxMaxs, data, ivec3(cw, ch, cd), ivec3(w, h, d), bd, sd); Progress::Update(5); ComputeSideBBoxes(F_BACK, 0, 2, boxMins, boxMaxs, data, ivec3(cw, ch, cd), ivec3(w, h, d), bd, sd); Progress::Finish(); int levels = 1; int size = bd; while ((size = size >> 1)) levels++; levels = min(levels, MAX_LEVELS); _BBLevels = levels; _minTexture.TexImage(GL_RGB32F, sd, bd, 6, GL_RGB, GL_FLOAT, boxMins); _maxTexture.TexImage(GL_RGB32F, sd, bd, 6, GL_RGB, GL_FLOAT, boxMaxs); // --------------------------------------- // Compute mipmap for acceleration tree // // Each subsequent mipmip level contains outermost bounds of all the bounding // boxes it encompases from the previous level. // --------------------------------------- vector sizes(levels); vector> mipDims(levels); vector minMip(levels); vector maxMip(levels); sizes[0] = bd; minMip[0] = boxMins; maxMip[0] = boxMaxs; mipDims[0][FI_LEFT] = ivec2(ch, cd); mipDims[0][FI_RIGHT] = ivec2(ch, cd); mipDims[0][FI_UP] = ivec2(cw, ch); mipDims[0][FI_DOWN] = ivec2(cw, ch); mipDims[0][FI_FRONT] = ivec2(cw, cd); mipDims[0][FI_BACK] = ivec2(cw, cd); Progress::Start("Generate tree", levels); for (int level = 1; level < levels; level++) { Progress::Update(level); int ms = bd >> level; int mUpS = sizes[level - 1]; sizes[level] = ms; minMip[level] = new vec3[ms * ms * 6]; maxMip[level] = new vec3[ms * ms * 6]; for (int z = 0; z < 6; z++) { int mUpW = mipDims[level - 1][z][0]; int mUpH = mipDims[level - 1][z][1]; int mW = std::max(1, mUpW >> 1); int mH = std::max(1, mUpH >> 1); mipDims[level][z][0] = mW; mipDims[level][z][1] = mH; // At each higher mipmap, the dimensions halve. So each pixel maps to at least 4 // pixels at the previous level. However if the previous level dim was 1, it // no longer halves so we set the increment to 0. This resamples the same pixel twice // for simplicities sake. int ix = 1, iy = 1; if (mUpW == 1) ix = 0; if (mUpH == 1) iy = 0; for (int y = 0; y < mH; y++) { for (int x = 0; x < mW; x++) { vec3 v0 = minMip[level - 1][z * mUpS * mUpS + (y * 2) * mUpS + x * 2]; vec3 v1 = minMip[level - 1][z * mUpS * mUpS + (y * 2) * mUpS + x * 2 + ix]; vec3 v2 = minMip[level - 1][z * mUpS * mUpS + (y * 2 + iy) * mUpS + x * 2 + ix]; vec3 v3 = minMip[level - 1][z * mUpS * mUpS + (y * 2 + iy) * mUpS + x * 2]; // glm::min and glm::max are component-wise minMip[level][z * ms * ms + y * ms + x] = glm::min(v0, glm::min(v1, glm::min(v2, v3))); v0 = maxMip[level - 1][z * mUpS * mUpS + (y * 2) * mUpS + x * 2]; v1 = maxMip[level - 1][z * mUpS * mUpS + (y * 2) * mUpS + x * 2 + ix]; v2 = maxMip[level - 1][z * mUpS * mUpS + (y * 2 + iy) * mUpS + x * 2 + ix]; v3 = maxMip[level - 1][z * mUpS * mUpS + (y * 2 + iy) * mUpS + x * 2]; maxMip[level][z * ms * ms + y * ms + x] = glm::max(v0, glm::max(v1, glm::max(v2, v3))); } } // If the upper level is odd, the top and right border pixels map to 6 pixels in the previous // level which are accounted for here. if (mUpW % 2 == 1) { for (int y = 0; y < mH; y++) { vec3 v0 = minMip[level][z * ms * ms + y * ms + mW - 1]; vec3 v1 = minMip[level - 1][z * mUpS * mUpS + (y * 2) * mUpS + mUpW - 1]; vec3 v2 = minMip[level - 1][z * mUpS * mUpS + (y * 2 + iy) * mUpS + mUpW - 1]; minMip[level][z * ms * ms + y * ms + mW - 1] = glm::min(v0, glm::min(v1, v2)); v0 = maxMip[level][z * ms * ms + y * ms + mW - 1]; v1 = maxMip[level - 1][z * mUpS * mUpS + (y * 2) * mUpS + mUpW - 1]; v2 = maxMip[level - 1][z * mUpS * mUpS + (y * 2 + iy) * mUpS + mUpW - 1]; maxMip[level][z * ms * ms + y * ms + mW - 1] = glm::max(v0, glm::max(v1, v2)); } } if (mUpH % 2 == 1) { for (int x = 0; x < mW; x++) { vec3 v0 = minMip[level][z * ms * ms + (mH - 1) * ms + x]; vec3 v1 = minMip[level - 1][z * mUpS * mUpS + (mUpH - 1) * mUpS + x * 2]; vec3 v2 = minMip[level - 1][z * mUpS * mUpS + (mUpH - 1) * mUpS + x * 2 + ix]; minMip[level][z * ms * ms + (mH - 1) * ms + x] = glm::min(v0, glm::min(v1, v2)); v0 = maxMip[level][z * ms * ms + (mH - 1) * ms + x]; v1 = maxMip[level - 1][z * mUpS * mUpS + (mUpH - 1) * mUpS + x * 2]; v2 = maxMip[level - 1][z * mUpS * mUpS + (mUpH - 1) * mUpS + x * 2 + ix]; maxMip[level][z * ms * ms + (mH - 1) * ms + x] = glm::max(v0, glm::max(v1, v2)); } } // If the both upper dims are odd, the top-right pixel maps to 9 pixels in the previous level. // 8 of these were already accounted for. This accounts for the last pixel in the corner if (mUpW % 2 == 1 && mUpH % 2 == 1) { vec3 v0 = minMip[level][z * ms * ms + (mH - 1) * ms + mW - 1]; vec3 v1 = minMip[level - 1][z * mUpS * mUpS + (mUpH - 1) * mUpS + mUpW - 1]; minMip[level][z * ms * ms + (mH - 1) * ms + mW - 1] = glm::min(v0, v1); v0 = maxMip[level][z * ms * ms + (mH - 1) * ms + mW - 1]; v1 = maxMip[level - 1][z * mUpS * mUpS + (mUpH - 1) * mUpS + mUpW - 1]; maxMip[level][z * ms * ms + (mH - 1) * ms + mW - 1] = glm::max(v0, v1); } } _minTexture.TexImage(GL_RGB32F, ms, ms, 6, GL_RGB, GL_FLOAT, minMip[level], level); _maxTexture.TexImage(GL_RGB32F, ms, ms, 6, GL_RGB, GL_FLOAT, maxMip[level], level); } Progress::Finish(); _BBLevelDimTexture.TexImage(GL_RG32I, 6, levels, 0, GL_RG_INTEGER, GL_INT, mipDims.data()); for (int level = 1; level < levels; level++) { delete[] minMip[level]; delete[] maxMip[level]; } delete[] data; delete[] boxMins; delete[] boxMaxs; return 0; } // System: CISL-VAPOR // Vendor: NVIDIA // Dataset: Lee Orf tornado Max/Min resolutions // // Render Times // Levels Compile Max Min // 9 64 0.05 - // 8 24 0.05 - // 7 9.5 0.04 - // 6 4 0.05 0.01 // 5 1.8 0.067 0.01 // 4 0.9 0.22 0.012 // 3 0.56 - 0.022 int VolumeCellTraversal::_getHeuristicBBLevels() const { int levels = _BBLevels; if (levels == 12) levels -= 4; else if (levels >= 9) levels -= 3; else if (levels >= 7) levels -= 2; else if (levels >= 2) levels -= 1; // Nvidia's loop optimizer has an exponential Big-O complexity in // relation to nesting and anything over 6 takes too long to compile. GLManager::Vendor vendor = GLManager::GetVendor(); if (vendor == GLManager::Vendor::Nvidia) if (levels > 6) levels = 6; return levels; } std::string VolumeCellTraversal::_addDefinitionsToShader(std::string shaderName) const { shaderName = VolumeRegular::_addDefinitionsToShader(shaderName); if (_useHighPrecisionTriangleRoutine) shaderName += ":USE_INTEL_TRI_ISECT"; if (_gridHasInvertedCoordinateSystemHandiness) shaderName += ":INVERT_GRID_COORD_SYS_HAND"; GLManager::Vendor vendor = GLManager::GetVendor(); if (vendor == GLManager::Vendor::Nvidia || vendor == GLManager::Vendor::AMD || vendor == GLManager::Vendor::Mesa) shaderName += ":NVIDIA"; shaderName += ":BB_LEVELS " + std::to_string(_getHeuristicBBLevels()); return shaderName; } ShaderProgram *VolumeCellTraversal::GetShader() const { return _glManager->shaderManager->GetShader(_addDefinitionsToShader("VolumeCellDVR")); } void VolumeCellTraversal::SetUniforms(const ShaderProgram *s) const { VolumeRegular::SetUniforms(s); s->SetUniform("coordDims", *(glm::ivec3 *)&_coordDims); s->SetSampler("coords", _coordTexture); s->SetSampler("boxMins", _minTexture); s->SetSampler("boxMaxs", _maxTexture); s->SetSampler("levelDims", _BBLevelDimTexture); } float VolumeCellTraversal::GuestimateFastModeSpeedupFactor() const { return 2; } int VolumeCellTraversal::CheckHardwareSupport(const Grid *grid) const { int ret = VolumeRegular::CheckHardwareSupport(grid); if (ret < 0) return ret; long freeKB = oglGetFreeMemory(); if (freeKB >= 0) { auto dims = grid->GetDimensions(); long estimatedMinimumB = dims[0]*dims[1]*dims[2] * sizeof(float) * 4; long estimatedMinimumKB = estimatedMinimumB/1024; if (freeKB < estimatedMinimumKB) { Wasp::MyBase::SetErrMsg("Not enough GPU RAM free (%liMB free, need at least %liMB)\n", freeKB/1024, estimatedMinimumKB/1024); return -1; } } return 0; } bool VolumeCellTraversal::_needsHighPrecisionTriangleRoutine(const Grid *grid) { vector extentsMin, extentsMax; grid->GetUserExtents(extentsMin, extentsMax); vector lengths = { extentsMax[0] - extentsMin[0], extentsMax[1] - extentsMin[1], extentsMax[2] - extentsMin[2], }; double minLength = min(lengths[0], min(lengths[1], lengths[2])); double maxLength = max(lengths[0], max(lengths[1], lengths[2])); double ratio = maxLength / minLength; if (ratio > 10000) return true; else return false; } // Needs more consideration for frequency bool VolumeCellTraversal::_need32BitForCoordinates(const Grid *grid) { vector minExts, maxExts; grid->GetUserExtents(minExts, maxExts); double minExt = min(minExts[0], min(minExts[1], minExts[2])); double maxExt = max(maxExts[0], max(maxExts[1], maxExts[2])); if (minExt <= -FLT16_MAX || maxExt >= FLT16_MAX) return true; return false; } ShaderProgram *VolumeCellTraversalIso::GetShader() const { return _glManager->shaderManager->GetShader(_addDefinitionsToShader("VolumeCellIso")); } void VolumeCellTraversalIso::SetUniforms(const ShaderProgram *shader) const { VolumeCellTraversal::SetUniforms(shader); } ================================================ FILE: lib/render/VolumeGLSL.cpp ================================================ #include #include #include #include #include #include #include using glm::vec3; using std::vector; using namespace VAPoR; // static VolumeAlgorithmRegistrar registration; VolumeGLSL::VolumeGLSL(GLManager *gl, VolumeRenderer *renderer) : VolumeAlgorithm(gl, renderer) { _LUTTexture.Generate(); _LUT2Texture.Generate(); _depthTexture.Generate(); } VolumeGLSL::~VolumeGLSL() {} void VolumeGLSL::SaveDepthBuffer(bool fast) { _depthTexture.CopyDepthBuffer(); } int VolumeGLSL::Render(bool fast) { _loadTF(); ShaderProgram *shader = GetShader(); if (!shader) return -1; shader->Bind(); _setShaderUniforms(shader, fast); return 0; } int VolumeGLSL::LoadData(const Grid *grid) { grid->GetUserExtents(_minDataExtents, _maxDataExtents); return 0; } void VolumeGLSL::GetFinalBlendingMode(int *src, int *dst) { *src = GL_ONE; *dst = GL_ONE_MINUS_SRC_ALPHA; } void VolumeGLSL::_loadTF() { VolumeParams *vp = GetParams(); vector constantColor = vp->GetConstantColor(); constantColor.push_back(vp->GetMapperFunc(vp->GetVariableName())->getOpacityScale()); _constantColor = constantColor; _loadTF(&_LUTTexture, vp->GetMapperFunc(vp->GetVariableName()), &_tf); if (_usingColorMapData()) { _loadTF(&_LUT2Texture, vp->GetMapperFunc(vp->GetColorMapVariableName()), &_tf2); } } void VolumeGLSL::_loadTF(Texture1D *texture, MapperFunction *tf, MapperFunction **cacheTF) { if (*cacheTF) delete *cacheTF; *cacheTF = new MapperFunction(*tf); vector LUT(4 * 256); _getLUTFromTF(tf, LUT.data()); texture->TexImage(GL_RGBA8, 256, 0, 0, GL_RGBA, GL_FLOAT, LUT.data()); } void VolumeGLSL::_getLUTFromTF(const MapperFunction *tf, float *LUT) const { // Constant opacity needs to be removed here and applied in the shader // because otherwise we run out of precision in the LUT MapperFunction tfSansConstantOpacity(*tf); tfSansConstantOpacity.setOpacityScale(1); tfSansConstantOpacity.makeLut(LUT); for (int i = 0; i < 256; i++) { LUT[4 * i + 3] = powf(LUT[4 * i + 3], 2); } } void VolumeGLSL::_setShaderUniforms(const ShaderProgram *shader, const bool fast) const { VolumeParams * vp = GetParams(); ViewpointParams *viewpointParams = GetViewpointParams(); Viewpoint * viewpoint = viewpointParams->getCurrentViewpoint(); double m[16]; double cameraPos[3], cameraUp[3], cameraDir[3]; _glManager->matrixManager->GetDoublev(MatrixManager::Mode::ModelView, m); viewpoint->ReconstructCamera(m, cameraPos, cameraUp, cameraDir); shader->SetUniform("MVP", _glManager->matrixManager->GetModelViewProjectionMatrix()); shader->SetUniform("cameraPos", vec3(cameraPos[0], cameraPos[1], cameraPos[2])); shader->SetUniform("samplingRateMultiplier", (float)vp->GetSamplingMultiplier()); shader->SetUniform("lightingEnabled", vp->GetLightingEnabled()); shader->SetUniform("phongAmbient", vp->GetPhongAmbient()); shader->SetUniform("phongDiffuse", vp->GetPhongDiffuse()); shader->SetUniform("phongSpecular", vp->GetPhongSpecular()); shader->SetUniform("phongShininess", powf(vp->GetPhongShininess(), 2) * 100); glm::vec3 dataMin, dataMax, userMin, userMax; _getExtents(&dataMin, &dataMax, &userMin, &userMax); vec3 extLengths = dataMax - dataMin; vec3 extScales = _getVolumeScales(); vec3 extLengthsScaled = extLengths * extScales; float smallestDimension = min(extLengthsScaled[0], min(extLengthsScaled[1], extLengthsScaled[2])); float largestDimension = max(extLengthsScaled[0], max(extLengthsScaled[1], extLengthsScaled[2])); shader->SetUniform("dataBoundsMin", dataMin); shader->SetUniform("dataBoundsMax", dataMax); shader->SetUniform("userExtsMin", userMin); shader->SetUniform("userExtsMax", userMax); shader->SetUniform("unitDistance", largestDimension / 100.f); shader->SetUniform("unitOpacityScalar", largestDimension / smallestDimension); shader->SetUniform("scales", extScales); float density = vp->GetValueDouble(VolumeParams::VolumeDensityTag, 1); density = powf(density, 4); shader->SetUniform("density", (float)density); shader->SetUniform("LUTMin", (float)_tf->getMinMapValue()); shader->SetUniform("LUTMax", (float)_tf->getMaxMapValue()); shader->SetUniform("mapOrthoMode", viewpointParams->GetProjectionType() == ViewpointParams::MapOrthographic); shader->SetSampler("LUT", _LUTTexture); shader->SetSampler("sceneDepth", _depthTexture); if (_usingColorMapData()) { shader->SetUniform("LUTMin2", (float)_tf2->getMinMapValue()); shader->SetUniform("LUTMax2", (float)_tf2->getMaxMapValue()); shader->SetSampler("LUT2", _LUT2Texture); } shader->SetUniform("fast", fast); vector isoValuesD = GetParams()->GetIsoValues(); vector isoValues(isoValuesD.begin(), isoValuesD.end()); vector enabledIsoValues(4, false); for (int i = 0; i < isoValues.size(); i++) enabledIsoValues[i] = true; shader->SetUniformArray("isoValue", isoValues.size(), isoValues.data()); shader->SetUniform("isoEnabled[0]", (bool)enabledIsoValues[0]); shader->SetUniform("isoEnabled[1]", (bool)enabledIsoValues[1]); shader->SetUniform("isoEnabled[2]", (bool)enabledIsoValues[2]); shader->SetUniform("isoEnabled[3]", (bool)enabledIsoValues[3]); if (_constantColor.size() == 4) shader->SetUniform("constantColor", *(glm::vec4 *)_constantColor.data()); SetUniforms(shader); } glm::vec3 VolumeGLSL::_getVolumeScales() const { Transform *datasetTransform = GetDatasetTransform(); Transform *rendererTransform = GetParams()->GetTransform(); VAssert(datasetTransform && rendererTransform); vector datasetScales, rendererScales; datasetScales = datasetTransform->GetScales(); rendererScales = rendererTransform->GetScales(); return glm::vec3(datasetScales[0] * rendererScales[0], datasetScales[1] * rendererScales[1], datasetScales[2] * rendererScales[2]); } void VolumeGLSL::_getExtents(glm::vec3 *dataMin, glm::vec3 *dataMax, glm::vec3 *userMin, glm::vec3 *userMax) const { vector minRendererExtents, maxRendererExtents; GetParams()->GetBox()->GetExtents(minRendererExtents, maxRendererExtents); *userMin = vec3(minRendererExtents[0], minRendererExtents[1], minRendererExtents[2]); *userMax = vec3(maxRendererExtents[0], maxRendererExtents[1], maxRendererExtents[2]); *dataMin = vec3(_minDataExtents[0], _minDataExtents[1], _minDataExtents[2]); *dataMax = vec3(_maxDataExtents[0], _maxDataExtents[1], _maxDataExtents[2]); // Moving domain allows area outside of data to be selected *userMin = glm::max(*userMin, *dataMin); *userMax = glm::min(*userMax, *dataMax); } bool VolumeGLSL::_usingColorMapData() const { // Overriden by VolumeIsoRenderer return GetParams()->GetValueLong(VAPoR::VolumeParams::UseColormapVariableTag, false); } ================================================ FILE: lib/render/VolumeIsoRenderer.cpp ================================================ #include "vapor/VolumeIsoRenderer.h" #include #include #include #include #include #include #include #include #include using glm::mat4; using glm::vec2; using glm::vec3; using glm::vec4; using namespace VAPoR; static RendererRegistrar registrar(VolumeIsoRenderer::GetClassType(), VolumeIsoParams::GetClassType()); VolumeIsoRenderer::VolumeIsoRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string &instName, DataMgr *dataMgr) : VolumeRenderer(pm, winName, dataSetName, VolumeIsoParams::GetClassType(), VolumeIsoRenderer::GetClassType(), instName, dataMgr) { // An ugly fix but I don't think we have a mechanism for this if (_needToSetDefaultAlgorithm()) { VolumeParams * vp = (VolumeParams *)GetActiveParams(); CoordType minExt, maxExt; vp->GetBox()->GetExtents(minExt, maxExt); Grid *grid = _dataMgr->GetVariable(vp->GetCurrentTimestep(), vp->GetVariableName(), vp->GetRefinementLevel(), vp->GetCompressionLevel(), minExt, maxExt); if (grid) { string algorithmName = _getDefaultAlgorithmForGrid(grid); vp->SetAlgorithm(algorithmName); delete grid; } else { vp->SetAlgorithm(VolumeRegularIso::GetName()); } } } VolumeIsoRenderer::~VolumeIsoRenderer() {} bool VolumeIsoRenderer::_usingColorMapData() const { return GetActiveParams()->GetValueLong(VolumeIsoParams::UseColormapVariableTag, false); } void VolumeIsoRenderer::_setShaderUniforms(const ShaderProgram *shader, const bool fast) const { // VolumeRenderer::_setShaderUniforms(shader, fast); vector isoValuesD = GetActiveParams()->GetIsoValues(); vector isoValues(isoValuesD.begin(), isoValuesD.end()); vector enabledIsoValues(4, false); for (int i = 0; i < isoValues.size(); i++) enabledIsoValues[i] = true; shader->SetUniformArray("isoValue", isoValues.size(), isoValues.data()); shader->SetUniform("isoEnabled[0]", (bool)enabledIsoValues[0]); shader->SetUniform("isoEnabled[1]", (bool)enabledIsoValues[1]); shader->SetUniform("isoEnabled[2]", (bool)enabledIsoValues[2]); shader->SetUniform("isoEnabled[3]", (bool)enabledIsoValues[3]); if (_cache.constantColor.size() == 4) shader->SetUniform("constantColor", *(vec4 *)_cache.constantColor.data()); } std::string VolumeIsoRenderer::_getDefaultAlgorithmForGrid(const Grid *grid) const { bool intel = GLManager::GetVendor() == GLManager::Vendor::Intel; if (dynamic_cast(grid)) return VolumeRegularIso::GetName(); if (dynamic_cast(grid)) return VolumeRectilinearIso::GetName(); if (dynamic_cast(grid)) return intel ? VolumeRegularIso::GetName() : VolumeCellTraversalIso::GetName(); if (dynamic_cast(grid)) return VolumeOSPRayIso ::GetName(); MyBase::SetErrMsg("Unsupported grid type: %s", grid->GetType().c_str()); return ""; } void VolumeIsoRenderer::_getLUTFromTF(const MapperFunction *tf, float *LUT) const { tf->makeLut(LUT); } ================================================ FILE: lib/render/VolumeOSPRay.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #include using glm::mat4; using glm::vec3; using glm::vec4; using std::vector; static vec3 D2V(const vector &dv) { VAssert(dv.size() == 3); return vec3(dv[0], dv[1], dv[2]); } #define PrintVec3(v) printf("%s = (%f, %f, %f)\n", #v, (v).x, (v).y, (v).z) using namespace VAPoR; static VolumeAlgorithmRegistrar registration; std::string VolumeOSPRay::GetName() { return VolumeParams::OSPVolmeAlgorithmName; } VolumeOSPRay::VolumeOSPRay(GLManager *gl, VolumeRenderer *renderer) : VolumeAlgorithm(gl, renderer) { _ospCamera = ospNewCamera("perspective"); _ospWorld = ospNewWorld(); OSPLight lightAmbient = ospNewLight("ambient"); ospSetFloat(lightAmbient, "intensity", 0.8); ospCommit(lightAmbient); // ospSetObjectAsData(_ospWorld, "light", OSP_LIGHT, lightAmbient); // ospRelease(lightAmbient); OSPLight lightDistant = ospNewLight("distant"); ospSetVec3f(lightDistant, "direction", 0, 0, -1); ospSetFloat(lightDistant, "angularDiameter", 1); ospSetFloat(lightDistant, "intensity", 4); ospCommit(lightDistant); vector lights = {lightAmbient, lightDistant}; OSPData lightsData = VOSP::NewCopiedData(lights.data(), OSP_LIGHT, lights.size()); ospCommit(lightsData); // Although these are already pointers, unlike every other function, // in the case of this function you need to reference here otherwise // it will crash. ospSetParam(_ospWorld, "light", OSP_LIGHT, &lightsData); ospRelease(lightsData); _ospLightDistant = lightDistant; // Not released therefore retained _ospLightAmbient = lightAmbient; _ospRenderTexture.Generate(); _ospWriteDepthTexture.Generate(); } VolumeOSPRay::~VolumeOSPRay() { if (_ospRenderer) ospRelease(_ospRenderer); if (_ospWorld) ospRelease(_ospWorld); if (_ospCamera) ospRelease(_ospCamera); if (_ospTF) ospRelease(_ospTF); if (_ospInstance) ospRelease(_ospInstance); if (_ospVolumeModel) ospRelease(_ospVolumeModel); if (_ospLightAmbient) ospRelease(_ospLightAmbient); if (_ospLightDistant) ospRelease(_ospLightDistant); if (_ospIso) ospRelease(_ospIso); if (_ospIsoModel) ospRelease(_ospIsoModel); } void VolumeOSPRay::SaveDepthBuffer(bool fast) { if (!fast) { _copyDepth(); if (GetParams()->GetValueLong("osp_useBackplate", false)) _copyBackplate(); } } int VolumeOSPRay::Render(bool fast) { auto viewport = GLManager::GetViewport(); glm::ivec2 fbSize(viewport[2], viewport[3]); OSPFrameBuffer framebuffer = ospNewFrameBuffer(fbSize.x, fbSize.y, OSP_FB_SRGBA, OSP_FB_COLOR | OSP_FB_DEPTH | OSP_FB_ACCUM); ospResetAccumulation(framebuffer); _setupCamera(); _loadTF(); _applyTransform(); _setupRenderer(fast); GetExtents(nullptr, nullptr, &_clipBox.min, &_clipBox.max); if (_isIso()) _setupIso(); ospSetFloat(_ospVolumeModel, "densityScale", GetParams()->GetValueDouble(VolumeParams::OSPDensity, 1)); ospCommit(_ospVolumeModel); ospRenderFrameBlocking(framebuffer, _ospRenderer, _ospCamera, _ospWorld); const uint32_t *fb = (uint32_t *)ospMapFrameBuffer(framebuffer, OSP_FB_COLOR); // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, windowSize.x, windowSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, fb); _ospRenderTexture.TexImage(GL_RGBA, fbSize.x, fbSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, fb); ospUnmapFrameBuffer(fb, framebuffer); const float *db = (float *)ospMapFrameBuffer(framebuffer, OSP_FB_DEPTH); _ospWriteDepthTexture.TexImage(GL_R32F, fbSize.x, fbSize.y, 0, GL_RED, GL_FLOAT, db); ospUnmapFrameBuffer(db, framebuffer); ospRelease(framebuffer); ShaderProgram *framebufferShader = _glManager->shaderManager->GetShader("FramebufferND"); framebufferShader->Bind(); if (!framebufferShader) return -1; framebufferShader->SetSampler("colorBuffer", _ospRenderTexture); framebufferShader->SetSampler("depthBuffer", _ospWriteDepthTexture); framebufferShader->SetUniform("MVP", _glManager->matrixManager->GetModelViewProjectionMatrix()); auto vp = GetViewpointParams(); double matrix[16], dpos[3], dup[3], ddir[3]; vp->GetModelViewMatrix(matrix); vp->ReconstructCamera(matrix, dpos, dup, ddir); vec3 pos(dpos[0], dpos[1], dpos[2]); vec3 dir(ddir[0], ddir[1], ddir[2]); framebufferShader->SetUniform("camPos", pos); framebufferShader->SetUniform("camDir", dir); return 0; } int VolumeOSPRay::LoadData(const Grid *grid) { auto p = GetParams(); OSPVolume volume; if (p->GetValueLong("osp_test_volume", false)) volume = _loadVolumeTest(grid); else if (p->GetValueLong("osp_force_regular", false)) volume = _loadVolumeRegular(grid); else if (dynamic_cast(grid)) volume = _loadVolumeRegular(grid); else if (dynamic_cast(grid)) volume = _loadVolumeStructured(grid); else if (dynamic_cast(grid)) volume = _loadVolumeUnstructured(grid); else volume = 0, VAssert(!"Unknown grid type"); if (volume == nullptr) return -1; ospRelease(_ospVolumeModel); _ospVolumeModel = ospNewVolumetricModel(volume); ospRelease(volume); ospRelease(_ospTF); _ospTF = ospNewTransferFunction("piecewiseLinear"); float temp[] = {0, 0, 0, 1, 1, 1}; OSPData data = VOSP::NewCopiedData(temp, OSP_VEC3F, 2); ospCommit(data); ospSetObject(_ospTF, "color", data); ospRelease(data); float temp2[] = {0, 1}; data = VOSP::NewCopiedData(temp2, OSP_FLOAT, 2); ospCommit(data); ospSetObject(_ospTF, "opacity", data); ospRelease(data); ospSetVec2f(_ospTF, "valueRange", -FLT_MAX, 0); // These initial values are necessary to work around bugs. ospCommit(_ospTF); ospSetObject(_ospVolumeModel, "transferFunction", _ospTF); ospCommit(_ospVolumeModel); if (_isIso()) { ospRelease(_ospIso); ospRelease(_ospIsoModel); _ospIso = ospNewGeometry("isosurface"); ospSetObject(_ospIso, "volume", _ospVolumeModel); ospSetFloat(_ospIso, "isovalue", 0); ospCommit(_ospIso); _ospIsoModel = ospNewGeometricModel(_ospIso); ospSetVec4f(_ospIsoModel, "color", 1, 1, 1, 1); ospCommit(_ospIsoModel); } OSPGeometry clip = ospNewGeometry("box"); data = ospNewSharedData(&_clipBox, OSP_BOX3F, 1); ospCommit(data); ospSetObject(clip, "box", data); ospRelease(data); ospCommit(clip); OSPGeometricModel clipModel = ospNewGeometricModel(clip); ospSetBool(clipModel, "invertNormals", true); ospRelease(clip); ospCommit(clipModel); OSPGroup group = ospNewGroup(); if (_isIso()) ospSetObjectAsData(group, "geometry", OSP_GEOMETRIC_MODEL, _ospIsoModel); else ospSetObjectAsData(group, "volume", OSP_VOLUMETRIC_MODEL, _ospVolumeModel); if (p->GetValueLong("osp_enable_clipping", true)) ospSetObjectAsData(group, "clippingGeometry", OSP_GEOMETRIC_MODEL, clipModel); // ospSetObjectAsData(group, "geometry", OSP_GEOMETRIC_MODEL, clipModel); ospCommit(group); ospRelease(clipModel); ospRelease(_ospInstance); _ospInstance = ospNewInstance(group); ospCommit(_ospInstance); ospRelease(group); ospSetObjectAsData(_ospWorld, "instance", OSP_INSTANCE, _ospInstance); ospCommit(_ospWorld); if (dynamic_cast(grid)) _ospSampleRateScalar = 1.f; else if (VOSP::IsVersionAtLeast(2, 5)) _ospSampleRateScalar = 1.f; else _ospSampleRateScalar = _guessSamplingRateScalar(grid); return 0; } ShaderProgram *VolumeOSPRay::GetShader() const { return _glManager->shaderManager->GetShader("VolumeDVR"); } void VolumeOSPRay::SetUniforms(const ShaderProgram *s) const {} float VolumeOSPRay::GuestimateFastModeSpeedupFactor() const { return 5; } void VolumeOSPRay::GetFinalBlendingMode(int *src, int *dst) { *src = GL_SRC_ALPHA; *dst = GL_ONE_MINUS_SRC_ALPHA; } void VolumeOSPRay::_setupRenderer(bool fast) { auto p = GetParams(); bool usePT = p->GetValueLong("osp_usePT", 0); if (!_ospRenderer || _cache.usePT != usePT) { ospRelease(_ospRenderer); _ospRenderer = ospNewRenderer(usePT ? "pathtracer" : "scivis"); _cache.usePT = usePT; } vector bgColor; int spp = p->GetValueLong("osp_spp", 1); bool opaqueBG = p->GetValueLong("osp_opaque_bg", false); GetAnnotationParams()->GetBackgroundColor(bgColor); ospSetVec4f(_ospRenderer, "backgroundColor", bgColor[0], bgColor[1], bgColor[2], opaqueBG ? 1 : 0); ospSetFloat(_ospRenderer, "volumeSamplingRate", _ospSampleRateScalar * (fast ? 0.1 : 1) * p->GetValueDouble(VolumeParams::OSPSampleRateScalar, 1)); ospSetInt(_ospRenderer, "pixelSamples", fast ? 1 : spp); ospSetInt(_ospRenderer, "aoSamples", 0); ViewpointParams *vp = GetViewpointParams(); auto viewport = GLManager::GetViewport(); glm::ivec2 fbSize(viewport[2], viewport[3]); if (fast) { ospRemoveParam(_ospRenderer, "map_maxDepth"); } else { auto mm = _glManager->matrixManager; double matrix[16], dpos[3], dup[3], ddir[3]; vp->GetModelViewMatrix(matrix); vp->ReconstructCamera(matrix, dpos, dup, ddir); vec3 pos(dpos[0], dpos[1], dpos[2]); vec3 up(dup[0], dup[1], dup[2]); vec3 dir(ddir[0], ddir[1], ddir[2]); OSPTexture depthMap = VOSP::OSPDepthFromGLPerspective(glm::degrees(mm->FOV), mm->Aspect, mm->Near, mm->Far, dir, up, _depthData.data(), fbSize.x, fbSize.y); ospSetObject(_ospRenderer, "map_maxDepth", depthMap); ospRelease(depthMap); } if (fast || !p->GetValueLong("osp_useBackplate", false)) { ospRemoveParam(_ospRenderer, "map_backplate"); } else { OSPTexture backplate = ospNewTexture("texture2d"); ospSetInt(backplate, "format", OSP_TEXTURE_R32F); ospSetInt(backplate, "filter", OSP_TEXTURE_FILTER_NEAREST); OSPData data = VOSP::NewCopiedData(_backplateData.data(), OSP_VEC3UC, fbSize.x, fbSize.y); ospCommit(data); ospSetObject(backplate, "data", data); ospRelease(data); ospSetObject(_ospRenderer, "map_backplate", backplate); ospRelease(backplate); } ospCommit(_ospRenderer); } void VolumeOSPRay::_setupCamera() { ViewpointParams *vp = GetViewpointParams(); auto viewport = GLManager::GetViewport(); glm::ivec2 fbSize(viewport[2], viewport[3]); double matrix[16], dpos[3], dup[3], ddir[3]; vp->GetModelViewMatrix(matrix); vp->ReconstructCamera(matrix, dpos, dup, ddir); vec3 pos(dpos[0], dpos[1], dpos[2]); vec3 up(dup[0], dup[1], dup[2]); vec3 dir(ddir[0], ddir[1], ddir[2]); // printf("Camera Pos = (%f, %f, %f)\n", pos.x, pos.y, pos.z); // printf("Camera Up = (%f, %f, %f)\n", up.x, up.y, up.z); // printf("Camera Dir = (%f, %f, %f)\n", dir.x, dir.y, dir.z); ospSetFloat(_ospCamera, "aspect", fbSize.x / (float)fbSize.y); ospSetFloat(_ospCamera, "fovy", vp->GetFOV()); ospSetParam(_ospCamera, "position", OSP_VEC3F, &pos); ospSetParam(_ospCamera, "direction", OSP_VEC3F, &dir); ospSetParam(_ospCamera, "up", OSP_VEC3F, &up); ospCommit(_ospCamera); float ambientIntensity = GetParams()->GetValueDouble(VolumeParams::OSPAmbientLightIntensity, 0.2); ospSetFloat(_ospLightAmbient, "intensity", ambientIntensity); ospCommit(_ospLightAmbient); float dirIntensity = GetParams()->GetValueDouble(VolumeParams::OSPDirectionalLightIntensity, 1); ospSetFloat(_ospLightDistant, "intensity", dirIntensity); ospSetVec3f(_ospLightDistant, "direction", dir.x, dir.y, dir.z); ospSetVec3f(_ospLightDistant, "color", 1, 1, 1); ospCommit(_ospLightDistant); } void VolumeOSPRay::_setupIso() { auto * p = GetParams(); vector isoValuesD = p->GetIsoValues(); vector isoValues(isoValuesD.begin(), isoValuesD.end()); OSPData data = VOSP::NewCopiedData(isoValues.data(), OSP_FLOAT, isoValues.size()); ospSetObject(_ospIso, "isovalue", data); ospRelease(data); ospCommit(_ospIso); vector c = p->GetConstantColor(); c.push_back(p->GetMapperFunc(p->GetVariableName())->getOpacityScale()); ospSetVec4f(_ospIsoModel, "color", c[0], c[1], c[2], c[3]); ospCommit(_ospIsoModel); } void VolumeOSPRay::_loadTF() { if (!_ospTF) { fprintf(stderr, "Warning: _ospTF = NULL\n"); return; } auto p = GetParams(); auto vtf = p->GetMapperFunc(p->GetVariableName()); auto range = vtf->getMinMaxMapValue(); float *LUT = new float[4 * 256]; vtf->makeLut(LUT); for (int i = 0; i < 256; i++) { LUT[4 * i + 3] = powf(LUT[4 * i + 3], 2); } vec3 * cLUT = new vec3[256]; float *oLUT = new float[256]; for (int i = 0; i < 256; i++) { cLUT[i].r = LUT[4 * i + 0]; cLUT[i].g = LUT[4 * i + 1]; cLUT[i].b = LUT[4 * i + 2]; oLUT[i] = LUT[4 * i + 3]; } OSPData data = VOSP::NewCopiedData(oLUT, OSP_FLOAT, 256); ospCommit(data); ospSetObject(_ospTF, "opacity", data); ospRelease(data); data = VOSP::NewCopiedData(cLUT, OSP_VEC3F, 256); ospCommit(data); ospSetObject(_ospTF, "color", data); ospRelease(data); ospSetVec2f(_ospTF, "valueRange", range[0], range[1]); ospCommit(_ospTF); delete[] LUT; delete[] cLUT; delete[] oLUT; } void VolumeOSPRay::_applyTransform() { auto p = GetParams(); vec3 translate = D2V(p->GetTransform()->GetTranslations()); vec3 rotate = D2V(p->GetTransform()->GetRotations()); vec3 scale = D2V(p->GetTransform()->GetScales()); vec3 origin = D2V(p->GetTransform()->GetOrigin()); Transform *datasetTransform = GetDatasetTransform(); vec3 datasetScales = D2V(datasetTransform->GetScales()); vec3 datasetRotation = D2V(datasetTransform->GetRotations()); vec3 datasetTranslation = D2V(datasetTransform->GetTranslations()); vec3 datasetOrigin = D2V(datasetTransform->GetOrigin()); mat4 m(1.f); m = glm::translate(m, datasetTranslation); m = glm::translate(m, datasetOrigin); m = glm::rotate(m, glm::radians(datasetRotation.x), vec3(1, 0, 0)); m = glm::rotate(m, glm::radians(datasetRotation.y), vec3(0, 1, 0)); m = glm::rotate(m, glm::radians(datasetRotation.z), vec3(0, 0, 1)); m = glm::scale(m, datasetScales); m = glm::translate(m, -datasetOrigin); m = glm::scale(m, 1.f / datasetScales); m = glm::translate(m, translate); m = glm::translate(m, origin); m = glm::rotate(m, glm::radians((float)rotate[0]), vec3(1, 0, 0)); m = glm::rotate(m, glm::radians((float)rotate[1]), vec3(0, 1, 0)); m = glm::rotate(m, glm::radians((float)rotate[2]), vec3(0, 0, 1)); m = glm::scale(m, scale); m = glm::translate(m, -origin); m = glm::scale(m, datasetScales); struct { vec3 x, y, z, o; } affine; affine.x = m * vec4(vec3(1, 0, 0), 0); affine.y = m * vec4(vec3(0, 1, 0), 0); affine.z = m * vec4(vec3(0, 0, 1), 0); affine.o = m * vec4(vec3(0, 0, 0), 1); ospSetParam(_ospInstance, "xfm", OSP_AFFINE3F, &affine); ospCommit(_ospInstance); ospCommit(_ospWorld); } void VolumeOSPRay::_copyDepth() { GLint viewport[4] = {0}; glGetIntegerv(GL_VIEWPORT, viewport); int width = viewport[2]; int height = viewport[3]; _depthData.resize(width * height); glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, (GLvoid *)_depthData.data()); } void VolumeOSPRay::_copyBackplate() { GLint viewport[4] = {0}; glGetIntegerv(GL_VIEWPORT, viewport); int width = viewport[2]; int height = viewport[3]; _backplateData.resize(width * height * 3); glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *)_backplateData.data()); } float VolumeOSPRay::_guessSamplingRateScalar(const Grid *grid) const { std::vector dataMinExtD, dataMaxExtD; grid->GetUserExtents(dataMinExtD, dataMaxExtD); vec3 dataMinExt(dataMinExtD[0], dataMinExtD[1], dataMinExtD[2]); vec3 dataMaxExt(dataMaxExtD[0], dataMaxExtD[1], dataMaxExtD[2]); vec3 lens = dataMaxExt - dataMinExt; float longest = max(lens.x, max(lens.y, lens.z)); // I was going to try to come up with a continuous equation but I'm // not sure how the original sample rate is determined so I'm just // going off the following two samples of resonable performance vs // quality: // // 4E7 = 0.001 // 3E6 = 0.1 return longest < 3E6f ? glm::mix(1.f, 0.1f, longest / 3E6f) : glm::mix(0.1f, 0.001f, (longest - 3E6f) / (4.05E7f - 3E6f)); } OSPVolume VolumeOSPRay::_loadVolumeRegular(const Grid *grid) { const auto dims = grid->GetDimensions(); const size_t nVerts = dims[0] * dims[1] * dims[2]; std::vector dataMinExtD, dataMaxExtD; grid->GetUserExtents(dataMinExtD, dataMaxExtD); vec3 dataMinExt(dataMinExtD[0], dataMinExtD[1], dataMinExtD[2]); vec3 dataMaxExt(dataMaxExtD[0], dataMaxExtD[1], dataMaxExtD[2]); vec3 dimsf(dims[0], dims[1], dims[2]); vec3 gridSpacing = (dataMaxExt - dataMinExt) / (dimsf - 1.f); float missingValue = grid->HasMissingData() ? grid->GetMissingValue() : NAN; float *fdata = new float[nVerts]; if (!fdata) { Wasp::MyBase::SetErrMsg("Could not allocate enough RAM to load data"); return nullptr; } auto dataIt = grid->cbegin(); for (size_t i = 0; i < nVerts; ++i, ++dataIt) { fdata[i] = *dataIt == missingValue ? NAN : *dataIt; } OSPData data = VOSP::NewCopiedData(fdata, OSP_FLOAT, dims[0], dims[1], dims[2]); ospCommit(data); delete[] fdata; OSPVolume volume = ospNewVolume("structuredRegular"); ospSetObject(volume, "data", data); ospRelease(data); ospSetVec3f(volume, "gridOrigin", dataMinExt.x, dataMinExt.y, dataMinExt.z); ospSetVec3f(volume, "gridSpacing", gridSpacing.x, gridSpacing.y, gridSpacing.z); ospCommit(volume); return volume; } VolumeOSPRay::WindingOrder VolumeOSPRay::getWindingOrderRespectToZ(const vec3 &a, const vec3 &b, const vec3 &c) { return glm::cross(b - a, c - b).z > 0 ? CCW : CW; } VolumeOSPRay::WindingOrder VolumeOSPRay::getWindingOrderTetra(const vec3 &a, const vec3 &b, const vec3 &c, const vec3 &d) { vec3 n = glm::cross(b - a, c - a); float s = glm::dot(d - a, n); if (fabsf(s) < FLT_EPSILON) return INVALID; return s < 0 ? CCW : CW; } const char *VolumeOSPRay::windingOrderToString(WindingOrder o) { return o == CCW ? "CCW" : o == CW ? "CW" : "INVALID"; } bool VolumeOSPRay::isQuadCoPlanar(const vec3 &a, const vec3 &b, const vec3 &c, const vec3 &d) { vec3 n = glm::normalize(glm::cross(b - a, c - a)); float s = glm::dot(d - a, n); return fabsf(s) <= FLT_EPSILON; } OSPVolume VolumeOSPRay::_loadVolumeStructured(const Grid *grid) { const auto dims = grid->GetDimensions(); const size_t nVerts = dims[0] * dims[1] * dims[2]; float missingValue = grid->HasMissingData() ? grid->GetMissingValue() : NAN; Progress::Start("Loading Grid", 2, false); float *vdata = new float[nVerts]; auto dataIt = grid->cbegin(); for (size_t i = 0; i < nVerts; ++i, ++dataIt) vdata[i] = *dataIt == missingValue ? NAN : *dataIt; Progress::Update(1); float *cdata = new float[nVerts * 3]; auto coord = grid->ConstCoordBegin(); for (size_t i = 0; i < nVerts; ++i, ++coord) { cdata[i * 3] = (*coord)[0]; cdata[i * 3 + 1] = (*coord)[1]; cdata[i * 3 + 2] = (*coord)[2]; } Progress::Finish(); int xd = dims[0]; int yd = dims[1]; int zd = dims[2]; int cxd = xd - 1; int cyd = yd - 1; int czd = zd - 1; if (cxd * cyd * czd == 0) { MyBase::SetErrMsg("Volume rendering a flat grid not supported with this method"); return nullptr; } // "indexPrefixed" is broken typedef struct { union { struct { unsigned int i0, i1, i2, i3, i4, i5, i6, i7; }; unsigned int i[8]; }; } Cell; vector indices(cxd * cyd * czd); #define I(x, y, z) (unsigned int)((z)*yd * xd + (y)*xd + (x)) Progress::Start("Convert Grid", czd, true); for (int z = 0; z < czd; z++) { Progress::Update(z); if (Progress::Cancelled()) { delete[] vdata; delete[] cdata; return nullptr; } for (int y = 0; y < cyd; y++) { for (int x = 0; x < cxd; x++) { indices[z * cyd * cxd + y * cxd + x] = {{{ I(x, y, z), I(x + 1, y, z), I(x + 1, y + 1, z), I(x, y + 1, z), I(x, y, z + 1), I(x + 1, y, z + 1), I(x + 1, y + 1, z + 1), I(x, y + 1, z + 1), }}}; } } } Progress::Finish(); #undef I const int maxCells = INT_MAX; const int nCells = min(maxCells, czd * cyd * cxd); vec3 * coords = (vec3 *)cdata; // for (int i = 0; i < 8; i++) { // int ci = indices[nCells-1].i[i]; // printf("cells[%i][%i] = (%f, %f, %f)\n", nCells-1, i, coords[ci].x, coords[ci].y, coords[ci].z); // } // for (int i = 0; i < 4; i++) { // int bi = indices[nCells-1].i[i]; // int ti = indices[nCells-1].i[i+4]; // auto &b = coords[bi]; // auto &t = coords[ti]; // float zdiff = (t-b).z; // printf("ZDiff[%i] = %f%s\n", i, zdiff, zdiff < FLT_EPSILON ? " (< EPSILON)" : ""); // } // bool decompose = GetActiveParams()->GetValueLong("osp_decompose", false); const bool decompose = true; unsigned nDecomposed = 0; unsigned nDiscarded = 0; Progress::Start("Preprocess Grid", nCells, true); vector startIndex; vector cellType; for (int i = 0; i < nCells; i++) { Progress::Update(i); if (Progress::Cancelled()) { delete[] vdata; delete[] cdata; return nullptr; } bool discard = false; for (int j = 0; j < 4; j++) { if (fabsf((coords[indices[i].i[j + 4]] - coords[indices[i].i[j]]).z) < FLT_EPSILON) { discard = true; break; } } if (discard) { nDiscarded++; continue; } if (decompose && (!isQuadCoPlanar(coords[indices[i].i0], coords[indices[i].i1], coords[indices[i].i2], coords[indices[i].i3]) || !isQuadCoPlanar(coords[indices[i].i4], coords[indices[i].i5], coords[indices[i].i6], coords[indices[i].i7]))) { Cell c = indices[i]; Cell w1 = {{{c.i0, c.i1, c.i3, c.i4, c.i5, c.i7, 0, 0}}}; Cell w2 = {{{c.i1, c.i2, c.i3, c.i5, c.i6, c.i7, 0, 0}}}; if (CW == getWindingOrderRespectToZ(coords[w1.i0], coords[w1.i1], coords[w1.i2])) { std::swap(w1.i1, w1.i2); std::swap(w1.i4, w1.i5); } if (CW == getWindingOrderRespectToZ(coords[w2.i0], coords[w2.i1], coords[w2.i2])) { std::swap(w2.i1, w2.i2); std::swap(w2.i4, w2.i5); } startIndex.push_back(indices.size() * 8); cellType.push_back(OSP_WEDGE); indices.push_back(w1); startIndex.push_back(indices.size() * 8); cellType.push_back(OSP_WEDGE); indices.push_back(w2); nDecomposed++; continue; } startIndex.push_back(i * 8); cellType.push_back(OSP_HEXAHEDRON); } Progress::Finish(); // printf("Discarded %i cells\n", nDiscarded); // printf("Decomposed %i cells\n", nDecomposed); VAssert(cellType.size() == startIndex.size()); OSPVolume volume = ospNewVolume("unstructured"); OSPData data; Progress::Start("Copy data to OSPRay", 5, false); data = VOSP::NewCopiedData(vdata, OSP_FLOAT, nVerts); ospCommit(data); ospSetObject(volume, "vertex.data", data); ospRelease(data); delete[] vdata; Progress::Update(1); data = VOSP::NewCopiedData(cdata, OSP_VEC3F, nVerts); ospCommit(data); ospSetObject(volume, "vertex.position", data); ospRelease(data); delete[] cdata; Progress::Update(2); // Was cxd*cyd*czd*8 // need to potentially modify when replacing non-parallelpiped cells. data = VOSP::NewCopiedData(indices.data(), OSP_UINT, indices.size() * 8); ospCommit(data); ospSetObject(volume, "index", data); ospRelease(data); indices.clear(); Progress::Update(3); data = VOSP::NewCopiedData(startIndex.data(), OSP_UINT, startIndex.size()); ospCommit(data); ospSetObject(volume, "cell.index", data); ospRelease(data); startIndex.clear(); Progress::Update(4); data = VOSP::NewCopiedData(cellType.data(), OSP_UCHAR, cellType.size()); ospCommit(data); ospSetObject(volume, "cell.type", data); ospRelease(data); cellType.clear(); Progress::Update(5); Progress::Finish(); Progress::StartIndefinite("Commit OSPRay"); ospSetBool(volume, "hexIterative", true); ospCommit(volume); Progress::Finish(); return volume; } OSPVolume VolumeOSPRay::_loadVolumeUnstructured(const Grid *grid) { const auto nodeDims = grid->GetDimensions(); size_t nodeDim = grid->GetNumDimensions(); const size_t nVerts = nodeDims[0] * nodeDims[1]; const DimsType &cellDims = grid->GetCellDimensions(); const size_t nCells = cellDims[0] * cellDims[1]; VAssert(nodeDim == 2); float missingValue = grid->HasMissingData() ? grid->GetMissingValue() : NAN; size_t maxNodes = grid->GetMaxVertexPerCell(); // size_t *nodes = (size_t*)alloca(sizeof(size_t) * maxNodes * nodeDim); std::vector nodes(maxNodes * nodeDim); Progress::Start("Loading Grid Data", 2, false); float *vdata = new float[nVerts]; auto dataIt = grid->cbegin(); for (size_t i = 0; i < nVerts; ++i, ++dataIt) vdata[i] = *dataIt == missingValue ? NAN : *dataIt; Progress::Update(1); float *cdata = new float[nVerts * 3]; auto coord = grid->ConstCoordBegin(); for (size_t i = 0; i < nVerts; ++i, ++coord) { cdata[i * 3] = (*coord)[0]; cdata[i * 3 + 1] = (*coord)[1]; cdata[i * 3 + 2] = (*coord)[2]; } Progress::Update(2); Progress::Finish(); vector cellIndices; vector cellStarts; vector cellTypes; long added[32] = {0}; long skipped[32] = {0}; #ifdef VAPOR_3_5_0 int maxCells = std::max(5, std::min((int)nCells, (int)GetParams()->GetValueLong("osp_max_cells", 1))); #endif auto cellIt = grid->ConstCellBegin(); Progress::Start("Loading Grid", nCells, true); for (size_t cellCounter = 0; cellCounter < nCells; ++cellIt, ++cellCounter) { Progress::Update(cellCounter); if (Progress::Cancelled()) { delete[] vdata; delete[] cdata; return nullptr; } const DimsType &cell = *cellIt; grid->GetCellNodes(cell, nodes); int numNodes = nodes.size(); if (numNodes == 4) { cellStarts.push_back(cellIndices.size()); cellTypes.push_back(OSP_TETRAHEDRON); added[numNodes]++; for (int i = 0; i < 4; i++) cellIndices.push_back(nodes[i][0] + nodes[i][1] * nodeDims[0]); } else if (numNodes == 6) { cellStarts.push_back(cellIndices.size()); cellTypes.push_back(OSP_WEDGE); added[numNodes]++; for (int i = 0; i < 6; i++) cellIndices.push_back(nodes[i][0] + nodes[i][1] * nodeDims[0]); } else if (numNodes == 8) { cellStarts.push_back(cellIndices.size()); cellTypes.push_back(OSP_HEXAHEDRON); added[numNodes]++; for (int i = 0; i < 8; i++) cellIndices.push_back(nodes[i][0] + nodes[i][1] * nodeDims[0]); } else if (numNodes == 12) { // Hexagonal Prism #define add(i) cellIndices.push_back(nodes[i][0] + nodes[i][1] * nodeDims[0]); for (int i = 0; i < 4; i++) { cellStarts.push_back(cellIndices.size()); cellTypes.push_back(OSP_WEDGE); add(0); add(i + 1); add(i + 2); add(6); add(6 + i + 1); add(6 + i + 2); } #undef add added[numNodes]++; } else { skipped[numNodes]++; } #ifdef VAPOR_3_5_0 if (cellCounter >= maxCells - 1) { printf("WARNING BREAKING EARLY\n"); break; } #endif } Progress::Finish(); #ifdef VAPOR_3_5_0 long totalAdded = 0, totalSkipped = 0; for (int i = 0; i < 32; i++) { if (added[i] > 0) printf("\tAdded[%i] = %li\n", i, added[i]); if (skipped[i] > 0) printf("\tSkipped[%i] = %li\n", i, skipped[i]); totalAdded += added[i]; totalSkipped += skipped[i]; } printf("\tTotal Added = %li\n", totalAdded); printf("\tTotal Skipped = %li\n", totalSkipped); printf("# Coords = %li\n", nVerts); #endif vec3 * coords = (vec3 *)cdata; vector erase(cellStarts.size(), false); Progress::Start("Preprocessing Cells", cellStarts.size(), true); for (unsigned i = 0; i < cellStarts.size(); i++) { Progress::Update(i); if (Progress::Cancelled()) { delete[] vdata; delete[] cdata; return nullptr; } unsigned start = cellStarts[i]; unsigned type = cellTypes[i]; if (type == OSP_WEDGE) { if (CW == getWindingOrderRespectToZ(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]])) { std::swap(cellIndices[start + 1], cellIndices[start + 2]); std::swap(cellIndices[start + 1 + 3], cellIndices[start + 2 + 3]); } WindingOrder w1 = getWindingOrderTetra(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]], coords[cellIndices[start + 3]]); WindingOrder w2 = getWindingOrderTetra(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]], coords[cellIndices[start + 4]]); WindingOrder w3 = getWindingOrderTetra(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]], coords[cellIndices[start + 5]]); if (w1 == INVALID || w2 == INVALID || w3 == INVALID) { erase[i] = true; continue; } } else if (type == OSP_TETRAHEDRON) { WindingOrder w = getWindingOrderTetra(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]], coords[cellIndices[start + 3]]); if (w == CW) std::swap(cellIndices[start + 1], cellIndices[start + 2]); if (w == INVALID) { erase[i] = true; continue; } VAssert(CCW == getWindingOrderTetra(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]], coords[cellIndices[start + 3]])); #ifdef VAPOR_3_5_0 if (CCW != GetWindingOrderTetra(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]], coords[cellIndices[start + 3]])) { PrintVec3(coords[cellIndices[start + 0]]); PrintVec3(coords[cellIndices[start + 1]]); PrintVec3(coords[cellIndices[start + 2]]); PrintVec3(coords[cellIndices[start + 3]]); printf("Winding = %s\n", to_string(GetWindingOrderTetra(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]], coords[cellIndices[start + 3]]))); assert(0); } #endif } else if (type == OSP_HEXAHEDRON) { auto windingBottom = getWindingOrderRespectToZ(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]]); auto windingTop = getWindingOrderRespectToZ(coords[cellIndices[start + 4]], coords[cellIndices[start + 5]], coords[cellIndices[start + 6]]); if (INVALID == windingBottom || INVALID == windingTop || windingTop != windingBottom) { erase[i] = true; continue; } if (windingTop == CW) { std::swap(cellIndices[start + 0 + 1], cellIndices[start + 0 + 3]); std::swap(cellIndices[start + 4 + 1], cellIndices[start + 4 + 3]); } vec3 min = coords[cellIndices[start]]; vec3 max = coords[cellIndices[start]]; for (int i = 1; i < 8; i++) { min = glm::min(min, coords[cellIndices[start + i]]); max = glm::max(max, coords[cellIndices[start + i]]); } vec3 bbSizes = max - min; float bbVolume = bbSizes.x * bbSizes.y * bbSizes.z; if (bbVolume <= FLT_EPSILON) { erase[i] = true; continue; } } } Progress::Finish(); { vector cellStartsNew; vector cellTypesNew; for (int i = 0; i < cellStarts.size(); i++) { if (!erase[i]) { cellStartsNew.push_back(cellStarts[i]); cellTypesNew.push_back(cellTypes[i]); } } cellStarts = cellStartsNew; cellTypes = cellTypesNew; } #ifdef VAPOR_3_5_0 int testCell = std::min(cellStarts.size() - 1, (size_t)maxCells - 1); if (testCell >= 0) { int testCellNodes = cellTypes[testCell] == OSP_TETRAHEDRON ? 4 : cellTypes[testCell] == OSP_HEXAHEDRON ? 8 : 6; printf("Test Cell[%i].nodes = %i\n", testCell, testCellNodes); vec3 testCellCoords[testCellNodes]; for (int i = 0; i < testCellNodes; i++) { int idx = cellIndices[cellStarts[testCell] + i]; testCellCoords[i] = coords[idx]; printf("\tCells[%i].vert[%i] = coords[%i] = (%f, %f, %f)\n", testCell, i, idx, coords[idx].x, coords[idx].y, coords[idx].z); } printf("\tWinding bottom = %s\n", C(getWindingOrderRespectToZ(testCellCoords[0], testCellCoords[1], testCellCoords[2]))); if (testCellNodes == 6) printf("\tWinding top = %s\n", C(getWindingOrderRespectToZ(testCellCoords[3], testCellCoords[4], testCellCoords[5]))); if (testCellNodes == 8) printf("\tWinding top = %s\n", C(getWindingOrderRespectToZ(testCellCoords[4], testCellCoords[5], testCellCoords[6]))); } #endif Progress::Start("Sanity Checks", 5, false); for (auto i : cellIndices) VAssert(i < nVerts); Progress::Update(1); for (auto i : cellStarts) VAssert(i < cellIndices.size()); Progress::Update(2); for (auto i : cellTypes) VAssert(i == OSP_WEDGE || i == OSP_TETRAHEDRON || i == OSP_HEXAHEDRON); Progress::Update(3); VAssert(cellStarts[cellStarts.size() - 1] + (cellTypes[cellTypes.size() - 1] == OSP_WEDGE ? 6 : 4) <= cellIndices.size()); Progress::Update(4); VAssert(cellStarts.size() == cellTypes.size()); Progress::Update(5); Progress::Finish(); Progress::Start("Copy data to OSPRay", 5, false); OSPVolume volume = ospNewVolume("unstructured"); OSPData data; data = VOSP::NewCopiedData(vdata, OSP_FLOAT, nVerts); ospCommit(data); ospSetObject(volume, "vertex.data", data); ospRelease(data); delete[] vdata; Progress::Update(1); data = VOSP::NewCopiedData(cdata, OSP_VEC3F, nVerts); ospCommit(data); ospSetObject(volume, "vertex.position", data); ospRelease(data); delete[] cdata; Progress::Update(2); data = VOSP::NewCopiedData(cellIndices.data(), OSP_UINT, cellIndices.size()); ospCommit(data); ospSetObject(volume, "index", data); ospRelease(data); cellIndices.clear(); Progress::Update(3); data = VOSP::NewCopiedData(cellStarts.data(), OSP_UINT, cellStarts.size()); ospCommit(data); ospSetObject(volume, "cell.index", data); ospRelease(data); cellStarts.clear(); Progress::Update(4); data = VOSP::NewCopiedData(cellTypes.data(), OSP_UCHAR, cellTypes.size()); ospCommit(data); ospSetObject(volume, "cell.type", data); ospRelease(data); cellTypes.clear(); Progress::Update(5); Progress::Finish(); Progress::Start("Commit OSPRay", 1, false); ospCommit(volume); Progress::Finish(); return volume; } OSPVolume VolumeOSPRay::_loadVolumeTest(const Grid *grid) { std::vector dataMinExtD, dataMaxExtD; grid->GetUserExtents(dataMinExtD, dataMaxExtD); vec3 dataMinExt(dataMinExtD[0], dataMinExtD[1], dataMinExtD[2]); vec3 dataMaxExt(dataMaxExtD[0], dataMaxExtD[1], dataMaxExtD[2]); int nVerts = 8; vector values(nVerts); for (int i = 0; i < nVerts; i++) values[i] = 0; vector coords(nVerts); float s = 1; vec3 l = s * dataMinExt; vec3 h = s * dataMaxExt; coords[0] = vec3(0, 0, 0); coords[1] = vec3(1, 0, 0); coords[2] = vec3(1, 1, 0); coords[3] = vec3(0, 1, 0); coords[4] = vec3(0, 0, 1); coords[5] = vec3(1, 0, 1); coords[6] = vec3(1, 1, 1); coords[7] = vec3(0, 1, 1); for (int i = 0; i < 8; i++) coords[i] = coords[i] * (h - l) + l; OSPVolume volume = ospNewVolume("unstructured"); OSPData data; data = VOSP::NewCopiedData(values.data(), OSP_FLOAT, nVerts); ospCommit(data); ospSetObject(volume, "vertex.data", data); ospRelease(data); data = VOSP::NewCopiedData(coords.data(), OSP_VEC3F, nVerts); ospCommit(data); ospSetObject(volume, "vertex.position", data); ospRelease(data); vector cellIndices; vector cellStarts; vector cellTypes; #if 1 cellStarts.push_back(cellIndices.size()); cellTypes.push_back(OSP_HEXAHEDRON); cellIndices.push_back(0); cellIndices.push_back(1); cellIndices.push_back(2); cellIndices.push_back(3); cellIndices.push_back(4); cellIndices.push_back(5); cellIndices.push_back(6); cellIndices.push_back(7); #else cellStarts.push_back(cellIndices.size()); cellTypes.push_back(OSP_WEDGE); cellIndices.push_back(0); cellIndices.push_back(1); cellIndices.push_back(3); cellIndices.push_back(4); cellIndices.push_back(5); cellIndices.push_back(7); cellStarts.push_back(cellIndices.size()); cellTypes.push_back(OSP_WEDGE); cellIndices.push_back(1); cellIndices.push_back(2); cellIndices.push_back(3); cellIndices.push_back(5); cellIndices.push_back(6); cellIndices.push_back(7); cellStarts.push_back(cellIndices.size()); cellTypes.push_back(OSP_TETRAHEDRON); cellIndices.push_back(0); cellIndices.push_back(1); cellIndices.push_back(2); cellIndices.push_back(3); #endif data = VOSP::NewCopiedData(cellIndices.data(), OSP_UINT, cellIndices.size()); ospCommit(data); ospSetObject(volume, "index", data); ospRelease(data); data = VOSP::NewCopiedData(cellStarts.data(), OSP_UINT, cellStarts.size()); ospCommit(data); ospSetObject(volume, "cell.index", data); ospRelease(data); data = VOSP::NewCopiedData(cellTypes.data(), OSP_UCHAR, cellTypes.size()); ospCommit(data); ospSetObject(volume, "cell.type", data); ospRelease(data); ospSetBool(volume, "hexIterative", true); ospCommit(volume); return volume; } /* #include void VolumeRenderer::drawTestCellOutline() { if (!GetActiveParams()->GetValueLong("osp_test_volume", false)) return; LegacyGL *lgl = _glManager->legacy; lgl->Begin(GL_LINE_STRIP); lgl->Color3f(1, 0, 0); lgl->Vertex(testCell[0]); lgl->Color3f(0, 1, 0); lgl->Vertex(testCell[1]); lgl->Color3f(0, 0, 1); lgl->Vertex(testCell[2]); lgl->Color3f(0, 1, 1); lgl->Vertex(testCell[3]); lgl->Color3f(1, 0, 0); lgl->Vertex(testCell[0]); lgl->Color3f(1, 1, 1); lgl->Vertex(testCell[4]); // lgl->Color3f(0, 1, 0); lgl->Vertex(testCell[5]); // lgl->Color3f(0, 0, 1); lgl->Vertex(testCell[6]); // lgl->Color3f(0, 1, 1); lgl->Vertex(testCell[7]); // lgl->Color3f(1, 0, 0); lgl->Vertex(testCell[4]); lgl->End(); lgl->Begin(GL_LINES); lgl->Color3f(0, 1, 0); lgl->Vertex(testCell[1]); lgl->Vertex(testCell[5]); lgl->Color3f(0, 0, 1); lgl->Vertex(testCell[2]); lgl->Vertex(testCell[6]); lgl->Color3f(0, 1, 1); lgl->Vertex(testCell[3]); lgl->Vertex(testCell[7]); lgl->End(); if (!GetActiveParams()->GetValueLong("osp_draw_test_cell_faces", false)) return; lgl->Color3f(1, 1, 1); lgl->EnableLighting(); ViewpointParams* vp = _paramsMgr->GetViewpointParams(_winName); double matrix[16], dpos[3], dup[3], ddir[3]; vp->GetModelViewMatrix(matrix); vp->ReconstructCamera(matrix, dpos, dup, ddir); vec3 dir(ddir[0], ddir[1], ddir[2]); lgl->LightDirectionfv((float*)&dir); glDepthFunc(GL_LESS); #define FACE(a, b, c) { vec3 n = glm::normalize(glm::cross(testCell[b]-testCell[a], testCell[c]-testCell[a])); lgl->Normal3fv((float*)&n); lgl->Vertex(testCell[a]); lgl->Vertex(testCell[b]); lgl->Vertex(testCell[c]); } #define QUAD(a, b, c, d) { FACE(a, b, d); FACE(d, b, c); } lgl->Begin(GL_TRIANGLES); QUAD(0, 1, 2, 3); QUAD(4, 5, 6, 7); QUAD(0, 1, 5, 4); QUAD(1, 2, 6, 5); QUAD(2, 3, 7, 6); QUAD(3, 0, 4, 7); lgl->End(); #undef FACE glDepthFunc(GL_ALWAYS); lgl->DisableLighting(); } */ static VolumeAlgorithmRegistrar registrationIso; ================================================ FILE: lib/render/VolumeRectilinear.cpp ================================================ #include "vapor/RegularGrid.h" #include #include #include #include #include #include #include #include #include #include #ifndef FLT16_MAX #define FLT16_MAX 6.55E4 #endif using glm::ivec2; using glm::ivec3; using glm::vec3; using std::array; using std::vector; using namespace VAPoR; static VolumeAlgorithmRegistrar registration; static VolumeAlgorithmRegistrar registration2; VolumeRectilinear::VolumeRectilinear(GLManager *gl, VolumeRenderer *renderer) : VolumeRegular(gl, renderer), _useHighPrecisionTriangleRoutine(false) { _coordLUTTexture.Generate(GL_LINEAR); _minTexture.Generate(GL_NEAREST); _maxTexture.Generate(GL_NEAREST); _BBLevelDimTexture.Generate(GL_NEAREST); } VolumeRectilinear::~VolumeRectilinear() {} int VolumeRectilinear::LoadData(const Grid *grid) { if (VolumeRegular::LoadData(grid) < 0) return -1; _useHighPrecisionTriangleRoutine = false; _gridHasInvertedCoordinateSystemHandiness = !grid->HasInvertedCoordinateSystemHandiness(); const auto dims = grid->GetDimensions(); const auto w = dims[0], h = dims[1], d = dims[2]; _coordDims[0] = w; _coordDims[1] = h; _coordDims[2] = d; vec3 dataMin, dataMax, userMin, userMax; _getExtents(&dataMin, &dataMax, &userMin, &userMax); vec3 extLengths = dataMax - dataMin; Progress::Start("Load coord data", 6); GLint max2DTexDim; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max2DTexDim); max2DTexDim /= 100; vector coordLUTData(max2DTexDim * 3); auto coords = array, 3>(); array, 3> srcCoords; auto rgrid = dynamic_cast(grid); if (rgrid) { srcCoords = { rgrid->GetXCoords(), rgrid->GetYCoords(), rgrid->GetZCoords(), }; } else { for (int i = 0; i < 3; i++) { srcCoords[i] = vector(dims[i]); for (int j = 0; j < dims[i]; j++) { auto idx = DimsType(); auto coord = CoordType(); idx[i] = j; grid->GetUserCoordinates(idx, coord); srcCoords[i][j] = coord[i]; } } } for (int i = 0; i < 3; i++) { Progress::Update(1+i); coords[i].resize(dims[i]); _coordSigns[i] = coords[i][0] < coords[i][dims[i]-1] ? 1 : -1; for (int j = 0; j < dims[i]; j++) { coords[i][j] = (srcCoords[i][j] - dataMin[i]) / extLengths[i]; } for (int j = 0; j < dims[i]-1; j++) { int start = coords[i][j]*max2DTexDim; int end = coords[i][j+1]*max2DTexDim; if (end < start) { int t = start; start = end; end = t; } for (int k = start; k < end; k++) coordLUTData[i*max2DTexDim + k] = (j + (k-start)/(float)(end-start))/(float)(dims[i]-1); } } Progress::Update(4); _coordLUTTexture.TexImage(GL_R32F, max2DTexDim, 3, 0, GL_RED, GL_FLOAT, coordLUTData.data()); Progress::Finish(); return 0; } std::string VolumeRectilinear::_addDefinitionsToShader(std::string shaderName) const { shaderName = VolumeRegular::_addDefinitionsToShader(shaderName); if (_useHighPrecisionTriangleRoutine) shaderName += ":USE_INTEL_TRI_ISECT"; if (_gridHasInvertedCoordinateSystemHandiness) shaderName += ":INVERT_GRID_COORD_SYS_HAND"; GLManager::Vendor vendor = GLManager::GetVendor(); if (vendor == GLManager::Vendor::Nvidia || vendor == GLManager::Vendor::AMD || vendor == GLManager::Vendor::Mesa) shaderName += ":NVIDIA"; shaderName += ":BB_LEVELS " + std::to_string(3); return shaderName; } ShaderProgram *VolumeRectilinear::GetShader() const { return _glManager->shaderManager->GetShader(_addDefinitionsToShader("VolumeRectilinearDVR")); } void VolumeRectilinear::SetUniforms(const ShaderProgram *s) const { VolumeRegular::SetUniforms(s); s->SetUniform("coordDims", *(glm::ivec3 *)&_coordDims); s->SetUniform("coordSigns", *(glm::ivec3 *)&_coordSigns); s->SetSampler("coordLUT", _coordLUTTexture); s->SetSampler("boxMins", _minTexture); s->SetSampler("boxMaxs", _maxTexture); s->SetSampler("levelDims", _BBLevelDimTexture); } float VolumeRectilinear::GuestimateFastModeSpeedupFactor() const { return 2; } int VolumeRectilinear::CheckHardwareSupport(const Grid *grid) const { int ret = VolumeRegular::CheckHardwareSupport(grid); if (ret < 0) return ret; long freeKB = oglGetFreeMemory(); if (freeKB >= 0) { auto dims = grid->GetDimensions(); long estimatedMinimumB = dims[0]*dims[1]*dims[2] * sizeof(float) * 4; long estimatedMinimumKB = estimatedMinimumB/1024; if (freeKB < estimatedMinimumKB) { Wasp::MyBase::SetErrMsg("Not enough GPU RAM free (%liMB free, need at least %liMB)\n", freeKB/1024, estimatedMinimumKB/1024); return -1; } } return 0; } ShaderProgram *VolumeRectilinearIso::GetShader() const { return _glManager->shaderManager->GetShader(_addDefinitionsToShader("VolumeRectilinearIso")); } void VolumeRectilinearIso::SetUniforms(const ShaderProgram *shader) const { VolumeRectilinear::SetUniforms(shader); } ================================================ FILE: lib/render/VolumeRegular.cpp ================================================ #include #include #include #include #include #include using std::vector; using namespace VAPoR; static VolumeAlgorithmRegistrar registration; VolumeRegular::VolumeRegular(GLManager *gl, VolumeRenderer *renderer) : VolumeGLSL(gl, renderer), _hasSecondData(false) { _data.Generate(); _missing.Generate(); } VolumeRegular::~VolumeRegular() {} int VolumeRegular::LoadData(const Grid *grid) { VolumeGLSL::LoadData(grid); if (grid->GetNumDimensions() != 3) { Wasp::MyBase::SetErrMsg("Variable has a volume of 0"); return -1; } auto tmp = grid->GetDimensions(); _dataDimensions = {tmp[0], tmp[1], tmp[2]}; _hasSecondData = false; return _loadDataDirect(grid, &_data, &_missing, &_hasMissingData); } int VolumeRegular::LoadSecondaryData(const Grid *grid) { _hasSecondData = false; auto tmp = grid->GetDimensions(); auto dims = std::vector{tmp[0], tmp[1], tmp[2]}; if (_dataDimensions != dims) { Wasp::MyBase::SetErrMsg("Secondary (color mapped) variable has different grid from primary variable"); return -1; } if (!_data2.Initialized()) _data2.Generate(); if (!_missing2.Initialized()) _missing2.Generate(); int ret = _loadDataDirect(grid, &_data2, &_missing2, &_hasMissingData2); if (ret >= 0) _hasSecondData = true; return ret; } void VolumeRegular::DeleteSecondaryData() { _hasSecondData = false; _data2.Delete(); _missing2.Delete(); } int VolumeRegular::_loadDataDirect(const Grid *grid, Texture3D *dataTexture, Texture3D *missingTexture, bool *hasMissingData) { auto dims = grid->GetDimensions(); const size_t nVerts = dims[0] * dims[1] * dims[2]; float * data = new float[nVerts]; if (!data) { Wasp::MyBase::SetErrMsg("Could not allocate enough RAM to load data"); return -1; } Progress::Start("Load volume data", nVerts, true); auto dataIt = grid->cbegin(); for (size_t i = 0; i < nVerts; ++i, ++dataIt) { Progress::Update(i); if (Progress::Cancelled()) { delete[] data; return -1; } data[i] = *dataIt; } Progress::Finish(); int ret = dataTexture->TexImage(GL_R32F, dims[0], dims[1], dims[2], GL_RED, GL_FLOAT, data); *hasMissingData = grid->HasMissingData(); if (ret == 0 && *hasMissingData) { const float missingValue = grid->GetMissingValue(); unsigned char *missingMask = new unsigned char[nVerts]; memset(missingMask, 0, nVerts); for (size_t i = 0; i < nVerts; i++) if (data[i] == missingValue) missingMask[i] = 255; glPixelStorei(GL_UNPACK_ALIGNMENT, 1); ret = missingTexture->TexImage(GL_R8, dims[0], dims[1], dims[2], GL_RED, GL_UNSIGNED_BYTE, missingMask); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); delete[] missingMask; } delete[] data; return ret; } ShaderProgram *VolumeRegular::GetShader() const { return _glManager->shaderManager->GetShader(_addDefinitionsToShader("VolumeDVR")); } void VolumeRegular::SetUniforms(const ShaderProgram *s) const { s->SetUniform("hasMissingData", _hasMissingData); s->SetSampler("data", _data); s->SetSampler("missingMask", _missing); s->SetUniform("useColormapData", _hasSecondData); if (_hasSecondData) { s->SetUniform("hasMissingData2", _hasMissingData2); s->SetSampler("data2", _data2); s->SetSampler("missing2", _missing2); } } float VolumeRegular::GuestimateFastModeSpeedupFactor() const { return 5; } int VolumeRegular::CheckHardwareSupport(const Grid *grid) const { int maxTexDim; glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &maxTexDim); auto dims = grid->GetDimensions(); for (auto d : dims) { if (d > maxTexDim) { Wasp::MyBase::SetErrMsg("Grid size (%lix%lix%li) not supported by GPU (max supported size per dim is %i)\n", dims[0], dims[1], dims[2], maxTexDim); return -1; } } long freeKB = oglGetFreeMemory(); if (freeKB >= 0) { long estimatedMinimumB = dims[0]*dims[1]*dims[2] * sizeof(float); long estimatedMinimumKB = estimatedMinimumB/1024; if (freeKB < estimatedMinimumKB) { Wasp::MyBase::SetErrMsg("Not enough GPU RAM free (%liMB free, need at least %liMB)\n", freeKB/1024, estimatedMinimumKB/1024); return -1; } } return 0; } std::string VolumeRegular::_addDefinitionsToShader(std::string shaderName) const { if (_hasSecondData) shaderName += ":USE_SECOND_DATA"; return shaderName; } static VolumeAlgorithmRegistrar registrationIso; ShaderProgram *VolumeRegularIso::GetShader() const { return _glManager->shaderManager->GetShader(_addDefinitionsToShader("VolumeIso")); } void VolumeRegularIso::SetUniforms(const ShaderProgram *shader) const { VolumeRegular::SetUniforms(shader); } ================================================ FILE: lib/render/VolumeRenderer.cpp ================================================ #include "vapor/VolumeRenderer.h" #include #include #include #include #include #include #include "vapor/VolumeRectilinear.h" #include #include using glm::ivec2; using glm::mat4; using glm::vec2; using glm::vec3; using glm::vec4; using std::string; using std::vector; #define CheckCache(cVar, pVar) \ if (cVar != pVar) { \ _cache.needsUpdate = true; \ cVar = pVar; \ } using namespace VAPoR; static RendererRegistrar registrar(VolumeRenderer::GetClassType(), VolumeParams::GetClassType()); VolumeRenderer::VolumeRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string &instName, DataMgr *dataMgr) : VolumeRenderer(pm, winName, dataSetName, VolumeParams::GetClassType(), VolumeRenderer::GetClassType(), instName, dataMgr) { } VolumeRenderer::VolumeRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string paramsType, std::string classType, std::string &instName, DataMgr *dataMgr) : Renderer(pm, winName, dataSetName, paramsType, classType, instName, dataMgr) { _lastRenderTime = 10000; _lastRenderWasFast = false; _framebufferRatio = 1; _previousFramebufferRatio = 1; if (_needToSetDefaultAlgorithm()) { VolumeParams * vp = (VolumeParams *)GetActiveParams(); CoordType minExt, maxExt; vp->GetBox()->GetExtents(minExt, maxExt); Grid *grid = _dataMgr->GetVariable(vp->GetCurrentTimestep(), vp->GetVariableName(), vp->GetRefinementLevel(), vp->GetCompressionLevel(), minExt, maxExt); if (grid) { string algorithmName = _getDefaultAlgorithmForGrid(grid); vp->SetAlgorithm(algorithmName); delete grid; } else { vp->SetAlgorithm(VolumeRegular::GetName()); } } } VolumeRenderer::~VolumeRenderer() { if (_VAO) glDeleteVertexArrays(1, &_VAO); if (_VBO) glDeleteBuffers(1, &_VBO); if (_VAOChunked) glDeleteVertexArrays(1, &_VAOChunked); if (_VBOChunked) glDeleteBuffers(1, &_VBOChunked); if (_cache.tf) delete _cache.tf; if (_algorithm) delete _algorithm; } int VolumeRenderer::_initializeGL() { const float BL = -1; const float data[] = {BL, BL, 0, 0, 1, BL, 1, 0, BL, 1, 0, 1, BL, 1, 0, 1, 1, BL, 1, 0, 1, 1, 1, 1}; glGenVertexArrays(1, &_VAO); glGenBuffers(1, &_VBO); glBindVertexArray(_VAO); glBindBuffer(GL_ARRAY_BUFFER, _VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float))); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glGenVertexArrays(1, &_VAOChunked); glGenBuffers(1, &_VBOChunked); glBindVertexArray(_VAOChunked); glBindBuffer(GL_ARRAY_BUFFER, _VBOChunked); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float))); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); _framebufferSize[0] = -1; _framebufferSize[1] = -1; _framebuffer.EnableDepthBuffer(); _framebuffer.Generate(); return 0; } int VolumeRenderer::_paintGL(bool fast) { if (fast && _wasTooSlowForFastRender()) return 0; auto p = GetActiveParams(); CheckCache(_cache.ospMaxCells, p->GetValueLong("osp_max_cells", 1)); CheckCache(_cache.ospTestCellId, p->GetValueLong("osp_test_cells", 1)); CheckCache(_cache.osp_force_regular, p->GetValueLong("osp_force_regular", 0)); CheckCache(_cache.osp_test_volume, p->GetValueLong("osp_test_volume", 0)); CheckCache(_cache.osp_decompose, p->GetValueLong("osp_decompose", 0)); CheckCache(_cache.osp_enable_clipping, p->GetValueLong("osp_enable_clipping", 1)); if (_initializeAlgorithm() < 0) return -1; if (_loadData() < 0) return -1; if (_loadSecondaryData() < 0) return -1; _cache.needsUpdate = false; _algorithm->SaveDepthBuffer(fast); _initializeFramebuffer(fast); glEnable(GL_BLEND); int src, dst; _algorithm->GetFinalBlendingMode(&src, &dst); glBlendFunc(src, dst); glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_ALWAYS); void *start = GLManager::BeginTimer(); _algorithm->Render(fast); if (_shouldUseChunkedRender(fast)) _drawScreenQuadChuncked(); else _drawScreenQuad(); double renderTime = GLManager::EndTimer(start); _lastRenderTime = renderTime; _lastRenderWasFast = fast; int ret = _renderFramebufferToDisplay(); glDepthFunc(GL_LESS); glDisable(GL_BLEND); glBindVertexArray(0); ShaderProgram::UnBind(); return ret; } std::string VolumeRenderer::_getColorbarVariableName() const { VolumeParams *vp = dynamic_cast(GetActiveParams()); if (vp->GetValueLong(VolumeParams::UseColormapVariableTag, 0)) return vp->GetColorMapVariableName(); else return vp->GetVariableName(); } void VolumeRenderer::_drawScreenQuad() { glBindVertexArray(_VAO); glDrawArrays(GL_TRIANGLES, 0, 6); } void VolumeRenderer::_drawScreenQuadChuncked() { // This constant is not correctly parenthesized because of precision issues #define CHUNKS_PER_DIM_CONSTANT 64 / (1000 * 1000) int width = _originalViewport[2] - _originalViewport[0]; int height = _originalViewport[3] - _originalViewport[1]; float nPixels = width * height; double chunksPerDim = sqrt(nPixels * CHUNKS_PER_DIM_CONSTANT); int framebufferChunksPerDim = ceil(chunksPerDim / _framebufferRatio); _generateChunkedRenderMesh(framebufferChunksPerDim); glBindVertexArray(_VAOChunked); for (int i = 0; i < _nChunks; i++) { glDrawArrays(GL_TRIANGLES, i * 6, 6); glFinish(); } } void VolumeRenderer::_generateChunkedRenderMesh(const float C) { vector d; _nChunks = powf(ceil(C), 2); d.reserve(powf(ceil(C), 2) * 6); float ts = 1 / (float)C; for (int yi = 0; yi < C; yi++) { float y = 2.f * yi / (float)C - 1.f; float ty = yi / (float)C; float y2 = 2.f * (yi + 1) / (float)C - 1.f; float ty2 = min(ty + ts, 1.0f); for (int xi = 0; xi < C; xi++) { float x = 2.f * xi / (float)C - 1.f; float tx = xi / (float)C; float x2 = 2.f * (xi + 1) / (float)C - 1.f; float tx2 = min(tx + ts, 1.0f); d.push_back(vec4(x, y, tx, ty)); d.push_back(vec4(x2, y, tx2, ty)); d.push_back(vec4(x, y2, tx, ty2)); d.push_back(vec4(x, y2, tx, ty2)); d.push_back(vec4(x2, y, tx2, ty)); d.push_back(vec4(x2, y2, tx2, ty2)); } } glBindBuffer(GL_ARRAY_BUFFER, _VBOChunked); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * d.size(), d.data(), GL_STATIC_DRAW); } #define MAX_FRAMEBUFFER_RATIO 15.0f bool VolumeRenderer::_wasTooSlowForFastRender() const { float prevFPS = 1 / _lastRenderTime; if (_lastRenderWasFast && prevFPS < 10 && _framebufferRatio == MAX_FRAMEBUFFER_RATIO) return true; return false; } void VolumeRenderer::_computeNewFramebufferRatio() { float prevFPS = 1 / _lastRenderTime; if (!_lastRenderWasFast) prevFPS *= _algorithm->GuestimateFastModeSpeedupFactor(); if (prevFPS < 24 || (prevFPS > 40 && _framebufferRatio > 3) || prevFPS > 60) { float ratioTo30FPS = 30 / prevFPS; float perDimRatio = sqrtf(ratioTo30FPS); _framebufferRatio *= perDimRatio; _framebufferRatio = min(_framebufferRatio, MAX_FRAMEBUFFER_RATIO); _framebufferRatio = max(_framebufferRatio, 1.0f); } } bool VolumeRenderer::_shouldUseChunkedRender(bool fast) const { if (_algorithm) { if (_algorithm->RequiresChunkedRendering()) return true; float estimatedTime = _lastRenderTime; if (_lastRenderWasFast && !fast) { estimatedTime *= powf(_previousFramebufferRatio, 2); estimatedTime *= _algorithm->GuestimateFastModeSpeedupFactor(); } if (estimatedTime > 1.0f) return true; } return false; } bool VolumeRenderer::_usingColorMapData() const { // Overriden by VolumeIsoRenderer return GetActiveParams()->GetValueLong(VAPoR::VolumeParams::UseColormapVariableTag, false); } void VolumeRenderer::_saveOriginalViewport() { glGetIntegerv(GL_VIEWPORT, _originalViewport); } void VolumeRenderer::_restoreOriginalViewport() { glViewport(_originalViewport[0], _originalViewport[1], _originalViewport[2], _originalViewport[3]); } void VolumeRenderer::_initializeFramebuffer(bool fast) { _previousFramebufferRatio = _framebufferRatio; if (fast) _computeNewFramebufferRatio(); else _framebufferRatio = 1; _saveOriginalViewport(); ivec2 fbSize(_originalViewport[2], _originalViewport[3]); fbSize /= _framebufferRatio; _framebuffer.SetSize(fbSize.x, fbSize.y); glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &_originalFramebuffer); _framebuffer.MakeRenderTarget(); glClearColor(0, 0, 0, 0); glDepthMask(true); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } int VolumeRenderer::_renderFramebufferToDisplay() { _framebuffer.UnBind(); glBindFramebuffer(GL_FRAMEBUFFER, _originalFramebuffer); _restoreOriginalViewport(); SmartShaderProgram framebufferShader = _glManager->shaderManager->GetShader("Framebuffer"); if (!framebufferShader.IsValid()) return -1; framebufferShader->SetSampler("colorBuffer", *_framebuffer.GetColorTexture()); framebufferShader->SetSampler("depthBuffer", *_framebuffer.GetDepthTexture()); _drawScreenQuad(); return 0; } int VolumeRenderer::_initializeAlgorithm() { VolumeParams *vp = (VolumeParams *)GetActiveParams(); if (_cache.algorithmName != vp->GetAlgorithm()) { _cache.algorithmName = vp->GetAlgorithm(); if (_cache.algorithmName == "") _cache.algorithmName = "NULL"; if (_algorithm) delete _algorithm; _algorithm = VolumeAlgorithm::NewAlgorithm(_cache.algorithmName, _glManager, this); _cache.needsUpdate = true; } if (_algorithm) return 0; else return -1; } int VolumeRenderer::_loadData() { VolumeParams * RP = (VolumeParams *)GetActiveParams(); vector minExtVec, maxExtVec; RP->GetBox()->GetExtents(minExtVec, maxExtVec); CheckCache(_cache.var, RP->GetVariableName()); CheckCache(_cache.ts, RP->GetCurrentTimestep()); CheckCache(_cache.refinement, RP->GetRefinementLevel()); CheckCache(_cache.compression, RP->GetCompressionLevel()); CheckCache(_cache.minExt, minExtVec); CheckCache(_cache.maxExt, maxExtVec); CheckCache(_cache.ospMaxCells, RP->GetValueLong("osp_max_cells", 1)); if (!_cache.needsUpdate) return 0; CoordType minExt, maxExt; Grid::CopyToArr3(_cache.minExt, minExt); Grid::CopyToArr3(_cache.maxExt, maxExt); Grid *grid = _dataMgr->GetVariable(_cache.ts, _cache.var, _cache.refinement, _cache.compression, minExt, maxExt); if (!grid) return -1; if (dynamic_cast(grid) && !dynamic_cast(_algorithm)) { MyBase::SetErrMsg("Unstructured grids are not supported by the GPU renderer"); return -1; } // Actual min and max extents of returned grid, which are in general // larger than requested extents. // grid->GetUserExtents(_dataMinExt, _dataMaxExt); if (_needToSetDefaultAlgorithm()) { RP->SetAlgorithm(_getDefaultAlgorithmForGrid(grid)); if (_initializeAlgorithm() < 0) { delete grid; return -1; } } int ret = _algorithm->CheckHardwareSupport(grid); if (ret == 0) { ret = _algorithm->LoadData(grid); _lastRenderTime = 10000; } delete grid; return ret; } int VolumeRenderer::_loadSecondaryData() { VolumeParams *vp = (VolumeParams *)GetActiveParams(); CheckCache(_cache.useColorMapVar, _usingColorMapData()); CheckCache(_cache.colorMapVar, vp->GetColorMapVariableName()); if (!_cache.needsUpdate) return 0; if (_cache.useColorMapVar) { CoordType minExt, maxExt; Grid::CopyToArr3(_cache.minExt, minExt); Grid::CopyToArr3(_cache.maxExt, maxExt); Grid *grid = _dataMgr->GetVariable(_cache.ts, _cache.colorMapVar, _cache.refinement, _cache.compression, minExt, maxExt); if (!grid) return -1; int ret = _algorithm->LoadSecondaryData(grid); delete grid; return ret; } else { _algorithm->DeleteSecondaryData(); return 0; } } std::string VolumeRenderer::_getDefaultAlgorithmForGrid(const Grid *grid) const { bool intel = GLManager::GetVendor() == GLManager::Vendor::Intel; if (dynamic_cast(grid)) return VolumeRegular::GetName(); if (dynamic_cast(grid)) return VolumeRectilinear::GetName(); if (dynamic_cast(grid)) return intel ? VolumeRegular::GetName() : VolumeCellTraversal::GetName(); if (dynamic_cast(grid)) return VolumeOSPRay::GetName(); MyBase::SetErrMsg("Unsupported grid type: %s", grid->GetType().c_str()); return ""; } bool VolumeRenderer::_needToSetDefaultAlgorithm() const { return !((VolumeParams *)GetActiveParams())->GetAlgorithmWasManuallySetByUser(); } ================================================ FILE: lib/render/VolumeResampled.cpp ================================================ #include #include #include #include using std::vector; using namespace VAPoR; // static VolumeAlgorithmRegistrar registration; int VolumeResampled::LoadData(const Grid *grid) { VolumeRegular::LoadData(grid); #define S 1 const vector dims = grid->GetDimensions(); const size_t w = dims[0] * S, h = dims[1] * S, d = dims[2] * S; float * data = new float[w * h * d]; vector min, max; grid->GetUserExtents(min, max); for (int z = 0; z < d; z++) { printf("Resampling... %i/%li\n", z, d); const float zSamplePos = (z + 0.5f) / (float)d * (max[2] - min[2]) + min[2]; for (int y = 0; y < h; y++) { const float ySamplePos = (y + 0.5f) / (float)h * (max[1] - min[1]) + min[1]; for (int x = 0; x < w; x++) { const float xSamplePos = (x + 0.5f) / (float)w * (max[0] - min[0]) + min[0]; data[z * w * h + y * w + x] = grid->GetValue(xSamplePos, ySamplePos, zSamplePos); } } } _data.TexImage(GL_R32F, w, h, d, GL_RED, GL_FLOAT, data); _hasMissingData = grid->HasMissingData(); if (_hasMissingData) { printf("Loading missing data...\n"); const float missingValue = grid->GetMissingValue(); unsigned char *missingMask = new unsigned char[w * h * d]; memset(missingMask, 0, w * h * d); for (size_t i = 0; i < w * h * d; i++) if (data[i] == missingValue) missingMask[i] = 255; glPixelStorei(GL_UNPACK_ALIGNMENT, 1); _missing.TexImage(GL_R8, dims[0], dims[1], dims[2], GL_RED, GL_UNSIGNED_BYTE, missingMask); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); delete[] missingMask; } delete[] data; return 0; } ================================================ FILE: lib/render/VolumeTest.cpp ================================================ #include #include #include #include #include using std::vector; using namespace VAPoR; static VolumeAlgorithmRegistrar registration; VolumeTest::VolumeTest(GLManager *gl) : VolumeRegular(gl) { glGenTextures(1, &zCoordTexture); glBindTexture(GL_TEXTURE_3D, zCoordTexture); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glGenTextures(1, &xyCoordTexture); glBindTexture(GL_TEXTURE_2D, xyCoordTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } VolumeTest::~VolumeTest() { if (zCoordTexture) glDeleteTextures(1, &zCoordTexture); if (xyCoordTexture) glDeleteTextures(1, &xyCoordTexture); } int VolumeTest::LoadData(const Grid *grid) { if (VolumeRegular::LoadData(grid) < 0) return -1; vector dims = grid->GetDimensions(); const int w = dims[0], h = dims[1], d = dims[2]; vector minExt, maxExt; grid->GetUserExtents(minExt, maxExt); const float minX = minExt[0]; const float minY = minExt[1]; const float minZ = minExt[2]; const float maxX = maxExt[0]; const float maxY = maxExt[1]; const float maxZ = maxExt[2]; // float *xy = new float[dims[0]*dims[1]]; float *data = new float[w * h * d * 3]; for (int i = 0; i < w * h * d * 3; i++) data[i] = -1; // auto coord = grid->ConstCoordBegin(); // broken // auto end = grid->ConstCoordEnd(); vector indices = {0, 0, 0}; vector coords; for (int z = 0; z < d; z++) { printf("%i/%i\n", z, d); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { // data[coord] = x,y,z; // float cx = (*coord)[0]; // float cy = (*coord)[1]; // float cz = (*coord)[2]; double dcx, dcy, dcz; float cx, cy, cz; // grid->GetUserCoordinates(x, y, z, dcx, dcy, dcz); // cx = dcx; // cy = dcy; // cz = dcz; // printf("[%i, %i, %i] = %.2f\t%.2f\t%.2f\n", x, y, z, dcx, dcy, dcz); indices[0] = x; indices[1] = y; indices[2] = z; grid->GetUserCoordinates(indices, coords); cx = coords[0]; cy = coords[1]; cz = coords[2]; int dx = (cx - minX) / (maxX - minX) * (w - 1); int dy = (cy - minY) / (maxY - minY) * (h - 1); int dz = (cz - minZ) / (maxZ - minZ) * (d - 1); // VAssert(dx>=0 && dx=0 && dy=0 && dzshaderManager->GetShader("ray2"); if (!s) return nullptr; s->Bind(); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_3D, zCoordTexture); s->SetUniform("coordLUT", 2); return s; } ================================================ FILE: lib/render/VolumeTest2.cpp ================================================ #include #include #include #include #include using glm::ivec3; using glm::vec3; using std::vector; using namespace VAPoR; static VolumeAlgorithmRegistrar registration; #define FI_LEFT 0 #define FI_RIGHT 1 #define FI_UP 2 #define FI_DOWN 3 #define FI_FRONT 4 #define FI_BACK 5 #define F_LEFT ivec3(-1, 0, 0) #define F_RIGHT ivec3(1, 0, 0) #define F_UP ivec3(0, 0, 1) #define F_DOWN ivec3(0, 0, -1) #define F_FRONT ivec3(0, -1, 0) #define F_BACK ivec3(0, 1, 0) static ivec3 GetFaceFromFaceIndex(int i) { if (i == FI_LEFT) return F_LEFT; if (i == FI_RIGHT) return F_RIGHT; if (i == FI_UP) return F_UP; if (i == FI_DOWN) return F_DOWN; if (i == FI_FRONT) return F_FRONT; if (i == FI_BACK) return F_BACK; VAssert(0); return F_LEFT; } static int GetFaceIndexFromFace(const ivec3 face) { if (face == F_LEFT) return FI_LEFT; if (face == F_RIGHT) return FI_RIGHT; if (face == F_UP) return FI_UP; if (face == F_DOWN) return FI_DOWN; if (face == F_FRONT) return FI_FRONT; if (face == F_BACK) return FI_BACK; VAssert(0); return 0; } static void GetFaceCoordinateIndices(const ivec3 &cell, const ivec3 &face, ivec3 &i0, ivec3 &i1, ivec3 &i2, ivec3 &i3) { // CCW if (face == F_DOWN) { i0 = cell + ivec3(0, 0, 0); i1 = cell + ivec3(0, 1, 0); i2 = cell + ivec3(1, 1, 0); i3 = cell + ivec3(1, 0, 0); } else if (face == F_UP) { i0 = cell + ivec3(0, 0, 1); i1 = cell + ivec3(1, 0, 1); i2 = cell + ivec3(1, 1, 1); i3 = cell + ivec3(0, 1, 1); } else if (face == F_LEFT) { i0 = cell + ivec3(0, 0, 0); i1 = cell + ivec3(0, 0, 1); i2 = cell + ivec3(0, 1, 1); i3 = cell + ivec3(0, 1, 0); } else if (face == F_RIGHT) { i0 = cell + ivec3(1, 0, 0); i1 = cell + ivec3(1, 1, 0); i2 = cell + ivec3(1, 1, 1); i3 = cell + ivec3(1, 0, 1); } else if (face == F_FRONT) { i0 = cell + ivec3(0, 0, 0); i1 = cell + ivec3(1, 0, 0); i2 = cell + ivec3(1, 0, 1); i3 = cell + ivec3(0, 0, 1); } else if (face == F_BACK) { i0 = cell + ivec3(0, 1, 0); i1 = cell + ivec3(0, 1, 1); i2 = cell + ivec3(1, 1, 1); i3 = cell + ivec3(1, 1, 0); } } static vec3 GetCoordAtIndex(const ivec3 &index, const vec3 *data, const ivec3 &dims) { const int w = dims.x; const int h = dims.y; const int d = dims.z; const int x = index.x; const int y = index.y; const int z = index.z; VAssert(x >= 0 && x < w && y >= 0 && y < h && z >= 0 && z < d); return data[(z * w * h + y * w + x)]; } static void GetFaceVertices(const ivec3 &cellIndex, const ivec3 &face, const vec3 *data, const ivec3 &dims, vec3 &v0, vec3 &v1, vec3 &v2, vec3 &v3) { ivec3 i0, i1, i2, i3; GetFaceCoordinateIndices(cellIndex, face, i0, i1, i2, i3); v0 = GetCoordAtIndex(i0, data, dims); v1 = GetCoordAtIndex(i1, data, dims); v2 = GetCoordAtIndex(i2, data, dims); v3 = GetCoordAtIndex(i3, data, dims); } static void GetFaceVertices(const ivec3 &cellIndex, int face, const vec3 *data, const ivec3 &dims, vec3 &v0, vec3 &v1, vec3 &v2, vec3 &v3) { GetFaceVertices(cellIndex, GetFaceFromFaceIndex(face), data, dims, v0, v1, v2, v3); } VolumeTest2::VolumeTest2(GLManager *gl) : VolumeRegular(gl) { glGenTextures(1, &zCoordTexture); glBindTexture(GL_TEXTURE_3D, zCoordTexture); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glGenTextures(1, &xyCoordTexture); glBindTexture(GL_TEXTURE_2D, xyCoordTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } VolumeTest2::~VolumeTest2() { if (zCoordTexture) glDeleteTextures(1, &zCoordTexture); if (xyCoordTexture) glDeleteTextures(1, &xyCoordTexture); } #define EPSILON 1.19e-07 static bool IsInsideCell(const vec3 &p, const ivec3 &cellIndex, const vec3 *coords, const ivec3 dims) { for (int face = 0; face < 6; face++) { vec3 v0, v1, v2, v3; GetFaceVertices(cellIndex, face, coords, dims, v0, v1, v2, v3); vec3 n = cross(v1 - v0, v2 - v0); if (glm::length(n) < EPSILON) { if (glm::dot(n, p - v0) > 0) return false; } } return true; } int VolumeTest2::LoadData(const Grid *grid) { if (VolumeRegular::LoadData(grid) < 0) return -1; vector dims = grid->GetDimensions(); const int w = dims[0], h = dims[1], d = dims[2]; const size_t nCoords = (size_t)w * h * d; vector minExt, maxExt; grid->GetUserExtents(minExt, maxExt); const float minX = minExt[0]; const float minY = minExt[1]; const float minZ = minExt[2]; const float maxX = maxExt[0]; const float maxY = maxExt[1]; const float maxZ = maxExt[2]; // float *xy = new float[dims[0]*dims[1]]; float *data = new float[w * h * d * 3]; for (int i = 0; i < w * h * d * 3; i++) data[i] = -1; vec3 *coords = new vec3[nCoords]; auto coord = grid->ConstCoordBegin(); for (size_t i = 0; i < nCoords; ++i, ++coord) { coords[i][0] = (*coord)[0]; coords[i][1] = (*coord)[1]; coords[i][2] = (*coord)[2]; } for (int z = 0; z < d; z++) { for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) {} } } glBindTexture(GL_TEXTURE_3D, zCoordTexture); glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F, dims[0], dims[1], dims[2], 0, GL_RGB, GL_FLOAT, data); delete[] data; return 0; } ShaderProgram *VolumeTest2::GetShader() const { ShaderProgram *s = _glManager->shaderManager->GetShader("ray2"); if (!s) return nullptr; s->Bind(); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_3D, zCoordTexture); s->SetUniform("coordLUT", 2); return s; } ================================================ FILE: lib/render/WireFrameRenderer.cpp ================================================ //************************************************************************ // * // Copyright (C) 2018 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: WireFrameRenderer.cpp // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: June 2018 // // Description: // Implementation of WireFrameRenderer // #include #include #include #include // Must be included first!!! #include #include #include #include #include #include #include #include #include "vapor/GLManager.h" #include "vapor/debug.h" #include using namespace VAPoR; #pragma pack(push, 4) struct WireFrameRenderer::VertexData { float x, y, z; float v; float missing; }; #pragma pack(pop) static RendererRegistrar registrar(WireFrameRenderer::GetClassType(), WireFrameParams::GetClassType()); WireFrameRenderer::WireFrameRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr) : Renderer(pm, winName, dataSetName, WireFrameParams::GetClassType(), WireFrameRenderer::GetClassType(), instName, dataMgr), _VAO(0), _VBO(0), _EBO(0) { } WireFrameRenderer::~WireFrameRenderer() { if (_VAO) glDeleteVertexArrays(1, &_VAO); if (_VBO) glDeleteBuffers(1, &_VBO); if (_EBO) glDeleteBuffers(1, &_EBO); _VAO = _VBO = _EBO = 0; } void WireFrameRenderer::_saveCacheParams() { WireFrameParams *p = (WireFrameParams *)GetActiveParams(); _cacheParams.varName = p->GetVariableName(); _cacheParams.heightVarName = p->GetHeightVariableName(); _cacheParams.ts = p->GetCurrentTimestep(); _cacheParams.level = p->GetRefinementLevel(); _cacheParams.lod = p->GetCompressionLevel(); p->GetBox()->GetExtents(_cacheParams.boxMin, _cacheParams.boxMax); } bool WireFrameRenderer::_isCacheDirty() const { WireFrameParams *p = (WireFrameParams *)GetActiveParams(); if (_cacheParams.varName != p->GetVariableName()) return true; if (_cacheParams.heightVarName != p->GetHeightVariableName()) return true; if (_cacheParams.ts != p->GetCurrentTimestep()) return true; if (_cacheParams.level != p->GetRefinementLevel()) return true; if (_cacheParams.lod != p->GetCompressionLevel()) return true; vector min, max; p->GetBox()->GetExtents(min, max); if (_cacheParams.boxMin != min) return true; if (_cacheParams.boxMax != max) return true; return false; } // // Generate wireframe line drawing list of line segments for a single // cell. Make use of drawList to avoid drawing line segments shared // by multiple cells // void WireFrameRenderer::_drawCell(const GLuint *cellNodeIndices, int n, bool layered, const vector &nodeMap, GLuint invalidIndex, vector &indices, DrawList &drawList) const { int count = layered ? n / 2 : n; for (int i = 0; i < count; i++) { GLuint idx0 = nodeMap[cellNodeIndices[i]]; VAssert(idx0 != invalidIndex); GLuint idx1 = nodeMap[cellNodeIndices[(i + 1) % count]]; VAssert(idx1 != invalidIndex); // Don't draw line segment if it's already been drawn // if (drawList.InList(idx0, idx1)) continue; indices.push_back(idx0); indices.push_back(idx1); } if (!layered) return; // if layered the coordinates are ordered bottom face first, then top face // for (int i = 0; i < count; i++) { GLuint idx0 = nodeMap[cellNodeIndices[i + count]]; VAssert(idx0 != invalidIndex); GLuint idx1 = nodeMap[cellNodeIndices[((i + 1) % count) + count]]; VAssert(idx1 != invalidIndex); if (drawList.InList(idx0, idx1)) continue; indices.push_back(idx0); indices.push_back(idx1); } // Now draw edges between top and bottom face // for (int i = 0; i < count; i++) { GLuint idx0 = nodeMap[cellNodeIndices[i]]; VAssert(idx0 != invalidIndex); GLuint idx1 = nodeMap[cellNodeIndices[i + count]]; VAssert(idx1 != invalidIndex); if (drawList.InList(idx0, idx1)) continue; indices.push_back(idx0); indices.push_back(idx1); } } // Generate list of vertices shared by all line segments, and populate // 'nodeMap': a map from a node's Grid index to its offset in the // list of vertices. // void WireFrameRenderer::_buildCacheVertices(const Grid *grid, const Grid *heightGrid, vector &nodeMap, bool *GPUOutOfMemory) const { double mv = grid->GetMissingValue(); auto tmp = grid->GetDimensions(); auto dims = std::vector{tmp[0], tmp[1], tmp[2]}; size_t numNodes = Wasp::VProduct(dims); // Pre-allocate vertices vector upfront for better performance // vector vertices; vertices.reserve(numNodes); // Visit each grid node. For each node store node's coordinates and // assigned color in 'vertices'. Create 'nodeMap': mapping from a // grid node's index to its offset in 'vertices' // Grid::ConstNodeIterator nodeItr = grid->ConstNodeBegin(); Grid::ConstNodeIterator nodeEnd = grid->ConstNodeEnd(); Grid::ConstCoordItr coordItr = grid->ConstCoordBegin(); Grid::ConstCoordItr coordEnd = grid->ConstCoordEnd(); Progress::Start("Load Grid", numNodes); long done = 0; for (; nodeItr != nodeEnd; ++nodeItr, ++coordItr, ++done) { Progress::Update(done); // Get current node's coordinates // double coord[3]; coord[0] = (*coordItr)[0]; coord[1] = (*coordItr)[1]; if (grid->GetGeometryDim() > 2) { coord[2] = (*coordItr)[2]; } else { double z; if (heightGrid) { z = heightGrid->GetValueAtIndex(*nodeItr); } else { z = 0; } coord[2] = z; } float dataValue = grid->GetValueAtIndex(*nodeItr); // Create an entry in nodeMap // size_t index = Wasp::LinearizeCoords((*nodeItr).data(), dims.data(), dims.size()); if (vertices.size() > std::numeric_limits::max()) { #ifndef NDEBUG MyBase::SetDiagMsg("WireFrameRenderer() : exceeded numeric limits"); #endif continue; } nodeMap[index] = vertices.size(); vertices.push_back({(float)coord[0], (float)coord[1], (float)coord[2], dataValue, mv == dataValue ? 1.f : 0.f}); } glBindVertexArray(_VAO); glBindBuffer(GL_ARRAY_BUFFER, _VBO); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_DYNAMIC_DRAW); GLenum err; while ((err = glGetError()) != GL_NO_ERROR) if (err == GL_OUT_OF_MEMORY) *GPUOutOfMemory = true; } // // Generate connectivity list for line segments joining cell nodes. // size_t WireFrameRenderer::_buildCacheConnectivity(const Grid *grid, const vector &nodeMap, bool *GPUOutOfMemory) const { auto tmp = grid->GetDimensions(); auto dims = std::vector{tmp[0], tmp[1], tmp[2]}; size_t invalidIndex = std::numeric_limits::max(); size_t numNodes = Wasp::VProduct(dims); bool layered = grid->GetTopologyDim() == 3; size_t maxVertsPerCell = grid->GetMaxVertexPerCell(); vector cellNodeIndices(maxVertsPerCell); vector cellNodeIndicesLinear(maxVertsPerCell); size_t numCells = Wasp::VProduct(grid->GetCellDimensions().data(), grid->GetNumCellDimensions()); size_t maxLineIndices = numCells * (layered ? maxVertsPerCell / 2 * 3 : maxVertsPerCell * 2); // Pre-allocate memory for (much) better performance. // vector indices; indices.reserve(maxLineIndices); { // drawList keeps track of line segments that have already been // drawn so that we can avoid duplicates. Avoiding duplicates // reduces the memory requirements substantially // DrawList drawList(numNodes, 10); // Loop over cells, drawing edges of each cell // Grid::ConstCellIterator cellItr = grid->ConstCellBegin(); Grid::ConstCellIterator cellEnd = grid->ConstCellEnd(); Progress::Start("Generate Connectivity", numCells, true); for (int done = 0; cellItr != cellEnd; ++cellItr, ++done) { Progress::Update(done); if (Progress::Cancelled()) return 0; grid->GetCellNodes((*cellItr).data(), cellNodeIndices); for (int i = 0; i < cellNodeIndices.size(); i++) { int ndim = grid->GetDimensions().size(); size_t idx = Wasp::LinearizeCoords(cellNodeIndices[i].data(), grid->GetDimensions().data(), ndim); if (idx > std::numeric_limits::max()) { #ifndef NDEBUG MyBase::SetDiagMsg("WireFrameRenderer() : exceeded numeric limits"); #endif continue; } cellNodeIndicesLinear[i] = idx; } _drawCell(cellNodeIndicesLinear.data(), cellNodeIndices.size(), layered, nodeMap, invalidIndex, indices, drawList); } } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_DYNAMIC_DRAW); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); GLenum err; while ((err = glGetError()) != GL_NO_ERROR) { if (err == GL_OUT_OF_MEMORY) *GPUOutOfMemory = true; } return (indices.size()); } int WireFrameRenderer::_buildCache() { WireFrameParams *rParams = (WireFrameParams *)GetActiveParams(); _saveCacheParams(); if (rParams->GetVariableName().empty()) { return 0; } CoordType boxMin = {0.0, 0.0, 0.0}; CoordType boxMax = {0.0, 0.0, 0.0}; Grid::CopyToArr3(_cacheParams.boxMin, boxMin); Grid::CopyToArr3(_cacheParams.boxMax, boxMax); Grid *grid = _dataMgr->GetVariable(_cacheParams.ts, _cacheParams.varName, _cacheParams.level, _cacheParams.lod, boxMin, boxMax); if (!grid) return (-1); Grid *heightGrid = NULL; if (!_cacheParams.heightVarName.empty()) { heightGrid = _dataMgr->GetVariable(_cacheParams.ts, _cacheParams.heightVarName, _cacheParams.level, _cacheParams.lod, boxMin, boxMax); if (!heightGrid) { delete grid; return (-1); } } auto tmp = grid->GetDimensions(); auto dims = std::vector{tmp[0], tmp[1], tmp[2]}; size_t numNodes = Wasp::VProduct(dims); GLuint invalidIndex = std::numeric_limits::max(); vector nodeMap(numNodes, invalidIndex); _GPUOutOfMemory = false; _buildCacheVertices(grid, heightGrid, nodeMap, &_GPUOutOfMemory); _nIndices = _buildCacheConnectivity(grid, nodeMap, &_GPUOutOfMemory); if (grid) delete grid; if (heightGrid) delete heightGrid; Progress::Finish(); return 0; } int WireFrameRenderer::_paintGL(bool fast) { int rc = 0; if (_isCacheDirty()) { rc = _buildCache(); } if (rc != 0) return rc; if (Progress::Cancelled()) { _cacheParams.varName = ""; return 0; } if (_GPUOutOfMemory) { SetErrMsg("GPU out of memory"); return -1; } RenderParams * rp = GetActiveParams(); MapperFunction *tf = rp->GetMapperFunc(rp->GetVariableName()); if (!tf) return -1; float lut[4 * 256]; tf->makeLut(lut); if (rp->UseSingleColor()) { float c[3]; rp->GetConstantColor(c); for (int i = 0; i < 256; i++) { lut[i * 4 + 0] = c[0]; lut[i * 4 + 1] = c[1]; lut[i * 4 + 2] = c[2]; } } _lutTexture.TexImage(GL_RGBA8, 256, 0, 0, GL_RGBA, GL_FLOAT, lut); if (rp->GetRenderDim() == 2) { float zOffset = GetDefaultZ(_dataMgr, GetActiveParams()->GetCurrentTimestep()); _glManager->matrixManager->Translate(0, 0, zOffset); } SmartShaderProgram shader = _glManager->shaderManager->GetSmartShader("Wireframe"); if (!shader.IsValid()) return -1; EnableClipToBox(_glManager->shaderManager->GetShader("Wireframe")); shader->SetUniform("MVP", _glManager->matrixManager->GetModelViewProjectionMatrix()); shader->SetUniform("minLUTValue", tf->getMinMapValue()); shader->SetUniform("maxLUTValue", tf->getMaxMapValue()); shader->SetSampler("colormap", _lutTexture); glBindVertexArray(_VAO); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _EBO); glDrawElements(GL_LINES, _nIndices, GL_UNSIGNED_INT, 0); DisableClippingPlanes(); glBindVertexArray(0); return rc; } int WireFrameRenderer::_initializeGL() { glGenVertexArrays(1, &_VAO); glBindVertexArray(_VAO); glGenBuffers(1, &_VBO); glGenBuffers(1, &_EBO); glBindBuffer(GL_ARRAY_BUFFER, _VBO); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), NULL); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void *)offsetof(struct VertexData, v)); glEnableVertexAttribArray(1); glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void *)offsetof(struct VertexData, missing)); glEnableVertexAttribArray(2); glBindVertexArray(0); _lutTexture.Generate(); return 0; } ================================================ FILE: lib/render/glutil.cpp ================================================ //************************************************************************ // * // Copyright (C) 2004 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: glutil.cpp // // Adaptor: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: July 2004 // // Description: Methods to facilitate use of trackball navigation, // adapted from Ken Purcell's code to work in QT window // // Copyright (C) 1992 AHPCRC, Univeristy of Minnesota // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program in a file named 'Copying'; if not, write to // the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139. // // Original Author: // Ken Chin-Purcell (ken@ahpcrc.umn.edu) // Army High Performance Computing Research Center (AHPCRC) // Univeristy of Minnesota // #include "vapor/VAssert.h" #include #include #include #include #include #include #include #include #include #include #define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH #include /* Most of the 'v' routines are in the form vsomething(src1, src2, dst), * dst can be one of the source vectors. */ namespace VAPoR { bool oglStatusOK(vector &status) { GLenum glErr; while ((glErr = glGetError()) != GL_NO_ERROR) { status.push_back((int)glErr); } if (status.size()) return (false); return (true); } static const char *_glErrorStr(int err) { switch (err) { #define ERR_TO_STR(E) case E: return #E ERR_TO_STR(GL_NO_ERROR); ERR_TO_STR(GL_INVALID_ENUM); ERR_TO_STR(GL_INVALID_VALUE); ERR_TO_STR(GL_INVALID_OPERATION); ERR_TO_STR(GL_INVALID_FRAMEBUFFER_OPERATION); ERR_TO_STR(GL_OUT_OF_MEMORY); // ERR_TO_STR(GL_STACK_UNDERFLOW); // ERR_TO_STR(GL_STACK_OVERFLOW); default: return "GL_UNKNOWN_ERROR"; } } string oglGetErrMsg(vector status) { string msg; for (auto e : status) { msg += "OpenGL Error: "; msg += _glErrorStr(e); msg += " (#" + std::to_string(e) + ")\n"; } return msg; } int oglGetFreeMemory() { #define TEXTURE_FREE_MEMORY_ATI 0x87FC #define GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049 GLint buf[4]; vector _; #if AMD_MEM_QUERY_ENABLED // On some systems returns incorrect values memset(buf, 0, sizeof(buf)); glGetIntegerv(TEXTURE_FREE_MEMORY_ATI, buf); if (buf[0] > 0) return buf[0]; oglStatusOK(_); #endif memset(buf, 0, sizeof(buf)); glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, buf); if (buf[0] > 0) return buf[0]; oglStatusOK(_); return -1; } int __CheckGLError(const char *file, int line, const char *msg) { // // Returns -1 if an OpenGL error occurred, 0 otherwise. // GLenum glErr; int retCode = 0; glErr = glGetError(); while (glErr != GL_NO_ERROR) { #ifndef NDEBUG #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" // std::cout << "glError: " << gluErrorString(glErr) << std::endl << " " << file << " : " << line << std::endl; #pragma GCC diagnostic pop #endif if (msg) { Wasp::MyBase::SetErrMsg("glError: %s\n", msg); msg = NULL; } Wasp::MyBase::SetErrMsg("glError: %i\n\t%s : %d", glErr, file, line); retCode = -1; glErr = glGetError(); } return retCode; } bool FrameBufferReady() { GLuint fbstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (fbstatus != GL_FRAMEBUFFER_COMPLETE) { return (false); } // Not sure if this is necessary // vector errcodes; bool status = oglStatusOK(errcodes); if (status) return true; // If error, check for invalid frame buffer // for (int i = 0; i < errcodes.size(); i++) { if (errcodes[i] == GL_INVALID_FRAMEBUFFER_OPERATION) return false; } return (true); } }; // namespace VAPoR ================================================ FILE: lib/render/jfilewrite.cpp ================================================ /* * example.c * * This file illustrates how to use the IJG code as a subroutine library * to read or write JPEG image files. You should look at this code in * conjunction with the documentation file libjpeg.doc. * * This code will not do anything useful as-is, but it may be helpful as a * skeleton for constructing routines that call the JPEG library. * * We present these routines in the same coding style used in the JPEG code * (ANSI function definitions, etc); but you are of course free to code your * routines in a different style if you prefer. */ #include #include #include /* * Include file for users of JPEG library. * You will need to have included system headers that define at least * the typedefs FILE and size_t before you can include jpeglib.h. * (stdio.h is sufficient on ANSI-conforming systems.) * You may also wish to include "jerror.h". */ #ifdef WIN32 #include #else #include #endif #include /* * is used for the optional error recovery mechanism shown in * the second part of the example. */ #include #ifdef WIN32 #pragma warning(disable : 4996) #endif /******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/ /* This half of the example shows how to feed data into the JPEG compressor. * We present a minimal version that does not worry about refinements such * as error recovery (the JPEG code will just exit() if it gets an error). */ /* * IMAGE DATA FORMATS: * * The standard input image format is a rectangular array of pixels, with * each pixel having the same number of "component" values (color channels). * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars). * If you are working with color data, then the color values for each pixel * must be adjacent in the row; for example, R,G,B,R,G,B,R,G,B,... for 24-bit * RGB color. * * For this example, we'll assume that this data structure matches the way * our application has stored the image in memory, so we can just pass a * pointer to our image buffer. In particular, let's say that the image is * RGB color and is described by: */ /* * ERROR HANDLING: * * The JPEG library's standard error handler (jerror.c) is divided into * several "methods" which you can override individually. This lets you * adjust the behavior without duplicating a lot of code, which you might * have to update with each future release. * * Our example here shows how to override the "error_exit" method so that * control is returned to the library's caller when a fatal error occurs, * rather than calling exit() as the standard error_exit method does. * * We use C's setjmp/longjmp facility to return control. This means that the * routine which calls the JPEG library must first execute a setjmp() call to * establish the return point. We want the replacement error_exit to do a * longjmp(). But we need to make the setjmp buffer accessible to the * error_exit routine. To do this, we make a private extension of the * standard JPEG error handler object. (If we were using C++, we'd say we * were making a subclass of the regular error handler.) * * Here's the extended error handler struct: */ struct my_error_mgr { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf setjmp_buffer; /* for return to caller */ }; typedef struct my_error_mgr *my_error_ptr; /* * Here's the routine that will replace the standard error_exit method: */ namespace { METHODDEF(void) my_error_exit(j_common_ptr cinfo) { /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ my_error_ptr myerr = (my_error_ptr)cinfo->err; /* Always display the message. */ /* We could postpone this until after returning, if we chose. */ (*cinfo->err->output_message)(cinfo); /* Return control to the setjmp point */ longjmp(myerr->setjmp_buffer, 1); } /* method to resample rgb image to smaller image, needed to handle OpenGL power-of-two limitations. */ void resampleImage(unsigned char *image1, int xin, int yin, unsigned char *image2, int xout, int yout) { /*Simplest approach: Just sample one pixel for each:*/ int i, j, k; for (j = 0; j < yout; j++) { float ycrd = (float)j / (float)(yout - 1); // Normalize to 0..1 int ysample = (int)(ycrd * (float)(yin - 1) + 0.5f); for (i = 0; i < xout; i++) { float xcrd = (float)i / (float)(xout - 1); // Normalize to 0..1 int xsample = (int)(xcrd * (float)(xin - 1) + 0.5f); for (k = 0; k < 3; k++) { image2[k + 3 * (i + xout * j)] = image1[k + 3 * (xsample + ysample * xin)]; } } } } /* * Sample routine for JPEG compression. We assume that the target file * and a compression quality factor are passed in. * Returns 0 if OK, 1 for file I/O errors, 2 for other errors */ }; // namespace int VAPoR::write_JPEG_file(FILE *outfile, int image_width, int image_height, unsigned char *image_buffer, int quality) { /* This struct contains the JPEG compression parameters and pointers to * working space (which is allocated as needed by the JPEG library). * It is possible to have several such structures, representing multiple * compression/decompression processes, in existence at once. We refer * to any one struct (and its associated working data) as a "JPEG object". */ struct jpeg_compress_struct cinfo; /* This struct represents a JPEG error handler. It is declared separately * because applications often want to supply a specialized error handler * (see the second half of this file for an example). But here we just * take the easy way out and use the standard error handler, which will * print a message on stderr and call exit() if compression fails. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ // struct jpeg_error_mgr jerr; struct my_error_mgr jerr; /* More stuff */ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ int row_stride; /* physical row width in image buffer */ /* Step 1: allocate and initialize JPEG compression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ // cinfo.err = jpeg_std_error(&jerr); /* We set up the normal JPEG error routines, then override error_exit. */ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ jpeg_destroy_compress(&cinfo); /* * !!WRONG!! You should NOT close a file that does not belong to you!! */ // fclose(outfile); return 1; } /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ /* Here we use the library-supplied code to send compressed data to a * stdio stream. You can also write your own code to do something else. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to write binary files. */ jpeg_stdio_dest(&cinfo, outfile); /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ cinfo.image_width = image_width; /* image width and height, in pixels */ cinfo.image_height = image_height; cinfo.input_components = 3; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ /* Now use the library's routine to set default compression parameters. * (You must set at least cinfo.in_color_space before calling this, * since the defaults depend on the source color space.) */ jpeg_set_defaults(&cinfo); /* Now you can set any non-default parameters you wish to. * Here we just illustrate the use of quality (quantization table) scaling: */ jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ jpeg_start_compress(&cinfo, TRUE); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ while (cinfo.next_scanline < cinfo.image_height) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride]; (void)jpeg_write_scanlines(&cinfo, row_pointer, 1); } /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); /* After finish_compress, we can close the output file. */ /* * !!WRONG!! You should NOT close a file that does not belong to you!! */ // fclose(outfile); /* Step 7: release JPEG compression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress(&cinfo); /* And we're done! */ return 0; } /* * SOME FINE POINTS: * * In the above loop, we ignored the return value of jpeg_write_scanlines, * which is the number of scanlines actually written. We could get away * with this because we were only relying on the value of cinfo.next_scanline, * which will be incremented correctly. If you maintain additional loop * variables then you should be careful to increment them properly. * Actually, for output to a stdio stream you needn't worry, because * then jpeg_write_scanlines will write all the lines passed (or else exit * with a fatal error). Partial writes can only occur if you use a data * destination module that can demand suspension of the compressor. * (If you don't know what that's for, you don't need it.) * * If the compressor requires full-image buffers (for entropy-coding * optimization or a multi-scan JPEG file), it will create temporary * files for anything that doesn't fit within the maximum-memory setting. * (Note that temp files are NOT needed if you use the default parameters.) * On some systems you may need to set up a signal handler to ensure that * temporary files are deleted if the program is interrupted. See libjpeg.doc. * * Scanlines MUST be supplied in top-to-bottom order if you want your JPEG * files to be compatible with everyone else's. If you cannot readily read * your data in that order, you'll need an intermediate array to hold the * image. See rdtarga.c or rdbmp.c for examples of handling bottom-to-top * source data using the JPEG code's internal virtual-array mechanisms. */ /******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/ /* This half of the example shows how to read data from the JPEG decompressor. * It's a bit more refined than the above, in that we show: * (a) how to modify the JPEG library's standard error-reporting behavior; * (b) how to allocate workspace using the library's memory manager. * * Just to make this example a little different from the first one, we'll * assume that we do not intend to put the whole image into an in-memory * buffer, but to send it line-by-line someplace else. We need a one- * scanline-high JSAMPLE array as a work buffer, and we will let the JPEG * memory manager allocate it for us. This approach is actually quite useful * because we don't need to remember to deallocate the buffer separately: it * will go away automatically when the JPEG object is cleaned up. */ // JPEG_GLOBAL(void) free_image (unsigned char* image){ // free(image); //} /* * Sample routine for JPEG decompression. We assume that the source file name * is passed in. We want to return 1 on success, 0 on error. */ int VAPoR::read_JPEG_file(const char *filename, unsigned char **imageBuffer, int *width, int *height) { /* This struct contains the JPEG decompression parameters and pointers to * working space (which is allocated as needed by the JPEG library). */ struct jpeg_decompress_struct cinfo; /* We use our private extension JPEG error handler. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ struct my_error_mgr jerr; /* More stuff */ FILE * infile; /* source file */ JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ int newXDim, newYDim; /* dimensions for resampling*/ int k, testval; unsigned char *firstImage; /* In this example we want to open the input file before doing anything else, * so that the setjmp() error recovery below can assume the file is open. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to read binary files. */ if ((infile = fopen(filename, "rb")) == NULL) { fprintf(stderr, "can't open %s\n", filename); return 0; } /* Step 1: allocate and initialize JPEG decompression object */ /* We set up the normal JPEG error routines, then override error_exit. */ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ jpeg_destroy_decompress(&cinfo); fclose(infile); return 0; } /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&cinfo); /* Step 2: specify data source (eg, a file) */ jpeg_stdio_src(&cinfo, infile); /* Step 3: read file parameters with jpeg_read_header() */ (void)jpeg_read_header(&cinfo, TRUE); /* We can ignore the return value from jpeg_read_header since * (a) suspension is not possible with the stdio data source, and * (b) we passed TRUE to reject a tables-only JPEG file as an error. * See libjpeg.doc for more info. */ /* Step 4: set parameters for decompression */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ (void)jpeg_start_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* We may need to do some setup of our own at this point before reading * the data. After jpeg_start_decompress() we have the correct scaled * output image dimensions available, as well as the output colormap * if we asked for color quantization. * In this example, we need to make an output work buffer of the right size. */ /* JSAMPLEs per row in output buffer */ row_stride = cinfo.output_width * cinfo.output_components; /* Make a one-row-high sample array that will go away when done with image */ buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1); firstImage = (unsigned char *)malloc((size_t)(row_stride * cinfo.output_height)); /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. */ while (cinfo.output_scanline < cinfo.output_height) { /* jpeg_read_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could ask for * more than one scanline at a time if that's more convenient. */ (void)jpeg_read_scanlines(&cinfo, buffer, 1); /* Assume put_scanline_someplace wants a pointer and sample count. */ /* actually put the scanline in the image in reverse order, so that openGL will scan it in the correct order*/ memcpy((void *)(firstImage + (cinfo.output_height - cinfo.output_scanline) * (cinfo.output_width) * 3), buffer[0], (size_t)cinfo.output_width * 3); // put_scanline_someplace(buffer[0], row_stride); } // Find first power of two no greater than image dimensions: newXDim = cinfo.output_width; newYDim = cinfo.output_height; for (k = 0; k < 30; k++) { testval = newXDim >> k; if (testval == 0) { newXDim = (newXDim >> (k - 1)) << (k - 1); break; } } for (k = 0; k < 30; k++) { testval = newYDim >> k; if (testval == 0) { newYDim = (newYDim >> (k - 1)) << (k - 1); break; } } *width = newXDim; *height = newYDim; if (newXDim == cinfo.output_width && newYDim == cinfo.output_height) { *imageBuffer = firstImage; } else { *imageBuffer = (unsigned char *)malloc((size_t)(3 * newXDim * newYDim)); resampleImage(firstImage, cinfo.output_width, cinfo.output_height, *imageBuffer, newXDim, newYDim); free(firstImage); } /* Step 7: Finish decompression */ (void)jpeg_finish_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress(&cinfo); /* After finish_decompress, we can close the input file. * Here we postpone it until after no more JPEG errors are possible, * so as to simplify the setjmp error logic above. (Actually, I don't * think that jpeg_destroy can do an error exit, but why assume anything...) */ fclose(infile); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ /* And we're done! */ return 1; } /* * SOME FINE POINTS: * * In the above code, we ignored the return value of jpeg_read_scanlines, * which is the number of scanlines actually read. We could get away with * this because we asked for only one line at a time and we weren't using * a suspending data source. See libjpeg.doc for more info. * * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress(); * we should have done it beforehand to ensure that the space would be * counted against the JPEG max_memory setting. In some systems the above * code would risk an out-of-memory error. However, in general we don't * know the output image dimensions before jpeg_start_decompress(), unless we * call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this. * * Scanlines are returned in the same order as they appear in the JPEG file, * which is standardly top-to-bottom. If you must emit data bottom-to-top, * you can use one of the virtual arrays provided by the JPEG memory manager * to invert the data. See wrbmp.c for an example. * * As with compression, some operating modes may require temporary files. * On some systems you may need to set up a signal handler to ensure that * temporary files are deleted if the program is interrupted. See libjpeg.doc. */ ================================================ FILE: lib/vapi/CMakeLists.txt ================================================ if (NOT PROJECT_NAME) cmake_minimum_required (VERSION 3.10) project (VAPI) set (CMAKE_CXX_STANDARD 11) endif () file (GLOB HDRS ./*.h) file (GLOB SRCS ./*.cpp) if (APPLE) file (GLOB OBJC_SRCS ./*.mm) list (APPEND SRCS ${OBJC_SRCS}) endif () list(FILTER SRCS EXCLUDE REGEX ".*main\\.cpp$") add_library (vapi SHARED ${SRCS} ${HDRS}) target_link_libraries ( vapi render osgl ) if (APPLE) find_library (APPKIT AppKit) target_link_libraries (vapi ${APPKIT}) endif () # if (UNIX AND NOT APPLE) # target_link_libraries (vapi OSMesa EGL) # endif () file (GLOB GLContextLibFiles ./GLContext*.cpp ./GLContext*.h ./GLContext*.mm) source_group (GLContextLib FILES ${GLContextLibFiles}) # add_executable (vapitest main.cpp) # target_link_libraries (vapitest vapi ${Python_LIBRARIES}) file ( COPY ${HDRS} DESTINATION ${CMAKE_BINARY_DIR}/include/vapor ) target_include_directories (vapi PUBLIC ${CMAKE_BINARY_DIR}/include) install ( TARGETS vapi DESTINATION ${INSTALL_LIB_DIR} COMPONENT Libraries ) install ( FILES ${HDRS} DESTINATION ${INSTALL_INCLUDE_DIR} COMPONENT Libraries ) ================================================ FILE: lib/vapi/RenderManager.cpp ================================================ #include "RenderManager.h" #include #include #include #include #include #include #include #include #include #define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH #include using namespace VAPoR; GLContext *RenderManager::_glContext = nullptr; RenderManager::RenderManager(ControlExec *ce, bool useOSGLContext) : _controlExec(ce), _useOSGLContext(useOSGLContext) {} RenderManager::~RenderManager() { if (_glManager) delete _glManager; } void RenderManager::getNearFarDist(const double posVec[3], const double dirVec[3], double &boxNear, double &boxFar) { String _winName = GetWinName(); // First check full box double wrk[3], cor[3], boxcor[3]; double camPosBox[3], dvdir[3]; #ifdef WIN32 double maxProj = -DBL_MAX; double minProj = DBL_MAX; #else double maxProj = -std::numeric_limits::max(); double minProj = std::numeric_limits::max(); #endif DataStatus *dataStatus = _controlExec->GetDataStatus(); ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); AnimationParams *ap = ((AnimationParams *)paramsMgr->GetParams(AnimationParams::GetClassType())); size_t ts = ap->GetCurrentTimestep(); CoordType minExts, maxExts; dataStatus->GetActiveExtents(paramsMgr, _winName, ts, minExts, maxExts); for (int i = 0; i < 3; i++) camPosBox[i] = posVec[i]; for (int i = 0; i < 3; i++) dvdir[i] = dirVec[i]; vnormal(dvdir); // For each box corner, // convert to box coords, then project to line of view for (int i = 0; i < 8; i++) { for (int j = 0; j < 3; j++) { cor[j] = ((i >> j) & 1) ? maxExts[j] : minExts[j]; } for (int k = 0; k < 3; k++) boxcor[k] = cor[k]; vsub(boxcor, camPosBox, wrk); float mdist = abs(vdot(wrk, dvdir)); if (minProj > mdist) { minProj = mdist; } if (maxProj < mdist) { maxProj = mdist; } } if (maxProj < 1.e-10) maxProj = 1.e-10; if (minProj > 0.03 * maxProj) minProj = 0.03 * maxProj; // minProj will be < 0 if either the camera is in the box, or // if some of the region is behind the camera plane. In that case, just // set the nearDist a reasonable multiple of the fardist // if (minProj <= 0.0) minProj = 0.0002 * maxProj; boxFar = (float)maxProj; boxNear = (float)minProj; return; } void RenderManager::setUpProjMatrix() { assert(not _controlExec->GetVisualizerNames().empty()); ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); ViewpointParams *vParams = paramsMgr->GetViewpointParams(GetWinName()); MatrixManager * mm = _glManager->matrixManager; double m[16]; vParams->GetModelViewMatrix(m); double posvec[3], upvec[3], dirvec[3]; bool status = vParams->ReconstructCamera(m, posvec, upvec, dirvec); if (!status) { LogFatal("Failed to get camera parameters"); return; } double nearDist, farDist; getNearFarDist(posvec, dirvec, nearDist, farDist); nearDist *= 0.25; farDist *= 4.0; size_t width, height; vParams->GetWindowSize(width, height); // width *= QApplication::desktop()->devicePixelRatio(); // height *= QApplication::desktop()->devicePixelRatio(); int wWidth = width; int wHeight = height; if (vParams->GetValueLong(ViewpointParams::UseCustomFramebufferTag, 0)) { // printf("USE CUSTOM FRAMEBUFFER\n"); width = vParams->GetValueLong(ViewpointParams::CustomFramebufferWidthTag, 0); height = vParams->GetValueLong(ViewpointParams::CustomFramebufferHeightTag, 0); if (width == 0) width = 1; if (height == 0) height = 1; int maxSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize); if (width > maxSize) { width = maxSize; vParams->SetValueLong(ViewpointParams::CustomFramebufferWidthTag, ViewpointParams::CustomFramebufferWidthTag, width); LogFatal("Selected width is larger than your OpenGL implementation supports"); } if (height > maxSize) { height = maxSize; vParams->SetValueLong(ViewpointParams::CustomFramebufferHeightTag, ViewpointParams::CustomFramebufferHeightTag, height); LogFatal("Selected height is larger than your OpenGL implementation supports"); } float fa = width / (float)height; float wa = wWidth / (float)wHeight; if (fa >= wa) { int x = 0; int y = (wHeight / 2) - (wHeight / fa * wa / 2); int w = wWidth; int h = wHeight / fa * wa; glViewport(x, y, w, h); } else { int x = (wWidth / 2) - (wWidth * fa / wa / 2); int y = 0; int w = wWidth * fa / wa; int h = wHeight; glViewport(x, y, w, h); } } else { glViewport(0, 0, width, height); } mm->MatrixModeProjection(); mm->LoadIdentity(); float w = (float)width / (float)height; if (vParams->GetProjectionType() == ViewpointParams::MapOrthographic) { Trackball trackball; double center[3]; vParams->GetRotationCenter(center); trackball.setFromFrame(posvec, dirvec, upvec, center, true); float s = trackball.GetOrthoSize(); mm->Ortho(-s * w, s * w, -s, s, nearDist, farDist); vParams->SetOrthoProjectionSize(trackball.GetOrthoSize()); } else { double fov = vParams->GetFOV(); mm->Perspective(glm::radians(fov), w, nearDist, farDist); } double pMatrix[16]; mm->GetDoublev(MatrixManager::Mode::Projection, pMatrix); bool enabled = _controlExec->GetSaveStateEnabled(); _controlExec->SetSaveStateEnabled(false); vParams->SetProjectionMatrix(pMatrix); _controlExec->SetSaveStateEnabled(enabled); mm->MatrixModeModelView(); } void RenderManager::setUpModelViewMatrix() { ParamsMgr * paramsMgr = _controlExec->GetParamsMgr(); ViewpointParams *vParams = paramsMgr->GetViewpointParams(GetWinName()); double m[16]; vParams->GetModelViewMatrix(m); _glManager->matrixManager->LoadMatrixd(m); } int RenderManager::Render(String imagePath, bool fast) { if (_useOSGLContext) GetOSGLContext()->MakeCurrent(); _controlExec->SyncWithParams(); // GL_ERR_BREAK(); if (!_glManager) { _glManager = new GLManager; _controlExec->InitializeViz(GetWinName(), _glManager); } auto res = GetResolution(); int width = res[0]; int height = res[1]; Framebuffer defaultFB; defaultFB.Generate(); defaultFB.SetSize(width, height); defaultFB.MakeRenderTarget(); getViewpointParams()->SetWindowSize(width, height); _glManager->matrixManager->MatrixModeProjection(); _glManager->matrixManager->PushMatrix(); setUpProjMatrix(); _glManager->matrixManager->MatrixModeModelView(); _glManager->matrixManager->PushMatrix(); setUpModelViewMatrix(); int rc = _controlExec->EnableImageCapture(imagePath, GetWinName(), fast); if (rc < 0) { LogWarning("Paint Failed"); } _glManager->matrixManager->MatrixModeProjection(); _glManager->matrixManager->PopMatrix(); _glManager->matrixManager->MatrixModeModelView(); _glManager->matrixManager->PopMatrix(); return rc; } void RenderManager::SetResolution(int width, int height) { width = std::max(width, 1); height = std::max(height, 1); auto vp = getViewpointParams(); vp->BeginGroup("res"); vp->SetValueLong(ViewpointParams::UseCustomFramebufferTag, "", true); vp->SetValueLong(ViewpointParams::CustomFramebufferWidthTag, "", width); vp->SetValueLong(ViewpointParams::CustomFramebufferHeightTag, "", height); vp->EndGroup(); } vector RenderManager::GetResolution() const { vector res = {600, 480}; auto vp = getViewpointParams(); if (vp->GetValueLong(vp->UseCustomFramebufferTag, false)) { res[0] = getViewpointParams()->GetValueLong(ViewpointParams::CustomFramebufferWidthTag, 600); res[1] = getViewpointParams()->GetValueLong(ViewpointParams::CustomFramebufferHeightTag, 480); } return res; } String RenderManager::GetWinName() const { const auto names = _controlExec->GetParamsMgr()->GetVisualizerNames(); assert(not names.empty()); return names[0]; } GLContext *RenderManager::GetOSGLContext() { if (_glContext == nullptr) _glContext = GLContextProvider::CreateContext(); return _glContext; } VAPoR::ViewpointParams *RenderManager::getViewpointParams() const { return _controlExec->GetParamsMgr()->GetViewpointParams(GetWinName()); } ================================================ FILE: lib/vapi/RenderManager.h ================================================ #pragma once #include #include //! \class RenderManager //! \ingroup VAPI //! \brief Manages rendering visualizers class RenderManager { ControlExec *_controlExec; GLManager * _glManager = nullptr; bool _useOSGLContext = false; static GLContext * _glContext; public: RenderManager(ControlExec *ce, bool useOSGLContext = false); ~RenderManager(); int Render(String imagePath, bool fast=false); void SetResolution(int width, int height); vector GetResolution() const; String GetWinName() const; static GLContext *GetOSGLContext(); private: void getNearFarDist(const double posVec[3], const double dirVec[3], double &boxNear, double &boxFar); void setUpProjMatrix(); void setUpModelViewMatrix(); ViewpointParams *getViewpointParams() const; }; ================================================ FILE: lib/vapi/Session.cpp ================================================ #include "Session.h" #include #include #include #include #include #include #include #include #include #include using namespace VAPoR; Session::Session(bool useOSGLContext) : _useOSGLContext(useOSGLContext) { vector myParams; myParams.push_back(GUIStateParams::GetClassType()); myParams.push_back(AnimationParams::GetClassType()); myParams.push_back(SettingsParams::GetClassType()); vector myRenParams; _controlExec = new ControlExec(new ParamsMgr(myParams, myRenParams)); Reset(); } Session::~Session() { delete _renderManager; delete _controlExec; } void Session::CloseDataset(String datasetName) { _controlExec->CloseData(datasetName); } void Session::CloseAllDatasets() { auto datasetNames = _controlExec->GetDataNames(); for (auto &name : datasetNames) { CloseDataset(name); } } int Session::OpenDataset(String name, String format, const vector &files, const vector &options) { _controlExec->GetParamsMgr()->BeginSaveStateGroup("Import Dataset"); int rc = _controlExec->OpenData(files, name, format); if (rc < 0) { _controlExec->GetParamsMgr()->EndSaveStateGroup(); LogWarning("Failed to load data '%s'", files.empty() ? name.c_str() : files[0].c_str()); return rc; } GUIStateParams *p = getGUIStateParams(); DataStatus * ds = _controlExec->GetDataStatus(); bool isFirstDataset = p->GetOpenDataSetNames().empty(); p->InsertOpenDataSet(name, format, files); getAnimationParams()->SetEndTimestep(ds->GetTimeCoordinates().size() - 1); if (isFirstDataset) { NavigationUtils::ViewAll(_controlExec); NavigationUtils::SetHomeViewpoint(_controlExec); p->SetProjectionString(ds->GetMapProjection()); } _controlExec->GetParamsMgr()->EndSaveStateGroup(); return 0; } int Session::OpenDataset(String format, const vector &files, String name) { VAssert(!name.empty()); GUIStateParams *p = getGUIStateParams(); vector options = {"-project_to_pcs", "-vertical_xform"}; if (getSettingsParams()->GetAutoStretchEnabled()) options.push_back("-auto_stretch_z"); if (!p->GetProjectionString().empty()) { options.push_back("-proj4"); options.push_back(p->GetProjectionString()); } return OpenDataset(name, format, files, options); } String Session::OpenDataset(String format, vector files) { if (files.empty()) return ""; String name = ControlExec::MakeStringConformant(FileUtils::Basename(files[0])); if (OpenDataset(format, files, name) < 0) return ""; return name; } int Session::Load(String path) { Reset(); int rc = _controlExec->LoadState(path); if (rc < 0) { LogWarning("Session '%s' failed to load", path.c_str()); return rc; } auto dataSetNames = _controlExec->GetParamsMgr()->GetDataMgrNames(); for (auto d : dataSetNames) { printf("Dataset: '%s'\n", d.c_str()); } loadAllParamsDatasets(); getGUIStateParams()->SetActiveVizName(getWinName()); _controlExec->GetParamsMgr()->UndoRedoClear(); return 0; } int Session::Save(String path) { for (auto name : _controlExec->GetDataNames()) { if (dynamic_cast(_controlExec->GetDataStatus()->GetDataMgr(name))) { LogWarning("Cannot save session that contains data dynamically loaded from python (dataset.PYTHON)"); return -1; } } if (_controlExec->SaveSession(path) < 0) { LogWarning("Failed to save session \"%s\"", path.c_str()); return -1; } getGUIStateParams()->SetCurrentSessionFile(path); return 0; } void Session::Reset() { CloseAllDatasets(); _controlExec->LoadState(); _controlExec->SetCacheSize(getSettingsParams()->GetCacheMB()); _controlExec->NewVisualizer("viz_1"); getGUIStateParams()->SetActiveVizName("viz_1"); if (_renderManager) delete _renderManager; _renderManager = new RenderManager(_controlExec, _useOSGLContext); _controlExec->GetParamsMgr()->UndoRedoClear(); } int Session::Render(String imagePath, bool fast) { if (!_controlExec->GetParamsMgr()->GetDataMgrNames().size()) { LogWarning("Nothing to render"); return -1; } if (_controlExec->GetParamsMgr()->GetDataMgrNames() != getGUIStateParams()->GetOpenDataSetNames()) { LogWarning("Cannot render: There are missing datasets"); return -1; } return _renderManager->Render(imagePath, fast); } void Session::SetTimestep(int ts) { NavigationUtils::SetTimestep(_controlExec, ts); } int Session::GetTimesteps() const { return _controlExec->GetDataStatus()->getMaxTimestep() + 1; } void Session::SetWaspMyBaseErrMsgFilePtrToSTDERR() { Wasp::MyBase::SetErrMsgFilePtr(stderr); } vector Session::GetDatasetNames() const { return _controlExec->GetDataNames(); } vector Session::GetRendererNames() const { vector names; for (auto cls : _controlExec->GetAllRenderClasses()) for (auto inst : _controlExec->GetRenderInstances(getWinName(), cls)) names.push_back(inst); return names; } String Session::NewRenderer(String type, String dataset) { auto all = _controlExec->GetAllRenderClasses(); VAssert(STLUtils::Contains(all, type)); VAssert(!_controlExec->GetDataNames().empty()); if (dataset.empty()) dataset = _controlExec->GetDataNames()[0]; String rendererName = _controlExec->MakeRendererNameUnique(type); _controlExec->GetParamsMgr()->BeginSaveStateGroup("New Renderer"); int rc = _controlExec->ActivateRender(getWinName(), dataset, type, rendererName, false); if (rc < 0) { _controlExec->GetParamsMgr()->EndSaveStateGroup(); return ""; } getGUIStateParams()->SetActiveRenderer(getWinName(), type, rendererName); _controlExec->GetParamsMgr()->EndSaveStateGroup(); // ControlExec::RenderLookup string _win, _data, _type; _controlExec->RenderLookup(rendererName, _win, _data, _type); return rendererName; } void Session::DeleteRenderer(String name) { string win, data, type; _controlExec->RenderLookup(name, win, data, type); _controlExec->RemoveRenderer(win, data, type, name, false); } String Session::GetPythonWinName() const { return getWinName(); } void Session::loadAllParamsDatasets() { auto dataSetNames = _controlExec->GetParamsMgr()->GetDataMgrNames(); for (int i = 0; i < dataSetNames.size(); i++) { string name = dataSetNames[i]; string format; vector paths; getParamsDatasetInfo(name, &format, &paths); if (std::all_of(paths.begin(), paths.end(), FileUtils::Exists)) { if (OpenDataset(format, paths, name) < 0) getGUIStateParams()->RemoveOpenDataSet(name); } else { getGUIStateParams()->RemoveOpenDataSet(name); string details = "This session links to the dataset " + name + " which was not found. Please open this dataset if it is in a different location\n"; for (const auto &path : paths) if (!FileUtils::Exists(path)) details += "\"" + path + "\" not found.\n"; LogWarning("%s", details.c_str()); } } } void Session::getParamsDatasetInfo(String name, String *type, vector *files) { auto gsp = getGUIStateParams(); *type = gsp->GetOpenDataSetFormat(name); *files = gsp->GetOpenDataSetPaths(name); } GUIStateParams *Session::getGUIStateParams() const { return ((GUIStateParams *)_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); } AnimationParams *Session::getAnimationParams() const { return ((AnimationParams *)_controlExec->GetParamsMgr()->GetParams(AnimationParams::GetClassType())); } SettingsParams *Session::getSettingsParams() const { return ((SettingsParams *)_controlExec->GetParamsMgr()->GetParams(SettingsParams::GetClassType())); } String Session::getWinName() const { return _renderManager->GetWinName(); } ================================================ FILE: lib/vapi/Session.h ================================================ #pragma once #include class RenderManager; //! \class Session //! \ingroup VAPI //! \brief Manages a Vapor Session //! \author Stas Jaroszynski class Session { public: ControlExec * _controlExec = nullptr; RenderManager *_renderManager = nullptr; bool _useOSGLContext = false; Session(bool useOSGLContext = false); virtual ~Session(); void CloseDataset(String name); void CloseAllDatasets(); int OpenDataset(String name, String format, const vector &files, const vector &options); int OpenDataset(String format, const vector &files, String name); String OpenDataset(String format, vector files); int Load(String path); int Save(String path); void Reset(); vector GetDatasetNames() const; vector GetRendererNames() const; String NewRenderer(String type, String dataset=""); void DeleteRenderer(String name); int Render(String imagePath, bool fast=false); void SetTimestep(int ts); int GetTimesteps() const; static void SetWaspMyBaseErrMsgFilePtrToSTDERR(); String GetPythonWinName() const; protected: void loadAllParamsDatasets(); void getParamsDatasetInfo(String name, String *type, vector *files); GUIStateParams * getGUIStateParams() const; AnimationParams *getAnimationParams() const; SettingsParams * getSettingsParams() const; String getWinName() const; }; ================================================ FILE: lib/vapi/VPCommon.h ================================================ #pragma once #include namespace VAPoR { class ControlExec; class ParamsMgr; struct GLManager; class Framebuffer; class ViewpointParams; class RenderParams; } // namespace VAPoR using namespace VAPoR; class GUIStateParams; class AnimationParams; class SettingsParams; ================================================ FILE: lib/vapi/main.cpp ================================================ //#include #include #include #include #include #include #include #include using namespace VAPoR; Session *_session; int main(int argc, char **argv) { const char *sessionPath; if (argc == 2) sessionPath = argv[1]; else sessionPath = "/Users/stasj/Work/sessions/time.vs3"; Wasp::MyBase::SetErrMsgFilePtr(stderr); auto ctx = GLContextProvider::CreateContext(); VAssert(ctx); ctx->MakeCurrent(); LogMessage("Context: %s", glGetString(GL_VERSION)); _session = new Session; _session->Load(sessionPath); // _session->NewRenderer("Contour"); _session->Render("out-vapi-test.png"); return 0; } ================================================ FILE: lib/vdc/ArbitrarilyOrientedRegularGrid.cpp ================================================ #include #include #include #include #include #include #include using namespace std; using namespace VAPoR; // clang-format off ArbitrarilyOrientedRegularGrid::ArbitrarilyOrientedRegularGrid( const VAPoR::Grid *grid3d, planeDescription& pd, const DimsType& dims ) : RegularGrid( dims, {{pd.sideSize, pd.sideSize, 1}}, {(_myBlks = new float[dims[0]*dims[1]*dims[2]])}, {{0.,0.,0.}}, {{1.,1.,1.}} ) { SetMissingValue( grid3d->GetMissingValue() ); glm::vec3 n(pd.normal[0], pd.normal[1], pd.normal[2]); n = glm::normalize(n); if (glm::any(glm::isnan(n)) || abs(glm::length(n)) < 0.5) n = glm::vec3(0,0,1); _sideSize = pd.sideSize; _normal = {n[0], n[1], n[2]}; CoordType gridMin, gridMax; grid3d->GetUserExtents(gridMin, gridMax); _origin = {pd.origin[0], pd.origin[1], pd.origin[2]}; // Rotate the plane via quaternion method _rotate(); // Find the vertices where our plane intercepts the edges of the Box std::vector> vertices; _findIntercepts(gridMin, gridMax, vertices); // If there are no vertices to define our quad, make a grid of empty values if (!vertices.size()) { _makeEmptyGrid(); return; } // Find the minimum-area-rectangle that encloses the vertices that are along the edges // of the Box. Define this rectangle in 3D space, and in a newly projecteed 2D space. std::vector> tmpRectangle3D; _getMinimumAreaRectangle( vertices ); // Pick sample points along our 2D rectangle, and project those points back into 3D space // to query our 3D grid for data values. _populateData( grid3d, pd ); } ArbitrarilyOrientedRegularGrid::~ArbitrarilyOrientedRegularGrid() { if (_myBlks != nullptr) delete [] _myBlks; } void ArbitrarilyOrientedRegularGrid::_makeEmptyGrid() { _rectangle2D.clear(); _rectangle2D.resize(4); _rectangle2D[0] = glm::vec2(0., 0.); _rectangle2D[1] = glm::vec2(0., 0.); _rectangle2D[2] = glm::vec2(0., 0.); _rectangle2D[3] = glm::vec2(0., 0.); size_t numSamples = _sideSize*_sideSize; for (size_t i = 0; i < numSamples; i++) { _myBlks[i] = GetMissingValue(); } } // Huges-Moller algorithm to get an orthogonal vector // https://blog.selfshadow.com/2011/10/17/perp-vectors glm::tvec3 ArbitrarilyOrientedRegularGrid::_getOrthogonal(const glm::tvec3& u) { glm::tvec3 a = abs(u); glm::tvec3 v; if (a.x <= a.y && a.x <= a.z) v = glm::tvec3(0, -u.z, u.y); else if (a.y <= a.x && a.y <= a.z) v = glm::tvec3(-u.z, 0, u.x); else v = glm::tvec3(-u.y, u.x, 0); v = glm::normalize(v); return v; } void ArbitrarilyOrientedRegularGrid::_rotate() { // We will sample the slice in 2D coordinates. // So we first define a basis function of three orthogonal vectors (normal, _axis1, _axis2). _axis1 = _getOrthogonal(_normal); _axis2 = glm::cross(_normal, _axis1); } void ArbitrarilyOrientedRegularGrid::_findIntercepts( const VAPoR::CoordType& boxMin, const VAPoR::CoordType& boxMax, std::vector> &vertices ) { // Lambdas for finding intercepts on the XYZ edges of the Box // Plane equation: // normal.x*(x-origin.x) + normal.y*(y-origin.y) + normal.z*(z-origin.z) = 0 auto zIntercept = [&](double x, double y) { if (_normal.z == 0) return; double z = (_normal.x * _origin.x + _normal.y * _origin.y + _normal.z * _origin.z - _normal.x * x - _normal.y * y) / _normal.z; if (z >= boxMin[2] && z <= boxMax[2]) { glm::tvec3 p(x, y, z); vertices.push_back(p); } }; auto yIntercept = [&](double x, double z) { if (_normal.y == 0) return; double y = (_normal.x * _origin.x + _normal.y * _origin.y + _normal.z * _origin.z - _normal.x * x - _normal.z * z) / _normal.y; if (y >= boxMin[1] && y <= boxMax[1]) { glm::tvec3 p(x, y, z); vertices.push_back(p); } }; auto xIntercept = [&](double y, double z) { if (_normal.x == 0) return; double x = (_normal.x * _origin.x + _normal.y * _origin.y + _normal.z * _origin.z - _normal.y * y - _normal.z * z) / _normal.x; if (x >= boxMin[0] && x <= boxMax[0]) { glm::tvec3 p(x, y, z); vertices.push_back(p); } }; // Find vertices that exist on the Z edges of the Box zIntercept(boxMin[0], boxMin[1]); zIntercept(boxMax[0], boxMax[1]); zIntercept(boxMin[0], boxMax[1]); zIntercept(boxMax[0], boxMin[1]); // Find any vertices that exist on the Y edges of the Box yIntercept(boxMin[0], boxMin[2]); yIntercept(boxMax[0], boxMax[2]); yIntercept(boxMin[0], boxMax[2]); yIntercept(boxMax[0], boxMin[2]); // Find any vertices that exist on the X edges of the Box xIntercept(boxMin[1], boxMin[2]); xIntercept(boxMax[1], boxMax[2]); xIntercept(boxMin[1], boxMax[2]); xIntercept(boxMax[1], boxMin[2]); } void ArbitrarilyOrientedRegularGrid::_getMinimumAreaRectangle( const std::vector>& vertices ) { std::vector> gteVertices; for (int i=0; i v3d = vertices[i]; double x = glm::dot(_axis1, v3d-_origin); double y = glm::dot(_axis2, v3d-_origin); gte::Vector2 v{x,y}; gteVertices.push_back(v); } typedef gte::BSRational MABRational; gte::MinimumAreaBox2 mab2; gte::OrientedBox2 minimalBox = mab2(vertices.size(), >eVertices[0]); std::array, 4> rectangle; minimalBox.GetVertices(rectangle); // _rectangle2D _rectangle2D.clear(); _rectangle2D.resize(4); _rectangle2D[0] = glm::vec2(rectangle[0][0], rectangle[0][1]); _rectangle2D[1] = glm::vec2(rectangle[1][0], rectangle[1][1]); _rectangle2D[2] = glm::vec2(rectangle[3][0], rectangle[3][1]); _rectangle2D[3] = glm::vec2(rectangle[2][0], rectangle[2][1]); } void ArbitrarilyOrientedRegularGrid::GetUserCoordinates(const DimsType &indices, CoordType &coords) const { // For now, we ignore rotated grids that have greater than 3 dimensions // Therefore we only index on i an j, but not k // size_t i = indices[0]; size_t j = indices[1]; glm::tvec2 delta( (_rectangle2D[1].x-_rectangle2D[0].x)/_sideSize, (_rectangle2D[1].y-_rectangle2D[0].y)/_sideSize ); double xScanlineIncrement = (_rectangle2D[3].x-_rectangle2D[0].x)/_sideSize; double yScanlineIncrement = (_rectangle2D[3].y-_rectangle2D[0].y)/_sideSize; double x = _rectangle2D[0].x + j*xScanlineIncrement + i*delta.x; double y = _rectangle2D[0].y + j*yScanlineIncrement + i*delta.y; glm::tvec3 samplePoint = _origin + x*_axis1 + y*_axis2; coords = {samplePoint.x, samplePoint.y, samplePoint.z}; } void ArbitrarilyOrientedRegularGrid::_populateData( const VAPoR::Grid *grid, const planeDescription& description ) { VAPoR::CoordType min = description.boxMin; VAPoR::CoordType max = description.boxMax; float missingValue = grid->GetMissingValue(); size_t index = 0; for (size_t j = 0; j < _sideSize; j++) { for (size_t i = 0; i < _sideSize; i++) { VAPoR::CoordType p; GetUserCoordinates({i,j,1}, p); if ( p[0] < min[0] || p[0] > max[0] || p[1] < min[1] || p[1] > max[1] || p[2] < min[2] || p[2] > max[2] ) { _myBlks[index] = missingValue; } else { _myBlks[index] = grid->GetValue(p); } index++; } } } // clang-format on glm::vec3 ArbitrarilyOrientedRegularGrid::GetNormalFromRotations(const std::vector &rotations) { glm::vec3 r(rotations[0], rotations[1], rotations[2]); r = r * (float)M_PI / 180.f; auto q = glm::quat(r); auto n = q * glm::vec3(0, 0, 1); return n; } std::pair ArbitrarilyOrientedRegularGrid::GetOffsetRange(const planeDescription &pd) { glm::vec3 n(pd.normal[0], pd.normal[1], pd.normal[2]); glm::vec3 dataMin(pd.boxMin[0], pd.boxMin[1], pd.boxMin[2]); glm::vec3 dataMax(pd.boxMax[0], pd.boxMax[1], pd.boxMax[2]); glm::vec3 o(pd.origin[0], pd.origin[1], pd.origin[2]); float t0, t1; glm::vec3 tMin = (dataMin - o) / n; glm::vec3 tMax = (dataMax - o) / n; glm::vec3 bt1 = min(tMin, tMax); glm::vec3 bt2 = max(tMin, tMax); t0 = max(max(bt1.x, bt1.y), bt1.z); t1 = min(min(bt2.x, bt2.y), bt2.z); return std::pair(t0, t1); } ================================================ FILE: lib/vdc/BOVCollection.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include "vapor/VAssert.h" #include "vapor/utils.h" #include "vapor/FileUtils.h" #include #include #include #include using namespace VAPoR; const std::string BOVCollection::TIME_TOKEN = "TIME"; const std::string BOVCollection::DATA_FILE_TOKEN = "DATA_FILE"; const std::string BOVCollection::GRID_SIZE_TOKEN = "DATA_SIZE"; const std::string BOVCollection::FORMAT_TOKEN = "DATA_FORMAT"; const std::string BOVCollection::VARIABLE_TOKEN = "VARIABLE"; const std::string BOVCollection::ORIGIN_TOKEN = "BRICK_ORIGIN"; const std::string BOVCollection::BRICK_SIZE_TOKEN = "BRICK_SIZE"; const std::string BOVCollection::OFFSET_TOKEN = "BYTE_OFFSET"; // These tokens are parsed, but not used in ReadRegion() logic const std::string BOVCollection::ENDIAN_TOKEN = "DATA_ENDIAN"; const std::string BOVCollection::CENTERING_TOKEN = "CENTERING"; const std::string BOVCollection::DIVIDE_BRICK_TOKEN = "DIVIDE_BRICK"; const std::string BOVCollection::DATA_BRICKLETS_TOKEN = "DATA_BRICKLETS"; const std::string BOVCollection::DATA_COMPONENTS_TOKEN = "DATA_COMPONENTS"; const std::array BOVCollection::_defaultOrigin = {0., 0., 0.}; const std::array BOVCollection::_defaultBrickSize = {1., 1., 1.}; const std::array BOVCollection::_defaultGridSize = {0, 0, 0}; const DC::XType BOVCollection::_defaultFormat = DC::XType::INVALID; const std::string BOVCollection::_defaultFile = ""; const std::string BOVCollection::_defaultVar = "brickVar"; const double BOVCollection::_defaultTime = FLT_MIN; const size_t BOVCollection::_defaultByteOffset = 0; // Currently unused in ReadRegion() logic const std::string BOVCollection::_defaultEndian = "LITTLE"; const std::string BOVCollection::_defaultCentering = "ZONAL"; const bool BOVCollection::_defaultDivBrick = false; const std::array BOVCollection::_defaultBricklets = {0, 0, 0}; const size_t BOVCollection::_defaultComponents = 1; const std::string BOVCollection::_xDim = "x"; const std::string BOVCollection::_yDim = "y"; const std::string BOVCollection::_zDim = "z"; const std::string BOVCollection::_timeDim = "t"; const std::string BOVCollection::_byteFormatString = "BYTE"; const std::string BOVCollection::_shortFormatString = "SHORT"; const std::string BOVCollection::_intFormatString = "INT"; const std::string BOVCollection::_floatFormatString = "FLOAT"; const std::string BOVCollection::_doubleFormatString = "DOUBLE"; namespace { size_t getFileSize(std::string filename) // path to file { FILE *p_file = NULL; p_file = fopen(filename.c_str(), "rb"); fseek(p_file, 0, SEEK_END); size_t size = ftell(p_file); fclose(p_file); return size; } } // namespace BOVCollection::BOVCollection() : _time(_defaultTime), _dataFile(_defaultFile), _dataFormat(_defaultFormat), _variable(_defaultVar), _byteOffset(_defaultByteOffset), _divideBrick(_defaultDivBrick), _dataEndian(_defaultEndian), _centering(_defaultCentering), _dataComponents(_defaultComponents), _tmpDataFormat(_defaultFormat), _tmpByteOffset(_defaultByteOffset), _gridSizeAssigned(false), _formatAssigned(false), _brickOriginAssigned(false), _brickSizeAssigned(false), _byteOffsetAssigned(false), _timeDimension(_timeDim) { // Note: the following variables are unused in the ReadRegion() logic // _defaultEndian // _defaultCentering // _defaultDivBrick // _defaultBricklets // _defaultComponents _dataFiles.clear(); _times.clear(); _gridSize = _defaultGridSize; _tmpGridSize[0] = (int)_defaultGridSize[0]; _tmpGridSize[1] = (int)_defaultGridSize[1]; _tmpGridSize[2] = (int)_defaultGridSize[2]; _brickOrigin = _defaultOrigin; _tmpBrickOrigin = _defaultOrigin; _brickSize = _defaultBrickSize; _tmpBrickSize = _defaultBrickSize; _dataBricklets = _defaultBricklets; _spatialDimensions = {_xDim, _yDim, _zDim}; } int BOVCollection::Initialize(const std::vector &paths) { VAssert(paths.size() > 0); int rc; std::ifstream header; for (int i = 0; i < paths.size(); i++) { _dataFile = _defaultFile; // Save the path to the BOV header so we can add it // to data files given with a relative path _currentFilePath = Wasp::FileUtils::Dirname(paths[i]); header.open(paths[i]); if (header.is_open()) { if (getFileSize(paths[i]) > 1000000) { SetErrMsg(("BOV header file larger than 1MB. This text file shouldn't need to be larger than a few KB." + paths[0]).c_str()); return -1; } rc = _parseHeader(header); if (rc < 0) { SetErrMsg(("Error parsing BOV file " + paths[0]).c_str()); return -1; } // If _dataFile is not an absolute path, prepend with the BOV header's path if (!Wasp::FileUtils::IsPathAbsolute(_dataFile)) { auto dirAndPath = {_currentFilePath, _dataFile}; _dataFile = Wasp::FileUtils::JoinPaths(dirAndPath); } rc = _validateParsedValues(); if (rc < 0) { SetErrMsg("Validating BOV tokens failed"); return -1; } // Ensure we have the required tokens in the header // if (_dataFile == _defaultFile) { return _missingValueError(DATA_FILE_TOKEN); } if (_dataFormat == _defaultFormat) { return _missingValueError(FORMAT_TOKEN); } if (_gridSize == _defaultGridSize) { return _missingValueError(GRID_SIZE_TOKEN); } if (_time == _defaultTime) { return _missingValueError(TIME_TOKEN); } rc = _populateDataFileMap(); if (rc < 0) { SetErrMsg("Problem indexing data files."); return -1; } } else { SetErrMsg(("Failed to open BOV file " + paths[0]).c_str()); return -1; } header.close(); } return 0; } int BOVCollection::_parseHeader(std::ifstream &header) { int rc; std::string line; std::string dataFile; while (getline(header, line)) { // The _dataFile, _gridSize, and _dataFormat variables are all required to process // the BOV. Try to find them, and report errors if we can't. // rc = _findToken(DATA_FILE_TOKEN, line, dataFile); if (rc == (int)parseCodes::PARSE_ERROR) return _failureToReadError(DATA_FILE_TOKEN); else if (rc == (int)parseCodes::FOUND) { _dataFile = dataFile; continue; } double time; rc = _findToken(TIME_TOKEN, line, time); if (rc == (int)parseCodes::PARSE_ERROR) return _failureToReadError(TIME_TOKEN); else if (rc == (int)parseCodes::FOUND) { _time = time; continue; } std::string variable; rc = _findToken(VARIABLE_TOKEN, line, variable); if (rc == (int)parseCodes::PARSE_ERROR) return _invalidValueError(VARIABLE_TOKEN); else if (rc == (int)parseCodes::FOUND) { _variable = variable; continue; } rc = _findToken(GRID_SIZE_TOKEN, line, _tmpGridSize); if (rc == (int)parseCodes::PARSE_ERROR) return _failureToReadError(GRID_SIZE_TOKEN); else if (rc == (int)parseCodes::FOUND) continue; rc = _findToken(FORMAT_TOKEN, line, _tmpDataFormat); if (rc == (int)parseCodes::PARSE_ERROR) return _failureToReadError(FORMAT_TOKEN); else if (rc == (int)parseCodes::FOUND) continue; // Optional tokens. If their values are invalid, SetErrMsg, and return -1. // rc = _findToken(ORIGIN_TOKEN, line, _tmpBrickOrigin); if (rc == (int)parseCodes::PARSE_ERROR) return _invalidValueError(ORIGIN_TOKEN); else if (rc == (int)parseCodes::FOUND) continue; rc = _findToken(BRICK_SIZE_TOKEN, line, _tmpBrickSize); if (rc == (int)parseCodes::PARSE_ERROR) return _invalidValueError(BRICK_SIZE_TOKEN); else if (rc == (int)parseCodes::FOUND) continue; rc = _findToken(OFFSET_TOKEN, line, _tmpByteOffset); if (rc == (int)parseCodes::PARSE_ERROR) return _invalidValueError(OFFSET_TOKEN); else if (rc == (int)parseCodes::FOUND) continue; // All other variables are currently unused. // _findToken(ENDIAN_TOKEN, line, _dataEndian); _findToken(CENTERING_TOKEN, line, _centering); _findToken(DIVIDE_BRICK_TOKEN, line, _divideBrick); _findToken(DATA_BRICKLETS_TOKEN, line, _dataBricklets); _findToken(DATA_COMPONENTS_TOKEN, line, _dataComponents); } return 0; } int BOVCollection::_validateParsedValues() { // Validate grid dimensions if (_tmpGridSize[0] < 2 || _tmpGridSize[1] < 2 || _tmpGridSize[2] < 2) return _invalidDimensionError(GRID_SIZE_TOKEN); else if ((_tmpGridSize[0] != _gridSize[0] || _tmpGridSize[1] != _gridSize[1] || _tmpGridSize[2] != _gridSize[2]) && _gridSizeAssigned == true) return _inconsistentValueError(GRID_SIZE_TOKEN); else { _gridSize[0] = (size_t)_tmpGridSize[0]; _gridSize[1] = (size_t)_tmpGridSize[1]; _gridSize[2] = (size_t)_tmpGridSize[2]; _gridSizeAssigned = true; } // Validate data format if (_tmpDataFormat == DC::INVALID) return _invalidFormatError(FORMAT_TOKEN); else if (_tmpDataFormat != _dataFormat && _formatAssigned == true) { return _inconsistentValueError(FORMAT_TOKEN); } else { _dataFormat = _tmpDataFormat; _formatAssigned = true; } // Validate brick origin if (_tmpBrickOrigin != _brickOrigin && _brickOriginAssigned == true) return _inconsistentValueError(ORIGIN_TOKEN); else { _brickOrigin = _tmpBrickOrigin; _brickOriginAssigned = true; } // Validate brick size if (_tmpBrickSize != _brickSize && _brickSizeAssigned == true) return _inconsistentValueError(BRICK_SIZE_TOKEN); else { for (size_t i = 0; i < _tmpBrickSize.size(); i++) { if (_tmpBrickSize[i] < 0.) return _invalidValueError(BRICK_SIZE_TOKEN); } _brickSize = _tmpBrickSize; _brickSizeAssigned = true; } // Validate byte offest if (_tmpByteOffset != _byteOffset && _byteOffsetAssigned == true) return _inconsistentValueError(OFFSET_TOKEN); else { _byteOffset = _tmpByteOffset; _byteOffsetAssigned = true; } if (_variable.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-") != std::string::npos) return _invalidVarNameError(); return 0; } int BOVCollection::_populateDataFileMap() { if (_dataFileMap[_variable].count(_time)) { SetErrMsg("Duplicate time entries found in BOV files. Each file must uniquely describe one variable, at one timestep."); return -1; } _variables.push_back(_variable); if (std::find(_times.begin(), _times.end(), _time) == _times.end()) _times.push_back(_time); std::sort(_times.begin(), _times.end()); _dataFileMap[_variable][_time] = _dataFile; return 0; } int BOVCollection::_invalidVarNameError() const { SetErrMsg("Invalid variable name. (Must be alphanumeric)"); return -1; } int BOVCollection::_invalidFileSizeError(size_t numElements) const { SetErrMsg(("Data file " + _dataFile + ", which has " + to_string(numElements) + " values, does not match the size of the the data and offset " "specified in BOV header.") .c_str()); return -1; } int BOVCollection::_invalidFileError() const { SetErrMsg(("Reading " + _dataFile + " failed with error: " + strerror(errno)).c_str()); return -1; } int BOVCollection::_missingValueError(const std::string &token) const { SetErrMsg(("BOV file must contain token: " + token).c_str()); return -1; } int BOVCollection::_invalidDimensionError(const std::string &token) const { SetErrMsg((token + " must have all dimensions > 1").c_str()); return -1; } int BOVCollection::_invalidFormatError(const std::string &token) const { std::string message = token + " must be either INT, FLOAT, or DOUBLE."; SetErrMsg(message.c_str()); return -1; } int BOVCollection::_failureToReadError(const std::string &token) const { SetErrMsg(("Failure reading BOV token: " + token).c_str()); return -1; } int BOVCollection::_inconsistentValueError(const std::string &token) const { SetErrMsg((token + " must be consistent in all BOV files").c_str()); return -1; } int BOVCollection::_invalidValueError(const std::string &token) const { SetErrMsg(("Invalid value for token: " + token).c_str()); return -1; } std::vector BOVCollection::GetDataVariableNames() const { return _variables; } std::array BOVCollection::GetSpatialDimensions() const { return _spatialDimensions; } std::string BOVCollection::GetTimeDimension() const { return _timeDimension; } std::vector BOVCollection::GetUserTimes() const { return _times; } std::array BOVCollection::GetDataSize() const { return _gridSize; } DC::XType BOVCollection::GetDataFormat() const { return _dataFormat; } std::array BOVCollection::GetBrickOrigin() const { return _brickOrigin; } std::array BOVCollection::GetBrickSize() const { return _brickSize; } // Template specialization for reading data of type DC::XType template<> int BOVCollection::_findToken(const std::string &token, std::string &line, DC::XType &value, bool verbose) { // Skip comments for (size_t i = 0; i < line.length(); i++) { if (line[i] == '#') { line.erase(line.begin() + i, line.end()); break; } } if (line.length() == 0) return (int)parseCodes::NOT_FOUND; while (line.length() > 0) { if (line[line.length() - 1] == ' ') // If last char is a space, pop it line.pop_back(); else break; } size_t pos = line.find(token); if (pos != std::string::npos) { // We found the token std::string format = line; _findTokenValue(format); if (format == _intFormatString) value = DC::INT32; else if (format == _floatFormatString) value = DC::FLOAT; else if (format == _doubleFormatString) value = DC::DOUBLE; else { value = DC::INVALID; _invalidFormatError(token); return (int)parseCodes::PARSE_ERROR; } if (verbose) { std::cout << std::setw(20) << token << " " << value << std::endl; } return (int)parseCodes::FOUND; } return (int)parseCodes::NOT_FOUND; } // Template specialization for reading data of types bool or string template int BOVCollection::_findToken(const std::string &token, std::string &line, T &value, bool verbose) { // Skip comments for (size_t i = 0; i < line.length(); i++) { if (line[i] == '#') { line.erase(line.begin() + i, line.end()); break; } } if (line.length() == 0) return (int)parseCodes::NOT_FOUND; while (line.length() > 0) { if (line[line.length() - 1] == ' ') // If last char is a space, pop it line.pop_back(); else break; } size_t pos = line.find(token); if (pos != std::string::npos) { // We found the token _findTokenValue(line); stringstream ss(line); if (std::is_same::value) { ss >> std::boolalpha >> value; } else { ss >> value; } if (verbose) { std::cout << std::setw(20) << token << " " << value << std::endl; } if (ss.fail()) { return (int)parseCodes::PARSE_ERROR; } // If there is more than one value, throw error if (ss.eof() == false) return (int)parseCodes::PARSE_ERROR; return (int)parseCodes::FOUND; } return (int)parseCodes::NOT_FOUND; } // Template specialization for reading data of type std::array or std::array template int BOVCollection::_findToken(const std::string &token, std::string &line, std::array &value, bool verbose) { // Skip comments for (size_t i = 0; i < line.length(); i++) { if (line[i] == '#') { line.erase(line.begin() + i, line.end()); break; } } if (line.length() == 0) return (int)parseCodes::NOT_FOUND; while (line.length() > 0) { if (line[line.length() - 1] == ' ') // If last char is a space, pop it line.pop_back(); else break; } size_t pos = line.find(token); if (pos != std::string::npos) { // We found the token T lineValue; _findTokenValue(line); std::stringstream lineStream(line); for (int i = 0; i < value.size(); i++) { lineStream >> lineValue; if (lineStream.fail()) return (int)parseCodes::PARSE_ERROR; value[i] = lineValue; } // If there are more than 3 values, throw error if (!lineStream.eof()) return (int)parseCodes::PARSE_ERROR; if (verbose) { std::cout << std::setw(20) << token << " "; for (int i = 0; i < value.size(); i++) std::cout << value[i] << " "; std::cout << std::endl; } return (int)parseCodes::FOUND; } return (int)parseCodes::NOT_FOUND; } void BOVCollection::_findTokenValue(std::string &line) const { std::string delimiter = ": "; size_t pos = 0; std::string token; while ((pos = line.find(delimiter)) != std::string::npos) { token = line.substr(0, pos); line.erase(0, pos + delimiter.length()); } } int BOVCollection::_sizeOfFormat(DC::XType type) const { switch (type) { case DC::XType::INT32: return 4; case DC::XType::FLOAT: return 4; case DC::XType::DOUBLE: return 8; default: return -1; } } template int BOVCollection::ReadRegion(std::string varname, size_t ts, const std::vector &min, const std::vector &max, T region) { float time = _times[ts]; std::string dataFile = _dataFileMap[varname][time]; FILE *fp = fopen(dataFile.c_str(), "rb"); if (!fp) { if (dataFile == "") SetErrMsg("No data file associated with variable '%s' at timestep %d", varname.c_str(), time); else SetErrMsg("Invalid file: %s : %M", dataFile.c_str()); return -1; } int formatSize = _sizeOfFormat(_dataFormat); if (formatSize < 0) { SetErrMsg("Unspecified data format"); fclose(fp); return -1; } // Read a "pencil" of data along the X axis, one row at a time size_t count = max[0] - min[0] + 1; // Note: allocate buffer once and reuse for many times, so repeated allocation is avoided. std::vector vReadBuffer(count * formatSize); unsigned char * readBuffer = vReadBuffer.data(); for (size_t k = min[2]; k <= max[2]; k++) { size_t zOffset = _gridSize[0] * _gridSize[1] * k; for (size_t j = min[1]; j <= max[1]; j++) { size_t xOffset = min[0]; size_t yOffset = _gridSize[0] * j; size_t offset = formatSize * (xOffset + yOffset + zOffset) + _byteOffset; int rc = fseek(fp, offset, SEEK_SET); if (rc != 0) { MyBase::SetErrMsg("Unable to seek on file: %M"); return -1; } size_t fread_rc = fread(readBuffer, formatSize, count, fp); if (fread_rc != count) { if (ferror(fp) != 0) { MyBase::SetErrMsg("Error reading input file: %M"); } else { MyBase::SetErrMsg("Short read on input file: %M"); } fclose(fp); return -1; } if (_dataFormat == DC::XType::INT32) { int *castBuffer = (int *)readBuffer; for (size_t i = 0; i < count; i++) { *region++ = (typename std::remove_pointer::type)castBuffer[i]; } } else if (_dataFormat == DC::XType::FLOAT) { float *castBuffer = (float *)readBuffer; for (size_t i = 0; i < count; i++) { *region++ = (typename std::remove_pointer::type)castBuffer[i]; } } else if (_dataFormat == DC::XType::DOUBLE) { double *castBuffer = (double *)readBuffer; for (size_t i = 0; i < count; i++) { *region++ = (typename std::remove_pointer::type)castBuffer[i]; } } } } fclose(fp); return 0; } // ReadRegion can only be used with int* float* and double* template int BOVCollection::ReadRegion(std::string varname, size_t ts, const std::vector &, const std::vector &, int *); template int BOVCollection::ReadRegion(std::string varname, size_t ts, const std::vector &, const std::vector &, float *); template int BOVCollection::ReadRegion(std::string varname, size_t ts, const std::vector &, const std::vector &, double *); ================================================ FILE: lib/vdc/BlkMemMgr.cpp ================================================ #include #include #include #include #include #include #ifndef WIN32 #include #endif #include using namespace Wasp; using namespace VAPoR; // // Static member initialization // bool BlkMemMgr::_page_aligned_req = true; size_t BlkMemMgr::_mem_size_max_req = 32768; size_t BlkMemMgr::_blk_size_req = 32 * 32 * 32; bool BlkMemMgr::_page_aligned = false; size_t BlkMemMgr::_mem_size_max = 0; size_t BlkMemMgr::_blk_size = 0; vector BlkMemMgr::_mem_region_sizes; vector BlkMemMgr::_blks; vector> BlkMemMgr::_mem_regions; #ifdef VAPOR3_0_0_ALPHA #endif int BlkMemMgr::_ref_count = 0; int BlkMemMgr::_Reinit(size_t n) { long page_size = 0; size_t size = 0; if (_mem_size_max_req == 0 || _blk_size_req == 0) return (false); _page_aligned = _page_aligned_req; _mem_size_max = _mem_size_max_req; _blk_size = _blk_size_req; // // Calculate starting region size // size_t mem_size = n; // // How much total memory already allocated // size_t total_size = 0; int r; for (r = 0; r < _mem_regions.size(); r++) total_size += _mem_region_sizes[r]; // // New region size is double preceding one // if (r > 0) mem_size = _mem_region_sizes[r - 1] << 1; // Make sure region size will be large enough, and not too large // if (mem_size < n) mem_size = n; if ((mem_size + total_size) > _mem_size_max) mem_size = _mem_size_max - total_size; if (mem_size < n) return (false); if (_page_aligned) { #ifdef WIN32 page_size = 4096; #else page_size = sysconf(_SC_PAGESIZE); if (page_size < 0) page_size = 0; #endif } unsigned char *blks; do { size = (size_t)_blk_size * (size_t)mem_size; size += (size_t)page_size; blks = new (nothrow) unsigned char[size]; if (!blks) { SetDiagMsg("BlkMemMgr::_Reinit() : failed to allocate %d blocks, retrying", mem_size); mem_size = mem_size >> 1; } } while (blks == NULL && mem_size > 0 && _blk_size > 0); if (!blks && mem_size > 0 && _blk_size > 0) { SetDiagMsg("Memory allocation of %lu bytes failed", size); return (false); } else { SetDiagMsg("BlkMemMgr() : allocated %lu bytes", size); } unsigned char *blkptr = blks; if (page_size) { blkptr += page_size - (((size_t)blks) % page_size); } _mem_allocation_t m; vector<_mem_allocation_t> mem_region; m._nfree = mem_size; m._nused = 0; m._blk = blkptr; mem_region.push_back(m); _mem_regions.push_back(mem_region); _blks.push_back(blks); _mem_region_sizes.push_back(mem_size); return (true); } int BlkMemMgr::RequestMemSize(size_t blk_size, size_t num_blks, bool page_aligned) { SetDiagMsg("BlkMemMgr::RequestMemSize(%u,%u,%d)", blk_size, num_blks, page_aligned); // // If there are no instances of this object, re-initialized // the static memory pool if needed // if (blk_size == 0 || num_blks == 0) { SetErrMsg("Invalid request"); return (-1); } _blk_size_req = blk_size; _mem_size_max_req = num_blks; _page_aligned_req = page_aligned; return (0); } BlkMemMgr::BlkMemMgr() { SetDiagMsg("BlkMemMgr::BlkMemMgr()"); // // If there are no other instances of this object, re-initialized // the static memory pool if needed // if (_ref_count != 0) { _ref_count++; return; } for (int i = 0; i < _blks.size(); i++) { if (_blks[i]) delete[] _blks[i]; } _mem_regions.clear(); _mem_region_sizes.clear(); _blks.clear(); _page_aligned = _page_aligned_req; _mem_size_max = _mem_size_max_req; _blk_size = _blk_size_req; _ref_count = 1; } BlkMemMgr::~BlkMemMgr() { SetDiagMsg("BlkMemMgr::~BlkMemMgr()"); if (_ref_count > 0) _ref_count--; if (_ref_count != 0) return; for (int i = 0; i < _blks.size(); i++) { if (_blks[i]) delete[] _blks[i]; } _blks.clear(); _mem_regions.clear(); _mem_region_sizes.clear(); } void *BlkMemMgr::Alloc(size_t n, bool fill) { SetDiagMsg("BlkMemMgr::Alloc(%d)", n); // // Check each region, find the first run of blocks large enough // to satisfy the request // void *blk = NULL; for (int r = 0; r < _mem_regions.size() && !blk; r++) { vector<_mem_allocation_t> &mem_region = _mem_regions[r]; for (int i = 0; i < mem_region.size() && !blk; i++) { if (n <= mem_region[i]._nfree) { // Found a run of blocks blk = mem_region[i]._blk; mem_region[i]._nused = n; // // If run is strictly larger than request split it // if (n < mem_region[i]._nfree) { _mem_allocation_t m; m._nfree = mem_region[i]._nfree - n; m._nused = 0; m._blk = (unsigned char *)mem_region[i]._blk + (_blk_size * n); mem_region.insert(mem_region.begin() + i + 1, m); } mem_region[i]._nfree = 0; } } } if (!blk) { // Couldn't find space in existing memory pool. // Try to allocate more memory. // if (!BlkMemMgr::_Reinit(n)) return (NULL); return (Alloc(n, fill)); } if (fill) { unsigned char *ptr = (unsigned char *)blk; for (size_t i = 0; i < n * _blk_size; i++) ptr[i] = 0; } return (blk); } void BlkMemMgr::FreeMem(void *ptr) { SetDiagMsg("BlkMemMgr::FreeMem()"); bool found = false; for (int r = 0; r < _mem_regions.size() && !found; r++) { vector<_mem_allocation_t> &mem_region = _mem_regions[r]; for (int i = 0; i < mem_region.size() && !found; i++) { if (ptr == mem_region[i]._blk) { found = true; mem_region[i]._nfree = mem_region[i]._nused; mem_region[i]._nused = 0; } } } if (!found) cerr << "Failed to free block " << ptr << endl; // // Collapse any two adjacent runs of they're both free // bool collapse; do { collapse = false; for (int r = 0; r < _mem_regions.size(); r++) { vector<_mem_allocation_t> &mem_region = _mem_regions[r]; for (int i = 0; i < mem_region.size() - 1; i++) { if (mem_region[i]._nfree && mem_region[i + 1]._nfree) { mem_region[i]._nfree += mem_region[i + 1]._nfree; mem_region.erase(mem_region.begin() + i + 1); collapse = true; break; } } } } while (collapse); } ================================================ FILE: lib/vdc/CMakeLists.txt ================================================ set (SRC BlkMemMgr.cpp Grid.cpp ConstantGrid.cpp StructuredGrid.cpp RegularGrid.cpp StretchedGrid.cpp LayeredGrid.cpp CurvilinearGrid.cpp UnstructuredGrid.cpp UnstructuredGrid2D.cpp UnstructuredGrid3D.cpp UnstructuredGridLayered.cpp ArbitrarilyOrientedRegularGrid.cpp NetCDFSimple.cpp NetCDFCollection.cpp NetCDFCFCollection.cpp BOVCollection.cpp UDUnitsClass.cpp Proj4API.cpp DC.cpp DCWRF.cpp DCCF.cpp DCBOV.cpp DCMPAS.cpp DCP.cpp DCRAM.cpp DCMelanie.cpp VDC.cpp VDCNetCDF.cpp DerivedVar.cpp DerivedParticleDensity.cpp DerivedVarMgr.cpp DataMgr.cpp PythonDataMgr.cpp GridHelper.cpp DataMgrUtils.cpp GeoUtil.cpp vizutil.cpp KDTreeRG.cpp kdtree.c VDC_c.cpp DCUtils.cpp QuadTreeRectangleP.cpp DCUGRID.cpp ) set (HEADERS ${PROJECT_SOURCE_DIR}/include/vapor/BlkMemMgr.h ${PROJECT_SOURCE_DIR}/include/vapor/Grid.h ${PROJECT_SOURCE_DIR}/include/vapor/GridHelper.h ${PROJECT_SOURCE_DIR}/include/vapor/ConstantGrid.h ${PROJECT_SOURCE_DIR}/include/vapor/StructuredGrid.h ${PROJECT_SOURCE_DIR}/include/vapor/RegularGrid.h ${PROJECT_SOURCE_DIR}/include/vapor/StretchedGrid.h ${PROJECT_SOURCE_DIR}/include/vapor/LayeredGrid.h ${PROJECT_SOURCE_DIR}/include/vapor/CurvilinearGrid.h ${PROJECT_SOURCE_DIR}/include/vapor/UnstructuredGrid.h ${PROJECT_SOURCE_DIR}/include/vapor/UnstructuredGrid2D.h ${PROJECT_SOURCE_DIR}/include/vapor/UnstructuredGrid3D.h ${PROJECT_SOURCE_DIR}/include/vapor/UnstructuredGridLayered.h ${PROJECT_SOURCE_DIR}/include/vapor/ArbitrarilyOrientedRegularGrid.h ${PROJECT_SOURCE_DIR}/include/vapor/NetCDFSimple.h ${PROJECT_SOURCE_DIR}/include/vapor/NetCDFCollection.h ${PROJECT_SOURCE_DIR}/include/vapor/NetCDFCFCollection.h ${PROJECT_SOURCE_DIR}/include/vapor/BOVCollection.h ${PROJECT_SOURCE_DIR}/include/vapor/UDUnitsClass.h ${PROJECT_SOURCE_DIR}/include/vapor/Proj4API.h ${PROJECT_SOURCE_DIR}/include/vapor/DC.h ${PROJECT_SOURCE_DIR}/include/vapor/DCWRF.h ${PROJECT_SOURCE_DIR}/include/vapor/DCCF.h ${PROJECT_SOURCE_DIR}/include/vapor/DCBOV.h ${PROJECT_SOURCE_DIR}/include/vapor/DCMPAS.h ${PROJECT_SOURCE_DIR}/include/vapor/DCP.h ${PROJECT_SOURCE_DIR}/include/vapor/DCRAM.h ${PROJECT_SOURCE_DIR}/include/vapor/DCMelanie.h ${PROJECT_SOURCE_DIR}/include/vapor/VDC.h ${PROJECT_SOURCE_DIR}/include/vapor/VDCNetCDF.h ${PROJECT_SOURCE_DIR}/include/vapor/DataMgr.h ${PROJECT_SOURCE_DIR}/include/vapor/PythonDataMgr.h ${PROJECT_SOURCE_DIR}/include/vapor/DataMgrUtils.h ${PROJECT_SOURCE_DIR}/include/vapor/GeoUtil.h ${PROJECT_SOURCE_DIR}/include/vapor/vizutil.h ${PROJECT_SOURCE_DIR}/include/vapor/KDTreeRG.h ${PROJECT_SOURCE_DIR}/include/vapor/VDC_c.h ${PROJECT_SOURCE_DIR}/include/vapor/DerivedVar.h ${PROJECT_SOURCE_DIR}/include/vapor/DerivedParticleDensity.h ${PROJECT_SOURCE_DIR}/include/vapor/DerivedVarMgr.h ${PROJECT_SOURCE_DIR}/include/vapor/DCUtils.h ${PROJECT_SOURCE_DIR}/include/vapor/QuadTreeRectangle.hpp ${PROJECT_SOURCE_DIR}/include/vapor/QuadTreeRectangleP.h ${PROJECT_SOURCE_DIR}/include/vapor/OpenMPSupport.h ${PROJECT_SOURCE_DIR}/include/vapor/DCUGRID.h ${PROJECT_SOURCE_DIR}/include/vapor/UnstructuredGridCoordless.h ${PROJECT_SOURCE_DIR}/include/vapor/SetHDF5PluginPath.h ) add_library (vdc SHARED ${SRC} ${HEADERS}) if( USE_OMP ) target_compile_options( vdc PUBLIC ${OpenMP_CXX_FLAGS} ) target_compile_definitions (vdc PUBLIC USE_OMP) target_link_libraries (vdc PUBLIC OpenMP::OpenMP_CXX) elseif( NOT WIN32 ) target_compile_options( vdc PUBLIC "-Wno-unknown-pragmas" ) endif() target_link_libraries (vdc PUBLIC common wasp ${UDUNITS2} ${PROJ}) add_definitions (-DVDF_EXPORTS) OpenMPInstall ( TARGETS vdc DESTINATION ${INSTALL_LIB_DIR} COMPONENT Libraries ) install ( FILES ${HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR} COMPONENT Libraries ) ================================================ FILE: lib/vdc/ConstantGrid.cpp ================================================ #include #include "vapor/ConstantGrid.h" using VAPoR::ConstantGrid; ConstantGrid::ConstantGrid(float v, size_t d) : _value(v), _topologyDim(d) {} float ConstantGrid::GetConstantValue() const { return _value; } float ConstantGrid::GetValue(const VAPoR::CoordType &coords) const { return _value; } float ConstantGrid::GetValueNearestNeighbor(const VAPoR::CoordType &coords) const { return _value; } float ConstantGrid::GetValueLinear(const VAPoR::CoordType &coords) const { return _value; } std::string ConstantGrid::GetType() const { std::string type("ConstantGrid"); return type; } size_t ConstantGrid::GetTopologyDim() const { return _topologyDim; } void ConstantGrid::GetUserExtentsHelper(VAPoR::CoordType &minu, VAPoR::CoordType &maxu) const { for (int i = 0; i < minu.size(); i++) { minu[i] = std::numeric_limits::lowest(); maxu[i] = std::numeric_limits::max(); } } bool ConstantGrid::InsideGrid(const VAPoR::CoordType &coords) const { return true; } VAPoR::DimsType ConstantGrid::GetCoordDimensions(size_t) const { return (VAPoR::DimsType{1, 1, 1}); } size_t ConstantGrid::GetGeometryDim() const { return 3; } const VAPoR::DimsType &ConstantGrid::GetNodeDimensions() const { return (GetDimensions()); } const size_t ConstantGrid::GetNumNodeDimensions() const { return (GetNumDimensions()); } const VAPoR::DimsType &ConstantGrid::GetCellDimensions() const { _duplicate = GetDimensions(); return _duplicate; } const size_t ConstantGrid::GetNumCellDimensions() const { return (GetNumDimensions()); } bool ConstantGrid::GetIndicesCell(const VAPoR::CoordType &coords, VAPoR::DimsType &indices) const { return false; } bool ConstantGrid::GetCellNodes(const VAPoR::DimsType &cindices, std::vector &nodes) const { return false; } bool ConstantGrid::GetCellNeighbors(const VAPoR::DimsType &cindices, std::vector &cells) const { return false; } bool ConstantGrid::GetNodeCells(const VAPoR::DimsType &cindices, std::vector &cells) const { return false; } size_t ConstantGrid::GetMaxVertexPerFace() const { return 0; } size_t ConstantGrid::GetMaxVertexPerCell() const { return 0; } VAPoR::Grid::ConstCoordItr ConstantGrid::ConstCoordBegin() const { return VAPoR::Grid::ConstCoordItr(); } VAPoR::Grid::ConstCoordItr ConstantGrid::ConstCoordEnd() const { return VAPoR::Grid::ConstCoordItr(); } ================================================ FILE: lib/vdc/CurvilinearGrid.cpp ================================================ #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include #include using namespace std; using namespace VAPoR; void CurvilinearGrid::_curvilinearGrid(const RegularGrid &xrg, const RegularGrid &yrg, const RegularGrid &zrg, const vector &zcoords, std::shared_ptr qtr) { _zcoords.clear(); _xrg = xrg; _yrg = yrg; _zrg = zrg; _zcoords = zcoords; GetUserExtentsHelper(_minu, _maxu); _qtr = qtr; if (!_qtr) { _qtr = _makeQuadTreeRectangle(); } } CurvilinearGrid::CurvilinearGrid(const DimsType &dims, const DimsType &bs, const vector &blks, const RegularGrid &xrg, const RegularGrid &yrg, const vector &zcoords, std::shared_ptr qtr) : StructuredGrid(dims, bs, blks) { // Only support 2D X & Y coordinates currently. I.e. only support // "layered" curvilinear grids // VAssert(xrg.GetNumDimensions() == 2); VAssert(yrg.GetNumDimensions() == 2); VAssert(zcoords.size() == 0 || zcoords.size() == dims[2]); _terrainFollowing = false; _curvilinearGrid(xrg, yrg, RegularGrid(), zcoords, qtr); } CurvilinearGrid::CurvilinearGrid(const DimsType &dims, const DimsType &bs, const vector &blks, const RegularGrid &xrg, const RegularGrid &yrg, const RegularGrid &zrg, std::shared_ptr qtr) : StructuredGrid(dims, bs, blks) { // Only support 2D X & Y coordinates currently. I.e. only support // "layered" curvilinear grids // VAssert(xrg.GetNumDimensions() == 2); VAssert(yrg.GetNumDimensions() == 2); VAssert(zrg.GetNumDimensions() == 3); _terrainFollowing = true; _curvilinearGrid(xrg, yrg, zrg, vector(), qtr); } CurvilinearGrid::CurvilinearGrid(const DimsType &dims, const DimsType &bs, const vector &blks, const RegularGrid &xrg, const RegularGrid &yrg, std::shared_ptr qtr) : StructuredGrid(dims, bs, blks) { // Only support 2D X & Y coordinates currently. I.e. only support // "layered" curvilinear grids // VAssert(xrg.GetNumDimensions() == 2); VAssert(yrg.GetNumDimensions() == 2); _terrainFollowing = false; _curvilinearGrid(xrg, yrg, RegularGrid(), vector(), qtr); } CurvilinearGrid::CurvilinearGrid(const vector &dimsv, const vector &bsv, const vector &blks, const RegularGrid &xrg, const RegularGrid &yrg, const vector &zcoords, std::shared_ptr qtr) : StructuredGrid(dimsv, bsv, blks) { VAssert(dimsv.size() == 2 || dimsv.size() == 3); VAssert(bsv.size() == dimsv.size()); // Only support 2D X & Y coordinates currently. I.e. only support // "layered" curvilinear grids // VAssert(xrg.GetNumDimensions() == 2); VAssert(yrg.GetNumDimensions() == 2); VAssert(zcoords.size() == 0 || zcoords.size() == dimsv[2]); _terrainFollowing = false; DimsType dims = {1, 1, 1}; DimsType bs = {1, 1, 1}; CopyToArr3(dimsv, dims); CopyToArr3(bsv, bs); _curvilinearGrid(xrg, yrg, RegularGrid(), zcoords, qtr); } CurvilinearGrid::CurvilinearGrid(const vector &dimsv, const vector &bsv, const vector &blks, const RegularGrid &xrg, const RegularGrid &yrg, const RegularGrid &zrg, std::shared_ptr qtr) : StructuredGrid(dimsv, bsv, blks) { VAssert(dimsv.size() == 3); VAssert(bsv.size() == dimsv.size()); _terrainFollowing = true; DimsType dims = {1, 1, 1}; DimsType bs = {1, 1, 1}; CopyToArr3(dimsv, dims); CopyToArr3(bsv, bs); _curvilinearGrid(xrg, yrg, zrg, vector(), qtr); } CurvilinearGrid::CurvilinearGrid(const vector &dimsv, const vector &bsv, const vector &blks, const RegularGrid &xrg, const RegularGrid &yrg, std::shared_ptr qtr) : StructuredGrid(dimsv, bsv, blks) { VAssert(dimsv.size() == 2); VAssert(bsv.size() == dimsv.size()); // Only support 2D X & Y coordinates currently. I.e. only support // "layered" curvilinear grids // VAssert(xrg.GetNumDimensions() == 2); VAssert(yrg.GetNumDimensions() == 2); _terrainFollowing = false; DimsType dims = {1, 1, 1}; DimsType bs = {1, 1, 1}; CopyToArr3(dimsv, dims); CopyToArr3(bsv, bs); _curvilinearGrid(xrg, yrg, RegularGrid(), vector(), qtr); } DimsType CurvilinearGrid::GetCoordDimensions(size_t dim) const { DimsType dims = {1, 1, 1}; if (dim == 0) { dims = _xrg.GetDimensions(); } else if (dim == 1) { dims = _yrg.GetDimensions(); } else if (dim == 2) { if (_terrainFollowing) { dims = _zrg.GetDimensions(); } } return (dims); } void CurvilinearGrid::GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const { DimsType cMin; ClampIndex(min, cMin); DimsType cMax; ClampIndex(max, cMax); for (int i = 0; i < GetGeometryDim(); i++) { VAssert(cMin[i] <= cMax[i]); } for (int i = 0; i < minu.size(); i++) { minu[i] = 0.0; maxu[i] = 0.0; } // Get the horiztonal (X & Y) extents by visiting every point // on a single plane (horizontal coordinates are constant over Z). // vector min2d = {cMin[0], cMin[1]}; vector max2d = {cMax[0], cMax[1]}; float xrange[2], yrange[2]; _xrg.GetRange(min2d, max2d, xrange); _yrg.GetRange(min2d, max2d, yrange); minu[0] = xrange[0]; minu[1] = yrange[0]; maxu[0] = xrange[1]; maxu[1] = yrange[1]; // We're done if 2D grid // if (GetGeometryDim() == 2) return; if (_terrainFollowing) { float zrange[2]; _zrg.GetRange(cMin, cMax, zrange); minu[2] = zrange[0]; maxu[2] = zrange[1]; } else { minu[2] = _zcoords[cMin[2]]; maxu[2] = _zcoords[cMax[2]]; } } void CurvilinearGrid::GetUserCoordinates(const DimsType &indices, CoordType &coords) const { DimsType cIndices; ClampIndex(indices, cIndices); coords[0] = _xrg.AccessIJK(cIndices[0], cIndices[1]); coords[1] = _yrg.AccessIJK(cIndices[0], cIndices[1]); if (GetGeometryDim() < 3) return; if (_terrainFollowing) { coords[2] = _zrg.AccessIJK(cIndices[0], cIndices[1], cIndices[2]); } else { coords[2] = _zcoords[cIndices[2]]; } } bool CurvilinearGrid::GetIndicesCell(const CoordType &coords, DimsType &indices) const { // Clamp coordinates on periodic boundaries to grid extents // CoordType cCoords; ClampCoord(coords, cCoords); double x = cCoords[0]; double y = cCoords[1]; double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0; double lambda[4], zwgt[2]; size_t i, j, k; bool inside = _insideGrid(x, y, z, i, j, k, lambda, zwgt); if (!inside) return (false); indices[0] = i; indices[1] = j; if (GetGeometryDim() == 2) return (true); indices[2] = k; return (true); } bool CurvilinearGrid::InsideGrid(const CoordType &coords) const { // Clamp coordinates on periodic boundaries to reside within the // grid extents // CoordType cCoords; ClampCoord(coords, cCoords); // Do a quick check to see if the point is completely outside of // the grid bounds. // VAssert(GetGeometryDim() <= 3); for (int i = 0; i < GetGeometryDim(); i++) { if (cCoords[i] < _minu[i] || cCoords[i] > _maxu[i]) return (false); } double lambda[4], zwgt[2]; size_t i, j, k; // not used double x = cCoords[0]; double y = cCoords[1]; double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0; bool inside = _insideGrid(x, y, z, i, j, k, lambda, zwgt); return (inside); } CurvilinearGrid::ConstCoordItrCG::ConstCoordItrCG(const CurvilinearGrid *cg, bool begin) : ConstCoordItrAbstract() { _cg = cg; auto dims = _cg->GetDimensions(); _index = {0, 0, 0}; _coords = {0.0, 0.0, 0.0}; _terrainFollowing = _cg->_terrainFollowing; if (begin) { _xCoordItr = _cg->_xrg.cbegin(); _yCoordItr = _cg->_yrg.cbegin(); if (_terrainFollowing) { _zCoordItr = _cg->_zrg.cbegin(); } } else { _xCoordItr = _cg->_xrg.cend(); _yCoordItr = _cg->_yrg.cend(); if (_terrainFollowing) { _zCoordItr = _cg->_zrg.cend(); } _index = {0, 0, dims[dims.size() - 1]}; return; } _coords[0] = *_xCoordItr; _coords[1] = *_yCoordItr; if (_terrainFollowing) { _coords[2] = *_zCoordItr; } else { if (_cg->_zcoords.size()) _coords[2] = _cg->_zcoords[0]; } } CurvilinearGrid::ConstCoordItrCG::ConstCoordItrCG(const ConstCoordItrCG &rhs) : ConstCoordItrAbstract() { _cg = rhs._cg; _index = rhs._index; _coords = rhs._coords; _xCoordItr = rhs._xCoordItr; _yCoordItr = rhs._yCoordItr; if (rhs._terrainFollowing) { _zCoordItr = rhs._zCoordItr; } _terrainFollowing = rhs._terrainFollowing; } CurvilinearGrid::ConstCoordItrCG::ConstCoordItrCG() : ConstCoordItrAbstract() { _cg = NULL; _index = {0, 0, 0}; _coords = {0.0, 0.0, 0.0}; } void CurvilinearGrid::ConstCoordItrCG::next() { auto dims = _cg->GetDimensions(); _index[0]++; ++_xCoordItr; ++_yCoordItr; if (_terrainFollowing) { ++_zCoordItr; } if (_index[0] < dims[0]) { _coords[0] = *_xCoordItr; _coords[1] = *_yCoordItr; if (_terrainFollowing) { _coords[2] = *_zCoordItr; } return; } _index[0] = 0; _index[1]++; if (_index[1] < dims[1]) { _coords[0] = *_xCoordItr; _coords[1] = *_yCoordItr; if (_terrainFollowing) { _coords[2] = *_zCoordItr; } return; } _index[1] = 0; _index[2]++; if (_index[2] < dims[2]) { _xCoordItr = _cg->_xrg.cbegin(); _yCoordItr = _cg->_yrg.cbegin(); _coords[0] = *_xCoordItr; _coords[1] = *_yCoordItr; if (_terrainFollowing) { _coords[2] = *_zCoordItr; } else { _coords[2] = _cg->_zcoords[_index[2]]; } return; } _index = {0, 0, dims[dims.size() - 1]}; // last index } void CurvilinearGrid::ConstCoordItrCG::next(const long &offset) { auto dims = _cg->GetDimensions(); auto ndims = _cg->GetNumDimensions(); if (!ndims) return; long maxIndexL = Wasp::VProduct(dims.data(), dims.size()) - 1; long newIndexL = Wasp::LinearizeCoords(_index.data(), dims.data(), dims.size()) + offset; if (newIndexL < 0) { newIndexL = 0; } if (newIndexL > maxIndexL) { _index = {0, 0, dims[dims.size() - 1]}; return; } size_t index2DL = _index[1] * dims[0] + _index[0]; _index = {0, 0, 0}; Wasp::VectorizeCoords(newIndexL, dims.data(), _index.data(), dims.size()); VAssert(_index[1] * dims[0] + _index[0] >= index2DL); size_t offset2D = (_index[1] * dims[0] + _index[0]) - index2DL; _xCoordItr += offset2D; _yCoordItr += offset2D; _coords[0] = *_xCoordItr; _coords[1] = *_yCoordItr; if (_terrainFollowing) { _zCoordItr += offset; _coords[2] = *_zCoordItr; } else { _coords[2] = _cg->_zcoords[_index[2]]; } } float CurvilinearGrid::GetValueNearestNeighbor(const CoordType &coords) const { // Clamp coordinates on periodic boundaries to grid extents // CoordType cCoords; ClampCoord(coords, cCoords); double lambda[4], zwgt[2]; size_t i, j, k; double x = cCoords[0]; double y = cCoords[1]; double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0; bool inside = _insideGrid(x, y, z, i, j, k, lambda, zwgt); if (!inside) return (GetMissingValue()); // Find closest point within face // double maxl = lambda[0]; int maxidx = 0; for (int idx = 1; idx < 4; idx++) { if (lambda[idx] > maxl) { maxl = lambda[idx]; maxidx = idx; } } if (maxidx == 1) { i++; } else if (maxidx == 2) { i++; j++; } else if (maxidx == 3) { j++; } if (zwgt[1] > zwgt[0]) k++; return (AccessIJK(i, j, k)); } namespace { float interpolateQuad(const float values[4], const double lambda[4], float mv) { // Special handling for any missing values // if (std::any_of(values, values + 4, [&mv](float v) { return (mv == v); })) { double lambda0[] = {lambda[0], lambda[1], lambda[2], lambda[3]}; float values0[] = {values[0], values[1], values[2], values[3]}; // Find missing values. Zero out weight // double wTotal = 0.0; int nMissing = 0; for (int i = 0; i < 4; i++) { if (values0[i] == mv) { lambda0[i] = 0.0; values0[i] = 0.0; nMissing++; } else { wTotal += lambda0[i]; } } if (nMissing == 4) return (mv); if (wTotal == 0.0) return (mv); // Re-normalize weights if we have missing values // if (nMissing) { wTotal = 1.0 / wTotal; for (int i = 0; i < 4; i++) { lambda0[i] *= wTotal; } } float v = 0.0; for (int i = 0; i < 4; i++) { v += values0[i] * lambda0[i]; } return (v); } else { float v = 0.0; for (int i = 0; i < 4; i++) { v += values[i] * lambda[i]; } return (v); } } }; // namespace float CurvilinearGrid::GetValueLinear(const CoordType &coords) const { // Clamp coordinates on periodic boundaries to grid extents // CoordType cCoords; ClampCoord(coords, cCoords); // Get Wachspress coordinates for horizontal weights, and // simple linear interpolation weights for vertical axis. _insideGrid // handlese case where grid is 2D. I.e. if 2d then zwgt[0] == 1 && // zwgt[1] = 0.0 // double lambda[4], zwgt[2]; size_t i, j, k; double x = cCoords[0]; double y = cCoords[1]; double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0; bool inside = _insideGrid(x, y, z, i, j, k, lambda, zwgt); float mv = GetMissingValue(); if (!inside) return (mv); // Use Wachspress coordinates as weights to do linear interpolation // along XY plane // auto dims = GetDimensions(); VAssert(i < dims[0] - 1); VAssert(j < dims[1] - 1); if (GetNumDimensions() > 2) VAssert(k < dims[2]); float v0s[] = {AccessIJK(i, j, k), AccessIJK(i + 1, j, k), AccessIJK(i + 1, j + 1, k), AccessIJK(i, j + 1, k)}; float v0 = interpolateQuad(v0s, lambda, mv); if (GetGeometryDim() == 2 || dims[2] < 2) return (v0); if (v0 == mv && zwgt[0] != 0.0) return (mv); float v1s[] = {AccessIJK(i, j, k + 1), AccessIJK(i + 1, j, k + 1), AccessIJK(i + 1, j + 1, k + 1), AccessIJK(i, j + 1, k + 1)}; float v1 = interpolateQuad(v1s, lambda, mv); if (v1 == mv && zwgt[1] != 0.0) return (mv); // Linearly interpolate along Z axis // if (zwgt[0] == 0.0) return (v1); else if (zwgt[1] == 0.0) return (v0); else return (v0 * zwgt[0] + v1 * zwgt[1]); } void CurvilinearGrid::GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const { // Get the horiztonal (X & Y) extents by visiting every point // on a single plane (horizontal coordinates are constant over Z). // float xrange[2], yrange[2]; _xrg.GetRange(xrange); _yrg.GetRange(yrange); minu[0] = xrange[0]; minu[1] = yrange[0]; maxu[0] = xrange[1]; maxu[1] = yrange[1]; // We're done if 2D grid // if (GetGeometryDim() == 2) return; if (_terrainFollowing) { float zrange[2]; _zrg.GetRange(zrange); minu[2] = zrange[0]; maxu[2] = zrange[1]; } else { minu[2] = _zcoords[0]; maxu[2] = _zcoords[_zcoords.size() - 1]; } } bool CurvilinearGrid::_insideGridHelperStretched(double z, size_t &k, double zwgt[2]) const { // Now verify that Z coordinate of point is in grid, and find // its interpolation weights if so. // size_t kFound = 0; if (!Wasp::BinarySearchRange(_zcoords, z, kFound)) return (false); k = kFound; zwgt[0] = 1.0 - (z - _zcoords[k]) / (_zcoords[k + 1] - _zcoords[k]); zwgt[1] = 1.0 - zwgt[0]; return (true); } bool CurvilinearGrid::_insideGridHelperTerrain(double x, double y, double z, const size_t &i, const size_t &j, size_t &k, double zwgt[2]) const { // XZ and YZ cell sides are planar, but XY sides may not be. We divide // the XY faces into two triangles (changing hexahedrals into prims) // and figure out which triangle (prism) the point is in (first or // second). Then we search the stack of first (or second) prism in Z // // // Check if point is in "first" triangle (0,0), (1,0), (1,1) // double lambda[3]; double pt[] = {x, y}; DimsType iv = {i, i + 1, i + 1}; DimsType jv = {j, j, j + 1}; double tverts0[] = {_xrg.AccessIJK(iv[0], jv[0], 0), _yrg.AccessIJK(iv[0], jv[0], 0), _xrg.AccessIJK(iv[1], jv[1], 0), _yrg.AccessIJK(iv[1], jv[1], 0), _xrg.AccessIJK(iv[2], jv[2], 0), _yrg.AccessIJK(iv[2], jv[2], 0)}; bool inside = VAPoR::BarycentricCoordsTri(tverts0, pt, lambda); if (!inside) { // Not in first triangle. // Now check if point is in "second" triangle (0,0), (1,1), (0,1) // iv = {i, i + 1, i}; jv = {j, j + 1, j + 1}; double tverts1[] = {_xrg.AccessIJK(iv[0], jv[0], 0), _yrg.AccessIJK(iv[0], jv[0], 0), _xrg.AccessIJK(iv[1], jv[1], 0), _yrg.AccessIJK(iv[1], jv[1], 0), _xrg.AccessIJK(iv[2], jv[2], 0), _yrg.AccessIJK(iv[2], jv[2], 0)}; inside = VAPoR::BarycentricCoordsTri(tverts1, pt, lambda); if (!inside) return (false); } float z0, z1; // Find k index of cell containing z. Already know i and j indices // size_t nz = GetDimensions()[2]; vector zcoords(nz); for (int kk = 0; kk < nz; kk++) { // Interpolate Z coordinate across triangle // float zk = _zrg.AccessIJK(iv[0], jv[0], kk) * lambda[0] + _zrg.AccessIJK(iv[1], jv[1], kk) * lambda[1] + _zrg.AccessIJK(iv[2], jv[2], kk) * lambda[2]; zcoords[kk] = zk; } if (!Wasp::BinarySearchRange(zcoords, z, k)) return (false); z0 = zcoords[k]; z1 = k < nz - 1 ? zcoords[k + 1] : z0; zwgt[0] = 1.0 - (z - z0) / (z1 - z0); zwgt[1] = 1.0 - zwgt[0]; return (true); } bool CurvilinearGrid::_insideFace(const DimsType &face, double pt[2], double lambda[4], vector &nodes) const { CoordType verts[4]; // space for 4 vertices with 3D user coordinates size_t gDim = GetGeometryDim(); bool ok = GetCellNodes(face, nodes); VAssert(ok); // For 3D data GetCellNodes returns 3D cells. We only need the 2D // bottom face (all cells in a vertical column have same horizontal // coordinates // for layered 3D data) // size_t n = nodes.size(); if (gDim > 2 && n == 8) n /= 2; VAssert(n == 4); // Get X and Y coordinates for each vertex making up the face // for (int i = 0; i < n; i++) { GetUserCoordinates(nodes[i], verts[i]); } // The following functions operate on packed, raw arrays // double verts2d[] = {verts[0][0], verts[0][1], verts[1][0], verts[1][1], verts[2][0], verts[2][1], verts[3][0], verts[3][1]}; if (!Grid::PointInsideBoundingRectangle(pt, verts2d, 4)) { return (false); } bool ret = WachspressCoords2D(verts2d, pt, 4, lambda); return ret; } // Search for a point inside the grid. If the point is inside return true, // and provide the Wachspress weights/coordinates for the point within // the XY quadrilateral cell containing the point in XY, and the linear // interpolation weights/coordinates along Z. If the grid is 2D then // zwgt[0] == 1.0, and zwgt[1] == 0.0. If the point is outside of the // grid the values of 'lambda', and 'zwgt' are not defined // bool CurvilinearGrid::_insideGrid(double x, double y, double z, size_t &i, size_t &j, size_t &k, double lambda[4], double zwgt[2]) const { for (int l = 0; l < 4; l++) lambda[l] = 0.0; for (int l = 0; l < 2; l++) zwgt[l] = 0.0; i = j = k = 0; // Find the indices for the faces that might contain the point // vector face_indices; _qtr->GetPayloadContained(x, y, face_indices); bool inside = false; double pt[] = {x, y}; vector nodes(8); for (int ii = 0; ii < face_indices.size(); ii++) { if (_insideFace(face_indices[ii], pt, lambda, nodes)) { i = face_indices[ii][0]; j = face_indices[ii][1]; inside = true; break; } } if (!inside) return (false); if (GetGeometryDim() == 2) { zwgt[0] = 1.0; zwgt[1] = 0.0; return (true); } if (_terrainFollowing) { return (_insideGridHelperTerrain(x, y, z, i, j, k, zwgt)); } else { return (_insideGridHelperStretched(z, k, zwgt)); } } std::shared_ptr CurvilinearGrid::_makeQuadTreeRectangle() const { const DimsType &dims = GetCellDimensions(); size_t reserve_size = dims[0] * dims[1]; CoordType minu, maxu; GetUserExtents(minu, maxu); std::shared_ptr qtr = std::make_shared((float)minu[0], (float)minu[1], (float)maxu[0], (float)maxu[1], 12, reserve_size); qtr->Insert(this, dims[0] * dims[1]); return (qtr); } ================================================ FILE: lib/vdc/DC.cpp ================================================ #include "vapor/VAssert.h" #include #include "vapor/DC.h" using namespace VAPoR; namespace { string join(const vector &v, string separator) { string s; for (int i = 0; i < (int)v.size() - 1; i++) { s += v[i]; s += separator; } if (v.size()) { s += v[v.size() - 1]; } return (s); } #ifdef UNUSED_FUNCTION // Product of elements in a vector // size_t vproduct(vector a) { size_t ntotal = 1; for (int i = 0; i < a.size(); i++) ntotal *= a[i]; return (ntotal); } #endif }; // namespace DC::Attribute::Attribute(string name, XType type, const vector &values) { _name = name; _type = type; _values.clear(); Attribute::SetValues(values); } void DC::Attribute::SetValues(const vector &values) { _values.clear(); vector dvec; for (int i = 0; i < values.size(); i++) { dvec.push_back((double)values[i]); } DC::Attribute::SetValues(dvec); } DC::Attribute::Attribute(string name, XType type, const vector &values) { _name = name; _type = type; _values.clear(); Attribute::SetValues(values); } void DC::Attribute::SetValues(const vector &values) { _values.clear(); for (int i = 0; i < values.size(); i++) { podunion pod; if (_type == FLOAT) { pod.f = (float)values[i]; } else if (_type == DOUBLE) { pod.d = (double)values[i]; } else if (_type == INT32) { pod.i = (int)values[i]; } else if (_type == INT64) { pod.l = (int)values[i]; } else if (_type == TEXT) { pod.c = (char)values[i]; } _values.push_back(pod); } } DC::Attribute::Attribute(string name, XType type, const vector &values) { _name = name; _type = type; _values.clear(); Attribute::SetValues(values); } void DC::Attribute::SetValues(const vector &values) { _values.clear(); vector lvec; for (int i = 0; i < values.size(); i++) { lvec.push_back((long)values[i]); } DC::Attribute::SetValues(lvec); } DC::Attribute::Attribute(string name, XType type, const vector &values) { _name = name; _type = type; _values.clear(); Attribute::SetValues(values); } void DC::Attribute::SetValues(const vector &values) { _values.clear(); for (int i = 0; i < values.size(); i++) { podunion pod; if (_type == FLOAT) { pod.f = (float)values[i]; } else if (_type == DOUBLE) { pod.d = (double)values[i]; } else if (_type == INT32) { pod.i = (int)values[i]; } else if (_type == INT64) { pod.l = (long)values[i]; } else if (_type == TEXT) { pod.c = (char)values[i]; } _values.push_back(pod); } } DC::Attribute::Attribute(string name, XType type, const string &values) { _name = name; _type = type; _values.clear(); Attribute::SetValues(values); } void DC::Attribute::SetValues(const string &values) { _values.clear(); for (int i = 0; i < values.size(); i++) { podunion pod; if (_type == FLOAT) { pod.f = (float)values[i]; } else if (_type == DOUBLE) { pod.d = (double)values[i]; } else if (_type == INT32) { pod.i = (int)values[i]; } else if (_type == INT64) { pod.l = (long)values[i]; } else if (_type == TEXT) { pod.c = (char)values[i]; } _values.push_back(pod); } } void DC::Attribute::GetValues(vector &values) const { values.clear(); vector dvec; DC::Attribute::GetValues(dvec); for (int i = 0; i < dvec.size(); i++) { values.push_back((float)dvec[i]); } } void DC::Attribute::GetValues(vector &values) const { values.clear(); for (int i = 0; i < _values.size(); i++) { podunion pod = _values[i]; if (_type == FLOAT) { values.push_back((double)pod.f); } else if (_type == DOUBLE) { values.push_back((double)pod.d); } else if (_type == INT32) { values.push_back((double)pod.i); } else if (_type == INT64) { values.push_back((double)pod.l); } else if (_type == TEXT) { values.push_back((double)pod.c); } } } void DC::Attribute::GetValues(vector &values) const { values.clear(); vector lvec; DC::Attribute::GetValues(lvec); for (int i = 0; i < lvec.size(); i++) { values.push_back((int)lvec[i]); } } void DC::Attribute::GetValues(vector &values) const { values.clear(); for (int i = 0; i < _values.size(); i++) { podunion pod = _values[i]; if (_type == FLOAT) { values.push_back((long)pod.f); } else if (_type == DOUBLE) { values.push_back((long)pod.d); } else if (_type == INT32) { values.push_back((long)pod.i); } else if (_type == INT64) { values.push_back((long)pod.l); } else if (_type == TEXT) { values.push_back((long)pod.c); } } } void DC::Attribute::GetValues(string &values) const { values.clear(); for (int i = 0; i < _values.size(); i++) { podunion pod = _values[i]; if (_type == FLOAT) { values += (char)pod.f; } else if (_type == DOUBLE) { values += (char)pod.d; } else if (_type == INT32) { values += (char)pod.i; } else if (_type == INT64) { values += (char)pod.l; } else if (_type == TEXT) { values += (char)pod.c; } } } DC::BaseVar::BaseVar(string name, string units, XType type, std::vector periodic) : _name(name), _units(units), _type(type), _periodic(periodic) { _wname = ""; _cratios.push_back(1); } void DC::Mesh::_Mesh(string name, std::vector coord_vars, int max_nodes_per_face, int max_faces_per_node, Mesh::Type mtype) { _name.clear(); _dim_names.clear(); _coord_vars.clear(); _max_nodes_per_face = 1; _max_faces_per_node = 1; _node_dim_name.clear(); _face_dim_name.clear(); _layers_dim_name.clear(); _face_node_var.clear(); _node_face_var.clear(); _node_face_var.clear(); _face_edge_var.clear(); _face_face_var.clear(); _edge_dim_name.clear(); _edge_node_var.clear(); _edge_face_var.clear(); _mtype = STRUCTURED; _name = name; _coord_vars = coord_vars; _max_nodes_per_face = max_nodes_per_face; _max_faces_per_node = max_faces_per_node; _mtype = mtype; } DC::Mesh::Mesh(std::string name, std::vector dim_names, std::vector coord_vars) { VAssert(coord_vars.size() >= dim_names.size()); _Mesh(name, coord_vars, 4, 4, STRUCTURED); if (_name.empty()) { _name = MakeMeshName(dim_names); } _dim_names = dim_names; } DC::Mesh::Mesh(std::string name, size_t max_nodes_per_face, size_t max_faces_per_node, std::string node_dim_name, std::string face_dim_name, std::vector coord_vars, std::string face_node_var, std::string node_face_var) { VAssert(coord_vars.size() >= 2); _Mesh(name, coord_vars, max_nodes_per_face, max_faces_per_node, UNSTRUC_2D); _node_dim_name = node_dim_name; _face_dim_name = face_dim_name; _face_node_var = face_node_var; _node_face_var = node_face_var; _dim_names.push_back(node_dim_name); } DC::Mesh::Mesh(std::string name, size_t max_nodes_per_face, size_t max_faces_per_node, std::string node_dim_name, std::string face_dim_name, std::string layers_dim_name, std::vector coord_vars, std::string face_node_var, std::string node_face_var) { VAssert(coord_vars.size() == 3); _Mesh(name, coord_vars, max_nodes_per_face, max_faces_per_node, UNSTRUC_LAYERED); _node_dim_name = node_dim_name; _face_dim_name = face_dim_name; _layers_dim_name = layers_dim_name; _face_node_var = face_node_var; _node_face_var = node_face_var; _dim_names.push_back(node_dim_name); _dim_names.push_back(layers_dim_name); } DC::Mesh::Mesh(std::string name, int max_nodes_per_face, int max_faces_per_node, std::string node_dim_name, std::string face_dim_name, std::vector coord_vars) { _Mesh(name, coord_vars, max_nodes_per_face, max_faces_per_node, UNSTRUC_3D); _node_dim_name = node_dim_name; _face_dim_name = face_dim_name; _dim_names.push_back(node_dim_name); } size_t DC::Mesh::GetTopologyDim() const { switch (_mtype) { case STRUCTURED: return (_dim_names.size()); break; case UNSTRUC_2D: return (2); break; case UNSTRUC_LAYERED: return (3); break; case UNSTRUC_3D: return (0); break; default: VAssert(false); return (0); break; } } string DC::Mesh::MakeMeshName(std::vector s) { return (join(s, "x")); } DC::DC() {} int DC::GetHyperSliceInfo(string varname, int level, std::vector &hslice_dims, size_t &nslice, long ts) { hslice_dims.clear(); nslice = 0; vector dims_at_level; vector dummy; int rc = GetDimLensAtLevel(varname, level, dims_at_level, dummy, ts); if (rc < 0) return (-1); if (dims_at_level.size() == 0) return (0); hslice_dims = dims_at_level; if (dims_at_level.size() == 1) { nslice = 1; return (0); } int dim = hslice_dims.size() - 1; hslice_dims[dim] = 1; nslice = dims_at_level[dim] / hslice_dims[dim]; return (0); } vector DC::GetDataVarNames(int ndim) const { vector names, allnames; allnames = GetDataVarNames(); for (int i = 0; i < allnames.size(); i++) { DataVar dvar; bool ok = GetDataVarInfo(allnames[i], dvar); if (!ok) continue; string mesh_name; mesh_name = dvar.GetMeshName(); Mesh mesh; ok = GetMesh(mesh_name, mesh); if (!ok) continue; size_t d = mesh.GetGeometryDim(); if (d == ndim) { names.push_back(allnames[i]); } } return (names); } bool DC::_getDataVarDimensions(string varname, bool spatial, vector &dimensions, long ts) const { dimensions.clear(); DataVar var; bool status = GetDataVarInfo(varname, var); if (!status) return (false); string mname = var.GetMeshName(); if (!mname.empty()) { ; // 0-d variable Mesh mesh; status = GetMesh(mname, mesh); if (!status) return (false); vector dimnames; if (mesh.GetMeshType() == Mesh::STRUCTURED) { dimnames = mesh.GetDimNames(); } else { switch (var.GetSamplingLocation()) { case Mesh::NODE: dimnames.push_back(mesh.GetNodeDimName()); break; case Mesh::EDGE: dimnames.push_back(mesh.GetEdgeDimName()); break; case Mesh::FACE: dimnames.push_back(mesh.GetFaceDimName()); break; case Mesh::VOLUME: VAssert(0 && "VOLUME cells not supported"); break; } if (mesh.GetMeshType() == Mesh::UNSTRUC_LAYERED) { dimnames.push_back(mesh.GetLayersDimName()); } } for (int i = 0; i < dimnames.size(); i++) { Dimension dim; status = GetDimension(dimnames[i], dim, ts); if (!status) return (false); dimensions.push_back(dim); } } // we're done if time dim isn't wanted // if (spatial) return (true); string tvar = var.GetTimeCoordVar(); if (!tvar.empty()) { vector timedims; status = _getCoordVarDimensions(tvar, false, timedims, ts); if (!status) return (false); VAssert(timedims.size() == 1); dimensions.push_back(timedims[0]); } return (true); } bool DC::_getCoordVarDimensions(string varname, bool spatial, vector &dimensions, long ts) const { dimensions.clear(); CoordVar var; bool status = GetCoordVarInfo(varname, var); if (!status) return (false); vector dimnames = var.GetDimNames(); for (int i = 0; i < dimnames.size(); i++) { Dimension dim; status = GetDimension(dimnames[i], dim, ts); if (!status) return (false); dimensions.push_back(dim); } // we're done if time dim isn't wanted // if (spatial) return (true); string timedim = var.GetTimeDimName(); if (!timedim.empty()) { Dimension dim; status = GetDimension(timedim, dim, ts); if (!status) return (false); dimensions.push_back(dim); } return (true); } bool DC::_getAuxVarDimensions(string varname, vector &dimensions, long ts) const { dimensions.clear(); AuxVar var; bool status = GetAuxVarInfo(varname, var); if (!status) return (false); vector dimnames = var.GetDimNames(); for (int i = 0; i < dimnames.size(); i++) { Dimension dim; status = GetDimension(dimnames[i], dim, ts); if (!status) return (false); dimensions.push_back(dim); } return (true); } vector DC::_getBlockSize() const { vector bs = getBlockSize(); while (bs.size() > 3) { bs.pop_back(); } return (bs); } int DC::_openVariableRead(size_t ts, string varname, int level, int lod) { return (openVariableRead(ts, varname, level, lod)); } int DC::_closeVariable(int fd) { return (closeVariable(fd)); } template int DC::_readSliceTemplate(int fd, T *slice) { vector dims_at_level; vector dummy; FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor: %d", fd); return (-1); } string varname = f->GetVarname(); int level = f->GetLevel(); int sliceNum = f->GetSlice(); int rc = GetDimLensAtLevel(varname, level, dims_at_level, dummy, f->GetTS()); if (rc < 0) return (rc); vector hslice_dims; size_t nslice; rc = GetHyperSliceInfo(varname, level, hslice_dims, nslice); if (rc < 0) return (rc); VAssert(hslice_dims.size() == dims_at_level.size()); if (sliceNum >= nslice) return (0); // Done reading; vector min; vector max; int dim = 0; for (; dim < hslice_dims.size() - 1; dim++) { min.push_back(0); max.push_back(hslice_dims[dim] - 1); }; min.push_back(sliceNum * hslice_dims[dim]); max.push_back(min[dim] + hslice_dims[dim] - 1); // Last slice is a partial read if not block-aligned // if (max[dim] >= dims_at_level[dim]) { max[dim] = dims_at_level[dim] - 1; } rc = ReadRegion(fd, min, max, slice); if (rc < 0) return (rc); sliceNum++; f->SetSlice(sliceNum); return (rc); } template int DC::_readTemplate(int fd, T *data) { vector dims_at_level; vector dummy; FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor: %d", fd); return (-1); } string varname = f->GetVarname(); int level = f->GetLevel(); int rc = GetDimLensAtLevel(varname, level, dims_at_level, dummy, f->GetTS()); if (rc < 0) return (rc); vector min, max; for (int i = 0; i < dims_at_level.size(); i++) { min.push_back(0); max.push_back(dims_at_level[i] - 1); } return (ReadRegion(fd, min, max, data)); } template int DC::_getVarTemplate(string varname, int level, int lod, T *data) { vector dims_at_level; vector dummy; size_t numts = GetNumTimeSteps(varname); T *ptr = data; for (size_t ts = 0; ts < numts; ts++) { int rc = GetDimLensAtLevel(varname, level, dims_at_level, dummy, ts); if (rc < 0) return (-1); size_t var_size = 1; for (int i = 0; i < dims_at_level.size(); i++) { var_size *= dims_at_level[i]; } rc = GetVar(ts, varname, level, lod, ptr); if (rc < 0) return (-1); ptr += var_size; } return (0); } template int DC::_getVarTemplate(string varname, int level, int lod, double *data); template int DC::_getVarTemplate(string varname, int level, int lod, float *data); template int DC::_getVarTemplate(string varname, int level, int lod, int *data); template int DC::_getVarTemplate(size_t ts, string varname, int level, int lod, T *data) { int fd = OpenVariableRead(ts, varname, level, lod); if (fd < 0) return (-1); int rc = Read(fd, data); if (rc < 0) { CloseVariable(fd); return (-1); } rc = CloseVariable(fd); return (rc); } template int DC::_getVarTemplate(size_t ts, string varname, int level, int lod, double *data); template int DC::_getVarTemplate(size_t ts, string varname, int level, int lod, float *data); template int DC::_getVarTemplate(size_t ts, string varname, int level, int lod, int *data); bool DC::GetVarDimensions(string varname, bool spatial, vector &dimensions, long ts) const { dimensions.clear(); if (IsDataVar(varname)) { return (_getDataVarDimensions(varname, spatial, dimensions, ts)); } else if (IsCoordVar(varname)) { return (_getCoordVarDimensions(varname, spatial, dimensions, ts)); } else if (IsAuxVar(varname)) { return (_getAuxVarDimensions(varname, dimensions, ts)); } else { return (false); } } bool DC::GetVarDimLens(string varname, bool spatial, vector &dimlens, long ts) const { dimlens.clear(); vector dims; bool status = DC::GetVarDimensions(varname, spatial, dims, ts); if (!status) return (status); for (int i = 0; i < dims.size(); i++) { dimlens.push_back(dims[i].GetLength()); } return (true); } bool DC::GetVarDimLens(string varname, vector &sdimlens, size_t &time_dimlen, long ts) const { sdimlens.clear(); time_dimlen = 0; vector dims; bool status = DC::GetVarDimensions(varname, false, dims, ts); if (!status) return (status); if (DC::IsTimeVarying(varname)) { time_dimlen = dims[dims.size() - 1].GetLength(); dims.pop_back(); } for (int i = 0; i < dims.size(); i++) { sdimlens.push_back(dims[i].GetLength()); } return (true); } bool DC::GetVarDimNames(string varname, bool spatial, vector &dimnames) const { dimnames.clear(); vector dims; bool status = DC::GetVarDimensions(varname, spatial, dims, 0); if (!status) return (status); for (int i = 0; i < dims.size(); i++) { dimnames.push_back(dims[i].GetName()); } return (true); } bool DC::GetVarDimNames(string varname, vector &sdimnames, string &time_dimname) const { sdimnames.clear(); time_dimname = ""; vector dims; bool status = DC::GetVarDimensions(varname, false, dims, 0); if (!status) return (status); if (DC::IsTimeVarying(varname)) { time_dimname = dims[dims.size() - 1].GetName(); dims.pop_back(); } for (int i = 0; i < dims.size(); i++) { sdimnames.push_back(dims[i].GetName()); } return (true); } size_t DC::GetVarTopologyDim(string varname) const { DataVar var; bool status = GetDataVarInfo(varname, var); if (!status) return (0); string mname = var.GetMeshName(); Mesh mesh; status = GetMesh(mname, mesh); if (!status) return (0); return (mesh.GetTopologyDim()); } size_t DC::GetVarGeometryDim(string varname) const { DataVar var; bool status = GetDataVarInfo(varname, var); if (!status) return (0); string mname = var.GetMeshName(); Mesh mesh; status = GetMesh(mname, mesh); if (!status) return (0); return (mesh.GetGeometryDim()); } bool DC::IsTimeVarying(string varname) const { if (IsAuxVar(varname)) return (false); // If var is a data variable and has a time coordinate variable defined // if (IsDataVar(varname)) { DataVar var; bool ok = GetDataVarInfo(varname, var); if (!ok) return (false); return (!var.GetTimeCoordVar().empty()); } // If var is a coordinate variable and it has a time dimension // if (IsCoordVar(varname)) { CoordVar var; bool ok = GetCoordVarInfo(varname, var); if (!ok) return (false); return (!var.GetTimeDimName().empty()); } return (false); } bool DC::IsCompressed(string varname) const { BaseVar var; bool ok = GetBaseVarInfo(varname, var); if (!ok) return (false); return (var.IsCompressed()); } int DC::GetNumTimeSteps(string varname) const { if (IsAuxVar(varname)) return (1); // If data variable get it's time coordinate variable if it exists // if (IsDataVar(varname)) { DataVar var; bool ok = GetDataVarInfo(varname, var); if (!ok) return (0); string time_coord_var = var.GetTimeCoordVar(); if (time_coord_var.empty()) return (1); varname = time_coord_var; } CoordVar var; bool ok = GetCoordVarInfo(varname, var); if (!ok) return (0); string time_dim_name = var.GetTimeDimName(); if (time_dim_name.empty()) return (1); DC::Dimension dim; ok = GetDimension(time_dim_name, dim, 0); if (!ok) return (0); return (dim.GetLength()); } vector DC::GetCRatios(string varname) const { DC::BaseVar var; bool status = GetBaseVarInfo(varname, var); if (!status) { return (vector(1, 1)); } return (var.GetCRatios()); } bool DC::GetVarCoordVars(string varname, bool spatial, std::vector &coord_vars) const { coord_vars.clear(); DataVar dvar; bool status = GetDataVarInfo(varname, dvar); if (!status) return (false); Mesh m; status = GetMesh(dvar.GetMeshName(), m); if (!status) return (false); coord_vars = m.GetCoordVars(); if (spatial) return (true); if (!dvar.GetTimeCoordVar().empty()) { coord_vars.push_back(dvar.GetTimeCoordVar()); } return (true); } bool DC::GetVarConnVars(string varname, string &face_node_var, string &node_face_var, string &face_edge_var, string &face_face_var, string &edge_node_var, string &edge_face_var) const { face_node_var.clear(); node_face_var.clear(); face_edge_var.clear(); face_face_var.clear(); edge_node_var.clear(); edge_face_var.clear(); DataVar dvar; bool status = GetDataVarInfo(varname, dvar); if (!status) return (false); Mesh m; status = GetMesh(dvar.GetMeshName(), m); if (!status) return (false); face_node_var = m.GetFaceNodeVar(); node_face_var = m.GetNodeFaceVar(); face_edge_var = m.GetFaceEdgeVar(); face_face_var = m.GetFaceFaceVar(); edge_node_var = m.GetEdgeNodeVar(); edge_face_var = m.GetEdgeFaceVar(); return (true); } size_t DC::GetNumDimensions(string varname) const { DataVar dvar; bool status = GetDataVarInfo(varname, dvar); if (status) { Mesh m; status = GetMesh(dvar.GetMeshName(), m); if (!status) return (0); return (m.GetDimNames().size()); } CoordVar cvar; status = GetCoordVarInfo(varname, cvar); if (status) return (cvar.GetDimNames().size()); AuxVar avar; status = GetAuxVarInfo(varname, avar); if (status) return (avar.GetDimNames().size()); return (0); } std::vector DC::GetTimeCoordVarNames() const { vector cvars = GetCoordVarNames(); vector timeCoordVars; for (int i = 0; i < cvars.size(); i++) { CoordVar cvar; bool status = GetCoordVarInfo(cvars[i], cvar); VAssert(status); if (cvar.GetAxis() == 3) { timeCoordVars.push_back(cvars[i]); } } return (timeCoordVars); } DC::FileTable::FileTable() { _table.clear(); } DC::FileTable::~FileTable() { for (int i = 0; i < _table.size(); i++) { if (_table[i]) delete _table[i]; _table[i] = NULL; } } int DC::FileTable::AddEntry(DC::FileTable::FileObject *obj) { // Try to re-use an existing entry; // for (int i = 0; i < _table.size(); i++) { if (!_table[i]) { _table[i] = obj; return (i); } } // Create new entry // _table.push_back(obj); return (_table.size() - 1); } DC::FileTable::FileObject *DC::FileTable::GetEntry(int fd) const { if (fd < 0) return (NULL); if (fd < _table.size()) return (_table[fd]); return (NULL); } void DC::FileTable::RemoveEntry(int fd) { if (fd < 0 || fd >= _table.size()) return; _table[fd] = NULL; } vector DC::FileTable::GetEntries() const { vector fds; for (int i = 0; i < _table.size(); i++) { if (_table[i]) { fds.push_back(i); } } return (fds); } bool DC::GetMeshDimLens(const string &mesh_name, std::vector &dims, long ts) const { dims.clear(); DC::Mesh mesh; bool status = GetMesh(mesh_name, mesh); if (!status) return (false); vector dimNames = mesh.GetDimNames(); for (int i = 0; i < dimNames.size(); i++) { DC::Dimension dimension; status = GetDimension(dimNames[i], dimension, ts); if (!status) return (false); dims.push_back(dimension.GetLength()); } return (true); } bool DC::GetMeshDimNames(const string &mesh_name, std::vector &dimnames) const { dimnames.clear(); DC::Mesh mesh; bool status = GetMesh(mesh_name, mesh); if (!status) return (false); dimnames = mesh.GetDimNames(); return (true); } namespace VAPoR { std::ostream &operator<<(std::ostream &o, const DC::Dimension &d) { o << " Dimension" << endl; o << " Name: " << d._name << endl; o << " Lengths:"; for (int i = 0; i < d._lengths.size(); i++) { o << " " << d._lengths[i]; } o << endl; return (o); } std::ostream &operator<<(std::ostream &o, const DC::Mesh &m) { o << " Mesh" << endl; o << " Name: " << m._name << endl; o << " DimNames:"; for (int i = 0; i < m._dim_names.size(); i++) { o << " " << m._dim_names[i]; } o << endl; o << " CoordVars:"; for (int i = 0; i < m._coord_vars.size(); i++) { o << " " << m._coord_vars[i]; } o << endl; o << " MaxNodesPerFace: " << m._max_nodes_per_face << endl; o << " MaxFacesPerNode: " << m._max_faces_per_node << endl; o << " NodeDimName: " << m._node_dim_name << endl; o << " FaceDimName: " << m._face_dim_name << endl; o << " LayersDimName: " << m._layers_dim_name << endl; o << " FaceNodeVar: " << m._face_node_var << endl; o << " NodeFaceVar: " << m._node_face_var << endl; o << " FaceEdgeVar: " << m._face_edge_var << endl; o << " FaceFaceVar: " << m._face_face_var << endl; o << " EdgeDimName: " << m._edge_dim_name << endl; o << " EdgeNodeVar: " << m._edge_node_var << endl; o << " EdgeFaceVar: " << m._edge_face_var << endl; o << " Mtype: " << m._mtype << endl; return (o); } std::ostream &operator<<(std::ostream &o, const DC::Attribute &a) { o << " Attribute:" << endl; o << " Name: " << a._name << endl; o << " Type: " << a._type << endl; o << " Values: "; for (int i = 0; i < a._values.size(); i++) { DC::Attribute::podunion p = a._values[i]; if (a._type == DC::FLOAT) { o << p.f; } else if (a._type == DC::DOUBLE) { o << p.d; } else if (a._type == DC::INT32) { o << p.i; } else if (a._type == DC::INT64) { o << p.l; } if (a._type == DC::TEXT) { o << p.c; } o << " "; } o << endl; return (o); } std::ostream &operator<<(std::ostream &o, const DC::BaseVar &var) { o << " BaseVar" << endl; o << " Name: " << var._name << endl; o << " Units: " << var._units << endl; o << " XType: " << var._type << endl; o << " Compressed: " << (var._cratios.size() > 0) << endl; o << " WName: " << var._wname << endl; o << " CRatios: "; for (int i = 0; i < var._cratios.size(); i++) { o << var._cratios[i] << " "; } o << endl; o << endl; o << " Periodic: "; for (int i = 0; i < var._periodic.size(); i++) { o << var._periodic[i] << " "; } o << endl; std::map::const_iterator itr; for (itr = var._atts.begin(); itr != var._atts.end(); ++itr) { o << itr->second; } return (o); } std::ostream &operator<<(std::ostream &o, const DC::CoordVar &var) { o << " CoordVar" << endl; o << " Axis: " << var._axis << endl; o << " Uniform: " << var._uniform << endl; o << (DC::BaseVar)var; return (o); } std::ostream &operator<<(std::ostream &o, const DC::DataVar &var) { o << " DataVar" << endl; o << " Mesh: " << var._mesh << endl; o << " TimeCoordVar: " << var._time_coord_var << endl; o << " Location: " << var._location << endl; o << " MaskVar: " << var._maskvar << endl; o << " HasMissing: " << var._has_missing << endl; o << " MissingValue: " << var._missing_value << endl; o << (DC::BaseVar)var; return (o); } }; // namespace VAPoR ================================================ FILE: lib/vdc/DCBOV.cpp ================================================ #include #include #include #include #include #include "vapor/VAssert.h" #include #ifdef _WINDOWS #define _USE_MATH_DEFINES #pragma warning(disable : 4251 4100) #endif #include #include #include #include #include using namespace VAPoR; using namespace std; DCBOV::DCBOV() : _bovCollection(nullptr) { _dimsMap.clear(); _coordVarsMap.clear(); _dataVarsMap.clear(); _meshMap.clear(); _coordVarKeys.clear(); } DCBOV::~DCBOV() { if (_bovCollection != nullptr) { delete _bovCollection; } } int DCBOV::initialize(const vector &paths, const std::vector &options) { if (_bovCollection != nullptr) delete _bovCollection; _bovCollection = new BOVCollection(); int rc = _bovCollection->Initialize(paths); if (rc < 0) { SetErrMsg("Failure reading .bov file"); return (-1); } // // Get the dimensions of the grid. // Initializes members: _dimsMap // _InitDimensions(); // Set up the coordinate variables // _InitCoordinates(); // Identify data and coordinate variables. Sets up members: // Initializes members: _dataVarsMap, _meshMap // _InitVars(); return (0); } void DCBOV::_InitDimensions() { _dimsMap.clear(); std::array dimnames = _bovCollection->GetSpatialDimensions(); std::array dimlens = _bovCollection->GetDataSize(); for (int i = 0; i < dimnames.size(); i++) { Dimension dim(dimnames[i], dimlens[i]); _dimsMap[dimnames[i]] = dim; } string timeDim = _bovCollection->GetTimeDimension(); size_t numTimes = _bovCollection->GetUserTimes().size(); Dimension dim(timeDim, numTimes); _dimsMap[timeDim] = dim; } void DCBOV::_InitCoordinates() { bool uniformHint = true; vector periodic(1, false); std::string units = "m"; std::array dims = _bovCollection->GetSpatialDimensions(); _coordVarsMap[dims[0]] = CoordVar(dims[0], units, DC::FLOAT, periodic, 0, uniformHint, {dims[0]}, ""); _coordVarsMap[dims[1]] = CoordVar(dims[1], units, DC::FLOAT, periodic, 1, uniformHint, {dims[1]}, ""); _coordVarsMap[dims[2]] = CoordVar(dims[2], units, DC::FLOAT, periodic, 2, uniformHint, {dims[2]}, ""); std::string timeDim = _bovCollection->GetTimeDimension(); _coordVarsMap[timeDim] = CoordVar(timeDim, "seconds", DC::FLOAT, vector(), 3, false, vector(), timeDim); } // Collect metadata for all data variables found in the CF data // set. Initialize the _dataVarsMap member // void DCBOV::_InitVars() { _dataVarsMap.clear(); _meshMap.clear(); vector periodic(3, false); std::array dimnames = _bovCollection->GetSpatialDimensions(); std::vector vars = _bovCollection->GetDataVariableNames(); DC::XType format = _bovCollection->GetDataFormat(); std::string timeCoordVar = _bovCollection->GetTimeDimension(); string units = "m"; std::vector vDimNames = {dimnames[0], dimnames[1], dimnames[2]}; Mesh mesh("BOV", vDimNames, vDimNames); // Create new mesh. We're being lazy here and probably should only // createone if it doesn't ready exist // _meshMap[mesh.GetName()] = mesh; for (auto var : vars) { _dataVarsMap[var] = DataVar(var, units, format, periodic, mesh.GetName(), timeCoordVar, DC::Mesh::NODE); } } bool DCBOV::getDimension(string dimname, DC::Dimension &dimension) const { map::const_iterator itr; itr = _dimsMap.find(dimname); if (itr == _dimsMap.end()) return (false); dimension = itr->second; return (true); } std::vector DCBOV::getDimensionNames() const { map::const_iterator itr; vector names; for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } vector DCBOV::getMeshNames() const { vector mesh_names; std::map::const_iterator itr = _meshMap.begin(); for (; itr != _meshMap.end(); ++itr) { mesh_names.push_back(itr->first); } return (mesh_names); } bool DCBOV::getMesh(string mesh_name, DC::Mesh &mesh) const { map::const_iterator itr = _meshMap.find(mesh_name); if (itr == _meshMap.end()) return (false); mesh = itr->second; return (true); } bool DCBOV::getCoordVarInfo(string varname, DC::CoordVar &cvar) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr == _coordVarsMap.end()) { return (false); } cvar = itr->second; return (true); } bool DCBOV::getDataVarInfo(string varname, DC::DataVar &datavar) const { map::const_iterator itr; itr = _dataVarsMap.find(varname); if (itr == _dataVarsMap.end()) { return (false); } datavar = itr->second; return (true); } bool DCBOV::getBaseVarInfo(string varname, DC::BaseVar &var) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr != _coordVarsMap.end()) { var = itr->second; return (true); } map::const_iterator itr1 = _dataVarsMap.find(varname); if (itr1 != _dataVarsMap.end()) { var = itr1->second; return (true); } return (false); } std::vector DCBOV::getDataVarNames() const { map::const_iterator itr; vector names; for (itr = _dataVarsMap.begin(); itr != _dataVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } std::vector DCBOV::getCoordVarNames() const { map::const_iterator itr; vector names; for (itr = _coordVarsMap.begin(); itr != _coordVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } bool DCBOV::getAtt(string varname, string attname, vector &values) const { return false; } bool DCBOV::getAtt(string varname, string attname, vector &values) const { return false; } bool DCBOV::getAtt(string varname, string attname, string &values) const { return false; } std::vector DCBOV::getAttNames(string varname) const { return {}; } DC::XType DCBOV::getAttType(string varname, string attname) const { return INVALID; } int DCBOV::getDimLensAtLevel(string varname, int, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); bool ok = GetVarDimLens(varname, true, dims_at_level); if (!ok) { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (-1); } // Never blocked // bs_at_level = vector(dims_at_level.size(), 1); return (0); } int DCBOV::openVariableRead(size_t ts, string varname) { FileTable::FileObject *f = new FileTable::FileObject(ts, varname, 0, 0, 0); return (_fileTable.AddEntry(f)); } int DCBOV::closeVariable(int fd) { DC::FileTable::FileObject *w = _fileTable.GetEntry(fd); if (!w) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } _fileTable.RemoveEntry(fd); if (w != nullptr) delete w; return 0; } int DCBOV::_isCoordinateVariable(std::string varname) const { int dim = -1; std::array spatialDims = _bovCollection->GetSpatialDimensions(); for (int i = 0; i < spatialDims.size(); i++) { if (varname == spatialDims[i]) dim = i; } return dim; } template void DCBOV::_generateCoordinates(int dim, const vector &min, const vector &max, T *region) const { std::array dataSize = _bovCollection->GetDataSize(); std::array origin = _bovCollection->GetBrickOrigin(); std::array brickSize = _bovCollection->GetBrickSize(); double denom = (dataSize[dim] - 1); double increment = denom == 0. ? 0. : brickSize[dim] / denom; double start = origin[dim] + min[0] * increment; size_t steps = max[0] - min[0]; for (int i = 0; i <= steps; i++) { region[i] = start + i * increment; } } template int DCBOV::_readRegionTemplate(int fd, const vector &min, const vector &max, T *region) { FileTable::FileObject *w = (FileTable::FileObject *)_fileTable.GetEntry(fd); if (!w) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } std::string varname = w->GetVarname(); int dim = _isCoordinateVariable(varname); if (dim >= 0) { _generateCoordinates(dim, min, max, region); return 0; } size_t ts = w->GetTS(); // If a data variable is requested, read it with ReadRegion std::vector varnames = _bovCollection->GetDataVariableNames(); if (std::find(varnames.begin(), varnames.end(), varname) != varnames.end()) { int rc = _bovCollection->ReadRegion(varname, ts, min, max, region); if (rc < 0) { SetErrMsg("DCBOV::_readRegionTemplate error"); return -1; } } // Otherwise return time values else if (varname == _bovCollection->GetTimeDimension()) { *region = _bovCollection->GetUserTimes()[ts]; } return 0; } bool DCBOV::variableExists(size_t ts, string varname, int, int) const { if (_coordVarsMap.find(varname) != _coordVarsMap.end()) return true; if (_dataVarsMap.find(varname) != _dataVarsMap.end()) return true; return false; } ================================================ FILE: lib/vdc/DCCF.cpp ================================================ #include #include #include #include #include "vapor/VAssert.h" #include #ifdef _WINDOWS #define _USE_MATH_DEFINES #pragma warning(disable : 4251 4100) #endif #include #include #include #include #include using namespace VAPoR; using namespace std; namespace { DC::XType netcdf_to_dc_xtype(int t) { switch (t) { case NC_DOUBLE: return (DC::XType::DOUBLE); case NC_INT64: return (DC::XType::INT64); case NC_CHAR: return (DC::XType::TEXT); default: return (DC::XType::INVALID); } } #ifdef UNUSED_FUNCTION // Product of elements in a vector // size_t vproduct(vector a) { size_t ntotal = 1; for (int i = 0; i < a.size(); i++) ntotal *= a[i]; return (ntotal); } #endif }; // namespace DCCF::DCCF() { _ncdfc = NULL; _dimsMap.clear(); _coordVarsMap.clear(); _dataVarsMap.clear(); _auxVarsMap.clear(); _meshMap.clear(); } DCCF::~DCCF() { if (_ncdfc) delete _ncdfc; } int DCCF::initialize(const vector &paths, const std::vector &options) { auto ncdf = std::unique_ptr(new NetCDFCFCollection()); return initialize_impl(paths, options, std::move(ncdf)); } int DCCF::initialize_impl(const vector &paths, const std::vector &options, std::unique_ptr ncdfc) { // Initialize the NetCDFCFCollection class. // int rc = ncdfc->Initialize(paths); if (rc < 0) { SetErrMsg("Failed to initialize netCDF data collection for reading"); return (-1); } // Use UDUnits for unit conversion // rc = _udunits.Initialize(); if (rc < 0) { SetErrMsg("Failed to initialize udunits2 library : %s", _udunits.GetErrMsg().c_str()); return (-1); } // // To provide a more detailed message in the case described by issue 3626: // https://github.com/NCAR/VAPOR/issues/3626 // add a test if there's any 2D or 3D variables detected. If not, we raise an error. // // Update on 8/15/2024: // It turns out that this error message is also raised with UGRID 2D data sets, when it // shouldn't be raised (see issue 3650). Thus, Sam is commenting out this logic for // release 3.9.3, and will come back to design a more robust method to address both // issues 3626 and 3650. // // auto vars2d = ncdfc->GetDataVariableNames(2, true); // if (vars2d.empty()) { // auto vars3d = ncdfc->GetDataVariableNames(3, true); // if (vars3d.empty()) { // SetErrMsg("Failed to detect any 2D or 3D variables.\n" // "Did you forget any coordinate files?\n"); // return (-1); // } // } if (_ncdfc) { delete _ncdfc; } _ncdfc = ncdfc.release(); _paths = paths; return BuildCache(); } int DCCF::Reinitialize() { return Initialize(_paths, {}); } int DCCF::BuildCache() { auto ncdfc = _ncdfc; int rc; // // Get the dimensions of the grid. // Initializes members: _dimsMap // rc = initDimensions(ncdfc, _dimsMap); if (rc < 0) { SetErrMsg("No valid dimensions"); return (-1); } rc = initCoordinates(ncdfc, _coordVarsMap); if (rc < 0) { SetErrMsg("No valid dimensions"); return (-1); } // // Identify auxilliary variables. // rc = initAuxilliaryVars(ncdfc, _auxVarsMap); if (rc < 0) return (-1); // // Identify meshes. // rc = initMesh(ncdfc, _meshMap); if (rc < 0) return (-1); // // Identify data variables. // rc = initDataVars(ncdfc, _dataVarsMap); if (rc < 0) return (-1); return 0; } bool DCCF::getDimension(string dimname, DC::Dimension &dimension) const { map::const_iterator itr; itr = _dimsMap.find(dimname); if (itr == _dimsMap.end()) return (false); dimension = itr->second; return (true); } std::vector DCCF::getDimensionNames() const { map::const_iterator itr; vector names; for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } vector DCCF::getMeshNames() const { vector mesh_names; std::map::const_iterator itr = _meshMap.begin(); for (; itr != _meshMap.end(); ++itr) { mesh_names.push_back(itr->first); } return (mesh_names); } bool DCCF::getMesh(string mesh_name, DC::Mesh &mesh) const { map::const_iterator itr = _meshMap.find(mesh_name); if (itr == _meshMap.end()) return (false); mesh = itr->second; return (true); } bool DCCF::getCoordVarInfo(string varname, DC::CoordVar &cvar) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr == _coordVarsMap.end()) { return (false); } cvar = itr->second; return (true); } bool DCCF::getDataVarInfo(string varname, DC::DataVar &datavar) const { map::const_iterator itr; itr = _dataVarsMap.find(varname); if (itr == _dataVarsMap.end()) { return (false); } datavar = itr->second; return (true); } bool DCCF::getAuxVarInfo(string varName, DC::AuxVar &auxVar) const { map::const_iterator itr; itr = _auxVarsMap.find(varName); if (itr == _auxVarsMap.end()) { return (false); } auxVar = itr->second; return (true); } bool DCCF::getBaseVarInfo(string varname, DC::BaseVar &var) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr != _coordVarsMap.end()) { var = itr->second; return (true); } map::const_iterator itr1 = _dataVarsMap.find(varname); if (itr1 != _dataVarsMap.end()) { var = itr1->second; return (true); } return (false); } std::vector DCCF::getDataVarNames() const { map::const_iterator itr; vector names; for (itr = _dataVarsMap.begin(); itr != _dataVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } std::vector DCCF::getCoordVarNames() const { map::const_iterator itr; vector names; for (itr = _coordVarsMap.begin(); itr != _coordVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } std::vector DCCF::getAuxVarNames() const { map::const_iterator itr; vector names; for (itr = _auxVarsMap.begin(); itr != _auxVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } template bool DCCF::_getAttTemplate(string varname, string attname, T &values) const { if (varname.empty()) { _ncdfc->GetAtt("", attname, values); return (true); } DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) return (status); DC::Attribute att; status = var.GetAttribute(attname, att); if (!status) return (status); att.GetValues(values); return (true); } bool DCCF::getAtt(string varname, string attname, vector &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } bool DCCF::getAtt(string varname, string attname, vector &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } bool DCCF::getAtt(string varname, string attname, string &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } std::vector DCCF::getAttNames(string varname) const { if (varname.empty()) return (_ncdfc->GetAttNames("")); DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) return (vector()); vector names; const std::map & atts = var.GetAttributes(); std::map::const_iterator itr; for (itr = atts.begin(); itr != atts.end(); ++itr) { names.push_back(itr->first); } return (names); } DC::XType DCCF::getAttType(string varname, string attname) const { if (varname.empty()) { return (netcdf_to_dc_xtype(_ncdfc->GetAttType("", attname))); } DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) return (DC::INVALID); DC::Attribute att; status = var.GetAttribute(attname, att); if (!status) return (DC::INVALID); return (att.GetXType()); } int DCCF::getDimLensAtLevel(string varname, int, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); bool ok = GetVarDimLens(varname, true, dims_at_level, 0); if (!ok) { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (-1); } // Never blocked // bs_at_level = vector(dims_at_level.size(), 1); return (0); } int DCCF::openVariableRead(size_t ts, string varname) { int aux = _ncdfc->OpenRead(ts, varname); if (aux < 0) return (aux); FileTable::FileObject *f = new FileTable::FileObject(ts, varname, 0, 0, aux); return (_fileTable.AddEntry(f)); } int DCCF::closeVariable(int fd) { DC::FileTable::FileObject *w = _fileTable.GetEntry(fd); if (!w) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int aux = w->GetAux(); int rc = _ncdfc->Close(aux); _fileTable.RemoveEntry(fd); return (rc); } template int DCCF::_readRegionTemplate(int fd, const vector &min, const vector &max, T *region) { FileTable::FileObject *w = (FileTable::FileObject *)_fileTable.GetEntry(fd); if (!w) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int aux = w->GetAux(); vector ncdf_start = min; reverse(ncdf_start.begin(), ncdf_start.end()); vector ncdf_max = max; reverse(ncdf_max.begin(), ncdf_max.end()); vector ncdf_count; for (int i = 0; i < ncdf_start.size(); i++) { ncdf_count.push_back(ncdf_max[i] - ncdf_start[i] + 1); } return (_ncdfc->Read(ncdf_start, ncdf_count, region, aux)); } bool DCCF::variableExists(size_t ts, string varname, int, int) const { return (_ncdfc->VariableExists(ts, varname)); } bool DCCF::_isUniform(NetCDFCFCollection *ncdfc, string varname) { vector dims = ncdfc->GetDims(varname); if (dims.size() != 1) return (false); if (dims[0] < 2) return (true); vector buf(dims[0]); bool enabled = EnableErrMsg(false); int fd = ncdfc->OpenRead(0, varname); if (fd < 0) { EnableErrMsg(enabled); return (false); } int rc = ncdfc->Read(buf.data(), fd); if (rc < 0) { EnableErrMsg(enabled); return (false); } ncdfc->Close(fd); EnableErrMsg(enabled); VAssert(buf.size() >= 2); float epsilon = 0.0001; float delta = buf[1] - buf[0]; for (int i = 1; i < buf.size() - 1; i++) { if (!Wasp::NearlyEqual((buf[i + 1] - buf[i]), delta, epsilon)) { return (false); } } return (true); } int DCCF::addCoordvars(NetCDFCFCollection *ncdfc, const vector &cvars, std::map &coordVarsMap) { for (int i = 0; i < cvars.size(); i++) { // Get dimension names // vector dimnames = ncdfc->GetDimNames(cvars[i]); reverse(dimnames.begin(), dimnames.end()); // DC order string time_dim_name; if (ncdfc->IsTimeVarying(cvars[i])) { time_dim_name = dimnames.back(); dimnames.pop_back(); } int axis = 0; if (ncdfc->IsLonCoordVar(cvars[i])) { axis = 0; } else if (ncdfc->IsLatCoordVar(cvars[i])) { axis = 1; } else if (ncdfc->IsVertCoordVar(cvars[i])) { axis = 2; } else if (ncdfc->IsTimeCoordVar(cvars[i])) { axis = 3; } else { continue; // should this be a error condition? } string units; ncdfc->GetAtt(cvars[i], "units", units); if (!_udunits.ValidUnit(units)) { units = ""; } // See if the variable has uniform spacing. If so, set the uniform hint // bool uniformHint = _isUniform(ncdfc, cvars[i]); // Finally, add the variable to coordVarsMap. // vector periodic(false); coordVarsMap[cvars[i]] = CoordVar(cvars[i], units, DC::FLOAT, periodic, axis, uniformHint, dimnames, time_dim_name); int rc = DCUtils::CopyAtt(*ncdfc, cvars[i], coordVarsMap[cvars[i]]); if (rc < 0) return (-1); } return (0); } int DCCF::initCoordinates(NetCDFCFCollection *ncdfc, std::map &coordVarsMap) { coordVarsMap.clear(); // Set up the horizontal coordinate variables // int rc = _initHorizontalCoordinates(ncdfc, coordVarsMap); if (rc < 0) { return (-1); } // Set up the vertical coordinate variables. // rc = _initVerticalCoordinates(ncdfc, coordVarsMap); if (rc < 0) { return (-1); } // Set up user time coordinate variable. // rc = _initTimeCoordinates(ncdfc, coordVarsMap); if (rc < 0) { return (-1); } return (0); } int DCCF::_initHorizontalCoordinates(NetCDFCFCollection *ncdfc, std::map &coordVarsMap) { vector latVars = ncdfc->GetLatCoordVars(); int rc = addCoordvars(ncdfc, latVars, coordVarsMap); if (rc < 0) return (-1); vector lonVars = ncdfc->GetLonCoordVars(); rc = addCoordvars(ncdfc, lonVars, coordVarsMap); if (rc < 0) return (-1); return (0); } // // int DCCF::_initVerticalCoordinates(NetCDFCFCollection *ncdfc, std::map &coordVarsMap) { vector vertVars = ncdfc->GetVertCoordVars(); int rc = addCoordvars(ncdfc, vertVars, coordVarsMap); return (rc); } int DCCF::_initTimeCoordinates(NetCDFCFCollection *ncdfc, std::map &coordVarsMap) { // add native time coordinate variables // int rc = addCoordvars(ncdfc, ncdfc->GetTimeCoordVars(), coordVarsMap); if (rc < 0) return (-1); return (0); } // Get Space and time dimensions from CF data set. Initialize // _dimsMap // int DCCF::initDimensions(NetCDFCFCollection *ncdfc, std::map &dimsMap) { dimsMap.clear(); // Get dimension names and lengths for all dimensions in the // CF data set. // vector dimnames = ncdfc->GetDimNames(); vector dimlens = ncdfc->GetDims(); VAssert(dimnames.size() == dimlens.size()); // // Find all dimensions and their associated axis (X,Y,Z,T). From // CF 1.6: // // All of a variable's dimensions that are latitude, longitude, vertical, // or time dimensions (see Section 1.2, “Terminology”) must have // corresponding coordinate variables, i.e., one-dimensional variables // with the same name as the dimension (see examples in Chapter 4, // Coordinate Types ). This is the only method of associating dimensions // with coordinates that is supported by COARDS. // for (int i = 0; i < dimnames.size(); i++) { Dimension dim(dimnames[i], dimlens[i]); dimsMap[dimnames[i]] = dim; } return (0); } // Given a data variable name return the variable's dimensions and // associated coordinate variables. The coordinate variable names // returned is for the derived coordinate variables expressed in // Cartographic coordinates, not the native geographic coordinates // found in the CF file. // // The order of the returned vectors // is significant. // int DCCF::getVarCoordinates(NetCDFCFCollection *ncdfc, string varname, vector &sdimnames, vector &scoordvars, string &time_dim_name, string &time_coordvar) const { sdimnames.clear(); scoordvars.clear(); time_dim_name.clear(); time_coordvar.clear(); int rc = ncdfc->GetVarCoordVarNames(varname, scoordvars); if (rc < 0) return (-1); reverse(scoordvars.begin(), scoordvars.end()); // DC dimension order sdimnames = ncdfc->GetDimNames(varname); reverse(sdimnames.begin(), sdimnames.end()); // DC order // Coordinate variables returned by ncdfc are assumed to be lat, lon, // height, time. For each native coordinate variable a derived // coordinate variable has been created in Cartographic coordinates with // elevation expressed in meters, and time in seconds // for (int i = 0; i < scoordvars.size(); i++) { string xcv; if (ncdfc->IsLonCoordVar(scoordvars[i])) { xcv = scoordvars[i]; } else if (ncdfc->IsLatCoordVar(scoordvars[i])) { xcv = scoordvars[i]; } else if (ncdfc->IsVertCoordVar(scoordvars[i])) { xcv = scoordvars[i]; } else if (ncdfc->IsTimeCoordVar(scoordvars[i])) { xcv = scoordvars[i]; } // Rank of Cartographic coordinates must be less than or // equal to that of the data variable, or we have to use // the native coordinates // if (ncdfc->GetDimNames(xcv).size() <= sdimnames.size()) { scoordvars[i] = xcv; } } if (ncdfc->IsTimeVarying(varname)) { time_dim_name = sdimnames.back(); sdimnames.pop_back(); time_coordvar = scoordvars.back(); scoordvars.pop_back(); } return (0); } // Initialize the meshMap // int DCCF::initMesh(NetCDFCFCollection *ncdfc, std::map &meshMap) { meshMap.clear(); // // Get names of variables in the CF data set that have 0 to 3 // spatial dimensions // vector vars; for (int i = 0; i < 4; i++) { vector v = ncdfc->GetDataVariableNames(i, true); vars.insert(vars.end(), v.begin(), v.end()); } // For each variable determine the mesh // for (int i = 0; i < vars.size(); i++) { // variable type must be float or int // int type = ncdfc->GetXType(vars[i]); if (!(NetCDFSimple::IsNCTypeFloat(type) || NetCDFSimple::IsNCTypeInt(type))) continue; vector sdimnames; vector scoordvars; string time_dim_name; string time_coordvar; int rc = getVarCoordinates(ncdfc, vars[i], sdimnames, scoordvars, time_dim_name, time_coordvar); if (rc < 0) { SetErrMsg("Invalid variable : %s", vars[i].c_str()); return (-1); } Mesh mesh("", sdimnames, scoordvars); // Create new mesh. We're being lazy here and probably should only // createone if it doesn't ready exist // meshMap[mesh.GetName()] = mesh; } return (0); } int DCCF::initAuxilliaryVars(NetCDFCFCollection *ncdfc, std::map &auxVarsMap) { auxVarsMap.clear(); return (0); } // Collect metadata for all data variables found in the CF data // set. Initialize dataVarsMap member // int DCCF::initDataVars(NetCDFCFCollection *ncdfc, std::map &dataVarsMap) { vector periodic(3, false); // // Get names of variables in the CF data set that have 0 to 3 // spatial dimensions // vector vars; for (int i = 0; i < 4; i++) { vector v = ncdfc->GetDataVariableNames(i, true); vars.insert(vars.end(), v.begin(), v.end()); } // For each variable add a member to dataVarsMap // for (auto varName : vars) { // variable type must be float or int // int type = ncdfc->GetXType(varName); if (!(NetCDFSimple::IsNCTypeFloat(type) || NetCDFSimple::IsNCTypeInt(type))) continue; vector sdimnames; vector scoordvars; string time_dim_name; string time_coordvar; int rc = getVarCoordinates(ncdfc, varName, sdimnames, scoordvars, time_dim_name, time_coordvar); if (rc < 0) { SetErrMsg("Invalid variable : %s", varName.c_str()); return (-1); } string meshName = DC::Mesh::MakeMeshName(sdimnames); string units; ncdfc->GetAtt(varName, "units", units); if (!_udunits.ValidUnit(units)) { units = ""; } double mv; bool has_missing = ncdfc->GetMissingValue(varName, mv); if (!has_missing) { dataVarsMap[varName] = DataVar(varName, units, DC::FLOAT, periodic, meshName, time_coordvar, DC::Mesh::NODE); } else { dataVarsMap[varName] = DataVar(varName, units, DC::FLOAT, periodic, meshName, time_coordvar, DC::Mesh::NODE, mv); } rc = DCUtils::CopyAtt(*ncdfc, varName, dataVarsMap[varName]); if (rc < 0) return (-1); } return (0); } ================================================ FILE: lib/vdc/DCMPAS.cpp ================================================ #include #include #include #include #include "vapor/VAssert.h" #include #ifdef _WINDOWS #define _USE_MATH_DEFINES #pragma warning(disable : 4251 4100) #endif #include #include #include #include #include using namespace VAPoR; using namespace std; namespace { // MPAS variable and dimension names are hard-wired in the NetCDF // file :-( // Dimension names // const string timeDimName = "Time"; const string nVertLevelsDimName = "nVertLevels"; const string nVertLevelsP1DimName = "nVertLevelsP1"; const string nCellsDimName = "nCells"; const string nVerticesDimName = "nVertices"; const string nEdgesDimName = "nEdges"; const string maxEdgesDimName = "maxEdges"; const string maxEdges2DimName = "maxEdges2"; const string vertexDegreeDimName = "vertexDegree"; const vector requiredDimNames = {timeDimName, nCellsDimName, nVerticesDimName, vertexDegreeDimName}; const vector optionalVertDimNames = {nVertLevelsDimName}; // Horizontal coordinate variable names // const string latCellVarName = "latCell"; const string lonCellVarName = "lonCell"; const string xCellVarName = "xCell"; // Cartesian coord - not used const string yCellVarName = "yCell"; // Cartesian coord - not used const string zCellVarName = "zCell"; // Cartesian coord - not used const string latVertexVarName = "latVertex"; const string lonVertexVarName = "lonVertex"; const string xVertexVarName = "xVertex"; // Cartesian coord - not used const string yVertexVarName = "yVertex"; // Cartesian coord - not used const string zVertexVarName = "zVertex"; // Cartesian coord - not used const string latEdgeVarName = "latEdge"; const string lonEdgeVarName = "lonEdge"; const string xEdgeVarName = "xEdge"; // Cartesian coord - not used const string yEdgeVarName = "yEdge"; // Cartesian coord - not used const string zEdgeVarName = "zEdge"; // Cartesian coord - not used const vector requiredHorizCoordVarNames = {latCellVarName, lonCellVarName, latVertexVarName, lonVertexVarName}; const vector lonCoordVarNames = {lonCellVarName, lonVertexVarName, lonEdgeVarName}; // Vertical coordinate variables // const string zGridP1VarName = "zgrid"; // atmosphere vertical coordinate const string zTopVarName = "zTop"; // ocean vertical coordinate const vector optionalVertCoordVarNames = {zGridP1VarName, zTopVarName}; // Time coordinate variables // const string xTimeVarName = "xtime"; // Auxilliary variables (connectivity variables and others) // const string cellsOnVertexVarName = "cellsOnVertex"; const string verticesOnCellVarName = "verticesOnCell"; const string verticesOnEdge = "verticesOnEdge"; const string edgesOnVertexVarName = "edgesOnVertex"; const string edgesOnCellVarName = "edgesOnCell"; const string nEdgesOnCellVarName = "nEdgesOnCell"; const string angleEdgeVarName = "angleEdge"; // Special data variables // const string uNormalVarName = "u"; const string uTangentialVarName = "v"; const vector connectivityVarNames = {cellsOnVertexVarName, verticesOnCellVarName, verticesOnEdge, edgesOnCellVarName}; const vector requiredAuxVarNames = {cellsOnVertexVarName, verticesOnCellVarName}; // Meshes: dual mesh (triangle) and primal (hexagonal cell) // const string mesh2DTriName = "mesh2DTri"; const string mesh3DTriName = "mesh3DTri"; const string mesh3DP1TriName = "mesh3DTriP1"; const string mesh2DCellName = "mesh2DCell"; const string mesh3DCellName = "mesh3DCell"; const string mesh3DP1CellName = "mesh3DCellP1"; // Attributes // const string coreNameAttr = "core_name"; const string onASphereAttr = "on_a_sphere"; // Derived MPAS-A variable names. These don't appear in the MPAS output. // They are derived at run-time by the DCMPAS class // const string zGridVertP1VarName = "zgridVert"; const string zGridVarName = "zgridM1"; const string zGridVertVarName = "zgridVertM1"; // Derived MPAS-O variable names. These don't appear in the MPAS output. // They are derived at run-time by the DCMPAS class // const string zTopVertVarName = "zTopVert"; const vector requiredAttrNames = { // coreNameAttr, onASphereAttr}; // Product of elements in a vector // size_t vproduct(vector a) { size_t ntotal = 1; for (int i = 0; i < a.size(); i++) ntotal *= a[i]; return (ntotal); } // Return the name of the mesh for a specific set of dimension names // string get_mesh_name(vector dimnames) { VAssert(dimnames.size() == 1 || dimnames.size() == 2); if (dimnames[0] == nCellsDimName) { if ((dimnames.size() == 2) && (dimnames[1] == nVertLevelsDimName)) { // 3D dual mesh, unstaggered // return (mesh3DTriName); } else if ((dimnames.size() == 2) && (dimnames[1] == nVertLevelsP1DimName)) { // 3D dual mesh, staggered // return (mesh3DP1TriName); } else { // 2D dual mesh // return (mesh2DTriName); } } if (dimnames[0] == nVerticesDimName) { if ((dimnames.size() == 2) && (dimnames[1] == nVertLevelsDimName)) { // 3D primal mesh, unstaggered // return (mesh3DCellName); } else if ((dimnames.size() == 2) && (dimnames[1] == nVertLevelsP1DimName)) { // 3D primal mesh, staggered // return (mesh3DP1CellName); } else { // 2D primal mesh // return (mesh2DCellName); } } return (""); } // Is 'varname' a connectivity variable? // bool is_connectivity_var(string varname) { return (find(connectivityVarNames.begin(), connectivityVarNames.end(), varname) != connectivityVarNames.end()); } bool is_lat_or_lon(string varname) { return (find(requiredHorizCoordVarNames.begin(), requiredHorizCoordVarNames.end(), varname) != requiredHorizCoordVarNames.end()); } bool is_lon(string varname) { return (find(lonCoordVarNames.begin(), lonCoordVarNames.end(), varname) != lonCoordVarNames.end()); } void rad2degrees(float *buf, size_t n) { for (size_t i = 0; i < n; i++) { buf[i] = buf[i] * 180.0 / M_PI; } } // MPAS orders 3D data with vertical axis varying fastest. VAPOR // wants horizontal dimensions varying fastest. Return true if this is // a 3D variable with transposed horizontal and vertical dimensions // bool isTransposed(NetCDFCollection *ncdfc, string varname) { vector v = ncdfc->GetSpatialDimNames(varname); if (v.size() != 2) return (false); if ((v[1] == nVertLevelsDimName || v[1] == nVertLevelsP1DimName)) { return (true); } return (false); } bool isEdgeVariable(NetCDFCollection *ncdfc, string varname) { vector v = ncdfc->GetSpatialDimNames(varname); if (v[0] == nEdgesDimName) { return (true); } return (false); } template int _xgetVar(NetCDFCollection *ncdfc, size_t ts, string varname, T *buf) { int fd = ncdfc->OpenRead(ts, varname); if (fd < 0) return (fd); int rc = ncdfc->Read(buf, fd); if (rc < 0) return (fd); return (ncdfc->Close(fd)); } DC::XType netcdf_to_dc_xtype(int t) { switch (t) { case NC_DOUBLE: return (DC::XType::DOUBLE); case NC_INT64: return (DC::XType::INT64); case NC_CHAR: return (DC::XType::TEXT); default: return (DC::XType::INVALID); } } }; // namespace DCMPAS::DCMPAS() { _ncdfc = NULL; _dimsMap.clear(); _coordVarsMap.clear(); _dataVarsMap.clear(); _meshMap.clear(); _cellVars.clear(); _pointVars.clear(); _edgeVars.clear(); _hasVertical = false; } DCMPAS::~DCMPAS() { if (_ncdfc) delete _ncdfc; vector names = _dvm.GetDataVarNames(); for (int i = 0; i < names.size(); i++) { if (_dvm.GetVar(names[i])) delete _dvm.GetVar(names[i]); } } int DCMPAS::initialize(const vector &files, const std::vector &options) { if (_ncdfc) delete _ncdfc; _ncdfc = nullptr; // Use UDUnits for unit conversion // int rc = _udunits.Initialize(); if (rc < 0) { SetErrMsg("Failed to initialize udunits2 library : %s", _udunits.GetErrMsg().c_str()); return (-1); } NetCDFCollection *ncdfc = new NetCDFCollection(); // Initialize NetCDFCollection class // vector time_dimnames(1, timeDimName); rc = ncdfc->Initialize(files, time_dimnames, vector()); if (rc < 0) { SetErrMsg("Failed to initialize netCDF data collection for reading"); return (-1); } // Make sure NetCDF file(s) have everything we need // rc = _CheckRequiredFields(ncdfc); if (rc < 0) return (-1); _hasVertical = _HasVertical(ncdfc); // // Get the dimensions of the grid. // Initializes members: _dimsMap // rc = _InitDimensions(ncdfc); if (rc < 0) { SetErrMsg("No valid dimensions"); return (-1); } rc = _InitCoordvars(ncdfc); if (rc < 0) { return (-1); } // Create derived coordinate variables. // rc = _InitDerivedVars(ncdfc); if (rc < 0) { SetErrMsg("Failed to created required derived coordinate variables"); return (-1); } rc = _InitMeshes(ncdfc); if (rc < 0) return (-1); // // Identify data and coordinate variables. Sets up members: // Initializes members: _dataVarsMap, _coordVarsMap, _meshMap // rc = _InitAuxVars(ncdfc); if (rc < 0) return (-1); // Finally, get metdata for all data variables // rc = _InitDataVars(ncdfc); if (rc < 0) return (-1); // If u and v variables are present create derived Uzonal and Umeridional // variables. // if (ncdfc->VariableExists(uNormalVarName) && ncdfc->VariableExists(uTangentialVarName)) { for (auto varname : {"Uzonal", "Umeridional"}) { bool zonalFlag = (varname == string("Uzonal")); DerivedZonalMeridonal *derivedVar = new DerivedZonalMeridonal(varname, this, ncdfc, uNormalVarName, uTangentialVarName, zonalFlag); rc = derivedVar->Initialize(); if (rc < 0) { delete (derivedVar); return (-1); } _dvm.AddDataVar(derivedVar); DC::DataVar dvarInfo; (void)derivedVar->GetDataVarInfo(dvarInfo); _dataVarsMap[varname] = dvarInfo; } } _ncdfc = ncdfc; return (0); } template bool DCMPAS::_getAttTemplate(string varname, string attname, T &values) const { if (varname.empty()) { _ncdfc->GetAtt("", attname, values); return (true); } DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) return (status); DC::Attribute att; status = var.GetAttribute(attname, att); if (!status) return (status); att.GetValues(values); return (true); } bool DCMPAS::getAtt(string varname, string attname, vector &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } bool DCMPAS::getAtt(string varname, string attname, vector &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } bool DCMPAS::getAtt(string varname, string attname, string &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } std::vector DCMPAS::getAttNames(string varname) const { if (varname.empty()) return (_ncdfc->GetAttNames("")); DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) return (vector()); vector names; const std::map & atts = var.GetAttributes(); std::map::const_iterator itr; for (itr = atts.begin(); itr != atts.end(); ++itr) { names.push_back(itr->first); } return (names); } DC::XType DCMPAS::getAttType(string varname, string attname) const { if (varname.empty()) { return (netcdf_to_dc_xtype(_ncdfc->GetAttType("", attname))); } DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) return (DC::INVALID); DC::Attribute att; status = var.GetAttribute(attname, att); if (!status) return (DC::INVALID); return (att.GetXType()); } bool DCMPAS::getDimension(string dimname, DC::Dimension &dimension) const { map::const_iterator itr; itr = _dimsMap.find(dimname); if (itr == _dimsMap.end()) return (false); dimension = itr->second; return (true); } std::vector DCMPAS::getDimensionNames() const { map::const_iterator itr; vector names; for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } vector DCMPAS::getMeshNames() const { vector mesh_names; std::map::const_iterator itr = _meshMap.begin(); for (; itr != _meshMap.end(); ++itr) { mesh_names.push_back(itr->first); } return (mesh_names); } bool DCMPAS::getMesh(string mesh_name, DC::Mesh &mesh) const { map::const_iterator itr = _meshMap.find(mesh_name); if (itr == _meshMap.end()) return (false); mesh = itr->second; return (true); } bool DCMPAS::getCoordVarInfo(string varname, DC::CoordVar &cvar) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr == _coordVarsMap.end()) { return (false); } cvar = itr->second; return (true); } bool DCMPAS::getDataVarInfo(string varname, DC::DataVar &datavar) const { map::const_iterator itr; itr = _dataVarsMap.find(varname); if (itr == _dataVarsMap.end()) { return (false); } datavar = itr->second; return (true); } bool DCMPAS::getAuxVarInfo(string varname, DC::AuxVar &auxvar) const { map::const_iterator itr; itr = _auxVarsMap.find(varname); if (itr == _auxVarsMap.end()) { return (false); } auxvar = itr->second; return (true); } bool DCMPAS::getBaseVarInfo(string varname, DC::BaseVar &var) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr != _coordVarsMap.end()) { var = itr->second; return (true); } map::const_iterator itr1 = _dataVarsMap.find(varname); if (itr1 != _dataVarsMap.end()) { var = itr1->second; return (true); } return (false); } std::vector DCMPAS::getDataVarNames() const { map::const_iterator itr; vector names; for (itr = _dataVarsMap.begin(); itr != _dataVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } std::vector DCMPAS::getCoordVarNames() const { map::const_iterator itr; vector names; for (itr = _coordVarsMap.begin(); itr != _coordVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } std::vector DCMPAS::getAuxVarNames() const { map::const_iterator itr; vector names; for (itr = _auxVarsMap.begin(); itr != _auxVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } int DCMPAS::getDimLensAtLevel(string varname, int, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); if (_dvm.HasVar(varname)) { return (_dvm.GetDimLensAtLevel(varname, 0, dims_at_level, bs_at_level, -1)); } bool ok = GetVarDimLens(varname, true, dims_at_level, -1); if (!ok) { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (-1); } // Never blocked // bs_at_level = vector(dims_at_level.size(), 1); return (0); } // Read the MPAS nEdgesOnCell auxiliary variable and store it for // use later // int DCMPAS::_read_nEdgesOnCell(size_t ts) { DC::Dimension dimension; bool ok = GetDimension(nCellsDimName, dimension, -1); if (!ok) { SetErrMsg("Invalid MPAS auxiliary variable: %s", nEdgesOnCellVarName.c_str()); return (-1); } int *buf = (int *)_nEdgesOnCellBuf.Alloc(dimension.GetLength() * sizeof(*buf)); int fd = _ncdfc->OpenRead(ts, nEdgesOnCellVarName); if (fd < 0) return (fd); int rc = _ncdfc->Read(buf, fd); if (rc < 0) return (fd); return (_ncdfc->Close(fd)); } // Read a floating point variable (data or coordinate) into a SmartBuf // int DCMPAS::_readVarToSmartBuf(size_t ts, string varname, Wasp::SmartBuf &smartBuf) { vector dims; bool ok = GetVarDimLens(varname, true, dims, -1); VAssert(ok); size_t n = vproduct(dims); float *buf = (float *)smartBuf.Alloc(n * sizeof(*buf)); int fd = _ncdfc->OpenRead(ts, varname); if (fd < 0) return (fd); int rc = _ncdfc->Read(buf, fd); if (rc < 0) return (fd); if (is_lat_or_lon(varname)) { rad2degrees((float *)buf, n); } if (is_lon(varname)) { GeoUtil::ShiftLon(buf, buf + n, 180.0); } return (_ncdfc->Close(fd)); } // Read the longitude coordinates for cell and vertices. Need these // to split the periodic mesh // int DCMPAS::_readCoordinates(size_t ts) { int rc = _readVarToSmartBuf(ts, lonCellVarName, _lonCellSmartBuf); if (rc < 0) return (rc); rc = _readVarToSmartBuf(ts, lonVertexVarName, _lonVertexSmartBuf); if (rc < 0) return (rc); return (0); } // MPAS uses an auxiliary array (the variable nEdgesOnCelll) to // indicate the number of elements (edges or vertices) in // multi-dimensional arrays with varying dimension lengths. But DC uses // a padding flag: -1. So using nEdgesOnCell we pad the fixed size // DC connectivity array with -1. // void DCMPAS::_addMissingFlag(int *data) const { int *nEdgesOnCell = (int *)_nEdgesOnCellBuf.GetBuf(); DC::Dimension dimension; bool ok = GetDimension(nCellsDimName, dimension, -1); VAssert(ok); size_t nCells = dimension.GetLength(); ok = GetDimension(maxEdgesDimName, dimension, -1); VAssert(ok); size_t nMaxEdges = dimension.GetLength(); // Add padding // for (size_t j = 0; j < nCells; j++) { for (int i = nEdgesOnCell[j]; i < nMaxEdges; i++) { data[j * nMaxEdges + i] = -1; } } } // MPAS data on sphere is periodic. But we're projecting the geographic // data to Cartesian coordinates. We need split the cells that straddle // the split location, here chose to be 180 (-180) degrees // void DCMPAS::_splitOnBoundary(string varname, int *connData) const { vector connDims; bool ok = GetVarDimLens(varname, true, connDims, -1); VAssert(ok && connDims.size() == 2); // Dimensions for vertex lon // vector lonVertexDims; ok = GetVarDimLens(lonVertexVarName, true, lonVertexDims, -1); VAssert(ok && lonVertexDims.size() == 1); // Dimensions for cell lon // vector lonCellDims; ok = GetVarDimLens(lonCellVarName, true, lonCellDims, -1); VAssert(ok && lonCellDims.size() == 1); // float *lonBuf1 = NULL; float *lonBuf2 = NULL; if (connDims[1] == lonVertexDims[0]) { // lonBuf1 = (float *) _lonVertexSmartBuf.GetBuf(); lonBuf2 = (float *)_lonCellSmartBuf.GetBuf(); } else if (connDims[1] == lonCellDims[0]) { // lonBuf1 = (float *) _lonCellSmartBuf.GetBuf(); lonBuf2 = (float *)_lonVertexSmartBuf.GetBuf(); } else { VAssert(0); } // For each cell (vertex) in the connectivity array make sure // that the cell's (vertices') coordinates and all of it's neighboring // vertices (cells) are on the same side of the split line for // longitude If not, introduce a split // by changing the index of the offending vertices (cells) to -2, // the boundary marker. This code assumes the valid lon coordiates // are 0.0 .. 2*M_PI, as // per the MPAS Mesh Specification, Version 1.0 (Oct. 8, 2015) document. // int n = connDims[0]; for (size_t j = 0; j < connDims[1]; j++) { // MPAS apparently uses a 0 to indicate cell boundaries. This is a undocumented feature // the we need to handle here // bool mpas_boundary_marker = false; for (size_t i = 0; i < n; i++) { if (connData[j * n + i] == 0) { for (size_t ii = 0; ii < n; ii++) { connData[j * n + ii] = -2; } mpas_boundary_marker = true; break; } } if (mpas_boundary_marker) continue; // Ha ha. despite MPAS documentation longitude may run -pi to pi // double lon1 = lonBuf2[connData[j * n] - 1]; if (lon1 > 180.0) lon1 -= 360.0; for (size_t i = 1; i < n && connData[j * n + i] >= 0; i++) { size_t index = connData[j * n + i] - 1; // Arrg. Index starts from 1!! double lon2 = lonBuf2[index]; // Ha ha. despite MPAS documentation longitude may run -pi to pi // if (lon2 > 180.0) lon2 -= 360.0; // Ugh. Test for cell stradling -pi and pi // if (fabs(lon1 - lon2) > 180.0 * 0.5) { connData[j * n + i] = -2; } } } } int DCMPAS::openVariableRead(size_t ts, string varname, int, int) { int aux; bool derivedFlag; if (_dvm.HasVar(varname)) { aux = _dvm.OpenVariableRead(ts, varname); derivedFlag = true; } else { aux = _ncdfc->OpenRead(ts, varname); derivedFlag = false; // Special handling for some auxiliary variables // if (varname == verticesOnCellVarName) { if (_read_nEdgesOnCell(ts) < 0) return (-1); } if (is_connectivity_var(varname)) { if (_readCoordinates(ts) < 0) return (-1); } } MPASFileObject *w = new MPASFileObject(ts, varname, 0, 0, aux, derivedFlag); return (_fileTable.AddEntry(w)); } int DCMPAS::closeVariable(int fd) { MPASFileObject *w = (MPASFileObject *)_fileTable.GetEntry(fd); if (!w) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int aux = w->GetAux(); int rc; if (w->GetDerivedFlag()) { rc = _dvm.CloseVariable(aux); } else { rc = _ncdfc->Close(aux); } _fileTable.RemoveEntry(fd); delete w; return (rc); } int DCMPAS::_readRegionTransposed(MPASFileObject *w, const vector &min, const vector &max, float *region) { VAssert(min.size() == 1 || min.size() == 2); VAssert(min.size() == max.size()); int aux = w->GetAux(); vector ncdf_start = min; vector ncdf_max = max; vector ncdf_count; for (int i = 0; i < ncdf_start.size(); i++) { ncdf_count.push_back(ncdf_max[i] - ncdf_start[i] + 1); } float *buf = new float[vproduct(ncdf_count)]; if (min.size() == 2) { int rc = _ncdfc->Read(ncdf_start, ncdf_count, buf, aux); if (rc < 0) return (-1); Wasp::Transpose(buf, region, ncdf_count[1], ncdf_count[0]); } // No transpose needed. 1D variable // else { int rc = _ncdfc->Read(ncdf_start, ncdf_count, region, aux); if (rc < 0) return (-1); } return (0); } int DCMPAS::_readRegionEdgeVariable(MPASFileObject *w, const vector &min, const vector &max, float *region) { VAssert(min.size() == 1 || min.size() == 2); VAssert(min.size() == max.size()); vector dims = _ncdfc->GetDims(edgesOnVertexVarName); int * edgesOnVertex = new int[vproduct(dims)]; int rc = _xgetVar(_ncdfc, w->GetTS(), edgesOnVertexVarName, edgesOnVertex); if (rc < 0) { delete[] edgesOnVertex; return (-1); } size_t vertexDegree = dims[1]; VAssert(vertexDegree == 3); string varname = w->GetVarname(); // Don't need to reverse dims because we have to do a tranpose anyway // dims = _ncdfc->GetSpatialDims(varname); float *edgeVariable = new float[vproduct(dims)]; vector minAll, maxAll; for (int i = 0; i < dims.size(); i++) { VAssert(dims[i] > 0); minAll.push_back(0); maxAll.push_back(dims[i] - 1); } rc = _readRegionTransposed(w, minAll, maxAll, edgeVariable); if (rc < 0) { delete[] edgesOnVertex; delete[] edgeVariable; return (-1); } size_t j0 = min.size() == 2 ? min[1] : 0; size_t j1 = max.size() == 2 ? max[1] : 0; float wgt = 1.0 / (float)vertexDegree; for (size_t j = j0; j <= j1; j++) { for (size_t i = min[0], ii = 0; i <= max[0]; i++, ii++) { size_t vidx0 = edgesOnVertex[i * vertexDegree + 0] - 1; size_t vidx1 = edgesOnVertex[i * vertexDegree + 1] - 1; size_t vidx2 = edgesOnVertex[i * vertexDegree + 2] - 1; region[j * (max[0] - min[0] + 1) + ii] = edgeVariable[j * dims[0] + vidx0] * wgt + edgeVariable[j * dims[0] + vidx1] * wgt + edgeVariable[j * dims[0] + vidx2] * wgt; } } delete[] edgesOnVertex; delete[] edgeVariable; return (0); } template int DCMPAS::_readRegionTemplate(int fd, const vector &min, const vector &max, T *region) { MPASFileObject *w = (MPASFileObject *)_fileTable.GetEntry(fd); if (!w) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int aux = w->GetAux(); string varname = w->GetVarname(); if (w->GetDerivedFlag()) { return (_dvm.ReadRegion(aux, min, max, region)); } if (isEdgeVariable(_ncdfc, varname)) { VAssert((std::is_same::value) == true); return (_readRegionEdgeVariable(w, min, max, (float *)region)); } else if (isTransposed(_ncdfc, varname)) { VAssert((std::is_same::value) == true); return (_readRegionTransposed(w, min, max, (float *)region)); } // Need to reverse coordinate ordering for NetCDFCollection API, which // orders coordinates from slowest to fastest. DC class expects order // from fastest to slowest. Unless the variable is tranposed, then // we need to "untranspose" it. // vector ncdf_start = min; vector ncdf_max = max; reverse(ncdf_start.begin(), ncdf_start.end()); reverse(ncdf_max.begin(), ncdf_max.end()); vector ncdf_count; for (int i = 0; i < ncdf_start.size(); i++) { ncdf_count.push_back(ncdf_max[i] - ncdf_start[i] + 1); } int rc = _ncdfc->Read(ncdf_start, ncdf_count, region, aux); if (rc < 0) return (-1); // If reading a coordinate variable need to convert from // radians to degrees :-( // if (is_lat_or_lon(varname)) { rad2degrees((float *)region, max[0] - min[0] + 1); } // Special handling for some auxiliary variables // if (varname == verticesOnCellVarName) { _addMissingFlag((int *)region); } if (is_connectivity_var(varname)) { _splitOnBoundary(varname, (int *)region); } return (0); } bool DCMPAS::variableExists(size_t ts, string varname, int, int) const { if (_dvm.HasVar(varname)) { return (_dvm.VariableExists(ts, varname, 0, 0)); } return (_ncdfc->VariableExists(ts, varname)); } int DCMPAS::_InitCoordvars(NetCDFCollection *ncdfc) { string time_dim_name = ""; // longitude coordinates, native (those found in MPAS output files), and // derived (those created on-the-fly by the DCMPAS class. The latter // are longitude coordinate variables mapped to PCS coordinates (e.g // meters on the ground) // vector cvars = {lonCellVarName, lonVertexVarName, lonEdgeVarName}; for (int i = 0; i < cvars.size(); i++) { vector periodic(true); vector dimnames; string units = "degrees_east"; int axis = 0; string name = cvars[i]; dimnames = ncdfc->GetDimNames(name); if (dimnames.size() != 1) continue; _coordVarsMap[name] = CoordVar(name, units, DC::FLOAT, periodic, axis, false, dimnames, time_dim_name); int rc = DCUtils::CopyAtt(*ncdfc, name, _coordVarsMap[name]); if (rc < 0) return (-1); } // LAtitude coordinate variables // cvars = {latCellVarName, latVertexVarName, latEdgeVarName}; for (int i = 0; i < cvars.size(); i++) { vector periodic(false); vector dimnames; string units = "degrees_north"; int axis = 1; string name = cvars[i]; dimnames = ncdfc->GetDimNames(name); if (dimnames.size() != 1) continue; _coordVarsMap[name] = CoordVar(name, units, DC::FLOAT, periodic, axis, false, dimnames, time_dim_name); int rc = DCUtils::CopyAtt(*ncdfc, name, _coordVarsMap[name]); if (rc < 0) return (-1); } vector periodic(false); vector dimnames; if (_hasVertical && (_isAtmosphere(ncdfc) || _isOcean(ncdfc))) { string name; if (_isAtmosphere(ncdfc)) { name = zGridP1VarName; } else { name = zTopVarName; } // Vertical coordinate variables // string units = "meters"; int axis = 2; dimnames = ncdfc->GetSpatialDimNames(name); time_dim_name = ncdfc->GetTimeDimName(name); VAssert(dimnames.size() == 2); _coordVarsMap[name] = CoordVar(name, units, DC::FLOAT, periodic, axis, false, dimnames, time_dim_name); int rc = DCUtils::CopyAtt(*ncdfc, name, _coordVarsMap[name]); if (rc < 0) return (-1); } return (0); } // Create all of the derived coordinate variables // int DCMPAS::_InitDerivedVars(NetCDFCollection *ncdfc) { int rc = _InitVerticalCoordinatesDerivedAtmosphere(ncdfc); if (rc < 0) return (-1); rc = _InitVerticalCoordinatesDerivedOcean(ncdfc); if (rc < 0) return (-1); DC::CoordVar cvarInfo; if (ncdfc->VariableExists(ncdfc->GetNumTimeSteps() - 1, xTimeVarName)) { // Create and install the Time coordinate variable // DerivedCoordVar_WRFTime *derivedVar = new DerivedCoordVar_WRFTime(timeDimName, ncdfc, xTimeVarName, timeDimName); rc = derivedVar->Initialize(); if (rc < 0) return (-1); _dvm.AddCoordVar(derivedVar); // Time coordinate is a derived variable // bool ok = _dvm.GetCoordVarInfo(timeDimName, cvarInfo); VAssert(ok); } else { // Synthesize and install a Time coordinate variable // DerivedCoordVar_Time *derivedVar = new DerivedCoordVar_Time(timeDimName, timeDimName, ncdfc->GetNumTimeSteps()); rc = derivedVar->Initialize(); if (rc < 0) return (-1); _dvm.AddCoordVar(derivedVar); // Time coordinate is a derived variable // bool ok = _dvm.GetCoordVarInfo(timeDimName, cvarInfo); VAssert(ok); } _coordVarsMap[timeDimName] = cvarInfo; return (0); } int DCMPAS::_InitVerticalCoordinatesDerivedAtmosphere(NetCDFCollection *ncdfc) { // MPAS-A only outputs a single vertical coordinate variable, zgrid, // which is the elevation of the staggered grid, primary (cell) mesh. // if (!_hasVertical) return (0); if (!_isAtmosphere(ncdfc)) return (0); DerivedCoordVar *derivedVar = NULL; derivedVar = new DerivedCoordVar_UnStaggered(zGridVarName, nVertLevelsDimName, this, zGridP1VarName, nVertLevelsP1DimName); int rc = derivedVar->Initialize(); if (rc < 0) return (-1); _dvm.AddCoordVar(derivedVar); DC::CoordVar cvarInfo; bool ok = _dvm.GetCoordVarInfo(zGridVarName, cvarInfo); VAssert(ok); _coordVarsMap[zGridVarName] = cvarInfo; derivedVar = new DerivedCoordVertFromCell(zGridVertP1VarName, nVerticesDimName, this, zGridP1VarName, cellsOnVertexVarName); rc = derivedVar->Initialize(); if (rc < 0) return (-1); _dvm.AddCoordVar(derivedVar); ok = _dvm.GetCoordVarInfo(zGridVertP1VarName, cvarInfo); VAssert(ok); _coordVarsMap[zGridVertP1VarName] = cvarInfo; derivedVar = new DerivedCoordVertFromCell(zGridVertVarName, nVerticesDimName, this, zGridVarName, cellsOnVertexVarName); rc = derivedVar->Initialize(); if (rc < 0) return (-1); _dvm.AddCoordVar(derivedVar); ok = _dvm.GetCoordVarInfo(zGridVertVarName, cvarInfo); VAssert(ok); _coordVarsMap[zGridVertVarName] = cvarInfo; return (0); } int DCMPAS::_InitVerticalCoordinatesDerivedOcean(NetCDFCollection *ncdfc) { // MPAS-O only outputs a single vertical coordinate variable, zTop, // which is the elevation of the primary (cell) mesh. // if (!_hasVertical) return (0); if (!_isOcean(ncdfc)) return (0); DerivedCoordVar *derivedVar = NULL; derivedVar = new DerivedCoordVertFromCell(zTopVertVarName, nVerticesDimName, this, zTopVarName, cellsOnVertexVarName); int rc = derivedVar->Initialize(); if (rc < 0) return (-1); _dvm.AddCoordVar(derivedVar); DC::CoordVar cvarInfo; bool ok = _dvm.GetCoordVarInfo(zTopVertVarName, cvarInfo); VAssert(ok); _coordVarsMap[zTopVertVarName] = cvarInfo; return (0); } int DCMPAS::_CheckRequiredFields(NetCDFCollection *ncdfc) const { vector::const_iterator itr; // Check for dimensions // vector dimnames = ncdfc->GetDimNames(); for (int i = 0; i < requiredDimNames.size(); i++) { string s = requiredDimNames[i]; itr = find(dimnames.begin(), dimnames.end(), s); if (itr == dimnames.end()) { SetErrMsg("Missing required dimension \"%s\"", s.c_str()); return (-1); } } // Check for horizontal coordinate variables and auxiallary vars // vector varnames; for (int ndim = 1; ndim < 3; ndim++) { vector v = ncdfc->GetVariableNames(ndim, true); varnames.insert(varnames.end(), v.begin(), v.end()); } for (int i = 0; i < requiredHorizCoordVarNames.size(); i++) { string s = requiredHorizCoordVarNames[i]; itr = find(varnames.begin(), varnames.end(), s); if (itr == varnames.end()) { SetErrMsg("Missing required dimension \"%s\"", s.c_str()); return (-1); } } for (int i = 0; i < requiredAuxVarNames.size(); i++) { string s = requiredAuxVarNames[i]; itr = find(varnames.begin(), varnames.end(), s); if (itr == varnames.end()) { SetErrMsg("Missing required dimension \"%s\"", s.c_str()); return (-1); } } // Check for required global attrs // vector attnames = ncdfc->GetAttNames(""); for (int i = 0; i < requiredAttrNames.size(); i++) { string s = requiredAttrNames[i]; itr = find(attnames.begin(), attnames.end(), s); if (itr == attnames.end()) { SetErrMsg("Missing required dimension \"%s\"", s.c_str()); return (-1); } } return (0); } bool DCMPAS::_HasVertical(NetCDFCollection *ncdfc) const { vector::const_iterator itr; // Check for dimensions // vector dimnames = ncdfc->GetDimNames(); for (int i = 0; i < optionalVertDimNames.size(); i++) { string s = optionalVertDimNames[i]; itr = find(dimnames.begin(), dimnames.end(), s); if (itr == dimnames.end()) { return (false); } } vector varnames; for (int ndim = 1; ndim < 3; ndim++) { vector v = ncdfc->GetVariableNames(ndim, true); varnames.insert(varnames.end(), v.begin(), v.end()); } for (int i = 0; i < optionalVertCoordVarNames.size(); i++) { string s = optionalVertCoordVarNames[i]; itr = find(varnames.begin(), varnames.end(), s); if (itr != varnames.end()) { return (true); } } return (false); } // Get Space and time dimensions from MPAS data set. Initialize // _dimsMap // int DCMPAS::_InitDimensions(NetCDFCollection *ncdfc) { _dimsMap.clear(); // Get dimension names and lengths for all dimensions in the // MPAS data set. // vector dimnames = ncdfc->GetDimNames(); vector dimlens = ncdfc->GetDims(); VAssert(dimnames.size() == dimlens.size()); for (int i = 0; i < dimnames.size(); i++) { Dimension dim(dimnames[i], dimlens[i]); _dimsMap[dimnames[i]] = dim; } return (0); } // Given a data variable name return the variable's dimensions and // associated coordinate variables. // // The order of the returned vectors // is significant. // int DCMPAS::_GetVarCoordinates(NetCDFCollection *ncdfc, string varname, vector &sdimnames, vector &scoordvars, string &time_dim_name, string &time_coordvar) { sdimnames.clear(); scoordvars.clear(); time_dim_name.clear(); time_coordvar.clear(); vector dimnames = ncdfc->GetDimNames(varname); VAssert(dimnames.size() >= 1); if (ncdfc->IsTimeVarying(varname)) { time_dim_name = dimnames[0]; time_coordvar = timeDimName; dimnames.erase(dimnames.begin()); } string verticalCellVarName; string verticalVertexVarName; if (_isAtmosphere(ncdfc)) { verticalCellVarName = zGridVarName; verticalVertexVarName = zGridVertVarName; } else { verticalCellVarName = zTopVarName; verticalVertexVarName = zTopVertVarName; } if (find(_cellVars.begin(), _cellVars.end(), varname) != _cellVars.end()) { sdimnames.push_back(nCellsDimName); scoordvars.push_back(lonCellVarName); scoordvars.push_back(latCellVarName); if (dimnames.size() > 1) { sdimnames.push_back(dimnames[1]); if (dimnames[1] == nVertLevelsDimName) { scoordvars.push_back(verticalCellVarName); } else { scoordvars.push_back(zGridP1VarName); } } } else if (find(_pointVars.begin(), _pointVars.end(), varname) != _pointVars.end()) { sdimnames.push_back(nVerticesDimName); scoordvars.push_back(lonVertexVarName); scoordvars.push_back(latVertexVarName); if (dimnames.size() > 1) { sdimnames.push_back(dimnames[1]); if (dimnames[1] == nVertLevelsDimName) { scoordvars.push_back(verticalVertexVarName); } else { scoordvars.push_back(zGridVertP1VarName); } } } else if (find(_edgeVars.begin(), _edgeVars.end(), varname) != _edgeVars.end()) { sdimnames.push_back(nEdgesDimName); scoordvars.push_back(lonEdgeVarName); scoordvars.push_back(latEdgeVarName); if (dimnames.size() > 1) { sdimnames.push_back(dimnames[1]); if (dimnames[1] == nVertLevelsDimName) { scoordvars.push_back(verticalCellVarName); } else { scoordvars.push_back(zGridP1VarName); } } } else { VAssert(0); } return (0); } int DCMPAS::_InitMeshes(NetCDFCollection *ncdfc) { // Max vertices or edges per cell // DC::Dimension dimension; bool ok = GetDimension(maxEdgesDimName, dimension, -1); VAssert(ok); // // Dual meshes (triangle mesh) // N.B. for the dual node the meanings of cellsOnVertexVarName, // and verticesOnCellVarName are reversed. // // 2D, layered, and layered with staggered dimensions // vector coordvars = {lonCellVarName, latCellVarName}; _meshMap[mesh2DTriName] = Mesh(mesh2DTriName, 3, dimension.GetLength(), nCellsDimName, nVerticesDimName, coordvars, cellsOnVertexVarName, verticesOnCellVarName); if ((_isAtmosphere(ncdfc) || _isOcean(ncdfc)) && _hasVertical) { if (_isAtmosphere(ncdfc)) { coordvars = {lonCellVarName, latCellVarName, zGridP1VarName}; _meshMap[mesh3DP1TriName] = Mesh(mesh3DP1TriName, 3, dimension.GetLength(), nCellsDimName, nVerticesDimName, nVertLevelsP1DimName, coordvars, cellsOnVertexVarName, verticesOnCellVarName); coordvars = {lonCellVarName, latCellVarName, zGridVarName}; } else { coordvars = {lonCellVarName, latCellVarName, zTopVarName}; } _meshMap[mesh3DTriName] = Mesh(mesh3DTriName, 3, dimension.GetLength(), nCellsDimName, nVerticesDimName, nVertLevelsDimName, coordvars, cellsOnVertexVarName, verticesOnCellVarName); } // // Primal meshes (hexagonal mesh) // // 2D, layered, and layered with staggered dimensions // coordvars = {lonVertexVarName, latVertexVarName}; _meshMap[mesh2DCellName] = Mesh(mesh2DCellName, dimension.GetLength(), 3, nVerticesDimName, nCellsDimName, coordvars, verticesOnCellVarName, cellsOnVertexVarName); if ((_isAtmosphere(ncdfc) || _isOcean(ncdfc)) && _hasVertical) { if (_isAtmosphere(ncdfc)) { coordvars = {lonVertexVarName, latVertexVarName, zGridVertP1VarName}; _meshMap[mesh3DP1CellName] = Mesh(mesh3DP1CellName, dimension.GetLength(), 3, nVerticesDimName, nCellsDimName, nVertLevelsP1DimName, coordvars, verticesOnCellVarName, cellsOnVertexVarName); coordvars = {lonVertexVarName, latVertexVarName, zGridVertVarName}; } else { coordvars = {lonVertexVarName, latVertexVarName, zTopVertVarName}; } _meshMap[mesh3DCellName] = Mesh(mesh3DCellName, dimension.GetLength(), 3, nVerticesDimName, nCellsDimName, nVertLevelsDimName, coordvars, verticesOnCellVarName, cellsOnVertexVarName); } return (0); } int DCMPAS::_InitAuxVars(NetCDFCollection *ncdfc) { _auxVarsMap.clear(); vector periodic(3, false); // // Get names of variables in the MPAS data set that have 1 or 2 // spatial dimensions // vector vars; for (int i = 1; i < 3; i++) { vector v = ncdfc->GetVariableNames(i, true); vars.insert(vars.end(), v.begin(), v.end()); } // For each variable add a member to _dataVarsMap // for (int i = 0; i < vars.size(); i++) { // variable type must be int // int type = ncdfc->GetXType(vars[i]); if (!(NetCDFSimple::IsNCTypeInt(type))) { continue; } vector dimnames = _GetSpatialDimNames(ncdfc, vars[i]); if (!dimnames.size()) continue; _auxVarsMap[vars[i]] = AuxVar(vars[i], "", DC::INT32, "", vector(), periodic, dimnames); // IDs in MPAS files start from 1, not 0 :-( // if (vars[i] == cellsOnVertexVarName || vars[i] == verticesOnCellVarName || vars[i] == verticesOnEdge || vars[i] == edgesOnCellVarName) { _auxVarsMap[vars[i]].SetOffset(-1); } } return (0); } int DCMPAS::_InitDataVars(NetCDFCollection *ncdfc) { _dataVarsMap.clear(); vector periodic(3, false); // // Get names of variables in the MPAS data set that have 1 or 2 // spatial dimensions // vector vars; for (int i = 1; i < 3; i++) { vector v = ncdfc->GetVariableNames(i, true); vars.insert(vars.end(), v.begin(), v.end()); } // For each variable add a member to _dataVarsMap // for (int i = 0; i < vars.size(); i++) { // variable type must be float // int type = ncdfc->GetXType(vars[i]); if (!(NetCDFSimple::IsNCTypeFloat(type))) { continue; } if (_isCoordVar(vars[i])) continue; vector sdimnames; vector scoordvars; string time_dim_name; string time_coordvar; vector dimnames = _GetSpatialDimNames(ncdfc, vars[i]); if (!dimnames.size()) continue; if (dimnames[0] == nCellsDimName) { _cellVars.push_back(vars[i]); } else if (dimnames[0] == nVerticesDimName) { _pointVars.push_back(vars[i]); } else if (dimnames[0] == nEdgesDimName) { // No grid support for edge variables in VAPOR, so we turn // them into node-centered data // //_edgeVars.push_back(vars[i]); dimnames[0] = nVerticesDimName; _pointVars.push_back(vars[i]); } else { continue; } string meshname = get_mesh_name(dimnames); if (meshname.empty()) continue; int rc = _GetVarCoordinates(ncdfc, vars[i], sdimnames, scoordvars, time_dim_name, time_coordvar); if (rc < 0) { SetErrMsg("Invalid variable : %s", vars[i].c_str()); return (-1); } string units; ncdfc->GetAtt(vars[i], "units", units); if (!_udunits.ValidUnit(units)) { units = ""; } double mv; bool has_missing = ncdfc->GetMissingValue(vars[i], mv); if (!has_missing) { _dataVarsMap[vars[i]] = DataVar(vars[i], units, DC::FLOAT, periodic, meshname, time_coordvar, DC::Mesh::NODE); } else { _dataVarsMap[vars[i]] = DataVar(vars[i], units, DC::FLOAT, periodic, meshname, time_coordvar, DC::Mesh::NODE, mv); } rc = DCUtils::CopyAtt(*ncdfc, vars[i], _dataVarsMap[vars[i]]); if (rc < 0) return (-1); } return (0); } vector DCMPAS::_GetSpatialDimNames(NetCDFCollection *ncdfc, string varname) const { vector v = ncdfc->GetSpatialDimNames(varname); if (v.size() == 0) return (v); if (!isTransposed(ncdfc, varname)) { reverse(v.begin(), v.end()); } return (v); } // Atmosphere core configuration ? // bool DCMPAS::_isAtmosphere(NetCDFCollection *ncdfc) const { string value; ncdfc->GetAtt("", coreNameAttr, value); return (value == "" || value == "atmosphere"); } // Ocean core configuration ? // bool DCMPAS::_isOcean(NetCDFCollection *ncdfc) const { string value; ncdfc->GetAtt("", coreNameAttr, value); return (value == "ocean"); } // // bool DCMPAS::_isCoordVar(string varname) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr == _coordVarsMap.end()) { return (false); } return (true); } bool DCMPAS::_isDataVar(string varname) const { map::const_iterator itr; itr = _dataVarsMap.find(varname); if (itr == _dataVarsMap.end()) { return (false); } return (true); } ////////////////////////////////////////////////////////////////////// // // Class definitions for derived coordinate variables // ////////////////////////////////////////////////////////////////////// DCMPAS::DerivedCoordVertFromCell::DerivedCoordVertFromCell(string derivedVarName, string derivedDimName, DC *dc, string inName, string cellsOnVertexName ) : DerivedCoordVar(derivedVarName) { _derivedDimName = derivedDimName; _dc = dc; _inName = inName; _cellsOnVertexName = cellsOnVertexName; } int DCMPAS::DerivedCoordVertFromCell::Initialize() { // Set up CoordVarInfo for derived variable. Only difference between // it and native variable is dimension name for first dimension // bool status = _dc->GetCoordVarInfo(_inName, _coordVarInfo); if (!status) { SetErrMsg("Invalid variable \"%s\"", _inName.c_str()); return (-1); } vector dimNames = _coordVarInfo.GetDimNames(); VAssert(dimNames.size()); dimNames[0] = _derivedDimName; _coordVarInfo.SetDimNames(dimNames); return (0); } bool DCMPAS::DerivedCoordVertFromCell::GetBaseVarInfo(DC::BaseVar &var) const { var = _coordVarInfo; return (true); } bool DCMPAS::DerivedCoordVertFromCell::GetCoordVarInfo(DC::CoordVar &cvar) const { cvar = _coordVarInfo; return (true); } int DCMPAS::DerivedCoordVertFromCell::GetDimLensAtLevel(int, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); int rc = _dc->GetDimLensAtLevel(_inName, -1, dims_at_level, bs_at_level, -1); if (rc < 0) return (-1); DC::Dimension dimension; bool ok = _dc->GetDimension(_derivedDimName, dimension, -1); if (!ok) { SetErrMsg("Invalid dimension name : %s", _derivedDimName.c_str()); return (-1); } dims_at_level[0] = dimension.GetLength(); // Never blocked // bs_at_level = vector(dims_at_level.size(), 1); return (0); } int DCMPAS::DerivedCoordVertFromCell::OpenVariableRead(size_t ts, int, int) { DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, 0, 0, 0); return (_fileTable.AddEntry(f)); } int DCMPAS::DerivedCoordVertFromCell::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } _fileTable.RemoveEntry(fd); delete f; return (0); } float *DCMPAS::DerivedCoordVertFromCell::_getCellData() { // Dimensions of input (cell) grid: // vector inDims, dummy; int rc = _dc->GetDimLensAtLevel(_inName, -1, inDims, dummy, -1); if (rc < 0) return (NULL); vector inMin, inMax; for (int i = 0; i < inDims.size(); i++) { inMin.push_back(0); inMax.push_back(inDims[i] - 1); } float *buf = new float[vproduct(inDims)]; rc = _getVar(_dc, 0, _inName, -1, -1, inMin, inMax, buf); if (rc < 0) { delete[] buf; return (NULL); } return (buf); } int *DCMPAS::DerivedCoordVertFromCell::_getCellsOnVertex(size_t i0, size_t i1, int &vertexDegree) { vertexDegree = 0; vector dims; bool ok = _dc->GetVarDimLens(_cellsOnVertexName, true, dims, -1); if (!ok) { SetErrMsg("Undefined variable name : %s", _cellsOnVertexName.c_str()); return (NULL); } int fd = _dc->OpenVariableRead(0, _cellsOnVertexName, 0, 0); vertexDegree = dims[0]; int *buf = new int[(i1 - i0 + 1) * vertexDegree]; vector min, max; min.push_back(0); min.push_back(i0); max.push_back(vertexDegree - 1); max.push_back(i1); int rc = _dc->ReadRegion(fd, min, max, buf); if (rc < 0) { delete[] buf; return (NULL); } _dc->CloseVariable(fd); return (buf); } int DCMPAS::DerivedCoordVertFromCell::ReadRegion(int fd, const vector &min, const vector &max, float *region) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } string varname = f->GetVarname(); vector inDims, dummy; int rc = _dc->GetDimLensAtLevel(_inName, -1, inDims, dummy, -1); if (rc < 0) return (-1); float *cellData = _getCellData(); if (!cellData) return (-1); int vertexDegree; int *cellsOnVertex = _getCellsOnVertex(min[0], max[0], vertexDegree); // only handle triangles for dual mesh // VAssert(vertexDegree == 3); if (!cellsOnVertex) { delete[] cellData; return (-1); } size_t ny = min.size() >= 2 ? max[1] - min[1] + 1 : 1; size_t nx = min.size() >= 1 ? max[0] - min[0] + 1 : 1; // Interpolation weights. Assume interpolated sample is at geometric // center of triangle // float wgt0 = 1.0 / 3.0; float wgt1 = 1.0 / 3.0; float wgt2 = 1.0 / 3.0; int offset = -1; // indexing in MPAS starts from -1 for (size_t j = 0; j < ny; j++) { for (size_t i = 0; i < nx; i++) { float v0 = cellData[j * inDims[0] + cellsOnVertex[i * vertexDegree + 0] + offset]; float v1 = cellData[j * inDims[0] + cellsOnVertex[i * vertexDegree + 1] + offset]; float v2 = cellData[j * inDims[0] + cellsOnVertex[i * vertexDegree + 2] + offset]; region[j * nx + i] = v0 * wgt0 + v1 * wgt1 + v2 * wgt2; } } delete[] cellData; delete[] cellsOnVertex; return (0); } bool DCMPAS::DerivedCoordVertFromCell::VariableExists(size_t ts, int, int) const { return (_dc->VariableExists(ts, _inName, -1, -1)); } ////////////////////////////////////////////////////////////////////// // // Class definitions for derived data variables // ////////////////////////////////////////////////////////////////////// DCMPAS::DerivedZonalMeridonal::DerivedZonalMeridonal(string derivedVarName, DC *dc, NetCDFCollection *ncdfc, string normalVarName, string tangentialVarName, bool zonalFlag ) : DerivedDataVar(derivedVarName) { _dc = dc; _ncdfc = ncdfc; _normalVarName = normalVarName; _tangentialVarName = tangentialVarName; _zonalFlag = zonalFlag; } int DCMPAS::DerivedZonalMeridonal::Initialize() { // Set up DataVarInfo for derived variable. No difference between // it and native variables derived from // bool status = _dc->GetDataVarInfo(_normalVarName, _dataVarInfo); if (!status) { SetErrMsg("Invalid variable \"%s\"", _normalVarName.c_str()); return (-1); } return (0); } bool DCMPAS::DerivedZonalMeridonal::GetBaseVarInfo(DC::BaseVar &var) const { var = _dataVarInfo; return (true); } bool DCMPAS::DerivedZonalMeridonal::GetDataVarInfo(DC::DataVar &cvar) const { cvar = _dataVarInfo; return (true); } int DCMPAS::DerivedZonalMeridonal::GetDimLensAtLevel(int, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); int rc = _dc->GetDimLensAtLevel(_normalVarName, -1, dims_at_level, bs_at_level, -1); if (rc < 0) return (-1); // Never blocked // bs_at_level = vector(dims_at_level.size(), 1); return (0); } int DCMPAS::DerivedZonalMeridonal::OpenVariableRead(size_t ts, int, int) { DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, 0, 0, 0); return (_fileTable.AddEntry(f)); } int DCMPAS::DerivedZonalMeridonal::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } _fileTable.RemoveEntry(fd); delete f; return (0); } int DCMPAS::DerivedZonalMeridonal::ReadRegion(int fd, const vector &min, const vector &max, float *region) { VAssert(min.size() == 2); VAssert(min.size() == max.size()); DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); size_t ts = f->GetTS(); vector dims = _ncdfc->GetDims(edgesOnVertexVarName); vector edgesOnVertex(vproduct(dims)); int rc = _xgetVar(_ncdfc, ts, edgesOnVertexVarName, edgesOnVertex.data()); if (rc < 0) return (-1); size_t vertexDegree = dims[1]; dims = _ncdfc->GetDims(angleEdgeVarName); vector angleEdge(vproduct(dims)); rc = _xgetVar(_ncdfc, ts, angleEdgeVarName, angleEdge.data()); if (rc < 0) return (-1); dims = _ncdfc->GetSpatialDims(_normalVarName); vector ncdf_start = {0, min[1]}; vector ncdf_count = {dims[0], max[1] - min[1] + 1}; vector u(vproduct(ncdf_count)); vector v(vproduct(ncdf_count)); vector buf(vproduct(ncdf_count)); int myfd = _ncdfc->OpenRead(ts, _normalVarName); if (rc < 0) return (-1); rc = _ncdfc->Read(ncdf_start, ncdf_count, buf.data(), myfd); if (rc < 0) return (-1); Wasp::Transpose(buf.data(), u.data(), ncdf_count[1], ncdf_count[0]); (void)_ncdfc->Close(myfd); myfd = _ncdfc->OpenRead(ts, _tangentialVarName); if (rc < 0) return (-1); rc = _ncdfc->Read(ncdf_start, ncdf_count, buf.data(), myfd); if (rc < 0) return (-1); Wasp::Transpose(buf.data(), v.data(), ncdf_count[1], ncdf_count[0]); (void)_ncdfc->Close(myfd); size_t j0 = min.size() == 2 ? min[1] : 0; size_t j1 = max.size() == 2 ? max[1] : 0; float wgt = 1.0 / (float)vertexDegree; for (size_t j = j0; j <= j1; j++) { for (size_t i = min[0], ii = 0; i <= max[0]; i++, ii++) { size_t vidx0 = edgesOnVertex[i * vertexDegree + 0] - 1; size_t vidx1 = edgesOnVertex[i * vertexDegree + 1] - 1; size_t vidx2 = edgesOnVertex[i * vertexDegree + 2] - 1; float alpha0 = angleEdge[vidx0]; float alpha1 = angleEdge[vidx1]; float alpha2 = angleEdge[vidx2]; float u0, u1, u2; // // |Um| = |cos(alpha) -sin(alpha)| |u| // | | | | x | | // |Uz| = |sin(alpha) cos(alpha) | |v| // if (_zonalFlag) { u0 = (cos(alpha0) * u.data()[j * dims[0] + vidx0]) - (sin(alpha0) * v.data()[j * dims[0] + vidx0]); u1 = (cos(alpha1) * u.data()[j * dims[0] + vidx1]) - (sin(alpha1) * v.data()[j * dims[0] + vidx1]); u2 = (cos(alpha2) * u.data()[j * dims[0] + vidx2]) - (sin(alpha2) * v.data()[j * dims[0] + vidx2]); } else { u0 = (sin(alpha0) * u.data()[j * dims[0] + vidx0]) + (cos(alpha0) * v.data()[j * dims[0] + vidx0]); u1 = (sin(alpha1) * u.data()[j * dims[0] + vidx1]) + (cos(alpha1) * v.data()[j * dims[0] + vidx1]); u2 = (sin(alpha2) * u.data()[j * dims[0] + vidx2]) + (cos(alpha2) * v.data()[j * dims[0] + vidx2]); } region[j * (max[0] - min[0] + 1) + ii] = u0 * wgt + u1 * wgt + u2 * wgt; } } return (0); } bool DCMPAS::DerivedZonalMeridonal::VariableExists(size_t ts, int, int) const { return (_dc->VariableExists(ts, _normalVarName, -1, -1) && _dc->VariableExists(ts, _tangentialVarName, -1, -1)); } ================================================ FILE: lib/vdc/DCMelanie.cpp ================================================ #ifdef BUILD_DC_MELANIE #include #include #include #include #include #include "vapor/VAssert.h" #include #ifdef _WINDOWS #define _USE_MATH_DEFINES #pragma warning(disable : 4251 4100) #endif #include #include #include #include #include using namespace VAPoR; DCMelanie::DCMelanie() { _ncdfc = NULL; _dimsMap.clear(); _coordVarsMap.clear(); _dataVarsMap.clear(); _meshMap.clear(); _coordVarKeys.clear(); _derivedVars.clear(); } DCMelanie::~DCMelanie() { if (_ncdfc) delete _ncdfc; for (int i = 0; i < _derivedVars.size(); i++) { if (_derivedVars[i]) delete _derivedVars[i]; } _derivedVars.clear(); } static void ReplaceAll(string *s, char a, char b) { for (auto &c : *s) c = c == a ? b : c; } int DCMelanie::initialize(const vector &paths, const std::vector &options) { if (_ncdfc) delete _ncdfc; _ncdfc = nullptr; NetCDFCFCollection *ncdfc = new NetCDFCFCollection(); // Initialize the NetCDFCFCollection class. // int rc = ncdfc->Initialize(paths); if (rc < 0) { SetErrMsg("Failed to initialize netCDF data collection for reading"); return (-1); } // Use UDUnits for unit conversion // rc = _udunits.Initialize(); if (rc < 0) { SetErrMsg("Failed to initialize udunits2 library : %s", _udunits.GetErrMsg().c_str()); return (-1); } auto particleAttributes = ncdfc->GetVariableNames(1, true); auto particleVecs = ncdfc->GetVariableNames(2, true); for (auto &n : particleAttributes) n = sanitizeVarName(n); for (auto &n : particleVecs) n = sanitizeVarName(n); string particlePositions = "Position"; vector coords = { particlePositions + "_x", particlePositions + "_y", particlePositions + "_z", }; { auto positionPos = find(particleVecs.begin(), particleVecs.end(), particlePositions); VAssert(positionPos != particleVecs.end()); particleVecs.erase(positionPos); } // printf("Particle Coordinates\n"); // printf("\t%s\n", particlePositions.c_str()); // printf("Particle Vecs\n"); // for (auto s : particleVecs) // printf("\t%s\n", s.c_str()); // printf("Particle Attributes\n"); // for (auto s : particleAttributes) // printf("\t%s\n", s.c_str()); // Dimensions // ================== const string particlesDim = "phony_dim_0"; const string axesDim = "phony_dim_1"; auto dimNames = ncdfc->GetDimNames(); auto dimLens = ncdfc->GetDims(); string timeDim = ""; assert(dimNames.size() == dimLens.size()); for (int i = 0; i < dimNames.size(); i++) _dimsMap[dimNames[i]] = DC::Dimension(dimNames[i], dimLens[i]); // Coord Vars // ================== string timeCoordVar = ""; { vector periodic(false); for (int i = 0; i < 3; i++) { auto c = coords[i]; auto axis = i; _coordVarsMap[c] = CoordVar(c, "", DC::FLOAT, periodic, axis, false, {"phony_dim_0"}, timeDim); } } // Aux Vars // ================== { vector periodic(3, false); for (auto v : {nodeFaceVar, faceNodeVar}) _auxVarsMap[v] = AuxVar(v, "", DC::INT32, "", vector(), periodic, {particlesDim}); } // Mesh // ================== DC::Mesh mesh("particles", 1, 1, "phony_dim_0", "phony_dim_0", coords); mesh.SetNodeFaceVar(nodeFaceVar); mesh.SetFaceNodeVar(faceNodeVar); _meshMap[mesh.GetName()] = mesh; // Data Vars // ================== { vector periodic(3, false); for (string v : particleVecs) { auto dims = ncdfc->GetDimNames(getOriginalVarName(v)); if (STLUtils::Contains(dims, axesDim)) { for (auto axis : {"_x", "_y", "_z"}) _dataVarsMap[v + axis] = DC::DataVar(v + axis, "", DC::FLOAT, periodic, mesh.GetName(), timeCoordVar, DC::Mesh::NODE); } else { _dataVarsMap[v] = DC::DataVar(v, "", DC::FLOAT, periodic, mesh.GetName(), timeCoordVar, DC::Mesh::NODE); } } } _ncdfc = ncdfc; return (0); } bool DCMelanie::getDimension(string dimname, DC::Dimension &dimension) const { map::const_iterator itr; itr = _dimsMap.find(dimname); if (itr == _dimsMap.end()) return (false); dimension = itr->second; return (true); } std::vector DCMelanie::getDimensionNames() const { map::const_iterator itr; vector names; for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } vector DCMelanie::getMeshNames() const { vector mesh_names; std::map::const_iterator itr = _meshMap.begin(); for (; itr != _meshMap.end(); ++itr) { mesh_names.push_back(itr->first); } return (mesh_names); } bool DCMelanie::getMesh(string mesh_name, DC::Mesh &mesh) const { map::const_iterator itr = _meshMap.find(mesh_name); if (itr == _meshMap.end()) return (false); mesh = itr->second; return (true); } bool DCMelanie::getCoordVarInfo(string varname, DC::CoordVar &cvar) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr == _coordVarsMap.end()) { return (false); } cvar = itr->second; return (true); } bool DCMelanie::getDataVarInfo(string varname, DC::DataVar &datavar) const { map::const_iterator itr; itr = _dataVarsMap.find(varname); if (itr == _dataVarsMap.end()) { return (false); } datavar = itr->second; return (true); } bool DCMelanie::getBaseVarInfo(string varname, DC::BaseVar &var) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr != _coordVarsMap.end()) { var = itr->second; return (true); } map::const_iterator itr1 = _dataVarsMap.find(varname); if (itr1 != _dataVarsMap.end()) { var = itr1->second; return (true); } return (false); } std::vector DCMelanie::getDataVarNames() const { map::const_iterator itr; vector names; for (itr = _dataVarsMap.begin(); itr != _dataVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } std::vector DCMelanie::getCoordVarNames() const { map::const_iterator itr; vector names; for (itr = _coordVarsMap.begin(); itr != _coordVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } template bool DCMelanie::_getAttTemplate(string varname, string attname, T &values) const { // printf("%s(%s, %s, %s&)\n", __func__, varname.c_str(), attname.c_str(), TypeToChar(values)); DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) return (status); DC::Attribute att; status = var.GetAttribute(attname, att); if (!status) return (status); att.GetValues(values); return (true); } bool DCMelanie::getAtt(string varname, string attname, vector &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } bool DCMelanie::getAtt(string varname, string attname, vector &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } bool DCMelanie::getAtt(string varname, string attname, string &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } std::vector DCMelanie::getAttNames(string varname) const { // printf("%s(%s) = ", __func__, varname.c_str()); DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) { // printf("{} (ERR)\n"); return (vector()); } vector names; const std::map & atts = var.GetAttributes(); std::map::const_iterator itr; for (itr = atts.begin(); itr != atts.end(); ++itr) { names.push_back(itr->first); } // printf("%s\n", ToStr(names).c_str()); return (names); } DC::XType DCMelanie::getAttType(string varname, string attname) const { // printf("%s(%s, %s)\n", __func__, varname.c_str(), attname.c_str()); DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) return (DC::INVALID); DC::Attribute att; status = var.GetAttribute(attname, att); if (!status) return (DC::INVALID); return (att.GetXType()); } int DCMelanie::getDimLensAtLevel(string varname, int, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); VAssert(0); bool ok = GetVarDimLens(varname, true, dims_at_level, 0); if (!ok) { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (-1); } // Never blocked // bs_at_level = vector(dims_at_level.size(), 1); return (0); } int DCMelanie::openVariableRead(size_t ts, string varname) { // printf("%s(%li, %s) = ", __func__, ts, varname.c_str()); if (STLUtils::Contains(fakeVars, varname)) { int ret = fakeVarsFileCounter++; // printf("(fake) %i\n", ret); _fdMap[ret] = varname; return ret; } string ncdfName = varname; if (STLUtils::EndsWith(ncdfName, "_x") || STLUtils::EndsWith(ncdfName, "_y") || STLUtils::EndsWith(ncdfName, "_z")) { ncdfName = ncdfName.substr(0, ncdfName.length() - 2); // printf("\n\t"); // printf("%s(%li, %s) = ", __func__, ts, ncdfName.c_str()); } ncdfName = getOriginalVarName(ncdfName); int aux = _ncdfc->OpenRead(ts, ncdfName); if (!(aux < 0)) { FileTable::FileObject *f = new FileTable::FileObject(ts, ncdfName, 0, 0, aux); aux = _fileTable.AddEntry(f); } // printf("%i\n", aux); _fdMap[aux] = varname; return aux; } int DCMelanie::closeVariable(int fd) { // printf("%s(%i)\n", __func__, fd); _fdMap.erase(_fdMap.find(fd)); if (fd >= fakeVarsFileCounterStart) { fakeVarsFileCounter--; return 0; } DC::FileTable::FileObject *w = _fileTable.GetEntry(fd); if (!w) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int aux = w->GetAux(); int rc = _ncdfc->Close(aux); _fileTable.RemoveEntry(fd); return (rc); } // min -> max is inclusive template int DCMelanie::_readRegionTemplate(int fd, const vector &min_, const vector &max_, T *region) { vector min = min_; vector max = max_; string varname = _fdMap[fd]; // printf("%s(%i(%s), %s, %s, %s*)\n", __func__, fd, varname.c_str(), ToStr(min).c_str(), ToStr(max).c_str(), TypeToChar(*region)); VAssert(min.size() == 1); bool fake = fd >= fakeVarsFileCounterStart; if (fake) { // printf("\t (Fake)\n"); for (size_t i = min[0]; i <= max[0]; i++) region[i] = i / (double)(max[0] - 1); return 0; } int axis = -1; if (STLUtils::EndsWith(varname, "_x")) axis = 0; if (STLUtils::EndsWith(varname, "_y")) axis = 1; if (STLUtils::EndsWith(varname, "_z")) axis = 2; if (axis != -1) { // printf("\t Read data from header\n"); // for (size_t i = min[0]; i <= max[0]; i++) // region[i] = Particle_Position[i*3+axis]; // return 0; // min.push_back(axis); // max.push_back(axis); min.push_back(min[0]); max.push_back(max[0]); min[0] = axis; max[0] = axis; // printf("\t %s(%i(%s), %s, %s, %s*)\n", __func__, fd, varname.substr(0,varname.length()-2).c_str(), ToStr(min).c_str(), ToStr(max).c_str(), TypeToChar(*region)); } FileTable::FileObject *w = (FileTable::FileObject *)_fileTable.GetEntry(fd); if (!w) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int aux = w->GetAux(); vector ncdf_start = min; reverse(ncdf_start.begin(), ncdf_start.end()); vector ncdf_max = max; reverse(ncdf_max.begin(), ncdf_max.end()); vector ncdf_count; for (int i = 0; i < ncdf_start.size(); i++) { ncdf_count.push_back(ncdf_max[i] - ncdf_start[i] + 1); } return (_ncdfc->Read(ncdf_start, ncdf_count, region, aux)); } bool DCMelanie::variableExists(size_t ts, string varname, int, int) const { bool found = false; for (const auto &it : _dataVarsMap) { if (found) break; if (it.first == varname) found = true; } for (const auto &it : _coordVarsMap) { if (found) break; if (it.first == varname) found = true; } for (const auto &it : _auxVarsMap) { if (found) break; if (it.first == varname) found = true; } // if (found == false) // printf("WARNING %s(%li, %s) = %s\n", __func__, ts, varname.c_str(), found?"true":"false"); return found; } std::vector DCMelanie::getAuxVarNames() const { vector names(_auxVarsMap.size()); for (const auto &it : _auxVarsMap) names.push_back(it.first); return names; } bool DCMelanie::getAuxVarInfo(string varname, DC::AuxVar &var) const { const auto &it = _auxVarsMap.find(varname); if (it == _auxVarsMap.end()) return false; var = it->second; return true; } string DCMelanie::sanitizeVarName(const string &name) { assert(_sanitizedToOriginalMap.count(name) == 0); string sanitizedName = name; ReplaceAll(&sanitizedName, ' ', '_'); _sanitizedToOriginalMap[sanitizedName] = name; return sanitizedName; } string DCMelanie::getOriginalVarName(const string &name) const { auto it = _sanitizedToOriginalMap.find(name); if (it == _sanitizedToOriginalMap.end()) return name; return it->second; } #endif ================================================ FILE: lib/vdc/DCP.cpp ================================================ #include #include #include #include #include #include "vapor/VAssert.h" #include #ifdef _WINDOWS #define _USE_MATH_DEFINES #pragma warning(disable : 4251 4100) #endif #include #include #include #include #include using namespace VAPoR; DCP::DCP() { _ncdfc = NULL; _dimsMap.clear(); _coordVarsMap.clear(); _dataVarsMap.clear(); _meshMap.clear(); _coordVarKeys.clear(); } DCP::~DCP() { if (_ncdfc) delete _ncdfc; } static void ReplaceAll(string *s, char a, char b) { for (auto &c : *s) c = c == a ? b : c; } int DCP::initialize(const vector &paths, const std::vector &options) { if (_ncdfc) delete _ncdfc; _ncdfc = nullptr; NetCDFCollection *ncdfc = new NetCDFCollection(); _ncdfc = ncdfc; // Initialize the NetCDFCFCollection class. // int rc = ncdfc->Initialize(paths, {"time", "T"}, {"time", "T"}); if (rc < 0) { SetErrMsg("Failed to initialize netCDF data collection for reading"); return (-1); } // Use UDUnits for unit conversion // rc = _udunits.Initialize(); if (rc < 0) { SetErrMsg("Failed to initialize udunits2 library : %s", _udunits.GetErrMsg().c_str()); return (-1); } // Dimensions // ================== string particlesDim; string axisDim; auto dimNames = ncdfc->GetDimNames(); auto dimLens = ncdfc->GetDims(); auto dimIsTimeVarying = ncdfc->GetDimsAreTimeVarying(); bool dimNamePhony = false; for (auto d : dimNames) if (STLUtils::BeginsWith(d, "phony")) dimNamePhony = true; if (dimNamePhony) { particlesDim = "phony_dim_0"; axisDim = "phony_dim_1"; } else { particlesDim = "P"; axisDim = "axis"; if (!STLUtils::Contains(dimNames, string("P"))) { MyBase::SetErrMsg("File missing required dimension P"); return -1; } } for (int i = 0; i < dimNames.size(); i++) if (dimIsTimeVarying[i]) _dimsMap[dimNames[i]] = DC::Dimension(dimNames[i], vector{dimLens[i], 0}); else _dimsMap[dimNames[i]] = DC::Dimension(dimNames[i], dimLens[i]); #if DCP_ENABLE_PARTICLE_DENSITY //! Vapor does not support derived dimensions so this is a "derived" dimension to allow particle densities. //! See documentation in DCP.h _dimsMap["densityX"] = DC::Dimension("densityX", 32); _dimsMap["densityY"] = DC::Dimension("densityY", 32); _dimsMap["densityZ"] = DC::Dimension("densityZ", 4); #endif // Aux Vars // ================== { vector periodic(3, false); for (auto v : {_nodeFaceVar, _faceNodeVar}) _auxVarsMap[v] = AuxVar(v, "", DC::INT32, "", vector(), periodic, {particlesDim}); } // Coord Vars // ================== for (int dim = 0; dim < 5; dim++) { auto vars = ncdfc->GetVariableNames(dim, true); for (auto &var : vars) { if (isCoordVar(var)) { const vector periodic(false); auto spacialDims = ncdfc->GetSpatialDimNames(var); auto timeDim = ncdfc->GetTimeDimName(var); if (STLUtils::Contains(spacialDims, axisDim)) { spacialDims.erase(find(spacialDims.begin(), spacialDims.end(), axisDim)); for (auto axis : {"_x", "_y", "_z"}) _coordVarsMap[var + axis] = CoordVar(var + axis, getUnits(var), DC::FLOAT, periodic, getAxis(var + axis), false, spacialDims, timeDim); } else { _coordVarsMap[var] = CoordVar(var, getUnits(var), DC::FLOAT, periodic, getAxis(var), false, spacialDims, timeDim); } } } } vector coordVarsNames; for (auto it = _coordVarsMap.cbegin(); it != _coordVarsMap.cend(); ++it) coordVarsNames.push_back(it->first); string particlePositions = "Position"; vector coords = { particlePositions + "_x", particlePositions + "_y", particlePositions + "_z", }; for (const auto &requiredCoordVar : coords) { if (!STLUtils::Contains(coordVarsNames, requiredCoordVar)) { MyBase::SetErrMsg("File missing required coord var %s", requiredCoordVar.c_str()); return -1; } } // Mesh // ================== DC::Mesh mesh("particles", 1, 1, particlesDim, particlesDim, coords); mesh.SetNodeFaceVar(_nodeFaceVar); mesh.SetFaceNodeVar(_faceNodeVar); _meshMap[mesh.GetName()] = mesh; // Data Vars // ================== { vector periodic(3, false); for (int dim = 0; dim < 5; dim++) { auto vars = ncdfc->GetVariableNames(dim, true); for (auto v : vars) { if (!isCoordVar(v)) { auto v_san = sanitizeVarName(v); auto dims = ncdfc->GetDimNames(v); if (STLUtils::Contains(dims, axisDim)) { for (auto axis : {"_x", "_y", "_z"}) { auto name = v_san + axis; _dataVarsMap[name] = DC::DataVar(name, "", DC::FLOAT, periodic, mesh.GetName(), getTimeCoordVar(v), DC::Mesh::NODE); } } else { _dataVarsMap[v_san] = DC::DataVar(v_san, "", DC::FLOAT, periodic, mesh.GetName(), getTimeCoordVar(v), DC::Mesh::NODE); } } } } } if (_dataVarsMap.empty()) { // If no data other than position, add a fake empty var to allow // the position data to be rendered on its own vector periodic(3, false); _dataVarsMap[_fakeEmptyVar] = DC::DataVar(_fakeEmptyVar, "", DC::FLOAT, periodic, mesh.GetName(), getTimeCoordVar(coords[0]), DC::Mesh::NODE); _fakeVars.push_back(_fakeEmptyVar); } return 0; } bool DCP::isCoordVar(const string &var) const { return STLUtils::BeginsWith(var, "Position") || var == "T"; int type = _ncdfc->GetAttType(var, "coordinates"); if (type < 0) return true; assert(type == NC_CHAR); return false; } int DCP::getAxis(const string &var) const { string s; _ncdfc->GetAtt(var, "axis", s); s = STLUtils::ToLower(s); if (s == "x") return 0; if (s == "y") return 1; if (s == "z") return 2; if (s == "t") return 3; if (var == "T") return 3; if (STLUtils::EndsWith(var, "_x")) return 0; if (STLUtils::EndsWith(var, "_y")) return 1; if (STLUtils::EndsWith(var, "_z")) return 2; VAssert(0); return -1; } string DCP::getUnits(const string &var) const { string s; _ncdfc->GetAtt(var, "units", s); return s; } string DCP::getTimeCoordVar(const string &var) const { if (_ncdfc->GetTimeDimName(var) == "T") return "T"; return ""; } bool DCP::getDimension(string dimname, DC::Dimension &dimension) const { VAssert(0); return false; } bool DCP::getDimension(string dimname, DC::Dimension &dimension, long ts) const { if (ts == -1 #if DCP_ENABLE_PARTICLE_DENSITY //! Vapor does not support derived dimensions so this is a "derived" dimension to allow particle densities. //! See documentation in DCP.h && !STLUtils::Contains(dimname, "density") #endif ) { assert(0); return false; } map::const_iterator itr; itr = _dimsMap.find(dimname); if (itr == _dimsMap.end()) return (false); dimension = itr->second; if (dimension.IsTimeVarying()) { long len = _ncdfc->GetDimLengthAtTime(dimname, ts); if (len >= 0) { dimension = Dimension(dimname, len); } } return true; } std::vector DCP::getDimensionNames() const { map::const_iterator itr; vector names; for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } vector DCP::getMeshNames() const { vector mesh_names; std::map::const_iterator itr = _meshMap.begin(); for (; itr != _meshMap.end(); ++itr) { mesh_names.push_back(itr->first); } return (mesh_names); } bool DCP::getMesh(string mesh_name, DC::Mesh &mesh) const { map::const_iterator itr = _meshMap.find(mesh_name); if (itr == _meshMap.end()) return (false); mesh = itr->second; return (true); } bool DCP::getCoordVarInfo(string varname, DC::CoordVar &cvar) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr == _coordVarsMap.end()) { return (false); } cvar = itr->second; return (true); } bool DCP::getDataVarInfo(string varname, DC::DataVar &datavar) const { map::const_iterator itr; itr = _dataVarsMap.find(varname); if (itr == _dataVarsMap.end()) { return (false); } datavar = itr->second; return (true); } bool DCP::getBaseVarInfo(string varname, DC::BaseVar &var) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr != _coordVarsMap.end()) { var = itr->second; return (true); } map::const_iterator itr1 = _dataVarsMap.find(varname); if (itr1 != _dataVarsMap.end()) { var = itr1->second; return (true); } return (false); } std::vector DCP::getDataVarNames() const { map::const_iterator itr; vector names; for (itr = _dataVarsMap.begin(); itr != _dataVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } std::vector DCP::getCoordVarNames() const { map::const_iterator itr; vector names; for (itr = _coordVarsMap.begin(); itr != _coordVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } template bool DCP::_getAttTemplate(string varname, string attname, T &values) const { // printf("%s(%s, %s, %s&)\n", __func__, varname.c_str(), attname.c_str(), TypeToChar(values)); if (_ncdfc->GetAttType(varname, attname) < 0) return false; _ncdfc->GetAtt(varname, attname, values); return (true); } bool DCP::getAtt(string varname, string attname, vector &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } bool DCP::getAtt(string varname, string attname, vector &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } bool DCP::getAtt(string varname, string attname, string &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } std::vector DCP::getAttNames(string varname) const { // printf("%s(%s) = ", __func__, varname.c_str()); if (varname.empty()) { return _ncdfc->GetAttNames(""); } else { DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) { // printf("{} (ERR)\n"); return (vector()); } vector names; const std::map & atts = var.GetAttributes(); std::map::const_iterator itr; for (itr = atts.begin(); itr != atts.end(); ++itr) { names.push_back(itr->first); } // printf("%s\n", ToStr(names).c_str()); return (names); } } DC::XType DCP::getAttType(string varname, string attname) const { // printf("%s(%s, %s)\n", __func__, varname.c_str(), attname.c_str()); DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) return (DC::INVALID); DC::Attribute att; status = var.GetAttribute(attname, att); if (!status) return (DC::INVALID); return (att.GetXType()); } int DCP::getDimLensAtLevel(string varname, int, std::vector &dims_at_level, std::vector &bs_at_level) const { VAssert(0); return -1; } int DCP::getDimLensAtLevel(string varname, int, std::vector &dims_at_level, std::vector &bs_at_level, long ts) const { dims_at_level.clear(); bs_at_level.clear(); bool ok = GetVarDimLens(varname, true, dims_at_level, ts); if (!ok) { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (-1); } // Never blocked // bs_at_level = vector(dims_at_level.size(), 1); return (0); } int DCP::openVariableRead(size_t ts, string varname) { // printf("DCP::%s(%li, %s) = ", __func__, ts, varname.c_str()); if (STLUtils::Contains(_fakeVars, varname)) { int ret = _fakeVarsFileCounter++; // printf("(fake) %i\n", ret); _fdMap[ret] = varname; return ret; } string ncdfName = varname; if (STLUtils::EndsWith(ncdfName, "_x") || STLUtils::EndsWith(ncdfName, "_y") || STLUtils::EndsWith(ncdfName, "_z")) { if (!_ncdfc->VariableExists(varname)) { ncdfName = ncdfName.substr(0, ncdfName.length() - 2); // printf("\n\t"); // printf("DCP::%s(%li, %s) = ", __func__, ts, ncdfName.c_str()); } } ncdfName = getOriginalVarName(ncdfName); int aux = _ncdfc->OpenRead(ts, ncdfName); if (!(aux < 0)) { FileTable::FileObject *f = new FileTable::FileObject(ts, ncdfName, 0, 0, aux); aux = _fileTable.AddEntry(f); } // printf("%i\n", aux); _fdMap[aux] = varname; return aux; } int DCP::closeVariable(int fd) { // printf("DCP::%s(%i)\n", __func__, fd); auto fdIt = _fdMap.find(fd); if (fdIt != _fdMap.end()) _fdMap.erase(fdIt); if (fd >= _fakeVarsFileCounterStart) { _fakeVarsFileCounter--; return 0; } DC::FileTable::FileObject *w = _fileTable.GetEntry(fd); if (!w) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int aux = w->GetAux(); int rc = _ncdfc->Close(aux); _fileTable.RemoveEntry(fd); return (rc); } // min -> max is inclusive template int DCP::_readRegionTemplate(int fd, const vector &min_, const vector &max_, T *region) { vector min = min_; vector max = max_; string varname = _fdMap[fd]; // printf("%s(%i(%s), %s, %s, %s*)\n", __func__, fd, varname.c_str(), ToStr(min).c_str(), ToStr(max).c_str(), TypeToChar(*region)); // VAssert(min.size() == 1); bool fake = fd >= _fakeVarsFileCounterStart; if (fake) { if (_fdMap[fd] == _fakeEmptyVar) { for (size_t i = min[0]; i <= max[0]; i++) region[i] = 0; } else { for (size_t i = min[0]; i <= max[0]; i++) region[i] = i / (double)(max[0] - 1); } return 0; } if (!_ncdfc->VariableExists(varname)) { int axis = -1; if (STLUtils::EndsWith(varname, "_x")) axis = 0; if (STLUtils::EndsWith(varname, "_y")) axis = 1; if (STLUtils::EndsWith(varname, "_z")) axis = 2; if (axis != -1) { // printf("\t Read data from header\n"); // for (size_t i = min[0]; i <= max[0]; i++) // region[i] = Particle_Position[i*3+axis]; // return 0; // min.push_back(axis); // max.push_back(axis); min.push_back(min[0]); max.push_back(max[0]); min[0] = axis; max[0] = axis; // printf("\t %s(%i(%s), %s, %s, %s*)\n", __func__, fd, varname.substr(0,varname.length()-2).c_str(), ToStr(min).c_str(), ToStr(max).c_str(), TypeToChar(*region)); } } FileTable::FileObject *w = (FileTable::FileObject *)_fileTable.GetEntry(fd); if (!w) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int aux = w->GetAux(); vector ncdf_start = min; reverse(ncdf_start.begin(), ncdf_start.end()); vector ncdf_max = max; reverse(ncdf_max.begin(), ncdf_max.end()); vector ncdf_count; for (int i = 0; i < ncdf_start.size(); i++) { ncdf_count.push_back(ncdf_max[i] - ncdf_start[i] + 1); } return (_ncdfc->Read(ncdf_start, ncdf_count, region, aux)); } bool DCP::variableExists(size_t ts, string varname, int, int) const { bool found = false; for (const auto &it : _dataVarsMap) { if (found) break; if (it.first == varname) found = true; } for (const auto &it : _coordVarsMap) { if (found) break; if (it.first == varname) found = true; } for (const auto &it : _auxVarsMap) { if (found) break; if (it.first == varname) found = true; } // if (found == false) // printf("WARNING %s(%li, %s) = %s\n", __func__, ts, varname.c_str(), found?"true":"false"); return found; } std::vector DCP::getAuxVarNames() const { vector names(_auxVarsMap.size()); for (const auto &it : _auxVarsMap) names.push_back(it.first); return names; } bool DCP::getAuxVarInfo(string varname, DC::AuxVar &var) const { const auto &it = _auxVarsMap.find(varname); if (it == _auxVarsMap.end()) return false; var = it->second; return true; } string DCP::sanitizeVarName(const string &name) { assert(_sanitizedToOriginalMap.count(name) == 0); string sanitizedName = name; ReplaceAll(&sanitizedName, ' ', '_'); _sanitizedToOriginalMap[sanitizedName] = name; return sanitizedName; } string DCP::getOriginalVarName(const string &name) const { auto it = _sanitizedToOriginalMap.find(name); if (it == _sanitizedToOriginalMap.end()) return name; return it->second; } ================================================ FILE: lib/vdc/DCRAM.cpp ================================================ #include #include #include #include #include #include #include "vapor/VAssert.h" #include #ifdef _WINDOWS #define _USE_MATH_DEFINES #pragma warning(disable : 4251 4100) #endif #include #include #include #include #include using namespace VAPoR; DCRAM::DCRAM() { _dimsMap.clear(); _coordVarsMap.clear(); _meshMap.clear(); } DCRAM::~DCRAM() { for (const auto &it : _dataMap) delete [] it.second; _dataMap.clear(); } int DCRAM::initialize(const vector &paths, const std::vector &options) { #ifdef DCRAM_GENERATE_TEST_DATA // Dimensions // ================== string particlesDim; string axisDim; auto dimNames = ncdfc->GetDimNames(); auto dimLens = ncdfc->GetDims(); auto dimIsTimeVarying = ncdfc->GetDimsAreTimeVarying(); _dimsMap["dimX"] = DC::Dimension("dimX", 32); _dimsMap["dimY"] = DC::Dimension("dimY", 32); _dimsMap["dimZ"] = DC::Dimension("dimZ", 32); // Coords // ================== const vector periodic(false); _coordVarsMap["coordX"] = CoordVar("coordX", "m", DC::FLOAT, periodic, /*axis=x*/0, /*uniformHint=*/true, {"dimX"}, /*timeDim*/""); _coordVarsMap["coordY"] = CoordVar("coordY", "m", DC::FLOAT, periodic, /*axis=y*/1, /*uniformHint=*/true, {"dimY"}, /*timeDim*/""); _coordVarsMap["coordZ"] = CoordVar("coordZ", "m", DC::FLOAT, periodic, /*axis=z*/2, /*uniformHint=*/true, {"dimZ"}, /*timeDim*/""); // Mesh // ================== vector dims = {"dimX", "dimY", "dimZ"}; vector coords = {"coordX", "coordY", "coordZ"}; DC::Mesh mesh("test_mesh", dims, coords); _meshMap[mesh.GetName()] = mesh; // Data Vars // ================== { vector periodic(3, false); _dataVarsMap["sphere"] = DC::DataVar("sphere", "", DC::FLOAT, periodic, mesh.GetName(), /*timeCoordVar*/"", DC::Mesh::NODE); _dataVarsMap["empty"] = DC::DataVar("empty", "", DC::FLOAT, periodic, mesh.GetName(), /*timeCoordVar*/"", DC::Mesh::NODE); _dataVarsMap["xval"] = DC::DataVar("xval", "", DC::FLOAT, periodic, mesh.GetName(), /*timeCoordVar*/"", DC::Mesh::NODE); } #endif return 0; } void DCRAM::Test() { #ifdef DCRAM_GENERATE_TEST_DATA // ========================== // New data on existing grid // ========================== vector periodic(3, false); _dataVarsMap["sine"] = DC::DataVar("sine", "", DC::FLOAT, periodic, "test_mesh", /*timeCoordVar*/"", DC::Mesh::NODE); // ========================== // New data on new grid // ========================== _dimsMap["dim2X"] = DC::Dimension("dim2X", 64); _dimsMap["dim2Y"] = DC::Dimension("dim2Y", 64); _dimsMap["dim2Z"] = DC::Dimension("dim2Z", 64); // Coords // ================== _coordVarsMap["coord2X"] = CoordVar("coord2X", "m", DC::FLOAT, periodic, /*axis=x*/0, /*uniformHint=*/true, {"dim2X"}, /*timeDim*/""); _coordVarsMap["coord2Y"] = CoordVar("coord2Y", "m", DC::FLOAT, periodic, /*axis=y*/1, /*uniformHint=*/true, {"dim2Y"}, /*timeDim*/""); _coordVarsMap["coord2Z"] = CoordVar("coord2Z", "m", DC::FLOAT, periodic, /*axis=z*/2, /*uniformHint=*/true, {"dim2Z"}, /*timeDim*/""); // Mesh // ================== vector dims = {"dim2X", "dim2Y", "dim2Z"}; vector coords = {"coord2X", "coord2Y", "coord2Z"}; DC::Mesh mesh("test_mesh2", dims, coords); _meshMap[mesh.GetName()] = mesh; _dataVarsMap["grid"] = DC::DataVar("grid", "", DC::FLOAT, periodic, "test_mesh2", /*timeCoordVar*/"", DC::Mesh::NODE); _dataVarsMap["xval2"] = DC::DataVar("xval2", "", DC::FLOAT, periodic, "test_mesh2", /*timeCoordVar*/"", DC::Mesh::NODE); // ========================== // New data on curve grid // ========================== _dimsMap["curveDimX"] = DC::Dimension("curveDimX", 8); _dimsMap["curveDimY"] = DC::Dimension("curveDimY", 8); _dimsMap["curveDimZ"] = DC::Dimension("curveDimZ", 8); // Coords // ================== _coordVarsMap["curveCoordX"] = CoordVar("curveCoordX", "m", DC::FLOAT, periodic, /*axis=x*/0, /*uniformHint=*/false, {"curveDimX", "curveDimY"}, /*timeDim*/""); _coordVarsMap["curveCoordY"] = CoordVar("curveCoordY", "m", DC::FLOAT, periodic, /*axis=y*/1, /*uniformHint=*/false, {"curveDimX", "curveDimY"}, /*timeDim*/""); _coordVarsMap["curveCoordZ"] = CoordVar("curveCoordZ", "m", DC::FLOAT, periodic, /*axis=z*/2, /*uniformHint=*/false, {"curveDimX", "curveDimY", "curveDimZ"}, /*timeDim*/""); // Mesh // ================== vector curveDims = {"curveDimX", "curveDimY", "curveDimZ"}; vector curveCoords = {"curveCoordX", "curveCoordY", "curveCoordZ"}; DC::Mesh curveMesh("curveMesh", curveDims, curveCoords); _meshMap[curveMesh.GetName()] = curveMesh; _dataVarsMap["curveData"] = DC::DataVar("curveData", "", DC::FLOAT, periodic, curveMesh.GetName(), /*timeCoordVar*/"", DC::Mesh::NODE); #endif } void DCRAM::AddDimension(const DC::Dimension &dim) { _dimsMap[dim.GetName()] = dim; } void DCRAM::AddMesh(const DC::Mesh &mesh) { _meshMap[mesh.GetName()] = mesh; } void DCRAM::AddCoordVar(const DC::CoordVar &var, const float *buf) { _coordVarsMap[var.GetName()] = var; size_t size = 1; auto dimNames = var.GetDimNames(); for (auto name : dimNames) { DC::Dimension dim; getDimension(name, dim); size *= dim.GetLength(); } copyVarData(var, buf, size); } void DCRAM::AddDataVar(const DC::DataVar &var, const float *buf) { _dataVarsMap[var.GetName()] = var; size_t size = 1; vector dimLens; GetMeshDimLens(var.GetMeshName(), dimLens); for (auto len : dimLens) size *= len; copyVarData(var, buf, size); } void DCRAM::copyVarData(const DC::BaseVar &var, const float *buf, const size_t size) { if (_dataMap.count(var.GetName())) delete [] _dataMap[var.GetName()]; float *copy = new float[size]; memcpy(copy, buf, sizeof(float)*size); _dataMap[var.GetName()] = copy; } bool DCRAM::getDimension(string dimname, DC::Dimension &dimension) const { return getDimension(dimname, dimension, -1); } bool DCRAM::getDimension(string dimname, DC::Dimension &dimension, long ts) const { map::const_iterator itr; itr = _dimsMap.find(dimname); if (itr == _dimsMap.end()) return (false); dimension = itr->second; if (dimension.IsTimeVarying()) { #ifndef NDEBUG printf("WARNING: RAM dimension '%s' is time varying", dimname.c_str()); #endif } return true; } std::vector DCRAM::getDimensionNames() const { map::const_iterator itr; vector names; for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } vector DCRAM::getMeshNames() const { vector mesh_names; std::map::const_iterator itr = _meshMap.begin(); for (; itr != _meshMap.end(); ++itr) { mesh_names.push_back(itr->first); } return (mesh_names); } bool DCRAM::getMesh(string mesh_name, DC::Mesh &mesh) const { map::const_iterator itr = _meshMap.find(mesh_name); if (itr == _meshMap.end()) return (false); mesh = itr->second; return (true); } bool DCRAM::getCoordVarInfo(string varname, DC::CoordVar &cvar) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr == _coordVarsMap.end()) { return (false); } cvar = itr->second; return (true); } bool DCRAM::getDataVarInfo(string varname, DC::DataVar &datavar) const { map::const_iterator itr; itr = _dataVarsMap.find(varname); if (itr == _dataVarsMap.end()) { return (false); } datavar = itr->second; return (true); } bool DCRAM::getBaseVarInfo(string varname, DC::BaseVar &var) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr != _coordVarsMap.end()) { var = itr->second; return (true); } map::const_iterator itr1 = _dataVarsMap.find(varname); if (itr1 != _dataVarsMap.end()) { var = itr1->second; return (true); } return (false); } std::vector DCRAM::getDataVarNames() const { map::const_iterator itr; vector names; for (itr = _dataVarsMap.begin(); itr != _dataVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } std::vector DCRAM::getCoordVarNames() const { map::const_iterator itr; vector names; for (itr = _coordVarsMap.begin(); itr != _coordVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } template bool DCRAM::_getAttTemplate(string varname, string attname, T &values) const { DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) return false; const std::map &atts = var.GetAttributes(); if (!atts.count(attname)) return false; atts.at(attname).GetValues(values); return true; } bool DCRAM::getAtt(string varname, string attname, vector &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } bool DCRAM::getAtt(string varname, string attname, vector &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } bool DCRAM::getAtt(string varname, string attname, string &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } std::vector DCRAM::getAttNames(string varname) const { if (varname.empty()) { return {}; } else { DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) { return (vector()); } vector names; const std::map & atts = var.GetAttributes(); std::map::const_iterator itr; for (itr = atts.begin(); itr != atts.end(); ++itr) { names.push_back(itr->first); } return (names); } } DC::XType DCRAM::getAttType(string varname, string attname) const { DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) return (DC::INVALID); DC::Attribute att; status = var.GetAttribute(attname, att); if (!status) return (DC::INVALID); return (att.GetXType()); } int DCRAM::getDimLensAtLevel(string varname, int, std::vector &dims_at_level, std::vector &bs_at_level) const { VAssert(0); return -1; } int DCRAM::getDimLensAtLevel(string varname, int, std::vector &dims_at_level, std::vector &bs_at_level, long ts) const { dims_at_level.clear(); bs_at_level.clear(); bool ok = GetVarDimLens(varname, true, dims_at_level, ts); if (!ok) { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (-1); } // Never blocked // bs_at_level = vector(dims_at_level.size(), 1); return (0); } int DCRAM::openVariableRead(size_t ts, string varname) { int ret = _fakeVarsFileCounter++; _fdMap[ret] = varname; return ret; } int DCRAM::closeVariable(int fd) { auto fdIt = _fdMap.find(fd); if (fdIt != _fdMap.end()) _fdMap.erase(fdIt); if (fd >= _fakeVarsFileCounterStart) { _fakeVarsFileCounter--; return 0; } assert(0); return -1; } // min -> max is inclusive #include using glm::vec3; using glm::vec2; template int DCRAM::_readRegionTemplate(int fd, const vector &min_, const vector &max_, T *region) { vector min = min_; vector max = max_; string varname = _fdMap[fd]; // printf("%s(%i(%s), %s, %s, %s*)\n", __func__, fd, varname.c_str(), S(min).c_str(), S(max).c_str(), TypeToChar(*region)); bool fake = fd >= _fakeVarsFileCounterStart; const size_t w = 1 + max[0] - min[0]; const size_t h = 1 + max[1] - min[1]; const size_t d = 1 + max[2] - min[2]; vec3 s(w,h,d); #ifdef DCRAM_GENERATE_TEST_DATA vec3 c = s/2.f; #endif auto var3d = [=](function f) { for (size_t z = min[2]; z <= max[2]; z++) for (size_t y = min[1]; y <= max[1]; y++) for (size_t x = min[0]; x <= max[0]; x++) region[z*w*h+y*w+x] = f(vec3(x,y,z)); return 0; }; auto var2d = [=](function f) { for (size_t y = min[1]; y <= max[1]; y++) for (size_t x = min[0]; x <= max[0]; x++) region[y*w+x] = f(vec2(x,y)); return 0; }; if (_dataMap.count(varname)) { float *data = _dataMap[varname]; vector dimLens; GetVarDimLens(varname, true, dimLens); assert((dimLens.size() == min.size()) && (min.size() == max.size())); int nDims = dimLens.size(); size_t rw=0, rh=0, sx=0, sy=0, sz=0; rw = dimLens[0]; sx = min[0]; if (nDims > 1) { rh = dimLens[1]; sy = min[1]; } if (nDims > 2) { sz = min[2]; } if (nDims == 1) { for (size_t x = min[0]; x <= max[0]; x++) region[(x-sx)] = data[x]; } else if (nDims == 2) { for (size_t y = min[1]; y <= max[1]; y++) for (size_t x = min[0]; x <= max[0]; x++) region[(y-sy)*w+(x-sx)] = data[y*rw+x]; } else if (nDims == 3) { for (size_t z = min[2]; z <= max[2]; z++) for (size_t y = min[1]; y <= max[1]; y++) for (size_t x = min[0]; x <= max[0]; x++) region[(z-sz)*w*h+(y-sy)*w+(x-sx)] = data[z*rw*rh+y*rw+x]; } return 0; } #ifdef DCRAM_GENERATE_TEST_DATA if (varname == "empty") return var3d([=](vec3 p) { return 0; }); if (varname == "sphere") return var3d([=](vec3 p) { return glm::distance(p, c); }); if (varname == "sine") return var3d([=](vec3 p) { return sinf(p.x/(float)w*36); }); if (varname == "grid") return var3d([=](vec3 p) { return (int)p.x/8%2 == (int)p.y/8%2 == (int)p.z/8%2; }); if (varname == "xval" || varname == "xval2") return var3d([=](vec3 p) { return p.x; }); if (varname == "curveCoordX") return var2d([=](vec2 p) { return cosf(p.y/(float)h*M_PI) * (p.x+(w+1)); }); if (varname == "curveCoordY") return var2d([=](vec2 p) { return sinf(p.y/(float)h*M_PI) * (p.x+(w+1)); }); if (varname == "curveCoordZ") return var3d([=](vec3 p) { return p.z; }); if (varname == "curveData") return var3d([=](vec3 p) { return glm::distance(p, c); }); #endif if (fake) { // Generate Regular Coords for (size_t i = min[0]; i <= max[0]; i++) region[i] = i / (double)(max[0] - 1); return 0; } VAssert(0); return -1; } bool DCRAM::variableExists(size_t ts, string varname, int, int) const { bool found = false; for (const auto &it : _dataVarsMap) { if (found) break; if (it.first == varname) found = true; } for (const auto &it : _coordVarsMap) { if (found) break; if (it.first == varname) found = true; } for (const auto &it : _auxVarsMap) { if (found) break; if (it.first == varname) found = true; } return found; } std::vector DCRAM::getAuxVarNames() const { vector names(_auxVarsMap.size()); for (const auto &it : _auxVarsMap) names.push_back(it.first); return names; } bool DCRAM::getAuxVarInfo(string varname, DC::AuxVar &var) const { const auto &it = _auxVarsMap.find(varname); if (it == _auxVarsMap.end()) return false; var = it->second; return true; } ================================================ FILE: lib/vdc/DCUGRID.cpp ================================================ #include #include #include #include #include #include #include #include #include using namespace VAPoR; using namespace std; namespace { // Attribute names and values for "dummy" UGRID mesh variable // const string cfRoleAttName = "cf_role"; const string cfRoleValueName = "mesh_topology"; const string topologyAttName = "topology_dimension"; const string nodeCoordinatesAttName = "node_coordinates"; const string faceNodeConnectivityAttName = "face_node_connectivity"; const string faceDimensionAttName = "face_dimension"; const string edgeNodeConnectivityAttName = "edge_node_connectivity"; const string edgeDimensionAttName = "edge_dimension"; const string faceEdgeConnectivityAttName = "face_edge_connectivity"; const string faceFaceConnectivityAttName = "face_face_connectivity"; const string edgeFaceConnectivityAttName = "edge_face_connectivity"; const string boundaryNodeConnectivityAttName = "boundary_node_connectivity"; const string faceCoordinatesAttName = "face_coordinates"; const string edgeCoordinatesAttName = "edge_coordinates"; // Attribute names and values for data variables // const string meshAttName = "mesh"; const string locationAttName = "location"; template int getVar(NetCDFCFCollection *ncdfc, size_t ts, string varname, T *buf) { int fd = ncdfc->OpenRead(ts, varname); if (fd < 0) return (fd); int rc = ncdfc->Read(buf, fd); if (rc < 0) return (fd); return (ncdfc->Close(fd)); } // Read a netcdf attribute of type int // int getAttInt(NetCDFCFCollection *ncdfc, string varName, string attName) { vector values; ncdfc->GetAtt(varName, attName, values); if (values.size()) { return (values[0]); } return (0); } // Read a netcdf attribute of type string // string getAttString(NetCDFCFCollection *ncdfc, string varName, string attName) { string v; ncdfc->GetAtt(varName, attName, v); return (v); } bool isUGridDummyVar(NetCDFCFCollection *ncdfc, string varName) { string v = getAttString(ncdfc, varName, cfRoleAttName); return (v == cfRoleValueName); } void unzipLongitude(vector &connVar, size_t numFaces, size_t maxNodes, const vector &lonVar, int missingNode) { VAssert(connVar.size() == numFaces * maxNodes); for (size_t j = 0; j < numFaces; j++) { // Sanitize the connectivity array // for (size_t i = 0; i < maxNodes; i++) { int nodeIdx = connVar[j * maxNodes + i]; if (nodeIdx < 0 || nodeIdx >= lonVar.size()) { connVar[j * maxNodes + i] = missingNode; } } // Find first valid node // size_t i = 0; for (; i < maxNodes; i++) { int nodeIdx = connVar[j * maxNodes + i]; if (nodeIdx != missingNode) { break; } } float p0 = 0.0; if (i < maxNodes) { int nodeIdx = connVar[j * maxNodes + i]; p0 = lonVar[nodeIdx]; i++; } for (; i < maxNodes; i++) { int nodeIdx = connVar[j * maxNodes + i]; if (nodeIdx == missingNode || (std::abs(p0 - lonVar[nodeIdx])) > 180.0) { connVar[j * maxNodes + i] = -2; } } } } }; // namespace // The vertical coordinate for a "layered" mesh is not explicity identified // by a mesh "dummy" variable. Instead we have to identify them using // the rules of the NetCDF CF conventions upon which UGRID is based // string DCUGRID::_getLayeredVerticalCoordVar(NetCDFCFCollection *ncdfc, string varName) const { // First check for CF "1D coordinate" variable. I.e a variable // with the same name as the vertical dimension // vector dimNames = ncdfc->GetSpatialDimNames(varName); if (dimNames.size() != 2) return (""); if (ncdfc->IsCoordVarCF(dimNames[0]) && ncdfc->IsVertCoordVar(dimNames[0])) { return (dimNames[0]); } // We didn't find a "1D coordinate" variable, so see if varName's // "coordinates" attribute names a vertical coordinate. I.e. look // for what the CF conventions call an "auxilliary" variable // string meshName = getAttString(ncdfc, varName, meshAttName); if (meshName.empty() || (_uGridMeshMap.find(meshName) == _uGridMeshMap.end())) { return (""); } string s; ncdfc->GetAtt(varName, "coordinates", s); vector atts; Wasp::StrToWordVec(s, atts); for (auto att : atts) { if (ncdfc->IsVertCoordVar(att)) return (att); } return (""); } // Read metadata for a UGRID "dummy" mesh variable, but do no validatation // void DCUGRID::_getUGridMeshFromFile(NetCDFCFCollection *ncdfc, string meshVarName, uGridMeshType &m) { m.topology = 0; m.nodeCoordinates = {}; m.faceNodeConnectivity = ""; m.faceDimension = ""; m.edgeNodeConnectivity = ""; m.edgeDimension = ""; m.faceEdgeConnectivity = ""; m.faceFaceConnectivity = ""; m.edgeFaceConnectivity = ""; m.boundaryNodeConnectivity = ""; m.faceCoordinates = {}; m.edgeCoordinates = {}; string s; m.topology = getAttInt(ncdfc, meshVarName, topologyAttName); s = getAttString(ncdfc, meshVarName, nodeCoordinatesAttName); Wasp::StrToWordVec(s, m.nodeCoordinates); m.faceNodeConnectivity = getAttString(ncdfc, meshVarName, faceNodeConnectivityAttName); m.faceDimension = getAttString(ncdfc, meshVarName, faceDimensionAttName); m.edgeNodeConnectivity = getAttString(ncdfc, meshVarName, edgeNodeConnectivityAttName); m.edgeDimension = getAttString(ncdfc, meshVarName, edgeDimensionAttName); m.faceEdgeConnectivity = getAttString(ncdfc, meshVarName, faceEdgeConnectivityAttName); m.faceFaceConnectivity = getAttString(ncdfc, meshVarName, faceFaceConnectivityAttName); m.edgeFaceConnectivity = getAttString(ncdfc, meshVarName, edgeFaceConnectivityAttName); m.boundaryNodeConnectivity = getAttString(ncdfc, meshVarName, boundaryNodeConnectivityAttName); s = getAttString(ncdfc, meshVarName, faceCoordinatesAttName); Wasp::StrToWordVec(s, m.faceCoordinates); s = getAttString(ncdfc, meshVarName, edgeCoordinatesAttName); Wasp::StrToWordVec(s, m.edgeCoordinates); } // Get the meshes node dimension by way of meshes' coordinate variables // string DCUGRID::_getMeshNodeDimName(NetCDFCFCollection *ncdfc, const uGridMeshType &m) const { if (!m.nodeCoordinates.size()) { return (""); } // Pick the first coordinate variable. According to the spec they must // all be dimension'd by nNodes // string cVarName = m.nodeCoordinates[0]; vector dimNames = ncdfc->GetSpatialDimNames(cVarName); if (!dimNames.size()) { return (""); } return (dimNames[0]); } // Get the meshes face dimension by way of meshes' face-node connectivity // variables // string DCUGRID::_getMeshFaceDimName(NetCDFCFCollection *ncdfc, const uGridMeshType &m) const { if (m.faceNodeConnectivity.empty()) { return (""); } vector dimNames = ncdfc->GetSpatialDimNames(m.faceNodeConnectivity); if (!dimNames.size()) { return (""); } return (dimNames[0]); } // Get the meshes max nodes per face // size_t DCUGRID::_getMeshMaxNodesPerFace(NetCDFCFCollection *ncdfc, const uGridMeshType &m) const { if (m.faceNodeConnectivity.empty()) { return (0); } vector dimLens = ncdfc->GetSpatialDims(m.faceNodeConnectivity); if (dimLens.size() < 2) { return (0); } return (dimLens[1]); } // Get the time coordinate variable for a named variable // bool DCUGRID::_getVarTimeCoords(NetCDFCFCollection *ncdfc, string varName, string &coordName) const { coordName.clear(); vector vars = ncdfc->GetTimeCoordVars(); string timeDimName = ncdfc->GetTimeDimName(varName); if (find(vars.begin(), vars.end(), timeDimName) != vars.end()) { coordName = timeDimName; } return (true); } int DCUGRID::_initFaceNodeConnectivityMap(NetCDFCFCollection *ncdfc) { _faceNodeConnectivityMap.clear(); // We need to synthesize the node-on-face connectivity map for each // mesh, splitting // faces that straddle the min and max longitude extent // vector meshNames = GetMeshNames(); for (auto mName : meshNames) { DC::Mesh mesh; bool ok = GetMesh(mName, mesh); VAssert(ok); string connVarName = mesh.GetFaceNodeVar(); // Get the longitude coordinate variable name for this mesh // string lonVarName; vector coordVarNames = mesh.GetCoordVars(); for (auto coordVarName : coordVarNames) { DC::CoordVar cvar; ok = GetCoordVarInfo(coordVarName, cvar); VAssert(ok); if (cvar.GetAxis() == 0) { lonVarName = coordVarName; break; } } if (lonVarName.empty()) { SetErrMsg("Invalid mesh %s : No longitude variable", mName.c_str()); return (-1); } // If a connection variable has a Fill Value attribute it indicates // missing nodes from a face. I.e. faces that less than the maximum // number of nodes. // int missingNode = -1; vector atts; ok = GetAtt(connVarName, "_FillValue", atts); if (ok && atts.size() > 0) missingNode = atts[0]; vector connVarDims; GetDimLens(connVarName, connVarDims); VAssert(connVarDims.size() == 2); vector lonVarDims; GetDimLens(lonVarName, lonVarDims); VAssert(lonVarDims.size() == 1); // Allocate space for the synthetic variable // _faceNodeConnectivityMap[connVarName] = vector(connVarDims[0] * connVarDims[1], 0); vector &connVar = _faceNodeConnectivityMap[connVarName]; int rc = getVar(ncdfc, 0, connVarName, connVar.data()); if (rc < 0) { SetErrMsg("Unable to read connectivity variable %s", connVarName.c_str()); return (rc); } // N.B. Can't call DC::GetVar because this class overrides it // vector lonVar(lonVarDims[0], 0); rc = getVar(ncdfc, 0, lonVarName, lonVar.data()); if (rc < 0) { SetErrMsg("Unable to read longitude coordinate variable %s", lonVarName.c_str()); return (rc); } unzipLongitude(connVar, connVarDims[1], connVarDims[0], lonVar, missingNode); } return (0); } int DCUGRID::initialize(const vector &paths, const std::vector &options) { int rc = DCCF::initialize(paths, options); if (rc < 0) return (rc); return (_initFaceNodeConnectivityMap(_ncdfc)); } int DCUGRID::initMesh(NetCDFCFCollection *ncdfc, std::map &meshMap) { // // Get names of variables of all the 0D variables so we can look // for the UGRID "dummy" variables. N.B. we can't use // NetCDFCFCollection::GetDataVariableNames() because that class // distinguishes data variables from other variables in a way // that is not compatible with UGRID // vector vars = ncdfc->GetVariableNames(0, true); for (auto v : vars) { if (!isUGridDummyVar(ncdfc, v)) { continue; } uGridMeshType m; _getUGridMeshFromFile(ncdfc, v, m); _uGridMeshMap[v] = m; } // Next go through list of all variables in the file, identify those that // are associated with one of the meshes we just found, and convert // from uGridMeshType to DC::Mesh // vars.clear(); for (int i = 1; i < 4; i++) { vector v = ncdfc->GetVariableNames(i, true); vars.insert(vars.end(), v.begin(), v.end()); } // For each variable determine the mesh // for (auto varName : vars) { // variable type must be float or int // int type = ncdfc->GetXType(varName); if (!(NetCDFSimple::IsNCTypeFloat(type) || NetCDFSimple::IsNCTypeInt(type))) continue; string meshName = getAttString(ncdfc, varName, meshAttName); if (meshName.empty() || (_uGridMeshMap.find(meshName) == _uGridMeshMap.end())) { continue; } auto itr = _uGridMeshMap.find(meshName); if (itr == _uGridMeshMap.end()) { continue; } const uGridMeshType &m = itr->second; string nodeDimName = _getMeshNodeDimName(ncdfc, m); string faceDimName = _getMeshFaceDimName(ncdfc, m); size_t maxNodesPerFace = _getMeshMaxNodesPerFace(ncdfc, m); // We could calculate the max faces per node, but this isn't // used and should probably be removed from the Mesh class // size_t maxFacesPerNode = 0; vector dimNames = ncdfc->GetSpatialDimNames(varName); reverse(dimNames.begin(), dimNames.end()); if (dimNames.size() == 1) { // Create new mesh. We're being lazy here and probably should only // create one if it doesn't ready exist // meshMap[meshName] = Mesh(meshName, maxNodesPerFace, maxFacesPerNode, nodeDimName, faceDimName, m.nodeCoordinates, m.faceNodeConnectivity, ""); } else if (dimNames.size() == 2) { // Layered grids (dimNames.size() == 2) require special handling // to identify the vertical coordinate. Also, because non layered // (2D) and layered (3D) variables can share the same UGRID mesh // we need to generate a unique mesh name for one of them // string layeredVarName = _getLayeredVerticalCoordVar(ncdfc, varName); if (layeredVarName.empty()) continue; vector coordVarNames = m.nodeCoordinates; coordVarNames.push_back(layeredVarName); meshName += layeredVarName; meshMap[meshName] = Mesh(meshName, maxNodesPerFace, maxFacesPerNode, nodeDimName, faceDimName, dimNames[1], coordVarNames, m.faceNodeConnectivity, ""); } else { continue; } } // Should the correct behavior be to return an error code if // no valid meshes are found? Right now need this is done so that MainForm // can auto-detect the file. We should probably introduce a separate // detection method on the DC class. // if (meshMap.size() == 0) { SetErrMsg("No valid UGRID meshes found"); return (-1); } return (0); } int DCUGRID::initAuxilliaryVars(NetCDFCFCollection *ncdfc, std::map &auxVarsMap) { auxVarsMap.clear(); vector periodic(3, false); // // Get names of variables in the UGRID data set that have 1 or 2 // "spatial" dimensions // vector vars; for (int i = 1; i < 3; i++) { vector v = ncdfc->GetVariableNames(i, true); vars.insert(vars.end(), v.begin(), v.end()); } for (auto varName : vars) { // variable type must be int // int type = ncdfc->GetXType(varName); if (!(NetCDFSimple::IsNCTypeInt(type))) { continue; } vector dimnames = ncdfc->GetSpatialDimNames(varName); if (!dimnames.size()) continue; reverse(dimnames.begin(), dimnames.end()); auxVarsMap[varName] = AuxVar(varName, "", DC::INT32, "", vector(), periodic, dimnames); } return (0); } int DCUGRID::initDataVars(NetCDFCFCollection *ncdfc, std::map &dataVarsMap) { dataVarsMap.clear(); vector periodic(3, false); // // Get names of variables in the UGRID data set that have 1 or 2 // "spatial" dimensions // vector vars; for (int i = 1; i < 3; i++) { vector v = ncdfc->GetVariableNames(i, true); vars.insert(vars.end(), v.begin(), v.end()); } // For each variable add a member to dataVarsMap // for (auto varName : vars) { // variable type must be float // int type = ncdfc->GetXType(varName); if (!(NetCDFSimple::IsNCTypeFloat(type))) { continue; } // Checking for whether a variable can be a coordinate variable // eliminates a lot of variables from being data variables. There // doesn't seem to be any reason why a variable can't be both a // data variable and a coordinate variable. Leaving this code // commented out for now. // // if (IsCoordVar(varName)) {continue; } // Currently coordinate variables can't be data variables :-( // if (ncdfc->IsCoordinateVar(varName)) continue; // variable must have valid mesh attribute // string meshName = getAttString(ncdfc, varName, meshAttName); if (meshName.empty()) { continue; } if (_uGridMeshMap.find(meshName) == _uGridMeshMap.end()) { SetDiagMsg("No valid mesh for variable named %s", varName.c_str()); continue; } // Need to generate a unique mesh name for layered grids since // UGRID allows 2D and 3D layered variables to share same mesh, // but DC class does not. // vector dimNames = ncdfc->GetSpatialDimNames(varName); if (dimNames.size() == 2) { meshName += _getLayeredVerticalCoordVar(ncdfc, varName); } // Only node-centered variables supported currently // string locationName = getAttString(ncdfc, varName, locationAttName); if (locationName != "node") { SetDiagMsg("Only node-centered data supported for variable named %s", varName.c_str()); continue; } string coordName; bool ok = _getVarTimeCoords(ncdfc, varName, coordName); if (!ok) { SetDiagMsg("Invalid variable : %s", varName.c_str()); continue; } string units; ncdfc->GetAtt(varName, "units", units); double mv; bool has_missing = ncdfc->GetMissingValue(varName, mv); if (!has_missing) { dataVarsMap[varName] = DataVar(varName, units, DC::FLOAT, periodic, meshName, coordName, DC::Mesh::NODE); } else { dataVarsMap[varName] = DataVar(varName, units, DC::FLOAT, periodic, meshName, coordName, DC::Mesh::NODE, mv); } int rc = DCUtils::CopyAtt(*ncdfc, varName, dataVarsMap[varName]); if (rc < 0) return (-1); } return (0); } int DCUGRID::OpenVariableRead(size_t ts, string varname, int level, int lod) { // Pass through normal open operation if this is not a synthesized // connectivity variable // if (_faceNodeConnectivityMap.find(varname) == _faceNodeConnectivityMap.end()) { return (DC::OpenVariableRead(ts, varname, level, lod)); } FileTable::FileObject *f = new FileTable::FileObject(ts, varname); return (_fileTable.AddEntry(f)); } int DCUGRID::Read(int fd, int *data) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } // Pass through normal read operation if this is not a synthesized // connectivity variable // if (_faceNodeConnectivityMap.find(f->GetVarname()) == _faceNodeConnectivityMap.end()) { return (DC::Read(fd, data)); } const vector &connVar = _faceNodeConnectivityMap[f->GetVarname()]; std::copy_n(connVar.data(), connVar.size(), data); return (0); } int DCUGRID::ReadRegion(int fd, const vector &min, const vector &max, int *data) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } if (_faceNodeConnectivityMap.find(f->GetVarname()) == _faceNodeConnectivityMap.end()) { return (DC::ReadRegion(fd, min, max, data)); } VAssert(min.size() == max.size()); size_t n = 1; for (int i = 0; i < min.size(); i++) { VAssert(min[i] == 0); n *= max[i] + 1; } const vector &connVar = _faceNodeConnectivityMap[f->GetVarname()]; VAssert(n == connVar.size()); std::copy_n(connVar.data(), connVar.size(), data); return (0); } int DCUGRID::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } if (_faceNodeConnectivityMap.find(f->GetVarname()) == _faceNodeConnectivityMap.end()) { return (DC::CloseVariable(fd)); } _fileTable.RemoveEntry(fd); delete f; return (0); } ================================================ FILE: lib/vdc/DCUtils.cpp ================================================ //************************************************************************ // * // Copyright (C) 2018 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: DataMgrUtils.cpp // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: June 2018 // // Description: Implements the DataMgrUtils free functions // #ifdef WIN32 #pragma warning(disable : 4251 4100) #endif #include #include "vapor/VAssert.h" #include #include #include using namespace VAPoR; using namespace Wasp; int DCUtils::CopyAtt(const NetCDFCollection &ncdfc, string varname, string attname, DC::BaseVar &var) { int nctype = ncdfc.GetAttType(varname, attname); if (nctype == NC_INT64) { vector values; ncdfc.GetAtt(varname, attname, values); DC::Attribute attr(attname, DC::INT64, values); var.SetAttribute(attr); } else if (nctype == NC_DOUBLE) { vector values; ncdfc.GetAtt(varname, attname, values); DC::Attribute attr(attname, DC::DOUBLE, values); var.SetAttribute(attr); } else if (nctype == NC_CHAR) { string values; ncdfc.GetAtt(varname, attname, values); DC::Attribute attr(attname, DC::TEXT, values); var.SetAttribute(attr); } else { Wasp::MyBase::SetErrMsg("Invalid attribute : %s.%s", varname.c_str(), attname.c_str()); return -1; } return 0; } int DCUtils::CopyAtt(const NetCDFCollection &ncdfc, string varname, DC::BaseVar &var) { vector attNames = ncdfc.GetAttNames(varname); for (int i = 0; i < attNames.size(); i++) { int rc = CopyAtt(ncdfc, varname, attNames[i], var); if (rc < 0) return (rc); } return (0); } ================================================ FILE: lib/vdc/DCWRF.cpp ================================================ #include #include #include #include #include "vapor/VAssert.h" #include #include #ifdef _WINDOWS #define _USE_MATH_DEFINES #pragma warning(disable : 4251 4100) #endif #include #include #include #include #include #include #include #include using namespace VAPoR; using namespace std; namespace { #ifdef UNUSED_FUNCTION bool mycompare(const pair &a, const pair &b) { return (a.second < b.second); } #endif float read_scalar_float_attr(NetCDFCollection *ncdfc, string varname, string attrname, float default_value) { vector dvalues; ncdfc->GetAtt(varname, attrname, dvalues); if (dvalues.size() != 1) return (default_value); return ((float)dvalues[0]); } DC::XType netcdf_to_dc_xtype(int t) { switch (t) { case NC_DOUBLE: return (DC::XType::DOUBLE); case NC_INT64: return (DC::XType::INT64); case NC_CHAR: return (DC::XType::TEXT); default: return (DC::XType::INVALID); } } }; // namespace DCWRF::DCWRF() { _ncdfc = NULL; _dx = 0.0; _dy = 0.0; _cen_lat = 0.0; _cen_lon = 0.0; _true_lat1 = 0.0; _true_lat2 = 0.0; _pole_lat = 90.0; _pole_lon = 0.0; _grav = 9.81; _radius = 0.0; _p2si = 1.0; _mapProj = 0; _proj4String.clear(); _derivedVars.clear(); _derivedTime = NULL; _dimsMap.clear(); _coordVarsMap.clear(); _dataVarsMap.clear(); _meshMap.clear(); } DCWRF::~DCWRF() { for (int i = 0; i < _derivedVars.size(); i++) { if (_derivedVars[i]) delete _derivedVars[i]; } if (_derivedTime) delete _derivedTime; if (_ncdfc) delete _ncdfc; } int DCWRF::initialize(const vector &files, const std::vector &options) { if (_ncdfc) delete _ncdfc; _ncdfc = nullptr; if (_derivedTime) delete _ncdfc; _derivedTime = nullptr; NetCDFCollection *ncdfc = new NetCDFCollection(); // Initialize the NetCDFCollection class. Need to specify the name // of the time dimension ("Time" for WRF), and time coordinate variable // names (N/A for WRF) // vector time_dimnames; vector time_coordvars; time_dimnames.push_back("Time"); int rc = ncdfc->Initialize(files, time_dimnames, time_coordvars); if (rc < 0) { SetErrMsg("Failed to initialize netCDF data collection for reading"); return (-1); } // Use UDUnits for unit conversion // rc = _udunits.Initialize(); if (rc < 0) { SetErrMsg("Failed to initialize udunits2 library : %s", _udunits.GetErrMsg().c_str()); return (-1); } // Get required and optional global attributes from WRF files. // Initializes members: _dx, _dy, _cen_lat, _cen_lon, _pole_lat, // _pole_lon, _grav, _radius, _p2si // rc = _InitAtts(ncdfc); if (rc < 0) return (-1); // // Get the dimensions of the grid. // Initializes members: _dimsMap // rc = _InitDimensions(ncdfc); if (rc < 0) { SetErrMsg("No valid dimensions"); return (-1); } // Set up map projection transforms // Initializes members: _proj4String, _mapProj // rc = _InitProjection(ncdfc, _radius); if (rc < 0) { return (-1); } // Set up the horizontal coordinate variables // // Initializes members: _coordVarMap // rc = _InitHorizontalCoordinates(ncdfc); if (rc < 0) { return (-1); } // Set up the vertical coordinate variable. WRF data set doesn't // provide one. // // Initializes members: _coordVarMap // rc = _InitVerticalCoordinates(ncdfc); if (rc < 0) { return (-1); } // Set up user time coordinate derived variable . Time must be // in seconds. // Initializes members: _coordVarsMap // rc = _InitTime(ncdfc); if (rc < 0) { return (-1); } // // Identify data and coordinate variables. Sets up members: // Initializes members: _dataVarsMap, _meshMap, _coordVarsMap // rc = _InitVars(ncdfc); if (rc < 0) return (-1); _ncdfc = ncdfc; return (0); } bool DCWRF::getDimension(string dimname, DC::Dimension &dimension) const { map::const_iterator itr; itr = _dimsMap.find(dimname); if (itr == _dimsMap.end()) return (false); dimension = itr->second; return (true); } std::vector DCWRF::getDimensionNames() const { map::const_iterator itr; vector names; for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } vector DCWRF::getMeshNames() const { vector mesh_names; std::map::const_iterator itr = _meshMap.begin(); for (; itr != _meshMap.end(); ++itr) { mesh_names.push_back(itr->first); } return (mesh_names); } bool DCWRF::getMesh(string mesh_name, DC::Mesh &mesh) const { map::const_iterator itr = _meshMap.find(mesh_name); if (itr == _meshMap.end()) return (false); mesh = itr->second; return (true); } bool DCWRF::getCoordVarInfo(string varname, DC::CoordVar &cvar) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr == _coordVarsMap.end()) { return (false); } cvar = itr->second; return (true); } bool DCWRF::getDataVarInfo(string varname, DC::DataVar &datavar) const { map::const_iterator itr; itr = _dataVarsMap.find(varname); if (itr == _dataVarsMap.end()) { return (false); } datavar = itr->second; return (true); } bool DCWRF::getBaseVarInfo(string varname, DC::BaseVar &var) const { map::const_iterator itr; itr = _coordVarsMap.find(varname); if (itr != _coordVarsMap.end()) { var = itr->second; return (true); } map::const_iterator itr1 = _dataVarsMap.find(varname); if (itr1 != _dataVarsMap.end()) { var = itr1->second; return (true); } return (false); } std::vector DCWRF::getDataVarNames() const { map::const_iterator itr; vector names; for (itr = _dataVarsMap.begin(); itr != _dataVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } std::vector DCWRF::getCoordVarNames() const { map::const_iterator itr; vector names; for (itr = _coordVarsMap.begin(); itr != _coordVarsMap.end(); ++itr) { names.push_back(itr->first); } return (names); } template bool DCWRF::_getAttTemplate(string varname, string attname, T &values) const { if (varname.empty()) { _ncdfc->GetAtt("", attname, values); return (true); } DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) return (status); DC::Attribute att; status = var.GetAttribute(attname, att); if (!status) return (status); att.GetValues(values); return (true); } bool DCWRF::getAtt(string varname, string attname, vector &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } bool DCWRF::getAtt(string varname, string attname, vector &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } bool DCWRF::getAtt(string varname, string attname, string &values) const { values.clear(); return (_getAttTemplate(varname, attname, values)); } std::vector DCWRF::getAttNames(string varname) const { if (varname.empty()) return (_ncdfc->GetAttNames("")); DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) return (vector()); vector names; const std::map & atts = var.GetAttributes(); std::map::const_iterator itr; for (itr = atts.begin(); itr != atts.end(); ++itr) { names.push_back(itr->first); } return (names); } DC::XType DCWRF::getAttType(string varname, string attname) const { if (varname.empty()) { return (netcdf_to_dc_xtype(_ncdfc->GetAttType("", attname))); } DC::BaseVar var; bool status = getBaseVarInfo(varname, var); if (!status) return (DC::INVALID); DC::Attribute att; status = var.GetAttribute(attname, att); if (!status) return (DC::INVALID); return (att.GetXType()); } int DCWRF::getDimLensAtLevel(string varname, int, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); bool ok; if (_dvm.IsCoordVar(varname)) { return (_dvm.GetDimLensAtLevel(varname, 0, dims_at_level, bs_at_level, -1)); } else { ok = GetVarDimLens(varname, true, dims_at_level, -1); } if (!ok) { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (-1); } // Never blocked // bs_at_level = vector(dims_at_level.size(), 1); return (0); } string DCWRF::getMapProjection() const { return (_proj4String); } int DCWRF::openVariableRead(size_t ts, string varname) { if (ts >= _ncdfc->GetNumTimeSteps()) { SetErrMsg("Time step out of range : %d", ts); return (-1); } ts = _derivedTime->TimeLookup(ts); int fd; bool derivedFlag; if (_dvm.IsCoordVar(varname)) { fd = _dvm.OpenVariableRead(ts, varname); derivedFlag = true; } else { fd = _ncdfc->OpenRead(ts, varname); derivedFlag = false; } if (fd < 0) return (-1); WRFFileObject *w = new WRFFileObject(ts, varname, 0, 0, fd, derivedFlag); return (_fileTable.AddEntry(w)); } int DCWRF::closeVariable(int fd) { WRFFileObject *w = (WRFFileObject *)_fileTable.GetEntry(fd); if (!w) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int aux = w->GetAux(); int rc; if (w->GetDerivedFlag()) { rc = _dvm.CloseVariable(aux); } else { rc = _ncdfc->Close(aux); } _fileTable.RemoveEntry(fd); delete w; return (rc); } template int DCWRF::_readRegionTemplate(int fd, const vector &min, const vector &max, T *region) { VAssert(min.size() == max.size()); WRFFileObject *w = (WRFFileObject *)_fileTable.GetEntry(fd); if (!w) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int aux = w->GetAux(); if (w->GetDerivedFlag()) { return (_dvm.ReadRegion(aux, min, max, region)); } vector ncdf_start = min; reverse(ncdf_start.begin(), ncdf_start.end()); vector ncdf_max = max; reverse(ncdf_max.begin(), ncdf_max.end()); vector ncdf_count; for (int i = 0; i < ncdf_start.size(); i++) { ncdf_count.push_back(ncdf_max[i] - ncdf_start[i] + 1); } return (_ncdfc->Read(ncdf_start, ncdf_count, region, aux)); } bool DCWRF::variableExists(size_t ts, string varname, int, int) const { if (ts >= _ncdfc->GetNumTimeSteps()) { return (false); } ts = _derivedTime->TimeLookup(ts); if (_dvm.IsCoordVar(varname)) { return (_dvm.VariableExists(ts, varname, 0, 0)); } return (_ncdfc->VariableExists(ts, varname)); } vector DCWRF::_GetSpatialDims(NetCDFCollection *ncdfc, string varname) const { vector dims = ncdfc->GetSpatialDims(varname); reverse(dims.begin(), dims.end()); return (dims); } vector DCWRF::_GetSpatialDimNames(NetCDFCollection *ncdfc, string varname) const { vector v = ncdfc->GetSpatialDimNames(varname); reverse(v.begin(), v.end()); return (v); } // // Read select attributes from the WRF files. Most of the attributes are // needed for map projections // int DCWRF::_InitAtts(NetCDFCollection *ncdfc) { _dx = read_scalar_float_attr(ncdfc, "", "DX", _dx); _dy = read_scalar_float_attr(ncdfc, "", "DY", _dy); _cen_lat = read_scalar_float_attr(ncdfc, "", "CEN_LAT", _cen_lat); _cen_lon = read_scalar_float_attr(ncdfc, "", "CEN_LON", _cen_lon); _true_lat1 = read_scalar_float_attr(ncdfc, "", "TRUELAT1", _true_lat1); _true_lat2 = read_scalar_float_attr(ncdfc, "", "TRUELAT2", _true_lat2); _pole_lat = read_scalar_float_attr(ncdfc, "", "POLE_LAT", _pole_lat); _pole_lon = read_scalar_float_attr(ncdfc, "", "POLE_LON", _pole_lon); // // "PlanetWRF" attributes // // RADIUS is the radius of the planet // // P2SI is the number of SI seconds in an planetary solar day // divided by the number of SI seconds in an earth solar day // vector dvalues; ncdfc->GetAtt("", "G", dvalues); if (dvalues.size() == 1) { _grav = dvalues[0]; _radius = read_scalar_float_attr(ncdfc, "", "RADIUS", _radius); _p2si = read_scalar_float_attr(ncdfc, "", "P2SI", _p2si); } return (0); } // // Generate a Proj4 projection string for whatever map projection is used // by the data. Map projection type is indicated by map_proj // The Proj4 string will be used to transform from geographic coordinates // measured in degrees to Cartographic coordinates in meters. // int DCWRF::_GetProj4String(NetCDFCollection *ncdfc, float radius, int map_proj, string &projstring) { projstring.clear(); ostringstream oss; vector dvalues; switch (map_proj) { case 0: { // Lat Lon double lon_0 = _cen_lon; double lat_0 = _cen_lat; oss << " +lon_0=" << lon_0 << " +lat_0=" << lat_0; projstring = "+proj=eqc +ellps=WGS84" + oss.str(); } break; case 1: { // Lambert ncdfc->GetAtt("", "STAND_LON", dvalues); if (dvalues.size() != 1) { SetErrMsg("Error reading required attribute : STAND_LON"); return (-1); } float lon0 = dvalues[0]; // Construct the projection string: projstring = "+proj=lcc"; projstring += " +lon_0="; oss.str(""); oss << (double)lon0; projstring += oss.str(); projstring += " +lat_1="; oss.str(""); oss << (double)_true_lat1; projstring += oss.str(); projstring += " +lat_2="; oss.str(""); oss << (double)_true_lat2; projstring += oss.str(); break; } case 2: { // Polar stereographic (pure north or south) projstring = "+proj=stere"; // Determine whether north or south pole (lat_ts is pos or neg) float lat0; if (_true_lat1 < 0.) lat0 = -90.0; else lat0 = 90.0; projstring += " +lat_0="; oss.str(""); oss << (double)lat0; projstring += oss.str(); projstring += " +lat_ts="; oss.str(""); oss << (double)_true_lat1; projstring += oss.str(); ncdfc->GetAtt("", "STAND_LON", dvalues); if (dvalues.size() != 1) { SetErrMsg("Error reading required attribute : STAND_LON"); return (-1); } float lon0 = dvalues[0]; projstring += " +lon_0="; oss.str(""); oss << (double)lon0; projstring += oss.str(); break; } case (3): { // Mercator ncdfc->GetAtt("", "STAND_LON", dvalues); if (dvalues.size() != 1) { SetErrMsg("Error reading required attribute : STAND_LON"); return (-1); } float lon0 = dvalues[0]; // Construct the projection string: projstring = "+proj=merc"; projstring += " +lon_0="; oss.str(""); oss << (double)lon0; projstring += oss.str(); projstring += " +lat_ts="; oss.str(""); oss << (double)_true_lat1; projstring += oss.str(); break; } case (6): { // lat-long, possibly rotated, possibly cassini // See if this is a regular cylindrical equidistant projection // with the pole in the default location // if (_pole_lat == 90.0 && _pole_lon == 0.0) { double lon_0 = _cen_lon; double lat_0 = _cen_lat; ostringstream oss; oss << " +lon_0=" << lon_0 << " +lat_0=" << lat_0; projstring = "+proj=eqc +ellps=WGS84" + oss.str(); } else { // // Assume arbitrary pole displacement. Probably should // check for cassini projection (transverse cylindrical) // but general rotated cyl. equidist. projection should work // ncdfc->GetAtt("", "STAND_LON", dvalues); if (dvalues.size() != 1) { SetErrMsg("Error reading required attribute : STAND_LON"); return (-1); } float lon0 = dvalues[0]; projstring = "+proj=ob_tran"; projstring += " +o_proj=eqc"; projstring += " +to_meter=0.0174532925199"; projstring += " +o_lat_p="; oss.str(""); oss << (double)_pole_lat; projstring += oss.str(); projstring += "d"; // degrees, not radians projstring += " +o_lon_p="; oss.str(""); oss << (double)(180. - _pole_lon); projstring += oss.str(); projstring += "d"; // degrees, not radians projstring += " +lon_0="; oss.str(""); oss << (double)(-lon0); projstring += oss.str(); projstring += "d"; // degrees, not radians } break; } default: { SetErrMsg("Unsupported MAP_PROJ value : %d", _mapProj); return -1; } } if (projstring.empty()) return (0); // // PlanetWRF data if radius is not zero // if (radius > 0) { // planetWRf (not on earth) projstring += " +ellps=sphere"; stringstream ss; ss << radius; projstring += " +a=" + ss.str() + " +es=0"; } else { projstring += " +ellps=WGS84"; } return (0); } // Check to see if the horizontal coordinates, XLONG and XLAT, are // constant value. For simplicity, only check the // first two elements of each array. // // N.B. older WRF files (pre 4.x) don't have an attribute that identifies // the files as being "idealized"; for idealized cases the horizontal // coordinates are initialized to constant values. // bool DCWRF::_isConstantValuedVariable(NetCDFCollection *ncdfc, string varname) const { bool enabled = EnableErrMsg(false); vector data; vector dims = ncdfc->GetSpatialDims(varname); vector start(dims.size(), 0); vector count = dims; // Edge case. // if (Wasp::VProduct(dims) < 2) return (true); data.resize(Wasp::VProduct(dims)); int fd = ncdfc->OpenRead(0, varname); if (fd < 0) { EnableErrMsg(enabled); return (false); } int rc = ncdfc->Read(start.data(), count.data(), data.data(), fd); if (rc < 0) { EnableErrMsg(enabled); return (false); } ncdfc->Close(fd); float a0 = data[0]; float epsilon = 0.000001; for (size_t i = 1; i < Wasp::VProduct(dims); i++) { if (!Wasp::NearlyEqual(a0, data[i], epsilon)) { EnableErrMsg(enabled); return (false); } } EnableErrMsg(enabled); return (true); } bool DCWRF::_isIdealized(NetCDFCollection *ncdfc) const { // Version 4.0 of WRF introduced "IDEAL_CASE" attribute. // For earlier versions we look for hints // vector l; ncdfc->GetAtt("", "IDEAL_CASE", l); if (l.size() && l[0] != 0) return (true); string s; ncdfc->GetAtt("", "MAP_PROJ_CHAR", s); if (Wasp::StrCmpNoCase(s, "Cartesian") == 0) return (true); ncdfc->GetAtt("", "SIMULATION_INITIALIZATION_TYPE", s); if (Wasp::StrCmpNoCase(s, "IDEALIZED DATA") == 0) return (true); // Pre version 4.x WRF did not have an attribute to identify // idealized cases. However, these cases have constant-valued // XLONG and XLAT coordinates. N.B. The staggered grid horizontal // coordinates (XLONG_U, XLAT_V, etc.) may not exist. // vector cvars = {"XLONG", "XLAT"}; for (auto &c : cvars) { if (_isConstantValuedVariable(ncdfc, c)) return (true); } if (_isWRFSFIRE(ncdfc) && _cen_lat == 0.0 && _cen_lon == 0.0 && _true_lat1 == 0.0 && _true_lat2 == 0.0) { return (true); } return (false); } bool DCWRF::_isWRFSFIRE(NetCDFCollection *ncdfc) const { if (!ncdfc->VariableExists("FXLONG")) return (false); if (!ncdfc->VariableExists("FXLAT")) return (false); return (true); } // // Set up map projection stuff // int DCWRF::_InitProjection(NetCDFCollection *ncdfc, float radius) { _proj4String.clear(); _mapProj = 0; if (_isIdealized(ncdfc)) return (0); vector ivalues; ncdfc->GetAtt("", "MAP_PROJ", ivalues); if (ivalues.size() != 1) { SetErrMsg("Error reading required attribute : MAP_PROJ"); return (-1); } _mapProj = ivalues[0]; int rc = _GetProj4String(ncdfc, radius, _mapProj, _proj4String); if (rc < 0) return (rc); return (0); } DerivedCoordVar_CF2D *DCWRF::_makeDerivedHorizontalIdealized(NetCDFCollection *ncdfc, string name, string &timeDimName, vector &spaceDimNames) { timeDimName.clear(); spaceDimNames.clear(); timeDimName = ncdfc->GetTimeDimName(name); spaceDimNames = ncdfc->GetSpatialDimNames(name); reverse(spaceDimNames.begin(), spaceDimNames.end()); vector dimLens = ncdfc->GetSpatialDims(name); reverse(dimLens.begin(), dimLens.end()); VAssert(dimLens.size() == 2); vector data; data.resize(dimLens[0] * dimLens[1]); string units = "km"; float offset = 0.0; int axis = 0; if (name == "XLONG") { axis = 0; offset = _dx / 2.0; } else if (name == "XLAT") { axis = 1; offset = _dy / 2.0; } else if (name == "XLONG_U") { axis = 0; offset = 0.0; } else if (name == "XLAT_U") { axis = 1; offset = _dy / 2.0; } else if (name == "XLONG_V") { axis = 0; offset = _dx / 2.0; } else if (name == "XLAT_V") { axis = 1; offset = 0.0; } else { return (NULL); } if (axis == 0) { for (size_t j = 0; j < dimLens[1]; j++) { for (size_t i = 0; i < dimLens[0]; i++) { data[j * dimLens[0] + i] = i * _dx + offset; } } } else { for (size_t j = 0; j < dimLens[1]; j++) { for (size_t i = 0; i < dimLens[0]; i++) { data[j * dimLens[0] + i] = j * _dy + offset; } } } DerivedCoordVar_CF2D *derivedVar = new DerivedCoordVar_CF2D(name, spaceDimNames, dimLens, axis, units, data); int rc = derivedVar->Initialize(); if (rc < 0) return (NULL); _dvm.AddCoordVar(derivedVar); return (derivedVar); } DerivedCoordVar_Staggered *DCWRF::_makeDerivedHorizontalStaggered(NetCDFCollection *ncdfc, string name, string &timeDimName, vector &spaceDimNames) { timeDimName.clear(); spaceDimNames.clear(); int stagDim; string stagDimName; string inName; string dimName; if (name == "XLONG_U") { stagDim = 0; stagDimName = "west_east_stag"; inName = "XLONG"; dimName = "west_east"; } else if (name == "XLAT_U") { stagDim = 0; stagDimName = "west_east_stag"; inName = "XLAT"; dimName = "west_east"; } else if (name == "XLONG_V") { stagDim = 1; stagDimName = "south_north_stag"; inName = "XLONG"; dimName = "south_north"; } else if (name == "XLAT_V") { stagDim = 1; stagDimName = "south_north_stag"; inName = "XLAT"; dimName = "south_north"; } else { return (NULL); } timeDimName = ncdfc->GetTimeDimName(inName); spaceDimNames = ncdfc->GetSpatialDimNames(inName); reverse(spaceDimNames.begin(), spaceDimNames.end()); spaceDimNames[stagDim] = stagDimName; DerivedCoordVar_Staggered *derivedVar = new DerivedCoordVar_Staggered(name, stagDimName, this, inName, dimName); int rc = derivedVar->Initialize(); if (rc < 0) return (NULL); _dvm.AddCoordVar(derivedVar); return (derivedVar); } int DCWRF::_InitHorizontalCoordinatesHelper(NetCDFCollection *ncdfc, string name, int axis) { VAssert(axis == 0 || axis == 1); DerivedVar *derivedVar = NULL; string timeDimName; vector spaceDimNames; // // Set up coordinate units identifier // string units; if (_proj4String.empty()) { if (_isWRFSFIRE(ncdfc)) { // For *idealized* WRF-SFIRE model runs the 'units' attribute // say degrees, but it's actually meters. Clever. // units = "meters"; } else { units = "km"; } } else { units = axis == 0 ? "degrees_east" : "degrees_north"; } if (ncdfc->VariableExists(name) && !_proj4String.empty()) { timeDimName = ncdfc->GetTimeDimName(name); spaceDimNames = ncdfc->GetSpatialDimNames(name); reverse(spaceDimNames.begin(), spaceDimNames.end()); } else if (ncdfc->VariableExists(name) && _proj4String.empty() && _isConstantValuedVariable(ncdfc, name)) { // For idealized case we need to synthesize Cartesian coordinates // derivedVar = _makeDerivedHorizontalIdealized(ncdfc, name, timeDimName, spaceDimNames); if (!derivedVar) return (-1); } else if (ncdfc->VariableExists(name) && _proj4String.empty() && _isWRFSFIRE(ncdfc) && !_isConstantValuedVariable(ncdfc, name)) { // Idealized WRF-SFIRE cases do have coordinate variables that // are already represented in meters // timeDimName = ncdfc->GetTimeDimName(name); spaceDimNames = ncdfc->GetSpatialDimNames(name); reverse(spaceDimNames.begin(), spaceDimNames.end()); } else { // Ugh. Older WRF files don't have coordinate variables for // staggered dimensions, so we need to derive them. // derivedVar = _makeDerivedHorizontalStaggered(ncdfc, name, timeDimName, spaceDimNames); if (!derivedVar) return (-1); } // Finally, add the variable to _coordVarsMap. Probably don't // need to do this here. Could do this when we process native WRF // variables later. Sigh // vector periodic(2, false); _coordVarsMap[name] = CoordVar(name, units, DC::FLOAT, periodic, axis, false, spaceDimNames, timeDimName); int rc = DCUtils::CopyAtt(*ncdfc, name, _coordVarsMap[name]); if (rc < 0) return (-1); if (derivedVar) { _derivedVars.push_back(derivedVar); } return (0); } // // Set up horizontal coordinates // int DCWRF::_InitHorizontalCoordinates(NetCDFCollection *ncdfc) { _coordVarsMap.clear(); // XLONG and XLAT must have same dimensionality // vector latlondims = ncdfc->GetDims("XLONG"); vector dummy = ncdfc->GetDims("XLAT"); if (dummy != latlondims) { SetErrMsg("Coordinate variables XLONG and XLAT having different dimensions!\n"); return (-1); } if (latlondims.size() < 2 || latlondims.size() > 3) { SetErrMsg("Coordinate variables XLONG and XLAT are not 2D or 3D variables!\n"); return (-1); } // "XLONG" coordinate, unstaggered // (void)_InitHorizontalCoordinatesHelper(ncdfc, "XLONG", 0); // "XLAT" coordinate, unstaggered // (void)_InitHorizontalCoordinatesHelper(ncdfc, "XLAT", 1); // "XLONG_U" coordinate, staggered // (void)_InitHorizontalCoordinatesHelper(ncdfc, "XLONG_U", 0); // "XLAT_U" coordinate, staggered // (void)_InitHorizontalCoordinatesHelper(ncdfc, "XLAT_U", 1); // "XLONG_V" coordinate, staggered // (void)_InitHorizontalCoordinatesHelper(ncdfc, "XLONG_V", 0); // "XLAT_V" coordinate, staggered // (void)_InitHorizontalCoordinatesHelper(ncdfc, "XLAT_V", 1); if (_isWRFSFIRE(ncdfc)) { // "FXLONG" coordinate, unstaggered // (void)_InitHorizontalCoordinatesHelper(ncdfc, "FXLONG", 0); // "FXLAT" coordinate, staggered // (void)_InitHorizontalCoordinatesHelper(ncdfc, "FXLAT", 1); } return (0); } DerivedCoordVar_CF1D *DCWRF::_InitVerticalCoordinatesHelper(string varName, string dimName) { DerivedCoordVar_CF1D *derivedVar; vector dimNames = {dimName}; string units = ""; int axis = 2; derivedVar = new DerivedCoordVar_CF1D(varName, this, dimName, axis, units); (void)derivedVar->Initialize(); _dvm.AddCoordVar(derivedVar); vector periodic(1, false); string time_dim_name = ""; CoordVar cvar(varName, units, DC::FLOAT, periodic, axis, false, dimNames, time_dim_name); if (varName == "bottom_top" || varName == "bottom_top_stag") { cvar.SetAttribute(Attribute("standard_name", DC::XType::TEXT, "wrf_terrain")); string formula_terms = "PH: PH PHB: PHB"; cvar.SetAttribute(Attribute("formula_terms", DC::XType::TEXT, formula_terms)); } _coordVarsMap[varName] = cvar; return (derivedVar); } // // Create 1D derived variables expressing the vertical coordinates // in unitless grid index coordinates. // int DCWRF::_InitVerticalCoordinates(NetCDFCollection *ncdfc) { // Create 1D vertical coordinate variable for each "vertical" dimension // // First do ones we know about. These require special treatment because // they may be transformed to other units // string name = "bottom_top"; if (_dimsMap.find(name) != _dimsMap.end()) { _derivedVars.push_back(_InitVerticalCoordinatesHelper(name, name)); } name = "bottom_top_stag"; if (_dimsMap.find(name) != _dimsMap.end()) { _derivedVars.push_back(_InitVerticalCoordinatesHelper(name, name)); } // Now handle dimensions that are not documented . I.e. everything // else in the 3rd dimension position // vector vars = ncdfc->GetVariableNames(3, true); for (int i = 0; i < vars.size(); i++) { vector dimnames = ncdfc->GetSpatialDimNames(vars[i]); assert(dimnames.size() == 3); reverse(dimnames.begin(), dimnames.end()); name = dimnames[2]; if (_dimsMap.find(name) == _dimsMap.end()) continue; // no duplicates // if (_coordVarsMap.find(name) != _coordVarsMap.end()) continue; _derivedVars.push_back(_InitVerticalCoordinatesHelper(name, name)); } return (0); } // Create a derived variable for the time coordinate. Time in WRF data // is an array of formatted time strings. The DC class requires that // time be expressed as seconds represented as floats. // int DCWRF::_InitTime(NetCDFCollection *ncdfc) { _derivedTime = NULL; // Create and install the Time coordinate variable // string derivedName = "Time"; string wrfVarName = "Times"; string dimName = "Time"; _derivedTime = new DerivedCoordVar_WRFTime(derivedName, ncdfc, wrfVarName, dimName, _p2si); int rc = _derivedTime->Initialize(); if (rc < 0) return (-1); _dvm.AddCoordVar(_derivedTime); DC::CoordVar cvarInfo; (void)_dvm.GetCoordVarInfo(derivedName, cvarInfo); _coordVarsMap[derivedName] = cvarInfo; return (0); } // Get Space and time dimensions from WRF data set. Initialize // _dimsMap // int DCWRF::_InitDimensions(NetCDFCollection *ncdfc) { _dimsMap.clear(); // Get dimension names and lengths for all dimensions in the // WRF data set. // vector dimnames = ncdfc->GetDimNames(); vector dimlens = ncdfc->GetDims(); VAssert(dimnames.size() == dimlens.size()); // WRF files use reserved names for dimensions. The time dimension // is always named "Time", etc. // Dimensions are expressed in the DC::Dimension class as a // combination of name, and length. // string timedimname = "Time"; for (int i = 0; i < dimnames.size(); i++) { Dimension dim(dimnames[i], dimlens[i]); _dimsMap[dimnames[i]] = dim; } if ((_dimsMap.find("west_east") == _dimsMap.end()) || (_dimsMap.find("west_east_stag") == _dimsMap.end()) || (_dimsMap.find("south_north") == _dimsMap.end()) || (_dimsMap.find("south_north_stag") == _dimsMap.end()) || // (_dimsMap.find("bottom_top") == _dimsMap.end()) || // (_dimsMap.find("bottom_top_stag") == _dimsMap.end()) || (_dimsMap.find("Time") == _dimsMap.end())) { SetErrMsg("Missing dimension"); return (-1); } return (0); } // Given a data variable name return the variable's dimension names and // associated coordinate variables. The coordinate variable names // returned is for the derived coordinate variables expressed in // Cartographic coordinates, not the native geographic coordinates // found in the WRF file. // // The order of the returned vectors // is significant. // bool DCWRF::_GetVarCoordinates(NetCDFCollection *ncdfc, string varname, vector &sdimnames, vector &scoordvars, string &time_dim_name, string &time_coordvar ) { sdimnames.clear(); scoordvars.clear(); time_dim_name.clear(); time_coordvar.clear(); // Order of dimensions in WRF files is reverse of DC convention // vector dimnames = ncdfc->GetDimNames(varname); reverse(dimnames.begin(), dimnames.end()); // Deal with time dimension first // if (dimnames.size() == 1) { if (dimnames[0].compare("Time") != 0) { return (false); } time_dim_name = "Time"; time_coordvar = "Time"; return (true); } // only handle 2d, 3d, and 4d variables // if (dimnames.size() < 2) return (false); if (dimnames[0].compare("west_east") == 0 && dimnames[1].compare("south_north") == 0) { scoordvars.push_back("XLONG"); scoordvars.push_back("XLAT"); } else if (dimnames[0].compare("west_east_stag") == 0 && dimnames[1].compare("south_north") == 0) { scoordvars.push_back("XLONG_U"); scoordvars.push_back("XLAT_U"); } else if (dimnames[0].compare("west_east") == 0 && dimnames[1].compare("south_north_stag") == 0) { scoordvars.push_back("XLONG_V"); scoordvars.push_back("XLAT_V"); } else if (_isWRFSFIRE(ncdfc) && dimnames[0].compare("west_east_subgrid") == 0 && dimnames[1].compare("south_north_subgrid") == 0) { scoordvars.push_back("FXLONG"); scoordvars.push_back("FXLAT"); } else { return (false); } if (dimnames.size() > 2 && dimnames[2] != "Time") { scoordvars.push_back(dimnames[2]); } sdimnames = dimnames; if (dimnames.size() == 2) { return (true); } if (sdimnames.back().compare("Time") == 0) { time_dim_name = "Time"; time_coordvar = "Time"; sdimnames.pop_back(); // Oops. Remove time dimension } return (true); } // Collect metadata for all data variables found in the WRF data // set. Initialize the _dataVarsMap member // int DCWRF::_InitVars(NetCDFCollection *ncdfc) { _dataVarsMap.clear(); _meshMap.clear(); // // Get names of variables in the WRF data set that have 1 2 or 3 // spatial dimensions // vector vars; for (int i = 1; i < 4; i++) { vector v = ncdfc->GetVariableNames(i, true); vars.insert(vars.end(), v.begin(), v.end()); } // For each variable add a member to _dataVarsMap // for (int i = 0; i < vars.size(); i++) { // variable type must be float or int // int type = ncdfc->GetXType(vars[i]); if (!(NetCDFSimple::IsNCTypeFloat(type) || NetCDFSimple::IsNCTypeInt(type))) continue; // If variables are in _coordVarsMap then they are coordinate, not // data, variables // if (_coordVarsMap.find(vars[i]) != _coordVarsMap.end()) continue; vector sdimnames; vector scoordvars; string time_dim_name; string time_coordvar; bool ok = _GetVarCoordinates(ncdfc, vars[i], sdimnames, scoordvars, time_dim_name, time_coordvar); // Must have a coordinate variable for each dimension! // if (sdimnames.size() != scoordvars.size()) { continue; } if (!ok) continue; // if (! ok) { // SetErrMsg("Invalid variable : %s", vars[i].c_str()); // return(-1); //} Mesh mesh("", sdimnames, scoordvars); // Create new mesh. We're being lazy here and probably should only // createone if it doesn't ready exist // _meshMap[mesh.GetName()] = mesh; string units; ncdfc->GetAtt(vars[i], "units", units); if (!_udunits.ValidUnit(units)) { units = ""; } vector periodic(3, false); DC::DataVar dvar = DataVar(vars[i], units, DC::FLOAT, periodic, mesh.GetName(), time_coordvar, DC::Mesh::NODE); int rc = DCUtils::CopyAtt(*ncdfc, vars[i], dvar); if (rc < 0) return (-1); _dataVarsMap[vars[i]] = dvar; } return (0); } ================================================ FILE: lib/vdc/DataMgr.cpp ================================================ #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if DCP_ENABLE_PARTICLE_DENSITY #include #endif #include #include #include #ifdef WIN32 #include #endif using namespace Wasp; using namespace VAPoR; namespace { size_t vproduct(DimsType a) { size_t ntotal = 1; for (size_t i = 0; i < a.size(); i++) ntotal *= a[i]; return (ntotal); } DimsType box_dims(const DimsType &min, const DimsType &max) { DimsType dims; for (int i = 0; i < min.size(); i++) { VAssert(min[i] <= max[i]); dims[i] = (max[i] - min[i] + 1); } return (dims); } // Again, stupid gcc-4.8 on CentOS7 requires this alias. template using enable_if_t = typename std::enable_if::type; // Format a vector as a space-separated element string // template string vector_to_string(T v) { ostringstream oss; oss << "["; for (int i = 0; i < v.size(); i++) { oss << v[i] << " "; } oss << "]"; return (oss.str()); } size_t number_of_dimensions(DimsType dims) { size_t ndims = 0; for (int i = 0; i < dims.size() && dims[i] > 1; i++) ndims++; return (ndims); } #ifdef UNUSED_FUNCTION size_t decimate_length(size_t l) { if (l % 2) return ((l + 1) / 2); else return (l / 2); } // Compute dimensions of a multidimensional array, specified by dims, // after undergoing decimiation // vector decimate_dims(const DimsType &dims, int l) { DimsType new_dims = dims; for (int i = 0; i < l; i++) { for (int j = 0; j < new_dims.size(); j++) { new_dims[j] = decimate_length(new_dims[j]); } } return (new_dims); } // Decimate a 1D array with simple averaging. // template void decimate1d(const DimsType &src_bs, const T *src, T *dst) { DimsType dst_bs; for (int i = 0; i < src_bs.size(); i++) { dst_bs[i] = (decimate_length(src_bs[i])); } size_t ni0 = src_bs[0]; size_t ni1 = dst_bs[0]; for (size_t i = 0; i < ni1; i++) { dst[i] = 0.0; } // Perform in-place 4-node averaging, handling odd boundary cases // for (size_t i = 0, ii = 0; i < ni0; i++) { float iwgt = 0.5; if (i == ni0 - 1 && ni0 % 2) iwgt = 1.0; // odd i boundary float w = iwgt; VAssert(w <= 1.0); dst[ii] += w * src[i]; if (i % 2) ii++; } } template void decimate2d(const DimsType &src_bs, const T *src, T *dst) { DimsType dst_bs; for (int i = 0; i < src_bs.size(); i++) { dst_bs[i] = (decimate_length(src_bs[i])); } size_t ni0 = src_bs[0]; size_t nj0 = src_bs[1]; size_t ni1 = dst_bs[0]; size_t nj1 = dst_bs[1]; for (size_t j = 0; j < nj1; j++) { for (size_t i = 0; i < ni1; i++) { dst[j * ni1 + i] = 0.0; } } // Perform in-place 4-node averaging, handling odd boundary cases // for (size_t j = 0, jj = 0; j < nj0; j++) { float jwgt = 0.0; if (j == nj0 - 1 && nj0 % 2) jwgt = 0.25; // odd j boundary for (size_t i = 0, ii = 0; i < ni0; i++) { float iwgt = 0.25; if (i == ni0 - 1 && ni0 % 2) iwgt = 0.5; // odd i boundary float w = iwgt + jwgt; VAssert(w <= 1.0); dst[jj * ni1 + ii] += w * src[j * ni0 + i]; if (i % 2) ii++; } if (j % 2) jj++; } } template void decimate3d(const DimsType > &src_bs, const T *src, T *dst) { DimsType dst_bs; for (int i = 0; i < src_bs.size(); i++) { dst_bs[i] = (decimate_length(src_bs[i])); } size_t ni0 = src_bs[0]; size_t nj0 = src_bs[1]; size_t nk0 = src_bs[2]; size_t ni1 = dst_bs[0]; size_t nj1 = dst_bs[1]; size_t nk1 = dst_bs[2]; for (size_t k = 0; k < nk1; k++) { for (size_t j = 0; j < nj1; j++) { for (size_t i = 0; i < ni1; i++) { dst[k * ni1 * nj1 + j * ni1 + i] = 0.0; } } } // Perform in-place 8-node averaging, handling odd boundary cases // for (size_t k = 0, kk = 0; k < nk0; k++) { float kwgt = 0.0; if (k == nk0 - 1 && nk0 % 2) kwgt = 0.125; // odd k boundary for (size_t j = 0, jj = 0; j < nj0; j++) { float jwgt = 0.0; if (j == nj0 - 1 && nj0 % 2) jwgt = 0.125; // odd j boundary for (size_t i = 0, ii = 0; i < ni0; i++) { float iwgt = 0.125; if (i == ni0 - 1 && ni0 % 2) iwgt = 0.25; // odd i boundary float w = iwgt + jwgt + kwgt; VAssert(w <= 1.0); dst[kk * ni1 * nj1 + jj * ni1 + ii] += w * src[k * ni0 * nj0 + j * ni0 + i]; if (i % 2) ii++; } if (j % 2) jj++; } if (k % 2) kk++; } } // Perform decimation of a 1D, 2D, or 3D blocked array // template void decimate(const DimsType &bmin, const DimsType &bmax, const DimsType &src_bs, const T *src, T *dst) { DimsType dst_bs; for (int i = 0; i < src_bs.size(); i++) { dst_bs[i] = (decimate_length(src_bs[i])); } size_t src_block_size = VProduct(src_bs); size_t dst_block_size = VProduct(dst_bs); size_t ndims = number_of_dimensions(src_bs); if (ndims == 1) { for (int i = bmin[0]; i <= bmax[0]; i++) { decimate1d(src_bs, src, dst); src += src_block_size; dst += dst_block_size; } } else if (ndims == 2) { for (int j = bmin[1]; j <= bmax[1]; j++) { for (int i = bmin[0]; i <= bmax[0]; i++) { decimate2d(src_bs, src, dst); src += src_block_size; dst += dst_block_size; } } } else { for (int k = bmin[2]; k <= bmax[2]; k++) { for (int j = bmin[1]; j <= bmax[1]; j++) { for (int i = bmin[0]; i <= bmax[0]; i++) { decimate3d(src_bs, src, dst); src += src_block_size; dst += dst_block_size; } } } } } #endif void downsample_compute_weights(size_t nIn, size_t nOut, vector &wgts) { VAssert(nOut <= nIn); wgts.resize(nOut, 0.0); float deltax = (float)nIn / (float)nOut; float shift = ((nIn - 1) - (deltax * (nOut - 1))) / 2.0; for (int i = 0; i < nOut; i++) { wgts[i] = (i * deltax) + shift; } } template void downsample1d(const T *signalIn, size_t nIn, size_t strideIn, T *signalOut, size_t nOut, size_t strideOut, const vector &wgts) { VAssert(nOut <= nIn); VAssert(nOut == wgts.size()); for (size_t i = 0; i < nOut; i++) { size_t i0 = wgts[i]; float w = wgts[i] - i0; signalOut[i * strideOut] = (signalIn[i0 * strideIn] * (1.0 - w)) + (signalIn[(i0 + 1) * strideIn] * w); } } template void downsample2d(const T *signalIn, DimsType inDims, T *signalOut, DimsType outDims) { // Sample along first dimension // vector wgts; downsample_compute_weights(inDims[0], outDims[0], wgts); T *buf = new T[inDims[1] * outDims[0]]; size_t nIn = inDims[0]; size_t nOut = outDims[0]; size_t strideIn = 1; size_t strideOut = 1; size_t n = inDims[1]; for (int i = 0; i < n; i++) { const T *inPtr = signalIn + (i * nIn); T * outPtr = buf + (i * nOut); downsample1d(inPtr, nIn, strideIn, outPtr, nOut, strideOut, wgts); } // Sample along second dimension // downsample_compute_weights(inDims[1], outDims[1], wgts); nIn = inDims[1]; nOut = outDims[1]; strideIn = outDims[0]; strideOut = outDims[0]; n = outDims[0]; for (int i = 0; i < n; i++) { const T *inPtr = buf + i; T * outPtr = signalOut + i; downsample1d(inPtr, nIn, strideIn, outPtr, nOut, strideOut, wgts); } delete[] buf; } template void downsample3d(const T *signalIn, DimsType inDims, T *signalOut, DimsType outDims) { // Sample along XY planes first // T *buf = new T[inDims[2] * outDims[1] * outDims[0]]; DimsType inDims2d = {inDims[0], inDims[1]}; DimsType outDims2d = {outDims[0], outDims[1]}; size_t nIn = inDims[0] * inDims[1]; size_t nOut = outDims[0] * outDims[1]; size_t n = inDims[2]; for (int i = 0; i < n; i++) { const T *inPtr = signalIn + (i * nIn); T * outPtr = buf + (i * nOut); downsample2d(inPtr, inDims2d, outPtr, outDims2d); } // Sample along Z dimension // vector wgts; downsample_compute_weights(inDims[2], outDims[2], wgts); nIn = inDims[2]; nOut = outDims[2]; size_t strideIn = outDims[0] * outDims[1]; size_t strideOut = outDims[0] * outDims[1]; n = outDims[0] * outDims[1]; for (int i = 0; i < n; i++) { const T *inPtr = buf + i; T * outPtr = signalOut + i; downsample1d(inPtr, nIn, strideIn, outPtr, nOut, strideOut, wgts); } delete[] buf; } template void downsample(const T *signalIn, DimsType inDims, T *signalOut, DimsType outDims) { size_t ndims = number_of_dimensions(inDims); if (ndims == 1) { vector wgts; downsample_compute_weights(inDims[0], outDims[0], wgts); downsample1d(signalIn, inDims[0], 1, signalOut, outDims[0], 1, wgts); } else if (ndims == 2) { downsample2d(signalIn, inDims, signalOut, outDims); } else if (ndims == 3) { downsample3d(signalIn, inDims, signalOut, outDims); } } // Map voxel to block coordinates // void map_vox_to_blk(DimsType bs, const DimsType &vcoord, DimsType &bcoord) { for (int i = 0; i < bs.size(); i++) { bcoord[i] = (vcoord[i] / bs[i]); } } void map_blk_to_vox(DimsType bs, const DimsType &bmin, const DimsType &bmax, DimsType &vmin, DimsType &vmax) { for (int i = 0; i < bs.size(); i++) { vmin[i] = (bmin[i] * bs[i]); vmax[i] = (bmax[i] * bs[i] + bs[i] - 1); } } // Map block to vox coordinates, and clamp to dimension boundaries // void map_blk_to_vox(const DimsType &bs, const DimsType &dims, const DimsType &bmin, const DimsType &bmax, DimsType &vmin, DimsType &vmax) { for (int i = 0; i < bs.size(); i++) { VAssert(dims[i] > 0); vmin[i] = (bmin[i] * bs[i]); vmax[i] = (bmax[i] * bs[i] + bs[i] - 1); if (vmin[i] >= dims[i]) vmin[i] = dims[i] - 1; if (vmax[i] >= dims[i]) vmax[i] = dims[i] - 1; } } // Copy a contiguous region to a blocked grid // // src : pointer to contiguous region // dst : pointer to blocked grid // min : min region coordinates within destination grid (in voxels) // max : max region coordinates within destination grid (in voxels) // bs : block size of destination grid (in voxels) // dims : dimensions of destination grid (in voxels) // template void copy_block(const T *src, T *dst, const DimsType &min, const DimsType &max, const DimsType &bs, const DimsType &grid_min, const DimsType &grid_max) { DimsType dims; // dimensions of destination region in voxels DimsType bdims; // dimensions of destination grid in blocks DimsType src_dims; // dimensions of source region in voxels for (int i = 0; i < grid_min.size(); i++) { dims[i] = (grid_max[i] - grid_min[i] + 1); bdims[i] = (((dims[i] - 1) / bs[i]) + 1); src_dims[i] = (max[i] - min[i] + 1); } // Input coordinates are specified relative to origin of entire // domain, but 'dst' region origin is at 'grid_min' // DimsType my_min = min; DimsType my_max = max; for (int i = 0; i < min.size(); i++) { my_min[i] -= grid_min[i]; my_max[i] -= grid_min[i]; } size_t block_size = vproduct(bs); for (long k = my_min[2], kk = 0; k <= (long)my_max[2] && k < (long)dims[2]; k++, kk++) { if (k < 0) continue; // Coordinates of destination block (block coordinates) // size_t dst_k_b = k / bs[2]; // Coordinates within destination block (voxel coordinates) // size_t dst_k = k % bs[2]; for (long j = my_min[1], jj = 0; j <= (long)my_max[1] && j < (long)dims[1]; j++, jj++) { if (j < 0) continue; size_t dst_j_b = j / bs[1]; size_t dst_j = j % bs[1]; for (long i = my_min[0], ii = 0; i <= (long)max[0] && i < (long)dims[0]; i++, ii++) { if (i < 0) continue; size_t dst_i_b = i / bs[0]; size_t dst_i = i % bs[0]; size_t dst_block_offset = (dst_k_b * bdims[0] * bdims[1] + dst_j_b * bdims[0] + dst_i_b) * block_size; size_t dst_offset = dst_k * bs[0] * bs[1] + dst_j * bs[0] + dst_i; size_t src_offset = kk * src_dims[0] * src_dims[1] + jj * src_dims[0] + ii; dst[dst_block_offset + dst_offset] = src[src_offset]; } } } } bool is_blocked(const DimsType &bs) { return (!std::all_of(bs.cbegin(), bs.cend(), [](size_t i) { return i == 1; })); } // Is string a number? // bool is_int(std::string str) { if (!str.empty() && str[0] == '-') str.erase(0, 1); return str.find_first_not_of("0123456789") == std::string::npos; } template::value, int> = 0> void _sanitizeFloats(T *buffer, size_t n) { for (size_t i = 0; i < n; i++) { if (std::isnan(buffer[i])) buffer[i] = std::numeric_limits::infinity(); } } // MSVC has a bug where isnan() is not overloaded for integral types. // This function specializes the template to bypass this bug. template::value, int> = 0> void _sanitizeFloats(T *buffer, size_t n) {} template bool contains(const vector &v, T element) { return (find(v.begin(), v.end(), element) != v.end()); } }; // namespace DataMgr::DataMgr(string format, size_t mem_size, int nthreads) { SetDiagMsg("DataMgr::DataMgr(%s,%d,%d)", format.c_str(), nthreads, mem_size); _format = format; _nthreads = nthreads; _mem_size = mem_size; if (!_mem_size) _mem_size = std::numeric_limits::max() / 1048576; _dc = NULL; _blk_mem_mgr = NULL; _PipeLines.clear(); _regionsList.clear(); _varInfoCacheSize_T.Clear(); _varInfoCacheDouble.Clear(); _varInfoCacheVoidPtr.Clear(); _doTransformHorizontal = false; _doTransformVertical = false; _openVarName.clear(); _proj4String.clear(); _proj4StringDefault.clear(); _bs = {64, 64, 64}; } DataMgr::~DataMgr() { SetDiagMsg("DataMgr::~DataMgr()"); if (_dc) delete _dc; _dc = NULL; Clear(); if (_blk_mem_mgr) delete _blk_mem_mgr; _blk_mem_mgr = NULL; vector names = _dvm.GetDataVarNames(); for (int i = 0; i < names.size(); i++) { if (_dvm.GetVar(names[i])) delete _dvm.GetVar(names[i]); } names = _dvm.GetCoordVarNames(); for (int i = 0; i < names.size(); i++) { if (_dvm.GetVar(names[i])) delete _dvm.GetVar(names[i]); } } int DataMgr::_parseOptions(vector &options) { vector newOptions; bool ok = true; int i = 0; while (i < options.size() && ok) { if (options[i] == "-proj4") { i++; if (i >= options.size()) { ok = false; } else { _proj4String = options[i]; } } if (options[i] == "-project_to_pcs") { _doTransformHorizontal = true; } if (options[i] == "-vertical_xform") { _doTransformVertical = true; } else { newOptions.push_back(options[i]); } i++; } options = newOptions; if (!ok) { SetErrMsg("Error parsing options"); return (-1); } return (0); } int DataMgr::Initialize(const vector &files, const std::vector &options) { vector deviceOptions = options; int rc = _parseOptions(deviceOptions); if (rc < 0) return (-1); Clear(); if (_dc) delete _dc; _dc = NULL; if (files.empty()) { SetErrMsg("Empty file list"); return (-1); } if (_format.compare("vdc") == 0) { _dc = new VDCNetCDF(_nthreads); } else if (_format.compare("wrf") == 0) { _dc = new DCWRF(); } else if (_format.compare("cf") == 0) { _dc = new DCCF(); } else if (_format.compare("mpas") == 0) { _dc = new DCMPAS(); } else if (_format.compare("bov") == 0) { _dc = new DCBOV(); } else if (_format.compare("dcp") == 0) { _dc = new DCP(); } else if (_format.compare("ram") == 0) { _dc = new DCRAM(); } else if (_format.compare("ugrid") == 0) { _dc = new DCUGRID(); #ifdef BUILD_DC_MELANIE } else if (_format.compare("melanie") == 0) { _dc = new DCMelanie(); #endif } else { SetErrMsg("Invalid data collection format : %s", _format.c_str()); return (-1); } rc = _dc->Initialize(files, deviceOptions); if (rc < 0) { SetErrMsg("Failed to initialize data importer"); return (-1); } // Use UDUnits for unit conversion // rc = _udunits.Initialize(); if (rc < 0) { SetErrMsg("Failed to initialize udunits2 library : %s", _udunits.GetErrMsg().c_str()); return (-1); } rc = _initHorizontalCoordVars(); if (rc < 0) { SetErrMsg("Failed to initialize horizontal coordinates"); return (-1); } rc = _initVerticalCoordVars(); if (rc < 0) { SetErrMsg("Failed to initialize vertical coordinates"); return (-1); } rc = _initTimeCoord(); if (rc < 0) { SetErrMsg("Failed to get time coordinates"); return (-1); } #if DCP_ENABLE_PARTICLE_DENSITY //! Generates a regular 3D mesh for use in creating a particle density field. //! See more documentation in DCP.h if (_format == "dcp") { vector dims = {"densityX", "densityY", "densityZ"}; CoordType min, max; GetVariableExtents(0, "Position_x", -1, -1, min, max); DerivedCoordVar1DSpan *XC = new DerivedCoordVar1DSpan("XC", _dc, dims[0], 0, "", "Position_x"); DerivedCoordVar1DSpan *YC = new DerivedCoordVar1DSpan("YC", _dc, dims[1], 1, "", "Position_y"); DerivedCoordVar1DSpan *ZC = new DerivedCoordVar1DSpan("ZC", _dc, dims[2], 2, "", "Position_z"); XC->Initialize(); YC->Initialize(); ZC->Initialize(); _dvm.AddCoordVar(XC); _dvm.AddCoordVar(YC); _dvm.AddCoordVar(ZC); DC::Mesh mesh("density", dims, {XC->GetName(), YC->GetName(), ZC->GetName()}); _dvm.AddMesh(mesh); DerivedParticleDensity *dpd = new DerivedParticleDensity("Particle_Density", _dc, mesh.GetName(), this); dpd->Initialize(); AddDerivedVar(dpd); auto dataVars = GetDataVarNames(3); for (auto var : dataVars) { DerivedParticleAverage *dpa = new DerivedParticleAverage(var + "_avg", _dc, mesh.GetName(), this, var); dpa->Initialize(); AddDerivedVar(dpa); } } #endif return (0); } bool DataMgr::GetMesh(string meshname, DC::Mesh &m) const { VAssert(_dc); bool ok = _dvm.GetMesh(meshname, m); if (!ok) { ok = _dc->GetMesh(meshname, m); } if (!ok) return (ok); // Make sure the number of coordinate variables is greater or // equal to the topological dimension. If not, add default coordinate // variables // vector coord_vars = m.GetCoordVars(); while (coord_vars.size() < m.GetTopologyDim()) { if (!_hasCoordForAxis(coord_vars, 0)) { coord_vars.insert(coord_vars.begin() + 0, _defaultCoordVar(m, 0)); continue; } else if (!_hasCoordForAxis(coord_vars, 1)) { coord_vars.insert(coord_vars.begin() + 1, _defaultCoordVar(m, 1)); continue; } else { coord_vars.insert(coord_vars.begin() + 2, _defaultCoordVar(m, 2)); continue; } } // if requested, replace native horizontal geographic coordiate variables // with derived PCS coordinate variables // if (_doTransformHorizontal) { _assignHorizontalCoords(coord_vars); } m.SetCoordVars(coord_vars); return (true); } vector DataMgr::GetDataVarNames() const { VAssert(_dc); vector validvars; for (int ndim = 2; ndim <= 3; ndim++) { vector vars = GetDataVarNames(ndim); validvars.insert(validvars.end(), vars.begin(), vars.end()); } return (validvars); } vector DataMgr::GetDataVarNames(int ndim, VarType type) const { VAssert(_dc); if (_dataVarNamesCache[std::make_pair(type, ndim)].size()) { return (_dataVarNamesCache[std::make_pair(type, ndim)]); } vector vars = _dc->GetDataVarNames(ndim); vector derived_vars = _getDataVarNamesDerived(ndim); vars.insert(vars.end(), derived_vars.begin(), derived_vars.end()); vector validVars; for (int i = 0; i < vars.size(); i++) { // If we don't have a grid class to support this variable reject it // if (_get_grid_type(vars[i]).empty()) continue; vector coordvars; GetVarCoordVars(vars[i], true, coordvars); if (coordvars.size() < ndim) continue; if (type == VarType::Scalar && GetVarTopologyDim(vars[i]) == 0) continue; if (type == VarType::Particle && GetVarTopologyDim(vars[i]) != 0) continue; validVars.push_back(vars[i]); } _dataVarNamesCache[std::make_pair(type, ndim)] = validVars; return (validVars); } vector DataMgr::GetCoordVarNames() const { VAssert(_dc); vector vars = _dc->GetCoordVarNames(); vector derived_vars = _dvm.GetCoordVarNames(); vars.insert(vars.end(), derived_vars.begin(), derived_vars.end()); return (vars); } string DataMgr::GetTimeCoordVarName() const { VAssert(_dc); // There can be only one time coordinate variable. If a // derived one exists, use it. // vector cvars = _dvm.GetTimeCoordVarNames(); if (!cvars.empty()) return (cvars[0]); cvars = _dc->GetTimeCoordVarNames(); if (!cvars.empty()) return (cvars[0]); return (""); } bool DataMgr::HasTimeVaryingCoordinates() const { const auto time = GetTimeCoordVarName(); for (const auto &v : GetCoordVarNames()) { if (v == time) continue; if (IsTimeVarying(v)) return true; } return false; } bool DataMgr::HasMovingDomain() const { return HasTimeVaryingCoordinates(); } bool DataMgr::GetVarCoordVars(string varname, bool spatial, std::vector &coord_vars) const { VAssert(_dc); coord_vars.clear(); DC::DataVar dvar; bool status = GetDataVarInfo(varname, dvar); if (!status) return (false); DC::Mesh m; status = GetMesh(dvar.GetMeshName(), m); if (!status) return (false); coord_vars = m.GetCoordVars(); if (spatial) return (true); if (!dvar.GetTimeCoordVar().empty()) { coord_vars.push_back(dvar.GetTimeCoordVar()); } return (true); } vector DataMgr::GetVarCoordVars(string varname, bool spatial) const { vector v; GetVarCoordVars(varname, spatial, v); return v; } bool DataMgr::GetDataVarInfo(string varname, VAPoR::DC::DataVar &var) const { VAssert(_dc); bool ok = _dvm.GetDataVarInfo(varname, var); if (!ok) { ok = _dc->GetDataVarInfo(varname, var); } if (!ok) return (ok); return (true); } bool DataMgr::GetCoordVarInfo(string varname, VAPoR::DC::CoordVar &var) const { VAssert(_dc); bool ok = _dvm.GetCoordVarInfo(varname, var); if (!ok) { ok = _dc->GetCoordVarInfo(varname, var); } return (ok); } bool DataMgr::GetBaseVarInfo(string varname, VAPoR::DC::BaseVar &var) const { VAssert(_dc); bool ok = _dvm.GetBaseVarInfo(varname, var); if (!ok) { ok = _dc->GetBaseVarInfo(varname, var); } return (ok); } bool DataMgr::IsTimeVarying(string varname) const { VAssert(_dc); // If var is a data variable and has a time coordinate variable defined // DC::DataVar dvar; bool ok = GetDataVarInfo(varname, dvar); if (ok) return (!dvar.GetTimeCoordVar().empty()); // If var is a coordinate variable and it has a time dimension // DC::CoordVar cvar; ok = GetCoordVarInfo(varname, cvar); if (ok) return (!cvar.GetTimeDimName().empty()); return (false); } bool DataMgr::IsCompressed(string varname) const { VAssert(_dc); DC::BaseVar var; // No error checking here!!!!! // bool status = GetBaseVarInfo(varname, var); if (!status) return (status); return (var.IsCompressed()); } int DataMgr::GetNumTimeSteps(string varname) const { VAssert(_dc); // If data variable get it's time coordinate variable if it exists // if (_isDataVar(varname)) { DC::DataVar var; bool ok = GetDataVarInfo(varname, var); if (!ok) return (0); string time_coord_var = var.GetTimeCoordVar(); if (time_coord_var.empty()) return (1); varname = time_coord_var; } DC::CoordVar var; bool ok = GetCoordVarInfo(varname, var); if (!ok) return (0); string time_dim_name = var.GetTimeDimName(); if (time_dim_name.empty()) return (1); DC::Dimension dim; ok = GetDimension(time_dim_name, dim, 0); if (!ok) return (0); return (dim.GetLength()); } int DataMgr::GetNumTimeSteps() const { return (_timeCoordinates.size()); } size_t DataMgr::GetNumRefLevels(string varname) const { VAssert(_dc); if (varname == "") return 1; DerivedVar *dvar = _getDerivedVar(varname); if (dvar) { return (dvar->GetNumRefLevels()); } return (_dc->GetNumRefLevels(varname)); } vector DataMgr::GetCRatios(string varname) const { VAssert(_dc); if (varname == "") return vector(1, 1); DerivedVar *dvar = _getDerivedVar(varname); if (dvar) { return (dvar->GetCRatios()); } return (_dc->GetCRatios(varname)); } Grid *DataMgr::GetVariable(size_t ts, string varname, int level, int lod, bool lock) { SetDiagMsg("DataMgr::GetVariable(%d,%s,%d,%d,%d, %d)", ts, varname.c_str(), level, lod, lock); int rc = _level_correction(varname, level); if (rc < 0) return (NULL); rc = _lod_correction(varname, lod); if (rc < 0) return (NULL); Grid *rg = _getVariable(ts, varname, level, lod, lock, false); if (!rg) { SetErrMsg("Failed to read variable \"%s\" at time step (%d), and\n" "refinement level (%d) and level-of-detail (%d)", varname.c_str(), ts, level, lod); } return (rg); } Grid *DataMgr::GetVariable(size_t ts, string varname, int level, int lod, CoordType min, CoordType max, bool lock) { SetDiagMsg("DataMgr::GetVariable(%d, %s, %d, %d, %s, %s, %d)", ts, varname.c_str(), level, lod, vector_to_string(min).c_str(), vector_to_string(max).c_str(), lock); int rc = _level_correction(varname, level); if (rc < 0) return (NULL); rc = _lod_correction(varname, lod); if (rc < 0) return (NULL); // // Find the coordinates in voxels of the grid that contains // the axis aligned bounding box specified in user coordinates // by min and max // DimsType min_ui, max_ui; rc = _find_bounding_grid(ts, varname, level, lod, min, max, min_ui, max_ui); if (rc < 0) return (NULL); if (rc == 1) { SetErrMsg("Failed to get requested variable: spatial extents out of range"); return (NULL); } return (DataMgr::GetVariable(ts, varname, level, lod, min_ui, max_ui, lock)); } Grid *DataMgr::_getVariable(size_t ts, string varname, int level, int lod, bool lock, bool dataless) { if (!VariableExists(ts, varname, level, lod)) { SetErrMsg("Invalid variable reference : %s", varname.c_str()); return (NULL); } vector dims_at_level; int rc = GetDimLensAtLevel(varname, level, dims_at_level, ts); if (rc < 0) { SetErrMsg("Invalid variable reference : %s", varname.c_str()); return (NULL); } DimsType min = {0, 0, 0}; DimsType max = {0, 0, 0}; for (int i = 0; i < dims_at_level.size(); i++) { min[i] = (0); max[i] = (dims_at_level[i] - 1); } return (DataMgr::_getVariable(ts, varname, level, lod, min, max, lock, dataless)); } // Find the subset of the data dimension that are the coord dimensions // void DataMgr::_setupCoordVecsHelper(string data_varname, const DimsType &data_dimlens, const DimsType &data_bmin, const DimsType &data_bmax, string coord_varname, int order, DimsType &coord_dimlens, DimsType &coord_bmin, DimsType &coord_bmax, bool structured, long ts) const { coord_dimlens = {1, 1, 1}; coord_bmin = {0, 0, 0}; coord_bmax = {0, 0, 0}; vector data_dims; bool ok = _getVarDimensions(data_varname, data_dims, ts); VAssert(ok); vector coord_dims; ok = _getVarDimensions(coord_varname, coord_dims, ts); VAssert(ok); if (structured) { // For structured data // Here we try to match dimensions of coordinate variables // with dimensions of data variables. Ideally, this would be done // by matching the dimension names. However, some CF data sets (e.g. MOM) // have data and coordinate variables that use different dimension // names (but have the same length) // if (data_dims.size() == 1) { VAssert(coord_dims.size() == 1); VAssert(order == 0); coord_dimlens[0] = (data_dimlens[0]); coord_bmin[0] = (data_bmin[0]); coord_bmax[0] = (data_bmax[0]); } else if (data_dims.size() == 2) { VAssert(order >= 0 && order <= 1); if (coord_dims.size() == 1) { coord_dimlens[0] = (data_dimlens[order]); coord_bmin[0] = (data_bmin[order]); coord_bmax[0] = (data_bmax[order]); } else { coord_dimlens[0] = (data_dimlens[0]); coord_bmin[0] = (data_bmin[0]); coord_bmax[0] = (data_bmax[0]); coord_dimlens[1] = (data_dimlens[1]); coord_bmin[1] = (data_bmin[1]); coord_bmax[1] = (data_bmax[1]); } } else if (data_dims.size() == 3) { VAssert(order >= 0 && order <= 2); if (coord_dims.size() == 1) { coord_dimlens[0] = (data_dimlens[order]); coord_bmin[0] = (data_bmin[order]); coord_bmax[0] = (data_bmax[order]); } else if (coord_dims.size() == 2) { // We assume 2D coordinates are horizontal (in XY plane). // No way currently to distinguish XZ and YZ plane 2D coordinates // for 3D data :-( // VAssert(order >= 0 && order <= 1); coord_dimlens[0] = (data_dimlens[0]); coord_bmin[0] = (data_bmin[0]); coord_bmax[0] = (data_bmax[0]); coord_dimlens[1] = (data_dimlens[1]); coord_bmin[1] = (data_bmin[1]); coord_bmax[1] = (data_bmax[1]); } else if (coord_dims.size() == 3) { coord_dimlens[0] = (data_dimlens[0]); coord_bmin[0] = (data_bmin[0]); coord_bmax[0] = (data_bmax[0]); coord_dimlens[1] = (data_dimlens[1]); coord_bmin[1] = (data_bmin[1]); coord_bmax[1] = (data_bmax[1]); coord_dimlens[2] = (data_dimlens[2]); coord_bmin[2] = (data_bmin[2]); coord_bmax[2] = (data_bmax[2]); } } else { VAssert(0 && "Only 1, 2, or 3D data supported"); } } else { // For unstructured data we can just match data dimension names // with coord dimension names. Yay! // int i = 0; for (int j = 0; j < coord_dims.size(); j++) { while (data_dims[i].GetLength() != coord_dims[j].GetLength() && i < data_dims.size()) { i++; } VAssert(i < data_dims.size()); coord_dimlens[j] = (data_dimlens[i]); coord_bmin[j] = (data_bmin[i]); coord_bmax[j] = (data_bmax[i]); } } } int DataMgr::_setupCoordVecs(size_t ts, string varname, int level, int lod, const DimsType &min, const DimsType &max, vector &varnames, DimsType &roi_dims, vector &dimsvec, vector &bsvec, vector &bminvec, vector &bmaxvec, bool structured) const { varnames.clear(); roi_dims = {1, 1, 1}; dimsvec.clear(); bsvec.clear(); bminvec.clear(); bmaxvec.clear(); // Compute dimenions of ROI // for (int i = 0; i < min.size(); i++) { roi_dims[i] = (max[i] - min[i] + 1); } // Grid and block dimensions at requested refinement // vector dimsv; int rc = GetDimLensAtLevel(varname, level, dimsv, ts); VAssert(rc >= 0); DimsType dims = {1, 1, 1}; Grid::CopyToArr3(dimsv, dims); dimsvec.push_back(dims); DimsType bs = {1, 1, 1}; Grid::CopyToArr3(_bs.data(), dimsv.size(), bs); bsvec.push_back(bs); // Map voxel coordinates into block coordinates // DimsType bmin, bmax; map_vox_to_blk(bs, min, bmin); map_vox_to_blk(bs, max, bmax); bminvec.push_back(bmin); bmaxvec.push_back(bmax); vector cvarnames; bool ok = GetVarCoordVars(varname, true, cvarnames); VAssert(ok); for (int i = 0; i < cvarnames.size(); i++) { // Map data indices to coordinate indices. Coordinate indices // are a subset of the data indices. // DimsType coord_dims, coord_bmin, coord_bmax; _setupCoordVecsHelper(varname, dims, bmin, bmax, cvarnames[i], i, coord_dims, coord_bmin, coord_bmax, structured, ts); dimsvec.push_back(coord_dims); bminvec.push_back(coord_bmin); bmaxvec.push_back(coord_bmax); DimsType bs = {1, 1, 1}; Grid::CopyToArr3(_bs.data(), Grid::GetNumDimensions(coord_dims), bs); bsvec.push_back(bs); } varnames.push_back(varname); varnames.insert(varnames.end(), cvarnames.begin(), cvarnames.end()); return (0); } int DataMgr::_setupConnVecs(size_t ts, string varname, int level, int lod, vector &varnames, vector &dimsvec, vector &bsvec, vector &bminvec, vector &bmaxvec) const { varnames.clear(); dimsvec.clear(); bsvec.clear(); bminvec.clear(); bmaxvec.clear(); string face_node_var; string node_face_var; string face_edge_var; string face_face_var; string edge_node_var; string edge_face_var; bool ok = _getVarConnVars(varname, face_node_var, node_face_var, face_edge_var, face_face_var, edge_node_var, edge_face_var); if (!ok) { SetErrMsg("Invalid variable reference : %s", varname.c_str()); return (-1); } if (!face_node_var.empty()) varnames.push_back(face_node_var); if (!node_face_var.empty()) varnames.push_back(node_face_var); if (!face_edge_var.empty()) varnames.push_back(face_edge_var); if (!face_face_var.empty()) varnames.push_back(face_face_var); if (!edge_node_var.empty()) varnames.push_back(edge_node_var); if (!edge_face_var.empty()) varnames.push_back(edge_face_var); for (int i = 0; i < varnames.size(); i++) { string name = varnames[i]; vector dimsv; int rc = GetDimLensAtLevel(name, level, dimsv, ts); if (rc < 0) { SetErrMsg("Invalid variable reference : %s", name.c_str()); return (-1); } DimsType dims = {1, 1, 1}; Grid::CopyToArr3(dimsv, dims); // Ugh. Connection data are not blocked. // DimsType bs = dims; // Always read the entire connection variable // DimsType conn_min = {0, 0, 0}; DimsType conn_max = {dims[0] - 1, dims[1] - 1, dims[2] - 1}; // Map voxel coordinates into block coordinates // DimsType bmin, bmax; map_vox_to_blk(bs, conn_min, bmin); map_vox_to_blk(bs, conn_max, bmax); dimsvec.push_back(dims); bsvec.push_back(bs); bminvec.push_back(bmin); bmaxvec.push_back(bmax); } return (0); } Grid *DataMgr::_getVariable(size_t ts, string varname, int level, int lod, DimsType min, DimsType max, bool lock, bool dataless) { Grid *rg = NULL; string gridType = _get_grid_type(varname); if (gridType.empty()) { SetErrMsg("Unrecognized grid type for variable %s", varname.c_str()); return (NULL); } DC::DataVar dvar; bool status = DataMgr::GetDataVarInfo(varname, dvar); VAssert(status); vector cvarsinfo; DC::CoordVar dummy; status = _get_coord_vars(varname, cvarsinfo, dummy); VAssert(status); vector varnames; DimsType roi_dims; vector dimsvec; vector bsvec; vector bminvec; vector bmaxvec; // Get dimensions for coordinate variables // int rc = _setupCoordVecs(ts, varname, level, lod, min, max, varnames, roi_dims, dimsvec, bsvec, bminvec, bmaxvec, !_gridHelper.IsUnstructured(gridType)); if (rc < 0) return (NULL); // // if dataless we only load coordinate data // if (dataless) varnames[0].clear(); vector blkvec; rc = DataMgr::_get_regions(ts, varnames, level, lod, true, dimsvec, bsvec, bminvec, bmaxvec, blkvec); if (rc < 0) return (NULL); // Get dimensions for connectivity variables (if any) // vector conn_varnames; vector conn_dimsvec; vector conn_bsvec; vector conn_bminvec; vector conn_bmaxvec; vector conn_blkvec; if (_gridHelper.IsUnstructured(gridType)) { rc = _setupConnVecs(ts, varname, level, lod, conn_varnames, conn_dimsvec, conn_bsvec, conn_bminvec, conn_bmaxvec); if (rc < 0) return (NULL); rc = DataMgr::_get_regions(ts, conn_varnames, level, lod, true, conn_dimsvec, conn_bsvec, conn_bminvec, conn_bmaxvec, conn_blkvec); if (rc < 0) return (NULL); } if (_gridHelper.IsUnstructured(gridType)) { DimsType vertexDims; DimsType faceDims; DimsType edgeDims; UnstructuredGrid::Location location; size_t maxVertexPerFace; size_t maxFacePerVertex; long vertexOffset; long faceOffset; _ugrid_setup(dvar, vertexDims, faceDims, edgeDims, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset, ts); rg = _gridHelper.MakeGridUnstructured(gridType, ts, level, lod, dvar, cvarsinfo, roi_dims, dimsvec[0], blkvec, bsvec, bminvec, bmaxvec, conn_blkvec, conn_bsvec, conn_bminvec, conn_bmaxvec, vertexDims, faceDims, edgeDims, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset); } else { rg = _gridHelper.MakeGridStructured(gridType, ts, level, lod, dvar, cvarsinfo, roi_dims, dimsvec[0], blkvec, bsvec, bminvec, bmaxvec); } VAssert(rg); // // Inform the grid of the offsets from the larger mesh to the // mesh subset contained in g. In general, gmin<=min // DimsType gmin, gmax; map_blk_to_vox(bsvec[0], dimsvec[0], bminvec[0], bmaxvec[0], gmin, gmax); rg->SetMinAbs(gmin); // // Safe to remove locks now that were not explicitly requested // if (!lock) { for (int i = 0; i < blkvec.size(); i++) { if (blkvec[i]) _unlock_blocks(blkvec[i]); } for (int i = 0; i < conn_blkvec.size(); i++) { if (conn_blkvec[i]) _unlock_blocks(conn_blkvec[i]); } } else { if (blkvec.size()) _lockedFloatBlks[rg] = blkvec; if (conn_blkvec.size()) _lockedIntBlks[rg] = conn_blkvec; } return (rg); } Grid *DataMgr::GetVariable(size_t ts, string varname, int level, int lod, DimsType min, DimsType max, bool lock) { SetDiagMsg("DataMgr::GetVariable(%d, %s, %d, %d, %s, %s, %d)", ts, varname.c_str(), level, lod, vector_to_string(min).c_str(), vector_to_string(max).c_str(), lock); int rc = _level_correction(varname, level); if (rc < 0) return (NULL); rc = _lod_correction(varname, lod); if (rc < 0) return (NULL); // Make sure variable dimensions match extents specification // vector coord_vars; bool ok = GetVarCoordVars(varname, true, coord_vars); VAssert(ok); DimsType min_vec = {0, 0, 0}; DimsType max_vec = {0, 0, 0}; for (int i = 0; i < coord_vars.size(); i++) { min_vec[i] = (min[i]); max_vec[i] = (max[i]); } Grid *rg = _getVariable(ts, varname, level, lod, min_vec, max_vec, lock, false); if (!rg) { SetErrMsg("Failed to read variable \"%s\" at time step (%d), and\n" "refinement level (%d) and level-of-detail (%d)", varname.c_str(), ts, level, lod); } return (rg); } int DataMgr::GetVariableExtents(size_t ts, string varname, int level, int lod, CoordType &min, CoordType &max) { SetDiagMsg("DataMgr::GetVariableExtents(%d, %s, %d, %d)", ts, varname.c_str(), level, lod); min = {0.0, 0.0, 0.0}; max = min; int rc = _lod_correction(varname, lod); if (rc < 0) return (-1); rc = _level_correction(varname, level); if (rc < 0) return (-1); vector cvars; string dummy; bool ok = _get_coord_vars(varname, cvars, dummy); if (!ok) return (-1); string key = "VariableExtents"; vector values; if (_varInfoCacheDouble.Get(ts, cvars, level, lod, key, values)) { int n = values.size(); for (int i = 0; i < n / 2; i++) { min[i] = values[i]; max[i] = values[i + (n / 2)]; } return (0); } Grid *rg = _getVariable(ts, varname, level, lod, false, true); if (!rg) return (-1); rg->GetUserExtents(min, max); // Cache results // values.clear(); for (int i = 0; i < min.size(); i++) values.push_back(min[i]); for (int i = 0; i < max.size(); i++) values.push_back(max[i]); _varInfoCacheDouble.Set(ts, cvars, level, lod, key, values); return (0); } int DataMgr::GetDataRange(size_t ts, string varname, int level, int lod, vector &range) { SetDiagMsg("DataMgr::GetDataRange(%d,%s)", ts, varname.c_str()); CoordType min, max; int rc = GetVariableExtents(ts, varname, level, lod, min, max); if (rc < 0) return (-1); return (GetDataRange(ts, varname, level, lod, min, max, range)); } int DataMgr::GetDataRange(size_t ts, string varname, int level, int lod, CoordType min, CoordType max, vector &range) { SetDiagMsg("DataMgr::GetDataRange(%d,%s)", ts, varname.c_str()); range = {0.0, 0.0}; int rc = _level_correction(varname, level); if (rc < 0) return (-1); rc = _lod_correction(varname, lod); if (rc < 0) return (-1); // // Find the coordinates in voxels of the grid that contains // the axis aligned bounding box specified in user coordinates // by min and max // DimsType min_ui, max_ui; rc = _find_bounding_grid(ts, varname, level, lod, min, max, min_ui, max_ui); if (rc != 0) return (-1); // See if we've already cache'd it. // ostringstream oss; oss << "VariableRange"; oss << vector_to_string(min_ui); oss << vector_to_string(max_ui); string key = oss.str(); if (_varInfoCacheDouble.Get(ts, varname, level, lod, key, range)) { VAssert(range.size() == 2); return (0); } const Grid *sg = DataMgr::GetVariable(ts, varname, level, lod, min_ui, max_ui, false); if (!sg) return (-1); float range_f[2]; sg->GetRange(range_f); range = {range_f[0], range_f[1]}; delete sg; _varInfoCacheDouble.Set(ts, varname, level, lod, key, range); return (0); } int DataMgr::GetDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level, long ts) const { VAssert(_dc); dims_at_level.clear(); bs_at_level.clear(); int rc = 0; DerivedVar *dvar = _getDerivedVar(varname); if (dvar) { rc = dvar->GetDimLensAtLevel(level, dims_at_level, bs_at_level); } else { rc = _dc->GetDimLensAtLevel(varname, level, dims_at_level, bs_at_level, ts); } if (rc < 0) return (-1); return (0); } vector DataMgr::_get_var_dependencies_1(string varname) const { vector varnames; DerivedVar *derivedVar = _getDerivedVar(varname); if (derivedVar) { varnames = derivedVar->GetInputs(); } // No more dependencies if not a data variable // if (!_isDataVar(varname)) return (varnames); vector cvars; bool ok = GetVarCoordVars(varname, false, cvars); if (ok) { for (int i = 0; i < cvars.size(); i++) varnames.push_back(cvars[i]); } // Test for connectivity variables, if any // string face_node_var; string node_face_var; string face_edge_var; string face_face_var; string edge_node_var; string edge_face_var; ok = _getVarConnVars(varname, face_node_var, node_face_var, face_edge_var, face_face_var, edge_node_var, edge_face_var); if (ok) { if (!face_node_var.empty()) varnames.push_back(face_node_var); if (!node_face_var.empty()) varnames.push_back(node_face_var); if (!face_edge_var.empty()) varnames.push_back(face_edge_var); if (!face_face_var.empty()) varnames.push_back(face_face_var); if (!edge_node_var.empty()) varnames.push_back(edge_node_var); if (!edge_face_var.empty()) varnames.push_back(edge_face_var); } sort(varnames.begin(), varnames.end()); varnames.erase(unique(varnames.begin(), varnames.end()), varnames.end()); return (varnames); } vector DataMgr::_get_var_dependencies_all(vector varnames, vector dependencies) const { // Recursively look for all of a variable's dependencies, handing any // cycles in the dependency graph // vector new_varnames; for (int i = 0; i < varnames.size(); i++) { vector new_dependencies = _get_var_dependencies_1(varnames[i]); for (int j = 0; j < new_dependencies.size(); j++) { // Avoid cycles by not adding variable names that are already // in the dependencies vector // if (!contains(dependencies, new_dependencies[j])) { dependencies.push_back(new_dependencies[j]); new_varnames.push_back(new_dependencies[j]); } } } if (new_varnames.size()) { return (_get_var_dependencies_all(new_varnames, dependencies)); } return (dependencies); } bool DataMgr::VariableExists(size_t ts, string varname, int level, int lod) const { if (varname.empty()) return (false); // disable error reporting // bool enabled = EnableErrMsg(false); int rc = _level_correction(varname, level); if (rc < 0) { EnableErrMsg(enabled); return (false); } rc = _lod_correction(varname, lod); if (rc < 0) { EnableErrMsg(enabled); return (false); } EnableErrMsg(enabled); string key = "VariableExists"; vector found; if (_varInfoCacheSize_T.Get(ts, varname, level, lod, key, found)) { return (found[0]); } // // Recursively find all variable dependencies needed by this // varible. E.g. coordinate variables, input for derived variables, // auxillary variables // vector varnames = _get_var_dependencies_all(vector({varname}), vector()); varnames.insert(varnames.begin(), varname); // Now check for the existence of the variable and all of its // dependencies, updating variable existence cache in process // for (int i = 0; i < varnames.size(); i++) { if (_varInfoCacheSize_T.Get(ts, varnames[i], level, lod, key, found)) { if (found[0]) continue; else return (false); } if (DataMgr::IsVariableNative(varnames[i])) { bool exists = _dc->VariableExists(ts, varnames[i], level, lod); if (!exists) { _varInfoCacheSize_T.Set(ts, varnames[i], level, lod, key, vector({0})); return (false); } } else { DerivedVar *derivedVar = _getDerivedVar(varnames[i]); if (!derivedVar) { _varInfoCacheSize_T.Set(ts, varnames[i], level, lod, key, vector({0})); return (false); } } } // Cache found results for later. // for (int i = 0; i < varnames.size(); i++) { _varInfoCacheSize_T.Set(ts, varnames[i], level, lod, key, vector({1})); } return (true); } bool DataMgr::IsVariableNative(string name) const { vector svec = _get_native_variables(); for (int i = 0; i < svec.size(); i++) { if (name.compare(svec[i]) == 0) return (true); } return (false); } bool DataMgr::IsVariableDerived(string name) const { return (_getDerivedVar(name) != NULL); } int DataMgr::AddDerivedVar(DerivedDataVar *derivedVar) { string varname = derivedVar->GetName(); if (_dvm.HasVar(varname)) { SetErrMsg("Variable named %s already defined", varname.c_str()); return (-1); } _dvm.AddDataVar(derivedVar); // // Clear variable name cache // for (auto itr = _dataVarNamesCache.begin(); itr != _dataVarNamesCache.end(); ++itr) { vector &ref = itr->second; ref.clear(); } _varInfoCacheSize_T.Purge(vector({varname})); return (0); } void DataMgr::RemoveDerivedVar(string varname) { if (!_dvm.HasVar(varname)) return; _dvm.RemoveVar(_dvm.GetVar(varname)); _free_var(varname); // // Clear variable name cache // for (auto itr = _dataVarNamesCache.begin(); itr != _dataVarNamesCache.end(); ++itr) { vector &ref = itr->second; ref.clear(); } _varInfoCacheSize_T.Purge(vector({varname})); } void DataMgr::Clear() { _PipeLines.clear(); list::iterator itr; for (itr = _regionsList.begin(); itr != _regionsList.end(); itr++) { const region_t ®ion = *itr; if (region.blks) _blk_mem_mgr->FreeMem(region.blks); } _regionsList.clear(); } void DataMgr::UnlockGrid(const Grid *rg) { SetDiagMsg("DataMgr::UnlockGrid()"); const auto fb = _lockedFloatBlks.find(rg); if (fb != _lockedFloatBlks.end()) { auto &bvec = fb->second; for (auto b : bvec) { _unlock_blocks(b); } _lockedFloatBlks.erase(fb); } const auto ib = _lockedIntBlks.find(rg); if (ib != _lockedIntBlks.end()) { auto &bvec = ib->second; for (auto b : bvec) { _unlock_blocks(b); } _lockedIntBlks.erase(ib); } } size_t DataMgr::GetNumDimensions(string varname) const { VAssert(_dc); vector dims, dummy; bool enabled = EnableErrMsg(false); int rc = GetDimLensAtLevel(varname, 0, dims, dummy, 0); EnableErrMsg(enabled); if (rc < 0) return (0); return (dims.size()); } size_t DataMgr::GetVarTopologyDim(string varname) const { VAssert(_dc); DC::DataVar var; bool status = GetDataVarInfo(varname, var); if (!status) return (0); string mname = var.GetMeshName(); DC::Mesh mesh; status = GetMesh(mname, mesh); if (!status) return (0); return (mesh.GetTopologyDim()); } size_t DataMgr::GetVarGeometryDim(string varname) const { VAssert(_dc); DC::DataVar var; bool status = GetDataVarInfo(varname, var); if (!status) return (0); string mname = var.GetMeshName(); DC::Mesh mesh; status = GetMesh(mname, mesh); if (!status) return (0); return (mesh.GetGeometryDim()); } template T *DataMgr::_get_region_from_cache(size_t ts, string varname, int level, int lod, const DimsType &bmin, const DimsType &bmax, bool lock) { list::iterator itr; for (itr = _regionsList.begin(); itr != _regionsList.end(); itr++) { region_t ®ion = *itr; if (region.ts == ts && region.varname.compare(varname) == 0 && region.level == level && region.lod == lod && region.bmin == bmin && region.bmax == bmax) { // Increment the lock counter region.lock_counter += lock ? 1 : 0; // Move region to front of list region_t tmp_region = region; _regionsList.erase(itr); _regionsList.push_back(tmp_region); SetDiagMsg("DataMgr::_get_region_from_cache() - data in cache %xll\n", tmp_region.blks); return ((T *)tmp_region.blks); } } return (NULL); } template int DataMgr::_get_unblocked_region_from_fs(size_t ts, string varname, int level, int lod, const DimsType &grid_dims, const DimsType &grid_bs, const DimsType &grid_min, const DimsType &grid_max, T *blks) { int fd = _openVariableRead(ts, varname, level, lod); if (fd < 0) return (fd); T *region = new T[vproduct(box_dims(grid_min, grid_max))]; int nlevels = DataMgr::GetNumRefLevels(varname); // Rank of array describing variable // size_t ndims = GetNumDimensions(varname); // Downsample the data if needed // if (level < -nlevels) { vector dimsv; int rc = GetDimLensAtLevel(varname, level, dimsv, ts); DimsType dims = {1, 1, 1}; Grid::CopyToArr3(dimsv, dims); // grid_min and grid_max are specified in voxel coordinates // relative to the downsampled grid. Figure out coordinates for // region we need on the native grid // DimsType file_min, file_max; for (int i = 0; i < dims.size(); i++) { VAssert(dims[i] > 0); vector weights; downsample_compute_weights(dims[i], grid_dims[i], weights); int loffset = (int)weights[0]; int roffset = (dims[i] - 1) - (int)(weights[weights.size() - 1] + 1.0); file_min[i] = ((int)weights[grid_min[i]] - loffset); file_max[i] = ((int)weights[grid_max[i]] + 1 + roffset); } T *buf = new T[vproduct(box_dims(file_min, file_max))]; rc = _readRegion(fd, file_min, file_max, ndims, buf); if (rc < 0) { delete[] buf; return (-1); } downsample(buf, box_dims(file_min, file_max), region, box_dims(grid_min, grid_max)); if (buf) delete[] buf; } else { int rc = _readRegion(fd, grid_min, grid_max, ndims, region); if (rc < 0) { if (region) delete[] region; _closeVariable(fd); return (-1); } } copy_block(region, blks, grid_min, grid_max, grid_bs, grid_min, grid_max); (void)_closeVariable(fd); if (region) delete[] region; return (0); } template int DataMgr::_get_blocked_region_from_fs(size_t ts, string varname, int level, int lod, const DimsType &file_bs, const DimsType &file_dims, const DimsType &grid_dims, const DimsType &grid_bs, const DimsType &grid_min, const DimsType &grid_max, T *blks) { // Map requested region voxel coordinates to disk block coordinates // DimsType file_bmin, file_bmax; map_vox_to_blk(file_bs, grid_min, file_bmin); map_vox_to_blk(file_bs, grid_max, file_bmax); int fd = _openVariableRead(ts, varname, level, lod); if (fd < 0) return (fd); DimsType bmin = file_bmin; DimsType bmax = file_bmax; // For 3D data read 2D slabs one at a time. This just reduces // memory requirements for the temporary buffer we need // size_t nreads = 1; if (bmax[2] > bmin[2]) { nreads = bmax[2] - bmin[2] + 1; bmax[2] = bmin[2]; } DimsType file_min, file_max; map_blk_to_vox(file_bs, bmin, bmax, file_min, file_max); T *file_block = new T[vproduct(box_dims(file_min, file_max))]; size_t ndims = GetNumDimensions(varname); for (size_t i = 0; i < nreads; i++) { map_blk_to_vox(file_bs, file_dims, bmin, bmax, file_min, file_max); int rc = _readRegion(fd, file_min, file_max, ndims, file_block); if (rc < 0) { delete[] file_block; return (-1); } copy_block(file_block, blks, file_min, file_max, grid_bs, grid_min, grid_max); // Increment along slowest axis (2) // This is a no-op if less than 3 dimensions // IncrementCoords(file_bmin.data(), file_bmax.data(), bmin.data(), bmin.size(), 2); IncrementCoords(file_bmin.data(), file_bmax.data(), bmax.data(), bmin.size(), 2); } (void)_closeVariable(fd); if (file_block) delete[] file_block; return (0); } template T *DataMgr::_get_region_from_fs(size_t ts, string varname, int level, int lod, const DimsType &grid_dims, const DimsType &grid_bs, const DimsType &grid_bmin, const DimsType &grid_bmax, bool lock) { T *blks = (T *)_alloc_region(ts, varname, level, lod, grid_bmin, grid_bmax, grid_bs, sizeof(T), lock, false); if (!blks) return (NULL); vector file_dimsv, file_bsv; int rc = GetDimLensAtLevel(varname, level, file_dimsv, file_bsv, ts); VAssert(rc >= 0); DimsType file_dims = {1, 1, 1}; Grid::CopyToArr3(file_dimsv, file_dims); DimsType file_bs = {1, 1, 1}; Grid::CopyToArr3(file_bsv, file_bs); // Get voxel coordinates of requested region, clamped to grid // boundaries. // DimsType grid_min, grid_max; map_blk_to_vox(grid_bs, grid_dims, grid_bmin, grid_bmax, grid_min, grid_max); int nlevels = DataMgr::GetNumRefLevels(varname); // If data aren't blocked on disk or if the requested level is not // available do a non-blocked read // if (!is_blocked(file_bs) || level < -nlevels) { rc = _get_unblocked_region_from_fs(ts, varname, level, lod, grid_dims, grid_bs, grid_min, grid_max, blks); } else { rc = _get_blocked_region_from_fs(ts, varname, level, lod, file_bs, file_dims, grid_dims, grid_bs, grid_min, grid_max, blks); } if (rc < 0) { _free_region(ts, varname, level, lod, grid_bmin, grid_bmax, true); return (NULL); } SetDiagMsg("DataMgr::GetGrid() - data read from fs\n"); return (blks); } template T *DataMgr::_get_region(size_t ts, string varname, int level, int lod, int nlods, const DimsType &dims, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, bool lock) { if (lod < -nlods) lod = -nlods; // See if region is already in cache. If not, read from the // file system. // T *blks = _get_region_from_cache(ts, varname, level, lod, bmin, bmax, lock); if (!blks) { blks = (T *)_get_region_from_fs(ts, varname, level, lod, dims, bs, bmin, bmax, lock); } if (!blks) { SetErrMsg("Failed to read region from variable/timestep/level/lod (%s, %d, %d, %d)", varname.c_str(), ts, level, lod); return (NULL); } return (blks); } template int DataMgr::_get_regions(size_t ts, const vector &varnames, int level, int lod, bool lock, const vector &dimsvec, const vector &bsvec, // native coordinates const vector &bminvec, const vector &bmaxvec, vector &blkvec) { blkvec.clear(); for (int i = 0; i < varnames.size(); i++) { if (varnames[i].empty()) { // nothing to do blkvec.push_back(NULL); continue; } DC::BaseVar var; int rc = GetBaseVarInfo(varnames[i], var); if (rc < 0) return (rc); int nlods = var.GetCRatios().size(); size_t my_ts = ts; // If variable isn't time varying time step should always be 0 // if (!DataMgr::IsTimeVarying(varnames[i])) my_ts = 0; T *blks = _get_region(my_ts, varnames[i], level, lod, nlods, dimsvec[i], bsvec[i], bminvec[i], bmaxvec[i], true); if (!blks) { for (int i = 0; i < blkvec.size(); i++) { if (blkvec[i]) _unlock_blocks(blkvec[i]); } return (-1); } blkvec.push_back(blks); } // // Safe to remove locks now that were not explicitly requested // if (!lock) { for (int i = 0; i < blkvec.size(); i++) { if (blkvec[i]) _unlock_blocks(blkvec[i]); } } return (0); } void *DataMgr::_alloc_region(size_t ts, string varname, int level, int lod, DimsType bmin, DimsType bmax, DimsType bs, int element_sz, bool lock, bool fill) { size_t mem_block_size; if (!_blk_mem_mgr) { mem_block_size = 1024 * 1024; size_t num_blks = (_mem_size * 1024 * 1024) / mem_block_size; BlkMemMgr::RequestMemSize(mem_block_size, num_blks); _blk_mem_mgr = new BlkMemMgr(); } mem_block_size = BlkMemMgr::GetBlkSize(); // Free region already exists // _free_region(ts, varname, level, lod, bmin, bmax, true); size_t size = element_sz; for (int i = 0; i < bmin.size(); i++) { size *= (bmax[i] - bmin[i] + 1) * bs[i]; } size_t nblocks = (size_t)ceil((double)size / (double)mem_block_size); void *blks; while (!(blks = (void *)_blk_mem_mgr->Alloc(nblocks, fill))) { if (!_free_lru()) { SetErrMsg("Failed to allocate requested memory"); return (NULL); } } region_t region; region.ts = ts; region.varname = varname; region.level = level; region.lod = lod; region.bmin = bmin; region.bmax = bmax; region.lock_counter = lock ? 1 : 0; region.blks = blks; _regionsList.push_back(region); return (region.blks); } void DataMgr::_free_region(size_t ts, string varname, int level, int lod, DimsType bmin, DimsType bmax, bool forceFlag) { list::iterator itr; for (itr = _regionsList.begin(); itr != _regionsList.end(); itr++) { const region_t ®ion = *itr; if (region.ts == ts && region.varname.compare(varname) == 0 && region.level == level && region.lod == lod && region.bmin == bmin && region.bmax == bmax) { if (region.lock_counter == 0 || forceFlag) { if (region.blks) _blk_mem_mgr->FreeMem(region.blks); _regionsList.erase(itr); return; } } } return; } void DataMgr::_free_var(string varname) { list::iterator itr; for (itr = _regionsList.begin(); itr != _regionsList.end();) { const region_t ®ion = *itr; if (region.varname.compare(varname) == 0) { if (region.blks) _blk_mem_mgr->FreeMem(region.blks); _regionsList.erase(itr); itr = _regionsList.begin(); } else itr++; } _varInfoCacheSize_T.Purge(vector(1, varname)); _varInfoCacheDouble.Purge(vector(1, varname)); _varInfoCacheVoidPtr.Purge(vector(1, varname)); } bool DataMgr::_free_lru() { // The least recently used region is at the front of the list // list::iterator itr; for (itr = _regionsList.begin(); itr != _regionsList.end(); itr++) { const region_t ®ion = *itr; if (region.lock_counter == 0) { if (region.blks) _blk_mem_mgr->FreeMem(region.blks); _regionsList.erase(itr); return (true); } } // nothing to free return (false); } // // return complete list of native variables // vector DataMgr::_get_native_variables() const { vector v1 = _dc->GetDataVarNames(); vector v2 = _dc->GetCoordVarNames(); vector v3 = _dc->GetAuxVarNames(); v1.insert(v1.end(), v2.begin(), v2.end()); v1.insert(v1.end(), v3.begin(), v3.end()); return (v1); } bool DataMgr::_hasHorizontalXForm() const { VAssert(_dc); vector meshnames = _dc->GetMeshNames(); for (int i = 0; i < meshnames.size(); i++) { if (_hasHorizontalXForm(meshnames[i])) return (true); } return (false); } bool DataMgr::_hasHorizontalXForm(string meshname) const { DC::Mesh m; bool status = _dc->GetMesh(meshname, m); if (!status) return (false); vector coordVars = m.GetCoordVars(); for (int i = 0; i < coordVars.size(); i++) { DC::CoordVar varInfo; bool ok = _dc->GetCoordVarInfo(coordVars[i], varInfo); VAssert(ok); // if (varInfo.GetUnits().empty()) continue; // Version 1.0 of CF conventions allows "degrees" as units // for both lat and longitude. So we check IsLonUnit, // which looks for "degrees_east", "degrees_E", etc., and // IsLatOrLonUnit, which will return true for "degrees". Unforunately, // IsLatOrLonUnit will also return true for an empty string "", so // we explicitly test for that above. // if (varInfo.GetAxis() == 0 && (_udunits.IsLonUnit(varInfo.GetUnits()) || _udunits.IsLatOrLonUnit(varInfo.GetUnits()))) { return (true); } if (varInfo.GetAxis() == 1 && (_udunits.IsLatUnit(varInfo.GetUnits()) || _udunits.IsLatOrLonUnit(varInfo.GetUnits()))) { return (true); } } return (false); } bool DataMgr::_hasVerticalXForm() const { VAssert(_dc); // Only 3D variables can have vertical coordinates? // vector meshnames = _dc->GetMeshNames(); for (int i = 0; i < meshnames.size(); i++) { if (_hasVerticalXForm(meshnames[i])) return (true); } return (false); } bool DataMgr::_hasVerticalXForm(string meshname, string &standard_name, string &formula_terms) const { standard_name.clear(); formula_terms.clear(); DC::Mesh m; bool ok = _dc->GetMesh(meshname, m); if (!ok) return (false); if (m.GetDimNames().size() != 3) return (false); vector coordVars = m.GetCoordVars(); bool hasVertCoord = false; DC::CoordVar cvarInfo; for (int i = 0; i < coordVars.size(); i++) { bool ok = _dc->GetCoordVarInfo(coordVars[i], cvarInfo); VAssert(ok); if (cvarInfo.GetAxis() == 2) { hasVertCoord = true; break; } } if (!hasVertCoord) return (false); DC::Attribute attr_name; if (!cvarInfo.GetAttribute("standard_name", attr_name)) return (false); attr_name.GetValues(standard_name); if (standard_name.empty()) return (false); DC::Attribute attr_formula; if (!cvarInfo.GetAttribute("formula_terms", attr_formula)) return (false); attr_formula.GetValues(formula_terms); if (formula_terms.empty()) return (false); // Make sure all of the dependent variables needed by the // formula actually exist // map parsed_terms; ok = DerivedCFVertCoordVar::ParseFormula(formula_terms, parsed_terms); if (!ok) return (false); for (auto itr = parsed_terms.begin(); itr != parsed_terms.end(); ++itr) { const string &varname = itr->second; if (!_dc->VariableExists(0, varname, 0, 0)) return (false); } // Does a converter exist for this standard name? // vector names = DerivedCFVertCoordVarFactory::Instance()->GetFactoryNames(); for (int i = 0; i < names.size(); i++) { if (standard_name == names[i]) return (true); } return (false); } bool DataMgr::_isCoordVarInUse(string varName) const { std::vector dataVars = GetDataVarNames(); for (auto dataVar : dataVars) { std::vector coordVars; bool ok = GetVarCoordVars(dataVar, false, coordVars); if (!ok) continue; if (find(coordVars.begin(), coordVars.end(), varName) != coordVars.end()) { return (true); } } return (false); } template string DataMgr::VarInfoCache::_make_hash(string key, size_t ts, vector varnames, int level, int lod) { ostringstream oss; oss << key << ":"; oss << ts << ":"; for (int i = 0; i < varnames.size(); i++) { oss << varnames[i] << ":"; } oss << level << ":"; oss << lod; return (oss.str()); } template void DataMgr::VarInfoCache::_decode_hash(const string &hash, string &key, size_t &ts, vector &varnames, int &level, int &lod) { varnames.clear(); stringstream ss(hash); vector result; // parse hash into vector of strings // while (ss.good()) { string substr; getline(ss, substr, ':'); result.push_back(substr); } VAssert(result.size() >= 5); int i = 0; key = result[i++]; ts = (size_t)stoi(result[i++]); while (!is_int(result[i])) { varnames.push_back(result[i++]); } level = stoi(result[i++]); lod = stoi(result[i++]); } template void DataMgr::VarInfoCache::Set(size_t ts, vector varnames, int level, int lod, string key, const vector &values) { string hash = _make_hash(key, ts, varnames, level, lod); _cache[hash] = values; } template bool DataMgr::VarInfoCache::Get(size_t ts, vector varnames, int level, int lod, string key, vector &values) const { values.clear(); string hash = _make_hash(key, ts, varnames, level, lod); typename map>::const_iterator itr = _cache.find(hash); if (itr == _cache.end()) return (false); values = itr->second; return (true); } template void DataMgr::VarInfoCache::Purge(size_t ts, vector varnames, int level, int lod, string key) { string hash = _make_hash(key, ts, varnames, level, lod); typename map>::iterator itr = _cache.find(hash); if (itr == _cache.end()) return; _cache.erase(itr); } template void DataMgr::VarInfoCache::Purge(vector varnames) { vector hashes; typename map>::iterator itr; for (itr = _cache.begin(); itr != _cache.end(); ++itr) { hashes.push_back(itr->first); } for (int i = 0; i < hashes.size(); i++) { string hash = hashes[i]; string key; size_t ts; vector cvarnames; int level; int lod; _decode_hash(hash, key, ts, cvarnames, level, lod); if (varnames == cvarnames) { Purge(ts, varnames, level, lod, key); } } } DataMgr::BlkExts::BlkExts(const DimsType &bmin, const DimsType &bmax) { _bmin = bmin; _bmax = bmax; size_t nelements = Wasp::LinearizeCoords(bmax.data(), bmin.data(), bmax.data(), bmin.size()) + 1; _mins.resize(nelements); _maxs.resize(nelements); } void DataMgr::BlkExts::Insert(const DimsType &bcoord, const CoordType &min, const CoordType &max) { size_t offset = Wasp::LinearizeCoords(bcoord.data(), _bmin.data(), _bmax.data(), bcoord.size()); _mins[offset] = min; _maxs[offset] = max; } bool DataMgr::BlkExts::Intersect(const CoordType &min, const CoordType &max, DimsType &bmin, DimsType &bmax, int nCoords) const { bmin = _bmax; bmax = _bmin; bool intersection = false; // Test for intersection with the axis aligned bounding box of each // block. // for (size_t offset = 0; offset < _mins.size(); offset++) { bool overlap = true; for (int j = 0; j < nCoords; j++) { if (_maxs[offset][j] < min[j] || _mins[offset][j] > max[j]) { overlap = false; break; } } // If the current block intersects the specified bounding volume // compute the block coordinates of the first and last block // that intersect the volume // if (overlap) { intersection = true; // at least one block intersects DimsType coord; Wasp::VectorizeCoords(offset, _bmin.data(), _bmax.data(), coord.data(), coord.size()); for (int i = 0; i < nCoords; i++) { if (coord[i] < bmin[i]) bmin[i] = coord[i]; if (coord[i] > bmax[i]) bmax[i] = coord[i]; } } } return (intersection); } int DataMgr::_level_correction(string varname, int &level) const { int nlevels = DataMgr::GetNumRefLevels(varname); if (level >= nlevels) level = nlevels - 1; if (level >= 0) level = -(nlevels - level); if (level < -nlevels) level = -nlevels; return (0); } int DataMgr::_lod_correction(string varname, int &lod) const { DC::BaseVar var; int rc = GetBaseVarInfo(varname, var); if (rc < 0) return (rc); int nlod = var.GetCRatios().size(); if (lod >= nlod) lod = nlod - 1; if (lod >= 0) lod = -(nlod - lod); if (lod < -nlod) lod = -nlod; return (0); } // // Get coordiante variable names for a data variable, return as // a list of spatial coordinate variables, and a single (if it exists) // time coordinate variable // bool DataMgr::_get_coord_vars(string varname, vector &scvars, string &tcvar) const { scvars.clear(); tcvar.clear(); // Get space and time coord vars // bool ok = GetVarCoordVars(varname, false, scvars); if (!ok) return (ok); // Split out time and space coord vars // if (IsTimeVarying(varname)) { VAssert(scvars.size()); tcvar = scvars.back(); scvars.pop_back(); } return (true); } bool DataMgr::_get_coord_vars(string varname, vector &scvarsinfo, DC::CoordVar &tcvarinfo) const { scvarsinfo.clear(); vector scvarnames; string tcvarname; bool ok = _get_coord_vars(varname, scvarnames, tcvarname); if (!ok) return (ok); for (int i = 0; i < scvarnames.size(); i++) { DC::CoordVar cvarinfo; bool ok = GetCoordVarInfo(scvarnames[i], cvarinfo); if (!ok) return (ok); scvarsinfo.push_back(cvarinfo); } if (!tcvarname.empty()) { bool ok = GetCoordVarInfo(tcvarname, tcvarinfo); if (!ok) return (ok); } return (true); } int DataMgr::_initTimeCoord() { _timeCoordinates.clear(); // A data collection can have multiple time variables, but // the DataMgr currently can only handle one. If there are // multiple time coordinate variables figure out how many // are actually in use. // vector vars; for (auto varName : _dc->GetTimeCoordVarNames()) { if (_isCoordVarInUse(varName)) { vars.push_back(varName); } } if (vars.size() > 1) { SetErrMsg("Data set contains more than one time coordinate"); return (-1); } if (vars.size() == 0) { // No time coordinates present // _timeCoordinates.push_back(0.0); return (0); } string nativeTimeCoordName = vars[0]; size_t numTS = _dc->GetNumTimeSteps(nativeTimeCoordName); // If we have a time unit expressed as: // // ( since YYYY-MM-DD hh:mm:ss ) // // as supported by the UDUNITS2 package, try to convert to seconds from // EPOCH. N.B. unforunately the UDUNITS API does not provide an interaface // for programatically detecting a formatted time string. So we simply // look for the keyword "since" :-( // VAPoR::DC::CoordVar cvar; _dc->GetCoordVarInfo(nativeTimeCoordName, cvar); if (_udunits.IsTimeUnit(cvar.GetUnits()) && STLUtils::ContainsIgnoreCase(cvar.GetUnits(), "since")) { string derivedTimeCoordName = nativeTimeCoordName; DerivedCoordVar_TimeInSeconds *derivedVar = new DerivedCoordVar_TimeInSeconds(derivedTimeCoordName, _dc, nativeTimeCoordName, cvar.GetTimeDimName()); int rc = derivedVar->Initialize(); if (rc < 0) { SetErrMsg("Failed to initialize derived coord variable"); return (-1); } _dvm.AddCoordVar(derivedVar); _timeCoordinates = derivedVar->GetTimes(); } else { double *buf = new double[numTS]; int rc = _getVar(nativeTimeCoordName, -1, -1, buf); if (rc < 0) { return (-1); } for (int j = 0; j < numTS; j++) { _timeCoordinates.push_back(buf[j]); } delete[] buf; } return (0); } void DataMgr::_ugrid_setup(const DC::DataVar &var, DimsType &vertexDims, DimsType &faceDims, DimsType &edgeDims, UnstructuredGrid::Location &location, // node,face, edge size_t &maxVertexPerFace, size_t &maxFacePerVertex, long &vertexOffset, long &faceOffset, long ts) const { vertexDims = {1, 1, 1}; faceDims = {1, 1, 1}; edgeDims = {1, 1, 1}; DC::Mesh m; bool status = GetMesh(var.GetMeshName(), m); VAssert(status); DC::Dimension dimension; size_t layers_dimlen = 0; if (m.GetMeshType() == DC::Mesh::UNSTRUC_LAYERED) { string dimname = m.GetLayersDimName(); VAssert(!dimname.empty()); status = _dc->GetDimension(dimname, dimension, ts); VAssert(status); layers_dimlen = dimension.GetLength(); } string dimname = m.GetNodeDimName(); status = _dc->GetDimension(dimname, dimension, ts); VAssert(status); vertexDims[0] = dimension.GetLength(); if (layers_dimlen) { vertexDims[1] = (layers_dimlen); } dimname = m.GetFaceDimName(); if (!dimname.empty()) { status = _dc->GetDimension(dimname, dimension, ts); VAssert(status); faceDims[0] = (dimension.GetLength()); if (layers_dimlen) { faceDims[1] = (layers_dimlen - 1); } } else VAssert(!"FaceDim Required"); dimname = m.GetEdgeDimName(); if (dimname.size()) { status = _dc->GetDimension(dimname, dimension, ts); VAssert(status); edgeDims[0] = (dimension.GetLength()); if (layers_dimlen) { edgeDims[1] = (layers_dimlen - 1); } } DC::Mesh::Location l = var.GetSamplingLocation(); if (l == DC::Mesh::NODE) { location = UnstructuredGrid::NODE; } else if (l == DC::Mesh::EDGE) { location = UnstructuredGrid::EDGE; } else if (l == DC::Mesh::FACE) { location = UnstructuredGrid::CELL; } else if (l == DC::Mesh::VOLUME) { location = UnstructuredGrid::CELL; } maxVertexPerFace = m.GetMaxNodesPerFace(); maxFacePerVertex = m.GetMaxFacesPerNode(); string face_node_var; string node_face_var; string dummy; bool ok = _getVarConnVars(var.GetName(), face_node_var, node_face_var, dummy, dummy, dummy, dummy); VAssert(ok); DC::AuxVar auxvar; if (!face_node_var.empty()) { status = _dc->GetAuxVarInfo(face_node_var, auxvar); VAssert(status); vertexOffset = auxvar.GetOffset(); } else { VAssert(!"FaceNodeVar Required"); vertexOffset = 0; } if (!node_face_var.empty()) { status = _dc->GetAuxVarInfo(node_face_var, auxvar); VAssert(status); faceOffset = auxvar.GetOffset(); } } string DataMgr::_get_grid_type(string varname) const { vector cvarsinfo; DC::CoordVar dummy; bool ok = _get_coord_vars(varname, cvarsinfo, dummy); if (!ok) return (""); vector> cdimnames; for (int i = 0; i < cvarsinfo.size(); i++) { vector v; bool ok = _getVarDimNames(cvarsinfo[i].GetName(), v); if (!ok) return (""); cdimnames.push_back(v); } DC::DataVar dvar; ok = GetDataVarInfo(varname, dvar); VAssert(ok); DC::Mesh m; ok = GetMesh(dvar.GetMeshName(), m); VAssert(ok); return (_gridHelper.GetGridType(m, cvarsinfo, cdimnames)); } // Find the grid coordinates, in voxels, for the region containing // the axis aligned bounding box specified by min and max // int DataMgr::_find_bounding_grid(size_t ts, string varname, int level, int lod, CoordType min, CoordType max, DimsType &min_ui, DimsType &max_ui) { min_ui = {0, 0, 0}; max_ui = {0, 0, 0}; vector scvars; string tcvar; bool ok = _get_coord_vars(varname, scvars, tcvar); if (!ok) return (-1); size_t hash_ts = 0; for (int i = 0; i < scvars.size(); i++) { if (IsTimeVarying(scvars[i])) hash_ts = ts; } vector dims_at_level; int rc = GetDimLensAtLevel(varname, level, dims_at_level, ts); if (rc < 0) { SetErrMsg("Invalid variable reference : %s", varname.c_str()); return (-1); } // Currently unstructured grids can not be subset. We always need // to read the entire data set. // if (_gridHelper.IsUnstructured(_get_grid_type(varname))) { for (int i = 0; i < dims_at_level.size(); i++) { min_ui[i] = 0; max_ui[i] = dims_at_level[i] - 1; } return (0); } DimsType bs = {1, 1, 1}; for (int i = 0; i < dims_at_level.size(); i++) { bs[i] = _bs[i]; } // hash tag for block coordinate cache // string hash = VarInfoCache::_make_hash("BlkExts", hash_ts, scvars, level, lod); // See if bounding volumes for individual blocks are already // cached for this grid // map::iterator itr = _blkExtsCache.find(hash); if (itr == _blkExtsCache.end()) { SetDiagMsg("DataMgr::_find_bounding_grid() - coordinates not in cache"); // Get a "dataless" Grid - a Grid class the contains // coordiante information, but not data // Grid *rg = _getVariable(ts, varname, level, lod, false, true); if (!rg) return (-1); // Voxel and block min and max coordinates of entire grid // DimsType vmin = {0, 0, 0}; DimsType vmax = {0, 0, 0}; DimsType bmin = {0, 0, 0}; DimsType bmax = {0, 0, 0}; for (int i = 0; i < dims_at_level.size(); i++) { vmin[i] = 0; vmax[i] = (dims_at_level[i] - 1); } map_vox_to_blk(bs, vmin, bmin); map_vox_to_blk(bs, vmax, bmax); BlkExts blkexts(bmin, bmax); // For each block in the grid compute the block's bounding // box. Include a one-voxel halo region on all non-boundary // faces // size_t nblocks = Wasp::LinearizeCoords(bmax.data(), bmin.data(), bmax.data(), bmax.size()) + 1; for (size_t offset = 0; offset < nblocks; offset++) { CoordType my_min, my_max; DimsType my_vmin, my_vmax; // Get coordinates for current block // DimsType bcoord = {0, 0, 0}; Wasp::VectorizeCoords(offset, bmin.data(), bmax.data(), bcoord.data(), bmin.size()); for (int i = 0; i < bcoord.size(); i++) { my_vmin[i] = bcoord[i] * bs[i]; if (my_vmin[i] > 0) my_vmin[i] -= 1; // not boundary face my_vmax[i] = bcoord[i] * bs[i] + bs[i] - 1; if (my_vmax[i] > vmax[i]) my_vmax[i] = vmax[i]; if (my_vmax[i] < vmax[i]) my_vmax[i] += 1; } // Use the regular grid class to compute the user-coordinate // axis aligned bounding volume for the block+halo // rg->GetBoundingBox(my_vmin, my_vmax, my_min, my_max); // Insert the bounding volume into blkexts // blkexts.Insert(bcoord, my_min, my_max); } // Add to the hash table // _blkExtsCache[hash] = blkexts; itr = _blkExtsCache.find(hash); VAssert(itr != _blkExtsCache.end()); } else { SetDiagMsg("DataMgr::_find_bounding_grid() - coordinates in cache"); } const BlkExts &blkexts = itr->second; // Find block coordinates of region that contains the bounding volume // DimsType bmin, bmax; ok = blkexts.Intersect(min, max, bmin, bmax, GetVarGeometryDim(varname)); if (!ok) { return (1); } // Finally, map from block to voxel coordinates // map_blk_to_vox(bs, bmin, bmax, min_ui, max_ui); for (int i = 0; i < dims_at_level.size(); i++) { if (max_ui[i] >= dims_at_level[i]) { max_ui[i] = dims_at_level[i] - 1; } } return (0); } void DataMgr::_unlock_blocks(const void *blks) { list::iterator itr; for (itr = _regionsList.begin(); itr != _regionsList.end(); itr++) { region_t ®ion = *itr; if (region.blks == blks && region.lock_counter > 0) { region.lock_counter--; return; } } return; } vector DataMgr::_getDataVarNamesDerived(int ndim) const { vector names; vector allnames = _dvm.GetDataVarNames(); ; for (int i = 0; i < allnames.size(); i++) { string name = allnames[i]; DC::DataVar dvar; bool ok = GetDataVarInfo(name, dvar); if (!ok) continue; string mesh_name; mesh_name = dvar.GetMeshName(); DC::Mesh mesh; ok = GetMesh(mesh_name, mesh); if (!ok) continue; size_t d = mesh.GetTopologyDim(); if (d == ndim) { names.push_back(name); } } return (names); } bool DataMgr::_hasCoordForAxis(vector coord_vars, int axis) const { for (int i = 0; i < coord_vars.size(); i++) { DC::CoordVar varInfo; bool ok = GetCoordVarInfo(coord_vars[i], varInfo); if (!ok) continue; if (varInfo.GetAxis() == axis) return (true); } return (false); } string DataMgr::_defaultCoordVar(const DC::Mesh &m, int axis) const { VAssert(axis >= 0 && axis <= 2); // For a structured mesh use the coresponding dimension name // as the coordinate variable name. For unstructured nothing // we can do // if (m.GetMeshType() == DC::Mesh::STRUCTURED) { VAssert(m.GetDimNames().size() >= axis); return (m.GetDimNames()[axis]); } else { return (""); } } void DataMgr::_assignHorizontalCoords(vector &coord_vars) const { for (int i = 0; i < coord_vars.size(); i++) { DC::CoordVar varInfo; bool ok = GetCoordVarInfo(coord_vars[i], varInfo); VAssert(ok); if (_udunits.IsLonUnit(varInfo.GetUnits())) { coord_vars[i] = coord_vars[i] + "X"; } if (_udunits.IsLatUnit(varInfo.GetUnits())) { coord_vars[i] = coord_vars[i] + "Y"; } } } bool DataMgr::_getVarDimensions(string varname, vector &dimensions, long ts) const { dimensions.clear(); if (!IsVariableDerived(varname)) { return (_dc->GetVarDimensions(varname, true, dimensions, ts)); } if (_getDerivedDataVar(varname)) { return (_getDataVarDimensions(varname, dimensions, ts)); } else if (_getDerivedCoordVar(varname)) { return (_getCoordVarDimensions(varname, dimensions, ts)); } else { return (false); } } bool DataMgr::_getDataVarDimensions(string varname, vector &dimensions, long ts) const { dimensions.clear(); DC::DataVar var; bool status = GetDataVarInfo(varname, var); if (!status) return (false); string mname = var.GetMeshName(); DC::Mesh mesh; status = GetMesh(mname, mesh); if (!status) return (false); vector dimnames; if (mesh.GetMeshType() == DC::Mesh::STRUCTURED) { dimnames = mesh.GetDimNames(); } else { switch (var.GetSamplingLocation()) { case DC::Mesh::NODE: dimnames.push_back(mesh.GetNodeDimName()); break; case DC::Mesh::EDGE: dimnames.push_back(mesh.GetEdgeDimName()); break; case DC::Mesh::FACE: dimnames.push_back(mesh.GetFaceDimName()); break; case DC::Mesh::VOLUME: VAssert(0 && "VOLUME cells not supported"); break; } if (mesh.GetMeshType() == DC::Mesh::UNSTRUC_LAYERED) { dimnames.push_back(mesh.GetLayersDimName()); } } for (int i = 0; i < dimnames.size(); i++) { DC::Dimension dim; status = _dc->GetDimension(dimnames[i], dim, ts); if (!status) return (false); dimensions.push_back(dim); } return (true); } bool DataMgr::_getCoordVarDimensions(string varname, vector &dimensions, long ts) const { dimensions.clear(); DC::CoordVar var; bool status = GetCoordVarInfo(varname, var); if (!status) return (false); vector dimnames = var.GetDimNames(); for (int i = 0; i < dimnames.size(); i++) { DC::Dimension dim; status = _dc->GetDimension(dimnames[i], dim, ts); if (!status) return (false); dimensions.push_back(dim); } return (true); } bool DataMgr::_getVarDimNames(string varname, vector &dimnames) const { dimnames.clear(); vector dims; bool status = _getVarDimensions(varname, dims, 0); if (!status) return (status); for (int i = 0; i < dims.size(); i++) { dimnames.push_back(dims[i].GetName()); } return (true); } bool DataMgr::_getVarConnVars(string varname, string &face_node_var, string &node_face_var, string &face_edge_var, string &face_face_var, string &edge_node_var, string &edge_face_var) const { face_node_var.clear(); node_face_var.clear(); face_edge_var.clear(); face_face_var.clear(); edge_node_var.clear(); edge_face_var.clear(); DC::DataVar dvar; bool status = GetDataVarInfo(varname, dvar); if (!status) return (false); DC::Mesh m; status = GetMesh(dvar.GetMeshName(), m); if (!status) return (false); face_node_var = m.GetFaceNodeVar(); node_face_var = m.GetNodeFaceVar(); face_edge_var = m.GetFaceEdgeVar(); face_face_var = m.GetFaceFaceVar(); edge_node_var = m.GetEdgeNodeVar(); edge_face_var = m.GetEdgeFaceVar(); return (true); } DerivedVar *DataMgr::_getDerivedVar(string varname) const { DerivedVar *dvar; dvar = _getDerivedDataVar(varname); if (dvar) return (dvar); dvar = _getDerivedCoordVar(varname); if (dvar) return (dvar); return (NULL); } DerivedDataVar *DataMgr::_getDerivedDataVar(string varname) const { vector varnames = _dvm.GetDataVarNames(); if (find(varnames.begin(), varnames.end(), varname) != varnames.end()) { return (dynamic_cast(_dvm.GetVar(varname))); } return (NULL); } DerivedCoordVar *DataMgr::_getDerivedCoordVar(string varname) const { vector varnames = _dvm.GetCoordVarNames(); if (find(varnames.begin(), varnames.end(), varname) != varnames.end()) { return (dynamic_cast(_dvm.GetVar(varname))); } return (NULL); } int DataMgr::_openVariableRead(size_t ts, string varname, int level, int lod) { _openVarName = varname; DerivedVar *derivedVar = _getDerivedVar(_openVarName); if (derivedVar) { return (derivedVar->OpenVariableRead(ts, level, lod)); } return (_dc->OpenVariableRead(ts, _openVarName, level, lod)); } template int DataMgr::_readRegion(int fd, const DimsType &min, const DimsType &max, size_t ndims, T *region) { vector minv, maxv; Grid::CopyFromArr3(min, minv); minv.resize(ndims); Grid::CopyFromArr3(max, maxv); maxv.resize(ndims); int rc = 0; DerivedVar *derivedVar = _getDerivedVar(_openVarName); if (derivedVar) { VAssert((std::is_same::value) == true); rc = derivedVar->ReadRegion(fd, minv, maxv, (float *)region); } else { rc = _dc->ReadRegion(fd, minv, maxv, region); } _sanitizeFloats(region, vproduct(box_dims(min, max))); return (rc); } int DataMgr::_closeVariable(int fd) { DerivedVar *derivedVar = _getDerivedVar(_openVarName); if (derivedVar) { return (derivedVar->CloseVariable(fd)); } _openVarName.clear(); return (_dc->CloseVariable(fd)); } template int DataMgr::_getVar(string varname, int level, int lod, T *data) { vector dims_at_level, dummy; size_t numts = _dc->GetNumTimeSteps(varname); T *ptr = data; for (size_t ts = 0; ts < numts; ts++) { int rc = _dc->GetDimLensAtLevel(varname, level, dims_at_level, dummy, ts); if (rc < 0) return (-1); size_t var_size = 1; for (int i = 0; i < dims_at_level.size(); i++) { var_size *= dims_at_level[i]; } rc = _getVar(ts, varname, level, lod, ptr); if (rc < 0) return (-1); ptr += var_size; } return (0); } template int DataMgr::_getVar(size_t ts, string varname, int level, int lod, T *data) { vector dims_at_level, dummy; int rc = _dc->GetDimLensAtLevel(varname, level, dims_at_level, dummy, ts); if (rc < 0) return (-1); vector min, max; for (int i = 0; i < dims_at_level.size(); i++) { min.push_back(0); max.push_back(dims_at_level[i] - 1); } int fd = _dc->OpenVariableRead(ts, varname, level, lod); if (fd < 0) return (-1); rc = _dc->ReadRegion(fd, min, max, data); if (rc < 0) return (-1); rc = _dc->CloseVariable(fd); if (rc < 0) return (-1); return (0); } void DataMgr::_getLonExtents(vector &lons, DimsType dims, float &min, float &max) const { min = max = 0.0; if (!lons.size()) return; auto minmaxitr = std::minmax_element(lons.begin(), lons.end()); min = *(minmaxitr.first); max = *(minmaxitr.second); } void DataMgr::_getLatExtents(vector &lats, DimsType dims, float &min, float &max) const { min = max = 0.0; if (!lats.size()) return; auto minmaxitr = std::minmax_element(lats.begin(), lats.end()); min = *(minmaxitr.first); max = *(minmaxitr.second); } int DataMgr::_getCoordPairExtents(string lon, string lat, float &lonmin, float &lonmax, float &latmin, float &latmax, long ts) { lonmin = lonmax = latmin = latmax = 0.0; vector dimsv, dummy; int rc = _dc->GetDimLensAtLevel(lon, 0, dimsv, dummy, ts); if (rc < 0) { SetErrMsg("Invalid variable reference : %s", lon.c_str()); return (-1); } if (!(dimsv.size() == 1 || dimsv.size() == 2)) { SetErrMsg("Unsupported variable dimension for variable \"%s\"", lon.c_str()); return (-1); } DimsType dims = {1, 1, 1}; Grid::CopyToArr3(dimsv, dims); vector buf(VProduct(dimsv)); rc = _getVar(0, lon, 0, 0, buf.data()); if (rc < 0) return (-1); _getLonExtents(buf, dims, lonmin, lonmax); rc = _dc->GetDimLensAtLevel(lat, 0, dimsv, dummy, ts); if (rc < 0) { SetErrMsg("Invalid variable reference : %s", lat.c_str()); return (-1); } if (!(dimsv.size() == 1 || dimsv.size() == 2)) { SetErrMsg("Unsupported variable dimension for variable \"%s\"", lat.c_str()); return (-1); } dims = {1, 1, 1}; Grid::CopyToArr3(dimsv, dims); buf.resize(vproduct(dims)); rc = _getVar(0, lat, 0, 0, buf.data()); if (rc < 0) return (-1); _getLatExtents(buf, dims, latmin, latmax); return (0); } int DataMgr::_initProj4StringDefault() { // If data set has a map projection use it // _proj4StringDefault = _dc->GetMapProjection(); if (!_proj4StringDefault.empty()) { return (0); } // Generate our own proj4 string // vector meshnames = _dc->GetMeshNames(); if (meshnames.empty()) return (0); vector coordvars; for (int i = 0; i < meshnames.size() && coordvars.size() < 2; i++) { if (!_hasHorizontalXForm(meshnames[i])) continue; DC::Mesh m; bool ok = _dc->GetMesh(meshnames[i], m); if (!ok) continue; if (m.GetCoordVars().size() < 2) continue; coordvars = m.GetCoordVars(); } if (coordvars.empty()) return (0); float lonmin, lonmax, latmin, latmax; int rc = _getCoordPairExtents(coordvars[0], coordvars[1], lonmin, lonmax, latmin, latmax, 0); if (rc < 0) return (-1); float lon_0 = (lonmin + lonmax) / 2.0; float lat_0 = (latmin + latmax) / 2.0; ostringstream oss; oss << " +lon_0=" << lon_0 << " +lat_0=" << lat_0; _proj4StringDefault = "+proj=eqc +ellps=WGS84" + oss.str(); return (0); } int DataMgr::_initHorizontalCoordVars() { if (!_doTransformHorizontal) return (0); if (!_hasHorizontalXForm()) return (0); int rc = _initProj4StringDefault(); if (rc < 0) return (-1); // Already initialized via Initialize() options // if (_proj4String.empty()) { _proj4String = _proj4StringDefault; } vector meshnames = _dc->GetMeshNames(); vector coordvars; for (int i = 0; i < meshnames.size(); i++) { if (!_hasHorizontalXForm(meshnames[i])) continue; DC::Mesh m; bool ok = _dc->GetMesh(meshnames[i], m); if (!ok) continue; if (m.GetCoordVars().size() < 2) continue; coordvars = m.GetCoordVars(); while (coordvars.size() > 2) { coordvars.pop_back(); } vector derivedCoordvars = coordvars; _assignHorizontalCoords(derivedCoordvars); // no duplicates // if (!_getDerivedCoordVar(derivedCoordvars[0])) { DerivedCoordVar_PCSFromLatLon *derivedVar = new DerivedCoordVar_PCSFromLatLon(derivedCoordvars[0], _dc, coordvars, _proj4String, m.GetMeshType() != DC::Mesh::STRUCTURED, true); rc = derivedVar->Initialize(); if (rc < 0) { SetErrMsg("Failed to initialize derived coord variable"); return (-1); } _dvm.AddCoordVar(derivedVar); } if (!_getDerivedCoordVar(derivedCoordvars[1])) { DerivedCoordVar_PCSFromLatLon *derivedVar = new DerivedCoordVar_PCSFromLatLon(derivedCoordvars[1], _dc, coordvars, _proj4String, m.GetMeshType() != DC::Mesh::STRUCTURED, false); rc = derivedVar->Initialize(); if (rc < 0) { SetErrMsg("Failed to initialize derived coord variable"); return (-1); } _dvm.AddCoordVar(derivedVar); } } return (0); } int DataMgr::_initVerticalCoordVars() { if (!_doTransformVertical) return (0); if (!_hasVerticalXForm()) return (0); vector meshnames = _dc->GetMeshNames(); vector coordvars; for (int i = 0; i < meshnames.size(); i++) { string standard_name, formula_terms; if (!_hasVerticalXForm(meshnames[i], standard_name, formula_terms)) { continue; } DC::Mesh m; bool ok = _dc->GetMesh(meshnames[i], m); if (!ok) continue; VAssert(m.GetCoordVars().size() > 2); DerivedCoordVar *derivedVar = NULL; derivedVar = DerivedCFVertCoordVarFactory::Instance()->CreateInstance(standard_name, _dc, meshnames[i], formula_terms); if (!derivedVar) { SetErrMsg("Failed to initialize derived coord variable"); return (-1); } int rc = derivedVar->Initialize(); if (rc < 0) { SetErrMsg("Failed to initialize derived coord variable"); return (-1); } _dvm.AddCoordVar(derivedVar); vector coord_vars = m.GetCoordVars(); coord_vars[2] = derivedVar->GetName(); m.SetCoordVars(coord_vars); _dvm.AddMesh(m); } return (0); } namespace VAPoR { std::ostream &operator<<(std::ostream &o, const DataMgr::BlkExts &b) { VAssert(b._bmin.size() == b._bmax.size()); VAssert(b._mins.size() == b._maxs.size()); o << "Block dimensions" << endl; for (int i = 0; i < b._bmin.size(); i++) { o << " " << b._bmin[i] << " " << b._bmax[i] << endl; } o << "Block coordinates" << endl; for (int i = 0; i < b._mins.size(); i++) { VAssert(b._mins[i].size() == b._maxs[i].size()); o << "Block index " << i << endl; for (int j = 0; j < b._mins[i].size(); j++) { o << " " << b._mins[i][j] << " " << b._maxs[i][j] << endl; } o << endl; } return (o); } }; // namespace VAPoR ================================================ FILE: lib/vdc/DataMgrUtils.cpp ================================================ //************************************************************************ // * // Copyright (C) 2017 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: DataMgrUtils.cpp // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: June 2017 // // Description: Implements the DataMgrUtils free functions // #ifdef WIN32 #pragma warning(disable : 4251 4100) #endif #include #include "vapor/VAssert.h" #include #include #include #include #include #include #include using namespace VAPoR; using namespace Wasp; bool DataMgrUtils::MaxXFormPresent(const DataMgr *dataMgr, size_t timestep, string varname, size_t &maxXForm) { size_t maxx = dataMgr->GetNumRefLevels(varname); maxXForm = 0; for (; maxXForm < maxx; maxXForm++) { if (!dataMgr->VariableExists(timestep, varname, maxXForm)) break; } if (maxXForm == 0) return false; maxXForm -= 1; return true; } bool DataMgrUtils::MaxLODPresent(const DataMgr *dataMgr, size_t timestep, string varname, size_t &maxLOD) { maxLOD = 0; vector cratios = dataMgr->GetCRatios(varname); VAssert(cratios.size() > 0); for (maxLOD = 0; maxLOD < cratios.size(); maxLOD++) { if (!dataMgr->VariableExists(timestep, varname, 0, maxLOD)) break; } if (maxLOD == 0) return false; maxLOD -= 1; return true; } int DataMgrUtils::ConvertPCSToLonLat(const DataMgr *dataMgr, double coords[2], int npoints) { // Set up proj.4 to convert to latlon string pstring = dataMgr->GetMapProjection(); if (pstring.size() == 0) return 0; return ConvertPCSToLonLat(pstring, coords, npoints); } int DataMgrUtils::ConvertPCSToLonLat(string pstring, double coords[2], int npoints) { if (pstring.size() == 0) return 0; Proj4API proj4API; int rc = proj4API.Initialize(pstring, ""); if (rc < 0) return (rc); rc = proj4API.Transform(coords, coords + 1, npoints, 2); if (rc < 0) return (rc); return 0; } int DataMgrUtils::ConvertLonLatToPCS(const DataMgr *dataMgr, double coords[2], int npoints) { // Set up proj.4 to convert from LatLon to VDC coords string projString = dataMgr->GetMapProjection(); if (projString.size() == 0) return (0); return ConvertLonLatToPCS(projString, coords, npoints); } int DataMgrUtils::ConvertLonLatToPCS(string projString, double coords[2], int npoints) { Proj4API proj4API; int rc = proj4API.Initialize("", projString); if (rc < 0) return (rc); rc = proj4API.Transform(coords, coords + 1, npoints, 2); if (rc < 0) return (rc); return 0; } template int DataMgrUtils::GetGrids(DataMgr *dataMgr, size_t ts, const vector &varnames, const T &minExtsReq, const T &maxExtsReq, bool useLowerAccuracy, int *refLevel, int *lod, vector &grids, bool lock) { grids.clear(); VAssert(minExtsReq.size() == maxExtsReq.size()); for (int i = 0; i < varnames.size(); i++) grids.push_back(NULL); // First, find an lod and a refinement level that will work with // all variables. // int tempRefLevel = *refLevel; int tempLOD = *lod; for (int i = 0; i < varnames.size(); i++) { if (varnames[i].empty()) continue; size_t maxRefLevel; bool status = MaxXFormPresent(dataMgr, ts, varnames[i], maxRefLevel); if (!status) { MyBase::SetErrMsg("Variable not present at required refinement and LOD"); return -1; } tempRefLevel = std::min((int)maxRefLevel, tempRefLevel); size_t maxLOD; status = MaxLODPresent(dataMgr, ts, varnames[i], maxLOD); if (!status) { MyBase::SetErrMsg("Variable not present at required refinement and LOD"); return -1; } tempLOD = std::min((int)maxLOD, tempLOD); } if (useLowerAccuracy) { *lod = tempLOD; *refLevel = tempRefLevel; } else { if (tempRefLevel < *refLevel || tempLOD < *lod) { MyBase::SetErrMsg("Variable not present at required refinement and LOD"); return -1; } } // Now obtain a regular grid for each valid variable // for (int i = 0; i < varnames.size(); i++) { if (varnames[i].empty()) continue; Grid *rGrid = dataMgr->GetVariable(ts, varnames[i], *refLevel, *lod, minExtsReq, maxExtsReq, true); if (!rGrid) { for (int j = 0; j < i; j++) { if (grids[j]) dataMgr->UnlockGrid(grids[j]); } MyBase::SetErrMsg("Error retrieving variable data"); return -1; } grids[i] = rGrid; } if (!lock) { for (auto g : grids) { if (g) dataMgr->UnlockGrid(g); } } // obtained all of the grids needed return 0; } template VDF_API int DataMgrUtils::GetGrids(DataMgr *dataMgr, size_t ts, const vector &varnames, const CoordType &minExtsReq, const CoordType &maxExtsReq, bool useLowerAccuracy, int *refLevel, int *lod, vector &grids, bool lock); template VDF_API int DataMgrUtils::GetGrids(DataMgr *dataMgr, size_t ts, const vector &varnames, const DimsType &minExtsReq, const DimsType &maxExtsReq, bool useLowerAccuracy, int *refLevel, int *lod, vector &grids, bool lock); int DataMgrUtils::GetGrids(DataMgr *dataMgr, size_t ts, string varname, const CoordType &minExtsReq, const CoordType &maxExtsReq, bool useLowerAccuracy, int *refLevel, int *lod, Grid **gridptr, bool lock) { *gridptr = NULL; if (varname == "") { MyBase::SetErrMsg("Cannot get grid for variable \"\""); return -1; } vector varnames; varnames.push_back(varname); vector grids; int rc = GetGrids(dataMgr, ts, varnames, minExtsReq, maxExtsReq, useLowerAccuracy, refLevel, lod, grids, lock); if (rc < 0) return (rc); *gridptr = grids[0]; return (0); } int DataMgrUtils::GetGrids(DataMgr *dataMgr, size_t ts, const vector &varnames, bool useLowerAccuracy, int *refLevel, int *lod, vector &grids, bool lock) { grids.clear(); CoordType minExtsReq, maxExtsReq; for (int i = 0; i < 3; i++) { minExtsReq[i] = (std::numeric_limits::lowest()); } for (int i = 0; i < 3; i++) { maxExtsReq[i] = (std::numeric_limits::max()); } return (DataMgrUtils::GetGrids(dataMgr, ts, varnames, minExtsReq, maxExtsReq, useLowerAccuracy, refLevel, lod, grids, lock)); } int DataMgrUtils::GetGrids(DataMgr *dataMgr, size_t ts, string varname, bool useLowerAccuracy, int *refLevel, int *lod, Grid **gridptr, bool lock) { *gridptr = NULL; vector varnames; varnames.push_back(varname); vector grids; int rc = GetGrids(dataMgr, ts, varnames, useLowerAccuracy, refLevel, lod, grids, lock); if (rc < 0) return (rc); *gridptr = grids[0]; return (0); } void DataMgrUtils::UnlockGrids(DataMgr *dataMgr, const std::vector &grids) { for (int i = 0; i < grids.size(); i++) { dataMgr->UnlockGrid(grids[i]); } } bool DataMgrUtils::GetAxes(const DataMgr *dataMgr, string varname, vector &axes) { axes.clear(); vector coordvars; bool status = dataMgr->GetVarCoordVars(varname, true, coordvars); if (!status) return (status); for (int i = 0; i < coordvars.size(); i++) { VAPoR::DC::CoordVar cvar; status = dataMgr->GetCoordVarInfo(coordvars[i], cvar); VAssert(status); axes.push_back(cvar.GetAxis()); } return (true); } bool DataMgrUtils::GetExtents(DataMgr *dataMgr, size_t timestep, string varname, int refLevel, int lod, CoordType &minExts, CoordType &maxExts) { minExts = {0.0, 0.0, 0.0}; maxExts = {0.0, 0.0, 0.0}; // If varname not specified look for first variable of highest // dimensionality // if (varname.empty()) { for (int ndim = 3; ndim > 0; ndim--) { bool ok = DataMgrUtils::GetFirstExistingVariable(dataMgr, timestep, refLevel, lod, ndim, varname); if (ok) break; } } if (varname.empty()) return (false); if (refLevel == -1) { size_t maxXForm; bool status = DataMgrUtils::MaxXFormPresent(dataMgr, timestep, varname, maxXForm); if (!status) return (status); refLevel = (int)maxXForm; } bool errEnabled = MyBase::EnableErrMsg(false); int rc = dataMgr->GetVariableExtents(timestep, varname, refLevel, lod, minExts, maxExts); MyBase::EnableErrMsg(errEnabled); if (rc < 0) return (false); return (true); } bool DataMgrUtils::GetExtents(DataMgr *dataMgr, size_t timestep, const vector &varnames, int refLevel, int lod, CoordType &minExts, CoordType &maxExts, vector &axes) { minExts = {0.0, 0.0, 0.0}; maxExts = {0.0, 0.0, 0.0}; axes.clear(); vector tmpMinExts(3, std::numeric_limits::max()); vector tmpMaxExts(3, std::numeric_limits::lowest()); // Get the coordinate extents of each variable. Grow the bounding // box to accomodate each new variable. Handle cases where variables // have different dimensionality, or, in 2D case, live in different // planes. // // Have to be careful // about what coordinate axis the coordinate extents apply to // for (int i = 0; i < varnames.size(); i++) { if (varnames[i] == "") { continue; } CoordType varMinExts = {0.0, 0.0, 0.0}; CoordType varMaxExts = {0.0, 0.0, 0.0}; vector varAxes; bool status = DataMgrUtils::GetExtents(dataMgr, timestep, varnames[i], refLevel, lod, varMinExts, varMaxExts); if (!status) continue; // Figure out which axes the variable coordinate extents // apply to. // status = DataMgrUtils::GetAxes(dataMgr, varnames[i], varAxes); VAssert(status); for (int j = 0; j < varAxes.size(); j++) { int axis = varAxes[j]; if (varMinExts[j] < tmpMinExts[axis]) { tmpMinExts[axis] = varMinExts[j]; } if (varMaxExts[j] > tmpMaxExts[axis]) { tmpMaxExts[axis] = varMaxExts[j]; } } } // tmp{Min,Max}Exts are always 3D vectors. // for (int i = 0; i < tmpMinExts.size(); i++) { if (tmpMinExts[i] != std::numeric_limits::max()) { minExts[i] = (tmpMinExts[i]); maxExts[i] = (tmpMaxExts[i]); axes.push_back(i); } } return (true); } // This is an arbitrary number and method for determening a default that I just moved from elsewhere #define REQUIRED_SAMPLE_SIZE 1000000 int DataMgrUtils::GetDefaultMetaInfoStride(DataMgr *dataMgr, std::string varname, int refinementLevel) { std::vector dimsAtLevel; int rc = dataMgr->GetDimLensAtLevel(varname, refinementLevel, dimsAtLevel, 0); VAssert(rc >= 0); long size = 1; for (int i = 0; i < dimsAtLevel.size(); i++) size *= dimsAtLevel[i]; int stride = 1; if (size > REQUIRED_SAMPLE_SIZE) stride = 1 + size / REQUIRED_SAMPLE_SIZE; return stride; } double DataMgrUtils::Get2DRendererDefaultZ(DataMgr *dataMgr, size_t ts, int refLevel, int lod) { CoordType minExts; CoordType maxExts; bool status = DataMgrUtils::GetExtents(dataMgr, ts, "", refLevel, lod, minExts, maxExts); if (!status) return (0.0); // Return whichever XY plane is closest to 0 meters (typically MSL) return (std::abs(minExts[2]) < std::abs(maxExts[2])) ? minExts[2] : maxExts[2]; } bool DataMgrUtils::GetFirstExistingVariable(DataMgr *dataMgr, int level, int lod, int ndim, string &varname, size_t &ts) { varname.clear(); size_t numTS = dataMgr->GetTimeCoordinates().size(); if (ts < 0 || ts >= numTS) ts = 0; std::vector timesteps(numTS); std::iota(timesteps.begin(), timesteps.end(), 0); std::sort(timesteps.begin(), timesteps.end(), [ts](size_t a, size_t b) { return abs((long)ts-(long)a) < abs((long)ts-(long)b); }); for (size_t l_ts : timesteps) { bool ok = GetFirstExistingVariable(dataMgr, l_ts, level, lod, ndim, varname); if (ok) { ts = l_ts; return (true); } } return (false); } bool DataMgrUtils::GetFirstExistingVariable(DataMgr *dataMgr, size_t ts, int level, int lod, int ndim, string &varname) { varname.clear(); vector varnames = dataMgr->GetDataVarNames(ndim); for (int i = 0; i < varnames.size(); i++) { if (dataMgr->VariableExists(ts, varnames[i], level, lod)) { varname = varnames[i]; return (true); } } return (false); } #ifdef VAPOR3_0_0_ALPHA // Map corners of box to voxels. void DataMgrUtils::mapBoxToVox(Box *box, string varname, int refLevel, int lod, int timestep, size_t voxExts[6]) { double userExts[6]; box->GetUserExtents(userExts, (size_t)timestep); vector minexts, maxexts; for (int i = 0; i < 3; i++) { minexts.push_back(userExts[i]); maxexts.push_back(userExts[i + 3]); } bool errEnabled = MyBase::EnableErrMsg(false); Grid *rg = dataMgr->GetVariable(timestep, varname, refLevel, lod, minexts, maxexts); MyBase::EnableErrMsg(errEnabled); if (rg) { rg->GetIJKIndex(minexts[0], minexts[1], minexts[2], voxExts, voxExts + 1, voxExts + 2); rg->GetIJKIndex(maxexts[0], maxexts[1], maxexts[2], voxExts + 3, voxExts + 4, voxExts + 5); } else { for (int i = 0; i < 6; i++) voxExts[i] = 0; } //(Note: this can be expensive with layered data) return; } double DataMgrUtils::getVoxelSize(size_t ts, string varname, int refLevel, int dir) { DataMgr *dataMgr = GetActiveDataMgr(); if (!dataMgr) { return (1.0); } // If refLevel is -1, use maximum refinement level // Obtain the variable at lowest refinement level, then convert to higher levels if needed // If dir is -1 get maximum side of voxel // If dir is -2 get minimum side of voxel Grid *rGrid = dataMgr->GetVariable(ts, varname, 0, 0); if (refLevel == -1) refLevel = dataMgr->GetNumRefLevels(varname) - 1; size_t dims[3]; rGrid->GetDimensions(dims); for (int i = 0; i < 3; i++) dims[i] *= 2 << refLevel; double extents[6]; rGrid->GetUserExtents(extents); int numdims = rGrid->GetRank(); if (numdims < dir) return 0.; if (dir >= 0) { double vsize = ((extents[dir + 3] - extents[dir]) / dims[dir]); return vsize; } else if (dir == -1) { // maximum size double maxsize = -1.; for (int i = 0; i < numdims; i++) { double vsize = ((extents[dir + 3] - extents[dir]) / dims[dir]); if (vsize > maxsize) maxsize = vsize; } return maxsize; } else { // minimum size double minsize = DBL_MAX; for (int i = 0; i < numdims; i++) { double vsize = ((extents[dir + 3] - extents[dir]) / dims[dir]); if (vsize < minsize) minsize = vsize; } return minsize; } } #endif ================================================ FILE: lib/vdc/DerivedParticleDensity.cpp ================================================ #include #include #include #include #include using namespace VAPoR; using glm::ivec3; using glm::vec3; // =================================== // DerivedParticleDensity // =================================== DerivedParticleDensity::DerivedParticleDensity(string varName, DC *dc, string meshName, DataMgr *dataMgr) : DerivedDataVar(varName), _dc(dc), _meshName(meshName), _dataMgr(dataMgr) {} int DerivedParticleDensity::Initialize() { auto dataVarNames = _dataMgr->GetDataVarNames(3); string dataVar; for (auto dv : dataVarNames) { vector coordNames; _dataMgr->GetVarCoordVars(dv, true, coordNames); if (STLUtils::Contains(coordNames, string("Position_x")) && STLUtils::Contains(coordNames, string("Position_y")) && STLUtils::Contains(coordNames, string("Position_z"))) { dataVar = dv; break; } } if (dataVar.empty()) { assert(0); return -1; } _dataVar = dataVar; return 0; } int DerivedParticleDensity::OpenVariableRead(size_t ts, int level, int lod) { DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod); return _fileTable.AddEntry(f); } int DerivedParticleDensity::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return -1; } _fileTable.RemoveEntry(fd); delete f; return 0; } int DerivedParticleDensity::ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return -1; } vector dims; _dataMgr->GetDimLens(_derivedVarName, dims, f->GetTS()); if (dims.size() != 3) { assert(0); return -1; } Grid *g = _dataMgr->GetVariable(f->GetTS(), _dataVar, -1, -1, true); if (!g) { assert(0); return -1; } vector particleDims; _dataMgr->GetDimLens(_dataVar, particleDims, f->GetTS()); assert(particleDims.size() == 1); size_t realNP = particleDims[0]; int xd = dims[0], yd = dims[1], zd = dims[2]; float *data = new float[xd * yd * zd]; compute(g, data, xd, yd, zd, realNP); delete g; // assert(max[0]-min[0]+1 == xd); // assert(max[1]-min[1]+1 == yd); // assert(max[2]-min[2]+1 == zd); // for (int z = 0; z < zd; z++) // for (int y = 0; y < yd; y++) // for (int x = 0; x < xd; x++) // if (x > 10 && x < 20 && y > 10 && y < 20 && z > 10 && z < 20) // data[z*yd*xd + y*xd + x] = 1; // else // data[z*yd*xd + y*xd + x] = 0; int oxd = 1 + max[0] - min[0], oyd = 1 + max[1] - min[1], ozd = 1 + max[2] - min[2]; // printf("Read(%s, %s, %s)\n", C(_derivedVarName), C(min), C(max)); // Copy subvolume for (int z = 0; z < ozd; z++) for (int y = 0; y < oyd; y++) for (int x = 0; x < oxd; x++) region[z * oyd * oxd + y * oxd + x] = data[(min[2] + z) * yd * xd + (min[1] + y) * xd + (min[0] + x)]; // region[z*oyd*oxd + y*oxd + x] = y % 3 ? 0 : 1; // for (size_t i = 0; i < nbins; i++) // region[i] = data[i]; delete[] data; return 0; } void DerivedParticleDensity::compute(Grid *inGrid, float *output, int xd, int yd, int zd, size_t realNP) const { CoordType minud, maxud; inGrid->GetUserExtents(minud, maxud); vec3 minu(minud[0], minud[1], minud[2]); vec3 maxu(maxud[0], maxud[1], maxud[2]); vec3 diffu = maxu - minu; vec3 binDimsF(xd, yd, zd); ivec3 binDimsI(xd, yd, zd); size_t nbins = xd * yd * zd; size_t *bins = new size_t[nbins]; for (size_t i = 0; i < nbins; i++) bins[i] = 0; auto it = inGrid->ConstCoordBegin(); auto end = inGrid->ConstCoordEnd(); for (size_t j = 0; it != end && j < realNP; ++it, ++j) { vec3 c((*it)[0], (*it)[1], (*it)[2]); vec3 t = (c - minu) / diffu; ivec3 i = t * binDimsF; i = glm::clamp(i, ivec3(0), binDimsI - ivec3(1, 1, 1)); bins[i.z * yd * xd + i.y * xd + i.x]++; } for (size_t i = 0; i < nbins; i++) output[i] = bins[i]; delete[] bins; } int DerivedParticleDensity::GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); DC::Mesh mesh; _dataMgr->GetMesh(_meshName, mesh); DC::Dimension dim; for (auto dimName : mesh.GetDimNames()) { _dataMgr->GetDimension(dimName, dim, -1); dims_at_level.push_back(dim.GetLength()); } bs_at_level = vector(dims_at_level.size(), 1); return 0; } bool DerivedParticleDensity::VariableExists(size_t ts, int reflevel, int lod) const { return true; } bool DerivedParticleDensity::GetBaseVarInfo(DC::BaseVar &var) const { DC::DataVar dvar; GetDataVarInfo(dvar); var = dvar; return true; } bool DerivedParticleDensity::GetDataVarInfo(DC::DataVar &dvar) const { if (_dataVar.empty()) return false; dvar.SetName(_derivedVarName); dvar.SetMeshName(_meshName); dvar.SetUnits(""); dvar.SetXType(DC::FLOAT); dvar.SetWName(""); dvar.SetCRatios(vector()); dvar.SetPeriodic(vector(3, false)); // dvar.SetHasMissing(true); // dvar.SetMissingValue(-1); DC::DataVar dv; _dc->GetDataVarInfo(_dataVar, dv); dvar.SetTimeCoordVar(dv.GetTimeCoordVar()); return true; } vector DerivedParticleDensity::GetInputs() const { return {_dataVar}; } // =================================== // DerivedParticleAverage // =================================== DerivedParticleAverage::DerivedParticleAverage(string varName, DC *dc, string meshName, DataMgr *dataMgr, string inputVar) : DerivedParticleDensity(varName, dc, meshName, dataMgr) { _dataVar = inputVar; } void DerivedParticleAverage::compute(Grid *inGrid, float *output, int xd, int yd, int zd, size_t realNP) const { CoordType minud, maxud; inGrid->GetUserExtents(minud, maxud); vec3 minu(minud[0], minud[1], minud[2]); vec3 maxu(maxud[0], maxud[1], maxud[2]); vec3 diffu = maxu - minu; vec3 binDimsF(xd, yd, zd); ivec3 binDimsI(xd, yd, zd); size_t nbins = xd * yd * zd; size_t *bins = new size_t[nbins]; double *accum = new double[nbins]; for (size_t i = 0; i < nbins; i++) { bins[i] = 0; accum[i] = 0; } auto it = inGrid->ConstCoordBegin(); auto dit = inGrid->cbegin(); auto end = inGrid->ConstCoordEnd(); for (size_t j = 0; it != end && j < realNP; ++it, ++dit, ++j) { vec3 c((*it)[0], (*it)[1], (*it)[2]); vec3 t = (c - minu) / diffu; ivec3 i = t * binDimsF; i = glm::clamp(i, ivec3(0), binDimsI - ivec3(1, 1, 1)); size_t index = i.z * yd * xd + i.y * xd + i.x; bins[index]++; accum[index] += *dit; } for (size_t i = 0; i < nbins; i++) output[i] = accum[i] / (float)bins[i]; delete[] accum; delete[] bins; } // =================================== // DerivedCoordVar1DSpan // =================================== DerivedCoordVar1DSpan::DerivedCoordVar1DSpan(string derivedVarName, DC *dc, string dimName, int axis, string units, float minExt, float maxExt) : DerivedCoordVar_CF1D(derivedVarName, dc, dimName, axis, units), _dc(dc), _minExt(minExt), _maxExt(maxExt) { VAssert(maxExt >= minExt); } DerivedCoordVar1DSpan::DerivedCoordVar1DSpan(string derivedVarName, DC *dc, string dimName, int axis, string units, string inputCoordVar) : DerivedCoordVar1DSpan(derivedVarName, dc, dimName, axis, units, 0, 1) { _inputCoordVar = inputCoordVar; } int DerivedCoordVar1DSpan::ReadRegion(int fd, const std::vector &min, const std::vector &max, float *region) { VAssert(min.size() == 1); VAssert(max.size() == 1); long ts = -1; if (!_derivedVarName.empty()) { if (!_dc->IsCoordVar(_inputCoordVar)) { assert(0); return -1; } DC::CoordVar cvInfo; _dc->GetCoordVarInfo(_inputCoordVar, cvInfo); auto dims = cvInfo.GetDimNames(); if (dims.size() != 1) { assert(0); return -1; } DC::CoordVar myInfo; GetCoordVarInfo(myInfo); if (myInfo.GetAxis() != cvInfo.GetAxis()) { assert(0); return -1; } DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { assert(0); return -1; } DC::Dimension dim; _dc->GetDimension(dims[0], dim, f->GetTS()); int fd = _dc->OpenVariableRead(f->GetTS(), _inputCoordVar); if (fd < 0) { assert(0); return -1; } size_t nCoords = dim.GetLength(); float *coords = new float[nCoords]; ts = f->GetTS(); _dc->ReadRegion(fd, {0}, {nCoords - 1}, coords); float min = FLT_MAX; float max = -FLT_MAX; for (size_t i = 0; i < nCoords; i++) { min = std::min(min, coords[i]); max = std::max(max, coords[i]); } _minExt = min; _maxExt = max; _dc->CloseVariable(fd); delete[] coords; } DC::CoordVar cv; GetCoordVarInfo(cv); auto dims = cv.GetDimNames(); if (dims.size() != 1) { assert(0); return -1; } DC::Dimension dim; _dc->GetDimension(dims[0], dim, ts); size_t dimLen = dim.GetLength(); size_t n = 1 + max[0] - min[0]; if (n == 1) { *region = (_maxExt + _minExt) / 2.f; } else { float diff = _maxExt - _minExt; for (size_t i = 0; i < n; i++) { size_t ri = i + min[0]; float t = ri / (float)(dimLen - 1); region[i] = t * diff + _minExt; } } return 0; } vector DerivedCoordVar1DSpan::GetInputs() const { if (!_inputCoordVar.empty()) return {_inputCoordVar}; else return {}; } ================================================ FILE: lib/vdc/DerivedVar.cpp ================================================ #include "vapor/VAssert.h" #include #include #include #include #include #include #include #include #include using namespace VAPoR; using namespace Wasp; namespace { #ifdef UNUSED_FUNCTION size_t numBlocks(size_t min, size_t max, size_t bs) { size_t b0 = min / bs; size_t b1 = max / bs; return (b1 - b0 + 1); } #endif #ifdef UNUSED_FUNCTION size_t numBlocks(const vector &min, const vector &max, const vector &bs) { VAssert(min.size() == max.size()); VAssert(min.size() == bs.size()); size_t nblocks = 1; for (int i = 0; i < bs.size(); i++) { nblocks *= numBlocks(min[i], max[i], bs[i]); } return (nblocks); } #endif #ifdef UNUSED_FUNCTION size_t numBlocks(const vector &dims, const vector &bs) { VAssert(dims.size() == bs.size()); size_t nblocks = 1; for (int i = 0; i < bs.size(); i++) { VAssert(dims[i] != 0); nblocks *= (((dims[i] - 1) / bs[i]) + 1); } return (nblocks); } #endif size_t numElements(const vector &min, const vector &max) { VAssert(min.size() == max.size()); size_t nElements = 1; for (int i = 0; i < min.size(); i++) { nElements *= (max[i] - min[i] + 1); } return (nElements); } #ifdef UNUSED_FUNCTION size_t blockSize(const vector &bs) { size_t sz = 1; for (int i = 0; i < bs.size(); i++) { sz *= bs[i]; } return (sz); } #endif #ifdef UNUSED_FUNCTION vector increment(vector dims, vector coord) { VAssert(dims.size() == coord.size()); for (int i = 0; i < coord.size(); i++) { coord[i] += 1; if (coord[i] < (dims[i])) { break; } coord[i] = 0; } return (coord); } #endif // Product of elements in a vector // size_t vproduct(vector a) { size_t ntotal = 1; for (int i = 0; i < a.size(); i++) ntotal *= a[i]; return (ntotal); } #ifdef UNUSED_FUNCTION void extractBlock(const float *data, const vector &dims, const vector &bcoords, const vector &bs, float *block) { VAssert(dims.size() == bcoords.size()); VAssert(dims.size() == bs.size()); // Block dimensions // size_t bz = bs.size() > 2 ? bs[2] : 1; size_t by = bs.size() > 1 ? bs[1] : 1; size_t bx = bs.size() > 0 ? bs[0] : 1; // Data dimensions // size_t nz = dims.size() > 2 ? dims[2] : 1; size_t ny = dims.size() > 1 ? dims[1] : 1; size_t nx = dims.size() > 0 ? dims[0] : 1; // Data dimensions // size_t bcz = bcoords.size() > 2 ? bcoords[2] : 0; size_t bcy = bcoords.size() > 1 ? bcoords[1] : 0; size_t bcx = bcoords.size() > 0 ? bcoords[0] : 0; size_t z = bcz * bz; for (size_t zb = 0; zb < bz && z < nz; zb++, z++) { size_t y = bcy * by; for (size_t yb = 0; yb < by && y < ny; yb++, y++) { size_t x = bcx * bx; for (size_t xb = 0; xb < bx && x < nx; xb++, x++) { block[bx * by * zb + bx * yb + xb] = data[nx * ny * z + nx * y + x]; } } } } #endif #ifdef UNUSED_FUNCTION void blockit(const float *data, const vector &dims, const vector &bs, float *blocks) { VAssert(dims.size() == bs.size()); size_t block_size = vproduct(bs); vector bdims; for (int i = 0; i < bs.size(); i++) { VAssert(dims[i] > 0); bdims.push_back(((dims[i] - 1) / bs[i]) + 1); } size_t nbz = bdims.size() > 2 ? bdims[2] : 1; size_t nby = bdims.size() > 1 ? bdims[1] : 1; size_t nbx = bdims.size() > 0 ? bdims[0] : 1; float * blockptr = blocks; vector bcoord(bdims.size(), 0); for (size_t zb = 0; zb < nbz; zb++) { for (size_t yb = 0; yb < nby; yb++) { for (size_t xb = 0; xb < nbx; xb++) { extractBlock(data, dims, bcoord, bs, blockptr); blockptr += block_size; bcoord = increment(bdims, bcoord); } } } } #endif // make 2D lat and lon arrays from 1D arrays by replication, in place // void make2D(float *lonBuf, float *latBuf, vector dims) { VAssert(dims.size() == 2); size_t nx = dims[0]; size_t ny = dims[1]; // longitude // for (int j = 1; j < ny; j++) { for (int i = 0; i < nx; i++) { lonBuf[j * nx + i] = lonBuf[i]; } } // latitude requires a transpose first // for (int i = 0; i < ny; i++) { latBuf[i * nx] = latBuf[i]; } for (int j = 0; j < ny; j++) { for (int i = 1; i < nx; i++) { latBuf[j * nx + i] = latBuf[j * nx]; } } } // Transpose a 1D, 2D, or 3D array. For 1D 'a' is simply copied // to 'b'. Otherwise 'b' contains a permuted version of 'a' as follows: // // axis 1D 2D 3D // ---- -- -- -- // 0 (0) (0,1) (0,1,2) // 1 N/A (1,0) (1,0,2) // 2 N/A N/A (2,0,1) // // where the numbers in parenthesis indicate the permutation of the // axes. // // NOTE: The contents of 'a' are overwritten // void transpose(float *a, float *b, vector inDims, int axis) { VAssert(inDims.size() < 4); VAssert(axis >= 0 && axis < inDims.size()); size_t sz = vproduct(inDims); // No-op if axis is 0 // if (axis == 0) { // 1D, 2D, and 3D case for (size_t i = 0; i < sz; i++) { b[i] = a[i]; } return; } if (inDims.size() == 2) { VAssert(axis == 1); Wasp::Transpose(a, b, inDims[0], inDims[1]); } else if (inDims.size() == 3) { VAssert(axis == 1 || axis == 2); size_t stride = inDims[0] * inDims[1]; ; const float *aptr = a; float * bptr = b; for (size_t i = 0; i < inDims[2]; i++) { Wasp::Transpose(aptr, bptr, inDims[0], inDims[1]); aptr += stride; bptr += stride; } // For (2,1,0) permutation we do (0,1,2) -> (1,0,2) -> (2,1,0) // if (axis == 2) { // We can treat 3D array as 2D in this case, linearizing X and Y // Wasp::Transpose(b, a, inDims[0] * inDims[1], inDims[2]); // Ugh need to copy data from a back to b // for (size_t i = 0; i < vproduct(inDims); i++) { b[i] = a[i]; } } } } void transpose(vector inDims, int axis, vector &outDims) { outDims = inDims; if (axis == 1) { size_t tmp = outDims[0]; outDims[0] = outDims[1]; outDims[1] = tmp; } else if (axis == 2) { size_t tmp = outDims[0]; outDims[0] = outDims[2]; outDims[2] = tmp; } } void resampleToStaggered(float *src, const vector &inMin, const vector &inMax, float *dst, const vector &outMin, const vector &outMax, int stagDim) { VAssert(inMin.size() == inMax.size()); VAssert(inMin.size() == outMax.size()); VAssert(inMin.size() == outMax.size()); vector inDims, outDims; for (size_t i = 0; i < outMin.size(); i++) { inDims.push_back(inMax[i] - inMin[i] + 1); outDims.push_back(outMax[i] - outMin[i] + 1); } size_t sz = std::max(vproduct(outDims), vproduct(inDims)); float *buf = new float[sz]; // Tranpose the dimensions and array so that we always interpolate // with unit stride // vector inDimsT; // transposed input dimensions vector outDimsT; // transposed output dimensions transpose(inDims, stagDim, inDimsT); transpose(outDims, stagDim, outDimsT); transpose(src, buf, inDims, stagDim); size_t nz = inDimsT.size() >= 3 ? inDimsT[2] : 1; size_t ny = inDimsT.size() >= 2 ? inDimsT[1] : 1; size_t nx = inDimsT.size() >= 1 ? inDimsT[0] : 1; // Interpolate interior // size_t nxs = outDimsT[0]; // staggered dimension size_t i0 = outMin[stagDim] > inMin[stagDim] ? 0 : 1; for (size_t k = 0; k < nz; k++) { for (size_t j = 0; j < ny; j++) { for (size_t i = 0, ii = i0; i < nx - 1; i++, ii++) { src[k * nxs * ny + j * nxs + ii] = 0.5 * (buf[k * nx * ny + j * nx + i] + buf[k * nx * ny + j * nx + i + 1]); } } } // Next extrapolate boundary points if needed // // left boundary // if (outMin[stagDim] <= inMin[stagDim]) { if (inMin[stagDim] < inMax[stagDim]) { for (size_t k = 0; k < nz; k++) { for (size_t j = 0; j < ny; j++) { src[k * nxs * ny + j * nxs] = buf[k * nx * ny + j * nx + 0] + (-0.5 * (buf[k * nx * ny + j * nx + 1] - buf[k * nx * ny + j * nx + 0])); } } } else { for (size_t k = 0; k < nz; k++) { for (size_t j = 0; j < ny; j++) { src[k * nxs * ny + j * nxs] = buf[k * nx * ny + j * nx + 0]; } } } } // right boundary // if (outMax[stagDim] > inMax[stagDim]) { if (inMin[stagDim] < inMax[stagDim]) { for (size_t k = 0; k < nz; k++) { for (size_t j = 0; j < ny; j++) { src[k * nxs * ny + j * nxs + nxs - 1] = buf[k * nx * ny + j * nx + nx - 1] + (0.5 * (buf[k * nx * ny + j * nx + nx - 1] - buf[k * nx * ny + j * nx + nx - 2])); } } } else { for (size_t k = 0; k < nz; k++) { for (size_t j = 0; j < ny; j++) { src[k * nxs * ny + j * nxs + nxs - 1] = buf[k * nx * ny + j * nx + nx - 1]; } } } } // Undo tranpose // transpose(src, dst, outDimsT, stagDim); delete[] buf; } void resampleToUnStaggered(float *src, const vector &inMin, const vector &inMax, float *dst, const vector &outMin, const vector &outMax, int stagDim) { VAssert(inMin.size() == inMax.size()); VAssert(inMin.size() == outMax.size()); VAssert(inMin.size() == outMax.size()); vector myOutMax = outMax; vector myOutMin = outMin; myOutMin[stagDim] += 1; myOutMax[stagDim] += 1; resampleToStaggered(src, inMin, inMax, dst, myOutMin, myOutMax, stagDim); } #ifdef UNIT_TEST void print_matrix(const float *a, const vector &dims) { size_t nz = dims.size() >= 3 ? dims[2] : 1; size_t ny = dims.size() >= 2 ? dims[1] : 1; size_t nx = dims.size() >= 1 ? dims[0] : 1; for (int k = 0; k < nz; k++) { for (int j = 0; j < ny; j++) { for (int i = 0; i < nx; i++) { cout << a[k * nx * ny + j * nx + i] << " "; } cout << endl; } cout << endl; } } void test_resample(int stagDim) { vector inMin = {0, 0, 0}; vector inMax = {1, 2, 3}; vector outMin = inMin; vector outMax = inMax; outMax[stagDim] += 1; vector inDims, outDims; for (int i = 0; i < inMax.size(); i++) { inDims.push_back(inMax[i] - inMin[i] + 1); outDims.push_back(outMax[i] - outMin[i] + 1); } size_t nz = inDims.size() >= 3 ? inDims[2] : 1; size_t ny = inDims.size() >= 2 ? inDims[1] : 1; size_t nx = inDims.size() >= 1 ? inDims[0] : 1; size_t nzs = outDims.size() >= 3 ? outDims[2] : 1; size_t nys = outDims.size() >= 2 ? outDims[1] : 1; size_t nxs = outDims.size() >= 1 ? outDims[0] : 1; size_t sz = std::max(vproduct(outDims), vproduct(inDims)); float *src = new float[sz]; float *dst = new float[sz]; for (int k = 0; k < nz; k++) { for (int j = 0; j < ny; j++) { for (int i = 0; i < nx; i++) { src[k * nx * ny + j * nx + i] = k * nx * ny + j * nx + i; } } } for (int k = 0; k < nzs; k++) { for (int j = 0; j < nys; j++) { for (int i = 0; i < nxs; i++) { dst[k * nxs * nys + j * nxs + i] = 99; } } } cout << "original array" << endl; print_matrix(src, inDims); resampleToStaggered(src, inMin, inMax, dst, outMin, outMax, stagDim); cout << endl << endl; cout << "staggered array" << endl; print_matrix(dst, outDims); resampleToUnStaggered(dst, outMin, outMax, src, inMin, inMax, stagDim); cout << "reconstructed unstaggered array" << endl; print_matrix(src, inDims); } int main(int argc, char **argv) { VAssert(argc == 2); int stagDim = atoi(argv[1]); test_resample(stagDim); } #endif }; // namespace int DerivedVar::_getVar(DC *dc, size_t ts, string varname, int level, int lod, const vector &min, const vector &max, float *region) const { int fd = dc->OpenVariableRead(ts, varname, level, lod); if (fd < 0) return (-1); int rc = dc->ReadRegion(fd, min, max, region); if (rc < 0) { dc->CloseVariable(fd); return (-1); } return (dc->CloseVariable(fd)); } int DerivedVar::_getVarDestagger(DC *dc, size_t ts, string varname, int level, int lod, const vector &min, const vector &max, float *region, int stagDim) const { VAssert(stagDim >= 0 && stagDim < max.size()); VAssert(min.size() == max.size()); vector maxIn = max; maxIn[stagDim]++; vector dimsIn; for (int i = 0; i < min.size(); i++) { dimsIn.push_back(max[i] - min[i] + 1); } vector buf(vproduct(dimsIn)); int rc = _getVar(dc, ts, varname, level, lod, min, maxIn, buf.data()); if (rc < 0) return (rc); resampleToUnStaggered(buf.data(), min, maxIn, region, min, max, stagDim); return (0); } int DerivedVar::ReadRegion(int fd, const std::vector &min, const std::vector &max, double *region) { SetErrMsg("Not implemented"); return (-1); } ////////////////////////////////////////////////////////////////////////////// // // DerivedCoordVar_PCSFromLatLon // ////////////////////////////////////////////////////////////////////////////// DerivedCoordVar_PCSFromLatLon::DerivedCoordVar_PCSFromLatLon(string derivedVarName, DC *dc, vector inNames, string proj4String, bool uGridFlag, bool lonFlag) : DerivedCoordVar(derivedVarName) { VAssert(inNames.size() == 2); _dc = dc; _proj4String = proj4String; _lonName = inNames[0]; _latName = inNames[1]; _make2DFlag = false; _uGridFlag = uGridFlag; _lonFlag = lonFlag; _dimLens.clear(); } int DerivedCoordVar_PCSFromLatLon::Initialize() { int rc = _proj4API.Initialize("", _proj4String); if (rc < 0) { SetErrMsg("Invalid map projection : %s", _proj4String.c_str()); return (-1); } rc = _setupVar(); if (rc < 0) return (-1); return (0); } bool DerivedCoordVar_PCSFromLatLon::GetBaseVarInfo(DC::BaseVar &var) const { var = _coordVarInfo; return (true); } bool DerivedCoordVar_PCSFromLatLon::GetCoordVarInfo(DC::CoordVar &cvar) const { cvar = _coordVarInfo; return (true); } int DerivedCoordVar_PCSFromLatLon::GetDimLensAtLevel(int, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); dims_at_level = _dimLens; // No blocking // bs_at_level = vector(dims_at_level.size(), 1); return (0); } int DerivedCoordVar_PCSFromLatLon::OpenVariableRead(size_t ts, int, int) { DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, -1, -1); return (_fileTable.AddEntry(f)); } int DerivedCoordVar_PCSFromLatLon::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } _fileTable.RemoveEntry(fd); delete f; return (0); } int DerivedCoordVar_PCSFromLatLon::_readRegionHelperCylindrical(DC::FileTable::FileObject *f, const vector &min, const vector &max, float *region) { VAssert(min.size() == 1); VAssert(min.size() == max.size()); size_t ts = f->GetTS(); string varname = f->GetVarname(); int lod = f->GetLOD(); size_t nElements = max[0] - min[0] + 1; vector buf(nElements, 0.0); string geoCoordVar; if (_lonFlag) { geoCoordVar = _lonName; } else { geoCoordVar = _latName; } int rc = _getVar(_dc, ts, geoCoordVar, -1, lod, min, max, region); if (rc < 0) { return (rc); } if (_lonFlag) { rc = _proj4API.Transform(region, buf.data(), nElements); } else { rc = _proj4API.Transform(buf.data(), region, nElements); } return (rc); } int DerivedCoordVar_PCSFromLatLon::_readRegionHelper1D(DC::FileTable::FileObject *f, const vector &min, const vector &max, float *region) { size_t ts = f->GetTS(); string varname = f->GetVarname(); int lod = f->GetLOD(); // Need temporary buffer space for the X or Y coordinate // NOT being returned (we still need to calculate it) // size_t nElements = numElements(min, max); vector buf(nElements); vector roidims; for (int i = 0; i < min.size(); i++) { roidims.push_back(max[i] - min[i] + 1); } // Assign temporary buffer 'buf' as appropriate // float *lonBufPtr; float *latBufPtr; if (_lonFlag) { lonBufPtr = region; latBufPtr = buf.data(); } else { lonBufPtr = buf.data(); latBufPtr = region; } // Reading 1D data so no blocking // vector lonMin = {min[0]}; vector lonMax = {max[0]}; int rc = _getVar(_dc, ts, _lonName, -1, lod, lonMin, lonMax, lonBufPtr); if (rc < 0) { return (rc); } vector latMin = {min[1]}; vector latMax = {max[1]}; rc = _getVar(_dc, ts, _latName, -1, lod, latMin, latMax, latBufPtr); if (rc < 0) { return (rc); } // Combine the 2 1D arrays into a 2D array // make2D(lonBufPtr, latBufPtr, roidims); rc = _proj4API.Transform(lonBufPtr, latBufPtr, vproduct(roidims)); return (rc); } int DerivedCoordVar_PCSFromLatLon::_readRegionHelper2D(DC::FileTable::FileObject *f, const vector &min, const vector &max, float *region) { size_t ts = f->GetTS(); string varname = f->GetVarname(); int lod = f->GetLOD(); // Need temporary buffer space for the X or Y coordinate // NOT being returned (we still need to calculate it) // size_t nElements = numElements(min, max); vector buf(nElements); // Assign temporary buffer 'buf' as appropriate // float *lonBufPtr; float *latBufPtr; if (_lonFlag) { lonBufPtr = region; latBufPtr = buf.data(); } else { lonBufPtr = buf.data(); latBufPtr = region; } int rc = _getVar(_dc, ts, _lonName, -1, lod, min, max, lonBufPtr); if (rc < 0) { return (rc); } rc = _getVar(_dc, ts, _latName, -1, lod, min, max, latBufPtr); if (rc < 0) { return (rc); } rc = _proj4API.Transform(lonBufPtr, latBufPtr, nElements); return (rc); } int DerivedCoordVar_PCSFromLatLon::ReadRegion(int fd, const vector &min, const vector &max, float *region) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor: %d", fd); return (-1); } if (min.size() == 1) { // Lat and Lon are 1D variables // return (_readRegionHelperCylindrical(f, min, max, region)); } else { if (_make2DFlag) { // Lat and Lon are 1D variables but projections to PCS // result in X and Y coordinate variables that are 2D // return (_readRegionHelper1D(f, min, max, region)); } else { return (_readRegionHelper2D(f, min, max, region)); } } } bool DerivedCoordVar_PCSFromLatLon::VariableExists(size_t ts, int, int) const { return (_dc->VariableExists(ts, _lonName, -1, -1) && _dc->VariableExists(ts, _latName, -1, -1)); } int DerivedCoordVar_PCSFromLatLon::_setupVar() { DC::CoordVar lonVar; bool ok = _dc->GetCoordVarInfo(_lonName, lonVar); if (!ok) return (-1); DC::CoordVar latVar; ok = _dc->GetCoordVarInfo(_latName, latVar); if (!ok) return (-1); vector lonDims; ok = _dc->GetVarDimLens(_lonName, true, lonDims, -1); if (!ok) { SetErrMsg("GetVarDimLens(%s) failed", _lonName.c_str()); return (-1); } vector latDims; ok = _dc->GetVarDimLens(_latName, true, latDims, -1); if (!ok) { SetErrMsg("GetVarDimLens(%s) failed", _lonName.c_str()); return (-1); } if (lonDims.size() != latDims.size()) { SetErrMsg("Incompatible block size"); return (-1); } bool cylProj = _proj4API.IsCylindrical(); vector dimNames; if (lonVar.GetDimNames().size() == 1 && !_uGridFlag) { if (cylProj) { if (_lonFlag) { dimNames.push_back(lonVar.GetDimNames()[0]); _dimLens.push_back(lonDims[0]); } else { dimNames.push_back(latVar.GetDimNames()[0]); _dimLens.push_back(latDims[0]); } } else { dimNames.push_back(lonVar.GetDimNames()[0]); dimNames.push_back(latVar.GetDimNames()[0]); _dimLens.push_back(lonDims[0]); _dimLens.push_back(latDims[0]); _make2DFlag = true; } } else if (lonVar.GetDimNames().size() == 2 && !_uGridFlag) { if (lonDims[0] != latDims[0] && lonDims[1] != latDims[1]) { SetErrMsg("Incompatible dimensions "); return (-1); } dimNames.push_back(lonVar.GetDimNames()[0]); dimNames.push_back(lonVar.GetDimNames()[1]); _dimLens.push_back(lonDims[0]); _dimLens.push_back(lonDims[1]); _make2DFlag = false; } else { VAssert(lonVar.GetDimNames().size() == 1 && _uGridFlag); dimNames = lonVar.GetDimNames(); _dimLens = lonDims; } if (lonVar.GetTimeDimName() != latVar.GetTimeDimName()) { SetErrMsg("Incompatible time dimensions"); return (-1); } string timeDimName = lonVar.GetTimeDimName(); DC::XType xtype = lonVar.GetXType(); vector periodic = lonVar.GetPeriodic(); _coordVarInfo.SetName(_derivedVarName); _coordVarInfo.SetUnits("meters"); _coordVarInfo.SetXType(xtype); _coordVarInfo.SetWName(""); _coordVarInfo.SetCRatios(vector()); _coordVarInfo.SetPeriodic(periodic); _coordVarInfo.SetUniform(false); _coordVarInfo.SetDimNames(dimNames); _coordVarInfo.SetTimeDimName(timeDimName); _coordVarInfo.SetAxis(_lonFlag ? 0 : 1); return (0); } ////////////////////////////////////////////////////////////////////////////// // // DerivedCoordVar_CF1D // ////////////////////////////////////////////////////////////////////////////// DerivedCoordVar_CF1D::DerivedCoordVar_CF1D(string derivedVarName, DC *dc, string dimName, int axis, string units) : DerivedCoordVar(derivedVarName) { _dc = dc; _dimName = dimName; _coordVarInfo = DC::CoordVar(_derivedVarName, units, DC::XType::FLOAT, vector(1, false), axis, true, vector(1, dimName), ""); } int DerivedCoordVar_CF1D::Initialize() { return (0); } bool DerivedCoordVar_CF1D::GetBaseVarInfo(DC::BaseVar &var) const { var = _coordVarInfo; return (true); } bool DerivedCoordVar_CF1D::GetCoordVarInfo(DC::CoordVar &cvar) const { cvar = _coordVarInfo; return (true); } int DerivedCoordVar_CF1D::GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const { return GetDimLensAtLevel(level, dims_at_level, bs_at_level, -1); } int DerivedCoordVar_CF1D::GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level, long ts) const { dims_at_level.clear(); bs_at_level.clear(); DC::Dimension dimension; int rc = _dc->GetDimension(_dimName, dimension, ts); if (rc < 0) return (-1); dims_at_level.push_back(dimension.GetLength()); // No blocking // bs_at_level = vector(dims_at_level.size(), 1); return (0); } int DerivedCoordVar_CF1D::OpenVariableRead(size_t ts, int level, int lod) { DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod); return (_fileTable.AddEntry(f)); } int DerivedCoordVar_CF1D::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } _fileTable.RemoveEntry(fd); delete f; return (0); } int DerivedCoordVar_CF1D::ReadRegion(int fd, const vector &min, const vector &max, float *region) { VAssert(min.size() == 1); VAssert(max.size() == 1); float *regptr = region; for (size_t i = min[0]; i <= max[0]; i++) { *regptr++ = (float)i; } return (0); } bool DerivedCoordVar_CF1D::VariableExists(size_t ts, int reflevel, int lod) const { if (reflevel != 0) return (false); if (lod != 0) return (false); return (true); } ////////////////////////////////////////////////////////////////////////////// // // DerivedCoordVar_CF2D // ////////////////////////////////////////////////////////////////////////////// DerivedCoordVar_CF2D::DerivedCoordVar_CF2D(string derivedVarName, vector dimNames, vector dimLens, int axis, string units, const vector &data) : DerivedCoordVar(derivedVarName) { VAssert(dimNames.size() == 2); VAssert(dimLens.size() == 2); VAssert(dimLens[0] * dimLens[1] <= data.size()); _dimNames = dimNames; _dimLens = dimLens; _data = data; _coordVarInfo = DC::CoordVar(_derivedVarName, units, DC::XType::FLOAT, vector(2, false), axis, false, dimNames, ""); } int DerivedCoordVar_CF2D::Initialize() { return (0); } bool DerivedCoordVar_CF2D::GetBaseVarInfo(DC::BaseVar &var) const { var = _coordVarInfo; return (true); } bool DerivedCoordVar_CF2D::GetCoordVarInfo(DC::CoordVar &cvar) const { cvar = _coordVarInfo; return (true); } int DerivedCoordVar_CF2D::GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); dims_at_level = _dimLens; // No blocking // bs_at_level = vector(dims_at_level.size(), 1); return (0); } int DerivedCoordVar_CF2D::OpenVariableRead(size_t ts, int level, int lod) { return (0); } int DerivedCoordVar_CF2D::CloseVariable(int fd) { return (0); } int DerivedCoordVar_CF2D::ReadRegion(int fd, const vector &min, const vector &max, float *region) { VAssert(min.size() == 2); VAssert(max.size() == 2); float *regptr = region; for (size_t j = min[1]; j <= max[1]; j++) { for (size_t i = min[0]; i <= max[0]; i++) { *regptr++ = (float)_data[j * _dimLens[0] + i]; } } return (0); } bool DerivedCoordVar_CF2D::VariableExists(size_t ts, int reflevel, int lod) const { if (reflevel != 0) return (false); if (lod != 0) return (false); return (true); } ////////////////////////////////////////////////////////////////////////////// // // DerivedCoordVar_WRFTime // ////////////////////////////////////////////////////////////////////////////// DerivedCoordVar_WRFTime::DerivedCoordVar_WRFTime(string derivedVarName, NetCDFCollection *ncdfc, string wrfTimeVar, string dimName, float p2si) : DerivedCoordVar(derivedVarName) { _ncdfc = ncdfc; _times.clear(); _timePerm.clear(); _wrfTimeVar = wrfTimeVar; _p2si = p2si; _ovr_ts = 0; string units = "seconds"; int axis = 3; _coordVarInfo = DC::CoordVar(_derivedVarName, units, DC::XType::FLOAT, vector(), axis, false, vector(), dimName); } int DerivedCoordVar_WRFTime::_encodeTime(UDUnits &udunits, const vector &timeStrings, vector ×) const { times.clear(); for (int i = 0; i < timeStrings.size(); i++) { const string &s = timeStrings[i]; const char *format6 = "%4d-%2d-%2d_%2d:%2d:%2d"; int year, mon, mday, hour, min, sec; int rc = sscanf(s.data(), format6, &year, &mon, &mday, &hour, &min, &sec); if (rc != 6) { // Alternate date format // const char *format5 = "%4d-%5d_%2d:%2d:%2d"; rc = sscanf(s.data(), format5, &year, &mday, &hour, &min, &sec); if (rc != 5) { SetErrMsg("Unrecognized time stamp: %s", s.data()); return (-1); } mon = 1; } times.push_back(udunits.EncodeTime(year, mon, mday, hour, min, sec) * _p2si); } return (0); } int DerivedCoordVar_WRFTime::Initialize() { _times.clear(); _timePerm.clear(); // Use UDUnits for unit conversion // UDUnits udunits; int rc = udunits.Initialize(); if (rc < 0) { SetErrMsg("Failed to initialize udunits2 library : %s", udunits.GetErrMsg().c_str()); return (-1); } size_t numTS = _ncdfc->GetNumTimeSteps(); if (numTS < 1) return (0); vector dims = _ncdfc->GetSpatialDims(_wrfTimeVar); if (dims.size() != 1) { SetErrMsg("Invalid WRF time variable : %s", _wrfTimeVar.c_str()); return (-1); } // Read all of the formatted time strings up front - it's a 1D array // so we can simply store the results in memory - and convert from // a formatted time string to seconds since the EPOCH // vector timeStrings; char * buf = new char[dims[0] + 1]; buf[dims[0]] = '\0'; for (size_t ts = 0; ts < numTS; ts++) { int fd = _ncdfc->OpenRead(ts, _wrfTimeVar); if (fd < 0) { SetErrMsg("Can't read time variable"); return (-1); } int rc = _ncdfc->Read(buf, fd); if (rc < 0) { SetErrMsg("Can't read time variable"); _ncdfc->Close(fd); delete[] buf; return (-1); } _ncdfc->Close(fd); timeStrings.push_back(buf); } delete[] buf; // Encode time stamp string as double precision float // rc = _encodeTime(udunits, timeStrings, _times); if (rc < 0) return (rc); // The NetCDFCollection class doesn't handle the WRF time // variable. Hence, the time steps aren't sorted. Sort them now and // create a lookup table to map a time index to the correct time step // in the WRF data collection. N.B. this is only necessary if multiple // WRF files are present and they're not passed to Initialize() in // the correct order. // _timePerm.clear(); for (int i = 0; i != _times.size(); i++) { _timePerm.push_back(i); } sort(_timePerm.begin(), _timePerm.end(), [&](const int &a, const int &b) { return (_times[a] < _times[b]); }); return (0); } bool DerivedCoordVar_WRFTime::GetBaseVarInfo(DC::BaseVar &var) const { var = _coordVarInfo; return (true); } bool DerivedCoordVar_WRFTime::GetCoordVarInfo(DC::CoordVar &cvar) const { cvar = _coordVarInfo; return (true); } int DerivedCoordVar_WRFTime::GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); return (0); } int DerivedCoordVar_WRFTime::OpenVariableRead(size_t ts, int level, int lod) { ts = ts < _times.size() ? ts : _times.size() - 1; DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod); return (_fileTable.AddEntry(f)); } int DerivedCoordVar_WRFTime::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } _fileTable.RemoveEntry(fd); delete f; return (0); } int DerivedCoordVar_WRFTime::ReadRegion(int fd, const vector &min, const vector &max, float *region) { VAssert(min.size() == 0); VAssert(max.size() == 0); DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor: %d", fd); return (-1); } size_t ts = f->GetTS(); *region = _times[ts]; return (0); } int DerivedCoordVar_WRFTime::ReadRegion(int fd, const vector &min, const vector &max, double *region) { VAssert(min.size() == 0); VAssert(max.size() == 0); DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor: %d", fd); return (-1); } size_t ts = f->GetTS(); *region = _times[ts]; return (0); } bool DerivedCoordVar_WRFTime::VariableExists(size_t ts, int reflevel, int lod) const { return (ts < _times.size()); } ////////////////////////////////////////////////////////////////////////////// // // DerivedCoordVar_TimeInSeconds // ////////////////////////////////////////////////////////////////////////////// DerivedCoordVar_TimeInSeconds::DerivedCoordVar_TimeInSeconds(string derivedVarName, DC *dc, string nativeTimeVar, string dimName) : DerivedCoordVar(derivedVarName) { _dc = dc; _times.clear(); _nativeTimeVar = nativeTimeVar; string units = "seconds"; int axis = 3; _coordVarInfo = DC::CoordVar(_derivedVarName, units, DC::XType::FLOAT, vector(), axis, false, vector(), dimName); } int DerivedCoordVar_TimeInSeconds::Initialize() { // Use UDUnits for unit conversion // UDUnits udunits; int rc = udunits.Initialize(); if (rc < 0) { SetErrMsg("Failed to initialize udunits2 library : %s", udunits.GetErrMsg().c_str()); return (-1); } DC::CoordVar cvar; bool status = _dc->GetCoordVarInfo(_nativeTimeVar, cvar); if (!status) { SetErrMsg("Invalid coordinate variable %s", _nativeTimeVar.c_str()); return (-1); } if (!udunits.IsTimeUnit(cvar.GetUnits())) { SetErrMsg("Invalid coordinate variable %s", _nativeTimeVar.c_str()); return (-1); } size_t numTS = _dc->GetNumTimeSteps(_nativeTimeVar); // double *dbuf = new double[2 * numTS]; double *dbufptr1 = dbuf; double *dbufptr2 = dbuf + numTS; rc = _dc->GetVar(_nativeTimeVar, -1, -1, dbuf); if (rc < 0) { SetErrMsg("Can't read time variable"); return (-1); } for (int i = 0; i < numTS; i++) { dbufptr1[i] = (double)dbuf[i]; } status = udunits.Convert(cvar.GetUnits(), "seconds", dbufptr1, dbufptr2, numTS); if (!status) { SetErrMsg("Invalid coordinate variable %s", _nativeTimeVar.c_str()); return (-1); } _times.clear(); for (int i = 0; i < numTS; i++) { _times.push_back(dbufptr2[i]); } delete[] dbuf; return (0); } bool DerivedCoordVar_TimeInSeconds::GetBaseVarInfo(DC::BaseVar &var) const { var = _coordVarInfo; return (true); } bool DerivedCoordVar_TimeInSeconds::GetCoordVarInfo(DC::CoordVar &cvar) const { cvar = _coordVarInfo; return (true); } int DerivedCoordVar_TimeInSeconds::GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); return (0); } int DerivedCoordVar_TimeInSeconds::OpenVariableRead(size_t ts, int level, int lod) { ts = ts < _times.size() ? ts : _times.size() - 1; DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod); return (_fileTable.AddEntry(f)); } int DerivedCoordVar_TimeInSeconds::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } _fileTable.RemoveEntry(fd); delete f; return (0); } int DerivedCoordVar_TimeInSeconds::ReadRegion(int fd, const vector &min, const vector &max, float *region) { VAssert(min.size() == 0); VAssert(max.size() == 0); DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor: %d", fd); return (-1); } size_t ts = f->GetTS(); *region = _times[ts]; return (0); } int DerivedCoordVar_TimeInSeconds::ReadRegion(int fd, const vector &min, const vector &max, double *region) { VAssert(min.size() == 0); VAssert(max.size() == 0); DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor: %d", fd); return (-1); } size_t ts = f->GetTS(); *region = _times[ts]; return (0); } bool DerivedCoordVar_TimeInSeconds::VariableExists(size_t ts, int reflevel, int lod) const { return (ts < _times.size()); } ////////////////////////////////////////////////////////////////////////////// // // DerivedCoordVar_Time // ////////////////////////////////////////////////////////////////////////////// DerivedCoordVar_Time::DerivedCoordVar_Time(string derivedVarName, string dimName, size_t n) : DerivedCoordVar(derivedVarName) { _times.clear(); for (size_t i = 0; i < n; i++) _times.push_back((float)i); string units = "seconds"; int axis = 3; _coordVarInfo = DC::CoordVar(_derivedVarName, units, DC::XType::FLOAT, vector(), axis, false, vector(), dimName); } int DerivedCoordVar_Time::Initialize() { return (0); } bool DerivedCoordVar_Time::GetBaseVarInfo(DC::BaseVar &var) const { var = _coordVarInfo; return (true); } bool DerivedCoordVar_Time::GetCoordVarInfo(DC::CoordVar &cvar) const { cvar = _coordVarInfo; return (true); } int DerivedCoordVar_Time::GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); return (0); } int DerivedCoordVar_Time::OpenVariableRead(size_t ts, int level, int lod) { ts = ts < _times.size() ? ts : _times.size() - 1; DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod); return (_fileTable.AddEntry(f)); } int DerivedCoordVar_Time::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } _fileTable.RemoveEntry(fd); delete f; return (0); } int DerivedCoordVar_Time::ReadRegion(int fd, const vector &min, const vector &max, float *region) { VAssert(min.size() == 0); VAssert(max.size() == 0); DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor: %d", fd); return (-1); } size_t ts = f->GetTS(); *region = _times[ts]; return (0); } bool DerivedCoordVar_Time::VariableExists(size_t ts, int reflevel, int lod) const { return (ts < _times.size()); } ////////////////////////////////////////////////////////////////////////////// // // DerivedCoordVar_Staggered // ////////////////////////////////////////////////////////////////////////////// DerivedCoordVar_Staggered::DerivedCoordVar_Staggered(string derivedVarName, string stagDimName, DC *dc, string inName, string dimName) : DerivedCoordVar(derivedVarName) { _stagDimName = stagDimName; _inName = inName; _dimName = dimName; _dc = dc; } int DerivedCoordVar_Staggered::Initialize() { bool ok = _dc->GetCoordVarInfo(_inName, _coordVarInfo); if (!ok) return (-1); vector dimNames = _coordVarInfo.GetDimNames(); _stagDim = -1; for (int i = 0; i < dimNames.size(); i++) { if (dimNames[i] == _dimName) { _stagDim = i; dimNames[i] = _stagDimName; break; } } if (_stagDim < 0) { SetErrMsg("Dimension %s not found", _dimName.c_str()); return (-1); } // Change the name of the staggered dimension // _coordVarInfo.SetDimNames(dimNames); return (0); } bool DerivedCoordVar_Staggered::GetBaseVarInfo(DC::BaseVar &var) const { var = _coordVarInfo; return (true); } bool DerivedCoordVar_Staggered::GetCoordVarInfo(DC::CoordVar &cvar) const { cvar = _coordVarInfo; return (true); } int DerivedCoordVar_Staggered::GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); vector dummy; int rc = _dc->GetDimLensAtLevel(_inName, level, dims_at_level, dummy, -1); if (rc < 0) return (-1); dims_at_level[_stagDim] += 1; bs_at_level = vector(dims_at_level.size(), 1); return (0); } int DerivedCoordVar_Staggered::OpenVariableRead(size_t ts, int level, int lod) { int fd = _dc->OpenVariableRead(ts, _inName, level, lod); if (fd < 0) return (fd); DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod, fd); return (_fileTable.AddEntry(f)); } int DerivedCoordVar_Staggered::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int rc = _dc->CloseVariable(f->GetAux()); _fileTable.RemoveEntry(fd); delete f; return (rc); } int DerivedCoordVar_Staggered::ReadRegion(int fd, const vector &min, const vector &max, float *region) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } vector dims, dummy; int rc = GetDimLensAtLevel(f->GetLevel(), dims, dummy); if (rc < 0) return (-1); vector inMin = min; vector inMax = max; // adjust coords for native data so that we have what we // need for interpolation or extrapolation. // // Adjust min max boundaries to handle 4 case (below) where X's // are samples on the destination grid (staggered) and O's are samples // on the source grid (unstaggered) and the numbers represent // the address of the samples in their respective arrays // // X O X O X O X // 0 0 1 1 2 2 3 // // O X O X O X // 0 1 1 2 2 3 // // X O X O X O // 0 0 1 1 2 2 // // O X O X O // 0 1 1 2 2 // Adjust input min so we can interpolate interior. // if (min[_stagDim] > 0) { inMin[_stagDim] -= 1; } // input dimensions are one less then output // if (max[_stagDim] >= (dims[_stagDim] - 1)) { inMax[_stagDim] -= 1; } // Adjust min and max for edge cases // if (max[_stagDim] == 0 && (dims[_stagDim] - 1) > 1) { inMax[_stagDim] += 1; } if (min[_stagDim] == dims[_stagDim] - 1 && min[_stagDim] > 0) { inMin[_stagDim] -= 1; } vector inDims, outDims; for (size_t i = 0; i < min.size(); i++) { inDims.push_back(inMax[i] - inMin[i] + 1); outDims.push_back(max[i] - min[i] + 1); } size_t sz = std::max(vproduct(outDims), vproduct(inDims)); float *buf = new float[sz]; // Read unstaggered data // rc = _dc->ReadRegion(f->GetAux(), inMin, inMax, buf); if (rc < 0) return (-1); resampleToStaggered(buf, inMin, inMax, region, min, max, _stagDim); delete[] buf; return (0); } bool DerivedCoordVar_Staggered::VariableExists(size_t ts, int reflevel, int lod) const { return (_dc->VariableExists(ts, _inName, reflevel, lod)); } ////////////////////////////////////////////////////////////////////////////// // // DerivedCoordVar_UnStaggered // ////////////////////////////////////////////////////////////////////////////// DerivedCoordVar_UnStaggered::DerivedCoordVar_UnStaggered(string derivedVarName, string unstagDimName, DC *dc, string inName, string dimName) : DerivedCoordVar(derivedVarName) { _unstagDimName = unstagDimName; _inName = inName; _dimName = dimName; _dc = dc; } int DerivedCoordVar_UnStaggered::Initialize() { bool ok = _dc->GetCoordVarInfo(_inName, _coordVarInfo); if (!ok) return (-1); vector dimNames = _coordVarInfo.GetDimNames(); _stagDim = -1; for (int i = 0; i < dimNames.size(); i++) { if (dimNames[i] == _dimName) { _stagDim = i; dimNames[i] = _unstagDimName; break; } } if (_stagDim < 0) { SetErrMsg("Dimension %s not found", _dimName.c_str()); return (-1); } // Change the name of the staggered dimension // _coordVarInfo.SetDimNames(dimNames); return (0); } bool DerivedCoordVar_UnStaggered::GetBaseVarInfo(DC::BaseVar &var) const { var = _coordVarInfo; return (true); } bool DerivedCoordVar_UnStaggered::GetCoordVarInfo(DC::CoordVar &cvar) const { cvar = _coordVarInfo; return (true); } int DerivedCoordVar_UnStaggered::GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); int rc = _dc->GetDimLensAtLevel(_inName, level, dims_at_level, bs_at_level, -1); if (rc < 0) return (-1); dims_at_level[_stagDim] -= 1; bs_at_level = vector(dims_at_level.size(), 1); return (0); } int DerivedCoordVar_UnStaggered::OpenVariableRead(size_t ts, int level, int lod) { int fd = _dc->OpenVariableRead(ts, _inName, level, lod); if (fd < 0) return (fd); DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod, fd); return (_fileTable.AddEntry(f)); } int DerivedCoordVar_UnStaggered::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int rc = _dc->CloseVariable(f->GetAux()); _fileTable.RemoveEntry(fd); delete f; return (rc); } int DerivedCoordVar_UnStaggered::ReadRegion(int fd, const vector &min, const vector &max, float *region) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } vector dims, dummy; int rc = GetDimLensAtLevel(f->GetLevel(), dims, dummy); if (rc < 0) return (-1); vector inMin = min; vector inMax = max; // adjust coords for native data so that we have what we // need for interpolation . // inMax[_stagDim] += 1; vector inDims, outDims; for (size_t i = 0; i < min.size(); i++) { inDims.push_back(inMax[i] - inMin[i] + 1); outDims.push_back(max[i] - min[i] + 1); } size_t sz = std::max(vproduct(outDims), vproduct(inDims)); float *buf = new float[sz]; // Read staggered data // rc = _dc->ReadRegion(f->GetAux(), inMin, inMax, buf); if (rc < 0) return (-1); resampleToUnStaggered(buf, inMin, inMax, region, min, max, _stagDim); delete[] buf; return (0); } bool DerivedCoordVar_UnStaggered::VariableExists(size_t ts, int reflevel, int lod) const { return (_dc->VariableExists(ts, _inName, reflevel, lod)); } ////////////////////////////////////////////////////////////////////////////// // // DerivedCFVertCoordVar // ////////////////////////////////////////////////////////////////////////////// bool DerivedCFVertCoordVar::ParseFormula(string formula_terms, map &parsed_terms) { parsed_terms.clear(); // Remove ":" to ease parsing. It's superflous // replace(formula_terms.begin(), formula_terms.end(), ':', ' '); string buf; // Have a buffer string stringstream ss(formula_terms); // Insert the string into a stream vector tokens; // Create vector to hold our words while (ss >> buf) { tokens.push_back(buf); } if (tokens.size() % 2) return (false); for (int i = 0; i < tokens.size(); i += 2) { parsed_terms[tokens[i]] = tokens[i + 1]; if (parsed_terms[tokens[i]].empty()) return (false); } return (true); } bool DerivedCFVertCoordVar::ValidFormula(const vector &required_terms, string formula) { map formulaMap; if (!ParseFormula(formula, formulaMap)) { return (false); } for (int i = 0; i < required_terms.size(); i++) { map::const_iterator itr; itr = formulaMap.find(required_terms[i]); if (itr == formulaMap.end()) return (false); } return (true); } ////////////////////////////////////////////////////////////////////////// // // DerivedCFVertCoordVarFactory Class // ///////////////////////////////////////////////////////////////////////// DerivedCFVertCoordVar *DerivedCFVertCoordVarFactory::CreateInstance(string standard_name, DC *dc, string mesh, string formula) { DerivedCFVertCoordVar *instance = NULL; // find standard_name in the registry and call factory method. // auto it = _factoryFunctionRegistry.find(standard_name); if (it != _factoryFunctionRegistry.end()) { instance = it->second(dc, mesh, formula); } return instance; } vector DerivedCFVertCoordVarFactory::GetFactoryNames() const { vector names; map>::const_iterator itr; for (const auto &itr : _factoryFunctionRegistry) { names.push_back(itr.first); } return (names); } ////////////////////////////////////////////////////////////////////////////// // // DerivedCoordVarStandardWRF_Terrain // ////////////////////////////////////////////////////////////////////////////// static DerivedCFVertCoordVarFactoryRegistrar registrar_wrf_terrain("wrf_terrain"); DerivedCoordVarStandardWRF_Terrain::DerivedCoordVarStandardWRF_Terrain(DC *dc, string mesh, string formula) : DerivedCFVertCoordVar("", dc, mesh, formula) { _PHVar.clear(); _PHBVar.clear(); _grav = 9.80665; } int DerivedCoordVarStandardWRF_Terrain::Initialize() { map formulaMap; if (!ParseFormula(_formula, formulaMap)) { SetErrMsg("Invalid conversion formula \"%s\"", _formula.c_str()); return (-1); } map::const_iterator itr; itr = formulaMap.find("PH"); if (itr != formulaMap.end()) { _PHVar = itr->second; } itr = formulaMap.find("PHB"); if (itr != formulaMap.end()) { _PHBVar = itr->second; } if (_PHVar.empty() || _PHBVar.empty()) { SetErrMsg("Invalid conversion formula \"%s\"", _formula.c_str()); return (-1); } DC::DataVar dvarInfo; bool status = _dc->GetDataVarInfo(_PHVar, dvarInfo); if (!status) { SetErrMsg("Invalid variable \"%s\"", _PHVar.c_str()); return (-1); } string timeCoordVar = dvarInfo.GetTimeCoordVar(); string timeDimName; if (!timeCoordVar.empty()) { DC::CoordVar cvarInfo; bool status = _dc->GetCoordVarInfo(timeCoordVar, cvarInfo); if (!status) { SetErrMsg("Invalid variable \"%s\"", timeCoordVar.c_str()); return (-1); } timeDimName = cvarInfo.GetTimeDimName(); } DC::Mesh m; status = _dc->GetMesh(_mesh, m); if (!status) { SetErrMsg("Invalid mesh \"%s\"", _mesh.c_str()); return (-1); } // Elevation variable // vector dimnames = m.GetDimNames(); VAssert(dimnames.size() == 3); if (dimnames[0] == "west_east" && dimnames[1] == "south_north" && dimnames[2] == "bottom_top") { _derivedVarName = "Elevation"; } else if (dimnames[0] == "west_east_stag" && dimnames[1] == "south_north" && dimnames[2] == "bottom_top") { _derivedVarName = "ElevationU"; } else if (dimnames[0] == "west_east" && dimnames[1] == "south_north_stag" && dimnames[2] == "bottom_top") { _derivedVarName = "ElevationV"; } else if (dimnames[0] == "west_east" && dimnames[1] == "south_north" && dimnames[2] == "bottom_top_stag") { _derivedVarName = "ElevationW"; } else { SetErrMsg("Invalid mesh \"%s\"", _mesh.c_str()); return (-1); } _coordVarInfo = DC::CoordVar(_derivedVarName, "m", DC::XType::FLOAT, dvarInfo.GetWName(), dvarInfo.GetCRatios(), vector(3, false), dimnames, timeDimName, 2, false); return (0); } bool DerivedCoordVarStandardWRF_Terrain::GetBaseVarInfo(DC::BaseVar &var) const { var = _coordVarInfo; return (true); } bool DerivedCoordVarStandardWRF_Terrain::GetCoordVarInfo(DC::CoordVar &cvar) const { cvar = _coordVarInfo; return (true); } int DerivedCoordVarStandardWRF_Terrain::GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); vector dims, bs; int rc = _dc->GetDimLensAtLevel(_PHVar, -1, dims, bs, -1); if (rc < 0) return (-1); if (_derivedVarName == "Elevation") { if (dims[2] > 1) dims[2]--; } else if (_derivedVarName == "ElevationU") { dims[0]++; if (dims[2] > 1) dims[2]--; } else if (_derivedVarName == "ElevationV") { dims[1]++; if (dims[2] > 1) dims[2]--; } else if (_derivedVarName == "ElevationW") { } else { SetErrMsg("Invalid variable name: %s", _derivedVarName.c_str()); return (-1); } int nlevels = _dc->GetNumRefLevels(_PHVar); if (level < 0) level = nlevels + level; WASP::InqDimsAtLevel(_coordVarInfo.GetWName(), level, dims, bs, dims_at_level, bs_at_level); // No blocking // // bs_at_level = vector (dims_at_level.size(), 1); return (0); } int DerivedCoordVarStandardWRF_Terrain::OpenVariableRead(size_t ts, int level, int lod) { DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod); return (_fileTable.AddEntry(f)); } int DerivedCoordVarStandardWRF_Terrain::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } _fileTable.RemoveEntry(fd); delete f; return (0); } int DerivedCoordVarStandardWRF_Terrain::ReadRegion(int fd, const vector &min, const vector &max, float *region) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); string varname = f->GetVarname(); // Dimensions of "W" grid: PH and PHB variables are sampled on the // same grid as the W component of velocity // vector wDims, dummy; int rc = _dc->GetDimLensAtLevel(_PHVar, f->GetLevel(), wDims, dummy, -1); if (rc < 0) return (-1); vector myDims; rc = DerivedCoordVarStandardWRF_Terrain::GetDimLensAtLevel(f->GetLevel(), myDims, dummy); if (rc < 0) return (-1); // coordinates of "W" grid. // vector wMin = min; vector wMax = max; // coordinates of base (Elevation) grid. // if (varname == "Elevation") { // In general myDims[2] != wDims[2]. However, for multiresolution // data the two can be equal // if (myDims[2] != wDims[2]) { wMax[2] += 1; } } else if (varname == "ElevationU") { if (myDims[2] != wDims[2]) { wMax[2] += 1; } if (min[0] > 0) { wMin[0] -= 1; } if (max[0] >= (wDims[0] - 1)) { wMax[0] -= 1; } } else if (varname == "ElevationV") { if (myDims[2] != wDims[2]) { wMax[2] += 1; } if (min[1] > 0) { wMin[1] -= 1; } if (max[1] >= (wDims[1] - 1)) { wMax[1] -= 1; } } // Base grid dimensions // vector bMin = wMin; vector bMax = wMax; if (myDims[2] != wDims[2]) { bMax[2] -= 1; } size_t nElements = std::max(numElements(wMin, wMax), numElements(min, max)); vector buf1(nElements); rc = _getVar(_dc, f->GetTS(), _PHVar, f->GetLevel(), f->GetLOD(), wMin, wMax, buf1.data()); if (rc < 0) { return (rc); } vector buf2(nElements); rc = _getVar(_dc, f->GetTS(), _PHBVar, f->GetLevel(), f->GetLOD(), wMin, wMax, buf2.data()); if (rc < 0) { return (rc); } float *dst = region; if (varname != "ElevationW" && wDims[2] > 1) { dst = buf1.data(); } // Compute elevation on the W grid // for (size_t i = 0; i < nElements; i++) { dst[i] = (buf1.data()[i] + buf2.data()[i]) / _grav; } if (wDims[2] < 2) return (0); // Elevation is correct for W grid. If we want Elevation, ElevationU, or // Elevation V grid we need to interpolate // if (varname == "Elevation") { // Resample stagged W grid to base grid // resampleToUnStaggered(buf1.data(), wMin, wMax, region, min, max, 2); } else if (varname == "ElevationU") { // Resample stagged W grid to base grid // resampleToUnStaggered(buf1.data(), wMin, wMax, buf2.data(), bMin, bMax, 2); resampleToStaggered(buf2.data(), bMin, bMax, region, min, max, 0); } else if (varname == "ElevationV") { // Resample stagged W grid to base grid // resampleToUnStaggered(buf1.data(), wMin, wMax, buf2.data(), bMin, bMax, 2); resampleToStaggered(buf2.data(), bMin, bMax, region, min, max, 1); } return (0); } bool DerivedCoordVarStandardWRF_Terrain::VariableExists(size_t ts, int reflevel, int lod) const { return (_dc->VariableExists(ts, _PHVar, reflevel, lod) && _dc->VariableExists(ts, _PHBVar, reflevel, lod)); } bool DerivedCoordVarStandardWRF_Terrain::ValidFormula(string formula) { return (DerivedCFVertCoordVar::ValidFormula(vector{"PH", "PHB"}, formula)); } ////////////////////////////////////////////////////////////////////////////// // // DerivedCoordVarStandardOceanSCoordinate // ////////////////////////////////////////////////////////////////////////////// // // Register class with object factory!!! // static DerivedCFVertCoordVarFactoryRegistrar registrar_ocean_s_coordinate_g1("ocean_s_coordinate_g1"); static DerivedCFVertCoordVarFactoryRegistrar registrar_ocean_s_coordinate_g2("ocean_s_coordinate_g2"); DerivedCoordVarStandardOceanSCoordinate::DerivedCoordVarStandardOceanSCoordinate(DC *dc, string mesh, string formula) : DerivedCFVertCoordVar("", dc, mesh, formula) { _standard_name = "ocean_s_coordinate_g1"; _sVar.clear(); _CVar.clear(); _etaVar.clear(); _depthVar.clear(); _depth_cVar.clear(); _CVarMV = std::numeric_limits::infinity(); _etaVarMV = std::numeric_limits::infinity(); _depthVarMV = std::numeric_limits::infinity(); _destaggerEtaXDim = false; _destaggerEtaYDim = false; _destaggerDepthXDim = false; _destaggerDepthYDim = false; } int DerivedCoordVarStandardOceanSCoordinate::initialize_missing_values() { DC::DataVar dataInfo; bool status = _dc->GetDataVarInfo(_CVar, dataInfo); if (!status) { SetErrMsg("Invalid variable \"%s\"", _CVar.c_str()); return (-1); } if (dataInfo.GetHasMissing()) _CVarMV = dataInfo.GetMissingValue(); status = _dc->GetDataVarInfo(_etaVar, dataInfo); if (!status) { SetErrMsg("Invalid variable \"%s\"", _etaVar.c_str()); return (-1); } if (dataInfo.GetHasMissing()) _etaVarMV = dataInfo.GetMissingValue(); status = _dc->GetDataVarInfo(_depthVar, dataInfo); if (!status) { SetErrMsg("Invalid variable \"%s\"", _depthVar.c_str()); return (-1); } if (dataInfo.GetHasMissing()) _depthVarMV = dataInfo.GetMissingValue(); return (0); } int DerivedCoordVarStandardOceanSCoordinate::initialize_stagger_flags() { vector derivedDims; bool status = _dc->GetMeshDimLens(_mesh, derivedDims); if (!status) { SetErrMsg("Invalid mesh \"%s\"", _mesh.c_str()); return (-1); } vector nativeDims; int rc = _dc->GetDimLens(_etaVar, nativeDims); if (rc < 0) return (-1); if (nativeDims[0] == derivedDims[0] - 1) _destaggerEtaXDim = true; if (nativeDims[1] == derivedDims[1] - 1) _destaggerEtaYDim = true; rc = _dc->GetDimLens(_depthVar, nativeDims); if (rc < 0) return (-1); if (nativeDims[0] == derivedDims[0] - 1) _destaggerDepthXDim = true; if (nativeDims[1] == derivedDims[1] - 1) _destaggerDepthYDim = true; return (0); } int DerivedCoordVarStandardOceanSCoordinate::Initialize() { map formulaMap; if (!ParseFormula(_formula, formulaMap)) { SetErrMsg("Invalid conversion formula \"%s\"", _formula.c_str()); return (-1); } map::const_iterator itr; VAssert((itr = formulaMap.find("s")) != formulaMap.end()); _sVar = itr->second; VAssert((itr = formulaMap.find("C")) != formulaMap.end()); _CVar = itr->second; VAssert((itr = formulaMap.find("eta")) != formulaMap.end()); _etaVar = itr->second; VAssert((itr = formulaMap.find("depth")) != formulaMap.end()); _depthVar = itr->second; VAssert((itr = formulaMap.find("depth_c")) != formulaMap.end()); _depth_cVar = itr->second; if (initialize_missing_values() < 0) return (-1); if (initialize_stagger_flags() < 0) return (-1); // Figure out if this is a Ocean s-coordinate, generic form 1, or // Ocean s-coordinate, generic form 2 // DC::CoordVar sInfo; bool status = _dc->GetCoordVarInfo(_sVar, sInfo); if (!status) { SetErrMsg("Invalid variable \"%s\"", _sVar.c_str()); return (-1); } DC::Attribute attr_name; if (!sInfo.GetAttribute("standard_name", attr_name)) { // Default to generic form 1 // _standard_name = "ocean_s_coordinate_g1"; } else { attr_name.GetValues(_standard_name); } // Use the eta variable to set up metadata for the derived variable // DC::DataVar etaInfo; status = _dc->GetDataVarInfo(_etaVar, etaInfo); if (!status) { SetErrMsg("Invalid variable \"%s\"", _etaVar.c_str()); return (-1); } string timeCoordVar = etaInfo.GetTimeCoordVar(); string timeDimName; if (!timeCoordVar.empty()) { DC::CoordVar cvarInfo; bool status = _dc->GetCoordVarInfo(timeCoordVar, cvarInfo); if (!status) { SetErrMsg("Invalid variable \"%s\"", timeCoordVar.c_str()); return (-1); } timeDimName = cvarInfo.GetTimeDimName(); } _derivedVarName = "Z_" + _sVar; vector dimnames; status = _dc->GetMeshDimNames(_mesh, dimnames); if (!status) { SetErrMsg("Invalid mesh \"%s\"", _mesh.c_str()); return (-1); } VAssert(dimnames.size() == 3); // We're deriving a 3D varible from 1D and 2D varibles. We arbitarily // use one of the 2D variables to configure metadata such as the // available compression ratios // _coordVarInfo = DC::CoordVar(_derivedVarName, "m", DC::XType::FLOAT, vector(3, false), 2, false, dimnames, timeDimName); return (0); } bool DerivedCoordVarStandardOceanSCoordinate::GetBaseVarInfo(DC::BaseVar &var) const { var = _coordVarInfo; return (true); } bool DerivedCoordVarStandardOceanSCoordinate::GetCoordVarInfo(DC::CoordVar &cvar) const { cvar = _coordVarInfo; return (true); } vector DerivedCoordVarStandardOceanSCoordinate::GetInputs() const { map formulaMap; bool ok = ParseFormula(_formula, formulaMap); VAssert(ok); vector inputs; for (auto it = formulaMap.begin(); it != formulaMap.end(); ++it) { inputs.push_back(it->second); } return (inputs); } int DerivedCoordVarStandardOceanSCoordinate::GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); vector dims2d, bs2d; int rc = _dc->GetDimLensAtLevel(_etaVar, -1, dims2d, bs2d); if (rc < 0) return (-1); vector dims1d, bs1d; rc = _dc->GetDimLensAtLevel(_sVar, -1, dims1d, bs1d); if (rc < 0) return (-1); dims_at_level = {dims2d[0], dims2d[1], dims1d[0]}; bs_at_level = {bs2d[0], bs2d[1], bs1d[0]}; return (0); } int DerivedCoordVarStandardOceanSCoordinate::OpenVariableRead(size_t ts, int level, int lod) { // Compression not supported // level = -1; lod = -1; DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod); return (_fileTable.AddEntry(f)); } int DerivedCoordVarStandardOceanSCoordinate::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } _fileTable.RemoveEntry(fd); delete f; return (0); } int DerivedCoordVarStandardOceanSCoordinate::ReadRegion(int fd, const vector &min, const vector &max, float *region) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); string varname = f->GetVarname(); vector dims, dummy; int rc = GetDimLensAtLevel(f->GetLevel(), dims, dummy); if (rc < 0) return (-1); vector s(dims[2]); vector myMin = {min[2]}; vector myMax = {max[2]}; rc = _getVar(_dc, f->GetTS(), _sVar, f->GetLevel(), f->GetLOD(), myMin, myMax, s.data()); if (rc < 0) return (rc); vector C(dims[2]); myMin = {min[2]}; myMax = {max[2]}; rc = _getVar(_dc, f->GetTS(), _CVar, f->GetLevel(), f->GetLOD(), myMin, myMax, C.data()); if (rc < 0) return (rc); vector eta(dims[0] * dims[1]); myMin = {min[0], min[1]}; myMax = {max[0], max[1]}; if (_destaggerEtaXDim) { rc = _getVarDestagger(_dc, f->GetTS(), _etaVar, f->GetLevel(), f->GetLOD(), myMin, myMax, eta.data(), 0); } else if (_destaggerEtaYDim) { rc = _getVarDestagger(_dc, f->GetTS(), _etaVar, f->GetLevel(), f->GetLOD(), myMin, myMax, eta.data(), 1); } else { rc = _getVar(_dc, f->GetTS(), _etaVar, f->GetLevel(), f->GetLOD(), myMin, myMax, eta.data()); } if (rc < 0) return (rc); vector depth(dims[0] * dims[1]); myMin = {min[0], min[1]}; myMax = {max[0], max[1]}; if (_destaggerDepthXDim) { rc = _getVarDestagger(_dc, f->GetTS(), _depthVar, f->GetLevel(), f->GetLOD(), myMin, myMax, depth.data(), 0); } else if (_destaggerDepthYDim) { rc = _getVarDestagger(_dc, f->GetTS(), _depthVar, f->GetLevel(), f->GetLOD(), myMin, myMax, depth.data(), 1); } else { rc = _getVar(_dc, f->GetTS(), _depthVar, f->GetLevel(), f->GetLOD(), myMin, myMax, depth.data()); } float depth_c; myMin = {}; myMax = {}; rc = _getVar(_dc, f->GetTS(), _depth_cVar, f->GetLevel(), f->GetLOD(), myMin, myMax, &depth_c); if (_standard_name == "ocean_s_coordinate_g1") { compute_g1(min, max, s.data(), C.data(), eta.data(), depth.data(), depth_c, region); } else { compute_g2(min, max, s.data(), C.data(), eta.data(), depth.data(), depth_c, region); } return (0); } bool DerivedCoordVarStandardOceanSCoordinate::VariableExists(size_t ts, int reflevel, int lod) const { return (_dc->VariableExists(ts, _sVar, reflevel, lod) && _dc->VariableExists(ts, _CVar, reflevel, lod) && _dc->VariableExists(ts, _etaVar, reflevel, lod) && _dc->VariableExists(ts, _depthVar, reflevel, lod) && _dc->VariableExists(ts, _depth_cVar, reflevel, lod)); } bool DerivedCoordVarStandardOceanSCoordinate::ValidFormula(string formula) { return (DerivedCFVertCoordVar::ValidFormula(vector{"s", "C", "eta", "depth", "depth_c"}, formula)); } void DerivedCoordVarStandardOceanSCoordinate::compute_g1(const vector &min, const vector &max, const float *s, const float *C, const float *eta, const float *depth, float depth_c, float *region) const { vector rDims; for (int i = 0; i < 3; i++) { rDims.push_back(max[i] - min[i] + 1); } for (size_t k = 0; k < max[2] - min[2] + 1; k++) { for (size_t j = 0; j < max[1] - min[1] + 1; j++) { for (size_t i = 0; i < max[0] - min[0] + 1; i++) { if (depth[j * rDims[0]] == 0.0) { region[k * rDims[0] * rDims[1] + j * rDims[0] + i] = 0.0; continue; } // We are deriving coordinate values from data values, so missing // values may be present // if (C[k] == _CVarMV || eta[j * rDims[0] + i] == _etaVarMV || depth[j * rDims[0] + i] == _depthVarMV) { region[k * rDims[0] * rDims[1] + j * rDims[0] + i] = 0.0; continue; } float tmp = depth_c * s[k] + (depth[j * rDims[0] + i] - depth_c) * C[k]; region[k * rDims[0] * rDims[1] + j * rDims[0] + i] = tmp + eta[j * rDims[0] + i] * (1 + tmp / depth[j * rDims[0] + i]); } } } } void DerivedCoordVarStandardOceanSCoordinate::compute_g2(const vector &min, const vector &max, const float *s, const float *C, const float *eta, const float *depth, float depth_c, float *region) const { vector rDims; for (int i = 0; i < 3; i++) { rDims.push_back(max[i] - min[i] + 1); } for (size_t k = 0; k < max[2] - min[2] + 1; k++) { for (size_t j = 0; j < max[1] - min[1] + 1; j++) { for (size_t i = 0; i < max[0] - min[0] + 1; i++) { if ((depth_c + depth[j * rDims[0]]) == 0.0) { region[k * rDims[0] * rDims[1] + j * rDims[0] + i] = 0.0; continue; } // We are deriving coordinate values from data values, so missing // values may be present // if (C[k] == _CVarMV || eta[j * rDims[0] + i] == _etaVarMV || depth[j * rDims[0] + i] == _depthVarMV) { region[k * rDims[0] * rDims[1] + j * rDims[0] + i] = 0.0; continue; } float tmp = (depth_c * s[k] + depth[j * rDims[0] + i] * C[k]) / (depth_c + depth[j * rDims[0] + i]); region[k * rDims[0] * rDims[1] + j * rDims[0] + i] = eta[j * rDims[0] + i] + (eta[j * rDims[0] + i] + depth[j * rDims[0] + i]) * tmp; } } } } ////////////////////////////////////////////////////////////////////////////// // // DerivedCoordVarStandardAHSPC // // Atmosphere Hybrid Sigma Pressure Coordinate // ////////////////////////////////////////////////////////////////////////////// // // Register class with object factory!!! // #ifdef VAPOR3_6_0 // // The atmosphere_hybrid_sigma_pressure_coordinate conversion from pressure // to meters unforunately results in a flipped (inverted?) vertical coordinate // system with logical grid indices increasing as user coordinates // decrease. I.e. Z[k] > Z[k+1]. In numerous places VAPOR // expects the grid index and associated vertical coordinate to be // monotonically increasing. This needs to be fixed as this assumption // often does not hold true. However it is a big lift. For now, just // remove the atmosphere_hybrid_sigma_pressure_coordinate converter from // the object factory. // static DerivedCFVertCoordVarFactoryRegistrar registrar_atmosphere_hybrid_sigma_pressure_coordinate("atmosphere_hybrid_sigma_pressure_coordinate"); #endif DerivedCoordVarStandardAHSPC::DerivedCoordVarStandardAHSPC(DC *dc, string mesh, string formula) : DerivedCFVertCoordVar("", dc, mesh, formula) { _standard_name = "atmosphere_hybrid_sigma_pressure_coordinate"; _aVar.clear(); _apVar.clear(); _bVar.clear(); _p0Var.clear(); _psVar.clear(); _psVarMV = std::numeric_limits::infinity(); } int DerivedCoordVarStandardAHSPC::initialize_missing_values() { DC::DataVar dataInfo; bool status = _dc->GetDataVarInfo(_psVar, dataInfo); if (!status) { SetErrMsg("Invalid variable \"%s\"", _psVar.c_str()); return (-1); } if (dataInfo.GetHasMissing()) _psVarMV = dataInfo.GetMissingValue(); return (0); } int DerivedCoordVarStandardAHSPC::Initialize() { map formulaMap; if (!ParseFormula(_formula, formulaMap)) { SetErrMsg("Invalid conversion formula \"%s\"", _formula.c_str()); return (-1); } // There are two possible formulations, one with 'ap', and one // with 'a' and 'p0' // map::const_iterator itr; VAssert((itr = formulaMap.find("a")) != formulaMap.end()); if (itr != formulaMap.end()) { _aVar = itr->second; VAssert((itr = formulaMap.find("p0")) != formulaMap.end()); _p0Var = itr->second; } else { VAssert((itr = formulaMap.find("ap")) != formulaMap.end()); _apVar = itr->second; } VAssert((itr = formulaMap.find("b")) != formulaMap.end()); _bVar = itr->second; VAssert((itr = formulaMap.find("ps")) != formulaMap.end()); _psVar = itr->second; if (initialize_missing_values() < 0) return (-1); // Use the 'b' and 'ps' variables to set up metadata for the derived // variable // DC::DataVar bInfo; bool status = _dc->GetDataVarInfo(_bVar, bInfo); if (!status) { SetErrMsg("Invalid variable \"%s\"", _bVar.c_str()); return (-1); } DC::DataVar psInfo; status = _dc->GetDataVarInfo(_psVar, psInfo); if (!status) { SetErrMsg("Invalid variable \"%s\"", _psVar.c_str()); return (-1); } // Construct spatial and temporal dimensions from the 1D 'b' // variable and 2D, time-varying 'ps' variable // DC::Mesh m; status = _dc->GetMesh(psInfo.GetMeshName(), m); if (!status) { SetErrMsg("Invalid mesh \"%s\"", _mesh.c_str()); return (-1); } vector dimnames = m.GetDimNames(); status = _dc->GetMesh(bInfo.GetMeshName(), m); if (!status) { SetErrMsg("Invalid mesh \"%s\"", _mesh.c_str()); return (-1); } dimnames.push_back(m.GetDimNames()[0]); string timeCoordVar = psInfo.GetTimeCoordVar(); string timeDimName; if (!timeCoordVar.empty()) { DC::CoordVar cvarInfo; bool status = _dc->GetCoordVarInfo(timeCoordVar, cvarInfo); if (!status) { SetErrMsg("Invalid variable \"%s\"", timeCoordVar.c_str()); return (-1); } timeDimName = cvarInfo.GetTimeDimName(); } // We're deriving a 3D varible from 1D and 2D varibles. We arbitarily // use one of the 2D variables to configure metadata such as the // available compression ratios // _derivedVarName = "Z_" + _bVar; _coordVarInfo = DC::CoordVar(_derivedVarName, "m", DC::XType::FLOAT, vector(3, false), 2, false, dimnames, timeDimName); return (0); } bool DerivedCoordVarStandardAHSPC::GetBaseVarInfo(DC::BaseVar &var) const { var = _coordVarInfo; return (true); } bool DerivedCoordVarStandardAHSPC::GetCoordVarInfo(DC::CoordVar &cvar) const { cvar = _coordVarInfo; return (true); } vector DerivedCoordVarStandardAHSPC::GetInputs() const { map formulaMap; bool ok = ParseFormula(_formula, formulaMap); VAssert(ok); vector inputs; for (auto it = formulaMap.begin(); it != formulaMap.end(); ++it) { inputs.push_back(it->second); } return (inputs); } int DerivedCoordVarStandardAHSPC::GetDimLensAtLevel(int level, std::vector &dims_at_level, std::vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); vector dims2d, bs2d; int rc = _dc->GetDimLensAtLevel(_psVar, -1, dims2d, bs2d); if (rc < 0) return (-1); vector dims1d, bs1d; rc = _dc->GetDimLensAtLevel(_bVar, -1, dims1d, bs1d); if (rc < 0) return (-1); dims_at_level = {dims2d[0], dims2d[1], dims1d[0]}; bs_at_level = {bs2d[0], bs2d[1], bs1d[0]}; return (0); } int DerivedCoordVarStandardAHSPC::OpenVariableRead(size_t ts, int level, int lod) { // We don't support compressed data // level = -1; lod = -1; DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod); return (_fileTable.AddEntry(f)); } int DerivedCoordVarStandardAHSPC::CloseVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } _fileTable.RemoveEntry(fd); delete f; return (0); } int DerivedCoordVarStandardAHSPC::ReadRegion(int fd, const vector &min, const vector &max, float *region) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); vector dims, dummy; int rc = GetDimLensAtLevel(f->GetLevel(), dims, dummy); if (rc < 0) return (-1); string aVar = _aVar.empty() ? _apVar : _aVar; vector a(dims[2]); vector myMin = {min[2]}; vector myMax = {max[2]}; rc = _getVar(_dc, f->GetTS(), aVar, f->GetLevel(), f->GetLOD(), myMin, myMax, a.data()); if (rc < 0) return (rc); vector b(dims[2]); myMin = {min[2]}; myMax = {max[2]}; rc = _getVar(_dc, f->GetTS(), _bVar, f->GetLevel(), f->GetLOD(), myMin, myMax, b.data()); if (rc < 0) return (rc); vector ps(dims[0] * dims[1]); myMin = {min[0], min[1]}; myMax = {max[0], max[1]}; rc = _getVar(_dc, f->GetTS(), _psVar, f->GetLevel(), f->GetLOD(), myMin, myMax, ps.data()); if (rc < 0) return (rc); float p0 = 1.0; if (!_aVar.empty()) { myMin = {}; myMax = {}; rc = _getVar(_dc, f->GetTS(), _p0Var, f->GetLevel(), f->GetLOD(), myMin, myMax, &p0); } compute_a(min, max, a.data(), b.data(), ps.data(), p0, region); return (0); } bool DerivedCoordVarStandardAHSPC::VariableExists(size_t ts, int reflevel, int lod) const { if (!_aVar.empty()) { return (_dc->VariableExists(ts, _aVar, reflevel, lod) && _dc->VariableExists(ts, _bVar, reflevel, lod) && _dc->VariableExists(ts, _psVar, reflevel, lod)); } else { return (_dc->VariableExists(ts, _apVar, reflevel, lod) && _dc->VariableExists(ts, _bVar, reflevel, lod) && _dc->VariableExists(ts, _psVar, reflevel, lod) && _dc->VariableExists(ts, _p0Var, reflevel, lod)); } } bool DerivedCoordVarStandardAHSPC::ValidFormula(string formula) { return (DerivedCFVertCoordVar::ValidFormula(vector{"a", "b", "p0", "ps"}, formula) || DerivedCFVertCoordVar::ValidFormula(vector{"ap", "b", "ps"}, formula)); } void DerivedCoordVarStandardAHSPC::compute_a(const vector &min, const vector &max, const float *a, const float *b, const float *ps, float p0, float *region) const { vector rDims; for (int i = 0; i < 3; i++) { rDims.push_back(max[i] - min[i] + 1); } for (size_t k = 0; k < max[2] - min[2] + 1; k++) { for (size_t j = 0; j < max[1] - min[1] + 1; j++) { for (size_t i = 0; i < max[0] - min[0] + 1; i++) { // We are deriving coordinate values from data values, so missing // values may be present // float l_ps = ps[j * rDims[0] + i]; if (l_ps == _psVarMV) l_ps = 0; float pressure = (a[k] * p0) + (b[k] * l_ps); // Convert from pressure to meters above the ground: // [1] "A Quick Derivation relating altitude to air pressure" from // Portland State Aerospace Society, Version 1.03, 12/22/2004. // region[k * rDims[0] * rDims[1] + j * rDims[0] + i] = 44331.5 - (4946.62 * std::pow(pressure, 0.190263)); } } } } ================================================ FILE: lib/vdc/DerivedVarMgr.cpp ================================================ #include "vapor/VAssert.h" #include #include "vapor/DerivedVarMgr.h" using namespace VAPoR; DerivedVarMgr::DerivedVarMgr() {} int DerivedVarMgr::initialize(const std::vector &, const std::vector &) { return (0); } void DerivedVarMgr::AddCoordVar(DerivedCoordVar *cvar) { _coordVars[cvar->GetName()] = cvar; _vars[cvar->GetName()] = cvar; } void DerivedVarMgr::AddDataVar(DerivedDataVar *dvar) { _dataVars[dvar->GetName()] = dvar; _vars[dvar->GetName()] = dvar; } void DerivedVarMgr::RemoveVar(const DerivedVar *var) { bool done = false; while (!done) { map::iterator itr; done = true; for (itr = _vars.begin(); itr != _vars.end(); ++itr) { if (itr->second == var) { _vars.erase(itr); done = false; break; } } } done = false; while (!done) { map::iterator itr; done = true; for (itr = _coordVars.begin(); itr != _coordVars.end(); ++itr) { if (itr->second == var) { _coordVars.erase(itr); done = false; break; } } } done = false; while (!done) { map::iterator itr; done = true; for (itr = _dataVars.begin(); itr != _dataVars.end(); ++itr) { if (itr->second == var) { _dataVars.erase(itr); done = false; break; } } } } void DerivedVarMgr::AddMesh(const Mesh &m) { _meshes[m.GetName()] = m; } DerivedVar *DerivedVarMgr::GetVar(string varname) const { DerivedVar *var = _getDataVar(varname); if (var) return (var); var = _getCoordVar(varname); if (var) return (var); return (NULL); } std::vector DerivedVarMgr::getMeshNames() const { std::map::const_iterator itr; vector names; for (itr = _meshes.begin(); itr != _meshes.end(); ++itr) { names.push_back(itr->first); } return (names); } bool DerivedVarMgr::getMesh(string mesh_name, DC::Mesh &mesh) const { std::map::const_iterator itr; itr = _meshes.find(mesh_name); if (itr == _meshes.end()) return (false); mesh = itr->second; return (true); } bool DerivedVarMgr::getCoordVarInfo(string varname, DC::CoordVar &cvarInfo) const { DerivedCoordVar *dvar = _getCoordVar(varname); if (!dvar) return (false); return (dvar->GetCoordVarInfo(cvarInfo)); } bool DerivedVarMgr::getDataVarInfo(string varname, DC::DataVar &dvarInfo) const { DerivedDataVar *dvar = _getDataVar(varname); if (!dvar) return (false); return (dvar->GetDataVarInfo(dvarInfo)); } bool DerivedVarMgr::getBaseVarInfo(string varname, DC::BaseVar &varInfo) const { DerivedVar *var = _getVar(varname); if (!var) return (false); return (var->GetBaseVarInfo(varInfo)); } std::vector DerivedVarMgr::getDataVarNames() const { ; map::const_iterator itr; vector names; for (itr = _dataVars.begin(); itr != _dataVars.end(); ++itr) { names.push_back(itr->first); } return (names); } std::vector DerivedVarMgr::getCoordVarNames() const { ; map::const_iterator itr; vector names; for (itr = _coordVars.begin(); itr != _coordVars.end(); ++itr) { names.push_back(itr->first); } return (names); } size_t DerivedVarMgr::getNumRefLevels(string varname) const { DerivedVar *var = _getVar(varname); if (!var) return (0); return (var->GetNumRefLevels()); } bool DerivedVarMgr::getAtt(string varname, string attname, vector &values) const { DerivedVar *var = _getVar(varname); if (!var) return (false); return (var->GetAtt(attname, values)); } bool DerivedVarMgr::getAtt(string varname, string attname, vector &values) const { DerivedVar *var = _getVar(varname); if (!var) return (false); return (var->GetAtt(attname, values)); } bool DerivedVarMgr::getAtt(string varname, string attname, string &values) const { DerivedVar *var = _getVar(varname); if (!var) return (false); return (var->GetAtt(attname, values)); } std::vector DerivedVarMgr::getAttNames(string varname) const { DerivedVar *var = _getVar(varname); if (!var) return (vector()); return (var->GetAttNames()); } DC::XType DerivedVarMgr::getAttType(string varname, string attname) const { DerivedVar *var = _getVar(varname); if (!var) return (DC::INVALID); return (var->GetAttType(attname)); } int DerivedVarMgr::getDimLensAtLevel(string varname, int level, std::vector &dims_at_level, std::vector &bs_at_level) const { DerivedVar *var = _getVar(varname); if (!var) return (-1); return (var->GetDimLensAtLevel(level, dims_at_level, bs_at_level)); } int DerivedVarMgr::openVariableRead(size_t ts, string varname, int level, int lod) { DerivedVar *var = _getVar(varname); if (!var) { SetErrMsg("Invalid variable : %s", varname.c_str()); return (-1); } int fd = var->OpenVariableRead(ts, level, lod); if (fd < 0) return (fd); DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, varname, level, lod, fd); return (_fileTable.AddEntry(f)); } int DerivedVarMgr::closeVariable(int fd) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } string varname = f->GetVarname(); DerivedVar *var = _getVar(varname); if (!var) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int derivedFD = f->GetAux(); _fileTable.RemoveEntry(fd); delete f; return (var->CloseVariable(derivedFD)); } int DerivedVarMgr::readRegion(int fd, const vector &min, const vector &max, double *region) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } string varname = f->GetVarname(); DerivedVar *var = _getVar(varname); if (!var) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int derivedFD = f->GetAux(); return (var->ReadRegion(derivedFD, min, max, region)); } int DerivedVarMgr::readRegion(int fd, const vector &min, const vector &max, float *region) { DC::FileTable::FileObject *f = _fileTable.GetEntry(fd); if (!f) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } string varname = f->GetVarname(); DerivedVar *var = _getVar(varname); if (!var) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int derivedFD = f->GetAux(); return (var->ReadRegion(derivedFD, min, max, region)); } bool DerivedVarMgr::variableExists(size_t ts, string varname, int reflevel, int lod) const { DerivedVar *var = _getVar(varname); if (!var) return (false); return (var->VariableExists(ts, reflevel, lod)); } DerivedVar *DerivedVarMgr::_getVar(string name) const { map::const_iterator itr; itr = _vars.find(name); if (itr == _vars.end()) return (NULL); return (itr->second); } DerivedDataVar *DerivedVarMgr::_getDataVar(string name) const { map::const_iterator itr; itr = _dataVars.find(name); if (itr == _dataVars.end()) return (NULL); return (itr->second); } DerivedCoordVar *DerivedVarMgr::_getCoordVar(string name) const { map::const_iterator itr; itr = _coordVars.find(name); if (itr == _coordVars.end()) return (NULL); return (itr->second); } ================================================ FILE: lib/vdc/GeoUtil.cpp ================================================ #include #include #include #include using namespace std; using namespace VAPoR; namespace { template void _minmax(const T *a, int n, int stride, T &min, T &max) { min = max = a[0]; for (int i = 0; i < n; i++) { if (a[i * stride] < min) min = a[i * stride]; if (a[i * stride] > max) max = a[i * stride]; } } // // Shift 1D array of longitudes, if needed, such that values // are in the specified range, typically [-360.0..360.0] or [-180.0..180.0] // template void shiftLonTemplate(ForwardIt first, ForwardIt last, double bound) { for (auto itr = first; itr != last; ++itr) { while (*itr > bound) *itr -= 360.0; } for (auto itr = first; itr != last; ++itr) { while (*itr < (-1 * bound)) *itr += 360.0; } } // // Make longitude values monotonically increasing // template void unwrapLongitudeTemplate(ForwardIt first, ForwardIt last) { auto itr = first; if (itr == last) return; auto startValue = *itr; ++itr; for (; itr != last; ++itr) { while (*itr < startValue) { *itr += 360.0; } } } template void _ExtractBoundaryTemplate(const T *a, int nx, int ny, T *bdry) { T *bdryptr = bdry; for (int i = 0; i < nx; i++) *bdryptr++ = a[i]; for (int j = 1; j < ny; j++) *bdryptr++ = a[nx * j + nx - 1]; for (int i = nx - 2; i >= 0; i--) *bdryptr++ = a[nx * (ny - 1) + i]; for (int j = ny - 2; j >= 1; j--) *bdryptr++ = a[j * nx]; } }; // namespace void GeoUtil::ShiftLon(vector::iterator first, vector::iterator last, double bound) { shiftLonTemplate(first, last, bound); } void GeoUtil::ShiftLon(vector::iterator first, vector::iterator last, double bound) { shiftLonTemplate(first, last, bound); } void GeoUtil::ShiftLon(float *first, float *last, double bound) { shiftLonTemplate(first, last, bound); } void GeoUtil::UnwrapLongitude(vector::iterator first, vector::iterator last) { unwrapLongitudeTemplate(first, last); } void GeoUtil::UnwrapLongitude(vector::iterator first, vector::iterator last) { unwrapLongitudeTemplate(first, last); } void GeoUtil::UnwrapLongitude(float *first, float *last) { unwrapLongitudeTemplate(first, last); } void GeoUtil::ExtractBoundary(const float *a, int nx, int ny, float *bdry) { _ExtractBoundaryTemplate(a, nx, ny, bdry); } void GeoUtil::ExtractBoundary(const double *a, int nx, int ny, double *bdry) { _ExtractBoundaryTemplate(a, nx, ny, bdry); } ================================================ FILE: lib/vdc/Grid.cpp ================================================ #include #include #include "vapor/VAssert.h" #include #include #include #include #include #ifdef Darwin #include #endif #ifdef _WINDOWS #include "windows.h" #include "Winbase.h" #include #endif #include #include #include using namespace std; using namespace VAPoR; namespace { // Check for point on a quadralateral vertex // bool interpolate_point_on_node(const std::array &verts, double xwgt, double ywgt, float mv, float &v) { if (xwgt == 1.0 && ywgt == 1.0) { v = verts[0]; return (true); } if (xwgt == 0.0 && ywgt == 1.0) { v = verts[1]; return (true); } if (xwgt == 1.0 && ywgt == 0.0) { v = verts[2]; return (true); } if (xwgt == 0.0 && ywgt == 0.0) { v = verts[3]; return (true); } return (false); } // Check for point on a quad edge, linear interplate along edge if found // bool interpolate_point_on_edge(const std::array &verts, double xwgt, double ywgt, float mv, float &v) { // X edge, bottom // if (ywgt == 1.0 && xwgt > 0.0 && xwgt < 1.0 && verts[0] != mv && verts[1] != mv) { v = (verts[0] * xwgt) + (verts[1] * (1.0 - xwgt)); return (true); } // Y edge, right // if (xwgt == 0.0 && ywgt > 0.0 && ywgt < 1.0 && verts[1] != mv && verts[3] != mv) { v = (verts[1] * ywgt) + (verts[3] * (1.0 - ywgt)); return (true); } // X edge, top // if (ywgt == 0.0 && xwgt > 0.0 && xwgt < 1.0 && verts[2] != mv && verts[3] != mv) { v = (verts[2] * xwgt) + (verts[3] * (1.0 - xwgt)); return (true); } // Y edge, left // if (xwgt == 1.0 && ywgt > 0.0 && ywgt < 1.0 && verts[0] != mv && verts[2] != mv) { v = (verts[0] * ywgt) + (verts[2] * (1.0 - ywgt)); return (true); } return (false); } } // namespace Grid::Grid() { _dims = {1, 1, 1}; } void Grid::_grid(const DimsType &dims, const DimsType &bs, const std::vector &blks, size_t topology_dimension) { for (int i = 0; i < bs.size(); i++) { VAssert(bs[i] > 0); VAssert(dims[i] > 0); _bdims[i] = ((dims[i] - 1) / bs[i]) + 1; _bs[i] = bs[i]; _bdimsDeprecated.push_back(_bdims[i]); _bsDeprecated.push_back(_bs[i]); } VAssert(blks.size() == 0 || // dataless blks.size() == std::accumulate(_bdims.begin(), _bdims.end(), 1, std::multiplies())); _dims = dims; _periodic = vector(topology_dimension, false); _topologyDimension = topology_dimension; _missingValue = INFINITY; _hasMissing = false; _nodeIDOffset = 0; _cellIDOffset = 0; _minAbs = {0, 0, 0}; // // Shallow copy blocks // _blks = blks; } Grid::Grid(const DimsType &dims, const DimsType &bs, const std::vector &blks, size_t topology_dimension) { _grid(dims, bs, blks, topology_dimension); } Grid::Grid(const std::vector &dimsv, const std::vector &bsv, const std::vector &blks, size_t topology_dimension) { VAssert(dimsv.size() <= 3); VAssert(dimsv.size() == bsv.size()); DimsType dims = {1, 1, 1}; DimsType bs = {1, 1, 1}; CopyToArr3(dimsv, dims); CopyToArr3(bsv, bs); _grid(dims, bs, blks, topology_dimension); } size_t Grid::GetNumDimensions(DimsType dims) { size_t nDims = 0; for (size_t i = 0; i < dims.size(); i++) { VAssert(dims[i] > 0); if (dims[i] > 1) nDims++; } return (nDims); } float Grid::GetMissingValue() const { return (_missingValue); } void Grid::GetUserExtents(CoordType &minu, CoordType &maxu) const { size_t n = min(GetGeometryDim(), _minuCache.size()); auto p = [](double v) { return (v == std::numeric_limits::infinity()); }; if (std::any_of(_minuCache.begin(), _minuCache.begin() + n, p) || std::any_of(_maxuCache.begin(), _maxuCache.begin() + n, p)) { _minuCache = {0.0, 0.0, 0.0}; _maxuCache = {0.0, 0.0, 0.0}; GetUserExtentsHelper(_minuCache, _maxuCache); } minu = _minuCache; maxu = _maxuCache; } float Grid::GetValueAtIndex(const DimsType &indices) const { float *fptr = GetValuePtrAtIndex(_blks, indices); if (!fptr) return (GetMissingValue()); return (*fptr); } void Grid::SetValue(const DimsType &indices, float v) { float *fptr = GetValuePtrAtIndex(_blks, indices); if (!fptr) return; *fptr = v; } float *Grid::GetValuePtrAtIndex(const std::vector &blks, const DimsType &indices) const { if (!blks.size()) return (NULL); DimsType cIndices; ClampIndex(indices, cIndices); size_t xb = cIndices[0] / _bs[0]; size_t yb = cIndices[1] / _bs[1]; size_t zb = cIndices[2] / _bs[2]; size_t x = cIndices[0] % _bs[0]; size_t y = cIndices[1] % _bs[1]; size_t z = cIndices[2] % _bs[2]; float *blk = blks[zb * _bdims[0] * _bdims[1] + yb * _bdims[0] + xb]; return (&blk[z * _bs[0] * _bs[1] + y * _bs[0] + x]); } float Grid::AccessIJK(size_t i, size_t j, size_t k) const { DimsType indices = {i, j, k}; return (GetValueAtIndex(indices)); } void Grid::SetValueIJK(size_t i, size_t j, size_t k, float v) { DimsType indices = {i, j, k}; return (SetValue(indices, v)); } void Grid::GetRange(float range[2]) const { const auto missingVal = GetMissingValue(); const auto num_vals = _dims[0] * _dims[1] * _dims[2]; auto num_threads = size_t{1}; #pragma omp parallel { if (omp_get_thread_num() == 0) num_threads = omp_get_num_threads(); } const auto stride_size = num_vals / num_threads; auto min_vec = std::vector(num_threads, missingVal); auto max_vec = std::vector(num_threads, missingVal); #pragma omp parallel for for (size_t i = 0; i < num_threads; i++) { auto beg = this->cbegin() + i * stride_size; auto end = beg; if (i < num_threads - 1) end += stride_size; else end = this->cend(); while (*beg == missingVal && beg != end) ++beg; if (beg != end) { auto min = *beg; auto max = *beg; for (auto itr = beg + 1; itr != end; ++itr) { if (*itr != missingVal) { min = std::min(*itr, min); max = std::max(*itr, max); } } min_vec[i] = min; max_vec[i] = max; } } // finish omp section if (std::all_of(min_vec.begin(), min_vec.end(), [missingVal](float v){return v == missingVal;})) { range[0] = missingVal; range[1] = missingVal; } else { auto it = std::remove(min_vec.begin(), min_vec.end(), missingVal); range[0] = *std::min_element(min_vec.begin(), it); it = std::remove(max_vec.begin(), max_vec.end(), missingVal); range[1] = *std::max_element(max_vec.begin(), it); } } void Grid::GetRange(const DimsType &min, const DimsType &max, float range[2]) const { DimsType cMin; ClampIndex(min, cMin); DimsType cMax; ClampIndex(max, cMax); float mv = GetMissingValue(); range[0] = range[1] = mv; bool first = true; for (size_t k = cMin[2]; k <= cMax[2]; k++) { for (size_t j = cMin[1]; j <= cMax[1]; j++) { for (size_t i = cMin[0]; i <= cMax[0]; i++) { float v = AccessIJK(i, j, k); if (first && v != mv) { range[0] = range[1] = v; first = false; } if (!first) { if (v < range[0] && v != mv) range[0] = v; else if (v > range[1] && v != mv) range[1] = v; } } } } } float Grid::GetValue(const CoordType &coords) const { if (!_blks.size()) return (GetMissingValue()); // Clamp coordinates on periodic boundaries to grid extents // CoordType cCoords; ClampCoord(coords, cCoords); if (_interpolationOrder == 0) { return (GetValueNearestNeighbor(cCoords)); } else { return (GetValueLinear(cCoords)); } } void Grid::GetUserCoordinates(size_t i, double &x, double &y, double &z) const { x = y = z = 0.0; vector indices = {i}; vector coords; GetUserCoordinates(indices, coords); x = coords[0]; y = coords[1]; z = coords[2]; } void Grid::GetUserCoordinates(size_t i, size_t j, double &x, double &y, double &z) const { x = y = z = 0.0; vector indices = {i, j}; vector coords; GetUserCoordinates(indices, coords); x = coords[0]; y = coords[1]; z = coords[2]; } void Grid::GetUserCoordinates(size_t i, size_t j, size_t k, double &x, double &y, double &z) const { x = y = z = 0.0; vector indices = {i, j, k}; vector coords; GetUserCoordinates(indices, coords); x = coords[0]; y = coords[1]; z = coords[2]; } void Grid::SetInterpolationOrder(int order) { if (order < 0 || order > 2) order = 1; _interpolationOrder = order; } DimsType Grid::Dims(const DimsType &min, const DimsType &max) { DimsType dims; for (int i = 0; i < min.size(); i++) { dims[i] = (max[i] - min[i] + 1); } return (dims); } float Grid::BilinearInterpolate(size_t i, size_t j, size_t k, const double xwgt, const double ywgt) const { auto dims = GetDimensions(); VAssert(i < dims[0]); VAssert(j < dims[1]); VAssert(k < dims[2]); float mv = GetMissingValue(); std::array verts{0.0, 0.0, 0.0, 0.0}; verts[0] = AccessIJK(i, j, k); verts[1] = dims[0] > 1 ? AccessIJK(i + 1, j, k) : 0.0; verts[2] = dims[1] > 1 ? AccessIJK(i, j + 1, k) : 0.0; verts[3] = dims[0] > 1 && dims[1] > 1 ? AccessIJK(i + 1, j + 1, k) : 0.0; if (std::any_of(verts.begin(), verts.end(), [&mv](float v) { return (mv == v); })) { float v = 0.0; if (interpolate_point_on_node(verts, xwgt, ywgt, mv, v)) return (v); if (interpolate_point_on_edge(verts, xwgt, ywgt, mv, v)) return (v); return (mv); } return (((verts[0] * xwgt + verts[1] * (1.0 - xwgt)) * ywgt) + ((verts[2] * xwgt + verts[3] * (1.0 - xwgt)) * (1.0 - ywgt))); } float Grid::TrilinearInterpolate(size_t i, size_t j, size_t k, const double xwgt, const double ywgt, const double zwgt) const { auto dims = GetDimensions(); VAssert(i < dims[0]); VAssert(j < dims[1]); VAssert(k < dims[2]); float mv = GetMissingValue(); float v0 = BilinearInterpolate(i, j, k, xwgt, ywgt); if (dims[2] > 1 && k < (dims[2] - 1)) k++; else return (v0); float v1 = BilinearInterpolate(i, j, k, xwgt, ywgt); if (v0 == mv || v1 == mv) { if (zwgt == 1.0) return (v0); else if (zwgt == 0.0) return (v1); else return (mv); } // Linearly interpolate along Z axis // return (v0 * zwgt + v1 * (1.0 - zwgt)); } ///////////////////////////////////////////////////////////////////////////// // // Iterators // ///////////////////////////////////////////////////////////////////////////// Grid::ConstNodeIteratorSG::ConstNodeIteratorSG(const Grid *g, bool begin) : ConstNodeIteratorAbstract() { _dims = g->GetNodeDimensions(); _index = {0, 0, 0}; _lastIndex = {0, 0, _dims[_dims.size() - 1]}; if (!begin) { _index = _lastIndex; } } Grid::ConstNodeIteratorSG::ConstNodeIteratorSG(const ConstNodeIteratorSG &rhs) : ConstNodeIteratorAbstract() { _dims = rhs._dims; _index = rhs._index; _lastIndex = rhs._lastIndex; } Grid::ConstNodeIteratorSG::ConstNodeIteratorSG() : ConstNodeIteratorAbstract() { _dims = {1, 1, 1}; _index = {0, 0, 0}; _lastIndex = {0, 0, 0}; } void Grid::ConstNodeIteratorSG::next() { _index[0]++; if (_index[0] < _dims[0]) { return; } _index[0] = 0; _index[1]++; if (_index[1] < _dims[1]) { return; } _index[1] = 0; _index[2]++; if (_index[2] < _dims[2]) { return; } _index[2] = _dims[2]; // last index; } void Grid::ConstNodeIteratorSG::next(const long &offset) { if (!_index.size()) return; long maxIndexL = Wasp::VProduct(_dims.data(), _dims.size()) - 1; long newIndexL = Wasp::LinearizeCoords(_index.data(), _dims.data(), _dims.size()) + offset; if (newIndexL < 0) { newIndexL = 0; } if (newIndexL > maxIndexL) { _index = _lastIndex; return; } Wasp::VectorizeCoords(newIndexL, _dims.data(), _index.data(), _dims.size()); } Grid::ConstNodeIteratorBoxSG::ConstNodeIteratorBoxSG(const Grid *g, const CoordType &minu, const CoordType &maxu) : ConstNodeIteratorSG(g, true), _pred(minu, maxu) { _coordItr = g->ConstCoordBegin(); // Advance to first node inside box // if (!_pred(*_coordItr)) { next(); } } Grid::ConstNodeIteratorBoxSG::ConstNodeIteratorBoxSG(const ConstNodeIteratorBoxSG &rhs) : ConstNodeIteratorSG() { _coordItr = rhs._coordItr; _pred = rhs._pred; } Grid::ConstNodeIteratorBoxSG::ConstNodeIteratorBoxSG() : ConstNodeIteratorSG() {} void Grid::ConstNodeIteratorBoxSG::next() { do { ConstNodeIteratorSG::next(); ++_coordItr; } while (_index != _lastIndex && !_pred(*_coordItr)); } void Grid::ConstNodeIteratorBoxSG::next(const long &offset) { _coordItr += offset; while (_index != _lastIndex && !_pred(*_coordItr)) { ConstNodeIteratorSG::next(); ++_coordItr; } } Grid::ConstCellIteratorSG::ConstCellIteratorSG(const Grid *g, bool begin) : ConstCellIteratorAbstract() { _dims = g->GetCellDimensions(); _index = {0, 0, 0}; _lastIndex = {0, 0, _dims[_dims.size() - 1]}; if (!begin) { _index = _lastIndex; } } Grid::ConstCellIteratorSG::ConstCellIteratorSG(const ConstCellIteratorSG &rhs) : ConstCellIteratorAbstract() { _dims = rhs._dims; _index = rhs._index; _lastIndex = rhs._lastIndex; } Grid::ConstCellIteratorSG::ConstCellIteratorSG() : ConstCellIteratorAbstract() { _dims = {1, 1, 1}; _index = {0, 0, 0}; _lastIndex = {0, 0, 0}; } void Grid::ConstCellIteratorSG::next() { _index[0]++; if (_index[0] < (_dims[0])) { return; } _index[0] = 0; _index[1]++; if (_index[1] < (_dims[1])) { return; } _index[1] = 0; _index[2]++; if (_index[2] < (_dims[2])) { return; } _index[2] = _dims[2]; // last index; } void Grid::ConstCellIteratorSG::next(const long &offset) { long maxIndexL = Wasp::VProduct(_dims.data(), _dims.size()) - 1; long newIndexL = Wasp::LinearizeCoords(_index.data(), _dims.data(), _dims.size()) + offset; if (newIndexL < 0) { newIndexL = 0; } if (newIndexL > maxIndexL) { _index = _lastIndex; return; } Wasp::VectorizeCoords(newIndexL, _dims.data(), _index.data(), _dims.size()); } bool Grid::ConstCellIteratorBoxSG::_cellInsideBox(const size_t cindices[]) const { return (true); } Grid::ConstCellIteratorBoxSG::ConstCellIteratorBoxSG(const Grid *g, const CoordType &minu, const CoordType &maxu) : ConstCellIteratorSG(g, true), _pred(minu, maxu) { _g = g; // Advance to first node inside box // if (!_cellInsideBox(_index.data())) { next(); } } Grid::ConstCellIteratorBoxSG::ConstCellIteratorBoxSG(const ConstCellIteratorBoxSG &rhs) : ConstCellIteratorSG() { _pred = rhs._pred; } Grid::ConstCellIteratorBoxSG::ConstCellIteratorBoxSG() : ConstCellIteratorSG() {} void Grid::ConstCellIteratorBoxSG::next() { do { ConstCellIteratorSG::next(); } while (!_cellInsideBox(_index.data()) && _index != _lastIndex); } void Grid::ConstCellIteratorBoxSG::next(const long &offset) { long count = offset; while (!_cellInsideBox(_index.data()) && _index != _lastIndex && count > 0) { ConstCellIteratorSG::next(); count--; } } // // // Iterators // // template Grid::ForwardIterator::ForwardIterator(T *rg, bool begin, const CoordType &minu, const CoordType &maxu) : _pred(minu, maxu) { _blks = rg->GetBlks(); _dims3d = rg->GetDimensions(); _bdims3d = {1, 1, 1}; _bs3d = {1, 1, 1}; CopyToArr3(rg->GetDimensionInBlks(), _bdims3d); CopyToArr3(rg->GetBlockSize(), _bs3d); _blocksize = Wasp::VProduct(_bs3d.data(), _bs3d.size()); _index = {0, 0, 0}; _lastIndex = {0, 0, _dims3d[_dims3d.size() - 1]}; if (!begin || !_blks.size()) { _index = _lastIndex; _itr = nullptr; _coordItr = rg->ConstCoordEnd(); return; } _coordItr = rg->ConstCoordBegin(); _xb = 0; _itr = &_blks[0][0]; if (!_pred(*_coordItr)) { operator++(); } } template Grid::ForwardIterator::ForwardIterator(ForwardIterator &&rhs) { _blks = rhs._blks; _dims3d = rhs._dims3d; _bdims3d = rhs._bdims3d; _bs3d = rhs._bs3d; _blocksize = rhs._blocksize; _coordItr = std::move(rhs._coordItr); _index = rhs._index; _lastIndex = rhs._lastIndex; _xb = rhs._xb; _itr = rhs._itr; rhs._itr = nullptr; _pred = rhs._pred; } template Grid::ForwardIterator::ForwardIterator() { _blks.clear(); _dims3d = {1, 1, 1}; _bdims3d = {1, 1, 1}; _bs3d = {1, 1, 1}; _blocksize = 1; _index = {0, 0, 0}; _lastIndex = {0, 0, 0}; _xb = 0; _itr = nullptr; } template Grid::ForwardIterator &Grid::ForwardIterator::operator=(ForwardIterator rhs) { swap(*this, rhs); return (*this); } template Grid::ForwardIterator &Grid::ForwardIterator::operator++() { if (!_blks.size()) return (*this); size_t xb = 0; size_t yb = 0; size_t zb = 0; size_t x = 0; size_t y = 0; size_t z = 0; do { _xb++; _itr++; _index[0]++; if (_pred.Enabled()) ++_coordItr; if (_xb < _bs3d[0] && _index[0] < _dims3d[0]) { if (_pred(*_coordItr)) { return (*this); } continue; } _xb = 0; if (_index[0] >= _dims3d[0]) { _index[0] = _xb = 0; _index[1]++; } if (_index[1] >= _dims3d[1]) { _index[1] = 0; _index[2]++; } if (_index == _lastIndex) { return (*this); // last element } x = _index[0] % _bs3d[0]; xb = _index[0] / _bs3d[0]; y = _index[1] % _bs3d[1]; yb = _index[1] / _bs3d[1]; z = _index[2] % _bs3d[2]; zb = _index[2] / _bs3d[2]; float *blk = _blks[zb * _bdims3d[0] * _bdims3d[1] + yb * _bdims3d[0] + xb]; _itr = &blk[z * _bs3d[0] * _bs3d[1] + y * _bs3d[0] + x]; } while (_index != _lastIndex && !_pred(*_coordItr)); return (*this); } template Grid::ForwardIterator Grid::ForwardIterator::operator++(int) { ForwardIterator temp(*this); ++(*this); return (temp); } template Grid::ForwardIterator &Grid::ForwardIterator::operator+=(const long int &offset) { VAssert(offset >= 0); if (!_blks.size()) return (*this); long maxIndexL = Wasp::VProduct(_dims3d.data(), _dims3d.size()) - 1; long indexL = Wasp::LinearizeCoords(_index.data(), _dims3d.data(), _index.size()) + offset; // Check for overflow // if (indexL < 0) { indexL = 0; } if (indexL > maxIndexL) { _index = _lastIndex; return (*this); } Wasp::VectorizeCoords(indexL, _dims3d.data(), _index.data(), _index.size()); if (_pred.Enabled()) _coordItr += offset; size_t x = _index[0] % _bs3d[0]; size_t xb = _index[0] / _bs3d[0]; size_t y = _index[1] % _bs3d[1]; size_t yb = _index[1] / _bs3d[1]; size_t z = _index[2] % _bs3d[2]; size_t zb = _index[2] / _bs3d[2]; _xb = x; float *blk = _blks[zb * _bdims3d[0] * _bdims3d[1] + yb * _bdims3d[0] + xb]; _itr = &blk[z * _bs3d[0] * _bs3d[1] + y * _bs3d[0] + x]; // If no predicate, or if there is a predicate and it evaluates to // true, we're done. // if (!_pred.Enabled() || _pred(*_coordItr)) { return (*this); } // Let operator++ increment until predicate passes (or end of list) // return (++(*this)); } template Grid::ForwardIterator Grid::ForwardIterator::operator+(const long int &offset) const { ForwardIterator temp(*this); temp += offset; return (temp); } // Need this so that template definitions can be made in .cpp file, not .h file // template class Grid::ForwardIterator; template class Grid::ForwardIterator; namespace VAPoR { std::ostream &operator<<(std::ostream &o, const Grid &g) { o << "Grid" << endl; o << " Dimensions "; for (int i = 0; i < g._dims.size(); i++) { o << g._dims[i] << " "; } o << endl; o << " Block dimensions "; for (int i = 0; i < g._bs.size(); i++) { o << g._bs[i] << " "; } o << endl; o << " Grid dimensions in blocks "; for (int i = 0; i < g._bdims.size(); i++) { o << g._bdims[i] << " "; } o << endl; o << " Topological dimension " << g._topologyDimension << endl; o << " Periodicity "; for (int i = 0; i < g._periodic.size(); i++) { o << g._periodic[i] << " "; } o << endl; o << " Missing value flag " << g._hasMissing << endl; o << " Missing value " << g._missingValue << endl; o << " Interpolation order " << g._interpolationOrder << endl; return (o); } }; // namespace VAPoR ================================================ FILE: lib/vdc/GridHelper.cpp ================================================ #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; namespace { // Format a vector type as a space-separated element string // template string vector_to_string(T v) { ostringstream oss; oss << "["; for (int i = 0; i < v.size(); i++) { oss << v[i] << " "; } oss << "]"; return (oss.str()); } bool isUnstructured2D(const DC::Mesh &m, const vector &cvarsinfo, const vector> &cdimnames) { DC::Mesh::Type mtype = m.GetMeshType(); if (mtype == DC::Mesh::UNSTRUC_2D) { return (true); } return (false); } bool isUnstructuredLayered(const DC::Mesh &m, const vector &cvarsinfo, const vector> &cdimnames) { DC::Mesh::Type mtype = m.GetMeshType(); if (mtype == DC::Mesh::UNSTRUC_LAYERED) { return (true); } return (false); } bool isRegular(const DC::Mesh &m, const vector &cvarsinfo, const vector> &cdimnames) { VAssert(cvarsinfo.size() == cdimnames.size()); for (int i = 0; i < cdimnames.size(); i++) { if (!(cdimnames[i].size() == 1 && cvarsinfo[i].GetUniform())) { return (false); } } return (true); } bool isStretched(const DC::Mesh &m, const vector &cvarsinfo, const vector> &cdimnames) { VAssert(cvarsinfo.size() == cdimnames.size()); // All dimensions need to be 1D and at least one non-uniform // for (int i = 0; i < cdimnames.size(); i++) { if (!(cdimnames[i].size() == 1)) { return (false); } } // Need at least one non-uniform dimension // for (int i = 0; i < cvarsinfo.size(); i++) { if (!(cvarsinfo[i].GetUniform())) { return (true); } } return (false); } bool isLayered(const DC::Mesh &m, const vector &cvarsinfo, const vector> &cdimnames) { VAssert(cvarsinfo.size() == cdimnames.size()); if (cdimnames.size() != 3) return (false); for (int i = 0; i < 2; i++) { if (!(cdimnames[i].size() == 1)) { return (false); } } if (!(cdimnames[2].size() == 3)) return (false); return (true); } bool isUnstructured3D(const DC::Mesh &m, const std::vector &cvarsinfo, const std::vector> &cdimnames) { DC::Mesh::Type mtype = m.GetMeshType(); if (mtype == DC::Mesh::UNSTRUC_3D) { return (true); } return (false); } bool isCurvilinear(const DC::Mesh &m, const vector &cvarsinfo, const vector> &cdimnames) { VAssert(cvarsinfo.size() == cdimnames.size()); if (!(cdimnames.size() == 2 || cdimnames.size() == 3)) return (false); if (cdimnames.size() == 3 && !((cdimnames[2].size() == 1) || (cdimnames[2].size() == 3))) { return (false); } if (!(cdimnames[0].size() == 2 && cdimnames[1].size() == 2)) return (false); return (true); } }; // namespace using namespace VAPoR; using namespace Wasp; string GridHelper::_getQuadTreeRectangleKey(size_t ts, int level, int lod, const vector &cvarsinfo, const DimsType &bmin, const DimsType &bmax) const { VAssert(cvarsinfo.size() >= 2); vector varnames; for (int i = 0; i < cvarsinfo.size(); i++) { varnames.push_back(cvarsinfo[i].GetName()); } bool time_varying = false; for (int i = 0; i < cvarsinfo.size(); i++) { if (!cvarsinfo[i].GetTimeDimName().empty()) { time_varying = true; } } if (!time_varying) ts = 0; ostringstream oss; oss << ts; oss << ":"; oss << vector_to_string(varnames); oss << ":"; oss << level; oss << ":"; oss << vector_to_string(bmin); oss << ":"; oss << vector_to_string(bmax); return (oss.str()); } RegularGrid *GridHelper::_make_grid_regular(const DimsType &dims, const vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax ) const { CoordType minu = {0.0, 0.0, 0.0}; CoordType maxu = {0.0, 0.0, 0.0}; for (int i = 0; i < blkvec.size() - 1 && blkvec[i + 1]; i++) { VAssert(dims[i] > 0); float *coords = blkvec[i + 1]; minu[i] = (coords[0]); maxu[i] = (coords[dims[i] - 1]); } size_t nblocks = 1; size_t block_size = 1; for (int i = 0; i < bs.size(); i++) { nblocks *= bmax[i] - bmin[i] + 1; block_size *= bs[i]; } vector blkptrs; if (blkvec[0]) { for (int i = 0; i < nblocks; i++) { blkptrs.push_back(blkvec[0] + i * block_size); } } RegularGrid *rg = new RegularGrid(dims, bs, blkptrs, minu, maxu); return (rg); } StretchedGrid *GridHelper::_make_grid_stretched(const DimsType &dims, const vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax ) const { size_t nblocks = 1; size_t block_size = 1; for (int i = 0; i < bs.size(); i++) { nblocks *= bmax[i] - bmin[i] + 1; block_size *= bs[i]; } vector blkptrs; if (blkvec[0]) { for (int i = 0; i < nblocks; i++) { blkptrs.push_back(blkvec[0] + i * block_size); } } vector xcoords; if (blkvec.size() > 1 && blkvec[1]) { for (int i = 0; i < dims[0]; i++) xcoords.push_back(blkvec[1][i]); } vector ycoords; if (blkvec.size() > 2 && blkvec[2]) { for (int i = 0; i < dims[1]; i++) ycoords.push_back(blkvec[2][i]); } vector zcoords; if (blkvec.size() > 3 && blkvec[3]) { for (int i = 0; i < dims[2]; i++) zcoords.push_back(blkvec[3][i]); } StretchedGrid *sg = new StretchedGrid(dims, bs, blkptrs, xcoords, ycoords, zcoords); return (sg); } LayeredGrid *GridHelper::_make_grid_layered(const DimsType &dims, const vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax) const { // Get horizontal dimensions // vector xcoords; for (int i = 0; i < dims[0]; i++) xcoords.push_back(blkvec[1][i]); vector ycoords; for (int i = 0; i < dims[1]; i++) ycoords.push_back(blkvec[2][i]); // Data blocks // size_t nblocks = 1; size_t block_size = 1; for (int i = 0; i < bs.size(); i++) { nblocks *= bmax[i] - bmin[i] + 1; block_size *= bs[i]; } vector blkptrs, zcblkptrs; if (blkvec[0]) { for (int i = 0; i < nblocks; i++) { blkptrs.push_back(blkvec[0] + i * block_size); } } // Z Coord blocks // nblocks = 1; block_size = 1; for (int i = 0; i < bs.size(); i++) { nblocks *= bmax[i] - bmin[i] + 1; block_size *= bs[i]; } for (int i = 0; i < nblocks; i++) { zcblkptrs.push_back(blkvec[3] + i * block_size); } RegularGrid rg(dims, bs, zcblkptrs, CoordType{0.0, 0.0, 0.0}, CoordType{1.0, 1.0, 1.0}); LayeredGrid *lg = new LayeredGrid(dims, bs, blkptrs, xcoords, ycoords, rg); return (lg); } CurvilinearGrid *GridHelper::_make_grid_curvilinear(size_t ts, int level, int lod, const vector &cvarsinfo, const DimsType &dims, const vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax) { // Data blocks // size_t nblocks = 1; size_t block_size = 1; for (int i = 0; i < bs.size(); i++) { nblocks *= bmax[i] - bmin[i] + 1; block_size *= bs[i]; } // block pointers for data // vector blkptrs; for (int i = 0; i < nblocks; i++) { if (blkvec[0]) blkptrs.push_back(blkvec[0] + i * block_size); } // X horizontal coord blocks // DimsType bs2d = {bs[0], bs[1], 1}; DimsType bmin2d = {bmin[0], bmin[1], 0}; DimsType bmax2d = {bmax[0], bmax[1], 0}; size_t nblocks2d = 1; size_t block_size2d = 1; for (int i = 0; i < bs2d.size(); i++) { nblocks2d *= bmax2d[i] - bmin2d[i] + 1; block_size2d *= bs2d[i]; } vector xcblkptrs; for (int i = 0; i < nblocks2d; i++) { xcblkptrs.push_back(blkvec[1] + i * block_size2d); } // Y horizontal coord blocks // vector ycblkptrs; for (int i = 0; i < nblocks2d; i++) { ycblkptrs.push_back(blkvec[2] + i * block_size2d); } CoordType minu2d = {0.0, 0.0, 0.0}; CoordType maxu2d = {1.0, 1.0, 1.0}; DimsType dims2d = {dims[0], dims[1], 1}; RegularGrid xrg(dims2d, bs2d, xcblkptrs, minu2d, maxu2d); RegularGrid yrg(dims2d, bs2d, ycblkptrs, minu2d, maxu2d); string qtr_key = _getQuadTreeRectangleKey(ts, level, lod, cvarsinfo, bmin2d, bmax2d); // Try to get a shared pointer to the QuadTreeRectangle from the // cache. If one does not exist the Grid class will make one. We use // a shared pointer so that we can cache it for use by other Grid // classes. This a peformance optimization, necessary be creating // a QuadTreeRectangle is expensive. // std::shared_ptr qtr = _qtrCache.get(qtr_key); CurvilinearGrid *g; if (Grid::GetNumDimensions(dims) == 3 && cvarsinfo[2].GetDimNames().size() == 3) { // Terrain following vertical // CoordType minu = {0.0, 0.0, 0.0}; CoordType maxu = {1.0, 1.0, 1.0}; vector zcblkptrs; for (int i = 0; i < nblocks; i++) { zcblkptrs.push_back(blkvec[3] + i * block_size); } RegularGrid zrg(dims, bs, zcblkptrs, minu, maxu); g = new CurvilinearGrid(dims, bs, blkptrs, xrg, yrg, zrg, qtr); } else if (Grid::GetNumDimensions(dims) == 3 && cvarsinfo[2].GetDimNames().size() == 1) { // stretched vertical // vector zcoords; for (int i = 0; i < dims[2]; i++) zcoords.push_back(blkvec[3][i]); g = new CurvilinearGrid(dims, bs, blkptrs, xrg, yrg, zcoords, qtr); } else { // 2D // g = new CurvilinearGrid(dims, bs, blkptrs, xrg, yrg, vector(), qtr); } // No QuadTreeRectangle in cache. So get shared pointer for one created // by UnstructuredGrid2D() and cache it for later use. The memory // will be garbage collected when all pointers to it go out of scope // if (!qtr) { qtr = g->GetQuadTreeRectangle(); (void)_qtrCache.put(qtr_key, qtr); } return (g); } UnstructuredGrid2D *GridHelper::_make_grid_unstructured2d(size_t ts, int level, int lod, const DC::DataVar &var, const vector &cvarsinfo, const DimsType &dims, const vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, const vector &conn_blkvec, const DimsType &conn_bs, const DimsType &conn_bmin, const DimsType &conn_bmax, const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace, size_t maxFacePerVertex, long vertexOffset, long faceOffset) { VAssert(conn_blkvec.size() >= 1); // block pointers for data // size_t nblocks = 1; size_t block_size = 1; for (int i = 0; i < bs.size(); i++) { nblocks *= bmax[i] - bmin[i] + 1; block_size *= bs[i]; } vector blkptrs; for (int i = 0; i < nblocks; i++) { if (blkvec[0]) blkptrs.push_back(blkvec[0] + i * block_size); } // Block pointers for X coordinates, which are always 1D // vector xcblkptrs; for (int i = 0; i < nblocks; i++) { xcblkptrs.push_back(blkvec[1] + i * block_size); } // Block pointers for X coordinates, which are always 1D // vector ycblkptrs; for (int i = 0; i < nblocks; i++) { ycblkptrs.push_back(blkvec[2] + i * block_size); } // N.B. assumes blkvec contains contiguous blocks :-( // const int *vertexOnFace = conn_blkvec[0]; const int *faceOnVertex = conn_blkvec.size() > 1 ? conn_blkvec[1] : NULL; const int *faceOnFace = conn_blkvec.size() > 2 ? conn_blkvec[2] : NULL; UnstructuredGridCoordless xug(vertexDims, faceDims, edgeDims, bs, xcblkptrs, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset); UnstructuredGridCoordless yug(vertexDims, faceDims, edgeDims, bs, ycblkptrs, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset); UnstructuredGridCoordless zug; string qtr_key = _getQuadTreeRectangleKey(ts, level, lod, cvarsinfo, bmin, bmax); // Try to get a shared pointer to the QuadTreeRectangle from the // cache. If one does not exist the Grid class will make one. We use // a shared pointer so that we can cache it for use by other Grid // classes. This a peformance optimization, necessary be creating // a QuadTreeRectangle is expensive. // std::shared_ptr qtr = _qtrCache.get(qtr_key); UnstructuredGrid2D *g = new UnstructuredGrid2D(vertexDims, faceDims, edgeDims, bs, blkptrs, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset, xug, yug, zug, qtr); // No QuadTreeRectangle in cache. So get shared pointer for one created // by UnstructuredGrid2D() and cache it for later use. The memory // will be garbage collected when all pointers to it go out of scope // if (!qtr) { qtr = g->GetQuadTreeRectangle(); (void)_qtrCache.put(qtr_key, qtr); } return (g); } UnstructuredGridLayered *GridHelper::_make_grid_unstructured_layered(size_t ts, int level, int lod, const DC::DataVar &var, const vector &cvarsinfo, const DimsType &dims, const vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, const vector &conn_blkvec, const DimsType &conn_bs, const DimsType &conn_bmin, const DimsType &conn_bmax, const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace, size_t maxFacePerVertex, long vertexOffset, long faceOffset) { VAssert(blkvec.size() == 4); VAssert(conn_blkvec.size() >= 1); // block pointers for data // size_t nblocks = 1; size_t block_size = 1; for (int i = 0; i < bs.size(); i++) { nblocks *= bmax[i] - bmin[i] + 1; block_size *= bs[i]; } vector blkptrs; for (int i = 0; i < nblocks; i++) { if (blkvec[0]) blkptrs.push_back(blkvec[0] + i * block_size); } // Block pointers for X coordinates, which are always 1D // nblocks = 1; block_size = 1; for (int i = 0; i < 1; i++) { nblocks *= bmax[i] - bmin[i] + 1; block_size *= bs[i]; } vector xcblkptrs; for (int i = 0; i < nblocks; i++) { xcblkptrs.push_back(blkvec[1] + i * block_size); } // Block pointers for Y coordinates, which are always 1D // vector ycblkptrs; for (int i = 0; i < nblocks; i++) { ycblkptrs.push_back(blkvec[2] + i * block_size); } // Block pointers for Z coordinates, which are always 2D // nblocks = 1; block_size = 1; for (int i = 0; i < bs.size(); i++) { nblocks *= bmax[i] - bmin[i] + 1; block_size *= bs[i]; } vector zcblkptrs; for (int i = 0; i < nblocks; i++) { zcblkptrs.push_back(blkvec[3] + i * block_size); } // N.B. assumes blkvec contains contiguous blocks :-( // const int *vertexOnFace = conn_blkvec[0]; const int *faceOnVertex = conn_blkvec[1]; const int *faceOnFace = conn_blkvec.size() == 3 ? conn_blkvec[2] : NULL; DimsType vertexDims1D = {vertexDims[0], 1, 1}; DimsType faceDims1D = {faceDims[0], 1, 1}; DimsType edgeDims1D = {edgeDims[0], 1, 1}; DimsType bs1D = {bs[0], 1, 1}; UnstructuredGridCoordless xug(vertexDims1D, faceDims1D, edgeDims1D, bs1D, xcblkptrs, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset); UnstructuredGridCoordless yug(vertexDims1D, faceDims1D, edgeDims1D, bs1D, ycblkptrs, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset); UnstructuredGridCoordless zug(vertexDims, faceDims, edgeDims, bs, zcblkptrs, 3, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset); string qtr_key = _getQuadTreeRectangleKey(ts, level, lod, cvarsinfo, bmin, bmax); // Try to get a shared pointer to the QuadTreeRectangle from the // cache. If one does not exist the Grid class will make one. We use // a shared pointer so that we can cache it for use by other Grid // classes. This a peformance optimization, necessary be creating // a QuadTreeRectangle is expensive. // std::shared_ptr qtr = _qtrCache.get(qtr_key); UnstructuredGridLayered *g = new UnstructuredGridLayered(vertexDims, faceDims, edgeDims, bs, blkptrs, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset, xug, yug, zug, qtr); // No QuadTreeRectangle in cache. So get shared pointer for one created // by UnstructuredGrid2D() and cache it for later use. The memory // will be garbage collected when all pointers to it go out of scope // if (!qtr) { qtr = g->GetQuadTreeRectangle(); (void)_qtrCache.put(qtr_key, qtr); } return (g); } UnstructuredGrid3D *GridHelper::_make_grid_unstructured_3d(size_t ts, int level, int lod, const DC::DataVar &var, const vector &cvarsinfo, const DimsType &dims, const vector &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, const vector &conn_blkvec, const DimsType &conn_bs, const DimsType &conn_bmin, const DimsType &conn_bmax, const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace, size_t maxFacePerVertex, long vertexOffset, long faceOffset) { VAssert(blkvec.size() == 4); VAssert(conn_blkvec.size() >= 2); // block pointers for data // size_t nblocks = 1; size_t block_size = 1; for (int i = 0; i < bs.size(); i++) { nblocks *= bmax[i] - bmin[i] + 1; block_size *= bs[i]; } vector blkptrs; for (int i = 0; i < nblocks; i++) { if (blkvec[0]) blkptrs.push_back(blkvec[0] + i * block_size); } // Block pointers for X coordinates, which are always 1D // nblocks = 1; block_size = 1; for (int i = 0; i < 1; i++) { nblocks *= bmax[i] - bmin[i] + 1; block_size *= bs[i]; } vector xcblkptrs; for (int i = 0; i < nblocks; i++) { xcblkptrs.push_back(blkvec[1] + i * block_size); } // Block pointers for Y coordinates, which are always 1D // vector ycblkptrs; for (int i = 0; i < nblocks; i++) { ycblkptrs.push_back(blkvec[2] + i * block_size); } // Block pointers for Z coordinates, which are always 2D // nblocks = 1; block_size = 1; for (int i = 0; i < bs.size(); i++) { nblocks *= bmax[i] - bmin[i] + 1; block_size *= bs[i]; } vector zcblkptrs; for (int i = 0; i < nblocks; i++) { zcblkptrs.push_back(blkvec[3] + i * block_size); } // N.B. assumes blkvec contains contiguous blocks :-( // const int *vertexOnFace = conn_blkvec[0]; const int *faceOnVertex = conn_blkvec[1]; const int *faceOnFace = conn_blkvec.size() == 3 ? conn_blkvec[2] : NULL; DimsType vertexDims1D = {vertexDims[0], 1, 1}; DimsType faceDims1D = {faceDims[0], 1, 1}; DimsType edgeDims1D = {edgeDims[0], 1, 1}; DimsType bs1D = {bs[0], 1, 1}; UnstructuredGridCoordless xug(vertexDims1D, faceDims1D, edgeDims1D, bs1D, xcblkptrs, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset); UnstructuredGridCoordless yug(vertexDims1D, faceDims1D, edgeDims1D, bs1D, ycblkptrs, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset); UnstructuredGridCoordless zug(vertexDims, faceDims, edgeDims, bs, zcblkptrs, 3, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset); UnstructuredGrid3D *g = new UnstructuredGrid3D(vertexDims, faceDims, edgeDims, bs, blkptrs, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset, xug, yug, zug); return (g); } void GridHelper::_makeGridHelper(const DC::DataVar &var, const DimsType &roi_dims, const DimsType &dims, Grid *g) const { vector has_periodic = var.GetPeriodic(); vector periodic; for (int i = 0; i < dims.size(); i++) { if (i < has_periodic.size() && has_periodic[i] && roi_dims[i] == dims[i]) { periodic.push_back(true); } else { periodic.push_back(false); } } bool has_missing = false; float mv = 0.0; if (var.GetHasMissing()) { has_missing = true; mv = var.GetMissingValue(); } // Don't allow NaNs as missing values. We replace any // missing values in the data with infinity // if (std::isnan(mv)) mv = std::numeric_limits::infinity(); g->SetPeriodic(periodic); if (has_missing) { g->SetHasMissingValues(true); g->SetMissingValue(mv); } } // var: variable info // roi_dims: spatial dimensions of ROI // dims: spatial dimensions of full variable domain in voxels // blkvec: data blocks, and coordinate blocks // bsvec: data block dimensions, and coordinate block dimensions // bminvec: ROI offsets in blocks, full domain, data and coordinates // bmaxvec: ROI offsets in blocks, full domain, data and coordinates // StructuredGrid *GridHelper::MakeGridStructured(string gridType, size_t ts, int level, int lod, const DC::DataVar &var, const vector &cvarsinfo, const DimsType &roi_dims, const DimsType &dims, const vector &blkvec, const vector &bsvec, const vector &bminvec, const vector &bmaxvec) { StructuredGrid *rg = NULL; if (gridType == RegularGrid::GetClassType()) { rg = _make_grid_regular(roi_dims, blkvec, bsvec[0], bminvec[0], bmaxvec[0]); } else if (gridType == StretchedGrid::GetClassType()) { rg = _make_grid_stretched(roi_dims, blkvec, bsvec[0], bminvec[0], bmaxvec[0]); } else if (gridType == LayeredGrid::GetClassType()) { rg = _make_grid_layered(roi_dims, blkvec, bsvec[0], bminvec[0], bmaxvec[0]); } else if (gridType == CurvilinearGrid::GetClassType()) { rg = _make_grid_curvilinear(ts, level, lod, cvarsinfo, roi_dims, blkvec, bsvec[0], bminvec[0], bmaxvec[0]); } else { return (NULL); } _makeGridHelper(var, roi_dims, dims, rg); return (rg); } UnstructuredGrid *GridHelper::MakeGridUnstructured(string gridType, size_t ts, int level, int lod, const DC::DataVar &var, const vector &cvarsinfo, const DimsType &roi_dims, const DimsType &dims, const vector &blkvec, const vector &bsvec, const vector &bminvec, const vector &bmaxvec, const vector &conn_blkvec, const vector &conn_bsvec, const vector &conn_bminvec, const vector &conn_bmaxvec, const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace, size_t maxFacePerVertex, long vertexOffset, long faceOffset) { UnstructuredGrid *rg = NULL; if (gridType == UnstructuredGrid2D::GetClassType()) { rg = _make_grid_unstructured2d(ts, level, lod, var, cvarsinfo, roi_dims, blkvec, bsvec[0], bminvec[0], bmaxvec[0], conn_blkvec, conn_bsvec[0], conn_bminvec[0], conn_bmaxvec[0], vertexDims, faceDims, edgeDims, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset); } else if (gridType == UnstructuredGridLayered::GetClassType()) { rg = _make_grid_unstructured_layered(ts, level, lod, var, cvarsinfo, roi_dims, blkvec, bsvec[0], bminvec[0], bmaxvec[0], conn_blkvec, conn_bsvec[0], conn_bminvec[0], conn_bmaxvec[0], vertexDims, faceDims, edgeDims, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset); } else if (gridType == UnstructuredGrid3D::GetClassType()) { rg = _make_grid_unstructured_3d(ts, level, lod, var, cvarsinfo, roi_dims, blkvec, bsvec[0], bminvec[0], bmaxvec[0], conn_blkvec, conn_bsvec[0], conn_bminvec[0], conn_bmaxvec[0], vertexDims, faceDims, edgeDims, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset); } else { return (NULL); } _makeGridHelper(var, roi_dims, dims, rg); return (rg); } GridHelper::~GridHelper() { while ((_qtrCache.remove_lru()) != NULL) {} } string GridHelper::GetGridType(const DC::Mesh &m, const vector &cvarsinfo, const vector> &cdimnames) const { if (isUnstructured2D(m, cvarsinfo, cdimnames)) { return (UnstructuredGrid2D::GetClassType()); } if (isUnstructuredLayered(m, cvarsinfo, cdimnames)) { return (UnstructuredGridLayered::GetClassType()); } if (isUnstructured3D(m, cvarsinfo, cdimnames)) { return UnstructuredGrid3D::GetClassType(); } if (isRegular(m, cvarsinfo, cdimnames)) { return (RegularGrid::GetClassType()); } if (isStretched(m, cvarsinfo, cdimnames)) { return (StretchedGrid::GetClassType()); } if (isLayered(m, cvarsinfo, cdimnames)) { return (LayeredGrid::GetClassType()); } if (isCurvilinear(m, cvarsinfo, cdimnames)) { return (CurvilinearGrid::GetClassType()); } if (isUnstructured3D(m, cvarsinfo, cdimnames)) { return UnstructuredGrid3D::GetClassType(); } return (""); } bool GridHelper::IsUnstructured(std::string gridType) const { return (gridType == UnstructuredGrid2D::GetClassType() || gridType == UnstructuredGridLayered::GetClassType() || gridType == UnstructuredGrid3D::GetClassType()); } bool GridHelper::IsStructured(std::string gridType) const { return ((gridType == RegularGrid::GetClassType()) || (gridType == StretchedGrid::GetClassType()) || (gridType == LayeredGrid::GetClassType()) || (gridType == CurvilinearGrid::GetClassType())); } ================================================ FILE: lib/vdc/KDTreeRG.cpp ================================================ #include #include #include "vapor/VAssert.h" #include #include #include #include "kdtree.h" using namespace std; using namespace VAPoR; KDTreeRG::KDTreeRG(const Grid &xg, const Grid &yg) : _points(xg, yg), _kdtree(2 /* dimension */, _points, nanoflann::KDTreeSingleIndexAdaptorParams(20 /* max leaf num */)) { auto tmp = xg.GetDimensions(); _dims = {tmp[0], tmp[1], tmp[2]}; _dims.resize(xg.GetNumDimensions()); _kdtree.buildIndex(); } KDTreeRG::~KDTreeRG() {} void KDTreeRG::Nearest(const vector &coordu, vector &coord) const { VAssert(coordu.size() == 2); // 3D case isn't supported yet size_t ret_index; float dist_sqr; nanoflann::KNNResultSet resultSet(1); resultSet.init(&ret_index, &dist_sqr); bool rt = _kdtree.findNeighbors(resultSet, coordu.data(), nanoflann::SearchParams()); VAssert(rt); // De-serialize the linear offset and put it back in vector form coord.clear(); coord = Wasp::VectorizeCoords(ret_index, _dims); } KDTreeRGSubset::KDTreeRGSubset() { _kdtree = NULL; _min.clear(); _max.clear(); } KDTreeRGSubset::KDTreeRGSubset(const KDTreeRG *kdtreerg, const vector &min, const vector &max) { VAssert(min.size() == max.size()); vector dims = kdtreerg->GetDimensions(); VAssert(min.size() == dims.size()); for (int i = 0; i < dims.size(); i++) { VAssert(min[i] <= max[i]); VAssert(max[i] < dims[i]); } _kdtree = kdtreerg; // shallow copy _min = min; _max = max; } // Returned coordinates are relative to min and max used in constructor // The origin is given by min // void KDTreeRGSubset::Nearest(const vector &coordu, vector &coord) const { VAssert(coordu.size() == _min.size()); coord.clear(); vector global_coords; // Find voxel coorindates of nearest point in global mesh // _kdtree->Nearest(coordu, global_coords); // Clamp global coordinates to region defined by _min, and _max // for (int i = 0; i < global_coords.size(); i++) { if (global_coords[i] < _min[i]) global_coords[i] = _min[i]; if (global_coords[i] > _max[i]) global_coords[i] = _max[i]; } // Translate global coordinates to ROI coordinates // for (int i = 0; i < global_coords.size(); i++) { coord.push_back(global_coords[i] - _min[i]); } } ================================================ FILE: lib/vdc/LayeredGrid.cpp ================================================ #include #include #include #include #include #include "vapor/utils.h" #include "vapor/LayeredGrid.h" #define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH #include "vapor/LegacyVectorMath.h" #include "vapor/VAssert.h" using namespace std; using namespace VAPoR; void LayeredGrid::_layeredGrid(const DimsType &dims, const DimsType &bs, const vector &blks, const std::vector &xcoords, const std::vector &ycoords, const RegularGrid &zrg) { VAssert(GetDimensions().size() == 3); VAssert(xcoords.size() == GetDimensions()[0]); VAssert(ycoords.size() == GetDimensions()[1]); VAssert(zrg.GetDimensions()[0] == xcoords.size()); VAssert(zrg.GetDimensions()[1] == ycoords.size()); _interpolationOrder = 1; // Set horizontal extents from sg2d // _sg2d.GetUserExtents(_minu, _maxu); // Get extents of layered dimension // float range[2]; _zrg.GetRange(range); _minu[2] = (double)range[0]; _maxu[2] = (double)range[1]; } LayeredGrid::LayeredGrid(const DimsType &dims, const DimsType &bs, const vector &blks, const std::vector &xcoords, const std::vector &ycoords, const RegularGrid &zrg) : StructuredGrid(dims, bs, blks), _sg2d(DimsType{dims[0], dims[1], 1}, DimsType{bs[0], bs[1], 1}, vector(), xcoords, ycoords, vector()), _zrg(zrg), _xcoords(xcoords), _ycoords(ycoords) { _layeredGrid(dims, bs, blks, xcoords, ycoords, zrg); } LayeredGrid::LayeredGrid(const vector &dimsv, const vector &bsv, const vector &blks, const std::vector &xcoords, const std::vector &ycoords, const RegularGrid &zrg) : StructuredGrid(dimsv, bsv, blks), _sg2d(vector(dimsv.begin(), dimsv.begin() + 2), vector(bsv.begin(), bsv.begin() + 2), vector(), xcoords, ycoords, vector()), _zrg(zrg), _xcoords(xcoords), _ycoords(ycoords) { DimsType dims = {1, 1, 1}; DimsType bs = {1, 1, 1}; CopyToArr3(dimsv, dims); CopyToArr3(bsv, bs); _layeredGrid(dims, bs, blks, xcoords, ycoords, zrg); } DimsType LayeredGrid::GetCoordDimensions(size_t dim) const { DimsType dims = {1, 1, 1}; if (dim == 0) { dims[0] = GetDimensions()[0]; } else if (dim == 1) { dims[0] = GetDimensions()[1]; } else if (dim == 2) { dims = _zrg.GetDimensions(); } return (dims); } void LayeredGrid::GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const { minu = _minu; maxu = _maxu; } void LayeredGrid::GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const { DimsType cMin; ClampIndex(min, cMin); DimsType cMax; ClampIndex(max, cMax); // Get extents of horizontal dimensions. Note: also get vertical // dimension, but it's bogus for layered grid. // GetUserCoordinates(cMin, minu); GetUserCoordinates(cMax, maxu); // Initialize min and max coordinates of varying dimension with // coordinates of "first" and "last" grid point. Coordinates of // varying dimension are stored as values of a scalar function // sampling the coordinate space. // float mincoord = _zrg.GetValueAtIndex(cMin); float maxcoord = _zrg.GetValueAtIndex(cMax); // Now find the extreme values of the varying dimension's coordinates // for (int j = cMin[1]; j <= cMax[1]; j++) { for (int i = cMin[0]; i <= cMax[0]; i++) { float v = _zrg.AccessIJK(i, j, cMin[2]); if (v < mincoord) mincoord = v; } } for (int j = cMin[1]; j <= cMax[1]; j++) { for (int i = cMin[0]; i <= cMax[0]; i++) { float v = _zrg.AccessIJK(i, j, cMax[2]); if (v > maxcoord) maxcoord = v; } } minu[2] = mincoord; maxu[2] = maxcoord; } bool LayeredGrid::_insideGrid(const CoordType &coords, DimsType &indices, double wgts[3]) const { // Get indices and weights for horizontal slice // bool found = _sg2d.GetIndicesCell(coords, indices, wgts); if (!found) return (found); // XZ and YZ cell sides are planar, but XY sides may not be. We divide // the XY faces into two triangles (changing hexahedrals into prims) // and figure out which triangle (prism) the point is in (first or // second). Then we search the stack of first (or second) prism in Z // // // Check if point is in "first" triangle (0,0), (1,0), (1,1) // double lambda[3]; double pt[] = {coords[0], coords[1]}; DimsType iv = {indices[0], indices[0] + 1, indices[0] + 1}; DimsType jv = {indices[1], indices[1], indices[1] + 1}; double tverts[] = {_xcoords[iv[0]], _ycoords[jv[0]], _xcoords[iv[1]], _ycoords[jv[1]], _xcoords[iv[2]], _ycoords[jv[2]]}; bool inside = VAPoR::BarycentricCoordsTri(tverts, pt, lambda); if (!inside) { // Not in first triangle. // Now check if point is in "second" triangle (0,0), (1,1), (0,1) // iv = {indices[0], indices[0] + 1, indices[0]}; jv = {indices[1], indices[1] + 1, indices[1] + 1}; double tverts[] = {_xcoords[iv[0]], _ycoords[jv[0]], _xcoords[iv[1]], _ycoords[jv[1]], _xcoords[iv[2]], _ycoords[jv[2]]}; inside = VAPoR::BarycentricCoordsTri(tverts, pt, lambda); // Mathematically this shouldn't happen if _sg2d.GetIndicesCell() // returns true, but have to contend with floating point roundoff // if (!inside) return (false); } float z0, z1; // Find k index of cell containing z. Already know i and j indices // vector zcoords; size_t nz = GetDimensions()[2]; zcoords.reserve(nz); for (int kk = 0; kk < nz; kk++) { // Interpolate Z coordinate across triangle // float zk = _zrg.AccessIJK(iv[0], jv[0], kk) * lambda[0] + _zrg.AccessIJK(iv[1], jv[1], kk) * lambda[1] + _zrg.AccessIJK(iv[2], jv[2], kk) * lambda[2]; zcoords.push_back(zk); } if (!Wasp::BinarySearchRange(zcoords, coords[2], indices[2])) return (false); z0 = zcoords[indices[2]]; z1 = indices[2] < nz - 1 ? zcoords[indices[2] + 1] : z0; wgts[2] = z0 == z1 ? 1.0 : (1.0 - (coords[2] - z0) / (z1 - z0)); return (true); } float LayeredGrid::GetValueNearestNeighbor(const CoordType &coords) const { DimsType indices; double wgts[3]; bool found = _insideGrid(coords, indices, wgts); if (!found) return (GetMissingValue()); if (wgts[0] < 0.5) indices[0] += 1; if (wgts[1] < 0.5) indices[1] += 1; if (wgts[2] < 0.5) indices[2] += 1; return (AccessIJK(indices[0], indices[1], indices[2])); } float LayeredGrid::GetValueLinear(const CoordType &coords) const { DimsType indices; double wgts[3]; bool found = _insideGrid(coords, indices, wgts); if (!found) return (GetMissingValue()); return (TrilinearInterpolate(indices[0], indices[1], indices[2], wgts[0], wgts[1], wgts[2])); } float LayeredGrid::GetValue(const CoordType &coords) const { // Clamp coordinates on periodic boundaries to grid extents // CoordType cCoords; ClampCoord(coords, cCoords); auto dims = GetDimensions(); // Figure out interpolation order // int interp_order = _interpolationOrder; if (interp_order == 2) { if (dims[2] < 3) interp_order = 1; } if (interp_order == 0) { return (GetValueNearestNeighbor(cCoords)); } else if (interp_order == 1) { return (GetValueLinear(cCoords)); } return _getValueQuadratic(cCoords.data()); } void LayeredGrid::SetInterpolationOrder(int order) { if (order < 0 || order > 3) order = 2; _interpolationOrder = order; } void LayeredGrid::GetUserCoordinates(const DimsType &indices, CoordType &coords) const { DimsType cIndices; ClampIndex(indices, cIndices); // First get coordinates of (horizontal) dimensions // _sg2d.GetUserCoordinates(indices, coords); // Now get coordinates of z dimension // coords[2] = _zrg.GetValueAtIndex(cIndices); } bool LayeredGrid::GetIndicesCell(const CoordType &coords, DimsType &indices) const { CoordType cCoords; ClampCoord(coords, cCoords); double dummy[3]; return (_insideGrid(coords, indices, dummy)); return (true); } bool LayeredGrid::InsideGrid(const CoordType &coords) const { // Clamp coordinates on periodic boundaries to reside within the // grid extents (vary-dimensions can not have periodic boundaries) // CoordType cCoords; ClampCoord(coords, cCoords); DimsType indices; bool found = GetIndicesCell(cCoords, indices); return (found); } LayeredGrid::ConstCoordItrLayered::ConstCoordItrLayered(const LayeredGrid *lg, bool begin) : ConstCoordItrAbstract() { _lg = lg; _nElements2D = lg->GetDimensions()[0] * lg->GetDimensions()[1]; _coords = {0.0, 0.0, 0.0}; if (begin) { _index2D = 0; _zCoordItr = lg->_zrg.cbegin(); _itr2D = lg->_sg2d.ConstCoordBegin(); } else { _index2D = _nElements2D - 1; _zCoordItr = lg->_zrg.cend(); _itr2D = lg->_sg2d.ConstCoordEnd(); } } LayeredGrid::ConstCoordItrLayered::ConstCoordItrLayered(const ConstCoordItrLayered &rhs) : ConstCoordItrAbstract() { _lg = rhs._lg; _nElements2D = rhs._nElements2D; _coords = rhs._coords; _index2D = rhs._index2D; _zCoordItr = rhs._zCoordItr; _itr2D = rhs._itr2D; } LayeredGrid::ConstCoordItrLayered::ConstCoordItrLayered() : ConstCoordItrAbstract() { _coords = {0.0, 0.0, 0.0}; } void LayeredGrid::ConstCoordItrLayered::next() { ++_index2D; ++_itr2D; ++_zCoordItr; // Check for overflow // if (_index2D == _nElements2D) { _itr2D = _lg->_sg2d.ConstCoordBegin(); _index2D = 0; } _coords[0] = (*_itr2D)[0]; _coords[1] = (*_itr2D)[1]; _coords[2] = *_zCoordItr; } void LayeredGrid::ConstCoordItrLayered::next(const long &offset) { long offset2D = offset % _nElements2D; if (offset2D + _index2D < _nElements2D) { _itr2D += offset; _index2D += offset; } else { size_t o = (offset2D + _index2D) % _nElements2D; _itr2D = _lg->_sg2d.ConstCoordBegin() + o; _index2D = o; } _coords[0] = (*_itr2D)[0]; _coords[1] = (*_itr2D)[1]; _zCoordItr += offset; _coords[2] = *_zCoordItr; } void LayeredGrid::_getBilinearWeights(const double coords[3], double &iwgt, double &jwgt) const { auto dims = GetDimensions(); size_t indices0[3]; bool found = GetIndicesCell(coords, indices0); VAssert(found); size_t indices1[3] = {indices0[0], indices0[1], indices0[2]}; if (indices0[0] != dims[0] - 1) { indices1[0] += 1; } if (indices0[1] != dims[1] - 1) { indices1[1] += 1; } double coords0[3], coords1[3]; GetUserCoordinates(indices0, coords0); GetUserCoordinates(indices1, coords1); double x = coords[0]; double y = coords[1]; double x0 = coords0[0]; double y0 = coords0[1]; double x1 = coords1[0]; double y1 = coords1[1]; if (x1 != x0) iwgt = fabs((x - x0) / (x1 - x0)); else iwgt = 0.0; if (y1 != y0) jwgt = fabs((y - y0) / (y1 - y0)); else jwgt = 0.0; } double LayeredGrid::_bilinearInterpolation(size_t i0, size_t i1, size_t j0, size_t j1, size_t k0, double iwgt, double jwgt) const { double val00, val01, val10, val11, xVal0, result; double xVal1 = 0.0; double mv = GetMissingValue(); val00 = AccessIJK(i0, j0, k0); val10 = AccessIJK(i1, j0, k0); if ((val00 == mv) || (val10 == mv)) return mv; if (val00 == mv) xVal0 = val10; else if (val10 == mv) xVal0 = val00; else xVal0 = val00 * (1 - iwgt) + val10 * iwgt; val01 = AccessIJK(i0, j1, k0); val11 = AccessIJK(i1, j1, k0); if ((val01 == mv) || (val11 == mv)) return mv; if (val01 == mv) xVal0 = val11; else if (val11 == mv) xVal0 = val01; else xVal1 = val01 * (1 - iwgt) + val11 * iwgt; result = xVal0 * (1 - jwgt) + xVal1 * jwgt; if ((val00 == mv) || (val01 == mv) || (val10 == mv) || (val11 == mv)) return mv; else return result; } double LayeredGrid::_bilinearElevation(size_t i0, size_t i1, size_t j0, size_t j1, size_t k0, double iwgt, double jwgt) const { double xVal0, result; double xVal1 = 0.0; double x, y, z00, z10, z01, z11; GetUserCoordinates(i0, j0, k0, x, y, z00); GetUserCoordinates(i1, j0, k0, x, y, z10); xVal0 = z00 * (1 - iwgt) + z10 * iwgt; GetUserCoordinates(i0, j1, k0, x, y, z01); GetUserCoordinates(i1, j1, k0, x, y, z11); xVal1 = z01 * (1 - iwgt) + z11 * iwgt; result = xVal0 * (1 - jwgt) + xVal1 * jwgt; return result; } float LayeredGrid::_getValueQuadratic(const double coords[3]) const { double mv = GetMissingValue(); auto dims = GetDimensions(); // Get the indecies of the hyperslab containing the point // k0 = level above the point // k1 = level below the point // k2 = two levels below the point // size_t indices[3]; bool found = GetIndicesCell(coords, indices); if (!found) return (GetMissingValue()); size_t i0 = indices[0]; size_t j0 = indices[1]; size_t k1 = indices[2]; size_t k0, k2; size_t i1, j1; if (i0 == dims[0] - 1) i1 = i0; else i1 = i0 + 1; if (j0 == dims[1] - 1) j1 = j0; else j1 = j0 + 1; if (k1 == 0) { k2 = 0; k1 = 1; k0 = 2; } else if (k1 == dims[2] - 1) { k2 = dims[2] - 3; k1 = dims[2] - 2; k0 = dims[2] - 1; } else { k0 = k1 + 1; k2 = k1 - 1; } double iwgt, jwgt; _getBilinearWeights(coords, iwgt, jwgt); // bilinearly interpolated values at each k0, k1 and k2 double val0, val1, val2; val0 = _bilinearInterpolation(i0, i1, j0, j1, k0, iwgt, jwgt); val1 = _bilinearInterpolation(i0, i1, j0, j1, k1, iwgt, jwgt); val2 = _bilinearInterpolation(i0, i1, j0, j1, k2, iwgt, jwgt); if ((val0 == mv) || (val1 == mv) || (val2 == mv)) return mv; // bilinearly interpolated elevations at each k0, k1, and k2 double z0, z1, z2; z0 = _bilinearElevation(i0, i1, j0, j1, k0, iwgt, jwgt); z1 = _bilinearElevation(i0, i1, j0, j1, k1, iwgt, jwgt); z2 = _bilinearElevation(i0, i1, j0, j1, k2, iwgt, jwgt); if ((z0 == mv) || (z1 == mv) || (z2 == mv)) return mv; // quadratic interpolation weights double z = coords[2]; double w0, w1, w2; w0 = ((z - z1) * (z - z2)) / ((z0 - z1) * (z0 - z2)); w1 = ((z - z0) * (z - z2)) / ((z1 - z0) * (z1 - z2)); w2 = ((z - z0) * (z - z1)) / ((z2 - z0) * (z2 - z1)); double val; val = val0 * w0 + val1 * w1 + val2 * w2; return val; } double LayeredGrid::_interpolateVaryingCoord(size_t i0, size_t j0, size_t k0, double x, double y) const { // varying dimension coord at corner grid points of cell face // double c00, c01, c10, c11; auto dims = GetDimensions(); size_t i1, j1, k1; if (i0 == dims[0] - 1) i1 = i0; else i1 = i0 + 1; if (j0 == dims[1] - 1) j1 = j0; else j1 = j0 + 1; if (k0 == dims[2] - 1) k1 = k0; else k1 = k0 + 1; // Coordinates of grid points for non-varying dimensions double x0, y0, z0, x1, y1, z1; GetUserCoordinates(i0, j0, k0, x0, y0, z0); GetUserCoordinates(i1, j1, k1, x1, y1, z1); double iwgt, jwgt; c00 = _zrg.AccessIJK(i0, j0, k0); c01 = _zrg.AccessIJK(i1, j0, k0); c10 = _zrg.AccessIJK(i0, j1, k0); c11 = _zrg.AccessIJK(i1, j1, k0); if (x1 != x0) iwgt = fabs((x - x0) / (x1 - x0)); else iwgt = 0.0; if (y1 != y0) jwgt = fabs((y - y0) / (y1 - y0)); else jwgt = 0.0; double z = c00 + iwgt * (c01 - c00) + jwgt * ((c10 + iwgt * (c11 - c10)) - (c00 + iwgt * (c01 - c00))); return (z); } ================================================ FILE: lib/vdc/NetCDFCFCollection.cpp ================================================ #include #include #include #include #include "vapor/VAssert.h" #ifdef WIN32 #include "vapor/udunits2.h" #else #include #endif #include using namespace VAPoR; using namespace Wasp; using namespace std; namespace { vector make_unique(vector v) { sort(v.begin(), v.end()); vector::iterator last2; last2 = unique(v.begin(), v.end()); v.erase(last2, v.end()); return (v); } }; // namespace NetCDFCFCollection::NetCDFCFCollection() : NetCDFCollection() { _coordinateVars.clear(); _auxCoordinateVars.clear(); _lonCoordVars.clear(); _latCoordVars.clear(); _vertCoordVars.clear(); _timeCoordVars.clear(); _missingValueMap.clear(); _udunit = NULL; } NetCDFCFCollection::~NetCDFCFCollection() { if (_udunit) delete _udunit; } static bool IsNameCFCompliant(const string &name, bool strict=true) { if (!isalpha(name[0]) || (!strict && name[0] == '_')) return false; for (int i = 1; i < name.size(); i++) if (!(isalnum(name[i]) || name[i] == '_' || (!strict && (name[i] == '_' || name[i] == '.' || name[i] == '-')))) return false; return true; } int NetCDFCFCollection::_Initialize(const vector &files) { // Look for time coordinate variables. Must be 1D and have same // name as dimension. Need not be present in all files. // vector tv; for (int j = 0; j < files.size(); j++) { vector emptyvec; vector file(1, files[j]); int rc = NetCDFCollection::Initialize(file, emptyvec, emptyvec); if (rc < 0) return (-1); // Get all 1D variables // vector vars = NetCDFCollection::GetVariableNames(1, false); for (int i = 0; i < vars.size(); i++) { NetCDFSimple::Variable varinfo; (void)NetCDFCollection::GetVariableInfo(vars[i], varinfo); if (_IsCoordinateVar(varinfo) && _IsTimeCoordVar(varinfo)) { tv.push_back(vars[i]); } } if (tv.size()) break; // Should we process all files??? } // // Reinitialize the base class now that we know the time coordinate // variable. We're assuming that the time coordinate variable and // the time dimension have the same name. Thus we're not handling // the case where time variable could be a CF "auxilliary // coordinate variable". // int rc = NetCDFCollection::Initialize(files, tv, tv); if (rc < 0) return (-1); for (const auto &v : GetVariableNames(-1, false)) { if (!IsNameCFCompliant(v, false)) { SetErrMsg("Variable name \"%s\" is not compliant with NetCDF-CF", v.c_str()); return -1; } } return (0); } int NetCDFCFCollection::Initialize(const vector &files) { _coordinateVars.clear(); _auxCoordinateVars.clear(); _lonCoordVars.clear(); _latCoordVars.clear(); _vertCoordVars.clear(); _timeCoordVars.clear(); _missingValueMap.clear(); if (_udunit) delete _udunit; _udunit = new UDUnits(); int rc = _udunit->Initialize(); if (rc < 0) { SetErrMsg("Failed to initialized udunits2 library : %s", _udunit->GetErrMsg().c_str()); return (0); } rc = _Initialize(files); if (rc < 0) return (-1); // // Identify all of the CF "coordinate" variables first, // which are 1D in space // or 1D in time and have // the same name as their one dimension // vector vars = NetCDFCollection::GetVariableNames(1, true); vector tcvars = NetCDFCollection::GetVariableNames(1, false); vars.insert(vars.end(), tcvars.begin(), tcvars.end()); for (int i = 0; i < vars.size(); i++) { NetCDFSimple::Variable varinfo; (void)NetCDFCollection::GetVariableInfo(vars[i], varinfo); if (_IsCoordinateVar(varinfo)) { _coordinateVars.push_back(vars[i]); } } // Now find all coordinate variables that can be identified // by their units, standard name, etc. // vars.clear(); for (int i = 1; i < 4; i++) { vector v = NetCDFCollection::GetVariableNames(i, false); vars.insert(vars.end(), v.begin(), v.end()); } for (auto varName : vars) { NetCDFSimple::Variable varinfo; (void)NetCDFCollection::GetVariableInfo(varName, varinfo); if (_IsLonCoordVar(varinfo)) { _lonCoordVars.push_back(varName); _auxCoordinateVars.push_back(varName); } else if (_IsLatCoordVar(varinfo)) { _latCoordVars.push_back(varName); _auxCoordinateVars.push_back(varName); } else if (_IsVertCoordVar(varinfo)) { _vertCoordVars.push_back(varName); _auxCoordinateVars.push_back(varName); // // Only support CF "Coordinate" variables as time coord variables // } else if (_IsCoordinateVar(varinfo) && _IsTimeCoordVar(varinfo)) { _timeCoordVars.push_back(varName); _auxCoordinateVars.push_back(varName); } } // Finally, any variable that is identified by a "coordinate" variable // attribute is an "auxilliary" coordinate variable // vars.clear(); for (int i = 0; i < 4; i++) { vector v = NetCDFCollection::GetVariableNames(1, false); vars.insert(vars.end(), v.begin(), v.end()); } for (auto varName : vars) { string timeDimName; NetCDFSimple::Variable varinfo; (void)NetCDFCollection::GetVariableInfo(varName, varinfo); if (!GetTimeDimName(varName).empty()) timeDimName = GetTimeDimName(varName); vector coordattr = _GetCoordAttrs(varinfo); if (!coordattr.size()) continue; for (int j = 0; j < coordattr.size(); j++) { // // Make sure the auxiliary coordinate variable // actually exists in the data collection // if (NetCDFCollection::VariableExists(coordattr[j])) { _auxCoordinateVars.push_back(coordattr[j]); } } } // // sort and remove duplicate coordinate variables // _coordinateVars = make_unique(_coordinateVars); _auxCoordinateVars = make_unique(_auxCoordinateVars); _lonCoordVars = make_unique(_lonCoordVars); _latCoordVars = make_unique(_latCoordVars); _vertCoordVars = make_unique(_vertCoordVars); _timeCoordVars = make_unique(_timeCoordVars); string mvattname; _GetMissingValueMap(_missingValueMap); return (0); } vector NetCDFCFCollection::GetDataVariableNames(int ndim, bool spatial) const { vector tmp = NetCDFCollection::GetVariableNames(ndim, spatial); vector varnames; for (int i = 0; i < tmp.size(); i++) { // // Strip off any coordinate variables // if (IsCoordVarCF(tmp[i])) continue; vector cvars; bool enable = EnableErrMsg(false); int rc = NetCDFCFCollection::GetVarCoordVarNames(tmp[i], cvars); EnableErrMsg(enable); SetErrCode(0); if (rc < 0) continue; // Doesn't have coordinate variables int myndim = cvars.size(); if (spatial && IsTimeVarying(tmp[i])) { myndim--; // don't count time dimension } if (myndim != ndim) continue; varnames.push_back(tmp[i]); } return (varnames); } int NetCDFCFCollection::GetVarCoordVarNames(string var, vector &cvars) const { cvars.clear(); NetCDFSimple::Variable varinfo; int rc = NetCDFCollection::GetVariableInfo(var, varinfo); if (rc < 0) return (rc); vector dimnames = varinfo.GetDimNames(); // // First look for auxiliary coordinate variables // bool hasTimeCoord = false; bool hasLatCoord = false; bool hasLonCoord = false; bool hasVertCoord = false; vector tmpcvars; vector auxcvars = _GetCoordAttrs(varinfo); for (int i = 0; i < auxcvars.size(); i++) { // // Make sure variable specified by "coordinate" attribute is in // fact an auxiliary coordinate variable (any coordinate variables // specified by the "coordinate" attribute should have already // been picked up above // if (NetCDFCFCollection::IsTimeCoordVar(auxcvars[i]) && !hasTimeCoord) { hasTimeCoord = true; tmpcvars.push_back(auxcvars[i]); } if (NetCDFCFCollection::IsLatCoordVar(auxcvars[i]) && !hasLatCoord) { hasLatCoord = true; tmpcvars.push_back(auxcvars[i]); } if (NetCDFCFCollection::IsLonCoordVar(auxcvars[i]) && !hasLonCoord) { hasLonCoord = true; tmpcvars.push_back(auxcvars[i]); } if (NetCDFCFCollection::IsVertCoordVar(auxcvars[i]) && !hasVertCoord) { hasVertCoord = true; tmpcvars.push_back(auxcvars[i]); } } // Ugh. Stupid hack to make Z3 the vertical coordinate variable // for 3D CAM variables // if (!hasVertCoord) { vector v, vars; v = NetCDFCollection::GetVariableNames(3, false); vars.insert(vars.end(), v.begin(), v.end()); v = NetCDFCollection::GetVariableNames(4, false); vars.insert(vars.end(), v.begin(), v.end()); } // // Now see if any "coordinate variables" for which we haven't // already identified a coord var exist. // if (tmpcvars.size() != dimnames.size()) { for (int i = 0; i < dimnames.size(); i++) { if (NetCDFCFCollection::IsCoordVarCF(dimnames[i])) { // is a CF "coordinate variable"? if (NetCDFCFCollection::IsTimeCoordVar(dimnames[i]) && !hasTimeCoord) { hasTimeCoord = true; tmpcvars.push_back(dimnames[i]); } if (NetCDFCFCollection::IsLatCoordVar(dimnames[i]) && !hasLatCoord) { hasLatCoord = true; tmpcvars.push_back(dimnames[i]); } if (NetCDFCFCollection::IsLonCoordVar(dimnames[i]) && !hasLonCoord) { hasLonCoord = true; tmpcvars.push_back(dimnames[i]); } if (NetCDFCFCollection::IsVertCoordVar(dimnames[i]) && !hasVertCoord) { hasVertCoord = true; tmpcvars.push_back(dimnames[i]); } } } } // // If we still don't have lat and lon coordinate (or auxiliary) // variables for 'var' then we look for coordinate variables whose // dim names match the dim names of 'var'. Don't think this is // part of the CF 1.6 spec, but it seems necessary for ROMS data sets // // // If "coordinate variables" are specified for each dimension we're don // if (tmpcvars.size() != dimnames.size()) { if (!hasLatCoord) { vector latcvs = NetCDFCFCollection::GetLatCoordVars(); for (int i = 0; i < latcvs.size(); i++) { NetCDFSimple::Variable varinfo; NetCDFCollection::GetVariableInfo(latcvs[i], varinfo); vector dns = varinfo.GetDimNames(); if (dimnames.size() >= dns.size()) { vector tmp(dimnames.end() - dns.size(), dimnames.end()); if (tmp == dns) { tmpcvars.push_back(latcvs[i]); break; } } } } if (!hasLonCoord) { vector loncvs = NetCDFCFCollection::GetLonCoordVars(); for (int i = 0; i < loncvs.size(); i++) { NetCDFSimple::Variable varinfo; NetCDFCollection::GetVariableInfo(loncvs[i], varinfo); vector dns = varinfo.GetDimNames(); if (dimnames.size() >= dns.size()) { vector tmp(dimnames.end() - dns.size(), dimnames.end()); if (tmp == dns) { tmpcvars.push_back(loncvs[i]); break; } } } } } if (tmpcvars.size() != dimnames.size()) { SetErrMsg("Non-conforming CF variable : %s", var.c_str()); return (-1); } // // Finally, order the coordinate variables from slowest to fastest // varying dimension // for (int i = 0; i < tmpcvars.size(); i++) { if (NetCDFCFCollection::IsTimeCoordVar(tmpcvars[i])) { cvars.push_back(tmpcvars[i]); break; } } for (int i = 0; i < tmpcvars.size(); i++) { if (NetCDFCFCollection::IsVertCoordVar(tmpcvars[i])) { cvars.push_back(tmpcvars[i]); break; } } for (int i = 0; i < tmpcvars.size(); i++) { if (NetCDFCFCollection::IsLatCoordVar(tmpcvars[i])) { cvars.push_back(tmpcvars[i]); break; } } for (int i = 0; i < tmpcvars.size(); i++) { if (NetCDFCFCollection::IsLonCoordVar(tmpcvars[i])) { cvars.push_back(tmpcvars[i]); break; } } VAssert(cvars.size() == tmpcvars.size()); return (0); } bool NetCDFCFCollection::IsVertCoordVarPressure(string var) const { if (!IsVertCoordVar(var)) return (false); NetCDFSimple::Variable varinfo; bool enable = EnableErrMsg(false); int rc = NetCDFCollection::GetVariableInfo(var, varinfo); if (rc < 0) { EnableErrMsg(enable); return (false); } string unit; varinfo.GetAtt("units", unit); if (unit.empty()) return (false); // No coordinates attribute found return (_udunit->IsPressureUnit(unit)); } bool NetCDFCFCollection::IsVertCoordVarLength(string var) const { if (!IsVertCoordVar(var)) return (false); NetCDFSimple::Variable varinfo; bool enable = EnableErrMsg(false); int rc = NetCDFCollection::GetVariableInfo(var, varinfo); EnableErrMsg(enable); if (rc < 0) { return (false); } string unit; varinfo.GetAtt("units", unit); if (unit.empty()) return (false); // No coordinates attribute found return (_udunit->IsLengthUnit(unit)); } bool NetCDFCFCollection::IsVertCoordVarUp(string cvar) const { NetCDFSimple::Variable varinfo; int rc = NetCDFCollection::GetVariableInfo(cvar, varinfo); if (rc < 0) { SetErrCode(0); return (false); } string s; varinfo.GetAtt("positive", s); if (StrCmpNoCase(s, "up") == 0) return (true); else return (false); } int NetCDFCFCollection::GetVarUnits(string var, string &units) const { units.clear(); NetCDFSimple::Variable varinfo; int rc = NetCDFCollection::GetVariableInfo(var, varinfo); if (rc < 0) return (rc); varinfo.GetAtt("units", units); return (0); } int NetCDFCFCollection::Convert(const string from, const string to, const double *src, double *dst, size_t n) const { bool status = _udunit->Convert(from, to, src, dst, n); if (!status) { SetErrMsg("NetCDFCFCollection::Convert(%s , %s,,) : failed", from.c_str(), to.c_str()); return (-1); } return (0); } int NetCDFCFCollection::Convert(const string from, const string to, const float *src, float *dst, size_t n) const { bool status = _udunit->Convert(from, to, src, dst, n); if (!status) { SetErrMsg("NetCDFCFCollection::Convert(%s , %s,,) : failed", from.c_str(), to.c_str()); return (-1); } return (0); } bool NetCDFCFCollection::GetMissingValue(string varname, double &mv) const { map::const_iterator itr; itr = _missingValueMap.find(varname); if (itr != _missingValueMap.end()) { mv = itr->second; return (true); } return (false); } int NetCDFCFCollection::OpenRead(size_t ts, string varname) { int fd = NetCDFCollection::OpenRead(ts, varname); return (fd); } bool NetCDFCFCollection::IsVertDimensionless(string cvar) const { // // Return false if variable isn't a vertical coordinate variable at all // if (!IsVertCoordVar(cvar)) return (false); // // If we get to here the cvar is a valid coordinate variable // so GetVariableInfo() should return successfully // NetCDFSimple::Variable varinfo; (void)NetCDFCollection::GetVariableInfo(cvar, varinfo); string unit; varinfo.GetAtt("units", unit); if (unit.empty()) return (false); // No coordinates attribute found return (!(_udunit->IsPressureUnit(unit) || _udunit->IsLengthUnit(unit))); } bool NetCDFCFCollection::GetMapProjectionProj4(string varname, string &proj4string) const { proj4string.clear(); bool enable = EnableErrMsg(false); NetCDFSimple::Variable varinfo; int rc = NetCDFCollection::GetVariableInfo(varname, varinfo); EnableErrMsg(enable); SetErrCode(0); if (rc < 0) return (false); // If variable has a map projection a NetCDF variable named // after the projection will exist that contains map projection // parameter attributes // string projection; varinfo.GetAtt("grid_mapping", projection); if (projection.empty()) return (false); // No map projection found // Currently only support rotated_latitude_longitude // if (projection.compare("rotated_latitude_longitude") != 0) return (false); enable = EnableErrMsg(false); rc = NetCDFCollection::GetVariableInfo(projection, varinfo); EnableErrMsg(enable); SetErrCode(0); if (rc < 0) return (false); vector lon0, pole_lat, pole_lon; varinfo.GetAtt("longitude_of_prime_meridian", lon0); varinfo.GetAtt("grid_north_pole_longitude", pole_lon); varinfo.GetAtt("grid_north_pole_latitude", pole_lat); if (lon0.size() != 1 || pole_lon.size() != 1 || pole_lat.size() != 1) { return (false); // Probably should return error } ostringstream oss; proj4string = "+ellps=WGS84 "; proj4string += "+proj=ob_tran"; proj4string += " +o_proj=eqc"; proj4string += " +to_meter=0.0174532925199"; proj4string += " +o_lat_p="; oss.str(""); oss << (double)pole_lat[0]; proj4string += oss.str(); proj4string += "d"; // degrees, not radians proj4string += " +o_lon_p="; oss.str(""); // oss << (double)(180. + pole_lon[0]); oss << (double)(-lon0[0]); proj4string += oss.str(); proj4string += "d"; // degrees, not radians proj4string += " +lon_0="; oss.str(""); // oss << (double)(-lon0[0]); oss << (double)(180. + pole_lon[0]); proj4string += oss.str(); proj4string += "d"; // degrees, not radians proj4string += " +no_defs"; return (true); } void NetCDFCFCollection::FormatTimeStr(double seconds, string &str) const { int year, month, day, hour, minute, second; _udunit->DecodeTime(seconds, &year, &month, &day, &hour, &minute, &second); ostringstream oss; oss.fill('0'); oss.width(4); oss << year; oss << "-"; oss.width(2); oss << month; oss << "-"; oss.width(2); oss << day; oss << " "; oss.width(2); oss << hour; oss << ":"; oss.width(2); oss << minute; oss << ":"; oss.width(2); oss << second; oss << " "; str = oss.str(); } namespace VAPoR { std::ostream &operator<<(std::ostream &o, const NetCDFCFCollection &ncdfcfc) { o << "NetCDFCFCollection" << endl; o << " _coordinateVars : "; for (int i = 0; i < ncdfcfc._coordinateVars.size(); i++) { o << ncdfcfc._coordinateVars[i] << " "; } o << endl; o << " _lonCoordVars : "; for (int i = 0; i < ncdfcfc._lonCoordVars.size(); i++) { o << ncdfcfc._lonCoordVars[i] << " "; } o << endl; o << " _latCoordVars : "; for (int i = 0; i < ncdfcfc._latCoordVars.size(); i++) { o << ncdfcfc._latCoordVars[i] << " "; } o << endl; o << " _vertCoordVars : "; for (int i = 0; i < ncdfcfc._vertCoordVars.size(); i++) { o << ncdfcfc._vertCoordVars[i] << " "; } o << endl; o << " _timeCoordVars : "; for (int i = 0; i < ncdfcfc._timeCoordVars.size(); i++) { o << ncdfcfc._timeCoordVars[i] << " "; } o << endl; o << " _missingValueMap : "; std::map::const_iterator itr; for (itr = ncdfcfc._missingValueMap.begin(); itr != ncdfcfc._missingValueMap.end(); ++itr) { o << itr->first << " " << itr->second << ", "; } o << endl; o << " Data Variables and coordinates :" << endl; for (int dim = 1; dim < 4; dim++) { vector vars = ncdfcfc.GetDataVariableNames(dim, true); for (int i = 0; i < vars.size(); i++) { o << " " << vars[i] << " : "; vector cvars; int rc = ncdfcfc.GetVarCoordVarNames(vars[i], cvars); if (rc < 0) continue; for (int j = 0; j < cvars.size(); j++) { o << cvars[j] << " "; } o << endl; } } o << endl; o << endl; o << (const NetCDFCollection &)ncdfcfc; return (o); } }; // namespace VAPoR bool NetCDFCFCollection::_IsCoordinateVar(const NetCDFSimple::Variable &varinfo) const { string varname = varinfo.GetName(); vector dimnames = varinfo.GetDimNames(); // A CF "coordinate variable" is a 1D variable whose name matches // its dimension name. Here we also allow a variable with 1 spatial // dimension and 1 time dimension // if (dimnames.size() == 1 && varname == dimnames[0]) return (true); if (dimnames.size() == 2 && IsTimeVarying(varname) && varname == dimnames[1]) return (true); return (false); } vector NetCDFCFCollection::_GetCoordAttrs(const NetCDFSimple::Variable &varinfo) const { vector coordattrs; string s; varinfo.GetAtt("coordinates", s); if (s.empty()) return (coordattrs); // No coordinates attribute found // // split the string using white space as the delimiter // stringstream ss(s); istream_iterator begin(ss); istream_iterator end; coordattrs.insert(coordattrs.begin(), begin, end); return (coordattrs); } bool NetCDFCFCollection::_IsLonCoordVar(const NetCDFSimple::Variable &varinfo) const { string s; varinfo.GetAtt("axis", s); if (StrCmpNoCase(s, "X") == 0) return (true); s.clear(); varinfo.GetAtt("standard_name", s); if (StrCmpNoCase(s, "longitude") == 0) return (true); if (StrCmpNoCase(s, "grid_longitude") == 0) return (true); string unit; varinfo.GetAtt("units", unit); if (unit.empty()) return (false); // No coordinates attribute found return (_udunit->IsLonUnit(unit)); } bool NetCDFCFCollection::_IsLatCoordVar(const NetCDFSimple::Variable &varinfo) const { string s; varinfo.GetAtt("axis", s); if (StrCmpNoCase(s, "Y") == 0) return (true); s.clear(); varinfo.GetAtt("standard_name", s); if (StrCmpNoCase(s, "latitude") == 0) return (true); if (StrCmpNoCase(s, "grid_latitude") == 0) return (true); string unit; varinfo.GetAtt("units", unit); if (unit.empty()) return (false); // No coordinates attribute found return (_udunit->IsLatUnit(unit)); } bool NetCDFCFCollection::_IsVertCoordVar(const NetCDFSimple::Variable &varinfo) const { if (varinfo.GetDimNames().size() < 1) return (false); string s; varinfo.GetAtt("axis", s); if (StrCmpNoCase(s, "Z") == 0) return (true); // The attribute "cartesian_axis" is not part of the CF spec, but // apparently the MOM6 ocean model uses it :-( // varinfo.GetAtt("cartesian_axis", s); if (StrCmpNoCase(s, "Z") == 0) return (true); s.clear(); varinfo.GetAtt("standard_name", s); if (StrCmpNoCase(s, "atmosphere_ln_pressure_coordinate") == 0) return (true); if (StrCmpNoCase(s, "atmosphere_sigma_coordinate") == 0) return (true); if (StrCmpNoCase(s, "atmosphere_hybrid_sigma_pressure_coordinate") == 0) return (true); if (StrCmpNoCase(s, "atmosphere_hybrid_height_coordinate") == 0) return (true); if (StrCmpNoCase(s, "atmosphere_sleve_coordinate") == 0) return (true); if (StrCmpNoCase(s, "ocean_sigma_coordinate") == 0) return (true); if (StrCmpNoCase(s, "ocean_s_coordinate") == 0) return (true); if (StrCmpNoCase(s, "ocean_double_sigma_coordinate") == 0) return (true); if (StrCmpNoCase(s, "ocean_double_sigma_coordinate") == 0) return (true); if (StrCmpNoCase(s, "ocean_s_coordinate_g1") == 0) return (true); if (StrCmpNoCase(s, "ocean_s_coordinate_g2") == 0) return (true); if (StrCmpNoCase(s, "altitude") == 0) return (true); s.clear(); varinfo.GetAtt("long_name", s); if (StrCmpNoCase(s, "model_level_number") == 0) return (true); varinfo.GetAtt("positive", s); if ((StrCmpNoCase(s, "up") == 0) || (StrCmpNoCase(s, "down") == 0)) return (true); string unit; varinfo.GetAtt("units", unit); if (unit.empty()) return (false); // No coordinates attribute found return (_udunit->IsPressureUnit(unit) || _udunit->IsLengthUnit(unit)); } bool NetCDFCFCollection::_IsTimeCoordVar(const NetCDFSimple::Variable &varinfo) const { string s; varinfo.GetAtt("axis", s); if (StrCmpNoCase(s, "T") == 0) return (true); s.clear(); varinfo.GetAtt("standard_name", s); if (StrCmpNoCase(s, "time") == 0) return (true); string unit; varinfo.GetAtt("units", unit); if (unit.empty()) return (false); // No coordinates attribute found return (_udunit->IsTimeUnit(unit)); } bool NetCDFCFCollection::_GetMissingValue(string varname, string attname, double &mv) const { mv = 0.0; NetCDFSimple::Variable varinfo; (void)NetCDFCollection::GetVariableInfo(varname, varinfo); vector dvec; varinfo.GetAtt(attname, dvec); if (dvec.size()) { mv = dvec[0]; return (true); } return (false); } void NetCDFCFCollection::_GetMissingValueMap(map &missingValueMap) const { missingValueMap.clear(); // // Generate a map from all data variables with missing value // attributes to missing value values. The CF conventions allow // for two different attributes to specify missing values, "missing_value", // and "_FillValue". The latter is for historical reasaons. Here we look // for either, but give priority to "missing_value" // for (int d = 1; d < 5; d++) { vector vars = NetCDFCFCollection::GetDataVariableNames(d, false); for (int i = 0; i < vars.size(); i++) { double mv; if (_GetMissingValue(vars[i], "_FillValue", mv)) { missingValueMap[vars[i]] = mv; } if (_GetMissingValue(vars[i], "missing_value", mv)) { missingValueMap[vars[i]] = mv; } } } } ================================================ FILE: lib/vdc/NetCDFCollection.cpp ================================================ #include #include #include #include #include "vapor/VAssert.h" #include #include using namespace VAPoR; using namespace Wasp; using namespace std; namespace { const string derivedTimeDimName = "derivedTimeDim"; template vector make_container_unique(vector v) { sort(v.begin(), v.end()); auto last2 = unique(v.begin(), v.end()); v.erase(last2, v.end()); return (v); } }; // namespace NetCDFCollection::NetCDFCollection() { _variableList.clear(); _dimNames.clear(); _dimLens.clear(); _missingValAttName.clear(); _times.clear(); _timesMap.clear(); _ovr_table.clear(); _ncdfmap.clear(); _failedVars.clear(); } NetCDFCollection::~NetCDFCollection() { ReInitialize(); } void NetCDFCollection::ReInitialize() { map::iterator itr; for (itr = _ncdfmap.begin(); itr != _ncdfmap.end(); ++itr) { delete itr->second; } std::map::iterator itr1; for (itr1 = _ovr_table.begin(); itr1 != _ovr_table.end(); ++itr1) { int fd = itr1->first; (void)NetCDFCollection::Close(fd); } _variableList.clear(); _dimNames.clear(); _dimLens.clear(); _missingValAttName.clear(); _times.clear(); _timesMap.clear(); _ovr_table.clear(); _ncdfmap.clear(); _failedVars.clear(); } int NetCDFCollection::Initialize(const vector &files, const vector &time_dimnames, const vector &time_coordvars) { vector l_time_dimnames = time_dimnames; ReInitialize(); // // Build a hash table to map a variable's time dimension // to its time coordinates // int file_org; // case 1, 2, 3 (3a or 3b) map timeDimLens; int rc = NetCDFCollection::_InitializeTimesMap(files, l_time_dimnames, time_coordvars, _timesMap, timeDimLens, _times, file_org); if (rc < 0) return (-1); for (auto itr : timeDimLens) { _dimNames.push_back(itr.first); _dimLens.push_back(itr.second); _dimIsTimeVarying.push_back(false); } for (int i = 0; i < files.size(); i++) { NetCDFSimple *netcdf = new NetCDFSimple(); _ncdfmap[files[i]] = netcdf; rc = netcdf->Initialize(files[i]); if (rc < 0) { SetErrMsg("NetCDFSimple::Initialize(%s)", files[i].c_str()); return (-1); } // printf("INIT %i = %s\n", i, files[i].c_str()); // // Get dimension names and lengths // vector dimnames; vector dims; netcdf->GetDimensions(dimnames, dims); for (int j = 0; j < dimnames.size(); j++) { // Handle time dims separately // if (timeDimLens.find(dimnames[j]) != timeDimLens.end()) continue; // No duplicates // vector::iterator itr; itr = find(_dimNames.begin(), _dimNames.end(), dimnames[j]); if (itr == _dimNames.end()) { _dimNames.push_back(dimnames[j]); _dimLens.push_back(dims[j]); _dimIsTimeVarying.push_back(false); } else if (_dimLens[itr - _dimNames.begin()] != dims[j]) { _dimIsTimeVarying[itr - _dimNames.begin()] = true; } } // // Get variable info for all variables in current file // const vector &variables = netcdf->GetVariables(); // // For each variable in the file add it to _variablesList // for (int j = 0; j < variables.size(); j++) { string name = variables[j].GetName(); map::iterator p = _variableList.find(name); // // If this is the first time we've seen this variable // add it to _variablesList // if (p == _variableList.end()) { TimeVaryingVar tvv; _variableList[name] = tvv; p = _variableList.find(name); } TimeVaryingVar &tvvref = p->second; bool enable = EnableErrMsg(false); int rc = tvvref.Insert(netcdf, variables[j], files[i], l_time_dimnames, _timesMap, file_org); (void)EnableErrMsg(enable); if (rc < 0) { SetErrCode(0); _failedVars.push_back(files[i] + ": " + variables[j].GetName()); continue; } } } for (auto itr = _variableList.begin(); itr != _variableList.end(); ++itr) { TimeVaryingVar &tvvref = itr->second; tvvref.Sort(); } return (0); } #include long NetCDFCollection::GetDimLengthAtTime(string name, long ts) { double realTime = _times[ts]; const auto end = _timesMap.cend(); string filePath; for (auto it = _timesMap.cbegin(); it != end; ++it) { for (int i = 0; i < it->second.size(); i++) { if (it->second[i] == realTime) { filePath = it->first; if (filePath == "constant") continue; goto SEARCH_FINISHED; } } } SEARCH_FINISHED: if (filePath.empty()) { MyBase::SetErrMsg("Time %li (%f) not found", ts, realTime); assert(0); return -1; } NetCDFSimple *nc = nullptr; for (auto it = _ncdfmap.cbegin(); it != _ncdfmap.cend(); ++it) { if (STLUtils::BeginsWith(filePath, it->first)) { nc = it->second; break; } } if (!nc) { MyBase::SetErrMsg("NC for file not found"); assert(0); return -1; } vector names; vector lengths; nc->GetDimensions(names, lengths); for (int i = 0; i < names.size(); i++) { if (names[i] == name) { return lengths[i]; } } MyBase::SetErrMsg("Dimension not found at timestep %li", ts); return -1; } bool NetCDFCollection::VariableExists(string varname) const { map::const_iterator p = _variableList.find(varname); if (p == _variableList.end()) { return (false); } return (true); } bool NetCDFCollection::VariableExists(size_t ts, string varname) const { if (ts >= _times.size()) return (false); map::const_iterator p = _variableList.find(varname); if (p == _variableList.end()) { return (false); } const TimeVaryingVar &tvvar = p->second; if (!tvvar.GetTimeVarying()) return (true); // CV variables exist for all times double mytime = _times[ts]; vector times = tvvar.GetTimes(); for (int i = 0; i < times.size(); i++) { if (times[i] == mytime) return (true); } return (false); } vector NetCDFCollection::GetVariableNames(int ndims, bool spatial) const { map::const_iterator p = _variableList.begin(); vector names; for (; p != _variableList.end(); ++p) { const TimeVaryingVar &tvvars = p->second; int myndims = tvvars.GetSpatialDims().size(); if (!spatial && tvvars.GetTimeVarying()) { myndims++; } if (myndims == ndims || ndims == -1) { names.push_back(p->first); } } return (names); } vector NetCDFCollection::GetSpatialDims(string varname) const { map::const_iterator p = _variableList.find(varname); if (p == _variableList.end()) { return (vector()); } const TimeVaryingVar &tvvars = p->second; return (tvvars.GetSpatialDims()); } vector NetCDFCollection::GetSpatialDimNames(string varname) const { vector dimnames; map::const_iterator p = _variableList.find(varname); if (p == _variableList.end()) { return (dimnames); } const TimeVaryingVar &tvvars = p->second; dimnames = tvvars.GetSpatialDimNames(); return (dimnames); } size_t NetCDFCollection::GetTimeDim(string varname) const { map::const_iterator p = _variableList.find(varname); if (p == _variableList.end()) { return (0); } const TimeVaryingVar &tvvars = p->second; return (tvvars.GetNumTimeSteps()); } string NetCDFCollection::GetTimeDimName(string varname) const { string dimname; map::const_iterator p = _variableList.find(varname); if (p == _variableList.end()) { return (dimname); } const TimeVaryingVar &tvvars = p->second; dimname = tvvars.GetTimeDimName(); return (dimname); } vector NetCDFCollection::GetDims(string varname) const { std::vector dims = NetCDFCollection::GetSpatialDims(varname); if (NetCDFCollection::IsTimeVarying(varname)) { dims.insert(dims.begin(), NetCDFCollection::GetTimeDim(varname)); } return (dims); } vector NetCDFCollection::GetDimNames(string varname) const { std::vector dimnames = NetCDFCollection::GetSpatialDimNames(varname); if (NetCDFCollection::IsTimeVarying(varname)) { dimnames.insert(dimnames.begin(), NetCDFCollection::GetTimeDimName(varname)); } return (dimnames); } bool NetCDFCollection::IsTimeVarying(string varname) const { map::const_iterator p = _variableList.find(varname); if (p == _variableList.end()) { return (false); } const TimeVaryingVar &tvvars = p->second; return (tvvars.GetTimeVarying()); } int NetCDFCollection::GetXType(string varname) const { NetCDFSimple::Variable varinfo; int rc = NetCDFCollection::GetVariableInfo(varname, varinfo); if (rc < 0) return (-1); return (varinfo.GetXType()); } std::vector NetCDFCollection::GetAttNames(string varname) const { std::vector attnames; // // See if global attribute // if (varname.empty()) { if (_ncdfmap.empty()) { return (attnames); } NetCDFSimple *netcdf = _ncdfmap.begin()->second; return (netcdf->GetAttNames()); } NetCDFSimple::Variable varinfo; bool ok = NetCDFCollection::_GetVariableInfo(varname, varinfo); if (!ok) { return (attnames); } return (varinfo.GetAttNames()); } int NetCDFCollection::GetAttType(string varname, string attname) const { // // See if global attribute // if (varname.empty()) { if (_ncdfmap.empty()) { return (-1); } NetCDFSimple *netcdf = _ncdfmap.begin()->second; return (netcdf->GetAttType(attname)); } NetCDFSimple::Variable varinfo; bool ok = NetCDFCollection::_GetVariableInfo(varname, varinfo); if (!ok) { return (-1); } return (varinfo.GetAttType(attname)); } void NetCDFCollection::GetAtt(string varname, string attname, std::vector &values) const { values.clear(); // // See if global attribute // if (varname.empty()) { if (_ncdfmap.empty()) { return; } NetCDFSimple *netcdf = _ncdfmap.begin()->second; netcdf->GetAtt(attname, values); return; } NetCDFSimple::Variable varinfo; bool ok = NetCDFCollection::_GetVariableInfo(varname, varinfo); if (!ok) { return; } varinfo.GetAtt(attname, values); } void NetCDFCollection::GetAtt(string varname, string attname, std::vector &values) const { values.clear(); // // See if global attribute // if (varname.empty()) { if (_ncdfmap.empty()) { return; } NetCDFSimple *netcdf = _ncdfmap.begin()->second; netcdf->GetAtt(attname, values); return; } NetCDFSimple::Variable varinfo; bool ok = NetCDFCollection::_GetVariableInfo(varname, varinfo); if (!ok) { return; } varinfo.GetAtt(attname, values); } void NetCDFCollection::GetAtt(string varname, string attname, string &values) const { values.clear(); // // See if global attribute // if (varname.empty()) { if (_ncdfmap.empty()) { return; } NetCDFSimple *netcdf = _ncdfmap.begin()->second; netcdf->GetAtt(attname, values); return; } NetCDFSimple::Variable varinfo; bool ok = NetCDFCollection::_GetVariableInfo(varname, varinfo); if (!ok) { return; } varinfo.GetAtt(attname, values); } int NetCDFCollection::GetTime(size_t ts, double &time) const { time = 0.0; if (ts >= _times.size()) { SetErrMsg("Invalid time step: %d", ts); return (-1); } time = _times[ts]; return (0); } int NetCDFCollection::GetTimes(string varname, vector ×) const { map::const_iterator p = _variableList.find(varname); if (p == _variableList.end()) { SetErrMsg("Invalid variable \"%s\"", varname.c_str()); return (-1); } const TimeVaryingVar &tvvars = p->second; if (!tvvars.GetTimeVarying()) { times = _times; // CV variables defined for all times } else { times = tvvars.GetTimes(); } return (0); } int NetCDFCollection::GetFile(size_t ts, string varname, string &file, size_t &local_ts) const { map::const_iterator p = _variableList.find(varname); if (p == _variableList.end()) { SetErrMsg("Invalid variable \"%s\"", varname.c_str()); return (-1); } const TimeVaryingVar &tvvars = p->second; double time; int rc = GetTime(ts, time); if (rc < 0) return (-1); size_t var_ts; rc = tvvars.GetTimeStep(time, var_ts); if (rc < 0) return (-1); local_ts = tvvars.GetLocalTimeStep(var_ts); return (tvvars.GetFile(var_ts, file)); } bool NetCDFCollection::_GetVariableInfo(string varname, NetCDFSimple::Variable &varinfo) const { map::const_iterator p = _variableList.find(varname); if (p == _variableList.end()) { return (false); } const TimeVaryingVar &tvvars = p->second; tvvars.GetVariableInfo(varinfo); vector dimnames = tvvars.GetSpatialDimNames(); if (!(tvvars.GetTimeDimName().empty())) { dimnames.insert(dimnames.begin(), tvvars.GetTimeDimName()); } varinfo.SetDimNames(dimnames); return (true); } int NetCDFCollection::GetVariableInfo(string varname, NetCDFSimple::Variable &varinfo) const { bool ok = NetCDFCollection::_GetVariableInfo(varname, varinfo); if (!ok) { SetErrMsg("Invalid variable \"%s\"", varname.c_str()); return (-1); } return (0); } bool NetCDFCollection::GetMissingValue(string varname, double &mv) const { map::const_iterator p = _variableList.find(varname); if (p == _variableList.end()) { SetErrMsg("Invalid variable \"%s\"", varname.c_str()); return (false); } const TimeVaryingVar &tvvars = p->second; return (tvvars.GetMissingValue(_missingValAttName, mv)); } int NetCDFCollection::OpenRead(size_t ts, string varname) { // // Find a file descriptor. Use lowest available, starting with zero // int fd; for (fd = 0; fd < _ovr_table.size(); fd++) { if (_ovr_table.find(fd) == _ovr_table.end()) { break; } } fileHandle fh; _ovr_table[fd] = fh; map::const_iterator p = _variableList.find(varname); if (p == _variableList.end()) { SetErrMsg("Invalid variable \"%s\"", varname.c_str()); return (-1); } const TimeVaryingVar &tvvars = p->second; double time; int rc = GetTime(ts, time); if (rc < 0) return (-1); size_t var_ts; rc = tvvars.GetTimeStep(time, var_ts); if (rc < 0) return (-1); fh._tvvars = tvvars; fh._local_ts = fh._tvvars.GetLocalTimeStep(var_ts); fh._slice = 0; fh._first_slice = true; string path; NetCDFSimple::Variable varinfo; fh._tvvars.GetFile(var_ts, path); fh._tvvars.GetVariableInfo(varinfo); fh._has_missing = fh._tvvars.GetMissingValue(_missingValAttName, fh._missing_value); fh._ncdfptr = _ncdfmap[path]; fh._fd = fh._ncdfptr->OpenRead(varinfo); if (fh._fd < 0) { SetErrMsg("NetCDFCollection::OpenRead(%d, %s) : failed", var_ts, varname.c_str()); return (-1); } _ovr_table[fd] = fh; return (fd); } template int NetCDFCollection::_read_template(size_t start[], size_t count[], T *data, int fd) { size_t mystart[NC_MAX_VAR_DIMS]; size_t mycount[NC_MAX_VAR_DIMS]; std::map::iterator itr; if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } fileHandle &fh = itr->second; int idx = 0; if (fh._tvvars.GetTimeVarying() && !(fh._tvvars.GetTimeDimName().empty() || fh._tvvars.GetTimeDimName() == derivedTimeDimName)) { mystart[idx] = fh._local_ts; mycount[idx] = 1; idx++; } for (int i = 0; i < fh._tvvars.GetSpatialDims().size(); i++) { mystart[idx] = start[i]; mycount[idx] = count[i]; idx++; } return (fh._ncdfptr->Read(mystart, mycount, data, fh._fd)); } int NetCDFCollection::Read(size_t start[], size_t count[], double *data, int fd) { return (_read_template(start, count, data, fd)); } int NetCDFCollection::Read(size_t start[], size_t count[], float *data, int fd) { return (_read_template(start, count, data, fd)); } int NetCDFCollection::Read(size_t start[], size_t count[], int *data, int fd) { return (_read_template(start, count, data, fd)); } int NetCDFCollection::Read(size_t start[], size_t count[], char *data, int fd) { return (_read_template(start, count, data, fd)); } int NetCDFCollection::_InitializeTimesMap(const vector &files, const vector &time_dimnames, const vector &time_coordvars, map> ×Map, map &timeDimLens, vector ×, int &file_org) const { timesMap.clear(); timeDimLens.clear(); if (time_coordvars.size() && (time_coordvars.size() != time_dimnames.size())) { SetErrMsg("NetCDFCollection::Initialize() : number of time coordinate variables and time dimensions must match when time coordinate variables specified"); return (-1); } int rc; if (time_dimnames.size() == 0) { file_org = 1; rc = _InitializeTimesMapCase1(files, timesMap, timeDimLens); } else if ((time_dimnames.size() != 0) && (time_coordvars.size() == 0)) { file_org = 2; rc = _InitializeTimesMapCase2(files, time_dimnames, timesMap, timeDimLens); } else { file_org = 3; rc = _InitializeTimesMapCase3(files, time_dimnames, time_coordvars, timesMap, timeDimLens); } if (rc < 0) return (rc); // // Generate times: a single vector of all the time coordinates // map>::const_iterator itr1; for (itr1 = timesMap.begin(); itr1 != timesMap.end(); ++itr1) { const vector ×ref = itr1->second; times.insert(times.end(), timesref.begin(), timesref.end()); } // // sort and remove duplicates // times = make_container_unique(times); if (times.empty()) { times.push_back(0.0); } // // Create an entry for constant variables, which are defined at all times // timesMap["constant"] = times; return (0); } int NetCDFCollection::_InitializeTimesMapCase1(const vector &files, map> ×Map, map &timeDimLens) const { timesMap.clear(); // If only on file and no time dimensions than there is no // if (files.size() < 2) return (0); map currentTime; // current time for each variable // Case 1: No TDs or TCVs => synthesize TCV // A variable's time coordinate is determined by the ordering // of the file that it occurs in. The timesMap key is the // concatentation of file name (where the variable occurs) and // variable name. The only type of variables present are ITVV // for (int i = 0; i < files.size(); i++) { NetCDFSimple *netcdf = new NetCDFSimple(); int rc = netcdf->Initialize(files[i]); if (rc < 0) { SetErrMsg("NetCDFSimple::Initialize(%s)", files[i].c_str()); return (-1); } const vector &variables = netcdf->GetVariables(); for (int j = 0; j < variables.size(); j++) { // // Skip 0D variables // if (variables[j].GetDimNames().size() == 0) continue; string varname = variables[j].GetName(); // If first time this variable has been seen // initialize the currentTime // if (currentTime.find(varname) == currentTime.end()) { currentTime[varname] = 0.0; } string key = files[i] + varname; vector times(1, currentTime[varname]); timesMap[key] = times; currentTime[varname] += 1.0; } delete netcdf; } timeDimLens[derivedTimeDimName] = files.size(); return (0); } int NetCDFCollection::_InitializeTimesMapCase2(const vector &files, const vector &time_dimnames, map> ×Map, map &timeDimLens) const { timesMap.clear(); map currentTime; // current time for each variable map> timeDimTimes; // Case 2: TD specified, but no TCV. // A variable's time coordinate is determined by the ordering // of the file that it occurs in, offset by its time dimesion. // The timesMap key is the // concatentation of file name (where the variable occurs) and // variable name. // Both TVV and CV variables may be present. // for (int i = 0; i < files.size(); i++) { NetCDFSimple *netcdf = new NetCDFSimple(); int rc = netcdf->Initialize(files[i]); if (rc < 0) { SetErrMsg("NetCDFSimple::Initialize(%s)", files[i].c_str()); return (-1); } const vector &variables = netcdf->GetVariables(); for (int j = 0; j < variables.size(); j++) { // // Skip 0D variables // if (variables[j].GetDimNames().size() == 0) continue; string varname = variables[j].GetName(); string key = files[i] + varname; string timedim = variables[j].GetDimNames()[0]; // If this is a CV variable (no time dimension) we skip it // if (find(time_dimnames.begin(), time_dimnames.end(), timedim) == time_dimnames.end()) continue; // CV variable // Number of time steps for this variable // size_t timedimlen = netcdf->DimLen(timedim); // If first time this varname has been seen // initialize the currentTime // if (currentTime.find(varname) == currentTime.end()) { currentTime[varname] = 0.0; } vector times; for (int t = 0; t < timedimlen; t++) { times.push_back(currentTime[varname]); currentTime[varname] += 1.0; } timesMap[key] = times; vector ×ref = timeDimTimes[timedim]; for (int t = 0; t < times.size(); t++) { timesref.push_back(times[t]); } } delete netcdf; } for (auto itr : timeDimTimes) { vector &ref = itr.second; ref = make_container_unique(ref); timeDimLens[itr.first] = ref.size(); } return (0); } int NetCDFCollection::_InitializeTimesMapCase3(const vector &files, const vector &time_dimnames, const vector &time_coordvars, map> ×Map, map &timeDimLens) const { timesMap.clear(); // // tcvcount counts occurrences of each TCV. tcvfile and tcvdim record // the last file name and TD pair used to generate hash key for each TCV // map tcvcount; // # of files of TCV appears in map tcvfile; map tcvdim; map> timeDimTimes; for (int i = 0; i < time_coordvars.size(); i++) { tcvcount[time_coordvars[i]] = 0; } for (int i = 0; i < files.size(); i++) { NetCDFSimple *netcdf = new NetCDFSimple(); int rc = netcdf->Initialize(files[i]); if (rc < 0) return (-1); const vector &variables = netcdf->GetVariables(); // // For each TCV see if it exists in current file, if so // read it and add times to timesMap // for (int j = 0; j < time_coordvars.size(); j++) { int index = _get_var_index(variables, time_coordvars[j]); if (index < 0) continue; // TCV doesn't exist // Increment count // tcvcount[time_coordvars[j]] += 1; // Read TCV double *buf = _Get1DVar(netcdf, variables[index]); if (!buf) { SetErrMsg("Failed to read time coordinate variable \"%s\"", time_coordvars[j].c_str()); return (-1); } string timedim = variables[index].GetDimNames()[0]; size_t timedimlen = netcdf->DimLen(timedim); vector times; for (int t = 0; t < timedimlen; t++) { times.push_back(buf[t]); } delete[] buf; // // The hash key for timesMap is the file plus the // time dimension name // string key = files[i] + timedim; // record file and timedim used to generate the hash key // tcvfile[time_coordvars[j]] = files[i]; tcvdim[time_coordvars[j]] = timedim; if (timesMap.find(key) == timesMap.end()) { timesMap[key] = times; } else { vector ×ref = timesMap[key]; for (int t = 0; t < times.size(); t++) { timesref.push_back(times[t]); } } // Map between time dimention names and time coordinates // vector ×ref = timeDimTimes[timedim]; for (int t = 0; t < times.size(); t++) { timesref.push_back(times[t]); } } delete netcdf; } for (auto itr : timeDimTimes) { vector &ref = itr.second; ref = make_container_unique(ref); timeDimLens[itr.first] = ref.size(); } // // Finally, if see if this is case 3a (only one file contains the TCV), // or case 3b (a TCV is present in any file containing a TVV). // We're only checking for case 3a here. If case 1, replicate the // times for each file & time dimension pair // // for (int i = 0; i < time_coordvars.size(); i++) { if (tcvcount[time_coordvars[i]] == 1) { string key1 = tcvfile[time_coordvars[i]] + tcvdim[time_coordvars[i]]; map>::const_iterator itr; for (int j = 0; j < files.size(); j++) { string key = files[j] + tcvdim[time_coordvars[i]]; timesMap[key] = timesMap[key1]; } } } return (0); } double *NetCDFCollection::_Get1DVar(NetCDFSimple *netcdf, const NetCDFSimple::Variable &variable) const { if (variable.GetDimNames().size() != 1) return (NULL); int fd = netcdf->OpenRead(variable); if (fd < 0) { SetErrMsg("Time coordinate variable \"%s\" is invalid", variable.GetName().c_str()); return (NULL); } string dimname = variable.GetDimNames()[0]; size_t dimlen = netcdf->DimLen(dimname); size_t start[] = {0}; size_t count[] = {dimlen}; double *buf = new double[dimlen]; int rc = netcdf->Read(start, count, buf, fd); if (rc < 0) { return (NULL); } netcdf->Close(fd); return (buf); } int NetCDFCollection::_get_var_index(const vector variables, string varname) const { for (int i = 0; i < variables.size(); i++) { if (varname.compare(variables[i].GetName()) == 0) return (i); } return (-1); } template int NetCDFCollection::_read_slice_template(T *data, int fd) { std::map::iterator itr; if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } fileHandle &fh = itr->second; const TimeVaryingVar &var = fh._tvvars; vector dims = var.GetSpatialDims(); if (dims.size() < 2 || dims.size() > 3) { SetErrMsg("Only 2D and 3D variables supported"); return (-1); } size_t nx = dims[dims.size() - 1]; size_t ny = dims[dims.size() - 2]; size_t nz = dims.size() > 2 ? dims[dims.size() - 3] : 1; if (fh._slice >= nz) return (0); size_t start[] = {0, 0, 0}; size_t count[] = {1, 1, 1}; if (dims.size() > 2) { start[0] = fh._slice; count[1] = ny; count[2] = nx; } else { count[0] = ny; count[1] = nx; } int rc = NetCDFCollection::Read(start, count, data, fd); fh._slice++; if (rc < 0) return (rc); return (1); } int NetCDFCollection::ReadSlice(float *data, int fd) { return (_read_slice_template(data, fd)); } int NetCDFCollection::SeekSlice(int offset, int whence, int fd) { std::map::iterator itr; if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } fileHandle &fh = itr->second; if (whence < 0 || whence > 2) { SetErrMsg("Invalid whence specification : %d", whence); return (-1); } vector dims = fh._tvvars.GetSpatialDims(); vector dimnames = fh._tvvars.GetSpatialDimNames(); size_t nz = dims.size() == 3 ? dims[dims.size() - 3] : 1; long nzus = nz; int slice = 0; if (whence == 0) { slice = offset; } else if (whence == 1) { slice = fh._slice + offset; } else if (whence == 2) { slice = offset + nzus - 1; } if (slice < 0) slice = 0; if (slice > nzus - 1) slice = nzus - 1; fh._slice = slice; fh._first_slice = true; return (0); } int NetCDFCollection::Read(vector start, vector count, double *data, int fd) { VAssert(start.size() == count.size()); size_t mystart[NC_MAX_VAR_DIMS]; size_t mycount[NC_MAX_VAR_DIMS]; for (int i = 0; i < start.size(); i++) { mystart[i] = start[i]; mycount[i] = count[i]; } return (NetCDFCollection::Read(mystart, mycount, data, fd)); } int NetCDFCollection::Read(vector start, vector count, float *data, int fd) { VAssert(start.size() == count.size()); size_t mystart[NC_MAX_VAR_DIMS]; size_t mycount[NC_MAX_VAR_DIMS]; for (int i = 0; i < start.size(); i++) { mystart[i] = start[i]; mycount[i] = count[i]; } return (NetCDFCollection::Read(mystart, mycount, data, fd)); } int NetCDFCollection::Read(vector start, vector count, int *data, int fd) { VAssert(start.size() == count.size()); size_t mystart[NC_MAX_VAR_DIMS]; size_t mycount[NC_MAX_VAR_DIMS]; for (int i = 0; i < start.size(); i++) { mystart[i] = start[i]; mycount[i] = count[i]; } return (NetCDFCollection::Read(mystart, mycount, data, fd)); } template int NetCDFCollection::_read_template(T *data, int fd) { std::map::iterator itr; if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } fileHandle &fh = itr->second; const TimeVaryingVar &var = fh._tvvars; vector dims = var.GetSpatialDims(); vector dimnames = var.GetSpatialDimNames(); // // Handle different dimenion cases // if (dims.size() > 3) { SetErrMsg("Only 0D, 1D, 2D and 3D variables supported"); return (-1); } size_t start[3] = {0, 0, 0}; size_t count[3]; if (dims.size() == 0) { count[0] = 1; return (NetCDFCollection::Read(start, count, data, fd)); } else if (dims.size() == 1) { size_t nx = dims[dims.size() - 1]; count[0] = nx; } else if (dims.size() == 2) { size_t nx = dims[dims.size() - 1]; size_t ny = dims[dims.size() - 2]; count[0] = ny; count[1] = nx; } else if (dims.size() == 3) { size_t nx = dims[dims.size() - 1]; size_t ny = dims[dims.size() - 2]; size_t nz = dims[dims.size() - 3]; count[0] = nz; count[1] = ny; count[2] = nx; } return (NetCDFCollection::Read(start, count, data, fd)); } int NetCDFCollection::Read(char *data, int fd) { return (_read_template(data, fd)); } int NetCDFCollection::Read(int *data, int fd) { return (_read_template(data, fd)); } int NetCDFCollection::Read(float *data, int fd) { return (_read_template(data, fd)); } int NetCDFCollection::Read(double *data, int fd) { return (_read_template(data, fd)); } int NetCDFCollection::Close(int fd) { std::map::iterator itr; if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } fileHandle &fh = itr->second; if (!fh._ncdfptr) return (0); int rc = fh._ncdfptr->Close(fh._fd); if (fh._slicebuf) delete[] fh._slicebuf; if (fh._linebuf) delete[] fh._linebuf; _ovr_table.erase(itr); return (rc); } namespace VAPoR { std::ostream &operator<<(std::ostream &o, const NetCDFCollection &ncdfc) { o << "NetCDFCollection" << endl; o << " _times : "; for (int i = 0; i < ncdfc._times.size(); i++) { o << ncdfc._times[i] << " "; } o << endl; o << " _missingValAttName : " << ncdfc._missingValAttName << endl; o << " _variableList : " << endl; map::const_iterator itr; for (itr = ncdfc._variableList.begin(); itr != ncdfc._variableList.end(); ++itr) { o << itr->second; o << endl; } return (o); } }; // namespace VAPoR NetCDFCollection::TimeVaryingVar::TimeVaryingVar() { _files.clear(); _tvmaps.clear(); _spatial_dims.clear(); _spatial_dim_names.clear(); _name.clear(); _time_name.clear(); _time_varying = false; } int NetCDFCollection::TimeVaryingVar::Insert(const NetCDFSimple *netcdf, const NetCDFSimple::Variable &variable, string file, const vector &time_dimnames, const map> ×map, int file_org) { bool first = (_tvmaps.size() == 0); // first insertion? vector space_dim_names = variable.GetDimNames(); vector space_dims; for (int i = 0; i < space_dim_names.size(); i++) { space_dims.push_back(netcdf->DimLen(space_dim_names[i])); } string time_name; // // Check if variable is time varying. I.e. if its slowest varying // dimension name matches a dimension name specified in time_dimnames // bool time_varying = false; string key; // hash key for timesmap if (variable.GetDimNames().size()) { string s = variable.GetDimNames()[0]; // Handle ITVV case // if (time_dimnames.size() == 1 && time_dimnames[0] == derivedTimeDimName) { time_varying = true; time_name = derivedTimeDimName; } else if (find(time_dimnames.begin(), time_dimnames.end(), s) != time_dimnames.end()) { time_varying = true; time_name = s; space_dims.erase(space_dims.begin()); space_dim_names.erase(space_dim_names.begin()); } } if (!time_varying) { key = "constant"; } else if (file_org == 1 || file_org == 2) { key = file + variable.GetName(); } else { key = file + variable.GetDimNames()[0]; } if (first) { _spatial_dims = space_dims; _spatial_dim_names = space_dim_names; _time_varying = time_varying; _name = variable.GetName(); _time_name = time_name; _variable = variable; } else { // // If this isn't the first variable to be inserted the new variable // must match the existing ones // if (!((variable.GetDimNames() == _variable.GetDimNames()) && variable.GetXType() == _variable.GetXType())) { SetErrMsg("Multiple definitions of variable \"%s\"", variable.GetName().c_str()); return (-1); } } _files.push_back(file); map>::const_iterator itr; itr = timesmap.find(key); if (itr == timesmap.end()) { SetErrMsg("Time coordinates not available for variable"); return (-1); } const vector ×ref = itr->second; size_t local_ts = 0; for (int i = 0; i < timesref.size(); i++) { tvmap_t tvmap; tvmap._fileidx = _files.size() - 1; tvmap._time = timesref[i]; tvmap._local_ts = local_ts; _tvmaps.push_back(tvmap); local_ts++; } return (0); } int NetCDFCollection::TimeVaryingVar::GetTime(size_t ts, double &time) const { if (ts >= _tvmaps.size()) return (-1); time = _tvmaps[ts]._time; return (0); } vector NetCDFCollection::TimeVaryingVar::GetTimes() const { vector times; for (int i = 0; i < _tvmaps.size(); i++) times.push_back(_tvmaps[i]._time); return (times); } int NetCDFCollection::TimeVaryingVar::GetTimeStep(double time, size_t &ts) const { if (!_time_varying) { ts = 0; return (0); } for (size_t i = 0; i < _tvmaps.size(); i++) { if (_tvmaps[i]._time == time) { ts = i; return (0); } } SetErrMsg("Invalid time %f", time); return (-1); } size_t NetCDFCollection::TimeVaryingVar::GetLocalTimeStep(size_t ts) const { if (ts >= _tvmaps.size()) return (0); return (_tvmaps[ts]._local_ts); } int NetCDFCollection::TimeVaryingVar::GetFile(size_t ts, string &file) const { if (ts >= _tvmaps.size()) return (-1); int fileidx = _tvmaps[ts]._fileidx; file = _files[fileidx]; return (0); } bool NetCDFCollection::TimeVaryingVar::GetMissingValue(string attname, double &mv) const { mv = 0.0; if (!attname.length()) return (false); vector vec; _variable.GetAtt(attname, vec); if (!vec.size()) return (false); mv = vec[0]; return (true); } void NetCDFCollection::TimeVaryingVar::Sort() { // // Sort variable by time // auto lambda = [](const NetCDFCollection::TimeVaryingVar::tvmap_t &s1, const NetCDFCollection::TimeVaryingVar::tvmap_t &s2) -> bool { return (s1._time < s2._time); }; std::sort(_tvmaps.begin(), _tvmaps.end(), lambda); } NetCDFCollection::fileHandle::fileHandle() { _ncdfptr = NULL; _fd = -1; _local_ts = 0; _slice = 0; _slicebuf = NULL; _slicebufsz = 0; _linebuf = NULL; _linebufsz = 0; _has_missing = false; _missing_value = 0.0; } namespace VAPoR { std::ostream &operator<<(std::ostream &o, const NetCDFCollection::TimeVaryingVar &var) { o << " TimeVaryingVar" << endl; o << " Variable : " << var._name << endl; o << " Files : " << endl; for (int i = 0; i < var._files.size(); i++) { o << " " << var._files[i] << endl; } o << " Dims : "; for (int i = 0; i < var._spatial_dims.size(); i++) { o << var._spatial_dims[i] << " "; } o << endl; o << " Dim Names : "; for (int i = 0; i < var._spatial_dim_names.size(); i++) { o << var._spatial_dim_names[i] << " "; } o << endl; o << " Time Varying : " << var._time_varying << endl; o << " Time Varying Map : " << endl; for (int i = 0; i < var._tvmaps.size(); i++) { o << " _fileidx : " << var._tvmaps[i]._fileidx << endl; o << " _time : " << var._tvmaps[i]._time << endl; o << " _local_ts : " << var._tvmaps[i]._local_ts << endl; o << endl; } return (o); } }; // namespace VAPoR ================================================ FILE: lib/vdc/NetCDFSimple.cpp ================================================ #include #include "vapor/VAssert.h" #include #include using namespace VAPoR; using namespace Wasp; using namespace std; NetCDFSimple::NetCDFSimple() { _ncid = -1; _ovr_table.clear(); _path = ""; // so _path.c_str() returns an empty string _dimnames.clear(); _dims.clear(); _unlimited_dimnames.clear(); _flt_atts.clear(); _int_atts.clear(); _str_atts.clear(); _variables.clear(); } NetCDFSimple::~NetCDFSimple() { if (_ncid != -1) { int rc = nc_close(_ncid); if (rc != 0) { SetErrMsg("nc_close(%d) : %s", _ncid, nc_strerror(rc)); return; } } } int NetCDFSimple::Initialize(string path) { _dimnames.clear(); _dims.clear(); _unlimited_dimnames.clear(); _flt_atts.clear(); _int_atts.clear(); _str_atts.clear(); _variables.clear(); _path = path; int ncid; int rc = nc_open(path.c_str(), NC_NOWRITE, &ncid); if (rc != 0) { SetErrMsg("nc_open(%s,) : %s", path.c_str(), nc_strerror(rc)); return (-1); } int ndims; rc = nc_inq_ndims(ncid, &ndims); if (rc != 0) { SetErrMsg("nc_inq_ndims(%d) : %s", ncid, nc_strerror(rc)); return (-1); } // // Get all the dimensions // for (int i = 0; i < ndims; i++) { char namebuf[NC_MAX_NAME + 1]; size_t len; rc = nc_inq_dim(ncid, i, namebuf, &len); if (rc != 0) { SetErrMsg("nc_inq_dim(%d, %d) : %s", ncid, i, nc_strerror(rc)); return (-1); } _dimnames.push_back(namebuf); _dims.push_back(len); } // // Get unlimited dim. N.B. in netCDF-4/HDF5 there can be multiple // unlimited dimensions. Here we only check for one! // int dimid; rc = nc_inq_unlimdim(ncid, &dimid); if (rc != 0) { SetErrMsg("nc_inq_unlimdim(%d) : %s", ncid, nc_strerror(rc)); return (-1); } if (dimid >= 0) _unlimited_dimnames.push_back(_dimnames[dimid]); // // Get all the global attributes // rc = _GetAtts(ncid, NC_GLOBAL, _flt_atts, _int_atts, _str_atts); if (rc < 0) return (-1); // // Finally, get all of the variable metadata // int nvars; rc = nc_inq_nvars(ncid, &nvars); if (rc != 0) { SetErrMsg("nc_inq_nvars(%d) : %s", ncid, nc_strerror(rc)); return (-1); } for (int varid = 0; varid < nvars; varid++) { char namebuf[NC_MAX_NAME + 1]; nc_type xtype; int ndims; int dimids[NC_MAX_VAR_DIMS]; int natts; rc = nc_inq_var(ncid, varid, namebuf, &xtype, &ndims, dimids, &natts); if (rc != 0) { SetErrMsg("nc_inq_var(%d, %d, %d) : %s", ncid, varid, namebuf, nc_strerror(rc)); return (-1); } vector dimnames; vector dims; for (int i = 0; i < ndims; i++) { dimnames.push_back(DimName(dimids[i])); dims.push_back(_dims[dimids[i]]); } Variable var(namebuf, dimnames, xtype); vector>> flt_atts; vector>> int_atts; vector> str_atts; rc = _GetAtts(ncid, varid, flt_atts, int_atts, str_atts); if (rc < 0) return (-1); for (int i = 0; i < flt_atts.size(); i++) { var.SetAtt(flt_atts[i].first, flt_atts[i].second); } for (int i = 0; i < int_atts.size(); i++) { var.SetAtt(int_atts[i].first, int_atts[i].second); } for (int i = 0; i < str_atts.size(); i++) { var.SetAtt(str_atts[i].first, str_atts[i].second); } _variables.push_back(var); } nc_close(ncid); return (0); } int NetCDFSimple::OpenRead(const NetCDFSimple::Variable &variable) { // // If _ncid is not valid open the NetCDF file // if (_ncid == -1) { int ncid; int rc = nc_open(_path.c_str(), NC_NOWRITE, &ncid); if (rc != 0) { SetErrMsg("nc_open(%s,) : %s", _path.c_str(), nc_strerror(rc)); return (-1); } _ncid = ncid; } int varid; int rc = nc_inq_varid(_ncid, variable.GetName().c_str(), &varid); if (rc != 0) { SetErrMsg("nc_inq_varid(%d, %s, ) : %s", _ncid, variable.GetName().c_str(), nc_strerror(rc)); return (-1); } // // Find a file descriptor. Use lowest available, starting with zero // int fd; for (fd = 0; fd < _ovr_table.size(); fd++) { if (_ovr_table.find(fd) == _ovr_table.end()) { break; } } _ovr_table[fd] = varid; return (fd); } int NetCDFSimple::Read(const size_t start[], const size_t count[], double *data, int fd) const { std::map::const_iterator itr; if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int varid = itr->second; int rc = nc_get_vara_double(_ncid, varid, start, count, data); if (rc != 0) { SetErrMsg("nc_get_vara_double(%d, %d) : %s", _ncid, varid, nc_strerror(rc)); return (-1); } return (0); } int NetCDFSimple::Read(const size_t start[], const size_t count[], float *data, int fd) const { std::map::const_iterator itr; if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int varid = itr->second; int rc = nc_get_vara_float(_ncid, varid, start, count, data); if (rc != 0) { SetErrMsg("nc_get_vara_float(%d, %d) : %s", _ncid, varid, nc_strerror(rc)); return (-1); } return (0); } int NetCDFSimple::Read(const size_t start[], const size_t count[], int *data, int fd) const { std::map::const_iterator itr; if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int varid = itr->second; int rc = nc_get_vara_int(_ncid, varid, start, count, data); if (rc != 0) { SetErrMsg("nc_get_vara_int(%d, %d) : %s", _ncid, varid, nc_strerror(rc)); return (-1); } return (0); } int NetCDFSimple::Read(const size_t start[], const size_t count[], char *data, int fd) const { std::map::const_iterator itr; if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } int varid = itr->second; int rc = nc_get_vara_text(_ncid, varid, start, count, data); if (rc != 0) { SetErrMsg("nc_get_vara_text(%d, %d) : %s", _ncid, varid, nc_strerror(rc)); return (-1); } return (0); } int NetCDFSimple::Close(int fd) { std::map::iterator itr; if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } _ovr_table.erase(itr); if (_ovr_table.empty() && _ncid != -1) { (void)nc_close(_ncid); _ncid = -1; } return (0); } void NetCDFSimple::GetDimensions(vector &names, vector &dims) const { names = _dimnames; dims = _dims; } string NetCDFSimple::DimName(int id) const { if (id >= 0 && id < _dimnames.size()) return (_dimnames[id]); return (""); } size_t NetCDFSimple::DimLen(string name) const { vector names; vector dims; VAssert(dims.size() == names.size()); NetCDFSimple::GetDimensions(names, dims); for (int i = 0; i < names.size(); i++) { if (names[i].compare(name) == 0) return (dims[i]); } return (0); // unknown name } int NetCDFSimple::DimId(string name) const { for (int i = 0; i < _dimnames.size(); i++) { if (_dimnames[i].compare(name) == 0) return (i); } return (-1); } std::vector NetCDFSimple::GetAttNames() const { vector names; for (int i = 0; i < _flt_atts.size(); i++) { names.push_back(_flt_atts[i].first); } for (int i = 0; i < _int_atts.size(); i++) { names.push_back(_int_atts[i].first); } for (int i = 0; i < _str_atts.size(); i++) { names.push_back(_str_atts[i].first); } return (names); } int NetCDFSimple::GetAttType(string name) const { for (int i = 0; i < _flt_atts.size(); i++) { if (name.compare(_flt_atts[i].first) == 0) return (NC_DOUBLE); } for (int i = 0; i < _int_atts.size(); i++) { if (name.compare(_int_atts[i].first) == 0) return (NC_INT64); } for (int i = 0; i < _str_atts.size(); i++) { if (name.compare(_str_atts[i].first) == 0) return (NC_CHAR); } return (-1); } void NetCDFSimple::GetAtt(string name, vector &values) const { values.clear(); for (int i = 0; i < _flt_atts.size(); i++) { if (_flt_atts[i].first.compare(name) == 0) { values = _flt_atts[i].second; return; } } // // Look for atts of type int and then cast to float if found // for (int i = 0; i < _int_atts.size(); i++) { if (_int_atts[i].first.compare(name) == 0) { for (int j = 0; j < _int_atts[i].second.size(); j++) { values.push_back(_int_atts[i].second[j]); } return; } } return; } void NetCDFSimple::GetAtt(string name, vector &values) const { values.clear(); for (int i = 0; i < _int_atts.size(); i++) { if (_int_atts[i].first.compare(name) == 0) { values = _int_atts[i].second; return; } } // // Look for atts of type float and then cast to int if found // for (int i = 0; i < _flt_atts.size(); i++) { if (_flt_atts[i].first.compare(name) == 0) { for (int j = 0; j < _flt_atts[i].second.size(); j++) { values.push_back((long)_flt_atts[i].second[j]); } return; } } return; } void NetCDFSimple::GetAtt(string name, string &values) const { values.clear(); for (int i = 0; i < _str_atts.size(); i++) { if (_str_atts[i].first.compare(name) == 0) { values = _str_atts[i].second; return; } } return; } bool NetCDFSimple::IsNCTypeInt(int type) { if (type == NC_BYTE || type == NC_SHORT || type == NC_INT || type == NC_LONG || type == NC_UBYTE || type == NC_USHORT || type == NC_UINT || type == NC_INT64 || type == NC_UINT64) { return (true); } return (false); } bool NetCDFSimple::IsNCTypeFloat(int type) { if (type == NC_FLOAT || type == NC_DOUBLE) { return (true); } return (false); } bool NetCDFSimple::IsNCTypeText(int type) { if (type == NC_CHAR) { return (true); } return (false); } int NetCDFSimple::_GetAtts(int ncid, int varid, vector>> &flt_atts, vector>> &int_atts, vector> &str_atts) { flt_atts.clear(); int_atts.clear(); str_atts.clear(); int rc; int natts; if (varid == NC_GLOBAL) { rc = nc_inq_natts(ncid, &natts); } else { rc = nc_inq_varnatts(ncid, varid, &natts); } if (rc != 0) { SetErrMsg("nc_inq_varnatts(%d, %d) : %s", ncid, varid, nc_strerror(rc)); return (-1); } for (int i = 0; i < natts; i++) { char namebuf[NC_MAX_NAME + 1]; rc = nc_inq_attname(ncid, varid, i, namebuf); if (rc != 0) { SetErrMsg("nc_inq_attname(%d, %d, %d) : %s", ncid, varid, i, nc_strerror(rc)); return (-1); } nc_type xtype; size_t len; rc = nc_inq_att(ncid, varid, namebuf, &xtype, &len); if (rc != 0) { SetErrMsg("nc_inq_att(%d, %d, %s) : %s", ncid, varid, namebuf, nc_strerror(rc)); return (-1); } else if (IsNCTypeInt(xtype)) { // N.B. Use long long for windows platforms, which may // represent longs as 32 bits. // See https://github.com/NCAR/VAPOR/issues/3139 // vector longbuf(len); rc = nc_get_att_longlong(ncid, varid, namebuf, longbuf.data()); if (rc != 0) { SetErrMsg("nc_get_att_long(%d, %d, %s) : %s", ncid, varid, namebuf, nc_strerror(rc)); return (-1); } vector vals; for (int i = 0; i < len; i++) { vals.push_back(longbuf[i]); } int_atts.push_back(make_pair(namebuf, vals)); } else if (IsNCTypeFloat(xtype)) { vector dblbuf(len); rc = nc_get_att_double(ncid, varid, namebuf, dblbuf.data()); if (rc != 0) { SetErrMsg("nc_get_att_double(%d, %d, %s) : %s", ncid, varid, namebuf, nc_strerror(rc)); return (-1); } flt_atts.push_back(make_pair(namebuf, dblbuf)); } else if (IsNCTypeText(xtype)) { vector textbuf(len+1, '\0'); rc = nc_get_att_text(ncid, varid, namebuf, textbuf.data()); if (rc != 0) { SetErrMsg("nc_get_att_text(%d, %d, %s) : %s", ncid, varid, namebuf, nc_strerror(rc)); return (-1); } str_atts.push_back(make_pair(namebuf, textbuf.data())); } else { SetErrMsg("Unhandled attribute type : %d", xtype); return (-1); } } return (0); } namespace VAPoR { std::ostream &operator<<(std::ostream &o, const NetCDFSimple &nc) { o << "NetCDFSimple" << endl; o << " File : " << nc._path << endl; o << " Dimensions : " << endl; for (int i = 0; i < nc._dimnames.size(); i++) { o << " " << nc._dimnames[i] << " " << nc._dims[i] << endl; } o << " Unlimited Dimensions : " << endl; for (int i = 0; i < nc._unlimited_dimnames.size(); i++) { o << " " << nc._unlimited_dimnames[i] << endl; } o << " Attributes : " << endl; for (int i = 0; i < nc._flt_atts.size(); i++) { o << " " << nc._flt_atts[i].first << ": "; for (int j = 0; j < nc._flt_atts[i].second.size(); j++) { o << nc._flt_atts[i].second[j] << " "; } o << endl; } for (int i = 0; i < nc._int_atts.size(); i++) { o << " " << nc._int_atts[i].first << ": "; for (int j = 0; j < nc._int_atts[i].second.size(); j++) { o << nc._int_atts[i].second[j] << " "; } o << endl; } for (int i = 0; i < nc._str_atts.size(); i++) { o << " " << nc._str_atts[i].first << ": "; o << nc._str_atts[i].second << endl; } for (int i = 0; i < nc._variables.size(); i++) { o << nc._variables[i]; } return (o); } } // namespace VAPoR NetCDFSimple::Variable::Variable() { _name.clear(); _dimnames.clear(); _flt_atts.clear(); _int_atts.clear(); _str_atts.clear(); _type = -1; } NetCDFSimple::Variable::Variable(string name, vector dimnames, int type) { _name = name; _dimnames = dimnames; _type = type; _flt_atts.clear(); _int_atts.clear(); _str_atts.clear(); } vector NetCDFSimple::Variable::GetAttNames() const { vector names; for (int i = 0; i < _flt_atts.size(); i++) { names.push_back(_flt_atts[i].first); } for (int i = 0; i < _int_atts.size(); i++) { names.push_back(_int_atts[i].first); } for (int i = 0; i < _str_atts.size(); i++) { names.push_back(_str_atts[i].first); } return (names); } int NetCDFSimple::Variable::GetAttType(string name) const { for (int i = 0; i < _flt_atts.size(); i++) { if (name.compare(_flt_atts[i].first) == 0) return (NC_DOUBLE); } for (int i = 0; i < _int_atts.size(); i++) { if (name.compare(_int_atts[i].first) == 0) return (NC_INT64); } for (int i = 0; i < _str_atts.size(); i++) { if (name.compare(_str_atts[i].first) == 0) return (NC_CHAR); } return (-1); } void NetCDFSimple::Variable::GetAtt(string name, vector &values) const { values.clear(); for (int i = 0; i < _flt_atts.size(); i++) { if (_flt_atts[i].first.compare(name) == 0) { values = _flt_atts[i].second; return; } } // // Look for atts of type int and then cast to float if found // for (int i = 0; i < _int_atts.size(); i++) { if (_int_atts[i].first.compare(name) == 0) { for (int j = 0; j < _int_atts[i].second.size(); j++) { values.push_back(_int_atts[i].second[j]); } return; } } return; } void NetCDFSimple::Variable::GetAtt(string name, vector &values) const { values.clear(); for (int i = 0; i < _int_atts.size(); i++) { if (_int_atts[i].first.compare(name) == 0) { values = _int_atts[i].second; return; } } // // Look for atts of type float and then cast to int if found // for (int i = 0; i < _flt_atts.size(); i++) { if (_flt_atts[i].first.compare(name) == 0) { for (int j = 0; j < _flt_atts[i].second.size(); j++) { values.push_back((long)_flt_atts[i].second[j]); } return; } } return; } void NetCDFSimple::Variable::GetAtt(string name, string &values) const { values.clear(); for (int i = 0; i < _str_atts.size(); i++) { if (_str_atts[i].first.compare(name) == 0) { values = _str_atts[i].second; return; } } return; } namespace VAPoR { std::ostream &operator<<(std::ostream &o, const NetCDFSimple::Variable &var) { o << "Variable" << endl; o << " Name : " << var._name << endl; o << " NetCDFSimple type : " << var._type << endl; o << " Dimensions : " << endl; for (int i = 0; i < var._dimnames.size(); i++) { o << " " << var._dimnames[i] << endl; } o << " Attributes : " << endl; for (int i = 0; i < var._flt_atts.size(); i++) { o << " " << var._flt_atts[i].first << ": "; for (int j = 0; j < var._flt_atts[i].second.size(); j++) { o << var._flt_atts[i].second[j] << " "; } o << endl; } for (int i = 0; i < var._int_atts.size(); i++) { o << " " << var._int_atts[i].first << ": "; for (int j = 0; j < var._int_atts[i].second.size(); j++) { o << var._int_atts[i].second[j] << " "; } o << endl; } for (int i = 0; i < var._str_atts.size(); i++) { o << " " << var._str_atts[i].first << ": "; o << var._str_atts[i].second << endl; } return (o); } }; // namespace VAPoR ================================================ FILE: lib/vdc/Proj4API.cpp ================================================ #define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H 1 #include #include #include #include using namespace VAPoR; using namespace Wasp; Proj4API::Proj4API() { _pjSrc = NULL; _pjDst = NULL; string path = GetSharePath("proj"); if (!path.empty()) { #ifdef WIN32 path = "PROJ_LIB=" + path; int rc = _putenv(path.c_str()); if (rc != 0) MyBase::SetErrMsg("putenv failed on PROJ_LIB setting"); #else setenv("PROJ_LIB", path.c_str(), 1); #endif } } Proj4API::~Proj4API() { if (_pjSrc) pj_free(_pjSrc); if (_pjDst) pj_free(_pjDst); } int Proj4API::_Initialize(string srcdef, string dstdef, void **pjSrc, void **pjDst) const { *pjSrc = NULL; *pjDst = NULL; if (!srcdef.empty()) { *pjSrc = pj_init_plus(srcdef.c_str()); if (!*pjSrc) { SetErrMsg("pj_init_plus(%s) : %s", srcdef.c_str(), ProjErr().c_str()); return (-1); } } if (!dstdef.empty()) { *pjDst = pj_init_plus(dstdef.c_str()); if (!*pjDst) { SetErrMsg("pj_init_plus(%s) : %s", dstdef.c_str(), ProjErr().c_str()); return (-1); } } // // If either the source or destination definition string is // not provided - but not both - generate a "latlong" conversion // if (srcdef.empty() && !dstdef.empty()) { *pjSrc = pj_latlong_from_proj(*pjDst); if (!*pjSrc) { SetErrMsg("pj_latlong_from_proj() : %s", ProjErr().c_str()); return (-1); } } else if (!srcdef.empty() && dstdef.empty()) { *pjDst = pj_latlong_from_proj(*pjSrc); if (!*pjDst) { SetErrMsg("pj_latlong_from_proj() : %s", ProjErr().c_str()); return (-1); } } else { // NULL transform. Transforms will be no-ops } return (0); } int Proj4API::Initialize(string srcdef, string dstdef) { if (_pjSrc) pj_free(_pjSrc); if (_pjDst) pj_free(_pjDst); _pjSrc = NULL; _pjDst = NULL; return (_Initialize(srcdef, dstdef, &_pjSrc, &_pjDst)); } bool Proj4API::IsLatLonSrc() const { if (!_pjSrc) return (false); return ((bool)pj_is_latlong(_pjSrc)); } bool Proj4API::IsLatLonDst() const { if (!_pjDst) return (false); return ((bool)pj_is_latlong(_pjDst)); } bool Proj4API::IsGeocentSrc() const { if (!_pjSrc) return (false); return ((bool)pj_is_geocent(_pjSrc)); } bool Proj4API::IsGeocentDst() const { if (!_pjDst) return (false); return ((bool)pj_is_geocent(_pjDst)); } string Proj4API::GetSrcStr() const { if (!_pjSrc) return (""); return ((string)pj_get_def(_pjSrc, 0)); } string Proj4API::GetDstStr() const { if (!_pjDst) return (""); return ((string)pj_get_def(_pjDst, 0)); } int Proj4API::Transform(double *x, double *y, size_t n, int offset) const { return (Proj4API::Transform(x, y, NULL, n, offset)); } int Proj4API::_Transform(void *pjSrc, void *pjDst, double *x, double *y, double *z, size_t n, int offset) const { // no-op // if (pjSrc == NULL || pjDst == NULL) return (0); // // Convert from degrees to radians if source is in // geographic coordinates // if (pj_is_latlong(pjSrc)) { if (x) { for (size_t i = 0; i < n; i++) { x[i * (size_t)offset] *= DEG_TO_RAD; } } if (y) { for (size_t i = 0; i < n; i++) { y[i * (size_t)offset] *= DEG_TO_RAD; } } if (z) { for (size_t i = 0; i < n; i++) { z[i * (size_t)offset] *= DEG_TO_RAD; } } } int rc = pj_transform(pjSrc, pjDst, n, offset, x, y, NULL); if (rc != 0) { SetErrMsg("pj_transform() : %s", ProjErr().c_str()); return (-1); } // // Convert from radians degrees if destination is in // geographic coordinates // if (pj_is_latlong(pjDst)) { if (x) { for (size_t i = 0; i < n; i++) { x[i * (size_t)offset] *= RAD_TO_DEG; } } if (y) { for (size_t i = 0; i < n; i++) { y[i * (size_t)offset] *= RAD_TO_DEG; } } if (z) { for (size_t i = 0; i < n; i++) { z[i * (size_t)offset] *= RAD_TO_DEG; } } } return (0); } int Proj4API::Transform(double *x, double *y, double *z, size_t n, int offset) const { return (_Transform(_pjSrc, _pjDst, x, y, z, n, offset)); } int Proj4API::Transform(float *x, float *y, size_t n, int offset) const { return (Proj4API::Transform(x, y, NULL, n, offset)); } int Proj4API::_Transform(void *pjSrc, void *pjDst, float *x, float *y, float *z, size_t n, int offset) const { double *xd = NULL; double *yd = NULL; double *zd = NULL; if (x) { xd = new double[n]; for (size_t i = 0; i < n; i++) xd[i] = x[i * offset]; } if (y) { yd = new double[n]; for (size_t i = 0; i < n; i++) yd[i] = y[i * offset]; } if (z) { zd = new double[n]; for (size_t i = 0; i < n; i++) zd[i] = z[i * offset]; } int rc = _Transform(pjSrc, pjDst, xd, yd, zd, n, 1); if (xd) { for (size_t i = 0; i < n; i++) x[i * offset] = xd[i]; delete[] xd; } if (yd) { for (size_t i = 0; i < n; i++) y[i * offset] = yd[i]; delete[] yd; } if (zd) { for (size_t i = 0; i < n; i++) z[i * offset] = zd[i]; delete[] zd; } return (rc); } int Proj4API::Transform(float *x, float *y, float *z, size_t n, int offset) const { return (Proj4API::_Transform(_pjSrc, _pjDst, x, y, z, n, offset)); } int Proj4API::Transform(string srcdef, string dstdef, double *x, double *y, double *z, size_t n, int offset) const { void *pjSrc = NULL; void *pjDst = NULL; int rc = _Initialize(srcdef, dstdef, &pjSrc, &pjDst); if (rc < 0) return (rc); return (_Transform(pjSrc, pjDst, x, y, z, n, offset)); return (0); } int Proj4API::Transform(string srcdef, string dstdef, float *x, float *y, float *z, size_t n, int offset) const { void *pjSrc = NULL; void *pjDst = NULL; int rc = _Initialize(srcdef, dstdef, &pjSrc, &pjDst); if (rc < 0) return (rc); return (_Transform(pjSrc, pjDst, x, y, z, n, offset)); return (0); } string Proj4API::ProjErr() const { return (pj_strerrno(*pj_get_errno_ref())); } void Proj4API::Clamp(double *x, double *y, size_t n, int offset) const { double minx, miny, maxx, maxy; string projstring = GetSrcStr(); if (IsLatLonSrc()) { minx = -180.0; miny = -90.0; maxx = 180.0; maxy = 90.0; } else if (std::string::npos != projstring.find("proj=eqc")) { minx = -20037508.3427892; miny = -10018754.1713946; maxx = -minx; maxy = -miny; } else if (std::string::npos != projstring.find("proj=merc")) { minx = -20037508.340; miny = minx; maxx = -minx; maxy = -miny; } else { return; // unknown projectoin } for (int i = 0; i < n; i++) { if (x[i * offset] < minx) x[i * offset] = minx; if (y[i * offset] < miny) y[i * offset] = miny; if (x[i * offset] > maxx) x[i * offset] = maxx; if (y[i * offset] > maxy) y[i * offset] = maxy; } } bool Proj4API::IsCylindrical() const { string proj4String = GetDstStr(); return ((proj4String.find("+proj=eqc") != std::string::npos) || (proj4String.find("+proj=merc") != std::string::npos)); } ================================================ FILE: lib/vdc/PythonDataMgr.cpp ================================================ #include #include #include using namespace Wasp; using namespace VAPoR; PythonDataMgr::PythonDataMgr(string format, size_t mem_size, int nthreads) : DataMgr(format, mem_size, nthreads) { // TODO: Disable caching. // TODO: DataMgr will fail to load anything if the cache is too small rather than // TODO: just loading it and not caching the result. // Disable caching // Setting to 0 will just cause it to be rejected and fallback to default cache size. // _mem_size = 1; } PythonDataMgr::~PythonDataMgr() {} void PythonDataMgr::AddRegularData(string name, const float *buf, vector dimLens) { auto dcr = GetDC(); size_t totalSize = 1; // printf("%s(dims=%li)\n", __func__, dimLens.size()); for (int i = 0; i < dimLens.size(); i++) { totalSize *= dimLens[i]; // printf("\t dim[%i] = %i\n", i, dimLens[i]); } // printf("\t data = "); for (int i = 0; i < (totalSize < 5 ? totalSize : 5); i++) { // printf("%f, ", buf[i]); } // printf("\n"); vector dims; for (auto len : dimLens) { string genName = "__regDim_" + std::to_string(len); DC::Dimension dim; if (!GetDimension(genName, dim, -1)) { dim = DC::Dimension(genName, len); dcr->AddDimension(dim); // printf("Created new dimension \"%s\"\n", dim.GetName().c_str()); } dims.push_back(dim); } vector coords; int currDim = 0; // (x,y,z,t) = (0,1,2,3) auto dimToStr = [](int d){ return "xyzt"[d]; }; for (auto dim : dims) { string genName = "__regCoord_" + std::to_string(dim.GetLength()) + "_" + dimToStr(currDim); DC::CoordVar coord; if (!GetCoordVarInfo(genName, coord)) { coord = DC::CoordVar(genName, "m", DC::FLOAT, {false}, /*axis=x*/currDim, /*uniformHint=*/true, {dim.GetName()}, /*timeDim*/""); vector cbuf; for (size_t i = 0; i < dim.GetLength(); i++) cbuf.push_back(i); dcr->AddCoordVar(coord, cbuf.data()); // printf("Created new coordinate \"%s\"\n", coord.GetName().c_str()); } coords.push_back(coord); currDim++; } vector dimNames, coordNames; for (auto dim : dims) dimNames.push_back(dim.GetName()); for (auto crd : coords) coordNames.push_back(crd.GetName()); string meshGenName = "__" + DC::Mesh::MakeMeshName(dimNames); DC::Mesh mesh; if (!GetMesh(meshGenName, mesh)) { mesh = DC::Mesh(meshGenName, dimNames, coordNames); dcr->AddMesh(mesh); // printf("Created new mesh \"%s\"\n", mesh.GetName().c_str()); } vector periodic(dims.size(), false); auto v = DC::DataVar(name, "", DC::FLOAT, periodic, mesh.GetName(), /*timeCoordVar*/"", DC::Mesh::NODE); dcr->AddDataVar(v, buf); ClearCache(name); } DCRAM *PythonDataMgr::GetDC() const { auto dcr = dynamic_cast(_dc); VAssert(dcr); return dcr; } void PythonDataMgr::ClearCache(string varname) { // printf("%s(%s)\n", __func__, varname.c_str()); _free_var(varname); _dataVarNamesCache.clear(); } ================================================ FILE: lib/vdc/QuadTreeRectangleP.cpp ================================================ #include #include #include #include #include #include using namespace VAPoR; using namespace std; using UInt32_tArr2 = std::array; using pType = UInt32_tArr2; QuadTreeRectangleP::QuadTreeRectangleP(float left, float top, float right, float bottom, size_t max_depth, size_t reserve_size) : _left(left), _right(right) { VAssert(left <= right); VAssert(top <= bottom); int nthreads = 1; #pragma omp parallel { if (omp_get_thread_num() == 0) nthreads = omp_get_num_threads(); } // We split the quadtree along the X-axis to create one subtree for // each thread. This way there are no dependencies between the regions // covered by each subtree and we can process each subtree in parallel // float bin_width = ((float)right - (float)left) / ((float)nthreads); float binLeft = left; for (int i = 0; i < nthreads; i++) { float binRight = binLeft + bin_width; if (i == nthreads - 1) binRight = right; _qtrs.push_back(new QuadTreeRectangle(binLeft, top, binRight, bottom, max_depth, reserve_size / nthreads)); binLeft = binRight; } } QuadTreeRectangleP::QuadTreeRectangleP(size_t max_depth, size_t reserve_size) : _left(0.0), _right(1.0) { int nthreads = 1; #pragma omp parallel { nthreads = omp_get_num_threads(); } float bin_width = (1.0 - 0.0) / ((float)nthreads); float binLeft = 0.0; for (int i = 0; i < nthreads; i++) { float binRight = binLeft + bin_width; if (i == nthreads - 1) binRight = 1.0; _qtrs.push_back(new QuadTreeRectangle(binLeft, 0.0, binRight, 1.0, max_depth, reserve_size / nthreads)); binLeft = binRight; } } QuadTreeRectangleP::QuadTreeRectangleP(const QuadTreeRectangleP &rhs) { _left = rhs._left; _right = rhs._right; _qtrs.resize(rhs._qtrs.size()); for (int i = 0; i < _qtrs.size(); i++) { _qtrs[i] = new QuadTreeRectangle(*(rhs._qtrs[i])); } } QuadTreeRectangleP &QuadTreeRectangleP::operator=(const QuadTreeRectangleP &rhs) { _left = rhs._left; _right = rhs._right; for (int i = 0; i < _qtrs.size(); i++) { if (_qtrs[i]) delete _qtrs[i]; } _qtrs.resize(rhs._qtrs.size()); for (size_t i = 0; i < rhs._qtrs.size(); i++) { _qtrs[i] = new QuadTreeRectangle(*(rhs._qtrs[i])); } return *this; } QuadTreeRectangleP::~QuadTreeRectangleP() { for (size_t i = 0; i < _qtrs.size(); i++) { if (_qtrs[i]) delete _qtrs[i]; } _qtrs.clear(); } bool QuadTreeRectangleP::Insert(float left, float top, float right, float bottom, DimsType payload) { // Serial insertion of a single element // bool status = true; float bin_width = (_right - _left) / ((float)_qtrs.size()); float binLeft = _left; for (int i = 0; i < _qtrs.size(); i++) { float binRight = binLeft + bin_width; if (i == _qtrs.size() - 1) binRight = right; if (left <= binRight && right >= binLeft) { pType p = {(uint32_t)payload[0], (uint32_t)payload[1]}; status &= _qtrs[i]->Insert(left, top, right, bottom, p); } binLeft = binRight; } return (status); } bool QuadTreeRectangleP::Insert(std::vector::rectangle_t> rectangles, std::vector payloads) { VAssert(rectangles.size() == payloads.size()); bool status = true; vector::rectangle_t>> parRectangles(_qtrs.size()); vector> parPayloads(_qtrs.size()); // Pre-allocate space for each tree // for (int i = 0; i < _qtrs.size(); i++) { parRectangles[i].reserve(rectangles.size() / _qtrs.size()); parPayloads[i].reserve(payloads.size() / _qtrs.size()); } // parRectangles and parPayloads will contain the regions that // need to be inserted into each subtree // float bin_width = (_right - _left) / ((float)_qtrs.size()); float binLeft = _left; for (size_t j = 0; j < rectangles.size(); j++) { for (int i = 0; i < _qtrs.size(); i++) { float binRight = binLeft + bin_width; if (i == _qtrs.size() - 1) binRight = _right; if ((rectangles[j]._left <= binRight) && (rectangles[j]._right >= binLeft)) { parRectangles[i].push_back(rectangles[j]); parPayloads[i].push_back(payloads[j]); } binLeft = binRight; } } // Perform parallel construction of tree // #pragma omp parallel #pragma omp for for (int i = 0; i < _qtrs.size(); i++) { for (size_t j = 0; j < parRectangles[i].size(); j++) { status &= _qtrs[i]->Insert(parRectangles[i][j], parPayloads[i][j]); } } return (status); } bool QuadTreeRectangleP::Insert(const Grid *grid, size_t ncells) { if (ncells == 0) { ncells = Wasp::VProduct(grid->GetCellDimensions().data(), grid->GetNumCellDimensions()); } // parRectangles and parPayloads will contain the rectangles and their // payloads that need to be inserted into each substree // vector::rectangle_t>> parRectangles(_qtrs.size()); vector> parPayloads(_qtrs.size()); for (int i = 0; i < _qtrs.size(); i++) { parRectangles[i].reserve(ncells / _qtrs.size()); parPayloads[i].reserve(ncells / _qtrs.size()); } int ncellindices = grid->GetNumCellDimensions(); // Populate parRectangles and parPayloads with the data that will // be used to contruct the quadtree // #pragma omp parallel { size_t maxNodes = grid->GetMaxVertexPerCell(); vector nodes(maxNodes); int id = omp_get_thread_num(); int nthreads = omp_get_num_threads(); size_t istart = id * ncells / nthreads; size_t iend = (id + 1) * ncells / nthreads; if (id == nthreads - 1) iend = ncells; CoordType coords; Grid::ConstCellIterator itr = grid->ConstCellBegin() + istart; for (size_t i = istart; i < iend; i++, ++itr) { DimsType cell = {0, 0, 0}; Grid::CopyToArr3((*itr).data(), ncellindices, cell); grid->GetCellNodes(cell, nodes); if (nodes.size() < 2) continue; grid->GetUserCoordinates(nodes[0], coords); float left = (float)coords[0]; float right = (float)coords[0]; float top = (float)coords[1]; float bottom = (float)coords[1]; for (int j = 1; j < nodes.size(); j++) { grid->GetUserCoordinates(nodes[j], coords); if (coords[0] < left) left = (float)coords[0]; if (coords[0] > right) right = (float)coords[0]; if (coords[1] < top) top = (float)coords[1]; if (coords[1] > bottom) bottom = (float)coords[1]; } // Figure out which subtree(s) contain the rectangle. In general, // a rectangle can span multiple subtrees, in which case it // will be inserted into both. // float bin_width = (_right - _left) / ((float)_qtrs.size()); float binLeft = _left; for (int j = 0; j < _qtrs.size(); j++) { float binRight = binLeft + bin_width; if (j == _qtrs.size() - 1) binRight = _right; if ((left <= binRight) && (right >= binLeft)) { class QuadTreeRectangle::rectangle_t r(left, top, right, bottom); pType p = {(uint32_t)cell[0], (uint32_t)cell[1]}; #pragma omp critical { parRectangles[j].push_back(r); parPayloads[j].push_back(p); } } binLeft = binRight; } } } // At this point parRectangles and parPayloads contain a vector of // rectangles and their payloads that intersect each of the subtrees that // make up the tree. Since there is no shared data between each of // the subtrees we can populate each subtree in parallel without any need // for synchronization (mutex, etc.) // bool status = true; #pragma omp parallel #pragma omp for for (int i = 0; i < _qtrs.size(); i++) { for (size_t j = 0; j < parRectangles[i].size(); j++) { status &= _qtrs[i]->Insert(parRectangles[i][j], parPayloads[i][j]); } } return (status); } void QuadTreeRectangleP::GetPayloadContained(float x, float y, std::vector &payloads) const { payloads.clear(); int bin = 0; float bin_width = ((float)_right - (float)_left) / ((float)_qtrs.size()); float binLeft = _left; for (int i = 0; i < _qtrs.size(); i++) { float binRight = binLeft + bin_width; if (i == _qtrs.size() - 1) binRight = _right; if (x >= binLeft && x <= binRight) { bin = i; break; } binLeft = binRight; } std::vector p; _qtrs[bin]->GetPayloadContained(x, y, p); for (auto itr = p.begin(); itr != p.end(); ++itr) { payloads.push_back(DimsType{(*itr)[0], (*itr)[1], 0}); } } void QuadTreeRectangleP::GetStats(std::vector &payload_histo, std::vector &level_histo) const { payload_histo.clear(); level_histo.clear(); for (int i = 0; i < _qtrs.size(); i++) { std::vector p; std::vector l; _qtrs[i]->GetStats(p, l); payload_histo.insert(payload_histo.end(), p.begin(), p.end()); level_histo.insert(level_histo.end(), l.begin(), l.end()); } } ================================================ FILE: lib/vdc/RegularGrid.cpp ================================================ #include #include #include "vapor/VAssert.h" #include #include #ifdef Darwin #include #endif #ifdef _WINDOWS #include "windows.h" #include "Winbase.h" #include #endif #include #include "vapor/RegularGrid.h" using namespace std; using namespace VAPoR; void RegularGrid::_regularGrid(const CoordType &minu, const CoordType &maxu) { VAssert(minu.size() == maxu.size()); _delta = {0.0, 0.0, 0.0}; _geometryDim = 0; for (int i = 0; i < minu.size(); i++) { if (minu[i] != maxu[i]) _geometryDim++; else break; } VAssert(_geometryDim >= GetNumDimensions()); _minu = minu; _maxu = maxu; DimsType dims = GetDimensions(); for (int i = 0; i < minu.size(); i++) { if (dims[i] > 1) { _delta[i] = (_maxu[i] - _minu[i]) / (double)(dims[i] - 1); } else { _delta[i] = 0.0; } } } RegularGrid::RegularGrid(const DimsType &dims, const DimsType &bs, const vector &blks, const CoordType &minu, const CoordType &maxu) : StructuredGrid(dims, bs, blks) { _regularGrid(minu, maxu); } RegularGrid::RegularGrid(const vector &dimsv, const vector &bsv, const vector &blks, const vector &minuv, const vector &maxuv) : StructuredGrid(dimsv, bsv, blks) { VAssert(minuv.size() == maxuv.size()); VAssert(minuv.size() >= GetNumDimensions()); CoordType minu = {0.0, 0.0, 0.0}; CoordType maxu = {0.0, 0.0, 0.0}; CopyToArr3(minuv, minu); CopyToArr3(maxuv, maxu); _regularGrid(minu, maxu); } DimsType RegularGrid::GetCoordDimensions(size_t dim) const { DimsType dims = {1, 1, 1}; if (dim == 0) { dims[0] = GetDimensions()[0]; } else if (dim == 1) { dims[0] = GetDimensions()[1]; } else if (dim == 2) { dims[0] = GetDimensions()[2]; } return (dims); } float RegularGrid::GetValueNearestNeighbor(const CoordType &coords) const { CoordType cCoords; ClampCoord(coords, cCoords); if (!InsideGrid(cCoords)) return (GetMissingValue()); size_t i = 0; size_t j = 0; size_t k = 0; if (_delta[0] != 0.0) i = (size_t)floor((cCoords[0] - _minu[0]) / _delta[0]); if (_delta[1] != 0.0) j = (size_t)floor((cCoords[1] - _minu[1]) / _delta[1]); auto dims = GetDimensions(); if (GetGeometryDim() == 3) if (_delta[2] != 0.0) k = (size_t)floor((cCoords[2] - _minu[2]) / _delta[2]); VAssert(i < dims[0]); VAssert(j < dims[1]); if (GetNumDimensions() == 3) VAssert(k < dims[2]); double iwgt = 0.0; double jwgt = 0.0; double kwgt = 0.0; if (_delta[0] != 0.0) { iwgt = ((cCoords[0] - _minu[0]) - (i * _delta[0])) / _delta[0]; } if (_delta[1] != 0.0) { jwgt = ((cCoords[1] - _minu[1]) - (j * _delta[1])) / _delta[1]; } if (GetGeometryDim() == 3) { if (_delta[2] != 0.0) { kwgt = ((cCoords[2] - _minu[2]) - (k * _delta[2])) / _delta[2]; } } if (iwgt > 0.5) i++; if (jwgt > 0.5) j++; if (GetNumDimensions() == 3 && kwgt > 0.5) k++; return (AccessIJK(i, j, k)); } float RegularGrid::GetValueLinear(const CoordType &coords) const { CoordType cCoords; ClampCoord(coords, cCoords); float mv = GetMissingValue(); if (!InsideGrid(cCoords)) return (mv); size_t i = 0; size_t j = 0; size_t k = 0; if (_delta[0] != 0.0) { i = (size_t)floor((cCoords[0] - _minu[0]) / _delta[0]); } if (_delta[1] != 0.0) { j = (size_t)floor((cCoords[1] - _minu[1]) / _delta[1]); } if (_delta[2] != 0.0) { k = (size_t)floor((cCoords[2] - _minu[2]) / _delta[2]); } auto dims = GetDimensions(); VAssert(i < dims[0]); VAssert(j < dims[1]); VAssert(k < dims[2]); double xwgt = 0.0; double ywgt = 0.0; double zwgt = 0.0; if (_delta[0] != 0.0) { xwgt = 1.0 - (((cCoords[0] - _minu[0]) - (i * _delta[0])) / _delta[0]); } if (_delta[1] != 0.0) { ywgt = 1.0 - (((cCoords[1] - _minu[1]) - (j * _delta[1])) / _delta[1]); } if (_delta[2] != 0.0) { zwgt = 1.0 - (((cCoords[2] - _minu[2]) - (k * _delta[2])) / _delta[2]); } return (TrilinearInterpolate(i, j, k, xwgt, ywgt, zwgt)); } void RegularGrid::GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const { minu = _minu; maxu = _maxu; } void RegularGrid::GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const { DimsType cMin; ClampIndex(min, cMin); DimsType cMax; ClampIndex(max, cMax); GetUserCoordinates(cMin, minu); GetUserCoordinates(cMax, maxu); } void RegularGrid::GetUserCoordinates(const DimsType &indices, CoordType &coords) const { coords = {0.0, 0.0, 0.0}; DimsType cIndices; ClampIndex(indices, cIndices); auto dims = GetDimensions(); for (int i = 0; i < dims.size(); i++) { size_t index = cIndices[i]; VAssert(dims[i] > 0); if (index >= dims[i]) { index = dims[i] - 1; } coords[i] = cIndices[i] * _delta[i] + _minu[i]; } } bool RegularGrid::GetIndicesCell(const CoordType &coords, DimsType &indices) const { CoordType cCoords; ClampCoord(coords, cCoords); auto dims = GetDimensions(); vector wgts; VAssert(GetGeometryDim() <= 3); for (int i = 0; i < GetGeometryDim(); i++) { VAssert(dims[i] > 0); if (cCoords[i] < _minu[i] || cCoords[i] > _maxu[i]) { return (false); } if (_delta[i] != 0.0) { indices[i] = (size_t)floor((cCoords[i] - _minu[i]) / _delta[i]); // Edge case // if (indices[i] == dims[i] - 1) indices[i]--; } VAssert(indices[i] < dims[i] - 1); } return (true); } bool RegularGrid::InsideGrid(const CoordType &coords) const { CoordType cCoords; ClampCoord(coords, cCoords); VAssert(GetGeometryDim() <= 3); for (int i = 0; i < GetGeometryDim(); i++) { if (cCoords[i] < _minu[i]) return (false); if (cCoords[i] > _maxu[i]) return (false); } return (true); } RegularGrid::ConstCoordItrRG::ConstCoordItrRG(const RegularGrid *rg, bool begin) : ConstCoordItrAbstract() { _dims = rg->GetDimensions(); _delta = rg->_delta; _minu = rg->_minu; _coords = rg->_minu; _index = {0, 0, 0}; if (!begin) { _index = {0, 0, _dims[_dims.size() - 1]}; } } RegularGrid::ConstCoordItrRG::ConstCoordItrRG(const ConstCoordItrRG &rhs) : ConstCoordItrAbstract() { _index = rhs._index; _dims = rhs._dims; _minu = rhs._minu; _delta = rhs._delta; _coords = rhs._coords; } RegularGrid::ConstCoordItrRG::ConstCoordItrRG() : ConstCoordItrAbstract() { _index = {0, 0, 0}; _dims = {1, 1, 1}; _minu = {0.0, 0.0, 0.0}; _delta = {0.0, 0.0, 0.0}; _coords = {0.0, 0.0, 0.0}; } void RegularGrid::ConstCoordItrRG::next() { _index[0]++; _coords[0] += _delta[0]; if (_index[0] < _dims[0]) { return; } _index[0] = 0; _coords[0] = _minu[0]; _index[1]++; _coords[1] += _delta[1]; if (_index[1] < _dims[1]) { return; } _index[1] = 0; _coords[1] = _minu[1]; _index[2]++; _coords[2] += _delta[2]; if (_index[2] < _dims[2]) { return; } _index[2] = _dims[2]; // last index; } void RegularGrid::ConstCoordItrRG::next(const long &offset) { long maxIndexL = Wasp::VProduct(_dims.data(), _dims.size()) - 1; long newIndexL = Wasp::LinearizeCoords(_index.data(), _dims.data(), _dims.size()) + offset; if (newIndexL < 0) { newIndexL = 0; } if (newIndexL > maxIndexL) { _index = {0, 0, _dims[_dims.size() - 1]}; return; } Wasp::VectorizeCoords(newIndexL, _dims.data(), _index.data(), _dims.size()); for (int i = 0; i < _dims.size(); i++) { _coords[i] = _index[i] * _delta[i] + _minu[i]; } } namespace VAPoR { std::ostream &operator<<(std::ostream &o, const RegularGrid &rg) { o << "RegularGrid " << endl; o << " Min coord "; for (int i = 0; i < rg._minu.size(); i++) { o << rg._minu[i] << " "; } o << endl; o << " Max coord "; for (int i = 0; i < rg._maxu.size(); i++) { o << rg._maxu[i] << " "; } o << endl; o << (const StructuredGrid &)rg; return o; } }; // namespace VAPoR ================================================ FILE: lib/vdc/StretchedGrid.cpp ================================================ #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include using namespace std; using namespace VAPoR; void StretchedGrid::_stretchedGrid(const vector &xcoords, const vector &ycoords, const vector &zcoords) { VAssert(xcoords.size() != 0); VAssert(ycoords.size() != 0); _xcoords.clear(); _ycoords.clear(); _zcoords.clear(); _xcoords = xcoords; _ycoords = ycoords; _zcoords = zcoords; // Get the user extents now. Do this only once. // GetUserExtentsHelper(_minu, _maxu); } StretchedGrid::StretchedGrid(const DimsType &dims, const DimsType &bs, const vector &blks, const vector &xcoords, const vector &ycoords, const vector &zcoords) : StructuredGrid(dims, bs, blks) { _stretchedGrid(xcoords, ycoords, zcoords); } StretchedGrid::StretchedGrid(const vector &dims, const vector &bs, const vector &blks, const vector &xcoords, const vector &ycoords, const vector &zcoords) : StructuredGrid(dims, bs, blks) { VAssert(bs.size() == dims.size()); VAssert(bs.size() >= 1 && bs.size() <= 3); _stretchedGrid(xcoords, ycoords, zcoords); } size_t StretchedGrid::GetGeometryDim() const { return (_zcoords.size() == 0 ? 2 : 3); } DimsType StretchedGrid::GetCoordDimensions(size_t dim) const { DimsType dims = {1, 1, 1}; if (dim < 3) { dims[0] = GetDimensions()[dim]; } return (dims); } void StretchedGrid::GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const { DimsType cMin = {0,0,0}; ClampIndex(min, cMin); DimsType cMax = {0,0,0}; ClampIndex(max, cMax); for (int i = 0; i < GetNodeDimensions().size(); i++) { VAssert(cMin[i] <= cMax[i]); } for (int i = 0; i < 3; i++) { minu[i] = 0.0; maxu[i] = 0.0; } minu[0] = _xcoords[cMin[0]]; maxu[0] = _xcoords[cMax[0]]; if (minu[0] > maxu[0]) std::swap(minu[0], maxu[0]); minu[1] = _ycoords[cMin[1]]; maxu[1] = _ycoords[cMax[1]]; if (minu[1] > maxu[1]) std::swap(minu[1], maxu[1]); // We're done if 2D grid // if (GetGeometryDim() == 2) return; minu[2] = _zcoords[cMin[2]]; maxu[2] = _zcoords[cMax[2]]; if (minu[2] > maxu[2]) std::swap(minu[2], maxu[2]); } void StretchedGrid::GetUserCoordinates(const DimsType &indices, CoordType &coords) const { DimsType cIndices; ClampIndex(indices, cIndices); coords[0] = _xcoords[cIndices[0]]; coords[1] = _ycoords[cIndices[1]]; if (GetGeometryDim() > 2) { coords[2] = _zcoords[cIndices[2]]; } } bool StretchedGrid::GetIndicesCell(const CoordType &coords, DimsType &indices, double wgts[3]) const { // Clamp coordinates on periodic boundaries to grid extents // CoordType cCoords; ClampCoord(coords, cCoords); double x = cCoords[0]; double y = cCoords[1]; double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0; size_t i, j, k; wgts[0] = 0.0; wgts[1] = 0.0; wgts[2] = 0.0; bool inside = _insideGrid(x, y, z, i, j, k, wgts[0], wgts[1], wgts[2]); if (!inside) return (false); indices[0] = i; indices[1] = j; if (GetGeometryDim() == 2) return (true); indices[2] = k; return (true); } bool StretchedGrid::InsideGrid(const CoordType &coords) const { // Clamp coordinates on periodic boundaries to reside within the // grid extents // CoordType cCoords; ClampCoord(coords, cCoords); // Do a quick check to see if the point is completely outside of // the grid bounds. // VAssert(GetGeometryDim() <= 3); for (int i = 0; i < GetGeometryDim(); i++) { if (cCoords[i] < _minu[i] || cCoords[i] > _maxu[i]) return (false); } double xwgt, ywgt, zwgt; size_t i, j, k; // not used double x = cCoords[0]; double y = cCoords[1]; double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0; bool inside = _insideGrid(x, y, z, i, j, k, xwgt, ywgt, zwgt); return (inside); } StretchedGrid::ConstCoordItrSG::ConstCoordItrSG(const StretchedGrid *sg, bool begin) : ConstCoordItrAbstract() { _sg = sg; _index = {0, 0, 0}; _coords = {0.0, 0.0, 0.0}; const DimsType &dims = sg->GetDimensions(); if (!begin) { _index = {0, 0, dims[dims.size() - 1]}; } if (_sg->_xcoords.size()) _coords[0] = _sg->_xcoords[0]; if (_sg->_ycoords.size()) _coords[1] = _sg->_ycoords[0]; if (_sg->_zcoords.size()) _coords[2] = _sg->_zcoords[0]; } StretchedGrid::ConstCoordItrSG::ConstCoordItrSG(const ConstCoordItrSG &rhs) : ConstCoordItrAbstract() { _sg = rhs._sg; _index = rhs._index; _coords = rhs._coords; } StretchedGrid::ConstCoordItrSG::ConstCoordItrSG() : ConstCoordItrAbstract() { _sg = NULL; _index = {0, 0, 0}; _coords = {0.0, 0.0, 0.0}; } void StretchedGrid::ConstCoordItrSG::next() { auto dims = _sg->GetDimensions(); _index[0]++; if (_index[0] < dims[0]) { _coords[0] = _sg->_xcoords[_index[0]]; _coords[1] = _sg->_ycoords[_index[1]]; return; } _index[0] = 0; _index[1]++; if (_index[1] < dims[1]) { _coords[0] = _sg->_xcoords[_index[0]]; _coords[1] = _sg->_ycoords[_index[1]]; return; } _index[1] = 0; _index[2]++; if (_index[2] < dims[2]) { _coords[0] = _sg->_xcoords[_index[0]]; _coords[1] = _sg->_ycoords[_index[1]]; _coords[2] = _sg->_zcoords[_index[2]]; return; } _index[2] = dims[2]; // last index; } void StretchedGrid::ConstCoordItrSG::next(const long &offset) { auto dims = _sg->GetDimensions(); long maxIndexL = Wasp::VProduct(dims.data(), dims.size()) - 1; long newIndexL = Wasp::LinearizeCoords(_index.data(), dims.data(), dims.size()) + offset; if (newIndexL < 0) { newIndexL = 0; } if (newIndexL > maxIndexL) { _index = {0, 0, dims[dims.size() - 1]}; return; } _index = {0, 0, 0}; Wasp::VectorizeCoords(newIndexL, dims.data(), _index.data(), dims.size()); _coords[0] = _sg->_xcoords[_index[0]]; _coords[1] = _sg->_ycoords[_index[1]]; _coords[2] = _sg->_zcoords[_index[2]]; } float StretchedGrid::GetValueNearestNeighbor(const CoordType &coords) const { // Clamp coordinates on periodic boundaries to grid extents // CoordType cCoords; ClampCoord(coords, cCoords); double wgts[] = {0.0, 0.0, 0.0}; size_t i, j, k; double x = cCoords[0]; double y = cCoords[1]; double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0; bool inside = _insideGrid(x, y, z, i, j, k, wgts[0], wgts[1], wgts[2]); if (wgts[0] < 0.5) i++; if (wgts[1] < 0.5) j++; if (wgts[2] < 0.5) k++; if (!inside) return (GetMissingValue()); return (AccessIJK(i, j, k)); } float StretchedGrid::GetValueLinear(const CoordType &coords) const { // Clamp coordinates on periodic boundaries to grid extents // CoordType cCoords; ClampCoord(coords, cCoords); // handlese case where grid is 2D. I.e. if 2d then zwgt[0] == 1 && // zwgt[1] = 0.0 // double wgts[] = {0.0, 0.0, 0.0}; size_t i, j, k; double x = cCoords[0]; double y = cCoords[1]; double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0; bool inside = _insideGrid(x, y, z, i, j, k, wgts[0], wgts[1], wgts[2]); float mv = GetMissingValue(); if (!inside) return (mv); return (TrilinearInterpolate(i, j, k, wgts[0], wgts[1], wgts[2])); } void StretchedGrid::GetUserExtentsHelper(CoordType &minext, CoordType &maxext) const { auto dims = StructuredGrid::GetDimensions(); DimsType min = {0, 0, 0}; DimsType max = {0, 0, 0}; for (int i = 0; i < dims.size(); i++) { assert(dims[i] > 0); // will help debug max[i] = (dims[i] - 1); } CoordType minv, maxv; StretchedGrid::GetBoundingBox(min, max, minv, maxv); for (int i = 0; i < min.size(); i++) { minext[i] = minv[i]; maxext[i] = maxv[i]; } } // Search for a point inside the grid. If the point is inside return true, // and provide the weights/coordinates for the point within // the XYZ cell containing the point // If the point is outside of the // grid the values of 'xwgt', 'ywgt', and 'zwgt' are not defined // bool StretchedGrid::_insideGrid(double x, double y, double z, size_t &i, size_t &j, size_t &k, double &xwgt, double &ywgt, double &zwgt) const { xwgt = 0.0; ywgt = 0.0; zwgt = 0.0; i = j = k = 0; if (!Wasp::BinarySearchRange(_xcoords, x, i)) return (false); if (_xcoords.size() > 1) { xwgt = 1.0 - (x - _xcoords[i]) / (_xcoords[i + 1] - _xcoords[i]); } else { xwgt = 1.0; } if (!Wasp::BinarySearchRange(_ycoords, y, j)) return (false); if (_ycoords.size() > 1) { ywgt = 1.0 - (y - _ycoords[j]) / (_ycoords[j + 1] - _ycoords[j]); } else { ywgt = 1.0; } if (GetGeometryDim() == 2) { zwgt = 1.0; return (true); } // Now verify that Z coordinate of point is in grid, and find // its interpolation weights if so. // if (!Wasp::BinarySearchRange(_zcoords, z, k)) return (false); if (_zcoords.size() > 1) { zwgt = 1.0 - (z - _zcoords[k]) / (_zcoords[k + 1] - _zcoords[k]); } else { zwgt = 1.0; } return (true); } ================================================ FILE: lib/vdc/StructuredGrid.cpp ================================================ #include #include #include #include "vapor/VAssert.h" #include #include #include #ifdef Darwin #include #endif #ifdef _WINDOWS #include "windows.h" #include "Winbase.h" #include #endif #include #include using namespace std; using namespace VAPoR; void StructuredGrid::_structuredGrid(const DimsType &dims, const DimsType &bs, const vector &blks) { _cellDims = Grid::GetDimensions(); for (int i = 0; i < _cellDims.size(); i++) { _cellDims[i]--; if (_cellDims[i] < 1) _cellDims[i] = 1; } } StructuredGrid::StructuredGrid(const DimsType &dims, const DimsType &bs, const vector &blks) : Grid(dims, bs, blks, GetNumDimensions(dims)) { _structuredGrid(dims, bs, blks); } StructuredGrid::StructuredGrid(const vector &dimsv, const vector &bsv, const vector &blks) : Grid(dimsv, bsv, blks, dimsv.size()) { DimsType dims = {1, 1, 1}; DimsType bs = {1, 1, 1}; CopyToArr3(dimsv, dims); CopyToArr3(bsv, bs); _structuredGrid(dims, bs, blks); } const DimsType &StructuredGrid::GetNodeDimensions() const { return GetDimensions(); } const size_t StructuredGrid::GetNumNodeDimensions() const { return GetNumDimensions(); } bool StructuredGrid::GetCellNodes(const DimsType &cindices, vector &nodes) const { DimsType cCindices; ClampCellIndex(cindices, cCindices); auto dims = GetDimensions(); // Cells have the same ID's as their first node // // walk counter-clockwise order // if (dims[0] > 1 && dims[1] > 1 && dims[2] < 2) { nodes.resize(4); nodes[0][0] = cCindices[0]; nodes[0][1] = cCindices[1]; nodes[0][2] = 0; nodes[1][0] = cCindices[0] + 1; nodes[1][1] = cCindices[1]; nodes[1][2] = 0; nodes[2][0] = cCindices[0] + 1; nodes[2][1] = cCindices[1] + 1; nodes[2][2] = 0; nodes[3][0] = cCindices[0]; nodes[3][1] = cCindices[1] + 1; nodes[3][2] = 0; } else if (dims[0] > 1 && dims[1] > 1 && dims[2] > 1) { nodes.resize(8); nodes[0][0] = cCindices[0]; nodes[0][1] = cCindices[1]; nodes[0][2] = cCindices[2]; nodes[1][0] = cCindices[0] + 1; nodes[1][1] = cCindices[1]; nodes[1][2] = cCindices[2]; nodes[2][0] = cCindices[0] + 1; nodes[2][1] = cCindices[1] + 1; nodes[2][2] = cCindices[2]; nodes[3][0] = cCindices[0]; nodes[3][1] = cCindices[1] + 1; nodes[3][2] = cCindices[2]; nodes[4][0] = cCindices[0]; nodes[4][1] = cCindices[1]; nodes[4][2] = cCindices[2] + 1; nodes[5][0] = cCindices[0] + 1; nodes[5][1] = cCindices[1]; nodes[5][2] = cCindices[2] + 1; nodes[6][0] = cCindices[0] + 1; nodes[6][1] = cCindices[1] + 1; nodes[6][2] = cCindices[2] + 1; nodes[7][0] = cCindices[0]; nodes[7][1] = cCindices[1] + 1; nodes[7][2] = cCindices[2] + 1; } // Handle dims[i] == 1 // for (int j = 0; j < nodes.size(); j++) { for (int i = 0; i < dims.size(); i++) { if (nodes[j][i] >= dims[i]) { nodes[j][i] -= 1; } } } return (true); } bool StructuredGrid::GetCellNeighbors(const DimsType &cindices, std::vector &cells) const { cells.clear(); DimsType cCindices; ClampCellIndex(cindices, cCindices); auto dims = GetDimensions(); auto ndims = GetNumDimensions(); VAssert((ndims == 2) && "3D cells not yet supported"); VAssert(dims[0] > 1 && dims[1] > 1); // Cells have the same ID's as their first node // // walk counter-clockwise order // if (ndims == 2) { DimsType indices; if (cCindices[1] != 0) { // below indices = {cCindices[0], cCindices[1] - 1, 0}; } cells.push_back(indices); if (cCindices[0] != dims[0] - 2) { // right indices = {cCindices[0] + 1, cCindices[1], 0}; } cells.push_back(indices); if (cCindices[1] != dims[1] - 2) { // top indices = {cCindices[0], cCindices[1] + 1, 0}; } cells.push_back(indices); if (cCindices[0] != 0) { // left indices = {cCindices[0] - 1, cCindices[1], 0}; } cells.push_back(indices); } return (true); } bool StructuredGrid::GetNodeCells(const DimsType &indices, std::vector &cells) const { cells.clear(); auto dims = GetDimensions(); auto ndims = GetNumDimensions(); VAssert((ndims == 2) && "3D cells not yet supported"); VAssert(dims[0] > 1 && dims[1] > 1); // Check if invalid indices // for (int i = 0; i < GetGeometryDim(); i++) { VAssert(dims[i] > 0); if (indices[i] > (dims[i] - 1)) return (false); } if (ndims == 2) { DimsType indices; if (indices[0] != 0 && indices[1] != 0) { // below, left indices = {indices[0] - 1, indices[1] - 1, 0}; cells.push_back(indices); } if (indices[1] != 0) { // below, right indices = {indices[0], indices[1] - 1, 0}; cells.push_back(indices); } if (indices[0] != (dims[0] - 1) && indices[1] != (dims[1])) { // top, right indices = {indices[0], indices[1], 0}; cells.push_back(indices); } if (indices[0] != 0) { // top, top indices = {indices[0] - 1, indices[1], 0}; cells.push_back(indices); } } return (true); } bool StructuredGrid::GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const { const DimsType &dims = GetNodeDimensions(); if (!GetIndicesCell(minu, min)) return (false); if (!GetIndicesCell(maxu, max)) return (false); for (int i = 0; i < max.size(); i++) { if (max[i] < dims[i] - 1) max[i] += 1; } // For curvilinear grids it's possible that minu and maxu components // are swapped // CoordType newMinu, newMaxu; GetUserCoordinates(min.data(), newMinu.data()); GetUserCoordinates(max.data(), newMaxu.data()); for (int i = 0; i < newMinu.size(); i++) { if (newMinu > newMaxu) std::swap(min[i], max[i]); } return (true); }; void StructuredGrid::ClampCoord(const CoordType &coords, CoordType &cCoords) const { const vector &periodic = GetPeriodic(); size_t n = min(GetGeometryDim(), periodic.size()); auto p = [](bool v) { return (v == true); }; if (std::none_of(periodic.begin(), periodic.begin() + n, p)) { cCoords = coords; return; } auto dims = GetDimensions(); CoordType minu, maxu; GetUserExtents(minu, maxu); cCoords = coords; VAssert(GetGeometryDim() <= 3); for (int i = 0; i < GetGeometryDim(); i++) { // // Handle coordinates for dimensions of length 1 // if (dims[i] == 1) { cCoords[i] = minu[i]; continue; } if (cCoords[i] < minu[i] && periodic[i]) { while (cCoords[i] < minu[i]) cCoords[i] += maxu[i] - minu[i]; } if (cCoords[i] > maxu[i] && periodic[i]) { while (cCoords[i] > maxu[i]) cCoords[i] -= maxu[i] - minu[i]; } } } bool StructuredGrid::HasInvertedCoordinateSystemHandiness() const { auto ndims = GetNumDimensions(); if (ndims < 2) return (true); // Arbitrary size_t vi0[] = {0, 0, 0}; size_t vi1[] = {1, 0, 0}; size_t vi2[] = {0, 1, 0}; double v0[3], v1[3], v2[3]; GetUserCoordinates(vi0, v0); GetUserCoordinates(vi1, v1); GetUserCoordinates(vi2, v2); glm::vec3 glm_v0(v0[0], v0[1], v0[2]); glm::vec3 glm_v1(v1[0], v1[1], v1[2]); glm::vec3 glm_v2(v2[0], v2[1], v2[2]); glm::vec3 c2d = glm::cross(glm_v1 - glm_v0, glm_v2 - glm_v0); // CCW if Z component of cross product is positive // if (ndims == 2) return (c2d[2] >= 0.0); size_t vi3[] = {0, 0, 1}; double v3[3]; GetUserCoordinates(vi3, v3); return (c2d[2] * (v3[2] - v0[2]) >= 0.0); } namespace VAPoR { std::ostream &operator<<(std::ostream &o, const StructuredGrid &sg) { o << "StructuredGrid " << endl; o << endl; o << (const Grid &)sg; return o; } }; // namespace VAPoR ================================================ FILE: lib/vdc/TODO.txt ================================================ DataMgr: Make Get* methods const by making cache supporting elements mutable NetCDFCollection: Remove deprecated staggered grid handling Add support for reading subsets of derived variables VDC: File format should store the actual data range of each variable and DataMgr::GetDataRange should be changed to use this. Otherwise statistics used for, e.g. histograms, will be wrong CurvlinearGrid: Broken with POP data in /glade/p/DASG/VAPOR/Data/POP/BryanASP/tenth_degree/daily DC: periodicity should be a property of each coordinate variable, not a data variable property. I.e. each coordinate variable should have a boolean flag indicating whether it is periodic or not. This would make more sense for unstructured grids ================================================ FILE: lib/vdc/UDUnitsClass.cpp ================================================ #include #include #include #include #include "vapor/VAssert.h" #ifdef WIN32 #include "vapor/udunits2.h" #else #include #endif #include #include using namespace VAPoR; using namespace Wasp; using namespace std; UDUnits::UDUnits() { _statmsg[UT_SUCCESS] = "Success"; _statmsg[UT_BAD_ARG] = "An argument violates the function's contract"; _statmsg[UT_EXISTS] = "Unit, prefix, or identifier already exists"; _statmsg[UT_NO_UNIT] = "No such unit exists"; _statmsg[UT_OS] = "Operating-system error."; _statmsg[UT_NOT_SAME_SYSTEM] = "The units belong to different unit-systems"; _statmsg[UT_MEANINGLESS] = "The operation on the unit(s) is meaningless"; _statmsg[UT_NO_SECOND] = "The unit-system doesn't have a unit named \"second\""; _statmsg[UT_VISIT_ERROR] = "An error occurred while visiting a unit"; _statmsg[UT_CANT_FORMAT] = "A unit can't be formatted in the desired manner"; _statmsg[UT_SYNTAX] = "string unit representation contains syntax error"; _statmsg[UT_UNKNOWN] = "string unit representation contains unknown word"; _statmsg[UT_OPEN_ARG] = "Can't open argument-specified unit database"; _statmsg[UT_OPEN_ENV] = "Can't open environment-specified unit database"; _statmsg[UT_OPEN_DEFAULT] = "Can't open installed, default, unit database"; _statmsg[UT_PARSE] = "Error parsing unit specification"; _pressureUnit = NULL; _timeUnit = NULL; _latUnit = NULL; _lonUnit = NULL; _lengthUnit = NULL; _status = (int)UT_SUCCESS; _unitSystem = NULL; } std::string UDUnits::GetDatabasePath() { return GetSharePath("udunits/udunits2.xml"); } int UDUnits::Initialize() { // // Need to turn off error messages, which go to stderr by default // ut_set_error_message_handler(ut_ignore); string unitstr; string path = GetDatabasePath(); if (!path.empty()) { _unitSystem = ut_read_xml(path.c_str()); } else { MyBase::SetErrMsg("Could not find VAPOR installed UDUnits database"); MyBase::SetErrMsg("Attempting to fall back to system install"); _unitSystem = ut_read_xml(NULL); } if (!_unitSystem) goto UDUnits_Initialize_Error; // // We need to be able to determine if a given unit is of a // particular type (e.g. time, pressure, mass, etc). The udunit2 // API doesn't support this directly. So we create a 'unit' // of a particular known type, and then later we can query udunit2 // to see if it is possible to convert between the known unit type // and a unit of unknown type // unitstr = "Pa"; // Pascal units of Pressure _pressureUnit = ut_parse(_unitSystem, unitstr.c_str(), UT_ASCII); if (!_pressureUnit) goto UDUnits_Initialize_Unit_Error; unitstr = "seconds"; _timeUnit = ut_parse(_unitSystem, unitstr.c_str(), UT_ASCII); if (!_timeUnit) goto UDUnits_Initialize_Unit_Error; unitstr = "degrees_north"; _latUnit = ut_parse(_unitSystem, unitstr.c_str(), UT_ASCII); if (!_latUnit) goto UDUnits_Initialize_Unit_Error; unitstr = "degrees_east"; _lonUnit = ut_parse(_unitSystem, unitstr.c_str(), UT_ASCII); if (!_lonUnit) goto UDUnits_Initialize_Unit_Error; unitstr = "meter"; _lengthUnit = ut_parse(_unitSystem, unitstr.c_str(), UT_ASCII); if (!_lengthUnit) goto UDUnits_Initialize_Unit_Error; return 0; UDUnits_Initialize_Unit_Error: MyBase::SetErrMsg("UDUnits failed to parse unit \"%s\"", unitstr.c_str()); UDUnits_Initialize_Error: _status = (int)ut_get_status(); MyBase::SetErrMsg("UDUnits failed to initialize"); MyBase::SetErrMsg("UDUnits Error: %s", GetErrMsg().c_str()); return -1; } bool UDUnits::AreUnitsConvertible(const ut_unit *unit, string unitstr) const { ut_unit *myunit = ut_parse(_unitSystem, unitstr.c_str(), UT_ASCII); if (!myunit) { ut_set_status(UT_SUCCESS); // clear error message return (false); } bool status = true; cv_converter *cv = NULL; if (!(cv = ut_get_converter((ut_unit *)unit, myunit))) { status = false; ut_set_status(UT_SUCCESS); } if (myunit) ut_free(myunit); if (cv) cv_free(cv); return (status); } bool UDUnits::ValidUnit(string unitstr) const { ut_unit *myunit = ut_parse(_unitSystem, unitstr.c_str(), UT_ASCII); if (!myunit) { ut_set_status(UT_SUCCESS); // clear error message return (false); } return (true); } bool UDUnits::IsPressureUnit(string unitstr) const { return (AreUnitsConvertible(_pressureUnit, unitstr)); } bool UDUnits::IsTimeUnit(string unitstr) const { return (AreUnitsConvertible(_timeUnit, unitstr)); } bool UDUnits::IsLatUnit(string unitstr) const { bool status = AreUnitsConvertible(_latUnit, unitstr); if (!status) return (false); // udunits2 does not distinguish between longitude and latitude, only // whether a unit is a plane angle measure. N.B. the conditional // below is probably all that is needed for this method. // if (!((unitstr.compare("degrees_north") == 0) || (unitstr.compare("degree_north") == 0) || (unitstr.compare("degree_N") == 0) || (unitstr.compare("degrees_N") == 0) || (unitstr.compare("degreeN") == 0) || (unitstr.compare("degreesN") == 0))) { status = false; } return (status); } bool UDUnits::IsLonUnit(string unitstr) const { bool status = AreUnitsConvertible(_lonUnit, unitstr); if (!status) return (false); // udunits2 does not distinguish between longitude and latitude, only // whether a unit is a plane angle measure. N.B. the conditional // below is probably all that is needed for this method. // if (!((unitstr.compare("degrees_east") == 0) || (unitstr.compare("degree_east") == 0) || (unitstr.compare("degree_E") == 0) || (unitstr.compare("degrees_E") == 0) || (unitstr.compare("degreeE") == 0) || (unitstr.compare("degreesE") == 0))) { status = false; } return (status); } bool UDUnits::IsLatOrLonUnit(string unitstr) const { return (AreUnitsConvertible(_lonUnit, unitstr) || AreUnitsConvertible(_latUnit, unitstr)); } bool UDUnits::IsLengthUnit(string unitstr) const { return (AreUnitsConvertible(_lengthUnit, unitstr)); } bool UDUnits::Convert(const string from, const string to, const float *src, float *dst, size_t n) const { ut_unit *fromunit = ut_parse(_unitSystem, from.c_str(), UT_ASCII); if (!fromunit) { ut_set_status(UT_SUCCESS); // clear error message return (false); } ut_unit *tounit = ut_parse(_unitSystem, to.c_str(), UT_ASCII); if (!tounit) { ut_free(fromunit); ut_set_status(UT_SUCCESS); // clear error message return (false); } cv_converter *cv = NULL; cv = ut_get_converter((ut_unit *)fromunit, tounit); if (!cv) { ut_free(tounit); ut_free(fromunit); ut_set_status(UT_SUCCESS); return (false); } cv_convert_floats(cv, src, n, dst); if (fromunit) ut_free(fromunit); if (tounit) ut_free(tounit); if (cv) cv_free(cv); return (true); } bool UDUnits::Convert(const string from, const string to, const double *src, double *dst, size_t n) const { ut_unit *fromunit = ut_parse(_unitSystem, from.c_str(), UT_ASCII); if (!fromunit) { ut_set_status(UT_SUCCESS); // clear error message return (false); } ut_unit *tounit = ut_parse(_unitSystem, to.c_str(), UT_ASCII); if (!tounit) { ut_free(fromunit); ut_set_status(UT_SUCCESS); // clear error message return (false); } cv_converter *cv = NULL; cv = ut_get_converter((ut_unit *)fromunit, tounit); if (!cv) { ut_free(tounit); ut_free(fromunit); ut_set_status(UT_SUCCESS); return (false); } cv_convert_doubles(cv, src, n, dst); if (fromunit) ut_free(fromunit); if (tounit) ut_free(tounit); if (cv) cv_free(cv); return (true); } void UDUnits::DecodeTime(double seconds, int *year, int *month, int *day, int *hour, int *minute, int *second) const { double dummy; double second_d; ut_decode_time(seconds, year, month, day, hour, minute, &second_d, &dummy); *second = (int)second_d; } double UDUnits::EncodeTime(int year, int month, int day, int hour, int minute, int second) const { return (ut_encode_time(year, month, day, hour, minute, (double)second)); } string UDUnits::GetErrMsg() const { map::const_iterator itr; itr = _statmsg.find(_status); if (itr == _statmsg.end()) return (string("UNKNOWN")); return (itr->second); } UDUnits::~UDUnits() { if (_pressureUnit) ut_free(_pressureUnit); if (_timeUnit) ut_free(_timeUnit); if (_latUnit) ut_free(_latUnit); if (_lonUnit) ut_free(_lonUnit); if (_lengthUnit) ut_free(_lengthUnit); if (_unitSystem) ut_free_system(_unitSystem); } ================================================ FILE: lib/vdc/UnstructuredGrid.cpp ================================================ #include #include #include "vapor/VAssert.h" #include #include #include #ifdef Darwin #include #endif #ifdef _WINDOWS #include "windows.h" #include "Winbase.h" #include #endif #include #include using namespace std; using namespace VAPoR; void UnstructuredGrid::_unstructuredGrid(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector &blks, size_t topology_dimension, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset) { // vertexDims can be 0 in the case of a single-particle dataset since vapor considers length 1 topological data-dimensions as not contributing to the grids topological dimension VAssert(GetNumDimensions(vertexDims) == 0 || GetNumDimensions(vertexDims) == 1 || GetNumDimensions(vertexDims) == 2); VAssert(GetNumDimensions(vertexDims) == GetNumDimensions(faceDims)); VAssert((GetNumDimensions(vertexDims) == GetNumDimensions(edgeDims)) || (GetNumDimensions(edgeDims) == 0)); // Edge data not supported yet // VAssert(location == NODE || location == CELL); _vertexDims = vertexDims; _faceDims = faceDims; _edgeDims = edgeDims; _nDims = GetNumDimensions(vertexDims); // // Shallow copy raw pointers // _vertexOnFace = vertexOnFace; _faceOnVertex = faceOnVertex; _faceOnFace = faceOnFace; _location = location; _maxVertexPerFace = maxVertexPerFace; _maxFacePerVertex = maxFacePerVertex; _missingID = -1; _boundaryID = -2; Grid::SetNodeOffset(nodeOffset); Grid::SetCellOffset(cellOffset); } UnstructuredGrid::UnstructuredGrid(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector &blks, size_t topology_dimension, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset) : Grid(location == NODE ? vertexDims : (location == CELL ? faceDims : edgeDims), bs, blks, topology_dimension) { _unstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, topology_dimension, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset); } UnstructuredGrid::UnstructuredGrid(const std::vector &vertexDimsv, const std::vector &faceDimsv, const std::vector &edgeDimsv, const std::vector &bsv, const std::vector &blks, size_t topology_dimension, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset) : Grid(location == NODE ? vertexDimsv : (location == CELL ? faceDimsv : edgeDimsv), bsv, blks, topology_dimension) { DimsType vertexDims = {1, 1, 1}; DimsType faceDims = {1, 1, 1}; DimsType edgeDims = {1, 1, 1}; DimsType bs = {1, 1, 1}; CopyToArr3(vertexDimsv, vertexDims); CopyToArr3(faceDimsv, faceDims); CopyToArr3(edgeDimsv, edgeDims); CopyToArr3(bsv, bs); _unstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, topology_dimension, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset); } const VAPoR::DimsType &UnstructuredGrid::GetNodeDimensions() const { return (_vertexDims); } const size_t UnstructuredGrid::GetNumNodeDimensions() const { return _nDims; } bool UnstructuredGrid::GetCellNodes(const DimsType &cindices, vector &nodes) const { DimsType cCindices; ClampCellIndex(cindices, cCindices); // _vertexOnFace is dimensioned cdims[0] x _maxVertexPerFace // const int *ptr = _vertexOnFace + (_maxVertexPerFace * cCindices[0]); long offset = GetNodeOffset(); size_t n = 0; if (GetNumCellDimensions() == 1) { nodes.resize(_maxVertexPerFace); // ensure sufficient memory for (int i = 0; i < _maxVertexPerFace; i++, ptr++) { if (*ptr == GetMissingID()) break; if (*ptr == GetBoundaryID()) continue; if (*ptr + offset < 0) break; nodes[n][0] = *ptr + offset; nodes[n][1] = 0; nodes[n][2] = 0; n++; } } else { // layered case nodes.resize(2 * _maxVertexPerFace); // ensure sufficient memory // Bottom layer // for (int i = 0; i < _maxVertexPerFace; i++, ptr++) { if (*ptr == GetMissingID()) break; if (*ptr == GetBoundaryID()) continue; if (*ptr + offset < 0) break; nodes[n][0] = *ptr + offset; nodes[n][1] = cCindices[1]; n++; } // Top layer is identical to bottom layer accept for the // slowest varying index (the layer index) // int nNodesPerLayer = n; for (int i = 0; i < nNodesPerLayer; i++) { nodes[n][0] = nodes[i][0]; nodes[n][1] = nodes[i][1] + 1; n++; } } nodes.resize(n); // resize to actual count return (true); } bool UnstructuredGrid::GetCellNeighbors(const DimsType &cindices, std::vector &cells) const { cells.clear(); DimsType cCindices = {0, 0, 0}; ClampCellIndex(cindices, cCindices); const DimsType &cdims = GetCellDimensions(); // _faceOnFace is dimensioned cdims[0] x _maxVertexPerFace // const int *ptr = _faceOnFace + (_maxVertexPerFace * cCindices[0]); long offset = GetCellOffset(); DimsType indices = {0, 0, 0}; if (GetNumCellDimensions() == 1) { for (int i = 0; i < _maxVertexPerFace; i++) { if (*ptr == GetMissingID() || *ptr + offset < 0) break; if (*ptr != GetBoundaryID()) { indices[0] = *ptr + offset; } cells.push_back(indices); } } else { // layered case for (int i = 0; i < _maxVertexPerFace; i++) { if (*ptr == GetMissingID() || *ptr + offset < 0) break; if (*ptr != GetBoundaryID()) { indices[0] = *ptr + offset; indices[1] = cCindices[1]; } cells.push_back(indices); } // layer below // if (cCindices[1] != 0) { DimsType indices = {cCindices[0], cCindices[1], 0}; indices[1] = cCindices[1] - 1; cells.push_back(indices); } // layer above // if (cCindices[1] != cdims[1] - 1) { DimsType indices = {cCindices[0], cCindices[1], 0}; indices[1] = indices[1] + 1; cells.push_back(indices); } } return (true); } bool UnstructuredGrid::GetNodeCells(const DimsType &indices, std::vector &cells) const { cells.clear(); VAssert(indices.size() == GetNumDimensions()); VAssert(0 && "GetNodeCells() Not supported"); return false; } ///////////////////////////////////////////////////////////////////////////// // // Iterators // ///////////////////////////////////////////////////////////////////////////// namespace VAPoR { std::ostream &operator<<(std::ostream &o, const UnstructuredGrid &ug) { o << "UnstructuredGrid " << endl; o << " Node dimensions "; for (int i = 0; i < ug._vertexDims.size(); i++) { o << ug._vertexDims[i] << " "; } o << endl; o << " Cell dimensions "; for (int i = 0; i < ug._faceDims.size(); i++) { o << ug._faceDims[i] << " "; } o << endl; o << " Edge dimensions "; for (int i = 0; i < ug._edgeDims.size(); i++) { o << ug._edgeDims[i] << " "; } o << endl; o << " Max nodes per face " << ug._maxVertexPerFace << endl; o << " Max face per node " << ug._maxFacePerVertex << endl; o << " Sample location" << ug._location << endl; o << " Missing ID" << ug._missingID << endl; o << " Boundary ID" << ug._boundaryID << endl; o << (const Grid &)ug; return o; } }; // namespace VAPoR ================================================ FILE: lib/vdc/UnstructuredGrid2D.cpp ================================================ #include #include #include "vapor/VAssert.h" #include #include #ifdef Darwin #include #endif #ifdef _WINDOWS #include "windows.h" #include "Winbase.h" #include #endif #include #include #include using namespace std; using namespace VAPoR; UnstructuredGrid2D::UnstructuredGrid2D(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug, const UnstructuredGridCoordless &zug, std::shared_ptr qtr) : UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset), _xug(xug), _yug(yug), _zug(zug), _qtr(qtr) { VAssert(xug.GetDimensions() == GetDimensions()); VAssert(yug.GetDimensions() == GetDimensions()); VAssert(zug.GetDimensions() == GetDimensions() || zug.GetNumDimensions() == 0); VAssert(location == NODE); if (!_qtr) { _qtr = _makeQuadTreeRectangle(); } } UnstructuredGrid2D::UnstructuredGrid2D(const std::vector &vertexDims, const std::vector &faceDims, const std::vector &edgeDims, const std::vector &bs, const std::vector &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug, const UnstructuredGridCoordless &zug, std::shared_ptr qtr) : UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset), _xug(xug), _yug(yug), _zug(zug), _qtr(qtr) { VAssert(xug.GetDimensions() == GetDimensions()); VAssert(yug.GetDimensions() == GetDimensions()); VAssert(zug.GetDimensions() == GetDimensions() || zug.GetNumDimensions() == 0); VAssert(location == NODE); if (!_qtr) { _qtr = _makeQuadTreeRectangle(); } } DimsType UnstructuredGrid2D::GetCoordDimensions(size_t dim) const { DimsType dims = {1, 1, 1}; if (dim == 0) { dims = _xug.GetDimensions(); } else if (dim == 1) { dims = _yug.GetDimensions(); } else if (dim == 2) { dims = _zug.GetDimensions(); } return (dims); } size_t UnstructuredGrid2D::GetGeometryDim() const { return (_zug.GetNumDimensions() == 0 ? 2 : 3); } void UnstructuredGrid2D::GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const { float range[2]; _xug.GetRange(range); minu[0] = range[0]; maxu[0] = range[1]; _yug.GetRange(range); minu[1] = range[0]; maxu[1] = range[1]; if (GetGeometryDim() < 3) return; _zug.GetRange(range); minu[2] = range[0]; maxu[2] = range[1]; } void UnstructuredGrid2D::GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const { DimsType cMin; ClampIndex(min, cMin); DimsType cMax; ClampIndex(max, cMax); int ncoords = GetGeometryDim(); minu = {std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()}; minu = {std::numeric_limits::lowest(), std::numeric_limits::lowest(), std::numeric_limits::lowest()}; auto dims = GetDimensions(); auto ndims = GetNumDimensions(); size_t start = Wasp::LinearizeCoords(cMin.data(), dims.data(), ndims); size_t stop = Wasp::LinearizeCoords(cMax.data(), dims.data(), ndims); // Currently only support ++ opererator for ConstCoordItr. So random // access is tricky. // ConstCoordItr itr = ConstCoordBegin(); ConstCoordItr enditr = ConstCoordBegin(); for (size_t i = 0; i < start; i++) ++itr; for (size_t i = 0; i < stop; i++) ++enditr; for (; itr != enditr; ++itr) { for (int i = 0; i < ncoords; i++) { if ((*itr)[i] < minu[i]) minu[i] = (*itr)[i]; if ((*itr)[i] > maxu[i]) maxu[i] = (*itr)[i]; } } } bool UnstructuredGrid2D::GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const { VAssert(0 && "Not implemented"); return (true); } void UnstructuredGrid2D::GetUserCoordinates(const DimsType &indices, CoordType &coords) const { DimsType cIndices; ClampIndex(indices, cIndices); coords[0] = _xug.GetValueAtIndex(cIndices); coords[1] = _yug.GetValueAtIndex(cIndices); if (GetGeometryDim() == 3) { coords[2] = _zug.GetValueAtIndex(cIndices); } } bool UnstructuredGrid2D::GetIndicesCell(const CoordType &coords, DimsType &cindices, std::vector> &nodes, std::vector &lambdav) const { nodes.clear(); lambdav.clear(); CoordType cCoords; ClampCoord(coords, cCoords); std::vector lambda(_maxVertexPerFace); int nlambda; // See if point is inside any cells (faces) // size_t my_index; std::vector my_nodes; bool status = _insideGridNodeCentered(cCoords, my_index, my_nodes, lambda.data(), nlambda); if (status) { cindices[0] = my_index; for (int i = 0; i < nlambda; i++) { lambdav.push_back(lambda[i]); nodes.push_back(vector(1, my_nodes[i])); } } return (status); } bool UnstructuredGrid2D::InsideGrid(const CoordType &coords) const { CoordType cCoords; ClampCoord(coords, cCoords); std::vector lambda(_maxVertexPerFace); int nlambda; size_t face; vector nodes; // See if point is inside any cells (faces) // bool status = _insideGridNodeCentered(cCoords, face, nodes, lambda.data(), nlambda); return (status); } float UnstructuredGrid2D::GetValueNearestNeighbor(const CoordType &coords) const { // Clamp coordinates on periodic boundaries to reside within the // grid extents // CoordType cCoords; ClampCoord(coords, cCoords); std::vector lambda(_maxVertexPerFace); int nlambda; size_t face; vector nodes; // See if point is inside any cells (faces) // bool inside = _insideGrid(cCoords, face, nodes, lambda.data(), nlambda); if (!inside) { return (GetMissingValue()); } VAssert(nodes.size() == nlambda); VAssert(face < GetCellDimensions()[0]); int maxindx = 0; for (int i = 1; i < nlambda; i++) { if (lambda[i] > lambda[maxindx]) maxindx = i; } float value = AccessIJK(nodes[maxindx], 0, 0); return ((float)value); } float UnstructuredGrid2D::GetValueLinear(const CoordType &coords) const { // Clamp coordinates on periodic boundaries to reside within the // grid extents // CoordType cCoords; ClampCoord(coords, cCoords); std::vector lambda(_maxVertexPerFace); int nlambda; size_t face; vector nodes; // See if point is inside any cells (faces) // bool inside = _insideGrid(cCoords, face, nodes, lambda.data(), nlambda); if (!inside) { return (GetMissingValue()); } VAssert(nodes.size() == nlambda); VAssert(face < GetCellDimensions()[0]); double value = 0; float mv = GetMissingValue(); for (int i = 0; i < nodes.size(); i++) { float v = AccessIJK(nodes[i], 0, 0); if (v == mv) { if (lambda[i] != 0.0) return (mv); else v = 0.0; } value += v * lambda[i]; } return ((float)value); } ///////////////////////////////////////////////////////////////////////////// // // Iterators // ///////////////////////////////////////////////////////////////////////////// UnstructuredGrid2D::ConstCoordItrU2D::ConstCoordItrU2D(const UnstructuredGrid2D *ug, bool begin) : ConstCoordItrAbstract() { _ncoords = ug->GetGeometryDim(); _coords = {0.0, 0.0, 0.0}; if (begin) { _xCoordItr = ug->_xug.cbegin(); _yCoordItr = ug->_yug.cbegin(); _zCoordItr = ug->_zug.cbegin(); _coords[0] = *_xCoordItr; _coords[1] = *_yCoordItr; if (_ncoords >= 3) { _coords[2] = *_zCoordItr; } } else { _xCoordItr = ug->_xug.cend(); _yCoordItr = ug->_yug.cend(); _zCoordItr = ug->_zug.cend(); } } UnstructuredGrid2D::ConstCoordItrU2D::ConstCoordItrU2D(const ConstCoordItrU2D &rhs) : ConstCoordItrAbstract() { _ncoords = rhs._ncoords; _coords = rhs._coords; _xCoordItr = rhs._xCoordItr; _yCoordItr = rhs._yCoordItr; if (rhs._ncoords >= 3) { _zCoordItr = rhs._zCoordItr; } } UnstructuredGrid2D::ConstCoordItrU2D::ConstCoordItrU2D() : ConstCoordItrAbstract() {} void UnstructuredGrid2D::ConstCoordItrU2D::next() { ++_xCoordItr; _coords[0] = *_xCoordItr; ++_yCoordItr; _coords[1] = *_yCoordItr; if (_ncoords < 3) return; ++_zCoordItr; _coords[2] = *_zCoordItr; } void UnstructuredGrid2D::ConstCoordItrU2D::next(const long &offset) { _xCoordItr += offset; _yCoordItr += offset; _coords[0] = *_xCoordItr; _coords[1] = *_yCoordItr; if (_ncoords < 3) return; _zCoordItr += offset; _coords[2] = *_zCoordItr; } namespace VAPoR { std::ostream &operator<<(std::ostream &o, const UnstructuredGrid2D &ug) { o << "UnstructuredGrid2D " << endl; o << (const Grid &)ug; return o; } }; // namespace VAPoR // Search for a point inside the grid. If the point is inside return true, // and provide the Wachspress weights/coordinates for the point within // the face containing the point in XY, and the linear // interpolation weights/coordinates along Z. // bool UnstructuredGrid2D::_insideGrid(const CoordType &coords, size_t &face, vector &nodes, double *lambda, int &nlambda) const { nodes.clear(); if (_location == NODE) { return (_insideGridNodeCentered(coords, face, nodes, lambda, nlambda)); } else { return (_insideGridFaceCentered(coords, face, nodes, lambda, nlambda)); } } bool UnstructuredGrid2D::_insideGridFaceCentered(const CoordType &coords, size_t &face, vector &nodes, double *lambda, int &nlambda) const { VAssert(0 && "Not supported"); return false; } bool UnstructuredGrid2D::_insideGridNodeCentered(const CoordType &coords, size_t &face_index, vector &nodes, double *lambda, int &nlambda) const { nodes.clear(); double pt[] = {coords[0], coords[1]}; // Find the indices for the faces that might contain the point // vector face_indices; _qtr->GetPayloadContained(pt[0], pt[1], face_indices); for (int i = 0; i < face_indices.size(); i++) { if (_insideFace(face_indices[i][0], pt, nodes, lambda, nlambda)) { face_index = face_indices[i][0]; return (true); } } return (false); } bool UnstructuredGrid2D::_insideFace(size_t face, double pt[2], vector &node_indices, double *lambda, int &nlambda) const { node_indices.clear(); nlambda = 0; double *verts = new double[_maxVertexPerFace * 2]; const int *ptr = _vertexOnFace + (face * _maxVertexPerFace); long offset = GetNodeOffset(); for (int i = 0; i < _maxVertexPerFace; i++) { if (*ptr == GetMissingID()) break; long vertex = *ptr + offset; if (vertex < 0) break; verts[i * 2 + 0] = _xug.AccessIJK(vertex, 0, 0); verts[i * 2 + 1] = _yug.AccessIJK(vertex, 0, 0); node_indices.push_back(*ptr + offset); ptr++; nlambda++; } // Should we test the line case where nlambda == 2? // if (nlambda < 3) { delete[] verts; return (false); } if (!Grid::PointInsideBoundingRectangle(pt, verts, nlambda)) { delete[] verts; return (false); } bool ret = WachspressCoords2D(verts, pt, nlambda, lambda); delete[] verts; return ret; } std::shared_ptr UnstructuredGrid2D::_makeQuadTreeRectangle() const { auto dims = GetDimensions(); size_t reserve_size = dims[0]; CoordType minu, maxu; GetUserExtents(minu, maxu); std::shared_ptr qtr = std::make_shared((float)minu[0], (float)minu[1], (float)maxu[0], (float)maxu[1], 12, reserve_size); qtr->Insert(this); return (qtr); } ================================================ FILE: lib/vdc/UnstructuredGrid3D.cpp ================================================ #include #include #include "vapor/VAssert.h" #include #include #ifdef Darwin #include #endif #ifdef _WINDOWS #include "windows.h" #include "Winbase.h" #include #endif #include #include #include using namespace std; using namespace VAPoR; UnstructuredGrid3D::UnstructuredGrid3D(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug, const UnstructuredGridCoordless &zug) : UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, 3, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset), _xug(xug), _yug(yug), _zug(zug) { // These can be 0 in the case of a single-particle dataset since vapor considers length 1 topological data-dimensions as not contributing to the grids topological dimension // VAssert(xug.GetNumDimensions() == 1); // VAssert(yug.GetNumDimensions() == 1); // VAssert(zug.GetNumDimensions() == 1); VAssert(location == NODE); } UnstructuredGrid3D::UnstructuredGrid3D(const std::vector &vertexDims, const std::vector &faceDims, const std::vector &edgeDims, const std::vector &bs, const std::vector &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug, const UnstructuredGridCoordless &zug) : UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, 3, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset), _xug(xug), _yug(yug), _zug(zug) { // These can be 0 in the case of a single-particle dataset since vapor considers length 1 topological data-dimensions as not contributing to the grids topological dimension // VAssert(xug.GetNumDimensions() == 1); // VAssert(yug.GetNumDimensions() == 1); // VAssert(zug.GetNumDimensions() == 1); VAssert(location == NODE); } DimsType UnstructuredGrid3D::GetCoordDimensions(size_t dim) const { DimsType dims = {1, 1, 1}; if (dim == 0) { dims = _xug.GetDimensions(); } else if (dim == 1) { dims = _yug.GetDimensions(); } else if (dim == 2) { dims = _zug.GetDimensions(); } return (dims); } size_t UnstructuredGrid3D::GetGeometryDim() const { return (3); } void UnstructuredGrid3D::GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const { float range[2]; _xug.GetRange(range); minu[0] = range[0]; maxu[0] = range[1]; _yug.GetRange(range); minu[1] = range[0]; maxu[1] = range[1]; _zug.GetRange(range); minu[2] = range[0]; maxu[2] = range[1]; } void UnstructuredGrid3D::GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const { DimsType cMin; ClampIndex(min, cMin); DimsType cMax; ClampIndex(max, cMax); float range[2]; _xug.GetRange(min, max, range); minu[0] = range[0]; maxu[0] = range[1]; _yug.GetRange(min, max, range); minu[1] = range[0]; maxu[1] = range[1]; _zug.GetRange(min, max, range); minu[2] = range[0]; maxu[2] = range[1]; } bool UnstructuredGrid3D::GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const { VAssert(0 && "Not implemented"); return (true); } void UnstructuredGrid3D::GetUserCoordinates(const DimsType &indices, CoordType &coords) const { DimsType cIndices; ClampIndex(indices, cIndices); coords[0] = _xug.GetValueAtIndex(cIndices); coords[1] = _yug.GetValueAtIndex(cIndices); coords[2] = _zug.GetValueAtIndex(cIndices); } bool UnstructuredGrid3D::GetIndicesCell(const CoordType &coords, DimsType &indices) const { vector nodes2D; vector lambda; float zwgt[2]; return (_insideGrid(coords, indices, nodes2D, lambda, zwgt)); } bool UnstructuredGrid3D::InsideGrid(const CoordType &coords) const { DimsType indices; std::vector nodes2D; vector lambda; float zwgt[2]; return (_insideGrid(coords, indices, nodes2D, lambda, zwgt)); } bool UnstructuredGrid3D::_insideGrid(const CoordType &coords, DimsType &cindices, std::vector &nodes2D, std::vector &lambda, float zwgt[2]) const { VAssert(!"Not implemented"); return false; } float UnstructuredGrid3D::GetValueNearestNeighbor(const CoordType &coords) const { VAssert(!"Not implemented"); return NAN; } float UnstructuredGrid3D::GetValueLinear(const CoordType &coords) const { VAssert(!"Not implemented"); return NAN; } ///////////////////////////////////////////////////////////////////////////// // // Iterators // ///////////////////////////////////////////////////////////////////////////// UnstructuredGrid3D::ConstCoordItrU3D::ConstCoordItrU3D(const UnstructuredGrid3D *ug, bool begin) : ConstCoordItrAbstract() { _ug = ug; _coords = {0.0, 0.0, 0.0}; if (begin) { _xCoordItr = ug->_xug.cbegin(); _yCoordItr = ug->_yug.cbegin(); _zCoordItr = ug->_zug.cbegin(); _coords[0] = *_xCoordItr; _coords[1] = *_yCoordItr; _coords[2] = *_zCoordItr; } else { _xCoordItr = ug->_xug.cend(); _yCoordItr = ug->_yug.cend(); _zCoordItr = ug->_zug.cend(); } } UnstructuredGrid3D::ConstCoordItrU3D::ConstCoordItrU3D(const ConstCoordItrU3D &rhs) : ConstCoordItrAbstract() { _ug = rhs._ug; _xCoordItr = rhs._xCoordItr; _yCoordItr = rhs._yCoordItr; _zCoordItr = rhs._zCoordItr; _coords = rhs._coords; } UnstructuredGrid3D::ConstCoordItrU3D::ConstCoordItrU3D() : ConstCoordItrAbstract() {} void UnstructuredGrid3D::ConstCoordItrU3D::next() { ++_xCoordItr; ++_yCoordItr; ++_zCoordItr; _coords[0] = *_xCoordItr; _coords[1] = *_yCoordItr; _coords[2] = *_zCoordItr; } void UnstructuredGrid3D::ConstCoordItrU3D::next(const long &offset) { VAssert(offset >= 0); _xCoordItr += offset; _yCoordItr += offset; _zCoordItr += offset; _coords[0] = *_xCoordItr; _coords[1] = *_yCoordItr; _coords[2] = *_zCoordItr; } namespace VAPoR { std::ostream &operator<<(std::ostream &o, const UnstructuredGrid3D &ug) { o << "UnstructuredGrid3D " << endl; o << (const Grid &)ug; return o; } }; // namespace VAPoR ================================================ FILE: lib/vdc/UnstructuredGridLayered.cpp ================================================ #include #include #include "vapor/VAssert.h" #include #include #ifdef Darwin #include #endif #ifdef _WINDOWS #include "windows.h" #include "Winbase.h" #include #endif #include #include #include using namespace std; using namespace VAPoR; UnstructuredGridLayered::UnstructuredGridLayered(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug, const UnstructuredGridCoordless &zug, std::shared_ptr qtr) : UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, 3, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset), _ug2d(vector{vertexDims[0]}, vector{faceDims[0]}, edgeDims.size() ? vector{edgeDims[0]} : vector(), vector{bs[0]}, vector(), vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset, xug, yug, UnstructuredGridCoordless(), qtr), _zug(zug) { VAssert(xug.GetNumDimensions() == 1); VAssert(yug.GetNumDimensions() == 1); VAssert(zug.GetNumDimensions() == 2); VAssert(location == NODE); } UnstructuredGridLayered::UnstructuredGridLayered(const std::vector &vertexDims, const std::vector &faceDims, const std::vector &edgeDims, const std::vector &bs, const std::vector &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace, Location location, // node,face, edge size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug, const UnstructuredGridCoordless &zug, std::shared_ptr qtr) : UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, 3, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset), _ug2d(vector{vertexDims[0]}, vector{faceDims[0]}, edgeDims.size() ? vector{edgeDims[0]} : vector(), vector{bs[0]}, vector(), vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset, xug, yug, UnstructuredGridCoordless(), qtr), _zug(zug) { VAssert(xug.GetNumDimensions() == 1); VAssert(yug.GetNumDimensions() == 1); VAssert(zug.GetNumDimensions() == 2); VAssert(location == NODE); } DimsType UnstructuredGridLayered::GetCoordDimensions(size_t dim) const { DimsType dims = {1, 1, 1}; if (dim == 0) { dims = _ug2d.GetCoordDimensions(dim); } else if (dim == 1) { dims = _ug2d.GetCoordDimensions(dim); } else if (dim == 2) { dims = _zug.GetDimensions(); } return (dims); } size_t UnstructuredGridLayered::GetGeometryDim() const { return (3); } void UnstructuredGridLayered::GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const { // Get horizontal extents from base class // _ug2d.GetUserExtents(minu, maxu); // Now add vertical extents // float range[2]; _zug.GetRange(range); minu[2] = range[0]; maxu[2] = range[1]; } void UnstructuredGridLayered::GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const { DimsType cMin; ClampIndex(min, cMin); DimsType cMax; ClampIndex(max, cMax); _ug2d.GetBoundingBox(cMin, cMax, minu, maxu); float range[2]; _zug.GetRange(min, max, range); minu[2] = range[0]; maxu[2] = range[1]; } bool UnstructuredGridLayered::GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const { VAssert(0 && "Not implemented"); return (true); } void UnstructuredGridLayered::GetUserCoordinates(const DimsType &indices, CoordType &coords) const { DimsType cIndices; ClampIndex(indices, cIndices); _ug2d.GetUserCoordinates(cIndices, coords); coords[2] = _zug.GetValueAtIndex(cIndices); } bool UnstructuredGridLayered::_insideGrid(const CoordType &coords, DimsType &cindices, std::vector &nodes2D, std::vector &lambda, float zwgt[2]) const { VAssert(_location == NODE); nodes2D.clear(); lambda.clear(); CoordType cCoords; ClampCoord(coords, cCoords); // Find the 2D horizontal cell containing the X,Y coordinates // std::vector> nodes; bool status = _ug2d.GetIndicesCell(cCoords, cindices, nodes, lambda); if (!status) return (status); VAssert(lambda.size() == nodes.size()); for (int i = 0; i < nodes.size(); i++) { nodes2D.push_back(nodes[i][0]); } // Find k index of cell containing z // vector zcoords; size_t nz = GetDimensions()[1]; for (int kk = 0; kk < nz; kk++) { float z = 0.0; for (int i = 0; i < lambda.size(); i++) { z += _zug.AccessIJK(nodes2D[i], kk) * lambda[i]; } zcoords.push_back(z); } size_t k; if (!Wasp::BinarySearchRange(zcoords, cCoords[2], k)) return (false); VAssert(k >= 0 && k < nz); cindices[1] = k; float z = cCoords[2]; zwgt[0] = 1.0 - (z - zcoords[k]) / (zcoords[k + 1] - zcoords[k]); zwgt[1] = 1.0 - zwgt[0]; return (true); } bool UnstructuredGridLayered::GetIndicesCell(const CoordType &coords, DimsType &indices) const { vector nodes2D; vector lambda; float zwgt[2]; return (_insideGrid(coords, indices, nodes2D, lambda, zwgt)); } bool UnstructuredGridLayered::InsideGrid(const CoordType &coords) const { DimsType indices; std::vector nodes2D; vector lambda; float zwgt[2]; return (_insideGrid(coords, indices, nodes2D, lambda, zwgt)); } float UnstructuredGridLayered::GetValueNearestNeighbor(const CoordType &coords) const { DimsType indices; std::vector nodes2D; vector lambda; float zwgt[2]; bool inside = _insideGrid(coords, indices, nodes2D, lambda, zwgt); if (!inside) return (GetMissingValue()); // Find nearest node in XY plane (the curvilinear part of grid) // The nearest node will have largest lambda resampling value. // float max_lambda = 0.0; int max_nodes2d_index = 0; for (int i = 0; i < lambda.size(); i++) { if (lambda[i] > max_lambda) { max_lambda = lambda[i]; max_nodes2d_index = i; } } // Now find out which node is closest along vertical axis. We rely on // the Cell index returned in 'indices' being identical to the node ID // along the vertical axis ('cause its a layered grid) // int max_vert_id = indices[1]; if (zwgt[1] > zwgt[0]) { max_vert_id += 1; } return (AccessIJK(nodes2D[max_nodes2d_index], max_vert_id)); } float UnstructuredGridLayered::GetValueLinear(const CoordType &coords) const { DimsType indices; std::vector nodes2D; vector lambda; float zwgt[2]; bool inside = _insideGrid(coords, indices, nodes2D, lambda, zwgt); if (!inside) return (GetMissingValue()); // Interpolate value inside bottom face // float mv = GetMissingValue(); float z0 = 0.0; size_t k0 = indices[1]; for (size_t i = 0; i < lambda.size(); i++) { float v = AccessIJK(nodes2D[i], k0, 0); if (v == mv) { if (lambda[i] != 0.0) { z0 = mv; break; } else v = 0.0; } z0 += v * lambda[i]; } if (z0 == mv) return (mv); size_t k1 = k0 + 1; if (k1 >= GetDimensions()[1] || zwgt[1] == 0.0) return (z0); // Interpolate value inside top face // float z1 = 0.0; for (int i = 0; i < lambda.size(); i++) { float v = AccessIJK(nodes2D[i], k1, 0); if (v == mv) { if (lambda[i] != 0.0) { z1 = mv; break; } else v = 0.0; } z1 += v * lambda[i]; } if (z1 == mv) return (mv); return (z0 * zwgt[0] + z1 * zwgt[1]); } ///////////////////////////////////////////////////////////////////////////// // // Iterators // ///////////////////////////////////////////////////////////////////////////// UnstructuredGridLayered::ConstCoordItrULayered::ConstCoordItrULayered(const UnstructuredGridLayered *ug, bool begin) : ConstCoordItrAbstract() { _ug = ug; _coords = {0.0, 0.0, 0.0}; _nElements2D = ug->GetDimensions()[0]; if (begin) { _itr2D = ug->_ug2d.ConstCoordBegin(); _zCoordItr = ug->_zug.cbegin(); _index2D = 0; _coords[0] = (*_itr2D)[0]; _coords[1] = (*_itr2D)[1]; _coords[2] = *_zCoordItr; } else { _itr2D = ug->_ug2d.ConstCoordEnd(); _zCoordItr = ug->_zug.cend(); _index2D = _nElements2D - 1; } } UnstructuredGridLayered::ConstCoordItrULayered::ConstCoordItrULayered(const ConstCoordItrULayered &rhs) : ConstCoordItrAbstract() { _ug = rhs._ug; _itr2D = rhs._itr2D; _zCoordItr = rhs._zCoordItr; _coords = rhs._coords; _nElements2D = rhs._nElements2D; _index2D = rhs._index2D; } UnstructuredGridLayered::ConstCoordItrULayered::ConstCoordItrULayered() : ConstCoordItrAbstract() {} void UnstructuredGridLayered::ConstCoordItrULayered::next() { ++_index2D; ++_itr2D; // Check for overflow // if (_index2D == _nElements2D) { _itr2D = _ug->_ug2d.ConstCoordBegin(); _index2D = 0; } _coords[0] = (*_itr2D)[0]; _coords[1] = (*_itr2D)[1]; ++_zCoordItr; _coords[2] = *_zCoordItr; } void UnstructuredGridLayered::ConstCoordItrULayered::next(const long &offset) { VAssert(offset >= 0); long offset2D = (_index2D + offset) % _nElements2D; _itr2D += (offset2D - _index2D); _index2D += (offset2D - _index2D); _coords[0] = (*_itr2D)[0]; _coords[1] = (*_itr2D)[1]; _zCoordItr += offset; _coords[2] = *_zCoordItr; } namespace VAPoR { std::ostream &operator<<(std::ostream &o, const UnstructuredGridLayered &ug) { o << "UnstructuredGridLayered " << endl; o << (const Grid &)ug; return o; } }; // namespace VAPoR ================================================ FILE: lib/vdc/VDC.cpp ================================================ #include "vapor/VAssert.h" #include #include #include "vapor/VDC.h" using namespace VAPoR; namespace { // Product of elements in a vector // size_t vproduct(vector a) { size_t ntotal = 1; for (int i = 0; i < a.size(); i++) ntotal *= a[i]; return (ntotal); } void _compute_bs(size_t ndims, const vector &default_bs, vector &bs) { bs.clear(); // If the default block size exists for a dimension use it. // Otherwise set the bs to 1 // for (int i = 0; i < ndims; i++) { if (i < default_bs.size()) { bs.push_back(default_bs[i]); } else { bs.push_back(1); // slowest varying block size can be one } } VAssert(ndims == bs.size()); } void _compute_periodic(const vector &dim_names, const vector &default_periodic, vector &periodic) { // If the default periodicity exists for a dimension use it. // Otherwise set the periodicity to false. No periodicity for // time dimensions // for (int i = 0; i < dim_names.size(); i++) { if (i < default_periodic.size()) { periodic.push_back(default_periodic[i]); } else { periodic.push_back(false); } } } string make_mesh_name(const vector &dim_names) { string name; for (int i = 0; i < dim_names.size(); i++) { name += dim_names[i]; if (i < (dim_names.size() - 1)) name += "X"; } return (name); } }; // namespace VDC::VDC() { _master_path.clear(); _mode = R; _defineMode = false; _bs.clear(); for (int i = 0; i < 3; i++) _bs.push_back(64); _wname = "bior4.4"; _cratios.clear(); _cratios.push_back(500); _cratios.push_back(100); _cratios.push_back(10); _cratios.push_back(1); _periodic.clear(); for (int i = 0; i < 3; i++) _periodic.push_back(false); _coordVars.clear(); _dataVars.clear(); _dimsMap.clear(); _atts.clear(); _newUniformVars.clear(); _proj4StringOption.clear(); } int VDC::initialize(const vector &paths, const vector &options, AccessMode mode, vector bs) { _proj4StringOption.clear(); if (options.size() >= 2) { if (options[0] == "-proj4") { _proj4StringOption = options[1]; } } if (!paths.size()) { SetErrMsg("Invalid argument"); return (-1); } _master_path = paths[0]; if (mode == R) { _defineMode = false; } else { _defineMode = true; } _mode = mode; if (mode == W) { _bs = bs; while (_bs.size() > 3) _bs.pop_back(); while (_bs.size() < 3) _bs.push_back(1); } int rc = _udunits.Initialize(); if (rc < 0) { SetErrMsg("Failed to initialize udunits2 library : %s", _udunits.GetErrMsg().c_str()); return (-1); } if (mode == R || mode == A) { return (_ReadMasterMeta()); } return (0); } int VDC::SetCompressionBlock(string wname, vector cratios) { if (!cratios.size()) cratios.push_back(1); sort(cratios.begin(), cratios.end()); reverse(cratios.begin(), cratios.end()); if (!_ValidCompressionBlock(_bs, wname, cratios)) { SetErrMsg("Invalid compression settings"); return (-1); } _wname = wname; _cratios = cratios; return (0); } void VDC::GetCompressionBlock(vector &bs, string &wname, vector &cratios) const { bs = _bs; wname = _wname; cratios = _cratios; } int VDC::DefineDimension(string name, size_t length) { if (!_defineMode) { SetErrMsg("Not in define mode"); return (-1); } // Can't redefine existing dimension names in append mode // if (_mode == A) { if (_dimsMap.find(name) != _dimsMap.end()) { SetErrMsg("Dimension name %s already defined", name.c_str()); return (-1); } } if (!_ValidDefineDimension(name, length)) { SetErrMsg("Invalid definition for variable %s", name.c_str()); return (-1); } Dimension dimension(name, length); // // _dimsMap contains all defined dimensions for the VDC // _dimsMap[name] = dimension; return (0); } int VDC::DefineDimension(string name, size_t length, int axis) { VAssert(axis >= 0 && axis <= 3); int rc = DefineDimension(name, length); if (rc < 0) return (rc); // Now define a 1D coordinate variable // vector sdimnames; string time_dim_name; if (axis == 3) { time_dim_name = name; } else { sdimnames.push_back(name); } return (DefineCoordVarUniform(name, sdimnames, time_dim_name, "", axis, XType::FLOAT, false)); } bool VDC::getDimension(string name, Dimension &dimension) const { map::const_iterator itr = _dimsMap.find(name); if (itr == _dimsMap.end()) return (false); dimension = itr->second; return (true); } vector VDC::getDimensionNames() const { vector dim_names; std::map::const_iterator itr = _dimsMap.begin(); for (; itr != _dimsMap.end(); ++itr) { dim_names.push_back(itr->first); } return (dim_names); } vector VDC::getMeshNames() const { vector mesh_names; std::map::const_iterator itr = _meshes.begin(); for (; itr != _meshes.end(); ++itr) { mesh_names.push_back(itr->first); } return (mesh_names); } bool VDC::getMesh(string mesh_name, DC::Mesh &mesh) const { map::const_iterator itr = _meshes.find(mesh_name); if (itr == _meshes.end()) return (false); mesh = itr->second; return (true); } vector VDC::_GetCoordVarDimNames(const CoordVar &cvar, bool &time_varying) const { time_varying = false; vector dim_names; dim_names = cvar.GetDimNames(); if (!cvar.GetTimeDimName().empty()) { dim_names.push_back(cvar.GetTimeDimName()); time_varying = true; } return (dim_names); } vector VDC::_GetDataVarDimNames(const DataVar &dvar, bool &time_varying) const { time_varying = false; vector dim_names; string mesh = dvar.GetMeshName(); map::const_iterator itr = _meshes.find(mesh); VAssert(itr != _meshes.end()); dim_names = itr->second.GetDimNames(); // Get time dimension if exists // string time_coord_var = dvar.GetTimeCoordVar(); if (time_coord_var.empty()) return (dim_names); std::map::const_iterator itr1; itr1 = _coordVars.find(time_coord_var); VAssert(itr1 != _coordVars.end()); vector dimvec = _GetCoordVarDimNames(itr1->second, time_varying); VAssert(dimvec.size() == 1); dim_names.push_back(dimvec[0]); return (dim_names); } int VDC::_DefineImplicitCoordVars(vector dim_names, vector coord_vars_in, vector &coord_vars_out) { coord_vars_out.clear(); if (dim_names.size() <= coord_vars_in.size()) { // No need to do anything // coord_vars_out = coord_vars_in; return (0); } for (int i = 0; i < dim_names.size(); i++) coord_vars_out.push_back(""); // figure out which coordinate variables are missing // for (int i = 0; i < coord_vars_in.size(); i++) { string name = coord_vars_in[i]; map::const_iterator itr = _coordVars.find(name); if (itr == _coordVars.end()) { SetErrMsg("Undefined coordinate variable \"%s\" ", name.c_str()); return (-1); } int axis = itr->second.GetAxis(); VAssert(axis >= 0 && axis <= 3); coord_vars_out[axis] = name; } // For every coordinate variable that is missing make up a new one // vector new_coord_vars; vector new_coord_axes; for (int i = 0; i < coord_vars_out.size(); i++) { if (coord_vars_out[i].empty()) { coord_vars_out[i] = dim_names[i]; // Keep track of the new coordinate variables that we will // create. // new_coord_vars.push_back(coord_vars_out[i]); new_coord_axes.push_back(i); } } // Create new, unitless coordinate variables if they don't // already exist // for (int i = 0; i < new_coord_vars.size(); i++) { string name = new_coord_vars[i]; int axis = new_coord_axes[i]; vector dim_names; string time_dim_name; if (axis == 3) { time_dim_name = name; } else { dim_names.push_back(name); } map::const_iterator itr = _coordVars.find(name); if (itr != _coordVars.end()) continue; vector periodic(1, false); _coordVars[name] = CoordVar(name, "", XType::FLOAT, "", vector(), periodic, dim_names, time_dim_name, axis, false); _coordVars[name].SetUniform(true); // Keep track of any uniform variables that get defined // _newUniformVars.push_back(name); } return (0); } int VDC::DefineCoordVar(string varname, vector dim_names, string time_dim_name, string units, int axis, XType type, bool compressed) { if (!_defineMode) { SetErrMsg("Not in define mode"); return (-1); } if (_mode == A) { if (_coordVars.find(varname) != _coordVars.end()) { SetErrMsg("Variable \"%s\" already defined", varname.c_str()); return (-1); } } if (axis == 3 && units.empty()) units = "seconds"; if (!_ValidDefineCoordVar(varname, dim_names, time_dim_name, units, axis, type, compressed)) { return (-1); } vector periodic; _compute_periodic(dim_names, _periodic, periodic); vector cratios(1, 1); string wname; if (compressed) { cratios = _cratios; wname = _wname; } // _coordVars contains a table of all the coordinate variables // _coordVars[varname] = CoordVar(varname, units, type, wname, cratios, periodic, dim_names, time_dim_name, axis, false); return (0); } int VDC::DefineCoordVarUniform(string varname, vector dim_names, string time_dim_name, string units, int axis, XType type, bool compressed) { int rc = VDC::DefineCoordVar(varname, dim_names, time_dim_name, units, axis, type, compressed); if (rc < 0) return (-1); VAssert(_coordVars.find(varname) != _coordVars.end()); _coordVars[varname].SetUniform(true); // Keep track of any uniform variables that get defined // _newUniformVars.push_back(varname); return (0); } bool VDC::getCoordVarInfo(string varname, DC::CoordVar &cvar) const { map::const_iterator itr = _coordVars.find(varname); if (itr == _coordVars.end()) return (false); cvar = itr->second; return (true); } bool VDC::getBaseVarInfo(string varname, DC::BaseVar &var) const { map::const_iterator itr1 = _coordVars.find(varname); if (itr1 != _coordVars.end()) { var = itr1->second; return (true); } map::const_iterator itr2 = _dataVars.find(varname); if (itr2 != _dataVars.end()) { var = itr2->second; return (true); } return (false); } void VDC::_DefineMesh(string meshname, vector dim_names, vector coord_vars) { VAssert(dim_names.size() == coord_vars.size()); _meshes[meshname] = DC::Mesh(meshname, dim_names, coord_vars); } int VDC::_DefineDataVar(string varname, vector dim_names, vector coord_vars, string units, XType type, bool compressed, bool has_missing, double mv, string maskvar) { if (!_defineMode) { SetErrMsg("Not in define mode"); return (-1); } if (_mode == A) { if (_dataVars.find(varname) != _dataVars.end()) { SetErrMsg("Variable \"%s\" already defined", varname.c_str()); return (-1); } } int rc = _DefineImplicitCoordVars(dim_names, coord_vars, coord_vars); if (rc < 0) return (-1); if (!_ValidDefineDataVar(varname, dim_names, coord_vars, units, type, compressed, has_missing, maskvar)) { return (-1); } // // Dimensions must have previosly been defined // vector dimensions; for (int i = 0; i < dim_names.size(); i++) { Dimension dimension; VDC::getDimension(dim_names[i], dimension); VAssert(!dimension.GetName().empty()); dimensions.push_back(dimension); } // Check for a time coordinate // string time_coord_var; if (coord_vars.size() > 0) { map::const_iterator itr; itr = _coordVars.find(coord_vars[coord_vars.size() - 1]); if (itr != _coordVars.end() && itr->second.GetAxis() == 3) { time_coord_var = coord_vars[coord_vars.size() - 1]; dim_names.pop_back(); coord_vars.pop_back(); } } vector periodic; _compute_periodic(dim_names, _periodic, periodic); vector cratios(1, 1); string wname; if (compressed) { cratios = _cratios; wname = _wname; } string meshname = make_mesh_name(dim_names); _DefineMesh(meshname, dim_names, coord_vars); if (!maskvar.empty()) { _dataVars[varname] = DataVar(varname, units, type, wname, cratios, periodic, meshname, time_coord_var, DC::Mesh::NODE, mv, maskvar); } else if (has_missing) { _dataVars[varname] = DataVar(varname, units, type, wname, cratios, periodic, meshname, time_coord_var, DC::Mesh::NODE, mv); } else { _dataVars[varname] = DataVar(varname, units, type, wname, cratios, periodic, meshname, time_coord_var, DC::Mesh::NODE); } return (0); } int VDC::DefineDataVar(string varname, vector dim_names, vector coord_vars, string units, XType type, bool compressed) { return (VDC::_DefineDataVar(varname, dim_names, coord_vars, units, type, compressed, false, 0.0, "")); } int VDC::DefineDataVar(string varname, vector dim_names, vector coord_vars, string units, XType type, double mv, string maskvar ) { bool compressed = !maskvar.empty(); return (VDC::_DefineDataVar(varname, dim_names, coord_vars, units, type, compressed, true, mv, maskvar)); } bool VDC::getDataVarInfo(string varname, DC::DataVar &datavar) const { map::const_iterator itr = _dataVars.find(varname); if (itr == _dataVars.end()) return (false); datavar = itr->second; return (true); } vector VDC::getDataVarNames() const { vector names; map::const_iterator itr; for (itr = _dataVars.begin(); itr != _dataVars.end(); ++itr) { names.push_back(itr->first); } return (names); } vector VDC::getCoordVarNames() const { vector names; map::const_iterator itr; for (itr = _coordVars.begin(); itr != _coordVars.end(); ++itr) { names.push_back(itr->first); } return (names); } size_t VDC::getNumRefLevels(string varname) const { string wname; if (_coordVars.find(varname) != _coordVars.end()) { std::map::const_iterator itr = _coordVars.find(varname); ; if (!itr->second.IsCompressed()) return (1); wname = itr->second.GetWName(); } else if (_dataVars.find(varname) != _dataVars.end()) { std::map::const_iterator itr = _dataVars.find(varname); if (!itr->second.IsCompressed()) return (1); ; wname = itr->second.GetWName(); } else { // Var doesn't exist. Still return 1 return (1); } vector mdimensions; bool ok = GetVarDimensions(varname, true, mdimensions, -1); if (!ok) return (1); // Determine block size // vector bs; _compute_bs(mdimensions.size(), _bs, bs); size_t nlevels, maxcratio; CompressionInfo(bs, wname, nlevels, maxcratio); return (nlevels); } int VDC::PutAtt(string varname, string attname, XType type, const vector &values) { Attribute attr(attname, type, values); if (varname.empty()) { _atts[attname] = attr; } else if (_dataVars.find(varname) != _dataVars.end()) { map::iterator itr = _dataVars.find(varname); map atts = itr->second.GetAttributes(); atts[attname] = attr; itr->second.SetAttributes(atts); } else if (_coordVars.find(varname) != _coordVars.end()) { map::iterator itr = _coordVars.find(varname); map atts = itr->second.GetAttributes(); atts[attname] = attr; itr->second.SetAttributes(atts); } else { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (-1); } return (0); } int VDC::PutAtt(string varname, string attname, XType type, const vector &values) { Attribute attr(attname, type, values); if (varname.empty()) { _atts[attname] = attr; } else if (_dataVars.find(varname) != _dataVars.end()) { map::iterator itr = _dataVars.find(varname); map atts = itr->second.GetAttributes(); atts[attname] = attr; itr->second.SetAttributes(atts); } else if (_coordVars.find(varname) != _coordVars.end()) { map::iterator itr = _coordVars.find(varname); map atts = itr->second.GetAttributes(); atts[attname] = attr; itr->second.SetAttributes(atts); } else { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (-1); } return (0); } int VDC::PutAtt(string varname, string attname, XType type, const string &values) { Attribute attr(attname, type, values); if (varname.empty()) { _atts[attname] = attr; } else if (_dataVars.find(varname) != _dataVars.end()) { map::iterator itr = _dataVars.find(varname); map atts = itr->second.GetAttributes(); atts[attname] = attr; itr->second.SetAttributes(atts); } else if (_coordVars.find(varname) != _coordVars.end()) { map::iterator itr = _coordVars.find(varname); map atts = itr->second.GetAttributes(); atts[attname] = attr; itr->second.SetAttributes(atts); } else { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (-1); } return (0); } bool VDC::getAtt(string varname, string attname, vector &values) const { values.clear(); if (varname.empty() && (_atts.find(attname) != _atts.end())) { map::const_iterator itr = _atts.find(attname); VAssert(itr != _atts.end()); const Attribute &attr = itr->second; attr.GetValues(values); } else if (_dataVars.find(varname) != _dataVars.end()) { map::const_iterator itr = _dataVars.find(varname); map atts = itr->second.GetAttributes(); map::const_iterator itr1 = atts.find(attname); if (itr1 == atts.end()) { return (false); } const Attribute &attr = itr1->second; attr.GetValues(values); } else if (_coordVars.find(varname) != _coordVars.end()) { map::const_iterator itr = _coordVars.find(varname); map atts = itr->second.GetAttributes(); map::const_iterator itr1 = atts.find(attname); if (itr1 == atts.end()) { return (false); } const Attribute &attr = itr1->second; attr.GetValues(values); } else { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (false); } return (true); } bool VDC::getAtt(string varname, string attname, vector &values) const { values.clear(); if (varname.empty() && (_atts.find(attname) != _atts.end())) { map::const_iterator itr = _atts.find(attname); VAssert(itr != _atts.end()); const Attribute &attr = itr->second; attr.GetValues(values); } else if (_dataVars.find(varname) != _dataVars.end()) { map::const_iterator itr = _dataVars.find(varname); map atts = itr->second.GetAttributes(); map::const_iterator itr1 = atts.find(attname); if (itr1 == atts.end()) { return (false); } const Attribute &attr = itr1->second; attr.GetValues(values); } else if (_coordVars.find(varname) != _coordVars.end()) { map::const_iterator itr = _coordVars.find(varname); map atts = itr->second.GetAttributes(); map::const_iterator itr1 = atts.find(attname); if (itr1 == atts.end()) { return (false); } const Attribute &attr = itr1->second; attr.GetValues(values); } else { return (false); } return (true); } bool VDC::getAtt(string varname, string attname, string &values) const { values.clear(); if (varname.empty() && (_atts.find(attname) != _atts.end())) { map::const_iterator itr = _atts.find(attname); VAssert(itr != _atts.end()); const Attribute &attr = itr->second; attr.GetValues(values); } else if (_dataVars.find(varname) != _dataVars.end()) { map::const_iterator itr = _dataVars.find(varname); map atts = itr->second.GetAttributes(); map::const_iterator itr1 = atts.find(attname); if (itr1 == atts.end()) { return (false); } const Attribute &attr = itr1->second; attr.GetValues(values); } else if (_coordVars.find(varname) != _coordVars.end()) { map::const_iterator itr = _coordVars.find(varname); map atts = itr->second.GetAttributes(); map::const_iterator itr1 = atts.find(attname); if (itr1 == atts.end()) { return (false); } const Attribute &attr = itr1->second; attr.GetValues(values); } else { return (false); } return (true); } int VDC::CopyAtt(const DC &src, string varname, string attname) { XType type = src.GetAttType(varname, attname); if (type == XType::INT32 || type == XType::INT64) { vector values; if (!src.GetAtt(varname, attname, values)) return -1; return PutAtt(varname, attname, type, values); } else if (type == XType::FLOAT || type == XType::DOUBLE) { vector values; if (!src.GetAtt(varname, attname, values)) return -1; return PutAtt(varname, attname, type, values); } else if (type == XType::TEXT) { string values; if (!src.GetAtt(varname, attname, values)) return -1; return PutAtt(varname, attname, type, values); } else if (type == XType::INVALID) { SetErrMsg("Invalid attribute : %s.%s", varname.c_str(), attname.c_str()); return -1; } return 0; } int VDC::CopyAtt(const DC &src, string varname) { vector names = src.GetAttNames(varname); for (int i = 0; i < names.size(); i++) { int rc = CopyAtt(src, varname, names[i]); if (rc < 0) return (-1); } return (0); } vector VDC::getAttNames(string varname) const { vector attnames; std::map::const_iterator itr; if (varname.empty()) { // global attributes for (itr = _atts.begin(); itr != _atts.end(); ++itr) { attnames.push_back(itr->first); } } else if (_dataVars.find(varname) != _dataVars.end()) { map::const_iterator itr1 = _dataVars.find(varname); map atts = itr1->second.GetAttributes(); for (itr = atts.begin(); itr != atts.end(); ++itr) { attnames.push_back(itr->first); } } else if (_coordVars.find(varname) != _coordVars.end()) { map::const_iterator itr1 = _coordVars.find(varname); map atts = itr1->second.GetAttributes(); for (itr = atts.begin(); itr != atts.end(); ++itr) { attnames.push_back(itr->first); } } return (attnames); } DC::XType VDC::getAttType(string varname, string attname) const { std::map::const_iterator itr; if (varname.empty()) { // global attributes itr = _atts.find(attname); if (itr == _atts.end()) return (INVALID); return (itr->second.GetXType()); } else if (_dataVars.find(varname) != _dataVars.end()) { map::const_iterator itr1 = _dataVars.find(varname); map atts = itr1->second.GetAttributes(); itr = atts.find(attname); if (itr == _atts.end()) return (INVALID); return (itr->second.GetXType()); } else if (_coordVars.find(varname) != _coordVars.end()) { map::const_iterator itr1 = _coordVars.find(varname); map atts = itr1->second.GetAttributes(); itr = atts.find(attname); if (itr == _atts.end()) return (INVALID); return (itr->second.GetXType()); } return (INVALID); } string VDC::getMapProjection(string varname) const { // Shoot. This doens't do anything. I.e. it doesn't force data to // be reprojected // if (!_proj4StringOption.empty()) { return (_proj4StringOption); } string attname = "MapProjection"; vector attnames = VDC::getAttNames(varname); if (find(attnames.begin(), attnames.end(), attname) == attnames.end()) { // Return default map projection. // // N.B. WE SHOULD BE VERIFYING THAT THIS IS A GEOREFERENCED // VARIABLE!!! // return (VDC::getMapProjection()); } string proj4string; bool status = VDC::getAtt(varname, attname, proj4string); if (status) return (proj4string); return (""); } string VDC::getMapProjection() const { if (!_proj4StringOption.empty()) { return (_proj4StringOption); } string attname = "MapProjection"; vector attnames = VDC::getAttNames(""); if (find(attnames.begin(), attnames.end(), attname) == attnames.end()) { return (""); } string proj4string; bool status = VDC::getAtt("", attname, proj4string); if (status) return (proj4string); return (""); } int VDC::SetMapProjection(string varname, string projstring) { string attname = "MapProjection"; return (VDC::PutAtt(varname, attname, TEXT, projstring)); } int VDC::SetMapProjection(string projstring) { string attname = "MapProjection"; return (VDC::PutAtt("", attname, TEXT, projstring)); } int VDC::EndDefine() { if (!_defineMode) return (0); if (_mode == R) return (0); if (_master_path.empty()) { // Initialized() not called // SetErrMsg("Master file not specified"); return (-1); } if (_WriteMasterMeta() < 0) return (-1); _defineMode = false; // For any 1D Uniform coordinate variables that // were defined go ahead // and give them default values // for (int i = 0; i < _newUniformVars.size(); i++) { vector dimensions; bool ok = GetVarDimensions(_newUniformVars[i], false, dimensions, -1); VAssert(ok); if (dimensions.size() != 1) continue; size_t l = dimensions[0].GetLength(); float *buf = new float[l]; for (size_t j = 0; j < l; j++) buf[j] = (float)j; int rc = PutVar(_newUniformVars[i], -1, buf); if (rc < 0) { delete[] buf; return (rc); } delete[] buf; } return (0); } bool VDC::_ValidDefineDimension(string name, size_t length) const { if (length < 1) { SetErrMsg("Dimension must be of length 1 or more"); return (false); } return (true); } bool VDC::_ValidDefineCoordVar(string varname, vector sdim_names, string time_dim_name, string units, int axis, XType type, bool compressed) const { if (sdim_names.size() > 3) { SetErrMsg("Invalid number of dimensions"); return (false); } if (axis == 3 && (sdim_names.size() != 0 || time_dim_name.empty())) { SetErrMsg("Time coordinate variables must have exactly one dimension"); return (false); } // All space + time dim names // vector dim_names = sdim_names; if (!time_dim_name.empty()) dim_names.push_back(time_dim_name); for (int i = 0; i < dim_names.size(); i++) { if (_dimsMap.find(dim_names[i]) == _dimsMap.end()) { SetErrMsg("Dimension \"%s\" not defined", dim_names[i].c_str()); return (false); } } if (axis < 0 || axis > 3) { SetErrMsg("Invalid axis specification : %d", axis); return (false); } if (!units.empty() && !_udunits.ValidUnit(units)) { SetErrMsg("Unrecognized units specification : %s ", units.c_str()); return (false); } #ifdef VAPOR3_0_0_ALPHA if (compressed && type != FLOAT) { SetErrMsg("Only FLOAT data supported with compressed variables"); return (false); } #endif // // IF this is a dimension coordinate variable (a variable with // the same name as any dimension) then the dimensions, // and compression cannot be changed. // map::const_iterator itr = _dimsMap.find(varname); if (itr != _dimsMap.end()) { if (dim_names.size() != 1 || varname.compare(dim_names[0]) != 0) { SetErrMsg("Invalid dimension coordinate variable definition"); return (false); } if (compressed) { SetErrMsg("Invalid dimension coordinate variable definition"); return (false); } } return (true); } bool VDC::_ValidCompressionBlock(vector bs, string wname, vector cratios) const { for (int i = 0; i < cratios.size(); i++) { if (cratios[i] < 1) return (false); } // No compression if no blocking // if (vproduct(bs) == 1) { if (!wname.empty()) return (false); if (!(cratios.size() == 1 && cratios[0] == 1)) return (false); } size_t nlevels, maxcratio; bool status = CompressionInfo(bs, wname, nlevels, maxcratio); if (!status) return (false); if (!wname.empty()) { for (int i = 0; i < cratios.size(); i++) { if (cratios[i] > maxcratio) return (false); } } return (true); } // Verify that dims0 is a subset of dims1, and that they have same block // size // bool VDC::_valid_dims(const vector &dims0, const vector &bs0, const vector &dims1, const vector &bs1) const { VAssert(dims0.size() == bs0.size()); VAssert(dims1.size() == bs1.size()); for (int i = 0; i < dims0.size(); i++) { bool match = false; for (int j = 0; j < dims1.size(); j++) { // Different names ok as long has have same length // // if (dims0[i].GetName() == dims1[j].GetName()) if (dims0[i].GetLength() == dims1[j].GetLength()) { match = true; // Must have same blocking or no blocking // if (!(bs0[i] == bs1[j] || bs0[i] == 1 || bs1[j] == 1)) return (false); } } if (!match) return (false); } return (true); } bool VDC::_valid_mask_var(string varname, vector dimensions, vector bs, bool compressed, string maskvar) const { map::const_iterator itr = _dataVars.find(maskvar); if (itr == _dataVars.end()) { SetErrMsg("Mask var \"%s\" not defined", maskvar.c_str()); return (false); } const DataVar &mvar = itr->second; map::const_iterator mitr = _meshes.find(mvar.GetMeshName()); if (mitr == _meshes.end()) return (false); // Fastest varying data variable dimensions must match mask // variable dimensions // vector mdimensions; bool ok = GetVarDimensions(maskvar, false, mdimensions, -1); VAssert(ok); while (dimensions.size() > mdimensions.size()) dimensions.pop_back(); while (bs.size() > mdimensions.size()) bs.pop_back(); if (dimensions.size() != mdimensions.size()) { SetErrMsg("Data variable and mask variable dimensions must match"); return (false); } if (compressed) { size_t nlevels, dummy; CompressionInfo(bs, _wname, nlevels, dummy); size_t nlevels_m; CompressionInfo(bs, mvar.GetWName(), nlevels_m, dummy); if (nlevels > nlevels_m) { SetErrMsg("Data variable and mask variable depth must match"); return (false); } } return (true); } bool VDC::_ValidDefineDataVar(string varname, vector dim_names, vector coord_vars, string units, XType type, bool compressed, bool has_missing, string maskvar) const { if (compressed && has_missing && maskvar.empty()) { SetErrMsg("Mask variable required for compressed data with missing values"); return (false); } if (dim_names.size() > 4) { SetErrMsg("Invalid number of dimensions"); return (false); } if (dim_names.size() != coord_vars.size()) { SetErrMsg("Number of dimensions and coordinate vars don't match"); return (false); } vector dimensions; for (int i = 0; i < dim_names.size(); i++) { DC::Dimension dim; bool ok = VDC::GetDimension(dim_names[i], dim, -1); if (!ok) { SetErrMsg("Dimension \"%s\" not defined", dim_names[i].c_str()); return (false); } dimensions.push_back(dim); } for (int i = 0; i < coord_vars.size(); i++) { if (_coordVars.find(coord_vars[i]) == _coordVars.end()) { SetErrMsg("Coordinate var \"%s\" not defined", coord_vars[i].c_str()); return (false); } } if (!units.empty() && !_udunits.ValidUnit(units)) { SetErrMsg("Unrecognized units specification : %s", units.c_str()); return (false); } #ifdef VAPOR3_0_0_ALPHA if (compressed && type != FLOAT) { SetErrMsg("Only FLOAT data supported with compressed variables"); return (false); } #endif // // If multidimensional the dimensions and coord names must be // ordered X, Y, Z, T // if (coord_vars.size() > 1) { map::const_iterator itr; int axis = -1; for (int i = 0; i < coord_vars.size(); i++) { itr = _coordVars.find(coord_vars[i]); VAssert(itr != _coordVars.end()); // already checked for existance if (itr->second.GetAxis() <= axis) { SetErrMsg("Dimensions must be ordered X, Y, Z, T"); return (false); } axis = itr->second.GetAxis(); } } // Check for a time coordinate // if (coord_vars.size() > 0) { map::const_iterator itr; itr = _coordVars.find(coord_vars[coord_vars.size() - 1]); if (itr != _coordVars.end() && itr->second.GetAxis() == 3) { dim_names.pop_back(); dimensions.pop_back(); coord_vars.pop_back(); } } // Determine block size // vector bs; _compute_bs(dim_names.size(), _bs, bs); // Validate mask variable if one exists // if (maskvar.empty()) return (true); return (_valid_mask_var(varname, dimensions, bs, compressed, maskvar)); } namespace VAPoR { std::ostream &operator<<(std::ostream &o, const VDC &vdc) { o << "VDC" << endl; o << " MasterPath: " << vdc._master_path << endl; o << " AccessMode: " << vdc._mode << endl; o << " DefineMode: " << vdc._defineMode << endl; o << " Block Size: "; for (int i = 0; i < vdc._bs.size(); i++) { o << vdc._bs[i] << " "; } o << endl; o << " WName: " << vdc._wname << endl; o << " CRatios: "; for (int i = 0; i < vdc._cratios.size(); i++) { o << vdc._cratios[i] << " "; } o << endl; o << " Periodic: "; for (int i = 0; i < vdc._periodic.size(); i++) { o << vdc._periodic[i] << " "; } o << endl; { o << " Attributes" << endl; std::map::const_iterator itr; for (itr = vdc._atts.begin(); itr != vdc._atts.end(); ++itr) { o << itr->second; } o << endl; } { o << " Dimensions" << endl; std::map::const_iterator itr; for (itr = vdc._dimsMap.begin(); itr != vdc._dimsMap.end(); ++itr) { o << itr->second; } o << endl; } { o << " CoordVars" << endl; std::map::const_iterator itr; for (itr = vdc._coordVars.begin(); itr != vdc._coordVars.end(); ++itr) { o << itr->second; o << endl; } o << endl; } { o << " DataVars" << endl; std::map::const_iterator itr; for (itr = vdc._dataVars.begin(); itr != vdc._dataVars.end(); ++itr) { o << itr->second; o << endl; } o << endl; } return (o); } }; // namespace VAPoR ================================================ FILE: lib/vdc/VDCNetCDF.cpp ================================================ #include "vapor/VAssert.h" #include #include #include #include #include #include "vapor/VDCNetCDF.h" #include "vapor/CFuncs.h" #include "vapor/Version.h" #include "vapor/FileUtils.h" using namespace VAPoR; using namespace Wasp; namespace { // Map a level specification for a given number of levels into // clevel (coarsest level is 0 increasing values corespond to finer // levels), and flevel (finest level is -1 and decreasing values // correspond to coarser levels) // void levels(int level, int nlevels, int &clevel, int &flevel) { if (level > nlevels - 1) level = nlevels - 1; if (level < -nlevels) level = -nlevels; if (level >= 0) { clevel = level; flevel = -nlevels + level; } else { clevel = level + nlevels; flevel = level; } } int vdc_xtype2ncdf_xtype(VDC::XType v_xtype) { int n_xtype; switch (v_xtype) { case VDC::FLOAT: n_xtype = NC_FLOAT; break; case VDC::DOUBLE: n_xtype = NC_DOUBLE; break; case VDC::INT8: n_xtype = NC_BYTE; break; case VDC::INT32: n_xtype = NC_INT; break; case VDC::INT64: n_xtype = NC_INT64; break; case VDC::UINT8: n_xtype = NC_UBYTE; break; case VDC::TEXT: n_xtype = NC_CHAR; break; default: n_xtype = NC_NAT; break; } return (n_xtype); } #ifdef UNUSED_FUNCTION VDC::XType ncdf_xtype2vdc_xtype(int n_xtype) { VDC::XType v_xtype; switch (n_xtype) { case NC_FLOAT: v_xtype = VDC::FLOAT; break; case NC_DOUBLE: v_xtype = VDC::DOUBLE; break; case NC_BYTE: v_xtype = VDC::INT8; break; case NC_INT: v_xtype = VDC::INT32; break; case NC_INT64: v_xtype = VDC::INT64; break; case NC_UBYTE: v_xtype = VDC::UINT8; break; case NC_CHAR: case NC_STRING: v_xtype = VDC::TEXT; break; default: v_xtype = VDC::INVALID; break; } return (v_xtype); } #endif void vdc_2_ncdfcoords(size_t ts0, size_t ts1, bool time_varying, const vector &min, const vector &max, vector &start, vector &count) { start.clear(); count.clear(); VAssert(min.size() == max.size()); ; VAssert(max.size() <= 3); VAssert(ts1 >= ts0); if (time_varying) { start.push_back(ts0); count.push_back(ts1 - ts0 + 1); } for (int i = min.size() - 1; i >= 0; i--) { VAssert(max[i] >= min[i]); start.push_back(min[i]); count.push_back(max[i] - min[i] + 1); } } // Product of elements in a vector // size_t vproduct(vector a) { size_t ntotal = 1; for (int i = 0; i < a.size(); i++) ntotal *= a[i]; return (ntotal); } size_t gcd(size_t n1, size_t n2) { size_t tmp; while (n2 != 0) { tmp = n1; n1 = n2; n2 = tmp % n2; } return n1; } size_t lcm(size_t n1, size_t n2) { return ((n1 * n2) / gcd(n1, n2)); } bool isblocked(vector bs) { for (int i = 0; i < bs.size(); i++) { if (bs[i] != 1) return (true); } return (false); } }; // namespace VDCNetCDF::VDCNetCDF(int nthreads, size_t master_threshold, size_t variable_threshold) : VDC() { _nthreads = nthreads; _master_threshold = master_threshold; _variable_threshold = variable_threshold; _chunksizehint = 0; _master = new WASP(nthreads); _version = 1; } VDCNetCDF::~VDCNetCDF() { vector fds = _fileTable.GetEntries(); for (int i = 0; i < fds.size(); i++) { (void)closeVariable(i); } if (_master) { _master->Close(); delete _master; } } int VDCNetCDF::GetHyperSliceInfo(string varname, int level, std::vector &hslice_dims, size_t &nslice) { hslice_dims.clear(); nslice = 0; vector dims_at_level; vector bs_at_level; int rc = GetDimLensAtLevel(varname, level, dims_at_level, bs_at_level, -1); if (rc < 0) return (-1); if (dims_at_level.size() == 0) return (0); if (!isblocked(bs_at_level)) { return (DC::GetHyperSliceInfo(varname, level, hslice_dims, nslice)); } hslice_dims = dims_at_level; if (dims_at_level.size() == 1) { nslice = 1; return (0); } int dim = hslice_dims.size() - 1; // This is where we override the DC::GetHyperSliceInfo() method. // Need to preserve block alignment. // hslice_dims[dim] = bs_at_level[dim]; nslice = (dims_at_level[dim] - 1) / hslice_dims[dim] + 1; return (0); } int VDCNetCDF::Initialize(const vector &paths, const vector &options, AccessMode mode, vector bs, size_t chunksizehint) { _chunksizehint = chunksizehint; int rc = VDC::initialize(paths, options, mode, bs); if (rc < 0) return (-1); if (mode == VDC::W) { size_t chsz = _chunksizehint; rc = _master->Create(_master_path, NC_64BIT_OFFSET | NC_WRITE, 0, chsz, 1); } else if (mode == VDC::A) { rc = _master->Open(_master_path, NC_WRITE); } else { rc = _master->Open(_master_path, NC_NOWRITE); } if (rc < 0) return (-1); return (0); } string VDCNetCDF::GetDataDir(string master) { string path = master; string extension = FileUtils::Extension(path); if (!extension.empty()) path.erase(path.rfind("." + extension)); path += "_data"; return (path); } // // Figure out where variable lives. This algorithm will most likely // change. // int VDCNetCDF::GetPath(string varname, size_t ts, string &path, size_t &file_ts, size_t &max_ts) const { path.clear(); file_ts = 0; max_ts = 0; bool time_varying = IsTimeVarying(varname); if (!time_varying) { ts = 0; // Could be anything if data aren't time varying; } VDC::BaseVar var; if (!VDC::GetBaseVarInfo(varname, var)) { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (false); } vector dimensions; bool ok = GetVarDimensions(varname, false, dimensions, -1); if (!ok) { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (false); } // Does this variable live in the master file? // if (_var_in_master(var)) { path = _master_path; file_ts = ts; return (0); } path = VDCNetCDF::GetDataDir(_master_path); path += "/"; if (VDC::IsDataVar(varname)) { path += "data"; path += "/"; } else { path += "coordinates"; path += "/"; } path += varname; path += "/"; path += varname; if (time_varying) { size_t ngridpoints = 1; for (int i = 0; i < dimensions.size() - 1; i++) { ngridpoints *= dimensions[i].GetLength(); } int idx; ostringstream oss; size_t numts = dimensions[dimensions.size() - 1].GetLength(); VAssert(numts > 0); max_ts = _variable_threshold / ngridpoints; if (max_ts > numts) max_ts = numts; if (max_ts == 0) { idx = ts; file_ts = 0; max_ts = 1; } else { idx = ts / max_ts; ; file_ts = ts % max_ts; } int width = (int)log10((double)numts - 1) + 1; if (width < 4) width = 4; oss.width(width); oss.fill('0'); oss << idx; path += "."; path += oss.str(); } path += "."; path += "nc"; return (0); } int VDCNetCDF::getDimLensAtLevel(string varname, int level, vector &dims_at_level, vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); int nlevels = VDC::GetNumRefLevels(varname); int clevel, dummy; levels(level, nlevels, clevel, dummy); vector dimlens; bool ok = GetVarDimLens(varname, true, dimlens, -1); if (!ok) { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (-1); } DC::BaseVar varinfo; ok = GetBaseVarInfo(varname, varinfo); if (!ok) { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (-1); } vector bs = _bs; while (bs.size() > dimlens.size()) { bs.pop_back(); } VAssert(bs.size() == dimlens.size()); if (varinfo.IsCompressed()) { string wname = varinfo.GetWName(); reverse(bs.begin(), bs.end()); reverse(dimlens.begin(), dimlens.end()); WASP::InqDimsAtLevel(wname, clevel, dimlens, bs, dims_at_level, bs_at_level); reverse(bs_at_level.begin(), bs_at_level.end()); reverse(dims_at_level.begin(), dims_at_level.end()); } else { bs_at_level = bs; dims_at_level = dimlens; } return (0); } bool VDCNetCDF::DataDirExists(string master) { string path = VDCNetCDF::GetDataDir(master); struct stat statbuf; if (stat(path.c_str(), &statbuf) < 0) return (false); return (true); } WASP *VDCNetCDF::_OpenVariableRead(size_t ts, string varname, int clevel, int lod, size_t &file_ts) { file_ts = 0; DC::BaseVar var; if (!VDC::GetBaseVarInfo(varname, var)) { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (NULL); } string path; size_t max_ts; int rc = GetPath(varname, ts, path, file_ts, max_ts); if (rc < 0) return (NULL); int ncratios = var.GetCRatios().size(); if (lod > ncratios - 1) lod = ncratios - 1; if (lod < 0) lod = lod + ncratios; if (lod < 0) lod = 0; WASP *wasp = NULL; if (path.compare(_master_path) == 0) { wasp = _master; } else { wasp = new WASP(_nthreads); rc = wasp->Open(path, NC_NOWRITE); if (rc < 0) return (NULL); } rc = wasp->OpenVarRead(varname, clevel, lod); if (rc < 0) return (NULL); return (wasp); } string VDCNetCDF::_get_mask_varname(string varname, double &mv) const { VDC::DataVar dvar; mv = 0.0; string mask_varname; if (VDC::getDataVarInfo(varname, dvar)) { mask_varname = dvar.GetMaskvar(); if (!mask_varname.empty()) { mv = dvar.GetMissingValue(); } } return (mask_varname); } int VDCNetCDF::openVariableRead(size_t ts, string varname, int level, int lod) { int nlevels = VDC::GetNumRefLevels(varname); int clevel, flevel; levels(level, nlevels, clevel, flevel); size_t file_ts; WASP * wasp = _OpenVariableRead(ts, varname, clevel, lod, file_ts); if (!wasp) return (-1); double mv; string maskvar = _get_mask_varname(varname, mv); // // If there is a mask variable we need to open it. // WASP * wasp_mask = NULL; int clevel_mask = -1; size_t file_ts_mask = 0; if (!maskvar.empty()) { // // the level specification can be tricky because the data variable // and the mask variable can have different numbers of levels (if // different wavelets are used). Convert the flevel - which indexes // from finest to coarsest and hence will be the same for both // variables - to a clevel, which is required by WASP API // nlevels = VDC::GetNumRefLevels(maskvar); levels(flevel, nlevels, clevel_mask, flevel); wasp_mask = _OpenVariableRead(ts, maskvar, clevel_mask, lod, file_ts_mask); if (!wasp_mask) return (-1); } VDCFileObject *o = new VDCFileObject(ts, varname, clevel, lod, file_ts, wasp, wasp_mask, maskvar, clevel_mask, file_ts_mask, mv); return (_fileTable.AddEntry(o)); } int VDCNetCDF::OpenVariableWrite(size_t ts, string varname, int lod) { VDC::BaseVar *varptr; VDC::DataVar dvar; VDC::CoordVar cvar; bool isdvar; if (VDC::getDataVarInfo(varname, dvar)) { varptr = &dvar; isdvar = true; } else if (VDC::getCoordVarInfo(varname, cvar)) { varptr = &cvar; isdvar = false; } else { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (false); } string path; size_t file_ts; size_t max_ts; int rc = GetPath(varname, ts, path, file_ts, max_ts); if (rc < 0) return (-1); WASP *wasp = NULL; if (path.compare(_master_path) == 0) { wasp = _master; } else if (_master->ValidFile(path)) { wasp = new WASP(_nthreads); rc = wasp->Open(path, NC_WRITE); } else { wasp = new WASP(_nthreads); string dir; dir = FileUtils::Dirname(path); rc = MkDirHier(dir); if (rc < 0) return (-1); size_t chsz = _chunksizehint; rc = wasp->Create(path, NC_WRITE | NC_64BIT_OFFSET, 0, chsz, varptr->GetCRatios().size()); if (rc < 0) return (-1); // Make a copy of attributes contained in master file // rc = _WriteAttributes(wasp, "", _atts); if (rc < 0) return (-1); if (isdvar) { rc = _DefDataVar(wasp, dvar, max_ts); } else { rc = _DefCoordVar(wasp, cvar, max_ts); } if (rc < 0) return (-1); rc = wasp->EndDef(); if (rc < 0) return (-1); } rc = wasp->OpenVarWrite(varname, lod); if (rc < 0) return (-1); int nlevels = VDC::GetNumRefLevels(varname); // // If there is a mask variable we need to open it for **reading** // double mv; string maskvar = _get_mask_varname(varname, mv); WASP * wasp_mask = NULL; size_t file_ts_mask = 0; if (!maskvar.empty()) { nlevels = VDC::GetNumRefLevels(maskvar); wasp_mask = _OpenVariableRead(ts, maskvar, nlevels - 1, lod, file_ts_mask); if (!wasp_mask) return (-1); } VDCFileObject *o = new VDCFileObject(ts, varname, nlevels - 1, lod, file_ts, wasp, wasp_mask, maskvar, nlevels - 1, file_ts_mask, mv); return (_fileTable.AddEntry(o)); } int VDCNetCDF::closeVariable(int fd) { VDCFileObject *o = (VDCFileObject *)_fileTable.GetEntry(fd); if (!o) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } WASP *wasp = o->GetWaspData(); if (wasp) { wasp->CloseVar(); } if (wasp && wasp != _master) { wasp->Close(); delete wasp; } WASP *wasp_mask = o->GetWaspMask(); if (wasp_mask) { wasp_mask->CloseVar(); } if (wasp_mask && wasp_mask != _master) { wasp_mask->Close(); delete wasp_mask; } _fileTable.RemoveEntry(fd); delete o; return (0); } unsigned char *VDCNetCDF::_read_mask_var(WASP *wasp, string varname, string varname_mask, vector start, vector count) { // data variable may be time varying, while mask variable is not. // If so remove the time dimension from start and count // if (VDC::IsTimeVarying(varname) && !VDC::IsTimeVarying(varname_mask)) { start.erase(start.begin()); count.erase(count.begin()); } size_t size = vproduct(count) * sizeof(unsigned char); unsigned char *mask = (unsigned char *)_mask_buffer.Alloc(size); int rc = wasp->GetVara(start, count, mask); if (rc < 0) return (NULL); return (mask); } template int VDCNetCDF::_writeTemplate(int fd, const T *data) { VDCFileObject *o = (VDCFileObject *)_fileTable.GetEntry(fd); if (!o) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } WASP * wasp = o->GetWaspData(); string varname = o->GetVarname(); int level = o->GetLevel(); vector dims, dummy; int rc = GetDimLensAtLevel(varname, level, dims, dummy, -1); if (rc < 0) return (rc); bool time_varying = VDC::IsTimeVarying(varname); vector start; vector count; vector mins(dims.size(), 0); vector maxs = dims; for (int i = 0; i < maxs.size(); i++) maxs[i] -= 1; size_t file_ts = o->GetFileTS(); vdc_2_ncdfcoords(file_ts, file_ts, time_varying, mins, maxs, start, count); double mv; string maskvar = _get_mask_varname(varname, mv); if (maskvar.empty()) { return (wasp->PutVara(start, count, data)); } unsigned char *mask = _read_mask_var(o->GetWaspMask(), varname, maskvar, start, count); if (!mask) return (-1); return (wasp->PutVara(start, count, data, mask)); } template int VDCNetCDF::_writeSliceTemplate(int fd, const T *slice) { VDCFileObject *o = (VDCFileObject *)_fileTable.GetEntry(fd); if (!o) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } WASP * wasp = o->GetWaspData(); string varname = o->GetVarname(); int level = o->GetLevel(); vector dims_at_level; vector dummy; int rc = GetDimLensAtLevel(varname, level, dims_at_level, dummy, -1); if (rc < 0) return (rc); vector hslice_dims; size_t nslice; rc = GetHyperSliceInfo(varname, level, hslice_dims, nslice); if (rc < 0) return (rc); VAssert(hslice_dims.size() == dims_at_level.size()); int slice_num = o->GetSlice(); if (slice_num >= nslice) return (0); // Done writing; vector min; vector max; int dim = 0; for (; dim < hslice_dims.size() - 1; dim++) { min.push_back(0); max.push_back(hslice_dims[dim] - 1); }; min.push_back(slice_num * hslice_dims[dim]); max.push_back(min[dim] + hslice_dims[dim] - 1); // Last slice is a partial read if not block-aligned // if (max[dim] >= dims_at_level[dim]) { max[dim] = dims_at_level[dim] - 1; } // // Map from VDC to NetCDF coordinates // vector start; vector count; size_t file_ts = o->GetFileTS(); vdc_2_ncdfcoords(file_ts, file_ts, IsTimeVarying(varname), min, max, start, count); double mv; string maskvar = _get_mask_varname(varname, mv); if (maskvar.empty()) { rc = wasp->PutVara(start, count, slice); } else { unsigned char *mask = _read_mask_var(o->GetWaspMask(), varname, maskvar, start, count); if (!mask) return (-1); rc = wasp->PutVara(start, count, slice, mask); } if (rc < 0) return (rc); slice_num++; o->SetSlice(slice_num); return (0); } template int VDCNetCDF::_writeSliceTemplate(int fd, const float *slice); template int VDCNetCDF::_readRegionTemplate(int fd, const vector &min, const vector &max, T *region) { VDCFileObject *o = (VDCFileObject *)_fileTable.GetEntry(fd); if (!o) { SetErrMsg("Invalid file descriptor : %d", fd); return (-1); } WASP * wasp = o->GetWaspData(); string varname = o->GetVarname(); size_t file_ts = o->GetFileTS(); WASP * wasp_mask = o->GetWaspMask(); bool time_varying = VDC::IsTimeVarying(varname); vector start; vector count; vdc_2_ncdfcoords(file_ts, file_ts, time_varying, min, max, start, count); int rc = wasp->GetVara(start, count, region); if (rc < 0) return (rc); // if no mask we're done // if (!wasp_mask) return (0); size_t file_ts_mask = o->GetFileTSMask(); double mv = o->GetMissingValue(); // If there is a mask associated with this variable we need to // restore the missing value // string mask_varname = o->GetVarnameMask(); time_varying = VDC::IsTimeVarying(mask_varname); vdc_2_ncdfcoords(file_ts_mask, file_ts_mask, time_varying, min, max, start, count); size_t size = vproduct(count); unsigned char *mask = (unsigned char *)_mask_buffer.Alloc(size); rc = wasp_mask->GetVara(start, count, mask); if (rc < 0) return (rc); for (size_t i = 0; i < size; i++) { if (!mask[i]) { region[i] = mv; } } return (0); } int VDCNetCDF::readRegion(int fd, const vector &min, const vector &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); } int VDCNetCDF::readRegion(int fd, const vector &min, const vector &max, double *region) { return (_readRegionTemplate(fd, min, max, region)); } int VDCNetCDF::readRegion(int fd, const vector &min, const vector &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); } template int VDCNetCDF::_putVarTemplate(string varname, int lod, const T *data) { vector dims_at_level; vector dummy; int rc = VDCNetCDF::GetDimLensAtLevel(varname, -1, dims_at_level, dummy, -1); if (rc < 0) return (-1); // If not a 1D time-varying variable. // if (!(VDC::IsTimeVarying(varname) && dims_at_level.size() == 1)) { // Number of per time step // size_t var_size = 1; for (int i = 0; i < dims_at_level.size(); i++) var_size *= dims_at_level[i]; int numts = VDC::GetNumTimeSteps(varname); const T *ptr = data; for (size_t ts = 0; ts < numts; ts++) { rc = VDCNetCDF::PutVar(ts, varname, lod, ptr); if (rc < 0) return (-1); ptr += var_size; } return (0); } // Write 1D time-varying variables directly with // NetCDFCpp class. // VDC::BaseVar var; if (!VDC::GetBaseVarInfo(varname, var)) { SetErrMsg("Undefined variable name : %s", varname.c_str()); return (false); } // Don't currently handle case where a variable is split across // multiple files. // if (!_var_in_master(var)) { SetErrMsg("Distributed variable reads not supported"); return (-1); } // N.B. calling NetCDFCpp::PutVar // rc = ((NetCDFCpp *)_master)->PutVar(varname, data); if (rc < 0) return (-1); return (0); } template int VDCNetCDF::_putVarTemplate(string varname, int lod, const float *data); template int VDCNetCDF::_putVarTemplate(string varname, int lod, const int *data); template int VDCNetCDF::_putVarTemplate(size_t ts, string varname, int lod, const T *data) { int fd = VDCNetCDF::OpenVariableWrite(ts, varname, lod); if (fd < 0) return (-1); int rc = VDCNetCDF::Write(fd, data); if (rc < 0) return (-1); rc = closeVariable(fd); if (rc < 0) return (-1); return (0); } template int VDCNetCDF::_putVarTemplate(size_t ts, string varname, int lod, const float *data); template int VDCNetCDF::_putVarTemplate(size_t ts, string varname, int lod, const int *data); int VDCNetCDF::_copyVar0d(DC &dc, size_t ts, const BaseVar &varInfo) { if (varInfo.GetXType() == FLOAT || varInfo.GetXType() == DOUBLE) { float buf; int rc = dc.GetVar(ts, varInfo.GetName(), -1, -1, &buf); if (rc < 0) return (rc); rc = PutVar(ts, varInfo.GetName(), -1, &buf); if (rc < 0) return (rc); } else { int buf; int rc = dc.GetVar(ts, varInfo.GetName(), -1, -1, &buf); if (rc < 0) return (rc); rc = PutVar(ts, varInfo.GetName(), -1, &buf); if (rc < 0) return (rc); } return (0); } template int VDCNetCDF::_copyVarHelper(DC &dc, int fdr, int fdw, vector &buffer_dims, vector &src_hslice_dims, vector &dst_hslice_dims, size_t src_nslice, size_t dst_nslice, T *buffer) { VAssert(buffer_dims.size() == src_hslice_dims.size()); VAssert(buffer_dims.size() == dst_hslice_dims.size()); size_t dim = buffer_dims.size() - 1; size_t src_slice_count = 0; size_t dst_slice_count = 0; while (src_slice_count < src_nslice) { T * bufptr = buffer; int n = buffer_dims[dim] / src_hslice_dims[dim]; for (int i = 0; i < n && src_slice_count < src_nslice; i++) { int rc = dc.ReadSlice(fdr, bufptr); if (rc < 0) return (-1); bufptr += vproduct(src_hslice_dims); src_slice_count++; } bufptr = buffer; n = buffer_dims[dim] / dst_hslice_dims[dim]; for (int i = 0; i < n && dst_slice_count < dst_nslice; i++) { int rc = WriteSlice(fdw, bufptr); if (rc < 0) return (-1); bufptr += vproduct(dst_hslice_dims); dst_slice_count++; } } return (0); } int VDCNetCDF::CopyVar(DC &dc, size_t ts, string varname, int srclod, int dstlod) { BaseVar varInfo; bool status = dc.GetBaseVarInfo(varname, varInfo); if (!status) { SetErrMsg("Invalid source variable name : %s", varname.c_str()); return (-1); } // Get the dimensions of a hyper slice for the source and destination // varible // vector src_hslice_dims; size_t src_nslice; int rc = dc.GetHyperSliceInfo(varname, -1, src_hslice_dims, src_nslice); if (rc < 0) return (rc); vector dst_hslice_dims; size_t dst_nslice; rc = GetHyperSliceInfo(varname, -1, dst_hslice_dims, dst_nslice); if (rc < 0) return (rc); if (src_hslice_dims.size() != dst_hslice_dims.size()) { SetErrMsg("Incompatible source and destination variable definitions"); return (-1); } if (src_hslice_dims.size() == 0) { return (_copyVar0d(dc, ts, varInfo)); } // n-1 fastest varying dimensions must be the same for both hyper-slices. // Slowest dimension may be different. // int dim = src_hslice_dims.size() - 1; size_t src_dimlen = src_hslice_dims[dim]; size_t dst_dimlen = dst_hslice_dims[dim]; for (int i = 0; i < src_hslice_dims.size() - 1; i++) { if (src_hslice_dims[i] != dst_hslice_dims[i]) { SetErrMsg("Incompatible source and destination variable definitions"); return (-1); } } // Find the slice dimension for slowest varying dimension, the Least // Common Multiple for the source and destination // size_t slice_dim = lcm(src_dimlen, dst_dimlen); // Common (fastest-varying) dimensions for both variables, plus // the lcm of the slowest varying dimension for the source // and destination. // vector buffer_dims = src_hslice_dims; buffer_dims.pop_back(); // Remove slowest varying dimension buffer_dims.push_back(slice_dim); int fdr = dc.OpenVariableRead(ts, varname, srclod); if (fdr < 0) return (fdr); int fdw = OpenVariableWrite(ts, varname, dstlod); if (fdw < 0) { dc.CloseVariable(fdr); return (fdw); } if (varInfo.GetXType() == FLOAT || varInfo.GetXType() == DOUBLE) { size_t bufsize = vproduct(buffer_dims); float *buffer = new float[bufsize]; rc = _copyVarHelper(dc, fdr, fdw, buffer_dims, src_hslice_dims, dst_hslice_dims, src_nslice, dst_nslice, buffer); delete[] buffer; } else { size_t bufsize = vproduct(buffer_dims); int * buffer = new int[bufsize]; rc = _copyVarHelper(dc, fdr, fdw, buffer_dims, src_hslice_dims, dst_hslice_dims, src_nslice, dst_nslice, buffer); delete[] buffer; } dc.CloseVariable(fdr); closeVariable(fdw); return (rc); } int VDCNetCDF::CopyVar(DC &dc, string varname, int srclod, int dstlod) { size_t numTS = dc.GetNumTimeSteps(varname); for (size_t ts = 0; ts < numTS; ts++) { int rc = CopyVar(dc, ts, varname, srclod, dstlod); if (rc < 0) return (rc); } return (0); } bool VDCNetCDF::CompressionInfo(std::vector bs, string wname, size_t &nlevels, size_t &maxcratio) const { nlevels = 1; maxcratio = 1; if (wname.empty()) return (true); std::reverse(bs.begin(), bs.end()); // NetCDF order return (WASP::InqCompressionInfo(bs, wname, nlevels, maxcratio)); } bool VDCNetCDF::variableExists(size_t ts, string varname, int level, int lod) const { VDC::BaseVar var; if (!VDC::GetBaseVarInfo(varname, var)) return (false); string path; size_t file_ts; size_t max_ts; int rc = GetPath(varname, ts, path, file_ts, max_ts); if (rc < 0) return (-1); vector paths; if (!var.IsCompressed()) { paths.push_back(path); } else { int numfiles = var.GetCRatios().size(); paths = WASP::GetPaths(path, numfiles); } int ncratios = var.GetCRatios().size(); if (lod > ncratios - 1) lod = ncratios - 1; if (lod < 0) lod = lod + ncratios; if (lod < 0) lod = 0; for (int i = 0; i <= lod; i++) { struct stat statbuf; if (stat(paths[i].c_str(), &statbuf) < 0) return (false); } return (true); } int VDCNetCDF::SetFill(int fillmode) { int last; int ret = ((NetCDFCpp *)_master)->SetFill(fillmode, last); return ret; } int VDCNetCDF::_WriteMasterMeta() { int rc; map::const_iterator itr; for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { const Dimension &dimension = itr->second; rc = _master->DefDim(dimension.GetName(), dimension.GetLength()); if (rc < 0) return (-1); } rc = _master->PutAtt("", "VDC.Version", Version::GetVersionString()); if (rc < 0) return (rc); rc = _master->PutAtt("", "VDC.BlockSize", _bs); if (rc < 0) return (rc); rc = _master->PutAtt("", "VDC.WaveName", _wname); if (rc < 0) return (rc); rc = _master->PutAtt("", "VDC.CompressionRatios", _cratios); if (rc < 0) return (rc); rc = _master->PutAtt("", "VDC.MasterThreshold", _master_threshold); if (rc < 0) return (rc); rc = _master->PutAtt("", "VDC.VariableThreshold", _variable_threshold); if (rc < 0) return (rc); vector periodic; for (int i = 0; i < _periodic.size(); i++) { periodic.push_back((int)_periodic[i]); } rc = _master->PutAtt("", "VDC.Periodic", periodic); if (rc < 0) return (rc); rc = _WriteMasterDimensions(); if (rc < 0) return (rc); rc = _WriteMasterAttributes(); if (rc < 0) return (rc); rc = _WriteMasterMeshDefs(); if (rc < 0) return (rc); rc = _WriteMasterCoordVarsDefs(); if (rc < 0) return (rc); rc = _WriteMasterDataVarsDefs(); if (rc < 0) return (rc); rc = _master->EndDef(); if (rc < 0) return (rc); return (0); } int VDCNetCDF::_ReadMasterMeta() { int rc = _master->Open(_master_path, 0); if (rc < 0) return (-1); rc = _master->GetAtt("", "VDC.Version", _version); if (rc < 0) { SetErrMsg("VDC versions prior to 3.0.0 not supported"); return (rc); } if (Version::Compare(_version, "3.0.0") < 0) { SetErrMsg("VDC versions prior to 3.0.0 not supported"); return (-1); } rc = _master->GetAtt("", "VDC.BlockSize", _bs); if (rc < 0) return (rc); rc = _master->GetAtt("", "VDC.WaveName", _wname); if (rc < 0) return (rc); rc = _master->GetAtt("", "VDC.CompressionRatios", _cratios); if (rc < 0) return (rc); sort(_cratios.begin(), _cratios.end()); reverse(_cratios.begin(), _cratios.end()); rc = _master->GetAtt("", "VDC.MasterThreshold", _master_threshold); if (rc < 0) return (rc); rc = _master->GetAtt("", "VDC.VariableThreshold", _variable_threshold); if (rc < 0) return (rc); vector periodic; rc = _master->GetAtt("", "VDC.Periodic", periodic); _periodic.clear(); for (int i = 0; i < periodic.size(); i++) { _periodic.push_back((bool)periodic[i]); } if (rc < 0) return (rc); rc = _ReadMasterDimensions(); if (rc < 0) return (rc); rc = _ReadMasterAttributes(); if (rc < 0) return (rc); rc = _ReadMasterMeshDefs(); if (rc < 0) return (rc); rc = _ReadMasterCoordVarsDefs(); if (rc < 0) return (rc); rc = _ReadMasterDataVarsDefs(); if (rc < 0) return (rc); return (0); } int VDCNetCDF::_ReadMasterDimensions() { _dimsMap.clear(); string tag = "VDC.DimensionNames"; vector dimnames; int rc = _master->GetAtt("", tag, dimnames); if (rc < 0) return (rc); for (int i = 0; i < dimnames.size(); i++) { tag = "VDC.Dimension." + dimnames[i] + ".Length"; int length; rc = _master->GetAtt("", tag, length); if (rc < 0) return (rc); _dimsMap[dimnames[i]] = VDC::Dimension(dimnames[i], (size_t)length); } return (0); } int VDCNetCDF::_ReadMasterAttributes(string prefix, map &atts) { atts.clear(); string tag = prefix + ".AttributeNames"; vector attnames; int rc = _master->GetAtt("", tag, attnames); if (rc < 0) return (rc); for (int i = 0; i < attnames.size(); i++) { tag = prefix + ".Attribute." + attnames[i] + ".XType"; int typetmp = -1; rc = _master->GetAtt("", tag, typetmp); VDC::XType xtype; if (rc < 0) return (rc); else xtype = (VAPoR::DC::XType)typetmp; tag = prefix + ".Attribute." + attnames[i] + ".Values"; switch (xtype) { case FLOAT: case DOUBLE: { vector values; rc = _master->GetAtt("", tag, values); if (rc < 0) return (rc); VDC::Attribute attr(attnames[i], xtype, values); atts[attnames[i]] = attr; break; } case UINT8: case INT8: case INT32: case INT64: { vector values; rc = _master->GetAtt("", tag, values); if (rc < 0) return (rc); VDC::Attribute attr(attnames[i], xtype, values); atts[attnames[i]] = attr; break; } case TEXT: { string values; rc = _master->GetAtt("", tag, values); if (rc < 0) return (rc); VDC::Attribute attr(attnames[i], xtype, values); atts[attnames[i]] = attr; break; } default: SetErrMsg("Invalid attribute xtype : %d", xtype); return (-1); break; } } return (0); } int VDCNetCDF::_ReadMasterAttributes() { string prefix = "VDC"; return (_ReadMasterAttributes(prefix, _atts)); } int VDCNetCDF::_ReadMasterMeshDefs() { string tag = "VDC.MeshNames"; vector mesh_names; int rc = _master->GetAtt("", tag, mesh_names); if (rc < 0) return (rc); // Only support STRUCTURED meshes currently // string prefix = "VDC.Mesh"; for (int i = 0; i < mesh_names.size(); i++) { tag = prefix + "." + mesh_names[i] + ".DimensionNames"; vector dim_names; int rc = _master->GetAtt("", tag, dim_names); if (rc < 0) return (rc); tag = prefix + "." + mesh_names[i] + ".CoordVars"; vector coord_vars; rc = _master->GetAtt("", tag, coord_vars); if (rc < 0) return (rc); _meshes[mesh_names[i]] = Mesh(mesh_names[i], dim_names, coord_vars); } return (0); } int VDCNetCDF::_ReadMasterBaseVarDefs(string prefix, BaseVar &var) { string tag; tag = prefix + "." + var.GetName() + ".Units"; string units; int rc = _master->GetAtt("", tag, units); if (rc < 0) return (rc); var.SetUnits(units); tag = prefix + "." + var.GetName() + ".XType"; int xtype; rc = _master->GetAtt("", tag, xtype); if (rc < 0) return (rc); var.SetXType((VAPoR::VDC::XType)xtype); tag = prefix + "." + var.GetName() + ".Periodic"; vector iperiodic; rc = _master->GetAtt("", tag, iperiodic); vector periodic; for (int i = 0; i < iperiodic.size(); i++) periodic.push_back(iperiodic[i]); if (rc < 0) return (rc); var.SetPeriodic(periodic); tag = prefix + "." + var.GetName() + ".WaveName"; string wname; rc = _master->GetAtt("", tag, wname); if (rc < 0) return (rc); var.SetWName(wname); tag = prefix + "." + var.GetName() + ".CompressionRatios"; vector cratios; rc = _master->GetAtt("", tag, cratios); if (rc < 0) return (rc); var.SetCRatios(cratios); prefix += "." + var.GetName(); map atts; rc = _ReadMasterAttributes(prefix, atts); if (rc < 0) return (rc); var.SetAttributes(atts); return (0); } int VDCNetCDF::_ReadMasterCoordVarsDefs() { _coordVars.clear(); string tag = "VDC.CoordVarNames"; vector varnames; int rc = _master->GetAtt("", tag, varnames); if (rc < 0) return (rc); string prefix = "VDC.CoordVar"; for (int i = 0; i < varnames.size(); i++) { CoordVar cvar; cvar.SetName(varnames[i]); tag = prefix + "." + cvar.GetName() + ".DimensionNames"; vector dim_names; int rc = _master->GetAtt("", tag, dim_names); if (rc < 0) return (rc); cvar.SetDimNames(dim_names); tag = prefix + "." + cvar.GetName() + ".TimeDimName"; string time_dim_name; rc = _master->GetAtt("", tag, time_dim_name); if (rc < 0) return (rc); cvar.SetTimeDimName(time_dim_name); tag = prefix + "." + cvar.GetName() + ".Axis"; int axis; rc = _master->GetAtt("", tag, axis); if (rc < 0) return (rc); cvar.SetAxis(axis); tag = prefix + "." + cvar.GetName() + ".UniformHint"; int uniform; rc = _master->GetAtt("", tag, uniform); if (rc < 0) return (rc); cvar.SetUniform(uniform); rc = _ReadMasterBaseVarDefs(prefix, cvar); if (rc < 0) return (rc); _coordVars[varnames[i]] = cvar; } return (0); } int VDCNetCDF::_ReadMasterDataVarsDefs() { string tag = "VDC.DataVarNames"; vector varnames; int rc = _master->GetAtt("", tag, varnames); if (rc < 0) return (rc); string prefix = "VDC.DataVar"; for (int i = 0; i < varnames.size(); i++) { DataVar var; var.SetName(varnames[i]); tag = prefix + "." + var.GetName() + ".Mesh"; string mesh_name; rc = _master->GetAtt("", tag, mesh_name); if (rc < 0) return (rc); var.SetMeshName(mesh_name); tag = prefix + "." + var.GetName() + ".TimeCoordVar"; string time_coord_var; int rc = _master->GetAtt("", tag, time_coord_var); if (rc < 0) return (rc); var.SetTimeCoordVar(time_coord_var); tag = prefix + "." + var.GetName() + ".MaskVar"; string maskvar; rc = _master->GetAtt("", tag, maskvar); if (rc < 0) return (rc); var.SetMaskvar(maskvar); tag = prefix + "." + var.GetName() + ".MissingValue"; if (_master->InqAttDefined("", tag)) { double mv; rc = _master->GetAtt("", tag, mv); if (rc < 0) return (rc); var.SetHasMissing(true); var.SetMissingValue(mv); } rc = _ReadMasterBaseVarDefs(prefix, var); if (rc < 0) return (rc); _dataVars[varnames[i]] = var; } return (0); } int VDCNetCDF::_WriteMasterDimensions() { map::const_iterator itr; string s; for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { s += itr->first; s += " "; } string tag = "VDC.DimensionNames"; int rc = _master->PutAtt("", tag, s); if (rc < 0) return (rc); for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { const Dimension &dimension = itr->second; tag = "VDC.Dimension." + dimension.GetName() + ".Length"; rc = _master->PutAtt("", tag, dimension.GetLength()); if (rc < 0) return (rc); } return (0); } int VDCNetCDF::_WriteMasterAttributes(string prefix, const map &atts) { map::const_iterator itr; string s; for (itr = atts.begin(); itr != atts.end(); ++itr) { s += itr->first; s += " "; } string tag = prefix + ".AttributeNames"; int rc = _master->PutAtt("", tag, s); if (rc < 0) return (rc); for (itr = atts.begin(); itr != atts.end(); ++itr) { const Attribute &attr = itr->second; tag = prefix + ".Attribute." + attr.GetName() + ".XType"; rc = _master->PutAtt("", tag, attr.GetXType()); if (rc < 0) return (rc); tag = prefix + ".Attribute." + attr.GetName() + ".Values"; rc = _PutAtt(_master, "", tag, attr); if (rc < 0) return (rc); } return (0); } int VDCNetCDF::_WriteMasterAttributes() { string prefix = "VDC"; return (_WriteMasterAttributes(prefix, _atts)); } int VDCNetCDF::_WriteMasterBaseVarDefs(string prefix, const BaseVar &var) { string tag; tag = prefix + "." + var.GetName() + ".Units"; int rc = _master->PutAtt("", tag, var.GetUnits()); if (rc < 0) return (rc); tag = prefix + "." + var.GetName() + ".XType"; rc = _master->PutAtt("", tag, (int)var.GetXType()); if (rc < 0) return (rc); tag = prefix + "." + var.GetName() + ".Periodic"; vector periodic = var.GetPeriodic(); vector iperiodic; for (int i = 0; i < periodic.size(); i++) iperiodic.push_back(periodic[i]); rc = _master->PutAtt("", tag, iperiodic); if (rc < 0) return (rc); tag = prefix + "." + var.GetName() + ".WaveName"; rc = _master->PutAtt("", tag, var.GetWName()); if (rc < 0) return (rc); tag = prefix + "." + var.GetName() + ".CompressionRatios"; rc = _master->PutAtt("", tag, var.GetCRatios()); if (rc < 0) return (rc); prefix += "." + var.GetName(); return (_WriteMasterAttributes(prefix, var.GetAttributes())); } int VDCNetCDF::_WriteMasterMeshDefs() { map::const_iterator itr; string s; for (itr = _meshes.begin(); itr != _meshes.end(); ++itr) { s += itr->first; s += " "; } string tag = "VDC.MeshNames"; int rc = _master->PutAtt("", tag, s); if (rc < 0) return (rc); string prefix = "VDC.Mesh"; for (itr = _meshes.begin(); itr != _meshes.end(); ++itr) { const Mesh &m = itr->second; tag = prefix + "." + m.GetName() + ".DimensionNames"; vector dim_names = m.GetDimNames(); string s; for (int i = 0; i < dim_names.size(); i++) { s += dim_names[i]; s += " "; } int rc = _master->PutAtt("", tag, s); if (rc < 0) return (rc); tag = prefix + "." + m.GetName() + ".CoordVars"; vector coord_vars = m.GetCoordVars(); s.clear(); for (int i = 0; i < coord_vars.size(); i++) { s += coord_vars[i]; s += " "; } rc = _master->PutAtt("", tag, s); if (rc < 0) return (rc); } return (0); } int VDCNetCDF::_WriteMasterCoordVarsDefs() { map::const_iterator itr; string s; for (itr = _coordVars.begin(); itr != _coordVars.end(); ++itr) { s += itr->first; s += " "; } string tag = "VDC.CoordVarNames"; int rc = _master->PutAtt("", tag, s); if (rc < 0) return (rc); string prefix = "VDC.CoordVar"; for (itr = _coordVars.begin(); itr != _coordVars.end(); ++itr) { const CoordVar &cvar = itr->second; int rc; if (_var_in_master(cvar)) { size_t numts = VDC::GetNumTimeSteps(cvar.GetName()); rc = _DefCoordVar(_master, cvar, numts); if (rc < 0) return (-1); } tag = prefix + "." + cvar.GetName() + ".DimensionNames"; vector dim_names = cvar.GetDimNames(); string s; for (int i = 0; i < dim_names.size(); i++) { s += dim_names[i]; s += " "; } rc = _master->PutAtt("", tag, s); if (rc < 0) return (rc); tag = prefix + "." + cvar.GetName() + ".TimeDimName"; rc = _master->PutAtt("", tag, cvar.GetTimeDimName()); if (rc < 0) return (rc); tag = prefix + "." + cvar.GetName() + ".Axis"; rc = _master->PutAtt("", tag, cvar.GetAxis()); if (rc < 0) return (rc); tag = prefix + "." + cvar.GetName() + ".UniformHint"; rc = _master->PutAtt("", tag, (int)cvar.GetUniform()); if (rc < 0) return (rc); rc = _WriteMasterBaseVarDefs(prefix, cvar); if (rc < 0) return (rc); } return (0); } int VDCNetCDF::_WriteMasterDataVarsDefs() { map::const_iterator itr; string s; for (itr = _dataVars.begin(); itr != _dataVars.end(); ++itr) { s += itr->first; s += " "; } string tag = "VDC.DataVarNames"; int rc = _master->PutAtt("", tag, s); if (rc < 0) return (rc); string prefix = "VDC.DataVar"; for (itr = _dataVars.begin(); itr != _dataVars.end(); ++itr) { const DataVar &var = itr->second; if (_var_in_master(var)) { size_t numts = VDC::GetNumTimeSteps(var.GetName()); rc = _DefDataVar(_master, var, numts); if (rc < 0) return (-1); } tag = prefix + "." + var.GetName() + ".Mesh"; int rc = _master->PutAtt("", tag, var.GetMeshName()); if (rc < 0) return (rc); tag = prefix + "." + var.GetName() + ".TimeCoordVar"; rc = _master->PutAtt("", tag, var.GetTimeCoordVar()); if (rc < 0) return (rc); tag = prefix + "." + var.GetName() + ".MaskVar"; rc = _master->PutAtt("", tag, var.GetMaskvar()); if (rc < 0) return (rc); if (var.GetHasMissing()) { tag = prefix + "." + var.GetName() + ".MissingValue"; rc = _master->PutAtt("", tag, var.GetMissingValue()); if (rc < 0) return (rc); } rc = _WriteMasterBaseVarDefs(prefix, var); if (rc < 0) return (rc); } return (0); } int VDCNetCDF::_DefBaseVar(WASP *wasp, const VDC::BaseVar &var, size_t max_ts) { vector dims; bool status = GetVarDimensions(var.GetName(), false, dims, -1); VAssert(status); bool time_varying = IsTimeVarying(var.GetName()); vector dimnames; for (int i = 0; i < dims.size(); i++) { size_t len = dims[i].GetLength(); // If data are split across files need to set the time dimension // to the number of time steps in the file // if (i == dims.size() - 1 && time_varying) { len = max_ts; } // Don't define same dimension twice // if (!wasp->InqDimDefined(dims[i].GetName())) { int rc = wasp->DefDim(dims[i].GetName(), len); if (rc < 0) return (-1); } dimnames.push_back(dims[i].GetName()); } reverse(dimnames.begin(), dimnames.end()); // NetCDF order size_t nspatial = time_varying ? dimnames.size() - 1 : dimnames.size(); // Only spatial dimensions are blocked // vector bs = _bs; while (bs.size() > nspatial) { bs.pop_back(); } reverse(bs.begin(), bs.end()); // NetCDF order int rc = wasp->DefVar(var.GetName(), vdc_xtype2ncdf_xtype(var.GetXType()), dimnames, var.GetWName(), bs, var.GetCRatios()); if (rc < 0) return (-1); // // Attributes // rc = wasp->PutAtt(var.GetName(), "Units", var.GetUnits()); if (rc < 0) return (rc); rc = wasp->PutAtt(var.GetName(), "BlockSize", bs); if (rc < 0) return (rc); vector periodic = var.GetPeriodic(); vector iperiodic; for (int i = 0; i < periodic.size(); i++) iperiodic.push_back(periodic[i]); rc = wasp->PutAtt(var.GetName(), "Periodic", iperiodic); if (rc < 0) return (rc); const map & atts = var.GetAttributes(); map::const_iterator itr; for (itr = atts.begin(); itr != atts.end(); ++itr) { const Attribute &attr = itr->second; rc = _PutAtt(wasp, var.GetName(), "", attr); if (rc < 0) return (-1); } return (0); } int VDCNetCDF::_WriteAttributes(WASP *wasp, string varname, const map &atts) { map::const_iterator itr; for (itr = _atts.begin(); itr != _atts.end(); ++itr) { const Attribute &attr = itr->second; int rc = _PutAtt(wasp, varname, attr.GetName(), attr); if (rc < 0) return (rc); } return (0); } int VDCNetCDF::_DefDataVar(WASP *wasp, const VDC::DataVar &var, size_t max_ts) { int rc = _DefBaseVar(wasp, var, max_ts); if (rc < 0) return (-1); vector coord_vars; bool status = GetVarCoordVars(var.GetName(), false, coord_vars); VAssert(status); rc = wasp->PutAtt(var.GetName(), "CoordVars", coord_vars); if (rc < 0) return (-1); rc = wasp->PutAtt(var.GetName(), "MaskVar", var.GetMaskvar()); if (var.GetHasMissing()) { rc = wasp->PutAtt(var.GetName(), "MissingValue", var.GetMissingValue()); if (rc < 0) return (rc); } return (rc); } int VDCNetCDF::_DefCoordVar(WASP *wasp, const VDC::CoordVar &var, size_t max_ts) { int rc = _DefBaseVar(wasp, var, max_ts); if (rc < 0) return (-1); rc = wasp->PutAtt(var.GetName(), "Axis", var.GetAxis()); if (rc < 0) return (-1); rc = wasp->PutAtt(var.GetName(), "UniformHint", var.GetUniform()); return (rc); } int VDCNetCDF::_PutAtt(WASP *wasp, string varname, string tag, const Attribute &attr) { if (tag.empty()) tag = attr.GetName(); DC::XType xtype = attr.GetXType(); // Ugh. For the special attributes missing_value and _FillValue // the type must match that of the data. Since currently the only // output format we support is float we must force the type of // these attributes to float. // if (tag == "missing_value" || tag == "_FillValue") { xtype = FLOAT; } int rc; switch (xtype) { case FLOAT: case DOUBLE: { vector values; attr.GetValues(values); rc = wasp->PutAtt(varname, tag, values); if (rc < 0) return (rc); break; } case UINT8: case INT8: case INT32: case INT64: { vector values; attr.GetValues(values); rc = wasp->PutAtt(varname, tag, values); if (rc < 0) return (rc); break; } case TEXT: { string values; attr.GetValues(values); rc = wasp->PutAtt(varname, tag, values); if (rc < 0) return (rc); break; } default: SetErrMsg("Invalid value, Attribute::GetXType() : %d", attr.GetXType()); return (-1); break; } return (0); } bool VDCNetCDF::_var_in_master(const VDC::BaseVar &var) const { vector dims; bool ok = GetVarDimensions(var.GetName(), false, dims, -1); VAssert(ok); bool time_varying = IsTimeVarying(var.GetName()); if (time_varying && dims.size() > 3) return (false); size_t nelements = 1; for (int i = 0; i < dims.size(); i++) { nelements *= dims[i].GetLength(); } if (nelements < _master_threshold && !var.IsCompressed()) { return (true); } return (false); } ================================================ FILE: lib/vdc/VDC_c.cpp ================================================ #include #include #include #include "vapor/VDC.h" #include "vapor/VDCNetCDF.h" #include "vapor/VDC_c.h" #include "vapor/MyBase.h" // __attribute__ not valid in VisualC++ #ifdef WIN32 #define __attribute__(x) #endif // #define VDC_DEBUG // #define VDC_DEBUG_CPP_RUN // #define VDC_DEBUG_RUN // #define VDC_DEBUG_RUN_WRITE_ONLY #ifdef VDC_DEBUG #include #ifdef VDC_DEBUG_RUN #define VDC_DEBUG_coloredLocation(color) \ { \ } #else #define VDC_DEBUG_coloredLocation(color) \ { \ const char *colorPre = "", *colorPost = ""; \ if (isatty(fileno(stderr))) { \ colorPre = "\x1b[" #color "m"; \ colorPost = "\x1b[0m"; \ } \ fprintf(stderr, "%s[VDC_c.cpp:%03i]%s", colorPre, __LINE__, colorPost); \ } #endif #define VDC_DEBUG_coloredLocation_standard() VDC_DEBUG_coloredLocation(34); #define VDC_DEBUG_coloredLocation_error() VDC_DEBUG_coloredLocation(31); #define VDC_DEBUG_func() fprintf(stderr, "%s", __func__); #define VDC_DEBUG_printf(...) fprintf(stderr, __VA_ARGS__) #define VDC_DEBUG_printff(...) \ { \ VDC_DEBUG_coloredLocation_standard(); \ VDC_DEBUG_func(); \ fprintf(stderr, __VA_ARGS__); \ } #define VDC_DEBUG_printff_error(...) \ { \ VDC_DEBUG_coloredLocation_error(); \ VDC_DEBUG_func(); \ fprintf(stderr, __VA_ARGS__); \ } #define VDC_DEBUG_called() VDC_DEBUG_printff("();\n") #ifdef VDC_DEBUG_RUN #define VDC_DEBUG_printff_nRun(...) \ { \ } #define VDC_DEBUG_called_nRun() \ { \ } #else #define VDC_DEBUG_printff_nRun(...) VDC_DEBUG_printff(__VA_ARGS__) #define VDC_DEBUG_called_nRun() VDC_DEBUG_called() #endif #ifdef VDC_DEBUG_RUN_WRITE_ONLY #define VDC_DEBUG_printff_readF(...) \ { \ } #define VDC_DEBUG_called_readF() \ { \ } #else #define VDC_DEBUG_printff_readF(...) VDC_DEBUG_printff(__VA_ARGS__) #define VDC_DEBUG_called_readF() VDC_DEBUG_called() #endif #include #define VDC_DEBUG_break() raise(SIGINT) #else #define VDC_DEBUG_printf(...) \ { \ } #define VDC_DEBUG_printff(...) \ { \ } #define VDC_DEBUG_printff_error(...) \ { \ } #define VDC_DEBUG_called() \ { \ } #define VDC_DEBUG_break() \ { \ } #define VDC_DEBUG_printff_readF(...) \ { \ } #define VDC_DEBUG_called_readF() \ { \ } #define VDC_DEBUG_printff_nRun(...) \ { \ } #define VDC_DEBUG_called_nRun() \ { \ } #endif using std::string; using std::vector; void _stringToCString(const string s, char **str); void _stringVectorToCStringArray(const vector v, char ***str, int *count); void _longVectorToCArray(const vector v, long **data, int *count); void _boolVectorToCArray(const vector v, long **data, int *count); void _doubleVectorToCArray(const vector v, double **data, int *count); void _size_tVectorToCArray(const vector v, size_t **data, int *count); int _XTypeToInt(const VDC::XType type); VDC::XType _IntToXType(int type); const char *_XTypeToString(const VDC::XType type); const char *_XTypeToIntCodeString(const VDC::XType type); const char *_boolToStr(const int b); const char *_AxisToStr(const int a); const char *_accessModeToStr(const int m); const char *_VDCPToStr(const VDC *p); vector _strArrayToStringVector(const char **a, size_t count); string _stringVectorToString(const vector v); string _strArrayToString(const char **a, size_t count); vector _size_tArrayToSize_tVector(const size_t *a, size_t count); string _size_tVectorToString(const vector v); string _size_tArrayToString(const size_t *a, size_t count); #ifdef VDC_DEBUG static string valueCArrayToString(const void *a, int l, VDC_XType type) __attribute__((unused)); #endif // ######################## // # VDC::Dimension # // ######################## VDCDimension *VDCDimension_new() { return new VDCDimension(); } void VDCDimension_delete(VDCDimension *p) { delete p; } void VDCDimension_GetName(const VDCDimension *p, char **name) { _stringToCString(p->GetName(), name); } size_t VDCDimension_GetLength(const VDCDimension *p) { return p->GetLength(); } int VDCDimension_IsTimeVarying(const VDCDimension *p) { return p->IsTimeVarying(); } // ######################## // # VDC::BaseVar # // ######################## VDCBaseVar *VDCBaseVar_new() { return new VDCBaseVar(); } void VDCBaseVar_delete(VDCBaseVar *p) { delete p; } void VDCBaseVar_GetName(const VDCBaseVar *p, char **name) { _stringToCString(p->GetName(), name); } void VDCBaseVar_GetUnits(const VDCBaseVar *p, char **units) { _stringToCString(p->GetUnits(), units); } int VDCBaseVar_GetXType(const VDCBaseVar *p) { return _XTypeToInt(p->GetXType()); } void VDCBaseVar_GetWName(const VDCBaseVar *p, char **name) { _stringToCString(p->GetWName(), name); } void VDCBaseVar_GetCRatios(const VDCBaseVar *p, size_t **ratios, int *count) { _size_tVectorToCArray(p->GetCRatios(), ratios, count); } void VDCBaseVar_GetPeriodic(const VDCBaseVar *p, long **periodic, int *count) { _boolVectorToCArray(p->GetPeriodic(), periodic, count); } void VDCBaseVar_GetAttributeNames(const VDCBaseVar *p, char ***names, int *count) { const std::map attributes = p->GetAttributes(); vector names_v; std::map::const_iterator it; for (it = attributes.begin(); it != attributes.end(); it++) names_v.push_back(it->first); _stringVectorToCStringArray(names_v, names, count); } int VDCBaseVar_IsCompressed(const VDCBaseVar *p) { return p->IsCompressed(); } // ######################## // # VDC::AuxVar # // ######################## VDCAuxVar *VDCAuxVar_new() { return new VDCAuxVar(); } void VDCAuxVar_delete(VDCAuxVar *p) { delete p; } void VDCAuxVar_GetDimNames(const VDCAuxVar *p, char ***names, int *count) { _stringVectorToCStringArray(p->GetDimNames(), names, count); } // ######################## // # VDC::DataVar # // ######################## VDCDataVar *VDCDataVar_new() { return new VDCDataVar(); } void VDCDataVar_delete(VDCDataVar *p) { delete p; } void VDCDataVar_GetMeshName(const VDCDataVar *p, char **name) { _stringToCString(p->GetMeshName(), name); } void VDCDataVar_GetTimeCoordVar(const VDCDataVar *p, char **name) { _stringToCString(p->GetTimeCoordVar(), name); } void VDCDataVar_GetMaskvar(const VDCDataVar *p, char **name) { _stringToCString(p->GetMaskvar(), name); } int VDCDataVar_GetHasMissing(const VDCDataVar *p) { return p->GetHasMissing(); } double VDCDataVar_GetMissingValue(const VDCDataVar *p) { return p->GetMissingValue(); } // ######################## // # VDC::CoordVar # // ######################## VDCCoordVar *VDCCoordVar_new() { return new VDCCoordVar(); } void VDCCoordVar_delete(VDCCoordVar *p) { delete p; } void VDCCoordVar_GetDimNames(const VDCCoordVar *p, char ***names, int *count) { _stringVectorToCStringArray(p->GetDimNames(), names, count); } void VDCCoordVar_GetTimeDimName(const VDCCoordVar *p, char **name) { _stringToCString(p->GetTimeDimName(), name); } int VDCCoordVar_GetAxis(const VDCCoordVar *p) { return p->GetAxis(); } int VDCCoordVar_GetUniform(const VDCCoordVar *p) { return p->GetUniform(); } // ######################## // # VDC # // ######################## VDC *VDC_new() { VDC_DEBUG_called_nRun(); return new VAPoR::VDCNetCDF(); } void VDC_delete(VDC *p) { VDC_DEBUG_printff_nRun("(%s);\n", _VDCPToStr(p)); delete p; } int VDC_InitializeDefaultBS(VDC *p, const char *path, int mode) { return VDC_Initialize(p, path, mode, NULL, 0); } int VDC_Initialize(VDC *p, const char *path, int mode, size_t *bs, int bsCount) { #ifdef VDC_DEBUG_CPP_RUN if (bs != NULL && bsCount > 0) { VDC_DEBUG_printff("(%s \"%s\", std::vector(), %s, %s, 0);\n", _VDCPToStr(p), path, _accessModeToStr(mode), bs ? "" : "NULL"); } else { VDC_DEBUG_printff("(%s \"%s\", std::vector(), %s);\n", _VDCPToStr(p), path, _accessModeToStr(mode)); } #else VDC_DEBUG_printff("(%s \"%s\", %s, %s, %i);\n", _VDCPToStr(p), path, _accessModeToStr(mode), bs ? "" : "NULL", bsCount); #endif VDC::AccessMode am = VDC::R; if (mode == VDC_AccessMode_R) am = VDC::R; else if (mode == VDC_AccessMode_W) am = VDC::W; else if (mode == VDC_AccessMode_A) am = VDC::A; VAPoR::VDCNetCDF *pnc = (VAPoR::VDCNetCDF *)p; int ret; if (bs != NULL && bsCount > 0) { vector bs_v = _size_tArrayToSize_tVector(bs, bsCount); ret = pnc->Initialize(string(path), vector(), am, bs_v, 0); } else { ret = pnc->Initialize(string(path), vector(), am); } // pnc->SetFill(0x100); // Required to disable set_fill return ret; } int VDC_GetDimension(const VDC *p, const char *dimname, VDCDimension *dimension) { VDC_DEBUG_printff_readF("(%s \"%s\", );\n", _VDCPToStr(p), dimname); return p->GetDimension(string(dimname), *dimension, -1); } void VDC_GetDimensionNames(const VDC *p, char ***names, int *count) { VDC_DEBUG_printff_readF("(%s <***names>, <*count>);\n", _VDCPToStr(p)); _stringVectorToCStringArray(p->GetDimensionNames(), names, count); } int VDC_GetCoordVarInfo(const VDC *p, const char *varname, VDCCoordVar *var) { VDC_DEBUG_printff_readF("(%s \"%s\", );\n", _VDCPToStr(p), varname); return p->GetCoordVarInfo(string(varname), *var); } int VDC_GetDataVarInfo(const VDC *p, const char *varname, VDCDataVar *var) { VDC_DEBUG_printff_readF("(%s \"%s\", );\n", _VDCPToStr(p), varname); return p->GetDataVarInfo(string(varname), *var); } int VDC_GetBaseVarInfo(const VDC *p, const char *varname, VDCBaseVar *var) { VDC_DEBUG_printff_readF("(%s \"%s\", );\n", _VDCPToStr(p), varname); return p->GetBaseVarInfo(string(varname), *var); } void VDC_GetDataVarNames(const VDC *p, char ***names, int *count) { VDC_DEBUG_printff_readF("(%s <***names>, <*count>);\n", _VDCPToStr(p)); _stringVectorToCStringArray(p->GetDataVarNames(), names, count); } void VDC_GetCoordVarNames(const VDC *p, char ***names, int *count) { VDC_DEBUG_printff_readF("(%s <***names>, <*count>);\n", _VDCPToStr(p)); _stringVectorToCStringArray(p->GetCoordVarNames(), names, count); } int VDC_GetNumRefLevels(const VDC *p, const char *varname) { VDC_DEBUG_printff_readF("(%s \"%s\");\n", _VDCPToStr(p), varname); return p->GetNumRefLevels(string(varname)); } int VDC_GetAtt_long(const VDC *p, const char *varname, const char *attname, long **values, int *count) { VDC_DEBUG_called_readF(); vector values_v; bool ret = p->GetAtt(string(varname), string(attname), values_v); if (ret) _longVectorToCArray(values_v, values, count); return ret; } int VDC_GetAtt_double(const VDC *p, const char *varname, const char *attname, double **values, int *count) { VDC_DEBUG_called_readF(); vector values_v; bool ret = p->GetAtt(string(varname), string(attname), values_v); if (ret) _doubleVectorToCArray(values_v, values, count); return ret; } int VDC_GetAtt_text(const VDC *p, const char *varname, const char *attname, char **text) { VDC_DEBUG_called_readF(); string text_s; bool ret = p->GetAtt(string(varname), string(attname), text_s); if (ret) _stringToCString(text_s, text); return ret; } int VDC_GetAtt_Count(const VDC *p, const char *varname, const char *attname, int *count) { VDC_DEBUG_printff_readF("(%s \"%s\", \"%s\", <*count>);\n", _VDCPToStr(p), varname, attname); VDC::XType type = p->GetAttType(string(varname), string(attname)); if (type < 0 || type == VDC::XType::INVALID) return 0; if (type == VDC::XType::TEXT) { *count = 1; } else if (type == VDC::XType::FLOAT || type == VDC::XType::DOUBLE) { vector v; p->GetAtt(string(varname), string(attname), v); *count = v.size(); } else if (type == VDC::XType::INT32 || type == VDC::XType::INT64) { vector v; p->GetAtt(string(varname), string(attname), v); *count = v.size(); } return 1; } void VDC_GetAttNames(const VDC *p, const char *varname, char ***names, int *count) { VDC_DEBUG_printff_readF("(%s \"%s\", <***names>, <*count>);\n", _VDCPToStr(p), varname); _stringVectorToCStringArray(p->GetAttNames(string(varname)), names, count); } int VDC_GetAttType(const VDC *p, const char *varname, const char *attname) { VDC_DEBUG_printff_readF("(%s \"%s\", \"%s\");\n", _VDCPToStr(p), varname, attname); return _XTypeToInt(p->GetAttType(string(varname), string(attname))); } int VDC_VariableExists(const VDC *p, size_t ts, const char *varname, int reflevel, int lod) { VDC_DEBUG_printff_readF("(%s %li, \"%s\", %i, %i);\n", _VDCPToStr(p), ts, varname, reflevel, lod); return p->VariableExists(ts, string(varname), reflevel, lod); } int VDC_IsTimeVarying(const VDC *p, const char *varname) { VDC_DEBUG_printff_readF("(%s \"%s\");\n", _VDCPToStr(p), varname); return p->IsTimeVarying(string(varname)); } int VDC_CoordVarExists(const VDC *p, const char *varname) { VDC_DEBUG_printff_readF("(%s \"%s\");\n", _VDCPToStr(p), varname); VDCCoordVar v; return p->GetCoordVarInfo(string(varname), v); } int VDC_GetCRatios(const VDC *p, const char *varname, size_t **ratios, int *count) { VDC_DEBUG_printff_readF("(%s \"%s\", <**ratios>, <*count>);\n", _VDCPToStr(p), varname); VDCBaseVar v; bool ret = p->GetBaseVarInfo(string(varname), v); if (ret) _size_tVectorToCArray(v.GetCRatios(), ratios, count); return ret; } int VDC_GetCRatiosCount(const VDC *p, const char *varname) { VDC_DEBUG_printff_readF("(%s \"%s\");\n", _VDCPToStr(p), varname); VDCBaseVar v; p->GetBaseVarInfo(string(varname), v); return v.GetCRatios().size(); } int VDC_GetVarDimLens(const VDC *p, const char *varname, int spatial, size_t **lens, int *count) { VDC_DEBUG_printff_readF("(%s \"%s\", %i, <**lens>, <*count>);\n", _VDCPToStr(p), varname, spatial); vector lens_v; bool ret = p->GetVarDimLens(string(varname), spatial, lens_v, -1); if (ret) _size_tVectorToCArray(lens_v, lens, count); return ret; } int VDC_GetVarDimNames(const VDC *p, const char *varname, int spatial, char ***names, int *count) { VDC_DEBUG_printff_readF("(%s \"%s\", %i, <***names>, <*count>);\n", _VDCPToStr(p), varname, spatial); vector names_v; bool ret = p->GetVarDimNames(string(varname), spatial, names_v); if (ret) _stringVectorToCStringArray(names_v, names, count); return ret; } int VDC_GetVarCoordVars(const VDC *p, const char *varname, int spatial, char ***names, int *count) { VDC_DEBUG_printff_readF("(%s \"%s\", %i, <***names>, <*count>);\n", _VDCPToStr(p), varname, spatial); vector names_v; bool ret = p->GetVarCoordVars(string(varname), spatial, names_v); if (ret) _stringVectorToCStringArray(names_v, names, count); return ret; } int VDC_GetVarDimLensAtLevel(const VDC *p, const char *varname, int level, size_t **lens, int *count) { VDC_DEBUG_called_readF(); vector lens_v, bs_v; bool ret = p->GetDimLensAtLevel(string(varname), level, lens_v, bs_v, -1); if (ret == 0) _size_tVectorToCArray(lens_v, lens, count); return ret; } int VDC_OpenVariableRead(VDC *p, size_t ts, const char *varname, int level, int lod) { VDC_DEBUG_printff("(%s %li, \"%s\", %i, %i);\n", _VDCPToStr(p), ts, varname, level, lod); return p->OpenVariableRead(ts, string(varname), level, lod); } int VDC_CloseVariable(VDC *p, int fd) { VDC_DEBUG_called(); return p->CloseVariable(fd); } int VDC_Read(VDC *p, int fd, float *region) { VDC_DEBUG_called(); return p->Read(fd, region); } int VDC_ReadSlice(VDC *p, int fd, float *slice) { VDC_DEBUG_called(); return p->ReadSlice(fd, slice); } int VDC_ReadRegion(VDC *p, int fd, const size_t *min, const size_t *max, const int dims, float *region) { VDC_DEBUG_called(); vector min_v; vector max_v; for (int i = 0; i < dims; i++) { min_v.push_back(min[i]); max_v.push_back(max[i]); } return p->ReadRegion(fd, min_v, max_v, region); } int VDC_GetVar(VDC *p, const char *varname, int level, int lod, float *data) { VDC_DEBUG_called(); return p->GetVar(string(varname), level, lod, data); } int VDC_GetVarAtTimeStep(VDC *p, size_t ts, const char *varname, int level, int lod, float *data) { VDC_DEBUG_called(); return p->GetVar(ts, string(varname), level, lod, data); } // ######################## // # Write # // ######################## int VDC_SetCompressionBlock(VDC *p, const char *wname, const size_t *cratios, int cratiosCount) { #ifdef VDC_DEBUG_CPP_RUN VDC_DEBUG_printff("(%s \"%s\", %s);\n", _VDCPToStr(p), wname, _size_tArrayToString(cratios, cratiosCount).c_str()); #else VDC_DEBUG_printff("(%s \"%s\", %s, %i);\n", _VDCPToStr(p), wname, _size_tArrayToString(cratios, cratiosCount).c_str(), cratiosCount); #endif vector cratios_v = _size_tArrayToSize_tVector(cratios, cratiosCount); int ret = p->SetCompressionBlock(string(wname), cratios_v); return ret; } int VDC_DefineDimension(VDC *p, const char *dimname, size_t length) { VDC_DEBUG_printff("(%s \"%s\", %li);\n", _VDCPToStr(p), dimname, length); return p->DefineDimension(string(dimname), length); } int VDC_DefineDimensionWithAxis(VDC *p, const char *dimname, size_t length, int axis) { VDC_DEBUG_printff("(%s \"%s\", %li, %s);\n", _VDCPToStr(p), dimname, length, _AxisToStr(axis)); return p->DefineDimension(string(dimname), length, axis); } int VDC_DefineDataVar(VDC *p, const char *varname, const char **dimnames, size_t dimnamesCount, const char **coordvars, size_t coordvarsCount, const char *units, VDC_XType xtype, int compressed) { #ifdef VDC_DEBUG_CPP_RUN VDC_DEBUG_printff("(%s \"%s\", %s, %s, \"%s\", %s, %s);\n", _VDCPToStr(p), varname, _strArrayToString(dimnames, dimnamesCount).c_str(), _strArrayToString(coordvars, coordvarsCount).c_str(), units, _XTypeToIntCodeString(_IntToXType(xtype)), _boolToStr(compressed)); #else VDC_DEBUG_printff("(%s \"%s\", %s, %li, %s, %li, \"%s\", %s, %s);\n", _VDCPToStr(p), varname, _strArrayToString(dimnames, dimnamesCount).c_str(), dimnamesCount, _strArrayToString(coordvars, coordvarsCount).c_str(), coordvarsCount, units, _XTypeToIntCodeString(_IntToXType(xtype)), _boolToStr(compressed)); #endif VDC_DEBUG_printff_nRun(": Current dimensions = %s\n", _stringVectorToString(p->GetDimensionNames()).c_str()); VDC_DEBUG_printff_nRun(": Current coordvars = %s\n", _stringVectorToString(p->GetCoordVarNames()).c_str()); VDC_DEBUG_printff_nRun(": Current datavars = %s\n", _stringVectorToString(p->GetDataVarNames()).c_str()); for (int i = 0; i < coordvarsCount; i++) { VDCCoordVar cv; p->GetCoordVarInfo(coordvars[i], cv); cout << cv; } vector dimnames_v; vector coordvars_v; for (int i = 0; i < dimnamesCount; i++) dimnames_v.push_back(string(dimnames[i])); for (int i = 0; i < coordvarsCount; i++) coordvars_v.push_back(string(coordvars[i])); VDC_DEBUG_printff_nRun(": calling VDC::DefineDataVar(\"%s\", %s, %s, \"%s\", %s, %s);\n", varname, _stringVectorToString(dimnames_v).c_str(), _stringVectorToString(coordvars_v).c_str(), units, _XTypeToString(_IntToXType(xtype)), _boolToStr(compressed)); int ret = p->DefineDataVar(string(varname), dimnames_v, coordvars_v, string(units), _IntToXType(xtype), (bool)compressed); VDC_DEBUG_printff_nRun(": return (%i);\n", ret); if (ret < 0) VDC_DEBUG_printff_error(": Error message = \"%s\"\n", Wasp::MyBase::GetErrMsg()); VDC_DEBUG_printff_nRun(": Current coordvars = %s\n", _stringVectorToString(p->GetCoordVarNames()).c_str()); return ret; } int VDC_DefineCoordVar(VDC *p, const char *varname, const char **dimnames, size_t dimnamesCount, const char *time_dim_name, const char *units, int axis, VDC_XType xtype, int compressed) { #ifdef VDC_DEBUG_CPP_RUN VDC_DEBUG_printff("(%s \"%s\", %s, \"%s\", \"%s\", %s, %s, %s);\n", _VDCPToStr(p), varname, _strArrayToString(dimnames, dimnamesCount).c_str(), time_dim_name, units, _AxisToStr(axis), _XTypeToIntCodeString(_IntToXType(xtype)), _boolToStr(compressed)); #else VDC_DEBUG_printff("(%s \"%s\", %s, %li, \"%s\", \"%s\", %s, %s, %s);\n", _VDCPToStr(p), varname, _strArrayToString(dimnames, dimnamesCount).c_str(), dimnamesCount, time_dim_name, units, _AxisToStr(axis), _XTypeToIntCodeString(_IntToXType(xtype)), _boolToStr(compressed)); #endif vector dimnames_v; for (int i = 0; i < dimnamesCount; i++) dimnames_v.push_back(string(dimnames[i])); VDC_DEBUG_printff_nRun(": calling VDC::DefineCoordVar(\"%s\", %s, \"%s\", \"%s\", %s, %s, %s);\n", varname, _stringVectorToString(dimnames_v).c_str(), time_dim_name, units, _AxisToStr(axis), _XTypeToString(_IntToXType(xtype)), _boolToStr(compressed)); return p->DefineCoordVar(string(varname), dimnames_v, string(time_dim_name), string(units), axis, _IntToXType(xtype), compressed); } int VDC_DefineCoordVarUniform(VDC *p, const char *varname, const char **dimnames, size_t dimnamesCount, const char *time_dim_name, const char *units, int axis, VDC_XType xtype, int compressed) { VDC_DEBUG_printff("(%s \"%s\", %s, %li, \"%s\", \"%s\", %s, %s, %s);\n", _VDCPToStr(p), varname, _stringVectorToString(_strArrayToStringVector(dimnames, dimnamesCount)).c_str(), dimnamesCount, time_dim_name, units, _AxisToStr(axis), _XTypeToString(_IntToXType(xtype)), _boolToStr(compressed)); vector dimnames_v; for (int i = 0; i < dimnamesCount; i++) dimnames_v.push_back(string(dimnames[i])); VDC_DEBUG_printff_nRun(": calling VDC::DefineCoordVarUniform(\"%s\", %s, \"%s\", \"%s\", %s, %s, %s);\n", varname, _stringVectorToString(dimnames_v).c_str(), time_dim_name, units, _AxisToStr(axis), _XTypeToString(_IntToXType(xtype)), _boolToStr(compressed)); return p->DefineCoordVarUniform(string(varname), dimnames_v, string(time_dim_name), string(units), axis, _IntToXType(xtype), compressed); } int VDC_PutAtt(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const void *values, size_t count) { VDC_DEBUG_printff_nRun("(%s \"%s\", \"%s\", %s, , %li);\n", _VDCPToStr(p), varname, attname, _XTypeToIntCodeString(_IntToXType(xtype)), count); switch (xtype) { case VDC_XType_FLOAT: case VDC_XType_DOUBLE: return VDC_PutAtt_double(p, varname, attname, xtype, (const double *)values, count); case VDC_XType_INT32: case VDC_XType_INT64: return VDC_PutAtt_long(p, varname, attname, xtype, (const long *)values, count); case VDC_XType_TEXT: return VDC_PutAtt_text(p, varname, attname, xtype, (const char *)values); case VDC_XType_INVALID: default: return -2; } } #ifdef VDC_DEBUG static string valueCArrayToString(const void *a, int l, VDC_XType type) { string s; switch (type) { #ifdef VDC_DEBUG_CPP_RUN case VDC_XType_FLOAT: s = "std::vector{"; break; // case VDC_XType_FLOAT: s = "std::vector{"; break; case VDC_XType_DOUBLE: s = "std::vector{"; break; case VDC_XType_INT32: s = "std::vector{"; break; case VDC_XType_INT64: s = "std::vector{"; break; #else case VDC_XType_FLOAT: s = "(float[]){"; break; case VDC_XType_DOUBLE: s = "(double[]){"; break; case VDC_XType_INT32: s = "(int[]){"; break; case VDC_XType_INT64: s = "(long[]){"; break; #endif } char buffer[128]; for (int i = 0; i < l; i++) { switch (type) { case VDC_XType_FLOAT: sprintf(buffer, "%g", ((float *)a)[i]); break; case VDC_XType_DOUBLE: sprintf(buffer, "%g", ((double *)a)[i]); break; case VDC_XType_INT32: sprintf(buffer, "%i", ((int *)a)[i]); break; case VDC_XType_INT64: sprintf(buffer, "%li", ((long *)a)[i]); break; } s += string(buffer); if (i != l - 1) s += ", "; } return s + string("}"); } #endif int VDC_PutAtt_double(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const double *values, size_t count) { #ifdef VDC_DEBUG_CPP_RUN VDC_DEBUG_coloredLocation_standard(); VDC_DEBUG_printf("VDC_PutAtt(%s \"%s\", \"%s\", %s, %s);\n", _VDCPToStr(p), varname, attname, _XTypeToIntCodeString(_IntToXType(xtype)), valueCArrayToString(values, count, xtype).c_str()); #else VDC_DEBUG_printff("(%s \"%s\", \"%s\", %s, %s, %li);\n", _VDCPToStr(p), varname, attname, _XTypeToIntCodeString(_IntToXType(xtype)), valueCArrayToString(values, count, xtype).c_str(), count); #endif vector values_v; if (xtype == VDC_XType_FLOAT) for (int i = 0; i < count; i++) values_v.push_back(((float *)values)[i]); else for (int i = 0; i < count; i++) values_v.push_back(values[i]); return p->PutAtt(string(varname), string(attname), _IntToXType(xtype), values_v); } int VDC_PutAtt_long(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const long *values, size_t count) { #ifdef VDC_DEBUG_CPP_RUN VDC_DEBUG_coloredLocation_standard(); VDC_DEBUG_printf("VDC_PutAtt(%s \"%s\", \"%s\", %s, %s);\n", _VDCPToStr(p), varname, attname, _XTypeToIntCodeString(_IntToXType(xtype)), valueCArrayToString(values, count, xtype).c_str()); #else VDC_DEBUG_printff("(%s \"%s\", \"%s\", %s, %s, %li);\n", _VDCPToStr(p), varname, attname, _XTypeToIntCodeString(_IntToXType(xtype)), valueCArrayToString(values, count, xtype).c_str(), count); #endif vector values_v; if (xtype == VDC_XType_INT32) for (int i = 0; i < count; i++) values_v.push_back(((int *)values)[i]); else for (int i = 0; i < count; i++) values_v.push_back(values[i]); return p->PutAtt(string(varname), string(attname), _IntToXType(xtype), values_v); } int VDC_PutAtt_text(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const char *values) { #ifdef VDC_DEBUG_CPP_RUN VDC_DEBUG_coloredLocation_standard(); VDC_DEBUG_printf("VDC_PutAtt(%s \"%s\", \"%s\", %s, \"%s\");\n", _VDCPToStr(p), varname, attname, _XTypeToIntCodeString(_IntToXType(xtype)), values); #else VDC_DEBUG_printff("(%s \"%s\", \"%s\", %s, \"%s\");\n", _VDCPToStr(p), varname, attname, _XTypeToIntCodeString(_IntToXType(xtype)), values); #endif return p->PutAtt(string(varname), string(attname), _IntToXType(xtype), string(values)); } int VDC_EndDefine(VDC *p) { VDC_DEBUG_printff("(%s);\n", _VDCPToStr(p)); return p->EndDefine(); } int VDC_PutVar(VDC *p, const char *varname, int lod, const float *data) { VDC_DEBUG_printff("(%s \"%s\", %i, data);\n", _VDCPToStr(p), varname, lod); return p->PutVar(string(varname), lod, data); } int VDC_PutVarAtTimeStep(VDC *p, size_t ts, const char *varname, int lod, const float *data) { VDC_DEBUG_printff("(%s %li, \"%s\", %i, );\n", _VDCPToStr(p), ts, varname, lod); int ret = p->PutVar(ts, string(varname), lod, data); if (ret < 0) VDC_DEBUG_printff_error(": ERROR: code = %i, message = \"%s\"\n", ret, Wasp::MyBase::GetErrMsg()); return ret; } // ######################## // # Utility # // ######################## const char *VDC_GetErrMsg() { #ifdef VDC_DEBUG_RUN #ifdef VDC_DEBUG_CPP_RUN VDC_DEBUG_printf("printf(\"ERR \\\"%%s\\\" \", vdc->GetErrMsg());\n"); #else VDC_DEBUG_printf("printf(\"ERR \\\"%%s\\\" \", VDC_GetErrMsg());\n"); #endif #else VDC_DEBUG_called(); #endif return Wasp::MyBase::GetErrMsg(); } void VDC_FreeStringArray(char ***str, int *count) { for (int i = 0; i < *count; i++) delete[](*str)[i]; delete[] * str; *str = 0; *count = 0; } void VDC_FreeString(char **str) { delete[] * str; *str = 0; } void VDC_FreeLongArray(long **data) { delete[] * data; *data = 0; } void VDC_FreeDoubleArray(double **data) { delete[] * data; *data = 0; } void VDC_FreeSize_tArray(size_t **data) { delete[] * data; *data = 0; } void VDC_ReverseSize_tArray(size_t *data, int count) { for (int i = 0; i < count / 2; i++) { size_t temp = data[i]; data[i] = data[count - i - 1]; data[count - i - 1] = temp; } } // ######################## // # Static # // ######################## void _stringToCString(const string s, char **str) { int size = s.size(); *str = new char[size + 1]; s.copy(*str, size); (*str)[size] = 0; } void _stringVectorToCStringArray(const vector v, char ***str, int *count) { *count = v.size(); *str = new char *[*count]; for (int i = 0; i < *count; i++) { (*str)[i] = new char[v[i].size() + 1]; v[i].copy((*str)[i], v[i].size()); (*str)[i][v[i].size()] = 0; } } void _longVectorToCArray(const vector v, long **data, int *count) { *count = v.size(); *data = new long[*count]; for (int i = 0; i < *count; i++) (*data)[i] = v[i]; } void _boolVectorToCArray(const vector v, long **data, int *count) { *count = v.size(); *data = new long[*count]; for (int i = 0; i < *count; i++) (*data)[i] = v[i]; } void _doubleVectorToCArray(const vector v, double **data, int *count) { *count = v.size(); *data = new double[*count]; for (int i = 0; i < *count; i++) (*data)[i] = v[i]; } void _size_tVectorToCArray(const vector v, size_t **data, int *count) { *count = v.size(); *data = new size_t[*count]; for (int i = 0; i < *count; i++) (*data)[i] = v[i]; } int _XTypeToInt(const VDC::XType type) { switch (type) { case VDC::XType::INVALID: return VDC_XType_INVALID; case VDC::XType::FLOAT: return VDC_XType_FLOAT; case VDC::XType::DOUBLE: return VDC_XType_DOUBLE; case VDC::XType::INT32: return VDC_XType_INT32; case VDC::XType::INT64: return VDC_XType_INT64; case VDC::XType::TEXT: return VDC_XType_TEXT; default: return -1; } } VDC::XType _IntToXType(int type) { switch (type) { case VDC_XType_INVALID: return VDC::XType::INVALID; case VDC_XType_FLOAT: return VDC::XType::FLOAT; case VDC_XType_DOUBLE: return VDC::XType::DOUBLE; case VDC_XType_INT32: return VDC::XType::INT32; case VDC_XType_INT64: return VDC::XType::INT64; case VDC_XType_TEXT: return VDC::XType::TEXT; default: return VDC::XType::INVALID; } } const char *_XTypeToString(const VDC::XType type) { switch (type) { case VDC::XType::INVALID: return "INVALID"; case VDC::XType::FLOAT: return "float"; case VDC::XType::DOUBLE: return "double"; case VDC::XType::INT32: return "int32"; case VDC::XType::INT64: return "int64"; case VDC::XType::TEXT: return "text"; default: return ""; } } const char *_XTypeToIntCodeString(const VDC::XType type) { switch (type) { #ifdef VDC_DEBUG_CPP_RUN case VDC::XType::INVALID: return "VDC::XType::INVALID"; case VDC::XType::FLOAT: return "VDC::XType::FLOAT"; case VDC::XType::DOUBLE: return "VDC::XType::DOUBLE"; case VDC::XType::INT32: return "VDC::XType::INT32"; case VDC::XType::INT64: return "VDC::XType::INT64"; case VDC::XType::TEXT: return "VDC::XType::TEXT"; #else case VDC::XType::INVALID: return "VDC_XType_INVALID"; case VDC::XType::FLOAT: return "VDC_XType_FLOAT"; case VDC::XType::DOUBLE: return "VDC_XType_DOUBLE"; case VDC::XType::INT32: return "VDC_XType_INT32"; case VDC::XType::INT64: return "VDC_XType_INT64"; case VDC::XType::TEXT: return "VDC_XType_TEXT"; #endif default: return ""; } } const char *_boolToStr(const int b) { if (b) return "true"; else return "false"; } #define xstr(s) str(s) #define str(s) #s const char *_AxisToStr(const int a) { switch (a) { #ifdef VDC_DEBUG_CPP_RUN case VDCDimension_Axis_X: return xstr(VDCDimension_Axis_X); case VDCDimension_Axis_Y: return xstr(VDCDimension_Axis_Y); case VDCDimension_Axis_Z: return xstr(VDCDimension_Axis_Z); case VDCDimension_Axis_T: return xstr(VDCDimension_Axis_T); #else case VDCDimension_Axis_X: return "VDCDimension_Axis_X"; case VDCDimension_Axis_Y: return "VDCDimension_Axis_Y"; case VDCDimension_Axis_Z: return "VDCDimension_Axis_Z"; case VDCDimension_Axis_T: return "VDCDimension_Axis_T"; #endif default: return "INVALID AXIS"; } } const char *_accessModeToStr(const int m) { switch (m) { #ifdef VDC_DEBUG_CPP_RUN case VDC_AccessMode_R: return "VDC::AccessMode::R"; case VDC_AccessMode_W: return "VDC::AccessMode::W"; case VDC_AccessMode_A: return "VDC::AccessMode::A"; #else case VDC_AccessMode_R: return "VDC_AccessMode_R"; case VDC_AccessMode_W: return "VDC_AccessMode_W"; case VDC_AccessMode_A: return "VDC_AccessMode_A"; #endif default: return ""; } } const char *_VDCPToStr(const VDC *p) { #ifdef VDC_DEBUG_CPP_RUN return ""; #else if (p) return "vdc,"; else return "NULL,"; #endif } vector _strArrayToStringVector(const char **a, size_t count) { vector v; for (int i = 0; i < count; i++) v.push_back(string(a[i])); return v; } string _stringVectorToString(const vector v) { string s; #ifndef VDC_DEBUG_CPP_RUN s += "(const char*[])"; #endif s += "{"; for (int i = 0; i < v.size(); i++) { s += "\"" + v[i] + "\"" + (i == v.size() - 1 ? "" : ", "); } s += "}"; return s; } string _strArrayToString(const char **a, size_t count) { #ifdef VDC_DEBUG_CPP_RUN if (!a) return "std::vector()"; #else if (!a) return "NULL"; #endif return _stringVectorToString(_strArrayToStringVector(a, count)); } vector _size_tArrayToSize_tVector(const size_t *a, size_t count) { vector v; for (int i = 0; i < count; i++) v.push_back(a[i]); return v; } string _size_tVectorToString(const vector v) { string s; #ifdef VDC_DEBUG_CPP_RUN s += "std::vector"; #else s += "(size_t[])"; #endif s += "{"; for (int i = 0; i < v.size(); i++) { s += std::to_string(v[i]) + (i == v.size() - 1 ? "" : ", "); } s += "}"; return s; } string _size_tArrayToString(const size_t *a, size_t count) { if (!a) return "NULL"; return _size_tVectorToString(_size_tArrayToSize_tVector(a, count)); } ================================================ FILE: lib/vdc/kdtree.c ================================================ /* This file is part of ``kdtree'', a library for working with kd-trees. Copyright (C) 2007-2011 John Tsiombikas Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* single nearest neighbor search written by Tamas Nepusz */ #include #include #include #include #include "kdtree.h" #ifdef Linux #include #endif #if defined(WIN32) || defined(__WIN32__) #include #endif #ifdef USE_LIST_NODE_ALLOCATOR #ifndef NO_PTHREADS #include #else #ifndef I_WANT_THREAD_BUGS #error "You are compiling with the fast list node allocator, with pthreads disabled! This WILL break if used from multiple threads." #endif /* I want thread bugs */ #endif /* pthread support */ #endif /* use list node allocator */ struct kdhyperrect { int dim; double *min, *max; /* minimum/maximum coords */ }; struct kdnode { double *pos; int dir; void * data; struct kdnode *left, *right; /* negative/positive side */ }; struct res_node { struct kdnode * item; double dist_sq; struct res_node *next; }; struct kdtree { int dim; struct kdnode * root; struct kdhyperrect *rect; void (*destr)(void *); }; struct kdres { struct kdtree * tree; struct res_node *rlist, *riter; int size; }; #define SQ(x) ((x) * (x)) static void clear_rec(struct kdnode *node, void (*destr)(void *)); static int insert_rec(struct kdnode **node, const double *pos, void *data, int dim); static int rlist_insert(struct res_node *list, struct kdnode *item, double dist_sq); static void clear_results(struct kdres *set); static struct kdhyperrect *hyperrect_create(int dim, const double *min, const double *max); static void hyperrect_free(struct kdhyperrect *rect); static struct kdhyperrect *hyperrect_duplicate(const struct kdhyperrect *rect); static void hyperrect_extend(struct kdhyperrect *rect, const double *pos); static double hyperrect_dist_sq(struct kdhyperrect *rect, const double *pos); #ifdef USE_LIST_NODE_ALLOCATOR static struct res_node *alloc_resnode(void); static void free_resnode(struct res_node *); #else #define alloc_resnode() malloc(sizeof(struct res_node)) #define free_resnode(n) free(n) #endif struct kdtree *kd_create(int k) { struct kdtree *tree; if (!(tree = malloc(sizeof *tree))) { return 0; } tree->dim = k; tree->root = 0; tree->destr = 0; tree->rect = 0; return tree; } void kd_free(struct kdtree *tree) { if (tree) { kd_clear(tree); free(tree); } } static void clear_rec(struct kdnode *node, void (*destr)(void *)) { if (!node) return; clear_rec(node->left, destr); clear_rec(node->right, destr); if (destr) { destr(node->data); } free(node->pos); free(node); } void kd_clear(struct kdtree *tree) { clear_rec(tree->root, tree->destr); tree->root = 0; if (tree->rect) { hyperrect_free(tree->rect); tree->rect = 0; } } void kd_data_destructor(struct kdtree *tree, void (*destr)(void *)) { tree->destr = destr; } static int insert_rec(struct kdnode **root, const double *pos, void *data, int dim) { int new_dir = 0; struct kdnode *parent = *root; struct kdnode *node = parent; while (node) { parent = node; new_dir = (node->dir + 1) % dim; if (pos[node->dir] < node->pos[node->dir]) { node = node->left; } else { node = node->right; } } if (!(node = malloc(sizeof *node))) { return -1; } if (!(node->pos = malloc(dim * sizeof *node->pos))) { free(node); return -1; } memcpy(node->pos, pos, dim * sizeof *node->pos); node->data = data; node->dir = new_dir; node->left = node->right = 0; // root of tree? // if (!*root) { *root = node; return 0; } if (pos[parent->dir] < parent->pos[parent->dir]) { parent->left = node; } else { parent->right = node; } return 0; } int kd_insert(struct kdtree *tree, const double *pos, void *data) { if (insert_rec(&tree->root, pos, data, tree->dim)) { return -1; } if (tree->rect == 0) { tree->rect = hyperrect_create(tree->dim, pos, pos); } else { hyperrect_extend(tree->rect, pos); } return 0; } int kd_insertf(struct kdtree *tree, const float *pos, void *data) { static double sbuf[16]; double * bptr, *buf = 0; int res, dim = tree->dim; if (dim > 16) { #ifndef NO_ALLOCA if (dim <= 256) bptr = buf = alloca(dim * sizeof *bptr); else #endif if (!(bptr = buf = malloc(dim * sizeof *bptr))) { return -1; } } else { bptr = buf = sbuf; } while (dim-- > 0) { *bptr++ = *pos++; } res = kd_insert(tree, buf, data); #ifndef NO_ALLOCA if (tree->dim > 256) #else if (tree->dim > 16) #endif free(buf); return res; } int kd_insert3(struct kdtree *tree, double x, double y, double z, void *data) { double buf[3]; buf[0] = x; buf[1] = y; buf[2] = z; return kd_insert(tree, buf, data); } int kd_insert3f(struct kdtree *tree, float x, float y, float z, void *data) { double buf[3]; buf[0] = x; buf[1] = y; buf[2] = z; return kd_insert(tree, buf, data); } static int find_nearest(struct kdnode *node, const double *pos, double range, struct res_node *list, int ordered, int dim) { double dist_sq, dx; int i, ret, added_res = 0; if (!node) return 0; dist_sq = 0; for (i = 0; i < dim; i++) { dist_sq += SQ(node->pos[i] - pos[i]); } if (dist_sq <= SQ(range)) { if (rlist_insert(list, node, ordered ? dist_sq : -1.0) == -1) { return -1; } added_res = 1; } dx = pos[node->dir] - node->pos[node->dir]; ret = find_nearest(dx <= 0.0 ? node->left : node->right, pos, range, list, ordered, dim); if (ret >= 0 && fabs(dx) < range) { added_res += ret; ret = find_nearest(dx <= 0.0 ? node->right : node->left, pos, range, list, ordered, dim); } if (ret == -1) { return -1; } added_res += ret; return added_res; } #if 0 static int find_nearest_n(struct kdnode *node, const double *pos, double range, int num, struct rheap *heap, int dim) { double dist_sq, dx; int i, ret, added_res = 0; if(!node) return 0; /* if the photon is close enough, add it to the result heap */ dist_sq = 0; for(i=0; ipos[i] - pos[i]); } if(dist_sq <= range_sq) { if(heap->size >= num) { /* get furthest element */ struct res_node *maxelem = rheap_get_max(heap); /* and check if the new one is closer than that */ if(maxelem->dist_sq > dist_sq) { rheap_remove_max(heap); if(rheap_insert(heap, node, dist_sq) == -1) { return -1; } added_res = 1; range_sq = dist_sq; } } else { if(rheap_insert(heap, node, dist_sq) == -1) { return =1; } added_res = 1; } } /* find signed distance from the splitting plane */ dx = pos[node->dir] - node->pos[node->dir]; ret = find_nearest_n(dx <= 0.0 ? node->left : node->right, pos, range, num, heap, dim); if(ret >= 0 && fabs(dx) < range) { added_res += ret; ret = find_nearest_n(dx <= 0.0 ? node->right : node->left, pos, range, num, heap, dim); } } #endif static void kd_nearest_i(struct kdnode *node, const double *pos, struct kdnode **result, double *result_dist_sq, struct kdhyperrect *rect) { int dir = node->dir; int i; double dummy, dist_sq; struct kdnode *nearer_subtree, *farther_subtree; double * nearer_hyperrect_coord, *farther_hyperrect_coord; /* Decide whether to go left or right in the tree */ dummy = pos[dir] - node->pos[dir]; if (dummy <= 0) { nearer_subtree = node->left; farther_subtree = node->right; nearer_hyperrect_coord = rect->max + dir; farther_hyperrect_coord = rect->min + dir; } else { nearer_subtree = node->right; farther_subtree = node->left; nearer_hyperrect_coord = rect->min + dir; farther_hyperrect_coord = rect->max + dir; } if (nearer_subtree) { /* Slice the hyperrect to get the hyperrect of the nearer subtree */ dummy = *nearer_hyperrect_coord; *nearer_hyperrect_coord = node->pos[dir]; /* Recurse down into nearer subtree */ kd_nearest_i(nearer_subtree, pos, result, result_dist_sq, rect); /* Undo the slice */ *nearer_hyperrect_coord = dummy; } /* Check the distance of the point at the current node, compare it * with our best so far */ dist_sq = 0; for (i = 0; i < rect->dim; i++) { dist_sq += SQ(node->pos[i] - pos[i]); } if (dist_sq < *result_dist_sq) { *result = node; *result_dist_sq = dist_sq; } if (farther_subtree) { /* Get the hyperrect of the farther subtree */ dummy = *farther_hyperrect_coord; *farther_hyperrect_coord = node->pos[dir]; /* Check if we have to recurse down by calculating the closest * point of the hyperrect and see if it's closer than our * minimum distance in result_dist_sq. */ if (hyperrect_dist_sq(rect, pos) < *result_dist_sq) { /* Recurse down into farther subtree */ kd_nearest_i(farther_subtree, pos, result, result_dist_sq, rect); } /* Undo the slice on the hyperrect */ *farther_hyperrect_coord = dummy; } } struct kdres *kd_nearest(struct kdtree *kd, const double *pos) { struct kdhyperrect *rect; struct kdnode * result; struct kdres * rset; double dist_sq; int i; if (!kd) return 0; if (!kd->rect) return 0; /* Allocate result set */ if (!(rset = malloc(sizeof *rset))) { return 0; } if (!(rset->rlist = alloc_resnode())) { free(rset); return 0; } rset->rlist->next = 0; rset->tree = kd; /* Duplicate the bounding hyperrectangle, we will work on the copy */ if (!(rect = hyperrect_duplicate(kd->rect))) { kd_res_free(rset); return 0; } /* Our first guesstimate is the root node */ result = kd->root; dist_sq = 0; for (i = 0; i < kd->dim; i++) dist_sq += SQ(result->pos[i] - pos[i]); /* Search for the nearest neighbour recursively */ kd_nearest_i(kd->root, pos, &result, &dist_sq, rect); /* Free the copy of the hyperrect */ hyperrect_free(rect); /* Store the result */ if (result) { if (rlist_insert(rset->rlist, result, -1.0) == -1) { kd_res_free(rset); return 0; } rset->size = 1; kd_res_rewind(rset); return rset; } else { kd_res_free(rset); return 0; } } struct kdres *kd_nearestf(struct kdtree *tree, const float *pos) { static double sbuf[16]; double * bptr, *buf = 0; int dim = tree->dim; struct kdres *res; if (dim > 16) { #ifndef NO_ALLOCA if (dim <= 256) bptr = buf = alloca(dim * sizeof *bptr); else #endif if (!(bptr = buf = malloc(dim * sizeof *bptr))) { return 0; } } else { bptr = buf = sbuf; } while (dim-- > 0) { *bptr++ = *pos++; } res = kd_nearest(tree, buf); #ifndef NO_ALLOCA if (tree->dim > 256) #else if (tree->dim > 16) #endif free(buf); return res; } struct kdres *kd_nearest3(struct kdtree *tree, double x, double y, double z) { double pos[3]; pos[0] = x; pos[1] = y; pos[2] = z; return kd_nearest(tree, pos); } struct kdres *kd_nearest3f(struct kdtree *tree, float x, float y, float z) { double pos[3]; pos[0] = x; pos[1] = y; pos[2] = z; return kd_nearest(tree, pos); } /* ---- nearest N search ---- */ /* static kdres *kd_nearest_n(struct kdtree *kd, const double *pos, int num) { int ret; struct kdres *rset; if(!(rset = malloc(sizeof *rset))) { return 0; } if(!(rset->rlist = alloc_resnode())) { free(rset); return 0; } rset->rlist->next = 0; rset->tree = kd; if((ret = find_nearest_n(kd->root, pos, range, num, rset->rlist, kd->dim)) == -1) { kd_res_free(rset); return 0; } rset->size = ret; kd_res_rewind(rset); return rset; }*/ struct kdres *kd_nearest_range(struct kdtree *kd, const double *pos, double range) { int ret; struct kdres *rset; if (!(rset = malloc(sizeof *rset))) { return 0; } if (!(rset->rlist = alloc_resnode())) { free(rset); return 0; } rset->rlist->next = 0; rset->tree = kd; if ((ret = find_nearest(kd->root, pos, range, rset->rlist, 0, kd->dim)) == -1) { kd_res_free(rset); return 0; } rset->size = ret; kd_res_rewind(rset); return rset; } struct kdres *kd_nearest_rangef(struct kdtree *kd, const float *pos, float range) { static double sbuf[16]; double * bptr, *buf = 0; int dim = kd->dim; struct kdres *res; if (dim > 16) { #ifndef NO_ALLOCA if (dim <= 256) bptr = buf = alloca(dim * sizeof *bptr); else #endif if (!(bptr = buf = malloc(dim * sizeof *bptr))) { return 0; } } else { bptr = buf = sbuf; } while (dim-- > 0) { *bptr++ = *pos++; } res = kd_nearest_range(kd, buf, range); #ifndef NO_ALLOCA if (kd->dim > 256) #else if (kd->dim > 16) #endif free(buf); return res; } struct kdres *kd_nearest_range3(struct kdtree *tree, double x, double y, double z, double range) { double buf[3]; buf[0] = x; buf[1] = y; buf[2] = z; return kd_nearest_range(tree, buf, range); } struct kdres *kd_nearest_range3f(struct kdtree *tree, float x, float y, float z, float range) { double buf[3]; buf[0] = x; buf[1] = y; buf[2] = z; return kd_nearest_range(tree, buf, range); } void kd_res_free(struct kdres *rset) { clear_results(rset); free_resnode(rset->rlist); free(rset); } int kd_res_size(struct kdres *set) { return (set->size); } void kd_res_rewind(struct kdres *rset) { rset->riter = rset->rlist->next; } int kd_res_end(struct kdres *rset) { return rset->riter == 0; } int kd_res_next(struct kdres *rset) { rset->riter = rset->riter->next; return rset->riter != 0; } void *kd_res_item(struct kdres *rset, double *pos) { if (rset->riter) { if (pos) { memcpy(pos, rset->riter->item->pos, rset->tree->dim * sizeof *pos); } return rset->riter->item->data; } return 0; } void *kd_res_itemf(struct kdres *rset, float *pos) { if (rset->riter) { if (pos) { int i; for (i = 0; i < rset->tree->dim; i++) { pos[i] = rset->riter->item->pos[i]; } } return rset->riter->item->data; } return 0; } void *kd_res_item3(struct kdres *rset, double *x, double *y, double *z) { if (rset->riter) { if (*x) *x = rset->riter->item->pos[0]; if (*y) *y = rset->riter->item->pos[1]; if (*z) *z = rset->riter->item->pos[2]; } return 0; } void *kd_res_item3f(struct kdres *rset, float *x, float *y, float *z) { if (rset->riter) { if (*x) *x = rset->riter->item->pos[0]; if (*y) *y = rset->riter->item->pos[1]; if (*z) *z = rset->riter->item->pos[2]; } return 0; } void *kd_res_item_data(struct kdres *set) { return kd_res_item(set, 0); } /* ---- hyperrectangle helpers ---- */ static struct kdhyperrect *hyperrect_create(int dim, const double *min, const double *max) { size_t size = dim * sizeof(double); struct kdhyperrect *rect = 0; if (!(rect = malloc(sizeof(struct kdhyperrect)))) { return 0; } rect->dim = dim; if (!(rect->min = malloc(size))) { free(rect); return 0; } if (!(rect->max = malloc(size))) { free(rect->min); free(rect); return 0; } memcpy(rect->min, min, size); memcpy(rect->max, max, size); return rect; } static void hyperrect_free(struct kdhyperrect *rect) { free(rect->min); free(rect->max); free(rect); } static struct kdhyperrect *hyperrect_duplicate(const struct kdhyperrect *rect) { return hyperrect_create(rect->dim, rect->min, rect->max); } static void hyperrect_extend(struct kdhyperrect *rect, const double *pos) { int i; for (i = 0; i < rect->dim; i++) { if (pos[i] < rect->min[i]) { rect->min[i] = pos[i]; } if (pos[i] > rect->max[i]) { rect->max[i] = pos[i]; } } } static double hyperrect_dist_sq(struct kdhyperrect *rect, const double *pos) { int i; double result = 0; for (i = 0; i < rect->dim; i++) { if (pos[i] < rect->min[i]) { result += SQ(rect->min[i] - pos[i]); } else if (pos[i] > rect->max[i]) { result += SQ(rect->max[i] - pos[i]); } } return result; } /* ---- static helpers ---- */ #ifdef USE_LIST_NODE_ALLOCATOR /* special list node allocators. */ static struct res_node *free_nodes; #ifndef NO_PTHREADS static pthread_mutex_t alloc_mutex = PTHREAD_MUTEX_INITIALIZER; #endif static struct res_node *alloc_resnode(void) { struct res_node *node; #ifndef NO_PTHREADS pthread_mutex_lock(&alloc_mutex); #endif if (!free_nodes) { node = malloc(sizeof *node); } else { node = free_nodes; free_nodes = free_nodes->next; node->next = 0; } #ifndef NO_PTHREADS pthread_mutex_unlock(&alloc_mutex); #endif return node; } static void free_resnode(struct res_node *node) { #ifndef NO_PTHREADS pthread_mutex_lock(&alloc_mutex); #endif node->next = free_nodes; free_nodes = node; #ifndef NO_PTHREADS pthread_mutex_unlock(&alloc_mutex); #endif } #endif /* list node allocator or not */ /* inserts the item. if dist_sq is >= 0, then do an ordered insert */ /* TODO make the ordering code use heapsort */ static int rlist_insert(struct res_node *list, struct kdnode *item, double dist_sq) { struct res_node *rnode; if (!(rnode = alloc_resnode())) { return -1; } rnode->item = item; rnode->dist_sq = dist_sq; if (dist_sq >= 0.0) { while (list->next && list->next->dist_sq < dist_sq) { list = list->next; } } rnode->next = list->next; list->next = rnode; return 0; } static void clear_results(struct kdres *rset) { struct res_node *tmp, *node = rset->rlist->next; while (node) { tmp = node; node = node->next; free_resnode(tmp); } rset->rlist->next = 0; } ================================================ FILE: lib/vdc/kdtree.h ================================================ /* This file is part of ``kdtree'', a library for working with kd-trees. Copyright (C) 2007-2011 John Tsiombikas Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _KDTREE_H_ #define _KDTREE_H_ #ifdef __cplusplus extern "C" { #endif struct kdtree; struct kdres; /* create a kd-tree for "k"-dimensional data */ struct kdtree *kd_create(int k); /* free the struct kdtree */ void kd_free(struct kdtree *tree); /* remove all the elements from the tree */ void kd_clear(struct kdtree *tree); /* if called with non-null 2nd argument, the function provided * will be called on data pointers (see kd_insert) when nodes * are to be removed from the tree. */ void kd_data_destructor(struct kdtree *tree, void (*destr)(void *)); /* insert a node, specifying its position, and optional data */ int kd_insert(struct kdtree *tree, const double *pos, void *data); int kd_insertf(struct kdtree *tree, const float *pos, void *data); int kd_insert3(struct kdtree *tree, double x, double y, double z, void *data); int kd_insert3f(struct kdtree *tree, float x, float y, float z, void *data); /* Find the nearest node from a given point. * * This function returns a pointer to a result set with at most one element. */ struct kdres *kd_nearest(struct kdtree *tree, const double *pos); struct kdres *kd_nearestf(struct kdtree *tree, const float *pos); struct kdres *kd_nearest3(struct kdtree *tree, double x, double y, double z); struct kdres *kd_nearest3f(struct kdtree *tree, float x, float y, float z); /* Find the N nearest nodes from a given point. * * This function returns a pointer to a result set, with at most N elements, * which can be manipulated with the kd_res_* functions. * The returned pointer can be null as an indication of an error. Otherwise * a valid result set is always returned which may contain 0 or more elements. * The result set must be deallocated with kd_res_free after use. */ /* struct kdres *kd_nearest_n(struct kdtree *tree, const double *pos, int num); struct kdres *kd_nearest_nf(struct kdtree *tree, const float *pos, int num); struct kdres *kd_nearest_n3(struct kdtree *tree, double x, double y, double z); struct kdres *kd_nearest_n3f(struct kdtree *tree, float x, float y, float z); */ /* Find any nearest nodes from a given point within a range. * * This function returns a pointer to a result set, which can be manipulated * by the kd_res_* functions. * The returned pointer can be null as an indication of an error. Otherwise * a valid result set is always returned which may contain 0 or more elements. * The result set must be deallocated with kd_res_free after use. */ struct kdres *kd_nearest_range(struct kdtree *tree, const double *pos, double range); struct kdres *kd_nearest_rangef(struct kdtree *tree, const float *pos, float range); struct kdres *kd_nearest_range3(struct kdtree *tree, double x, double y, double z, double range); struct kdres *kd_nearest_range3f(struct kdtree *tree, float x, float y, float z, float range); struct kdres *kd_region(struct kdtree *kd, const double *min, const double *max); /* frees a result set returned by kd_nearest_range() */ void kd_res_free(struct kdres *set); /* returns the size of the result set (in elements) */ int kd_res_size(struct kdres *set); /* rewinds the result set iterator */ void kd_res_rewind(struct kdres *set); /* returns non-zero if the set iterator reached the end after the last element */ int kd_res_end(struct kdres *set); /* advances the result set iterator, returns non-zero on success, zero if * there are no more elements in the result set. */ int kd_res_next(struct kdres *set); /* returns the data pointer (can be null) of the current result set item * and optionally sets its position to the pointers(s) if not null. */ void *kd_res_item(struct kdres *set, double *pos); void *kd_res_itemf(struct kdres *set, float *pos); void *kd_res_item3(struct kdres *set, double *x, double *y, double *z); void *kd_res_item3f(struct kdres *set, float *x, float *y, float *z); /* equivalent to kd_res_item(set, 0) */ void *kd_res_item_data(struct kdres *set); #ifdef __cplusplus } #endif #endif /* _KDTREE_H_ */ ================================================ FILE: lib/vdc/vizutil.cpp ================================================ #include #include #include #include "vapor/VAssert.h" #include namespace { double dot2d(const double a[], const double b[]) { return ((a[0] * b[0]) + (a[1] * b[1])); } }; // namespace void VAPoR::HexahedronToTets(const int hexahedron[8], int tets[5 * 4]) { int i = 0; if (hexahedron[0] % 2 == 0) { tets[i++] = hexahedron[0]; tets[i++] = hexahedron[1]; tets[i++] = hexahedron[5]; tets[i++] = hexahedron[3]; tets[i++] = hexahedron[0]; tets[i++] = hexahedron[5]; tets[i++] = hexahedron[6]; tets[i++] = hexahedron[3]; tets[i++] = hexahedron[0]; tets[i++] = hexahedron[5]; tets[i++] = hexahedron[4]; tets[i++] = hexahedron[6]; tets[i++] = hexahedron[0]; tets[i++] = hexahedron[3]; tets[i++] = hexahedron[6]; tets[i++] = hexahedron[2]; tets[i++] = hexahedron[5]; tets[i++] = hexahedron[6]; tets[i++] = hexahedron[3]; tets[i++] = hexahedron[7]; } else { tets[i++] = hexahedron[1]; tets[i++] = hexahedron[5]; tets[i++] = hexahedron[4]; tets[i++] = hexahedron[7]; tets[i++] = hexahedron[1]; tets[i++] = hexahedron[4]; tets[i++] = hexahedron[2]; tets[i++] = hexahedron[7]; tets[i++] = hexahedron[1]; tets[i++] = hexahedron[4]; tets[i++] = hexahedron[0]; tets[i++] = hexahedron[2]; tets[i++] = hexahedron[1]; tets[i++] = hexahedron[7]; tets[i++] = hexahedron[2]; tets[i++] = hexahedron[3]; tets[i++] = hexahedron[4]; tets[i++] = hexahedron[2]; tets[i++] = hexahedron[7]; tets[i++] = hexahedron[6]; } } void VAPoR::QuadToTris(const int quad[4], int tris[2 * 3]) { // Triangle #1 // int i = 0; tris[i++] = quad[0]; tris[i++] = quad[1]; tris[i++] = quad[3]; // Triangle #2 // tris[i++] = quad[0]; tris[i++] = quad[3]; tris[i++] = quad[2]; } #ifdef VAPOR3_0_0_ALPHA void VAPoR::BaryTet(const Point3d &p, const Point3d &a, const Point3d &b, const Point3d &c, const Point3d &d Point3d &ans) { Vect3d vap(a, p); Vect3d vbp(b, p); Vect3d vcp(c, p); Vect3d vdp(d, p); Vect3d vab(a, b); Vect3d vac(a, c); Vect3d vad(a, d); Vect3d vbc(b, c); Vect3d vbd(b, d); double va; double vb; double vc; double vd; double v; Vect3d temp; const double frecip = 1.0 / 6.0; temp = vbd.cross(vbc); va = vbp.dot(temp) * frecip; temp = vac.cross(vad); vb = vap.dot(temp) * frecip; temp = vad.cross(vab); vc = vap.dot(temp) * frecip; temp = vab.cross(vac); vd = vap.dot(temp) * frecip; temp = vac.cross(vad); v = vab.dot(temp) * frecip; VAssert(v != 0.0); double vrecip = 1.0 / v; ans.x = va * vrecip; ans.y = vb * vrecip; ans.z = vc * vrecip; ans.w = vd * vrecip; } void VAPoR::BaryTri(const Point3d &p, const Point3d &a, const Point3d &b, const Point3d &c Point3d &ans) { Vect3d vap(a, p); Vect3d vbp(b, p); Vect3d vcp(c, p); Vect3d vab(a, b); Vect3d vca(c, a); Vect3d vbc(b, c); Vect3d vac(a, c); Vect3d n; Vect3d na; Vect3d nb; Vect3d nc; n = vab.cross(vac); na = vbc.cross(vbp); nb = vca.cross(vcp); nc = vab.cross(vap); double nrecip = n.dot(n); VAssert(nrecip != 0); nrecip = 1.0 / nrecip; ans.x = n.dot(na) * nrecip; ans.y = n.dot(nb) * nrecip; ans.z = n.dot(nc) * nrecip; } #endif // Compute signed area of a triangle using the 3x3 determinant. Actually we // return 2 * A, where A is area // double VAPoR::SignedTriArea2D(const double a[2], const double b[2], const double c[2]) { return (a[0] * (b[1] * 1.0 - 1.0 * c[1]) - b[0] * (a[1] * 1.0 - 1.0 * c[1]) + c[0] * (a[1] * 1.0 - 1.0 * b[1])); } bool VAPoR::BarycentricCoordsTri(const double verts[], const double pt[], double lambda[]) { // Vector v0 = b - a, v1 = c - a, v2 = p - a; // double v0[] = {verts[2] - verts[0], verts[3] - verts[1]}; double v1[] = {verts[4] - verts[0], verts[5] - verts[1]}; double v2[] = {pt[0] - verts[0], pt[1] - verts[1]}; double d00 = dot2d(v0, v0); double d01 = dot2d(v0, v1); double d11 = dot2d(v1, v1); double d20 = dot2d(v2, v0); double d21 = dot2d(v2, v1); double denom = d00 * d11 - d01 * d01; lambda[1] = (d11 * d20 - d01 * d21) / denom; lambda[2] = (d00 * d21 - d01 * d20) / denom; lambda[0] = 1.0f - lambda[1] - lambda[2]; const double epsilon = std::numeric_limits::epsilon(); if ((lambda[0] < 0.0) && ((lambda[0] + epsilon) >= 0.0)) lambda[0] = 0.0; if ((lambda[1] < 0.0) && ((lambda[1] + epsilon) >= 0.0)) lambda[1] = 0.0; if ((lambda[2] < 0.0) && ((lambda[2] + epsilon) >= 0.0)) lambda[2] = 0.0; return (lambda[0] >= 0.0 && lambda[1] >= 0.0 && lambda[2] >= 0.0); } bool VAPoR::WachspressCoords2D(const double verts[], const double pt[], int n, double lambda[]) { if (n == 0) return (false); if (n == 3) return (BarycentricCoordsTri(verts, pt, lambda)); for (int i = 0; i < n; i++) lambda[i] = 0.0; double wTotal = 0.0; const double epsilon = 1e-6; int curr = 0; int prev = (curr + n - 1) % n; int next = (curr + 1) % n; double Aprev = SignedTriArea2D(pt, &verts[prev * 2], &verts[curr * 2]); bool onEdge = (Aprev > -epsilon && Aprev < epsilon); for (; curr < n && !onEdge; curr++) { prev = (curr + n - 1) % n; next = (curr + 1) % n; double C = SignedTriArea2D(&verts[prev * 2], &verts[curr * 2], &verts[next * 2]); double A = SignedTriArea2D(pt, &verts[curr * 2], &verts[next * 2]); onEdge = (A > -epsilon && A < epsilon); if (onEdge) break; // special handling required lambda[curr] = C / (Aprev * A); Aprev = A; wTotal += lambda[curr]; } // Special handling required if point is on an edge: simply linearly // interpolate between the adjacent points // if (onEdge) { for (int i = 0; i < n; i++) lambda[i] = 0.0; int i0, i1; // Which edge is point on? beteen points prev and curr, or curr // and next ? // if (Aprev > -epsilon && Aprev < epsilon) { i0 = (curr + n - 1) % n; i1 = curr; } else { i0 = curr; i1 = (curr + 1) % n; } double w; if (verts[i0 * 2] != verts[i1 * 2]) { w = 1.0 - ((pt[0] - verts[i0 * 2]) / (verts[i1 * 2] - verts[i0 * 2])); } else { w = 1.0 - ((pt[1] - verts[i0 * 2 + 1]) / (verts[i1 * 2 + 1] - verts[i0 * 2 + 1])); } lambda[i0] = w; lambda[i1] = 1.0 - w; if (w < 0.0 || w > 1.0) return (false); else return (true); } // Normalize so sum of weights is 1.0 if point inside; // bool inside = true; wTotal = 1.0 / wTotal; for (int i = 0; i < n; i++) { if (lambda[i] < 0.0) inside = false; lambda[i] *= wTotal; } return (inside); } bool VAPoR::InsideConvexPolygon(const double verts[], const double pt[], int n) { VAssert(n >= 3); // Partition the convex polygon into a triangle fan, testing each triangle // to see if it contains the point // double triverts[6]; triverts[0] = verts[0]; triverts[1] = verts[1]; double dummy[3]; for (int i = 2; i < n; i++) { triverts[2] = verts[2 * (i - 1)]; triverts[3] = verts[2 * (i - 1) + 1]; triverts[4] = verts[2 * (i)]; triverts[5] = verts[2 * (i) + 1]; if (BarycentricCoordsTri(triverts, pt, dummy)) return (true); } return (false); } ================================================ FILE: lib/wasp/CMakeLists.txt ================================================ set (SRC Compressor.cpp MatWaveBase.cpp MatWaveDwt.cpp MatWaveWavedec.cpp NetCDFCpp.cpp SignificanceMap.cpp WASP.cpp WaveFiltBase.cpp WaveFiltBior.cpp WaveFiltCoif.cpp WaveFiltDaub.cpp WaveFiltHaar.cpp WaveFiltInt.cpp ) set (HEADERS ${PROJECT_SOURCE_DIR}/include/vapor/Compressor.h ${PROJECT_SOURCE_DIR}/include/vapor/MatWaveBase.h ${PROJECT_SOURCE_DIR}/include/vapor/MatWaveDwt.h ${PROJECT_SOURCE_DIR}/include/vapor/MatWaveWavedec.h ${PROJECT_SOURCE_DIR}/include/vapor/NetCDFCpp.h ${PROJECT_SOURCE_DIR}/include/vapor/SignificanceMap.h ${PROJECT_SOURCE_DIR}/include/vapor/WASP.h ${PROJECT_SOURCE_DIR}/include/vapor/WaveFiltBase.h ${PROJECT_SOURCE_DIR}/include/vapor/WaveFiltBior.h ${PROJECT_SOURCE_DIR}/include/vapor/WaveFiltCoif.h ${PROJECT_SOURCE_DIR}/include/vapor/WaveFiltDaub.h ${PROJECT_SOURCE_DIR}/include/vapor/WaveFiltHaar.h ${PROJECT_SOURCE_DIR}/include/vapor/WaveFiltInt.h ) add_library (wasp SHARED ${SRC} ${HEADERS}) target_link_libraries (wasp PUBLIC common ${NETCDF}) add_definitions (-DWASP_EXPORTS) install ( TARGETS wasp DESTINATION ${INSTALL_LIB_DIR} COMPONENT Libraries ) install ( FILES ${HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR} COMPONENT Libraries ) ================================================ FILE: lib/wasp/Compressor.cpp ================================================ // // $Id: Compressor.cpp,v 1.6 2013/05/15 23:05:48 clynejp Exp $ // #include #include #include #include #include using namespace VAPoR; using namespace std; void Compressor::_Compressor(vector dims) { if (dims.size() > 3) return; _dims.clear(); _nlevels = 0; _indexvec.clear(); _nx = 1; _ny = 1; _nz = 1; _C = NULL; _CLen = 0; _L = NULL; _LLen = 0; _keepapp = true; _clamp_min_flag = false; _clamp_max_flag = false; _epsilon_flag = false; _clamp_min = 0.0; _clamp_max = 1.0; _epsilon = 0.0; for (int i = 0; i < dims.size(); i++) { _dims.push_back(dims[i]); } _nx = _ny = _nz = 1; if (_dims.size() >= 1) _nx = _dims[0]; if (_dims.size() >= 2) _ny = _dims[1]; if (_dims.size() >= 3) _nz = _dims[2]; // // Create an appropriate filter bank allocate memory for storing // wavelet coefficients // if (_dims.size() == 3) { _nlevels = min(min(wmaxlev(_nx), wmaxlev(_ny)), wmaxlev(_nz)); size_t clen = coefflength3(_nx, _ny, _nz, _nlevels); _C = new double[clen]; _CLen = clen; _L = new size_t[(21 * _nlevels) + 6]; _LLen = (21 * _nlevels) + 6; // Compute the bookkeeping vector, L. // // N.B. L will be recomputed by wavedec(), but not // waverec(); // computeL3(_nx, _ny, _nz, _nlevels, _L); } else if (_dims.size() == 2) { _nlevels = min(wmaxlev(_nx), wmaxlev(_ny)); size_t clen = coefflength2(_nx, _ny, _nlevels); _C = new double[clen]; _CLen = clen; _L = new size_t[(6 * _nlevels) + 4]; _LLen = (6 * _nlevels) + 4; computeL2(_nx, _ny, _nlevels, _L); } else { _nlevels = wmaxlev(_nx); size_t clen = coefflength(_nx, _nlevels); _C = new double[clen]; _CLen = clen; _L = new size_t[_nlevels + 2]; _LLen = _nlevels + 2; computeL(_nx, _nlevels, _L); } _indexvec.reserve(_CLen); } Compressor::Compressor(vector dims, const string &wavename, const string &mode) : MatWaveWavedec(wavename, mode) { _C = NULL; _L = NULL; _CLen = 0; _LLen = 0; _Compressor(dims); } Compressor::Compressor(vector dims, const string &wavename) : MatWaveWavedec(wavename) { _C = NULL; _L = NULL; _CLen = 0; _LLen = 0; _Compressor(dims); } Compressor::~Compressor() { if (_C) delete[] _C; if (_L) delete[] _L; } // // Comparision functions for the C++ Std Lib sort function // inline bool my_compare_f(const void *x1, const void *x2) { return (fabsf(*(float *)x1) > fabsf(*(float *)x2)); } inline bool my_compare_d(const void *x1, const void *x2) { return (fabs(*(double *)x1) > fabs(*(double *)x2)); } inline bool my_compare_i(const void *x1, const void *x2) { return (abs(*(int *)x1) > abs(*(int *)x2)); } inline bool my_compare_l(const void *x1, const void *x2) { return (labs(*(long *)x1) > labs(*(long *)x2)); } namespace { template int compress_template(Compressor *cmp, const T *src_arr, T *dst_arr, size_t dst_arr_len, T *C, size_t clen, size_t *L, SignificanceMap *sigmap, const vector &dims, size_t nlevels, vector indexvec, bool my_compare(const void *, const void *)) { if (!C) { Compressor::SetErrMsg("Invalid state"); return (-1); } if ((dims.size() < 1) || (dims.size() > 3)) { Compressor::SetErrMsg("Invalid array shape"); return (-1); } if (dst_arr_len > clen) { Compressor::SetErrMsg("Invalid array destination array length : %lu", dst_arr_len); return (-1); } // // Forward wavelet transform the array and compute the number of // approximation coefficients (numkeep). // size_t numkeep = 0; int rc = 0; if (dims.size() == 3) { if (cmp->KeepAppOnOff()) numkeep = L[0] * L[1] * L[2]; rc = cmp->wavedec3(src_arr, dims[0], dims[1], dims[2], nlevels, C, L); } else if (dims.size() == 2) { if (cmp->KeepAppOnOff()) numkeep = L[0] * L[1]; rc = cmp->wavedec2(src_arr, dims[0], dims[1], nlevels, C, L); } else if (dims.size() == 1) { if (cmp->KeepAppOnOff()) numkeep = L[0]; rc = cmp->wavedec(src_arr, dims[0], nlevels, C, L); } if (rc < 0) return (-1); VAssert(dst_arr_len >= numkeep); rc = sigmap->Reshape(clen); if (rc < 0) return (-1); sigmap->Clear(); // Data has been transformed. Now we need to sort it and find // the threshold value. Note: we don't actually move the data. We // sort an index array that references the data array. for (size_t i = 0; i < dst_arr_len; i++) dst_arr[i] = 0.0; if (numkeep) { // If numkeep>0, copy approximation coeffs. verbatim // for (size_t idx = 0; idx < numkeep; idx++) { rc = sigmap->Set(idx); if (rc < 0) return (-1); dst_arr[idx] = C[idx]; } if (numkeep == dst_arr_len) return (0); dst_arr += numkeep; dst_arr_len -= numkeep; } indexvec.clear(); for (size_t i = numkeep; i < clen; i++) indexvec.push_back(&C[i]); sort(indexvec.begin(), indexvec.end(), my_compare); // Copy coefficients that are larger than the threshold to // the destination array. Record their location in the significance // map. // sort(indexvec.begin(), indexvec.begin() + dst_arr_len); for (size_t idx = numkeep, i = 0; idx < clen && i < dst_arr_len; idx++) { const T *cptr = (T *)indexvec[i]; dst_arr[i++] = *cptr; sigmap->Set(cptr - C); } return (0); } }; // namespace int Compressor::Compress(const float *src_arr, float *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap) { return compress_template(this, src_arr, dst_arr, dst_arr_len, (float *)_C, _CLen, _L, sigmap, _dims, _nlevels, _indexvec, my_compare_f); } int Compressor::Compress(const double *src_arr, double *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap) { return compress_template(this, src_arr, dst_arr, dst_arr_len, (double *)_C, _CLen, _L, sigmap, _dims, _nlevels, _indexvec, my_compare_d); } int Compressor::Compress(const int *src_arr, int *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap) { return compress_template(this, src_arr, dst_arr, dst_arr_len, (int *)_C, _CLen, _L, sigmap, _dims, _nlevels, _indexvec, my_compare_i); } int Compressor::Compress(const long *src_arr, long *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap) { return compress_template(this, src_arr, dst_arr, dst_arr_len, (long *)_C, _CLen, _L, sigmap, _dims, _nlevels, _indexvec, my_compare_l); } namespace { template int decompress_template(Compressor *cmp, const T *src_arr, T *dst_arr, T *C, size_t clen, const size_t *L, int nlevels, SignificanceMap *sigmap, const vector &dims) { if (!C) { Compressor::SetErrMsg("Invalid state"); return (-1); } if ((dims.size() < 1) || (dims.size() > 3)) { Compressor::SetErrMsg("Invalid array shape"); return (-1); } for (size_t i = 0; i < clen; i++) { C[i] = 0.0; } // // Restore the non-zero wavelet coefficients // sigmap->GetNextEntryRestart(); size_t nsig = sigmap->GetNumSignificant(); for (size_t i = 0; i < nsig; i++) { size_t idx; if (!sigmap->GetNextEntry(&idx)) { Compressor::SetErrMsg("Invalid significance map"); return (-1); } C[idx] = src_arr[i]; } bool normalize = cmp->wavelet()->IsNormalized(); int rc = 0; size_t dst_dim[] = {1, 1, 1}; if (dims.size() == 3) { // rc = cmp->waverec3(C, L, nlevels, dst_arr); rc = cmp->appcoef3(C, L, nlevels, nlevels, normalize, dst_arr); cmp->approxlength3(L, nlevels, nlevels, &dst_dim[0], &dst_dim[1], &dst_dim[2]); } else if (dims.size() == 2) { // rc = cmp->waverec2(C, L, nlevels, dst_arr); rc = cmp->appcoef2(C, L, nlevels, nlevels, normalize, dst_arr); cmp->approxlength2(L, nlevels, nlevels, &dst_dim[0], &dst_dim[1]); } else if (dims.size() == 1) { // cmp->waverec(C, L, nlevels, dst_arr); rc = cmp->appcoef(C, L, nlevels, nlevels, normalize, dst_arr); cmp->approxlength(L, nlevels, nlevels, &dst_dim[0]); } if (rc < 0) return (rc); if (cmp->ClampMinOnOff() || cmp->ClampMaxOnOff() || cmp->EpsilonOnOff()) { bool clamp_min_f = cmp->ClampMinOnOff(); double clamp_min = cmp->ClampMin(); bool clamp_max_f = cmp->ClampMaxOnOff(); double clamp_max = cmp->ClampMax(); bool epsilon_f = cmp->EpsilonOnOff(); double epsilon = fabs(cmp->Epsilon()); size_t sz = dst_dim[0] * dst_dim[1] * dst_dim[2]; for (size_t i = 0; i < sz; i++) { if (clamp_min_f && dst_arr[i] < clamp_min) dst_arr[i] = clamp_min; if (clamp_max_f && dst_arr[i] > clamp_max) dst_arr[i] = clamp_max; if (epsilon_f && abs(dst_arr[i]) < epsilon) dst_arr[i] = 0.0; } } return (0); } }; // namespace int Compressor::Decompress(const float *src_arr, float *dst_arr, SignificanceMap *sigmap) { return decompress_template(this, src_arr, dst_arr, (float *)_C, _CLen, _L, _nlevels, sigmap, _dims); } int Compressor::Decompress(const double *src_arr, double *dst_arr, SignificanceMap *sigmap) { return decompress_template(this, src_arr, dst_arr, (double *)_C, _CLen, _L, _nlevels, sigmap, _dims); } int Compressor::Decompress(const int *src_arr, int *dst_arr, SignificanceMap *sigmap) { return decompress_template(this, src_arr, dst_arr, (int *)_C, _CLen, _L, _nlevels, sigmap, _dims); } int Compressor::Decompress(const long *src_arr, long *dst_arr, SignificanceMap *sigmap) { return decompress_template(this, src_arr, dst_arr, (long *)_C, _CLen, _L, _nlevels, sigmap, _dims); } namespace { template int decompose_template(Compressor *cmp, const T *src_arr, T *dst_arr, const vector &dst_arr_lens, T *C, size_t clen, size_t *L, vector &sigmaps, const vector &dims, size_t nlevels, vector indexvec, bool my_compare(const void *, const void *)) { if (!C) { Compressor::SetErrMsg("Invalid state"); return (-1); } if (sigmaps.size() != dst_arr_lens.size()) { Compressor::SetErrMsg("Invalid parameter"); return (-1); } vector my_dst_arr_lens = dst_arr_lens; size_t tlen = 0; // total # of coefficients to retain for (int i = 0; i < my_dst_arr_lens.size(); i++) { tlen += my_dst_arr_lens[i]; } if (tlen > clen) { Compressor::SetErrMsg("Invalid decomposition"); return (-1); } if ((dims.size() < 1) || (dims.size() > 3)) { Compressor::SetErrMsg("Invalid array shape"); return (-1); } // // Forward wavelet transform the array and compute the number of // approximation coefficients (numkeep). // size_t numkeep = 0; int rc = 0; if (dims.size() == 3) { if (cmp->KeepAppOnOff()) numkeep = L[0] * L[1] * L[2]; rc = cmp->wavedec3(src_arr, dims[0], dims[1], dims[2], nlevels, C, L); } else if (dims.size() == 2) { if (cmp->KeepAppOnOff()) numkeep = L[0] * L[1]; rc = cmp->wavedec2(src_arr, dims[0], dims[1], nlevels, C, L); } else if (dims.size() == 1) { if (cmp->KeepAppOnOff()) numkeep = L[0]; rc = cmp->wavedec(src_arr, dims[0], nlevels, C, L); } if (rc < 0) return (-1); if (my_dst_arr_lens[0] < numkeep) { Compressor::SetErrMsg("Invalid decomposition - not enougth coefficients"); return (-1); } for (int i = 0; i < sigmaps.size(); i++) { rc = sigmaps[i].Reshape(clen); if (rc < 0) return (-1); sigmaps[i].Clear(); } // Data has been transformed. Now we need to sort it and find // the threshold value. Note: we don't actually move the data. We // sort an index array that references the data array. for (size_t i = 0; i < tlen; i++) dst_arr[i] = 0.0; if (numkeep) { // If numkeep>0, copy approximation coeffs. verbatim // for (size_t idx = 0; idx < numkeep; idx++) { rc = sigmaps[0].Set(idx); if (rc < 0) return (-1); dst_arr[idx] = C[idx]; } if (numkeep == tlen) return (0); dst_arr += numkeep; my_dst_arr_lens[0] -= numkeep; } // // sort the **indecies** of the coefficients based on the // coefficient's magnitude // indexvec.clear(); for (size_t i = numkeep; i < clen; i++) indexvec.push_back(&C[i]); sort(indexvec.begin(), indexvec.end(), my_compare); vector::iterator itr = indexvec.begin(); for (int j = 0, idx = 0; j < my_dst_arr_lens.size(); j++) { sort(itr, itr + my_dst_arr_lens[j]); // sort coefficient's indecies itr += my_dst_arr_lens[j]; for (int i = 0; i < my_dst_arr_lens[j]; i++, idx++) { const T *cptr = (T *)indexvec[idx]; dst_arr[i] = *cptr; sigmaps[j].Set(cptr - C); } dst_arr += my_dst_arr_lens[j]; } return (0); } template int reconstruct_template(Compressor *cmp, const T *src_arr, T *dst_arr, T *C, size_t clen, const size_t *L, int nlevels, int l, vector &sigmaps, const vector &dims) { if (!C) { Compressor::SetErrMsg("Invalid state"); return (-1); } if ((dims.size() < 1) || (dims.size() > 3)) { Compressor::SetErrMsg("Invalid array shape"); return (-1); } for (size_t count = 0; count < clen; count++) { C[count] = 0.0; } size_t count = 0; size_t idx; for (int j = 0; j < sigmaps.size(); j++) { sigmaps[j].GetNextEntryRestart(); size_t nsig = sigmaps[j].GetNumSignificant(); for (size_t i = 0; i < nsig; i++) { if (!sigmaps[j].GetNextEntry(&idx)) { Compressor::SetErrMsg("Invalid significance map"); return (-1); } C[idx] = src_arr[count]; count++; } } bool normalize = cmp->wavelet()->IsNormalized(); int rc = 0; size_t dst_dim[] = {1, 1, 1}; if (dims.size() == 3) { // cmp->waverec3(C, L, nlevels, dst_arr); rc = cmp->appcoef3(C, L, nlevels, l, normalize, dst_arr); cmp->approxlength3(L, nlevels, l, &dst_dim[0], &dst_dim[1], &dst_dim[2]); } else if (dims.size() == 2) { // cmp->waverec2(C, L, nlevels, dst_arr); rc = cmp->appcoef2(C, L, nlevels, l, normalize, dst_arr); cmp->approxlength2(L, nlevels, l, &dst_dim[0], &dst_dim[1]); } else if (dims.size() == 1) { // cmp->waverec(C, L, nlevels, dst_arr); rc = cmp->appcoef(C, L, nlevels, l, normalize, dst_arr); cmp->approxlength(L, nlevels, l, &dst_dim[0]); } if (rc < 0) return (-1); if (cmp->ClampMinOnOff() || cmp->ClampMaxOnOff()) { bool clamp_min_f = cmp->ClampMinOnOff(); double clamp_min = cmp->ClampMin(); bool clamp_max_f = cmp->ClampMaxOnOff(); double clamp_max = cmp->ClampMax(); size_t sz = dst_dim[0] * dst_dim[1] * dst_dim[2]; for (size_t i = 0; i < sz; i++) { if (clamp_min_f && dst_arr[i] < clamp_min) dst_arr[i] = clamp_min; if (clamp_max_f && dst_arr[i] > clamp_max) dst_arr[i] = clamp_max; } } return (0); } }; // namespace int Compressor::Decompose(const float *src_arr, float *dst_arr, const vector &dst_arr_lens, vector &sigmaps) { return decompose_template(this, src_arr, dst_arr, dst_arr_lens, (float *)_C, _CLen, _L, sigmaps, _dims, _nlevels, _indexvec, my_compare_f); } int Compressor::Decompose(const double *src_arr, double *dst_arr, const vector &dst_arr_lens, vector &sigmaps) { return decompose_template(this, src_arr, dst_arr, dst_arr_lens, (double *)_C, _CLen, _L, sigmaps, _dims, _nlevels, _indexvec, my_compare_d); } int Compressor::Decompose(const int *src_arr, int *dst_arr, const vector &dst_arr_lens, vector &sigmaps) { return decompose_template(this, src_arr, dst_arr, dst_arr_lens, (int *)_C, _CLen, _L, sigmaps, _dims, _nlevels, _indexvec, my_compare_i); } int Compressor::Decompose(const long *src_arr, long *dst_arr, const vector &dst_arr_lens, vector &sigmaps) { return decompose_template(this, src_arr, dst_arr, dst_arr_lens, (long *)_C, _CLen, _L, sigmaps, _dims, _nlevels, _indexvec, my_compare_l); } int Compressor::Reconstruct(const float *src_arr, float *dst_arr, vector &sigmaps, int l) { if (l == -1) l = GetNumLevels(); return reconstruct_template(this, src_arr, dst_arr, (float *)_C, _CLen, _L, _nlevels, l, sigmaps, _dims); } int Compressor::Reconstruct(const double *src_arr, double *dst_arr, vector &sigmaps, int l) { if (l == -1) l = GetNumLevels(); return reconstruct_template(this, src_arr, dst_arr, (double *)_C, _CLen, _L, _nlevels, l, sigmaps, _dims); } int Compressor::Reconstruct(const int *src_arr, int *dst_arr, vector &sigmaps, int l) { if (l == -1) l = GetNumLevels(); return reconstruct_template(this, src_arr, dst_arr, (int *)_C, _CLen, _L, _nlevels, l, sigmaps, _dims); } int Compressor::Reconstruct(const long *src_arr, long *dst_arr, vector &sigmaps, int l) { if (l == -1) l = GetNumLevels(); return reconstruct_template(this, src_arr, dst_arr, (long *)_C, _CLen, _L, _nlevels, l, sigmaps, _dims); } #ifdef VAPOR3_0_0_ALPHA bool Compressor::IsCompressible(vector dims, const string &wavename, const string &mode) { if (dims.size() < 1 || dims.size() > 3) { return (false); } size_t nx; size_t ny; size_t nz; nx = ny = nz = 1; if (dims.size() >= 1) nx = dims[0]; if (dims.size() >= 2) ny = dims[1]; if (dims.size() >= 3) nz = dims[2]; int nlevels; if (dims.size() == 3) { nlevels = min(min(wmaxlev(nx), wmaxlev(ny)), wmaxlev(nz)); } else if (dims.size() == 2) { nlevels = min(wmaxlev(nx), wmaxlev(ny)); } else { nlevels = wmaxlev(nx); } return (nlevels > 0); } #endif void Compressor::GetDimension(vector &dims, int l) const { if (l < 0 || l > _nlevels) l = _nlevels; dims.clear(); for (int i = 0; i < _dims.size(); i++) { size_t len = approxlength(_dims[i], _nlevels - l); dims.push_back(len); } } size_t Compressor::GetMinCompression() const { if (!_keepapp) return (1); if (_dims.size() == 3) { return (_L[0] * _L[1] * _L[2]); } else if (_dims.size() == 2) { return (_L[0] * _L[1]); } else if (_dims.size() == 1) { return (_L[0]); } return (0); } bool Compressor::CompressionInfo(vector dims, const string wavename, bool keepapp, size_t &nlevels, size_t &maxcratio) { nlevels = 0; maxcratio = 0; if (dims.size() < 1 || dims.size() > 3) return (false); for (int i = 0; i < dims.size(); i++) { if (dims[i] < 1) return (false); } MatWaveWavedec mww(wavename); size_t ncoeff = 1; for (int i = 0; i < dims.size(); i++) ncoeff *= dims[i]; size_t mincoeff = 1; if (keepapp) { size_t *L; if (dims.size() == 1) { nlevels = mww.wmaxlev(dims[0]); L = new size_t[nlevels + 2]; mww.computeL(dims[0], nlevels, L); mincoeff = L[0]; } else if (dims.size() == 2) { nlevels = min(mww.wmaxlev(dims[0]), mww.wmaxlev(dims[1])); L = new size_t[(6 * nlevels) + 4]; mww.computeL2(dims[0], dims[1], nlevels, L); mincoeff = L[0] * L[1]; } else { // dims.size() == 3 nlevels = min(min(mww.wmaxlev(dims[0]), mww.wmaxlev(dims[1])), mww.wmaxlev(dims[2])); L = new size_t[(21 * nlevels) + 6]; mww.computeL3(dims[0], dims[1], dims[2], nlevels, L); mincoeff = L[0] * L[1] * L[2]; } delete[] L; } nlevels += 1; maxcratio = ncoeff / mincoeff; return (true); } namespace VAPoR { ostream &operator<<(std::ostream &o, const Compressor &rhs) { o << "Compressor:" << endl; o << " Dimensions:" << endl; for (int i = 0; i < rhs._dims.size(); i++) { o << " " << rhs._dims[i] << " "; } o << endl; o << " Coefficients length " << rhs._CLen << endl; o << " Book keeping length " << rhs._LLen << endl; o << " Keep approx flag " << rhs._keepapp << endl; o << " Clamp min flag " << rhs._clamp_min_flag << endl; o << " Clamp max flag " << rhs._clamp_max_flag << endl; o << " Clamp min " << rhs._clamp_min << endl; o << " Clamp max " << rhs._clamp_max << endl; o << " Epsilon flag " << rhs._epsilon_flag << endl; o << " Epsilon " << rhs._epsilon << endl; return (o); } }; // namespace VAPoR ================================================ FILE: lib/wasp/MatWaveBase.cpp ================================================ #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include using namespace VAPoR; MatWaveBase::MatWaveBase(const string &wname, const string &mode) { _wf = NULL; _mode = PER; _wname = wname; _wf = _create_wf(wname); if (!_wf) return; if (dwtmode(mode) < 0) { return; // nothing to do }; _InvalidFloatAbort = false; } MatWaveBase::MatWaveBase(const string &wname) { _wf = NULL; _mode = PER; _wname = wname; _wf = _create_wf(wname); if (!_wf) return; string wmode; if ((_wname.compare("bior1.1") == 0) || (_wname.compare("bior1.3") == 0) || (_wname.compare("bior1.5") == 0) || (_wname.compare("bior3.3") == 0) || (_wname.compare("bior3.5") == 0) || (_wname.compare("bior3.7") == 0) || (_wname.compare("bior3.9") == 0)) { wmode = "symh"; } else if ((_wname.compare("bior2.2") == 0) || (_wname.compare("bior2.4") == 0) || (_wname.compare("bior2.6") == 0) || (_wname.compare("bior2.8") == 0) || (_wname.compare("bior4.4") == 0) || (_wname.compare("intbior2.2") == 0)) { wmode = "symw"; } else { wmode = "sp0"; } if (dwtmode(wmode) < 0) { return; // nothing to do }; _InvalidFloatAbort = false; } MatWaveBase::~MatWaveBase() { if (_wf) delete _wf; _wf = NULL; } int MatWaveBase::dwtmode(const string &mode) { dwtmode_t imode = _dwtmodestr2enum(mode); if (imode == INVALID) { SetErrMsg("Invalid boundary handling mode : %s", mode.c_str()); return (-1); } _mode = imode; return (0); } int MatWaveBase::dwtmode(dwtmode_t mode) { if (mode == INVALID) { SetErrMsg("Invalid boundary handling mode : %d", mode); return (-1); } _mode = mode; return (0); } int MatWaveBase::wavelet(const string &wname) { if (_wf) delete _wf; _wf = _create_wf(wname); if (!_wf) { SetErrMsg("Invalid wavelet : %s", wname.c_str()); return (-1); } return (0); } const string MatWaveBase::dwtmode() const { return (_dwtmodeenum2str(_mode)); } size_t MatWaveBase::wmaxlev(size_t s) const { size_t lev, val; if (!_wf) return (0); int waveLength = _wf->GetLength(); _wave_len_validate(s, waveLength, &lev, &val); if (!val) return (0); return (lev); } size_t MatWaveBase::detaillength(size_t sigInLen) const { if (!_wf) return (0); int filterLen = _wf->GetLength(); if (_mode == PER) { return ((size_t)ceil(((double)(sigInLen)) / 2.0)); } else if (_wf->issymmetric()) { if ((_mode == MatWaveBase::SYMW && (filterLen % 2)) || (_mode == MatWaveBase::SYMH && (!(filterLen % 2)))) { if (sigInLen % 2) { return ((sigInLen - 1) / 2); } else { return ((sigInLen) / 2); } } } return ((size_t)floor((sigInLen + filterLen - 1.0) / 2.0)); } size_t MatWaveBase::approxlength(size_t sigInLen) const { if (!_wf) return (sigInLen); int filterLen = _wf->GetLength(); if (_mode == PER) { return ((size_t)ceil(((double)(sigInLen)) / 2.0)); } else if (_wf->issymmetric()) { if ((_mode == MatWaveBase::SYMW && (filterLen % 2)) || (_mode == MatWaveBase::SYMH && (!(filterLen % 2)))) { if (sigInLen % 2) { return ((sigInLen + 1) / 2); } else { return ((sigInLen) / 2); } } } return ((size_t)floor((double)((sigInLen + filterLen - 1) / 2))); } void MatWaveBase::_wave_len_validate(size_t sigInLen, int waveLength, size_t *lev, size_t *status) const { *lev = 0; *status = 1; double d = (log((double)sigInLen / (double)(waveLength)) / log(2.0)); if (d < 0) { *status = 0; return; } *lev = (int)d + 1; } WaveFiltBase *MatWaveBase::_create_wf(const string &wname) const { WaveFiltBase *wf = NULL; if (wname.compare(0, 2, "db") == 0) { wf = new WaveFiltDaub(wname); } else if (wname.compare(0, 4, "coif") == 0) { wf = new WaveFiltCoif(wname); } else if (wname.compare(0, 4, "bior") == 0) { wf = new WaveFiltBior(wname); } else if (wname.compare(0, 4, "haar") == 0) { wf = new WaveFiltHaar(); } else if (wname.compare(0, 3, "int") == 0) { wf = new WaveFiltInt(wname); } else { return (NULL); } return (wf); } MatWaveBase::dwtmode_t MatWaveBase::_dwtmodestr2enum(const string &mode) const { if ((mode.compare("zpd") == 0) || (mode.compare("ZPD") == 0)) { return (ZPD); } else if ((mode.compare("symh") == 0) || (mode.compare("SYMH") == 0)) { return (SYMH); } else if ((mode.compare("symw") == 0) || (mode.compare("SYMW") == 0)) { return (SYMW); } else if ((mode.compare("asymh") == 0) || (mode.compare("ASYMH") == 0)) { return (ASYMH); } else if ((mode.compare("asymw") == 0) || (mode.compare("ASYMW") == 0)) { return (ASYMW); } else if ((mode.compare("sp0") == 0) || (mode.compare("SP0") == 0)) { return (SP0); } else if ((mode.compare("sp1") == 0) || (mode.compare("SP1") == 0)) { return (SP1); } else if ((mode.compare("spd") == 0) || (mode.compare("SPD") == 0)) { return (SP1); } else if ((mode.compare("ppd") == 0) || (mode.compare("PPD") == 0)) { return (PPD); } else if ((mode.compare("per") == 0) || (mode.compare("PER") == 0)) { return (PER); } else { return (INVALID); } } string MatWaveBase::_dwtmodeenum2str(dwtmode_t mode) const { switch (mode) { case ZPD: return ("zpd"); break; case SYMH: return ("symh"); break; case SYMW: return ("symw"); break; case ASYMH: return ("asymh"); break; case ASYMW: return ("asymw"); break; case SP0: return ("sp0"); break; case SP1: return ("sp1"); break; case PPD: return ("ppd"); break; case PER: return ("per"); break; default: return ("invalid"); break; } } ================================================ FILE: lib/wasp/MatWaveDwt.cpp ================================================ #include #include #include "vapor/VAssert.h" #include #include #include #include #include #ifdef WIN32 #include #define isfinite _finite #endif using namespace VAPoR; using namespace Wasp; // Notes on Symmetric Extension for Symmetric Filters from // G. Strang and T. Nguyen, "Wavelets and Filter Banks", chapter 8 // // Forward xform // ------------- // // Considerations for extention: // // 1. When to repeat first and last samples (depends on filter length, N) // 2. Where to start subsampling (depends on signal length, L) // 3. How many subsamples to keep from each channel // // W extension: reflect about t==0. I.e x(-1) == x(1) // H extension: reflect about t==-1/2. I.e x(-1) == x(0) // // Goal: have symmetric extension after subsampling // - Use W extension for odd length filter. I.e. filters symmetric about t==0 // - Use H extension for even length filter. I.e. filters symm about t==-0.5 // // With W extension the extended signal has a period of 2(L-1). The filtered // signals (low-pass and high-pass) will both be symmetric. For even L there // will be 1/2(L+1) non-redundant low pass samples, and 1/2(L-1) non-redendant // high pass samples. // // // With H extension the extended signal has a period of 2L. The lowpass // filter will be symmetric, while high-pass is anti-symmetric. // namespace { #ifdef DEBUG template void printmatrix1d(const char *msg, const T *mat, size_t nx) { fprintf(stdout, "%s\n", msg); for (size_t i = 0; i < nx; i++) { fprintf(stdout, "%-10f", (float)mat[i]); } fprintf(stdout, "\n"); } template void printmatrix2d(const char *msg, const T *mat, size_t nx, size_t ny) { fprintf(stdout, "%s\n", msg); for (size_t j = 0; j < ny; j++) { fprintf(stdout, "%-4d", j); for (size_t i = 0; i < nx; i++) { fprintf(stdout, "%-10f", (float)mat[j * nx + i]); } fprintf(stdout, "\n"); } } template void printmatrix3d(const char *msg, const T *mat, size_t nx, size_t ny, size_t nz) { fprintf(stdout, "%s\n", msg); for (size_t k = 0; k < nz; k++) { fprintf(stdout, "\n"); for (size_t j = 0; j < ny; j++) { fprintf(stdout, "%-4d", k); for (size_t i = 0; i < nx; i++) { fprintf(stdout, "%-10f", (float)mat[k * nx * ny + j * nx + i]); } fprintf(stdout, "\n"); } } } #else #define printmatrix1d(a, b, c) #define printmatrix2d(a, b, c, d) #define printmatrix3d(a, b, c, d, e) #endif /*------------------------------------------- * Signal Extending *-----------------------------------------*/ template int valid_float(T *a, size_t n, bool invalid_float_abort) { for (size_t i = 0; i < n; i++) { if (!isfinite((double)a[i])) { if (invalid_float_abort) { MatWaveDwt::SetErrMsg("Invalid floating point value : %lf", (double)a[i]); return (-1); } a[i] = 0.0; } } return (0); } template int wextend_1D_center(const T *sigIn, size_t sigInLen, U *sigOut, size_t addLen, MatWaveBase::dwtmode_t leftExtMethod, MatWaveBase::dwtmode_t rightExtMethod) { int count = 0; for (count = 0; count < addLen; count++) { sigOut[count] = 0; sigOut[count + sigInLen + addLen] = 0; } for (count = 0; count < sigInLen; count++) { sigOut[count + addLen] = sigIn[count]; } if (!addLen) return (0); switch (leftExtMethod) { case MatWaveBase::ZPD: break; case MatWaveBase::SYMH: { for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[addLen - count - 1]; } break; } case MatWaveBase::SYMW: { for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[addLen - count]; } break; } case MatWaveBase::ASYMH: { for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[addLen - count - 1] * (-1); } break; } case MatWaveBase::ASYMW: { for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[addLen - count] * (-1); } break; } case MatWaveBase::SP0: { for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[0]; } break; } case MatWaveBase::SP1: { for (count = (addLen - 1); count >= 0; count--) { sigOut[count] = sigIn[0] - (sigIn[1] - sigIn[0]) * (addLen - count); } break; } case MatWaveBase::PPD: { for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[sigInLen - addLen + count]; } break; } case MatWaveBase::PER: { if (sigInLen % 2 == 0) { for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[sigInLen - addLen + count]; } } else { sigOut[addLen - 1] = sigIn[sigInLen - 1]; addLen--; for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[sigInLen - addLen + count]; } } break; } default: break; } switch (rightExtMethod) { case MatWaveBase::ZPD: break; case MatWaveBase::SYMH: { for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen] = sigIn[sigInLen - count - 1]; } break; } case MatWaveBase::SYMW: { for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen] = sigIn[sigInLen - count - 2]; } break; } case MatWaveBase::ASYMH: { for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen] = sigIn[sigInLen - count - 1] * (-1); } break; } case MatWaveBase::ASYMW: { for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen] = sigIn[sigInLen - count - 2] * (-1); } break; } case MatWaveBase::SP0: { for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen] = sigIn[sigInLen - 1]; } break; } case MatWaveBase::SP1: { for (count = (addLen - 1); count >= 0; count--) { sigOut[sigInLen + 2 * addLen - count - 1] = sigIn[sigInLen - 1] - (sigIn[sigInLen - 2] - sigIn[sigInLen - 1]) * (addLen - count); } break; } case MatWaveBase::PPD: { for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen] = sigIn[count]; } break; } case MatWaveBase::PER: { if (sigInLen % 2 == 0) { for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen] = sigIn[count]; } } else { sigOut[addLen + sigInLen] = sigIn[sigInLen - 1]; addLen--; for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen + 2] = sigIn[count]; } } break; } default: break; } return (0); } // // Perform single-level, 1D forward wavelet transform // (convolution + downsampling) // // // The number of samples computed for both cA and cD is: sigInLen / 2 // // If oddlow is true the odd indexed low pass samples are computed (the first // input sample is ignored), else the even samples are computed. This // parameter provides control over the centering of the filter. Similar // for the oddhigh parameter. // // sigIn must contain sigInLen + filterLen + 1 samples if oddlow or oddhigh // is true, otherwise sigInLen + filterLen samples are required // // See G. Strang and T. Nguyen, "Wavelets and Filter Banks", chap 8, finite // length filters // void forward_xform(const double *sigIn, size_t sigInLen, const double *low_filter, const double *high_filter, int filterLen, double *cA, double *cD, bool oddlow, bool oddhigh) { // VAssert(sigInLen > filterLen); size_t xlstart = oddlow ? 1 : 0; size_t xl; size_t xhstart = oddhigh ? 1 : 0; size_t xh; for (size_t yi = 0; yi < sigInLen; yi += 2) { cA[yi >> 1] = cD[yi >> 1] = 0.0; xl = xlstart; xh = xhstart; for (int k = filterLen - 1; k >= 0; k--) { cA[yi >> 1] += low_filter[k] * sigIn[xl]; cD[yi >> 1] += high_filter[k] * sigIn[xh]; xl++; xh++; } xlstart += 2; xhstart += 2; } return; } void inverse_xform_even(const double *cA, const double *cD, size_t sigOutLen, const double *low_filter, const double *high_filter, int filterLen, double *sigOut, bool matlab) { size_t xi; // input and out signal indecies int k; // filter index VAssert((filterLen % 2) == 0); for (size_t yi = 0; yi < sigOutLen; yi++) { sigOut[yi] = 0.0; if (matlab || (filterLen >> 1) % 2) { // odd length half filter xi = yi >> 1; if (yi % 2) { k = filterLen - 1; } else { k = filterLen - 2; } } else { xi = (yi + 1) >> 1; if (yi % 2) { k = filterLen - 2; } else { k = filterLen - 1; } } for (; k >= 0; k -= 2) { sigOut[yi] += (low_filter[k] * cA[xi]) + (high_filter[k] * cD[xi]); xi++; } } return; } // // Inverse transform for odd length, symmetric filters. In this case // it is assumed that cA coefficients come from even indexed samples // and cD coefficients come from odd indexed samples. // // See G. Strang and T. Nguyen, "Wavelets and Filter Banks", // chap 8, finite length filters // void inverse_xform_odd(const double *cA, const double *cD, size_t sigOutLen, const double *low_filter, const double *high_filter, int filterLen, double *sigOut) { size_t xi; // input and out signal indecies int k; // filter index VAssert((filterLen % 2) == 1); for (size_t yi = 0; yi < sigOutLen; yi++) { sigOut[yi] = 0.0; xi = (yi + 1) >> 1; if (yi % 2) { k = filterLen - 2; } else { k = filterLen - 1; } for (; k >= 0; k -= 2) { sigOut[yi] += (low_filter[k] * cA[xi]); xi++; } xi = (yi) >> 1; if (yi % 2) { k = filterLen - 1; } else { k = filterLen - 2; } for (; k >= 0; k -= 2) { sigOut[yi] += (high_filter[k] * cD[xi]); xi++; } } return; } void inverse_xform(const double *cA, const double *cD, size_t sigOutLen, const double *low_filter, const double *high_filter, int filterLen, double *sigOut, bool matlab) { if (filterLen % 2) { inverse_xform_odd(cA, cD, sigOutLen, low_filter, high_filter, filterLen, sigOut); } else { inverse_xform_even(cA, cD, sigOutLen, low_filter, high_filter, filterLen, sigOut, matlab); } } #define Minimum(a, b) ((a < b) ? a : b) #define BlockSize 32 // // blocked submatrix transpose suitable for multithreading // *a : pointer to input matrix // *b : pointer to output matrix // p1,p2: starting index of submatrix (row,col) // m1,m2: size of submatrix (row,col) // s1,s2: size of entire matrix (row,col) // template void transpose(const T *a, U *b, size_t p1, size_t p2, size_t m1, size_t m2, size_t s1, size_t s2) { size_t I1, I2; size_t i1, i2; size_t q, r; double c0; const size_t block = BlockSize; for (I2 = p2; I2 < p2 + m2; I2 += block) for (I1 = p1; I1 < p1 + m1; I1 += block) for (i2 = I2; i2 < Minimum(I2 + block, p2 + m2); i2++) for (i1 = I1; i1 < Minimum(I1 + block, p1 + m1); i1++) { q = i2 * s1 + i1; r = i1 * s2 + i2; c0 = a[q]; b[r] = c0; } } // specialization for Real -> Complex // note the S1 matrix dimension is for the Real matrix // and the size of the Complex output is then s2 x (S1/2+1) // // blocked matrix transpose single threaded // *a : pointer to input matrix // *b : pointer to output matrix // s1,s2: size of entire matrix (row,col) // template void transpose(const T *a, U *b, size_t s1, size_t s2) { transpose(a, b, 0, 0, s1, s2, s1, s2); } }; // namespace MatWaveDwt::MatWaveDwt(const string &wname, const string &mode) : MatWaveBase(wname, mode) {} MatWaveDwt::MatWaveDwt(const string &wname) : MatWaveBase(wname) {} MatWaveDwt::~MatWaveDwt() {} template int dwt_template(MatWaveDwt *dwt, const T *sigIn, size_t sigInLen, const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, U *cA, U *cD, size_t L[3], SmartBuf &sbuf, V dummy) { if (!wf) { MatWaveDwt::SetErrMsg("Invalid state, no wavelet"); return (-1); } if (dwt->wmaxlev(sigInLen) < 1) { MatWaveDwt::SetErrMsg("Can't transform signal of length : %d", sigInLen); return (-1); } if (mode == MatWaveBase::PER) { MatWaveDwt::SetErrMsg("Invalid boundary extension mode: %d", mode); return (-1); } L[0] = dwt->approxlength(sigInLen); L[1] = dwt->detaillength(sigInLen); L[2] = sigInLen; int filterLen = wf->GetLength(); // // See if we can do symmetric convolution // bool do_sym_conv = false; if (wf->issymmetric()) { if ((mode == MatWaveBase::SYMW && (filterLen % 2)) || (mode == MatWaveBase::SYMH && (!(filterLen % 2)))) { do_sym_conv = true; } } // cout << "filter length " << filterLen << endl; // printmatrix1d("dwt: low pass decomp filter", wf->GetLowDecomFilCoef(), filterLen); // printmatrix1d("dwt: high pass decomp filter", wf->GetHighDecomFilCoef(), filterLen); // cout << endl; printmatrix1d("dwt: input signal", sigIn, sigInLen); // length of signal after boundary extension. We extend both // left and right boundary by the width of the filter. // size_t sigConvolvedLen = L[0] + L[1]; size_t extendLen; bool oddlow = true; bool oddhigh = true; if (filterLen % 2) oddlow = false; if (do_sym_conv) { extendLen = filterLen >> 1; if (sigInLen % 2) sigConvolvedLen += 1; } else { extendLen = filterLen - 1; } size_t sigExtendedLen = sigInLen + (2 * extendLen); V *buf = (V *)sbuf.Alloc(sizeof(dummy) * (sigExtendedLen + sigConvolvedLen)); V *sigExtended = buf; V *sigConvolved = sigExtended + sigExtendedLen; // Signal boundary extension // int rc = wextend_1D_center(sigIn, sigInLen, sigExtended, extendLen, mode, mode); if (rc < 0) return (-1); // if (is_floating_point(*sigExtended)) { if (!std::numeric_limits::is_integer) { int rc = valid_float(sigExtended, sigExtendedLen, dwt->InvalidFloatAbortOnOff()); if (rc < 0) return (-1); } printmatrix1d("dwt: extended signal", sigExtended, sigExtendedLen); // Peform either conventional or integer DWT. Assumes template V // is either a double or long. Code won't compile for V of any // other type. // if (!std::numeric_limits::is_integer) { const double *s = (double *)sigExtended; double * cAdbl = (double *)sigConvolved; double * cDdbl = (double *)sigConvolved + L[0]; forward_xform(s, L[0] + L[1], wf->GetLowDecomFilCoef(), wf->GetHighDecomFilCoef(), filterLen, cAdbl, cDdbl, oddlow, oddhigh); } else { const WaveFiltInt *wfi = dynamic_cast(wf); VAssert(wfi != NULL); const long *s = (const long *)sigExtended; long * cAlong = (long *)sigConvolved; long * cDlong = (long *)sigConvolved + L[0]; wfi->Analysis(s, L[0] + L[1], cAlong, cDlong, oddlow, oddhigh); } for (size_t i = 0; i < L[0]; i++) { cA[i] = sigConvolved[i]; } printmatrix1d("dwt: convolved lowpass signal", cA, L[0]); for (size_t i = 0; i < L[1]; i++) { cD[i] = sigConvolved[i + L[0]]; } printmatrix1d("dwt: convolved high signal", cD, L[1]); return (0); } int MatWaveDwt::dwt(const double *sigIn, size_t sigInLen, double *C, size_t L[3]) { double *cA = C; double *cD = C + approxlength(sigInLen); double dummy = 0; return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy)); } int MatWaveDwt::dwt(const float *sigIn, size_t sigInLen, float *C, size_t L[3]) { float *cA = C; float *cD = C + approxlength(sigInLen); double dummy = 0; return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy)); } int MatWaveDwt::dwt(const double *sigIn, size_t sigInLen, double *cA, double *cD, size_t L[3]) { double dummy = 0; return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy)); } int MatWaveDwt::dwt(const float *sigIn, size_t sigInLen, float *cA, float *cD, size_t L[3]) { double dummy = 0; return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy)); } int MatWaveDwt::dwt(const long *sigIn, size_t sigInLen, long *C, size_t L[3]) { long *cA = C; long *cD = C + approxlength(sigInLen); long dummy = 0; return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy)); } int MatWaveDwt::dwt(const int *sigIn, size_t sigInLen, int *C, size_t L[3]) { int *cA = C; int *cD = C + approxlength(sigInLen); long dummy = 0; return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy)); } int MatWaveDwt::dwt(const long *sigIn, size_t sigInLen, long *cA, long *cD, size_t L[3]) { long dummy = 0; return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy)); } int MatWaveDwt::dwt(const int *sigIn, size_t sigInLen, int *cA, int *cD, size_t L[3]) { long dummy = 0; return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy)); } template int idwt_template(MatWaveDwt *dwt, const T *cA, const T *cD, const size_t L[3], const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, U *sigOut, SmartBuf &sbuf, V dummy) { if (!wf) { MatWaveDwt::SetErrMsg("Invalid state, no wavelet"); return (-1); } if (mode == MatWaveBase::PER) { MatWaveDwt::SetErrMsg("Invalid boundary extension mode: %d", mode); return (-1); } int filterLen = wf->GetLength(); bool do_sym_conv = false; MatWaveBase::dwtmode_t cALeftMode = mode; MatWaveBase::dwtmode_t cARightMode = mode; MatWaveBase::dwtmode_t cDLeftMode = mode; MatWaveBase::dwtmode_t cDRightMode = mode; if (wf->issymmetric()) { if ((mode == MatWaveBase::SYMW && (filterLen % 2)) || (mode == MatWaveBase::SYMH && (!(filterLen % 2)))) { if (mode == MatWaveBase::SYMH) { cDLeftMode = MatWaveBase::ASYMH; if (L[2] % 2) { cARightMode = MatWaveBase::SYMW; cDRightMode = MatWaveBase::ASYMW; } else { cDRightMode = MatWaveBase::ASYMH; } } else { cDLeftMode = MatWaveBase::SYMH; if (L[2] % 2) { cARightMode = MatWaveBase::SYMW; cDRightMode = MatWaveBase::SYMH; } else { cARightMode = MatWaveBase::SYMH; } } do_sym_conv = true; } } size_t cATempLen, cDTempLen, reconTempLen; size_t extendLen = 0; size_t cDPadLen = 0; if (do_sym_conv) { extendLen = filterLen >> 2; if ((L[0] > L[1]) && (mode == MatWaveBase::SYMH)) cDPadLen = L[0]; cATempLen = L[0] + (2 * extendLen); if (filterLen % 2) { cDTempLen = L[1] + (2 * extendLen); } else { // cD length must be same as cA (it's not for odd length signals) // if filter is even length // cDTempLen = cATempLen; } #ifdef VAPOR3_0_0_ALPHA #endif } else { cATempLen = L[0]; cDTempLen = L[1]; } reconTempLen = L[2]; if (reconTempLen % 2) reconTempLen++; V *buf = (V *)sbuf.Alloc(sizeof(dummy) * (cATempLen + cDTempLen + reconTempLen + cDPadLen)); V *cATemp = buf; V *cDTemp = cATemp + cATempLen; V *reconTemp = cDTemp + cDTempLen; V *cDPad = reconTemp + reconTempLen; // printmatrix1d("idwt: low pass reconstruct filter", wf->GetLowReconFilCoef(), filterLen); // printmatrix1d("idwt: high pass reconstruct filter", wf->GetHighReconFilCoef(), filterLen); // cout << endl; // For symmetric filters we need to add the boundary coefficients // if (do_sym_conv) { int rc = wextend_1D_center(cA, L[0], cATemp, extendLen, cALeftMode, cARightMode); if (rc < 0) return (-1); // For odd length signals we need to add back the missing final cD // coefficient before signal extension. // See G. Strang and T. Nguyen, "Wavelets and Filter Banks", // chap 8, finite length filters // if (cDPadLen) { for (size_t i = 0; i < L[1]; i++) cDPad[i] = cD[i]; cDPad[L[1]] = 0.0; rc = wextend_1D_center(cDPad, L[0], cDTemp, extendLen, cDLeftMode, cDRightMode); if (rc < 0) return (-1); } else { rc = wextend_1D_center(cD, L[1], cDTemp, extendLen, cDLeftMode, cDRightMode); if (rc < 0) return (-1); } } else { for (size_t i = 0; i < L[0]; i++) { cATemp[i] = (V)cA[i]; } for (size_t i = 0; i < L[1]; i++) { cDTemp[i] = (V)cD[i]; } } // if (is_floating_point(*cATemp)) { if (!std::numeric_limits::is_integer) { int rc = valid_float(cATemp, cATempLen, dwt->InvalidFloatAbortOnOff()); if (rc < 0) return (-1); rc = valid_float(cDTemp, cDTempLen, dwt->InvalidFloatAbortOnOff()); if (rc < 0) return (-1); } printmatrix1d("idwt: extended cA signal", cATemp, cATempLen); printmatrix1d("idwt: extended cD signal", cDTemp, cDTempLen); if (!std::numeric_limits::is_integer) { const double *cAdbl = (const double *)cATemp; const double *cDdbl = (const double *)cDTemp; double * s = (double *)reconTemp; inverse_xform(cAdbl, cDdbl, L[2], wf->GetLowReconFilCoef(), wf->GetHighReconFilCoef(), filterLen, s, !do_sym_conv); } else { const WaveFiltInt *wfi = dynamic_cast(wf); VAssert(wfi != NULL); const long *cAlong = (const long *)cATemp; const long *cDlong = (const long *)cDTemp; long * s = (long *)reconTemp; wfi->Synthesis(cAlong, cDlong, L[0], s); } for (size_t count = 0; count < L[2]; count++) { sigOut[count] = (U)reconTemp[count]; } printmatrix1d("idwt: reconstructed signal", sigOut, L[2]); return (0); } int MatWaveDwt::idwt(const double *C, const size_t L[3], double *sigOut) { const double *cA = C; const double *cD = C + L[0]; double dummy = 0; return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt(const float *C, const size_t L[3], float *sigOut) { const float *cA = C; const float *cD = C + L[0]; double dummy = 0; return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt(const double *cA, const double *cD, const size_t L[3], double *sigOut) { double dummy = 0; return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt(const float *cA, const float *cD, const size_t L[3], float *sigOut) { double dummy = 0; return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt(const long *C, const size_t L[3], long *sigOut) { const long *cA = C; const long *cD = C + L[0]; long dummy = 0; return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt(const int *C, const size_t L[3], int *sigOut) { const int *cA = C; const int *cD = C + L[0]; long dummy = 0; return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt(const long *cA, const long *cD, const size_t L[3], long *sigOut) { long dummy = 0; return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt(const int *cA, const int *cD, const size_t L[3], int *sigOut) { long dummy = 0; return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy); } template int dwt2d_template(MatWaveDwt *dwt, const T *sigIn, size_t sigInX, size_t sigInY, const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, U *cA, U *cDh, U *cDv, U *cDd, size_t L[10], SmartBuf &sbuf2d, SmartBuf &sbuf1d, V dummy) { if (!wf) { MatWaveDwt::SetErrMsg("Invalid state, no wavelet"); return (-1); } // // Store dimensions of cA, cDh, cDv, cDd, and original signal // in book keeping vector, L // // N.B. // L[0] == L[2] // L[1] == L[5] // L[3] == L[7] // L[4] == L[6] // // // ____L[0]_______L[4]____ // | | | // L[1] | cA | cDv | L[5] // | (LL) | (HL) | // | | | // |---------------------| // | | | // | cDh | cDd | L[7] // L[3] | (LH) | (HH) | // | | | // |__________|__________| // L[2] L[6] L[0] = dwt->approxlength(sigInX); L[1] = dwt->approxlength(sigInY); // cA L[2] = dwt->approxlength(sigInX); L[3] = dwt->detaillength(sigInY); // cDh L[4] = dwt->detaillength(sigInX); L[5] = dwt->approxlength(sigInY); // cDv L[6] = dwt->detaillength(sigInX); L[7] = dwt->detaillength(sigInY); // cDd L[8] = sigInX; L[9] = sigInY; // First: transform rows // size_t passXLen = (L[0] + L[4]) * sigInY; size_t transposeLen = max(L[0], L[4]) * sigInY; size_t passYLen = max(L[0], L[4]) * (L[1] + L[3]); V *buf2d = (V *)sbuf2d.Alloc(sizeof(dummy) * (passXLen + transposeLen + passYLen)); V *cAXbuf = buf2d; V *cDXbuf = cAXbuf + (L[0] * sigInY); V *buftranspose = cAXbuf + passXLen; V *cAYbuf = buftranspose + transposeLen; V *cDYbuf = cAYbuf + (max(L[0], L[4]) * L[1]); int rc; for (size_t y = 0; y < sigInY; y++) { size_t xL[3]; const T *row = &sigIn[sigInX * y]; V * cAptr = &cAXbuf[L[0] * y]; V * cDptr = &cDXbuf[L[4] * y]; rc = dwt_template(dwt, row, sigInX, wf, mode, cAptr, cDptr, xL, sbuf1d, dummy); if (rc < 0) return (-1); } // Second: transform columns. First approximation coefficients, then // detail coefficients // transpose(cAXbuf, buftranspose, L[0], sigInY); for (size_t y = 0; y < L[0]; y++) { size_t yL[3]; const V *row = &buftranspose[sigInY * y]; V * cAptr = &cAYbuf[L[1] * y]; V * cDptr = &cDYbuf[L[3] * y]; rc = dwt_template(dwt, row, sigInY, wf, mode, cAptr, cDptr, yL, sbuf1d, dummy); if (rc < 0) return (-1); } transpose(cAYbuf, cA, L[1], L[0]); transpose(cDYbuf, cDh, L[3], L[2]); printmatrix2d("cA", cA, L[0], L[1]); printmatrix2d("cDh", cDh, L[2], L[3]); // Now detail coefficients // // transpose(cDXbuf, buftranspose, L[4], sigInY); for (size_t y = 0; y < L[4]; y++) { size_t yL[3]; const V *row = &buftranspose[sigInY * y]; V * cAptr = &cAYbuf[L[1] * y]; V * cDptr = &cDYbuf[L[3] * y]; rc = dwt_template(dwt, row, sigInY, wf, mode, cAptr, cDptr, yL, sbuf1d, dummy); if (rc < 0) return (-1); } transpose(cAYbuf, cDv, L[5], L[4]); transpose(cDYbuf, cDd, L[7], L[6]); printmatrix2d("cDv", cDv, L[4], L[5]); printmatrix2d("cDd", cDd, L[6], L[7]); return (0); } int MatWaveDwt::dwt2d(const double *sigIn, size_t sigInX, size_t sigInY, double *C, size_t L[10]) { double *cA = C; double *cDh = cA + (approxlength(sigInX) * approxlength(sigInY)); double *cDv = cDh + (approxlength(sigInX) * detaillength(sigInY)); double *cDd = cDv + (detaillength(sigInX) * approxlength(sigInY)); double dummy = 0; return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::dwt2d(const float *sigIn, size_t sigInX, size_t sigInY, float *C, size_t L[10]) { float *cA = C; float *cDh = cA + (approxlength(sigInX) * approxlength(sigInY)); float *cDv = cDh + (approxlength(sigInX) * detaillength(sigInY)); float *cDd = cDv + (detaillength(sigInX) * approxlength(sigInY)); double dummy = 0; return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::dwt2d(const double *sigIn, size_t sigInX, size_t sigInY, double *cA, double *cDh, double *cDv, double *cDd, size_t L[10]) { double dummy = 0; return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::dwt2d(const float *sigIn, size_t sigInX, size_t sigInY, float *cA, float *cDh, float *cDv, float *cDd, size_t L[10]) { double dummy = 0; return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::dwt2d(const long *sigIn, size_t sigInX, size_t sigInY, long *C, size_t L[10]) { long *cA = C; long *cDh = cA + (approxlength(sigInX) * approxlength(sigInY)); long *cDv = cDh + (approxlength(sigInX) * detaillength(sigInY)); long *cDd = cDv + (detaillength(sigInX) * approxlength(sigInY)); long dummy = 0; return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::dwt2d(const int *sigIn, size_t sigInX, size_t sigInY, int *C, size_t L[10]) { int *cA = C; int *cDh = cA + (approxlength(sigInX) * approxlength(sigInY)); int *cDv = cDh + (approxlength(sigInX) * detaillength(sigInY)); int *cDd = cDv + (detaillength(sigInX) * approxlength(sigInY)); long dummy = 0; return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::dwt2d(const long *sigIn, size_t sigInX, size_t sigInY, long *cA, long *cDh, long *cDv, long *cDd, size_t L[10]) { long dummy = 0; return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::dwt2d(const int *sigIn, size_t sigInX, size_t sigInY, int *cA, int *cDh, int *cDv, int *cDd, size_t L[10]) { long dummy = 0; return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } template int idwt2d_template(MatWaveDwt *dwt, const T *cA, const T *cDh, const T *cDv, const T *cDd, const size_t L[10], const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, U *sigOut, SmartBuf &sbuf2d, SmartBuf &sbuf1d, V dummy) { if (!wf) { MatWaveDwt::SetErrMsg("Invalid state, no wavelet"); return (-1); } size_t passYLen = max(L[0], L[4]) * (L[1] + L[3]); size_t transposeLen = max(L[0], L[4]) * L[9]; size_t passXLen = (L[0] + L[4]) * L[9]; V *buf2d = (V *)sbuf2d.Alloc(sizeof(dummy) * (passYLen + transposeLen + passXLen)); V *cAYbuf = buf2d; V *cDYbuf = cAYbuf + (max(L[0], L[4]) * L[1]); V *buftranspose = cAYbuf + passYLen; V *cAXbuf = buftranspose + transposeLen; V *cDXbuf = cAXbuf + (L[0] * L[9]); // First: transform columns. First detail coefficients, then // approximation coefficients // // cDv and cDd detail coefficients // transpose(cDv, cAYbuf, L[4], L[1]); transpose(cDd, cDYbuf, L[4], L[3]); int rc; for (size_t y = 0; y < L[4]; y++) { size_t yL[3] = {L[1], L[3], L[9]}; const V *cAptr = &cAYbuf[L[1] * y]; const V *cDptr = &cDYbuf[L[3] * y]; V * row = &buftranspose[L[9] * y]; rc = idwt_template(dwt, cAptr, cDptr, yL, wf, mode, row, sbuf1d, dummy); if (rc < 0) return (-1); } transpose(buftranspose, cDXbuf, L[9], L[4]); // printmatrix2d("cDXbuf", cDXbuf, L[4], L[9]); // cA approximation and cDh detail coefficients // transpose(cA, cAYbuf, L[0], L[1]); transpose(cDh, cDYbuf, L[0], L[3]); for (size_t y = 0; y < L[0]; y++) { size_t yL[3] = {L[1], L[3], L[9]}; const V *cAptr = &cAYbuf[L[1] * y]; const V *cDptr = &cDYbuf[L[3] * y]; V * row = &buftranspose[L[9] * y]; rc = idwt_template(dwt, cAptr, cDptr, yL, wf, mode, row, sbuf1d, dummy); if (rc < 0) return (-1); } transpose(buftranspose, cAXbuf, L[9], L[0]); // // Second: tranform rows // for (size_t y = 0; y < L[9]; y++) { size_t xL[3] = {L[0], L[4], L[8]}; const V *cAptr = &cAXbuf[L[0] * y]; const V *cDptr = &cDXbuf[L[4] * y]; U * row = &sigOut[L[8] * y]; rc = idwt_template(dwt, cAptr, cDptr, xL, wf, mode, row, sbuf1d, dummy); if (rc < 0) return (-1); } return (0); } int MatWaveDwt::idwt2d(const double *C, const size_t L[10], double *sigOut) { const double *cA = C; const double *cDh = cA + (L[0] * L[1]); const double *cDv = cDh + (L[2] * L[3]); const double *cDd = cDv + (L[4] * L[5]); double dummy = 0; return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt2d(const float *C, const size_t L[10], float *sigOut) { const float *cA = C; const float *cDh = cA + (L[0] * L[1]); const float *cDv = cDh + (L[2] * L[3]); const float *cDd = cDv + (L[4] * L[5]); double dummy = 0; return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt2d(const double *cA, const double *cDh, const double *cDv, const double *cDd, const size_t L[10], double *sigOut) { double dummy = 0; return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt2d(const float *cA, const float *cDh, const float *cDv, const float *cDd, const size_t L[10], float *sigOut) { double dummy = 0; return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt2d(const long *C, const size_t L[10], long *sigOut) { const long *cA = C; const long *cDh = cA + (L[0] * L[1]); const long *cDv = cDh + (L[2] * L[3]); const long *cDd = cDv + (L[4] * L[5]); long dummy = 0; return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt2d(const int *C, const size_t L[10], int *sigOut) { const int *cA = C; const int *cDh = cA + (L[0] * L[1]); const int *cDv = cDh + (L[2] * L[3]); const int *cDd = cDv + (L[4] * L[5]); long dummy = 0; return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt2d(const long *cA, const long *cDh, const long *cDv, const long *cDd, const size_t L[10], long *sigOut) { long dummy = 0; return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt2d(const int *cA, const int *cDh, const int *cDv, const int *cDd, const size_t L[10], int *sigOut) { long dummy = 0; return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } template int _dwtz_template(MatWaveDwt *dwt, V *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, T *cA, T *cD, SmartBuf &sbuf3d, SmartBuf &sbuf1d, V dummy) { if (!wf) { MatWaveDwt::SetErrMsg("Invalid state, no wavelet"); return (-1); } size_t cALen = dwt->approxlength(sigInZ); size_t cDLen = dwt->detaillength(sigInZ); size_t sigInLen = sigInX * sigInY * sigInZ; size_t sigOutLen = sigInX * sigInY * (cALen + cDLen); V *buf3d = (V *)sbuf3d.Alloc(sizeof(dummy) * (sigInLen + sigOutLen)); V *sigtranspose = buf3d; V *cAbuf = sigtranspose + sigInLen; V *cDbuf = cAbuf + (sigInX * sigInY * cALen); // XZ plane transpose // transpose(sigIn, sigtranspose, sigInX * sigInY, sigInZ); int rc; for (size_t z = 0; z < sigInX; z++) { for (size_t y = 0; y < sigInY; y++) { size_t L[3]; const V *row = &sigtranspose[sigInY * sigInZ * z + y * sigInZ]; V * cAptr = &cAbuf[sigInY * cALen * z + y * cALen]; V * cDptr = &cDbuf[sigInY * cDLen * z + y * cDLen]; rc = dwt_template(dwt, row, sigInZ, wf, mode, cAptr, cDptr, L, sbuf1d, dummy); if (rc < 0) return (-1); } } // // now inverse transpose to restore original memory order // transpose(cAbuf, cA, cALen, sigInX * sigInY); transpose(cDbuf, cD, cDLen, sigInX * sigInY); return (0); } template int dwt3d_template(MatWaveDwt *dwt, const T *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, T *C, size_t L[27], SmartBuf &sbuf3d1, SmartBuf &sbuf3d2, SmartBuf &sbuf2d, SmartBuf &sbuf1d, V dummy) { if (!wf) { MatWaveDwt::SetErrMsg("Invalid state, no wavelet"); return (-1); } // // Store dimensions of LLL, LLH, LHL, LHH, HLL, // HLH, HHL, HHH // in book keeping vector, L // // L[3] L[15] // ----------------------- // / / /| // L[5] / / / | // / LLH / HLH / | // / / / | L[16] // ----------------------- | // / / /| | // L[2] / / / | /| // / / / | / | // /___L[0]___/___L[12]__/ | / | L[22] // | | | |/ | // L[1] | | | /HHH / // | LLL | HLL | /| / // | | | / | / L[23] // |---------------------|/ | / // | | | |/ // | | | / // L[7] | LHL | HHL | / // | | | / L[20] // |__________|__________|/ // L[6] L[18] // LLL // L[0] = dwt->approxlength(sigInX); L[1] = dwt->approxlength(sigInY); L[2] = dwt->approxlength(sigInZ); // LLH // L[3] = dwt->approxlength(sigInX); L[4] = dwt->approxlength(sigInY); L[5] = dwt->detaillength(sigInZ); // LHL // L[6] = dwt->approxlength(sigInX); L[7] = dwt->detaillength(sigInY); L[8] = dwt->approxlength(sigInZ); // LHH // L[9] = dwt->approxlength(sigInX); L[10] = dwt->detaillength(sigInY); L[11] = dwt->detaillength(sigInZ); // HLL // L[12] = dwt->detaillength(sigInX); L[13] = dwt->approxlength(sigInY); L[14] = dwt->approxlength(sigInZ); // HLH // L[15] = dwt->detaillength(sigInX); L[16] = dwt->approxlength(sigInY); L[17] = dwt->detaillength(sigInZ); // HHL // L[18] = dwt->detaillength(sigInX); L[19] = dwt->detaillength(sigInY); L[20] = dwt->approxlength(sigInZ); // HHH // L[21] = dwt->detaillength(sigInX); L[22] = dwt->detaillength(sigInY); L[23] = dwt->detaillength(sigInZ); L[24] = sigInX; L[25] = sigInY; L[26] = sigInZ; T *cLLL = C; T *cLLH = cLLL + L[0] * L[1] * L[2]; T *cLHL = cLLH + L[3] * L[4] * L[5]; T *cLHH = cLHL + L[6] * L[7] * L[8]; T *cHLL = cLHH + L[9] * L[10] * L[11]; T *cHLH = cHLL + L[12] * L[13] * L[14]; T *cHHL = cHLH + L[15] * L[16] * L[17]; T *cHHH = cHHL + L[18] * L[19] * L[20]; // First: transform XY planes // size_t passXYLen = (L[0] + L[12]) * (L[1] + L[7]) * sigInZ; V *buf3d1 = (V *)sbuf3d1.Alloc(sizeof(dummy) * passXYLen); V *xyC = buf3d1; V *cAXYbuf = xyC; V *cDhXYbuf = cAXYbuf + (L[0] * L[1] * sigInZ); V *cDvXYbuf = cDhXYbuf + (L[6] * L[7] * sigInZ); V *cDdXYbuf = cDvXYbuf + (L[12] * L[13] * sigInZ); int rc; for (size_t z = 0; z < sigInZ; z++) { size_t xyL[10]; const T *plane = &sigIn[sigInX * sigInY * z]; V * cAptr = &cAXYbuf[L[0] * L[1] * z]; V * cDhptr = &cDhXYbuf[L[6] * L[7] * z]; V * cDvptr = &cDvXYbuf[L[12] * L[13] * z]; V * cDdptr = &cDdXYbuf[L[18] * L[19] * z]; rc = dwt2d_template(dwt, plane, sigInX, sigInY, wf, mode, cAptr, cDhptr, cDvptr, cDdptr, xyL, sbuf2d, sbuf1d, dummy); if (rc < 0) return (rc); } // Second: transform along Z // rc = _dwtz_template(dwt, cAXYbuf, L[0], L[1], sigInZ, wf, mode, cLLL, cLLH, sbuf3d2, sbuf1d, dummy); if (rc < 0) return (rc); printmatrix3d("cLLL", cLLL, L[0], L[1], L[2]); printmatrix3d("cLLH", cLLH, L[3], L[4], L[5]); rc = _dwtz_template(dwt, cDhXYbuf, L[6], L[7], sigInZ, wf, mode, cLHL, cLHH, sbuf3d2, sbuf1d, dummy); if (rc < 0) return (rc); printmatrix3d("cLHL", cLHL, L[6], L[7], L[8]); printmatrix3d("cLHH", cLHH, L[9], L[10], L[11]); rc = _dwtz_template(dwt, cDvXYbuf, L[12], L[13], sigInZ, wf, mode, cHLL, cHLH, sbuf3d2, sbuf1d, dummy); if (rc < 0) return (rc); printmatrix3d("cHLL", cHLL, L[12], L[13], L[14]); printmatrix3d("cHLH", cHLH, L[15], L[16], L[17]); rc = _dwtz_template(dwt, cDdXYbuf, L[18], L[19], sigInZ, wf, mode, cHHL, cHHH, sbuf3d2, sbuf1d, dummy); if (rc < 0) return (rc); printmatrix3d("cHHL", cHHL, L[18], L[19], L[20]); printmatrix3d("cHHH", cHHH, L[21], L[22], L[23]); return (0); } int MatWaveDwt::dwt3d(const double *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, double *C, size_t L[27]) { double dummy = 0.0; return dwt3d_template(this, sigIn, sigInX, sigInY, sigInZ, wavelet(), dwtmodeenum(), C, L, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::dwt3d(const float *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, float *C, size_t L[27]) { double dummy = 0.0; return dwt3d_template(this, sigIn, sigInX, sigInY, sigInZ, wavelet(), dwtmodeenum(), C, L, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::dwt3d(const long *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, long *C, size_t L[27]) { long dummy = 0.0; return dwt3d_template(this, sigIn, sigInX, sigInY, sigInZ, wavelet(), dwtmodeenum(), C, L, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::dwt3d(const int *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int *C, size_t L[27]) { long dummy = 0.0; return dwt3d_template(this, sigIn, sigInX, sigInY, sigInZ, wavelet(), dwtmodeenum(), C, L, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } template int _idwtz_template(MatWaveDwt *dwt, T *cA, T *cD, size_t sigInX, size_t sigInY, size_t cALen, size_t cDLen, const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, V *sigOut, size_t sigOutZ, SmartBuf &sbuf3d, SmartBuf &sbuf1d, V dummy) { if (!wf) { MatWaveDwt::SetErrMsg("Invalid state, no wavelet"); return (-1); } size_t sigInLen = sigInX * sigInY * (cALen + cDLen); size_t sigOutLen = sigInX * sigInY * sigOutZ; V *buf3d = (V *)sbuf3d.Alloc(sizeof(dummy) * (sigInLen + sigOutLen)); V *cAtranspose = buf3d; V *cDtranspose = buf3d + (sigInX * sigInY * cALen); V *sigtranspose = cAtranspose + sigInLen; // // transpose to Z memory order // transpose(cA, cAtranspose, sigInX * sigInY, cALen); transpose(cD, cDtranspose, sigInX * sigInY, cDLen); int rc; for (size_t z = 0; z < sigInX; z++) { for (size_t y = 0; y < sigInY; y++) { size_t zL[3] = {cALen, cDLen, sigOutZ}; const V *cAptr = &cAtranspose[sigInY * cALen * z + y * cALen]; const V *cDptr = &cDtranspose[sigInY * cDLen * z + y * cDLen]; V * row = &sigtranspose[sigInY * sigOutZ * z + y * sigOutZ]; rc = idwt_template(dwt, cAptr, cDptr, zL, wf, mode, row, sbuf1d, dummy); if (rc < 0) return (-1); } } // Inverse transpose back to X memory order // transpose(sigtranspose, sigOut, sigOutZ, sigInY * sigInX); return (0); } template int idwt3d_template(MatWaveDwt *dwt, const T *cLLL, const T *cLLH, const T *cLHL, const T *cLHH, const T *cHLL, const T *cHLH, const T *cHHL, const T *cHHH, const size_t L[27], const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, U *sigOut, SmartBuf &sbuf3d1, SmartBuf &sbuf3d2, SmartBuf &sbuf2d, SmartBuf &sbuf1d, V dummy) { if (!wf) { MatWaveDwt::SetErrMsg("Invalid state, no wavelet"); return (-1); } size_t passXYLen = (L[0] + L[12]) * (L[1] + L[7]) * L[26]; V *buf3d1 = (V *)sbuf3d1.Alloc(sizeof(dummy) * passXYLen); V *xyC = buf3d1; V *cAXYbuf = xyC; V *cDhXYbuf = cAXYbuf + (L[0] * L[1] * L[26]); V *cDvXYbuf = cDhXYbuf + (L[6] * L[7] * L[26]); V *cDdXYbuf = cDvXYbuf + (L[12] * L[13] * L[26]); // First: inverse transform along Z // int rc; rc = _idwtz_template(dwt, cLLL, cLLH, L[0], L[1], L[2], L[5], wf, mode, cAXYbuf, L[26], sbuf3d2, sbuf1d, dummy); if (rc < 0) return (-1); rc = _idwtz_template(dwt, cLHL, cLHH, L[6], L[7], L[8], L[11], wf, mode, cDhXYbuf, L[26], sbuf3d2, sbuf1d, dummy); if (rc < 0) return (-1); rc = _idwtz_template(dwt, cHLL, cHLH, L[12], L[13], L[14], L[17], wf, mode, cDvXYbuf, L[26], sbuf3d2, sbuf1d, dummy); if (rc < 0) return (-1); rc = _idwtz_template(dwt, cHHL, cHHH, L[18], L[19], L[20], L[23], wf, mode, cDdXYbuf, L[26], sbuf3d2, sbuf1d, dummy); if (rc < 0) return (-1); // Second: inverse transform XY planes // size_t xyL[10] = {L[0], L[1], L[6], L[7], L[12], L[13], L[18], L[19], L[24], L[25]}; for (size_t z = 0; z < L[26]; z++) { const V *cAptr = &cAXYbuf[L[0] * L[1] * z]; const V *cDhptr = &cDhXYbuf[L[6] * L[7] * z]; const V *cDvptr = &cDvXYbuf[L[12] * L[13] * z]; const V *cDdptr = &cDdXYbuf[L[18] * L[19] * z]; U * plane = &sigOut[L[24] * L[25] * z]; rc = idwt2d_template(dwt, cAptr, cDhptr, cDvptr, cDdptr, xyL, wf, mode, plane, sbuf2d, sbuf1d, dummy); if (rc < 0) return (-1); } return (0); } int MatWaveDwt::idwt3d(const double *C, const size_t L[27], double *sigOut) { const double *cLLL = C; const double *cLLH = cLLL + L[0] * L[1] * L[2]; const double *cLHL = cLLH + L[3] * L[4] * L[5]; const double *cLHH = cLHL + L[6] * L[7] * L[8]; const double *cHLL = cLHH + L[9] * L[10] * L[11]; const double *cHLH = cHLL + L[12] * L[13] * L[14]; const double *cHHL = cHLH + L[15] * L[16] * L[17]; const double *cHHH = cHHL + L[18] * L[19] * L[20]; double dummy = 0.0; return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt3d(const float *C, const size_t L[27], float *sigOut) { const float *cLLL = C; const float *cLLH = cLLL + L[0] * L[1] * L[2]; const float *cLHL = cLLH + L[3] * L[4] * L[5]; const float *cLHH = cLHL + L[6] * L[7] * L[8]; const float *cHLL = cLHH + L[9] * L[10] * L[11]; const float *cHLH = cHLL + L[12] * L[13] * L[14]; const float *cHHL = cHLH + L[15] * L[16] * L[17]; const float *cHHH = cHHL + L[18] * L[19] * L[20]; double dummy = 0.0; return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt3d(const double *cLLL, const double *cLLH, const double *cLHL, const double *cLHH, const double *cHLL, const double *cHLH, const double *cHHL, const double *cHHH, const size_t L[27], double *sigOut) { double dummy = 0.0; return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt3d(const float *cLLL, const float *cLLH, const float *cLHL, const float *cLHH, const float *cHLL, const float *cHLH, const float *cHHL, const float *cHHH, const size_t L[27], float *sigOut) { double dummy = 0.0; return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt3d(const long *C, const size_t L[27], long *sigOut) { const long *cLLL = C; const long *cLLH = cLLL + L[0] * L[1] * L[2]; const long *cLHL = cLLH + L[3] * L[4] * L[5]; const long *cLHH = cLHL + L[6] * L[7] * L[8]; const long *cHLL = cLHH + L[9] * L[10] * L[11]; const long *cHLH = cHLL + L[12] * L[13] * L[14]; const long *cHHL = cHLH + L[15] * L[16] * L[17]; const long *cHHH = cHHL + L[18] * L[19] * L[20]; long dummy = 0.0; return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt3d(const int *C, const size_t L[27], int *sigOut) { const int *cLLL = C; const int *cLLH = cLLL + L[0] * L[1] * L[2]; const int *cLHL = cLLH + L[3] * L[4] * L[5]; const int *cLHH = cLHL + L[6] * L[7] * L[8]; const int *cHLL = cLHH + L[9] * L[10] * L[11]; const int *cHLH = cHLL + L[12] * L[13] * L[14]; const int *cHHL = cHLH + L[15] * L[16] * L[17]; const int *cHHH = cHHL + L[18] * L[19] * L[20]; long dummy = 0.0; return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt3d(const long *cLLL, const long *cLLH, const long *cLHL, const long *cLHH, const long *cHLL, const long *cHLH, const long *cHHL, const long *cHHH, const size_t L[27], long *sigOut) { long dummy = 0.0; return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } int MatWaveDwt::idwt3d(const int *cLLL, const int *cLLH, const int *cLHL, const int *cLHH, const int *cHLL, const int *cHLH, const int *cHHL, const int *cHHH, const size_t L[27], int *sigOut) { long dummy = 0.0; return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy); } ================================================ FILE: lib/wasp/MatWaveWavedec.cpp ================================================ #include #include "vapor/VAssert.h" #include #include #include using namespace VAPoR; MatWaveWavedec::MatWaveWavedec(const string &wname, const string &mode) : MatWaveDwt(wname, mode) {} MatWaveWavedec::MatWaveWavedec(const string &wname) : MatWaveDwt(wname) {} MatWaveWavedec::~MatWaveWavedec() {} template int wavedec_template(MatWaveWavedec *mww, const T *sigIn, size_t sigInLength, int n, T *C, size_t *L) { if (!mww->wavelet()) { MatWaveWavedec::SetErrMsg("Invalid state, no wavelet"); return (-1); } if (n < 0 || n > mww->wmaxlev(sigInLength)) { MatWaveWavedec::SetErrMsg("Invalid number of transforms : %d", n); return (-1); } // // Compute bookkeeping vector, L, and length of output vector, C // mww->computeL(sigInLength, n, L); size_t CLength = mww->coefflength(L, n); if (n == 0) { for (size_t i = 0; i < sigInLength; i++) C[i] = sigIn[i]; return (0); } int rc; const T *sigInPtr = sigIn; size_t len = sigInLength; size_t cALen = mww->MatWaveBase::approxlength(len); T * cptr; size_t tlen = 0; size_t L1d[3]; for (int i = n; i > 0; i--) { tlen += L[i]; cptr = C + CLength - tlen - cALen; rc = mww->dwt(sigInPtr, len, cptr, L1d); if (rc < 0) return (rc); len = cALen; cALen = mww->MatWaveBase::approxlength(cALen); sigInPtr = cptr; } return (0); } int MatWaveWavedec::wavedec(const double *sigIn, size_t sigInLength, int n, double *C, size_t *L) { return wavedec_template(this, sigIn, sigInLength, n, C, L); } int MatWaveWavedec::wavedec(const float *sigIn, size_t sigInLength, int n, float *C, size_t *L) { return wavedec_template(this, sigIn, sigInLength, n, C, L); } int MatWaveWavedec::wavedec(const long *sigIn, size_t sigInLength, int n, long *C, size_t *L) { return wavedec_template(this, sigIn, sigInLength, n, C, L); } int MatWaveWavedec::wavedec(const int *sigIn, size_t sigInLength, int n, int *C, size_t *L) { return wavedec_template(this, sigIn, sigInLength, n, C, L); } template int waverec_template(MatWaveWavedec *mww, const T *C, const size_t *L, int n, int l, bool normal, T *sigOut) { if (!mww->wavelet()) { MatWaveWavedec::SetErrMsg("Invalid state, no wavelet"); return (-1); } if (n < 0) { MatWaveWavedec::SetErrMsg("Invalid number of transforms : %d", n); return (-1); } if (l < 0 || l > n) l = n; int LLength = n + 2; if (l == 0) { double scale = 1.0; if (normal) { for (int i = l; i < n; i++) scale /= sqrt(2.0); } for (size_t i = 0; i < L[0]; i++) sigOut[i] = scale * C[i]; return (0); } const T *cA = C; const T *cD = cA + L[0]; size_t L1d[3] = {L[0], L[1], 0}; for (int i = 1; i <= l; i++) { L1d[2] = mww->approxlength(L[LLength - 1], n - i); int rc = mww->idwt(cA, cD, L1d, sigOut); if (rc < 0) return (rc); if (i == l) break; cA = sigOut; cD += L[i]; L1d[0] = L1d[2]; L1d[1] = L[i + 1]; } if (l != n && normal) { double scale = 1.0; for (int i = l; i < n; i++) scale /= sqrt(2.0); for (size_t i = 0; i < L1d[2]; i++) sigOut[i] *= scale; } return (0); } int MatWaveWavedec::waverec(const double *C, const size_t *L, int n, double *sigOut) { return waverec_template(this, C, L, n, n, false, sigOut); } int MatWaveWavedec::waverec(const float *C, const size_t *L, int n, float *sigOut) { return waverec_template(this, C, L, n, n, false, sigOut); } int MatWaveWavedec::waverec(const long *C, const size_t *L, int n, long *sigOut) { return waverec_template(this, C, L, n, n, false, sigOut); } int MatWaveWavedec::waverec(const int *C, const size_t *L, int n, int *sigOut) { return waverec_template(this, C, L, n, n, false, sigOut); } int MatWaveWavedec::appcoef(const double *C, const size_t *L, int n, int l, bool normal, double *sigOut) { return waverec_template(this, C, L, n, l, normal, sigOut); } int MatWaveWavedec::appcoef(const float *C, const size_t *L, int n, int l, bool normal, float *sigOut) { return waverec_template(this, C, L, n, l, normal, sigOut); } int MatWaveWavedec::appcoef(const long *C, const size_t *L, int n, int l, bool normal, long *sigOut) { return waverec_template(this, C, L, n, l, normal, sigOut); } int MatWaveWavedec::appcoef(const int *C, const size_t *L, int n, int l, bool normal, int *sigOut) { return waverec_template(this, C, L, n, l, normal, sigOut); } template int wavedec2_template(MatWaveWavedec *mww, const T *sigIn, size_t sigInX, size_t sigInY, int n, T *C, size_t *L) { if (!mww->wavelet()) { MatWaveWavedec::SetErrMsg("Invalid state, no wavelet"); return (-1); } if (n < 0 || n > min(mww->wmaxlev(sigInX), mww->wmaxlev(sigInY))) { MatWaveWavedec::SetErrMsg("Invalid number of transforms : %d", n); return (-1); } mww->computeL2(sigInX, sigInY, n, L); size_t CLength = mww->coefflength2(L, n); if (n == 0) { for (size_t j = 0; j < sigInY; j++) { for (size_t i = 0; i < sigInX; i++) { *C++ = *sigIn++; } } return (0); } int rc; const T *sigInPtr = sigIn; size_t lenx = sigInX; size_t leny = sigInY; size_t cALenX = mww->MatWaveBase::approxlength(sigInX); size_t cALenY = mww->MatWaveBase::approxlength(sigInY); T * cptr; size_t tlen = 0; size_t L2d[10]; for (int i = n; i > 0; i--) { tlen += (L[(6 * i) - 4] * L[(6 * i) - 3]) + // cDh (L[(6 * i) - 2] * L[(6 * i) - 1]) + // cDv (L[(6 * i) + 0] * L[(6 * i) + 1]); // cDd cptr = C + CLength - tlen - (cALenX * cALenY); rc = mww->dwt2d(sigInPtr, lenx, leny, cptr, L2d); if (rc < 0) return (rc); lenx = cALenX; leny = cALenY; cALenX = mww->MatWaveBase::approxlength(cALenX); cALenY = mww->MatWaveBase::approxlength(cALenY); sigInPtr = cptr; } return (0); } int MatWaveWavedec::wavedec2(const double *sigIn, size_t sigInX, size_t sigInY, int n, double *C, size_t *L) { return wavedec2_template(this, sigIn, sigInX, sigInY, n, C, L); } int MatWaveWavedec::wavedec2(const float *sigIn, size_t sigInX, size_t sigInY, int n, float *C, size_t *L) { return wavedec2_template(this, sigIn, sigInX, sigInY, n, C, L); } int MatWaveWavedec::wavedec2(const long *sigIn, size_t sigInX, size_t sigInY, int n, long *C, size_t *L) { return wavedec2_template(this, sigIn, sigInX, sigInY, n, C, L); } int MatWaveWavedec::wavedec2(const int *sigIn, size_t sigInX, size_t sigInY, int n, int *C, size_t *L) { return wavedec2_template(this, sigIn, sigInX, sigInY, n, C, L); } template int waverec2_template(MatWaveWavedec *mww, const T *C, const size_t *L, int n, int l, bool normal, T *sigOut) { if (!mww->wavelet()) { MatWaveWavedec::SetErrMsg("Invalid state, no wavelet"); return (-1); } if (n < 0) { MatWaveWavedec::SetErrMsg("Invalid number of transforms : %d", n); return (-1); } if (l < 0 || l > n) l = n; int LLength = 6 * n + 4; if (l == 0) { double scale = 1.0; if (normal) { for (int i = l; i < n; i++) scale /= (sqrt(2.0) * sqrt(2.0)); } for (size_t j = 0; j < L[3]; j++) { for (size_t i = 0; i < L[2]; i++) { *sigOut++ = scale * *C++; } } return (0); } const T *cA = C; const T *cDh = cA + L[0] * L[1]; const T *cDv = cDh + L[2] * L[3]; const T *cDd = cDv + L[4] * L[5]; size_t L2d[10] = {L[0], L[1], L[2], L[3], L[4], L[5], L[6], L[7], 0, 0}; for (int i = 1; i <= l; i++) { L2d[8] = mww->approxlength(L[LLength - 2], n - i); L2d[9] = mww->approxlength(L[LLength - 1], n - i); int rc = mww->idwt2d(cA, cDh, cDv, cDd, L2d, sigOut); if (rc < 0) return (rc); if (i == l) break; cA = sigOut; cDh += L[6 * (i - 1) + 2] * L[6 * (i - 1) + 3] + L[6 * (i - 1) + 4] * L[6 * (i - 1) + 5] + L[6 * (i - 1) + 6] * L[6 * (i - 1) + 7]; cDv = cDh + L[6 * i + 2] * L[6 * i + 3]; cDd = cDv + L[6 * i + 4] * L[6 * i + 5]; L2d[0] = L2d[8]; L2d[1] = L2d[9]; L2d[2] = L[6 * i + 2]; L2d[3] = L[6 * i + 3]; L2d[4] = L[6 * i + 4]; L2d[5] = L[6 * i + 5]; L2d[6] = L[6 * i + 6]; L2d[7] = L[6 * i + 7]; } if (l != n && normal) { double scale = 1.0; for (int i = l; i < n; i++) scale /= (sqrt(2.0) * sqrt(2.0)); for (size_t i = 0; i < L2d[8] * L2d[9]; i++) sigOut[i] *= scale; } return (0); } int MatWaveWavedec::waverec2(const double *C, const size_t *L, int n, double *sigOut) { return waverec2_template(this, C, L, n, n, false, sigOut); } int MatWaveWavedec::waverec2(const float *C, const size_t *L, int n, float *sigOut) { return waverec2_template(this, C, L, n, n, false, sigOut); } int MatWaveWavedec::waverec2(const long *C, const size_t *L, int n, long *sigOut) { return waverec2_template(this, C, L, n, n, false, sigOut); } int MatWaveWavedec::waverec2(const int *C, const size_t *L, int n, int *sigOut) { return waverec2_template(this, C, L, n, n, false, sigOut); } int MatWaveWavedec::appcoef2(const double *C, const size_t *L, int n, int l, bool normal, double *sigOut) { return waverec2_template(this, C, L, n, l, normal, sigOut); } int MatWaveWavedec::appcoef2(const float *C, const size_t *L, int n, int l, bool normal, float *sigOut) { return waverec2_template(this, C, L, n, l, normal, sigOut); } int MatWaveWavedec::appcoef2(const long *C, const size_t *L, int n, int l, bool normal, long *sigOut) { return waverec2_template(this, C, L, n, l, normal, sigOut); } int MatWaveWavedec::appcoef2(const int *C, const size_t *L, int n, int l, bool normal, int *sigOut) { return waverec2_template(this, C, L, n, l, normal, sigOut); } template int wavedec3_template(MatWaveWavedec *mww, const T *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, T *C, size_t *L) { if (!mww->wavelet()) { MatWaveWavedec::SetErrMsg("Invalid state, no wavelet"); return (-1); } if (n < 0 || n > min(min(mww->wmaxlev(sigInX), mww->wmaxlev(sigInY)), mww->wmaxlev(sigInZ))) { MatWaveWavedec::SetErrMsg("Invalid number of transforms : %d", n); return (-1); } mww->computeL3(sigInX, sigInY, sigInZ, n, L); size_t CLength = mww->coefflength3(L, n); if (n == 0) { for (size_t k = 0; k < sigInZ; k++) { for (size_t j = 0; j < sigInY; j++) { for (size_t i = 0; i < sigInX; i++) { *C++ = *sigIn++; } } } return (0); } int rc; const T *sigInPtr = sigIn; size_t lenx = sigInX; size_t leny = sigInY; size_t lenz = sigInZ; size_t cALenX = mww->MatWaveBase::approxlength(sigInX); size_t cALenY = mww->MatWaveBase::approxlength(sigInY); size_t cALenZ = mww->MatWaveBase::approxlength(sigInZ); T * cptr; size_t tlen = 0; size_t L3d[27]; for (int i = n; i > 0; i--) { tlen += (L[(21 * i) - 18] * L[(21 * i) - 17] * L[(21 * i) - 16]) + // cLLH (L[(21 * i) - 15] * L[(21 * i) - 14] * L[(21 * i) - 13]) + // cLHL (L[(21 * i) - 12] * L[(21 * i) - 11] * L[(21 * i) - 10]) + // cLHH (L[(21 * i) - 9] * L[(21 * i) - 8] * L[(21 * i) - 7]) + // cHLL (L[(21 * i) - 6] * L[(21 * i) - 5] * L[(21 * i) - 4]) + // cHLH (L[(21 * i) - 3] * L[(21 * i) - 2] * L[(21 * i) - 1]) + // HHL (L[(21 * i) + 0] * L[(21 * i) + 1] * L[(21 * i) + 2]); // HHH cptr = C + CLength - tlen - (cALenX * cALenY * cALenZ); rc = mww->dwt3d(sigInPtr, lenx, leny, lenz, cptr, L3d); if (rc < 0) return (rc); lenx = cALenX; leny = cALenY; lenz = cALenZ; cALenX = mww->MatWaveBase::approxlength(cALenX); cALenY = mww->MatWaveBase::approxlength(cALenY); cALenZ = mww->MatWaveBase::approxlength(cALenZ); sigInPtr = cptr; } return (0); } int MatWaveWavedec::wavedec3(const double *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, double *C, size_t *L) { return wavedec3_template(this, sigIn, sigInX, sigInY, sigInZ, n, C, L); } int MatWaveWavedec::wavedec3(const float *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, float *C, size_t *L) { return wavedec3_template(this, sigIn, sigInX, sigInY, sigInZ, n, C, L); } int MatWaveWavedec::wavedec3(const long *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, long *C, size_t *L) { return wavedec3_template(this, sigIn, sigInX, sigInY, sigInZ, n, C, L); } int MatWaveWavedec::wavedec3(const int *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, int *C, size_t *L) { return wavedec3_template(this, sigIn, sigInX, sigInY, sigInZ, n, C, L); } template int waverec3_template(MatWaveWavedec *mww, const T *C, const size_t *L, int n, int l, bool normal, T *sigOut) { if (!mww->wavelet()) { MatWaveWavedec::SetErrMsg("Invalid state, no wavelet"); return (-1); } if (n < 0) { MatWaveWavedec::SetErrMsg("Invalid number of transforms : %d", n); return (-1); } if (l < 0 || l > n) l = n; int LLength = 21 * n + 6; if (l == 0) { double scale = 1.0; if (normal) { for (int i = l; i < n; i++) scale /= (sqrt(2.0) * sqrt(2.0) * sqrt(2.0)); } for (size_t k = 0; k < L[5]; k++) { for (size_t j = 0; j < L[4]; j++) { for (size_t i = 0; i < L[3]; i++) { *sigOut++ = scale * *C++; } } } return (0); } const T *cLLL = C; const T *cLLH = cLLL + L[0] * L[1] * L[2]; const T *cLHL = cLLH + L[3] * L[4] * L[5]; const T *cLHH = cLHL + L[6] * L[7] * L[8]; const T *cHLL = cLHH + L[9] * L[10] * L[11]; const T *cHLH = cHLL + L[12] * L[13] * L[14]; const T *cHHL = cHLH + L[15] * L[16] * L[17]; const T *cHHH = cHHL + L[18] * L[19] * L[20]; size_t L3d[27] = {L[0], L[1], L[2], L[3], L[4], L[5], L[6], L[7], L[8], L[9], L[10], L[11], L[12], L[13], L[14], L[15], L[16], L[17], L[18], L[19], L[20], L[21], L[22], L[23], 0, 0, 0}; for (int i = 1; i <= l; i++) { L3d[24] = mww->approxlength(L[LLength - 3], n - i); L3d[25] = mww->approxlength(L[LLength - 2], n - i); L3d[26] = mww->approxlength(L[LLength - 1], n - i); int rc = mww->idwt3d(cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L3d, sigOut); if (rc < 0) return (rc); if (i == l) break; cLLL = sigOut; cLLH += (L[21 * (i - 1) + 3] * L[21 * (i - 1) + 4] * L[21 * (i - 1) + 5]) + (L[21 * (i - 1) + 6] * L[21 * (i - 1) + 7] * L[21 * (i - 1) + 8]) + (L[21 * (i - 1) + 9] * L[21 * (i - 1) + 10] * L[21 * (i - 1) + 11]) + (L[21 * (i - 1) + 12] * L[21 * (i - 1) + 13] * L[21 * (i - 1) + 14]) + (L[21 * (i - 1) + 15] * L[21 * (i - 1) + 16] * L[21 * (i - 1) + 17]) + (L[21 * (i - 1) + 18] * L[21 * (i - 1) + 19] * L[21 * (i - 1) + 20]) + (L[21 * (i - 1) + 21] * L[21 * (i - 1) + 22] * L[21 * (i - 1) + 23]); cLHL = cLLH + (L[21 * i + 3] * L[21 * i + 4] * L[21 * i + 5]); cLHH = cLHL + (L[21 * i + 6] * L[21 * i + 7] * L[21 * i + 8]); cHLL = cLHH + (L[21 * i + 9] * L[21 * i + 10] * L[21 * i + 11]); cHLH = cHLL + (L[21 * i + 12] * L[21 * i + 13] * L[21 * i + 14]); cHHL = cHLH + (L[21 * i + 15] * L[21 * i + 16] * L[21 * i + 17]); cHHH = cHHL + (L[21 * i + 18] * L[21 * i + 19] * L[21 * i + 20]); L3d[0] = L3d[24]; L3d[1] = L3d[25]; L3d[2] = L3d[26]; L3d[3] = L[21 * i + 3]; L3d[4] = L[21 * i + 4]; L3d[5] = L[21 * i + 5]; L3d[6] = L[21 * i + 6]; L3d[7] = L[21 * i + 7]; L3d[8] = L[21 * i + 8]; L3d[9] = L[21 * i + 9]; L3d[10] = L[21 * i + 10]; L3d[11] = L[21 * i + 11]; L3d[12] = L[21 * i + 12]; L3d[13] = L[21 * i + 13]; L3d[14] = L[21 * i + 14]; L3d[15] = L[21 * i + 15]; L3d[16] = L[21 * i + 16]; L3d[17] = L[21 * i + 17]; L3d[18] = L[21 * i + 18]; L3d[19] = L[21 * i + 19]; L3d[20] = L[21 * i + 20]; L3d[21] = L[21 * i + 21]; L3d[22] = L[21 * i + 22]; L3d[23] = L[21 * i + 23]; } if (l != n && normal) { double scale = 1.0; for (int i = l; i < n; i++) scale /= (sqrt(2.0) * sqrt(2.0) * sqrt(2.0)); for (size_t i = 0; i < L3d[24] * L3d[25] * L3d[26]; i++) sigOut[i] *= scale; } return (0); } int MatWaveWavedec::waverec3(const double *C, const size_t *L, int n, double *sigOut) { return waverec3_template(this, C, L, n, n, false, sigOut); } int MatWaveWavedec::waverec3(const float *C, const size_t *L, int n, float *sigOut) { return waverec3_template(this, C, L, n, n, false, sigOut); } int MatWaveWavedec::waverec3(const long *C, const size_t *L, int n, long *sigOut) { return waverec3_template(this, C, L, n, n, false, sigOut); } int MatWaveWavedec::waverec3(const int *C, const size_t *L, int n, int *sigOut) { return waverec3_template(this, C, L, n, n, false, sigOut); } int MatWaveWavedec::appcoef3(const double *C, const size_t *L, int n, int l, bool normal, double *sigOut) { return waverec3_template(this, C, L, n, l, normal, sigOut); } int MatWaveWavedec::appcoef3(const float *C, const size_t *L, int n, int l, bool normal, float *sigOut) { return waverec3_template(this, C, L, n, l, normal, sigOut); } int MatWaveWavedec::appcoef3(const long *C, const size_t *L, int n, int l, bool normal, long *sigOut) { return waverec3_template(this, C, L, n, l, normal, sigOut); } int MatWaveWavedec::appcoef3(const int *C, const size_t *L, int n, int l, bool normal, int *sigOut) { return waverec3_template(this, C, L, n, l, normal, sigOut); } void MatWaveWavedec::computeL(size_t sigInLen, int n, size_t *L) const { L[n + 1] = sigInLen; L[n] = sigInLen; for (int i = n; i > 0; i--) { L[i - 1] = MatWaveBase::approxlength(L[i]); L[i] = MatWaveBase::detaillength(L[i]); } } void MatWaveWavedec::computeL2(size_t sigInX, size_t sigInY, int n, size_t *L) const { L[(n * 6) + 4 - 4] = sigInX; L[(n * 6) + 4 - 3] = sigInY; L[(n * 6) + 4 - 2] = sigInX; L[(n * 6) + 4 - 1] = sigInY; for (int i = n; i > 0; i--) { // cA L[(i * 6) - 6] = MatWaveBase::approxlength(L[i * 6 + 0]); L[(i * 6) - 5] = MatWaveBase::approxlength(L[i * 6 + 1]); // cDh L[(i * 6) - 4] = MatWaveBase::approxlength(L[i * 6 + 0]); L[(i * 6) - 3] = MatWaveBase::detaillength(L[i * 6 + 1]); // cDv L[(i * 6) - 2] = MatWaveBase::detaillength(L[i * 6 + 0]); L[(i * 6) - 1] = MatWaveBase::approxlength(L[i * 6 + 1]); // cDd - overwrites previous value // L[(i * 6) - 0] = MatWaveBase::detaillength(L[i * 6 + 0]); L[(i * 6) + 1] = MatWaveBase::detaillength(L[i * 6 + 1]); } } void MatWaveWavedec::computeL3(size_t sigInX, size_t sigInY, size_t sigInZ, int n, size_t *L) const { L[(n * 21) + 6 - 6] = sigInX; L[(n * 21) + 6 - 5] = sigInY; L[(n * 21) + 6 - 4] = sigInZ; L[(n * 21) + 6 - 3] = sigInX; L[(n * 21) + 6 - 2] = sigInY; L[(n * 21) + 6 - 1] = sigInZ; for (int i = n; i > 0; i--) { // cLLL L[(i * 21) - 21] = MatWaveBase::approxlength(L[i * 21 + 0]); L[(i * 21) - 20] = MatWaveBase::approxlength(L[i * 21 + 1]); L[(i * 21) - 19] = MatWaveBase::approxlength(L[i * 21 + 2]); // cLLH L[(i * 21) - 18] = MatWaveBase::approxlength(L[i * 21 + 0]); L[(i * 21) - 17] = MatWaveBase::approxlength(L[i * 21 + 1]); L[(i * 21) - 16] = MatWaveBase::detaillength(L[i * 21 + 2]); // cLHL L[(i * 21) - 15] = MatWaveBase::approxlength(L[i * 21 + 0]); L[(i * 21) - 14] = MatWaveBase::detaillength(L[i * 21 + 1]); L[(i * 21) - 13] = MatWaveBase::approxlength(L[i * 21 + 2]); // cLHH L[(i * 21) - 12] = MatWaveBase::approxlength(L[i * 21 + 0]); L[(i * 21) - 11] = MatWaveBase::detaillength(L[i * 21 + 1]); L[(i * 21) - 10] = MatWaveBase::detaillength(L[i * 21 + 2]); // cHLL L[(i * 21) - 9] = MatWaveBase::detaillength(L[i * 21 + 0]); L[(i * 21) - 8] = MatWaveBase::approxlength(L[i * 21 + 1]); L[(i * 21) - 7] = MatWaveBase::approxlength(L[i * 21 + 2]); // cHLH L[(i * 21) - 6] = MatWaveBase::detaillength(L[i * 21 + 0]); L[(i * 21) - 5] = MatWaveBase::approxlength(L[i * 21 + 1]); L[(i * 21) - 4] = MatWaveBase::detaillength(L[i * 21 + 2]); // cHHL L[(i * 21) - 3] = MatWaveBase::detaillength(L[i * 21 + 0]); L[(i * 21) - 2] = MatWaveBase::detaillength(L[i * 21 + 1]); L[(i * 21) - 1] = MatWaveBase::approxlength(L[i * 21 + 2]); // cHHH - overwrites previous value // L[(i * 21) + 0] = MatWaveBase::detaillength(L[i * 21 + 0]); L[(i * 21) + 1] = MatWaveBase::detaillength(L[i * 21 + 1]); L[(i * 21) + 2] = MatWaveBase::detaillength(L[i * 21 + 2]); } } size_t MatWaveWavedec::coefflength(const size_t *L, int n) const { size_t tlength = L[0]; // cA coefficients for (int i = 1; i <= n; i++) tlength += L[i]; return (tlength); } size_t MatWaveWavedec::coefflength(size_t sigInLen, int n) const { size_t *L = new size_t[n + 2]; computeL(sigInLen, n, L); size_t tlength = coefflength(L, n); delete[] L; return (tlength); } size_t MatWaveWavedec::approxlength(size_t sigInLen, int n) const { size_t cALen = sigInLen; for (int i = 0; i < n; i++) { cALen = MatWaveBase::approxlength(cALen); if (cALen == 0) return (cALen); } return (cALen); } void MatWaveWavedec::approxlength(const size_t *L, int n, int l, size_t *len) const { if (l > n) l = n; int LLength = n + 2; *len = approxlength(L[LLength - 1], n - l); } void MatWaveWavedec::approxlength2(const size_t *L, int n, int l, size_t *lenx, size_t *leny) const { if (l > n) l = n; int LLength = n * 6 + 4; *lenx = approxlength(L[LLength - 2], n - l); *leny = approxlength(L[LLength - 1], n - l); } void MatWaveWavedec::approxlength3(const size_t *L, int n, int l, size_t *lenx, size_t *leny, size_t *lenz) const { if (l > n) l = n; int LLength = n * 21 + 6; *lenx = approxlength(L[LLength - 3], n - l); *leny = approxlength(L[LLength - 2], n - l); *lenz = approxlength(L[LLength - 1], n - l); } size_t MatWaveWavedec::coefflength2(const size_t *L, int n) const { size_t tlength = (L[0] * L[1]); // cA coefficients; for (int i = 1; i <= n; i++) { tlength += L[(i * 6) - 4] * L[(i * 6) - 3]; // cDh tlength += L[(i * 6) - 2] * L[(i * 6) - 1]; // cDv tlength += L[(i * 6) - 0] * L[(i * 6) + 1]; // cDd } return (tlength); } size_t MatWaveWavedec::coefflength2(size_t sigInX, size_t sigInY, int n) const { size_t *L = new size_t[(n * 6) + 4]; computeL2(sigInX, sigInY, n, L); size_t tlength = coefflength2(L, n); delete[] L; return (tlength); } size_t MatWaveWavedec::coefflength3(const size_t *L, int n) const { size_t tlength = (L[0] * L[1] * L[2]); // cA coefficients; for (int i = 1; i <= n; i++) { tlength += L[(i * 21) - 18] * L[(i * 21) - 17] * L[(i * 21) - 16]; // cLLH tlength += L[(i * 21) - 15] * L[(i * 21) - 14] * L[(i * 21) - 13]; // cLHL tlength += L[(i * 21) - 12] * L[(i * 21) - 11] * L[(i * 21) - 10]; // cLHH tlength += L[(i * 21) - 9] * L[(i * 21) - 8] * L[(i * 21) - 7]; // cHLL tlength += L[(i * 21) - 6] * L[(i * 21) - 5] * L[(i * 21) - 4]; // cHLH tlength += L[(i * 21) - 3] * L[(i * 21) - 2] * L[(i * 21) - 1]; // cHHL tlength += L[(i * 21) - 0] * L[(i * 21) + 1] * L[(i * 21) + 2]; // cHHH } return (tlength); } size_t MatWaveWavedec::coefflength3(size_t sigInX, size_t sigInY, size_t sigInZ, int n) const { size_t *L = new size_t[(n * 21) + 6]; computeL3(sigInX, sigInY, sigInZ, n, L); size_t tlength = coefflength3(L, n); delete[] L; return (tlength); } ================================================ FILE: lib/wasp/NOTES ================================================ Proposed file placement ---------------------- All 1D variables (including time CV) -> master static && not-compressed && size < max_ele_per_master -> master everything else -> /coords or /data as appropriate Notes ----- + Need to change append definitions to only allow appending of additional time steps (this is what NetCDF supports) + For NetCDF implementation the time dim should be unlimited. + It might be desirable to copy small CVs (e.g. time) to data and coord variable files, but no way to ensure that these stay in sync with what is in master file. Forget this! + Highly desirable that files can be operated on without master, albeit with some limitations. + PutVar and GetVar() don't have way to specify compression level - Does variable need to be opened ? + need to test VarBase assignement operator and copy constructor work for derived class i + Need to define meaning of \p reflevel. If it's kept compatible with VDC2 then we are precluded from having varying numbers of refinement levels along different dimensions Questions --------- + How handle masks/missing-values? + Only one time CV? + When are NetCDF files "defined" + Can append mode be made more general? I.e. allow for adding new variables to the data set? Seems like this would only impact master file, and would create reading and re-writing the master file. See http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f90/Adding-New-Dimensions.html#Adding-New-Dimensions. + Implications of append mode wrt defining new or changing existing stuff + How are uniform coordinate vars handled wrt what is read/written and what is actually stored? ================================================ FILE: lib/wasp/NetCDFCpp.cpp ================================================ #include "vapor/VAssert.h" #include #include #include #include "vapor/NetCDFCpp.h" #include "vapor/MatWaveBase.h" using namespace VAPoR; #define MY_NC_ERR(rc, path, func) \ if (rc != NC_NOERR) { \ string msg = func; \ SetErrMsg("Error accessing netCDF file \"%s\", %s : %s -- file (%s), line(%d)", path.c_str(), msg.c_str(), nc_strerror(rc), __FILE__, __LINE__); \ return (rc); \ } namespace { bool var_defs_match(int ncid, int varid, int dimids[], int ndimids, nc_type xtype) { int mydimids[NC_MAX_DIMS]; int myndims; (void)nc_inq_varndims(ncid, varid, &myndims); (void)nc_inq_vardimid(ncid, varid, mydimids); for (int i = 0; i < ndimids; i++) { if (mydimids[i] != dimids[i]) return (false); } nc_type myxtype; (void)nc_inq_vartype(ncid, varid, &myxtype); if (myxtype != xtype) return (false); return (true); } }; // namespace NetCDFCpp::NetCDFCpp() { _ncid = -1; _path.clear(); } NetCDFCpp::~NetCDFCpp() {} int NetCDFCpp::Create(string path, int cmode, size_t initialsz, size_t &bufrsizehintp) { NetCDFCpp::Close(); _ncid = -1; _path.clear(); int ncid; int rc = nc__create(path.c_str(), cmode, initialsz, &bufrsizehintp, &ncid); MY_NC_ERR(rc, path, "nc__create()"); _path = path; _ncid = ncid; return (NC_NOERR); } int NetCDFCpp::Open(string path, int mode) { NetCDFCpp::Close(); _ncid = -1; _path.clear(); int ncid; int rc = nc_open(path.c_str(), mode, &ncid); MY_NC_ERR(rc, path, "nc_open()"); _path = path; _ncid = ncid; return (NC_NOERR); } int NetCDFCpp::SetFill(int fillmode, int &old_modep) { int rc = nc_set_fill(_ncid, fillmode, &old_modep); MY_NC_ERR(rc, _path, "nc_set_fill()"); return (NC_NOERR); } int NetCDFCpp::EndDef() const { int rc = nc_enddef(_ncid); MY_NC_ERR(rc, _path, "nc_enddef()"); return (NC_NOERR); } int NetCDFCpp::ReDef() const { int rc = nc_redef(_ncid); MY_NC_ERR(rc, _path, "nc_redef()"); return (NC_NOERR); } int NetCDFCpp::Close() { if (_ncid < 0) return (NC_NOERR); int rc = nc_close(_ncid); MY_NC_ERR(rc, _path, "nc_close()"); _ncid = -1; _path.clear(); return (NC_NOERR); } int NetCDFCpp::DefDim(string name, size_t len) const { int dimid; int rc = nc_def_dim(_ncid, name.c_str(), len, &dimid); MY_NC_ERR(rc, _path, "nc_def_dim(" + name + ")"); return (NC_NOERR); } int NetCDFCpp::DefVar(string name, nc_type xtype, vector dimnames) { int dimids[NC_MAX_DIMS]; for (int i = 0; i < dimnames.size(); i++) { int rc = nc_inq_dimid(_ncid, dimnames[i].c_str(), &dimids[i]); MY_NC_ERR(rc, _path, "nc_inq_dimid(" + dimnames[i] + ")"); } // Don't error out if variable already exists and has same definition // int varid; int rc = nc_inq_varid(_ncid, name.c_str(), &varid); if (rc == NC_NOERR) { if (!var_defs_match(_ncid, varid, dimids, dimnames.size(), xtype)) { MY_NC_ERR(NC_ENAMEINUSE, _path, "nc_def_var(" + name + ")"); return (NC_ENAMEINUSE); } return (NC_NOERR); } rc = nc_def_var(_ncid, name.c_str(), xtype, dimnames.size(), dimids, &varid); MY_NC_ERR(rc, _path, "nc_def_var(" + name + ")"); return (NC_NOERR); } int NetCDFCpp::InqVarDims(string name, vector &dimnames, vector &dims) const { dimnames.clear(); dims.clear(); int varid; int rc = NetCDFCpp::InqVarid(name, varid); if (rc < 0) return (rc); int ndims; rc = nc_inq_varndims(_ncid, varid, &ndims); MY_NC_ERR(rc, _path, "nc_inq_varndims()"); int dimids[NC_MAX_VAR_DIMS]; rc = nc_inq_vardimid(_ncid, varid, dimids); MY_NC_ERR(rc, _path, "nc_inq_vardimid()"); for (int i = 0; i < ndims; i++) { char dimnamebuf[NC_MAX_NAME + 1]; size_t dimlen; rc = nc_inq_dim(_ncid, dimids[i], dimnamebuf, &dimlen); MY_NC_ERR(rc, _path, "nc_inq_dim()"); dimnames.push_back(dimnamebuf); dims.push_back(dimlen); } return (NC_NOERR); } int NetCDFCpp::InqDims(vector &dimnames, vector &dims) const { dimnames.clear(); dims.clear(); int dimids[NC_MAX_DIMS]; int ndims; int rc = nc_inq_dimids(_ncid, &ndims, dimids, 0); MY_NC_ERR(rc, _path, "nc_inq_dimids()"); for (int i = 0; i < ndims; i++) { char dimnamebuf[NC_MAX_NAME + 1]; size_t dimlen; rc = nc_inq_dim(_ncid, dimids[i], dimnamebuf, &dimlen); MY_NC_ERR(rc, _path, "nc_inq_dim()"); dimnames.push_back(dimnamebuf); dims.push_back(dimlen); } return (NC_NOERR); } int NetCDFCpp::InqDimlen(string name, size_t &len) const { len = 0; int dimid; int rc = nc_inq_dimid(_ncid, name.c_str(), &dimid); MY_NC_ERR(rc, _path, "nc_inq_dimid(" + name + ")"); rc = nc_inq_dimlen(_ncid, dimid, &len); MY_NC_ERR(rc, _path, "nc_inq_dimlen()"); return (0); } int NetCDFCpp::InqAttnames(string varname, std::vector &attnames) const { attnames.clear(); int varid; int rc = NetCDFCpp::InqVarid(varname, varid); if (rc < 0) return (-1); int natts; if (!varname.empty()) { rc = nc_inq_varnatts(_ncid, varid, &natts); MY_NC_ERR(rc, _path, "nc_inq_varnatts()"); } else { rc = nc_inq_natts(_ncid, &natts); MY_NC_ERR(rc, _path, "nc_inq_natts()"); } for (int attnum = 0; attnum < natts; attnum++) { char namebuf[NC_MAX_NAME + 1]; rc = nc_inq_attname(_ncid, varid, attnum, namebuf); MY_NC_ERR(rc, _path, "nc_inq_attname()"); attnames.push_back(namebuf); } return (0); } int NetCDFCpp::CopyAtt(string varname_in, string attname, NetCDFCpp &ncdf_out, string varname_out) const { int varid_in; int rc = NetCDFCpp::InqVarid(varname_in, varid_in); if (rc < 0) return (rc); int varid_out; rc = ncdf_out.InqVarid(varname_out, varid_out); if (rc < 0) return (rc); int ncid_out = ncdf_out.GetNCID(); if (rc < 0) return (rc); rc = nc_copy_att(_ncid, varid_in, attname.c_str(), ncid_out, varid_out); MY_NC_ERR(rc, _path, "nc_copy_att()"); return (NC_NOERR); } // // PutAtt - Integer // int NetCDFCpp::PutAtt(string varname, string attname, int value) const { return (NetCDFCpp::PutAtt(varname, attname, &value, 1)); } int NetCDFCpp::PutAtt(string varname, string attname, vector values) const { size_t n = values.size(); int * buf = new int[n]; for (size_t i = 0; i < n; i++) buf[i] = values[i]; int rc = NetCDFCpp::PutAtt(varname, attname, buf, n); delete[] buf; return (rc); } int NetCDFCpp::PutAtt(string varname, string attname, const int values[], size_t n) const { int varid; int rc = NetCDFCpp::InqVarid(varname, varid); if (rc < 0) return (rc); if (attname == "_FillValue") { nc_type xtype; rc = InqVartype(varname, xtype); if (rc < 0) return (rc); if (xtype == NC_BYTE) { unsigned char *valuesB = new unsigned char[n]; for (int i = 0; i < n; i++) valuesB[i] = (unsigned char)values[i]; rc = nc_put_att_ubyte(_ncid, varid, attname.c_str(), NC_BYTE, n, valuesB); delete[] valuesB; } else if (xtype == NC_SHORT) { short *valuesS = new short[n]; for (int i = 0; i < n; i++) valuesS[i] = (short)values[i]; rc = nc_put_att_short(_ncid, varid, attname.c_str(), NC_SHORT, n, valuesS); delete[] valuesS; } else if (xtype == NC_INT64) { long *valuesS = new long[n]; for (int i = 0; i < n; i++) valuesS[i] = (long)values[i]; rc = nc_put_att_long(_ncid, varid, attname.c_str(), NC_INT64, n, valuesS); delete[] valuesS; } else { rc = nc_put_att_int(_ncid, varid, attname.c_str(), NC_INT, n, values); } } else { rc = nc_put_att_int(_ncid, varid, attname.c_str(), NC_INT, n, values); } MY_NC_ERR(rc, _path, "nc_put_att_int(" + attname + ")"); return (NC_NOERR); } // // GetAtt - Integer // int NetCDFCpp::GetAtt(string varname, string attname, int &value) const { return (NetCDFCpp::GetAtt(varname, attname, &value, 1)); } int NetCDFCpp::GetAtt(string varname, string attname, vector &values) const { values.clear(); int varid; int rc = InqVarid(varname, varid); if (rc < 0) return (rc); size_t n; rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &n); MY_NC_ERR(rc, _path, "nc_inq_attlen(" + attname + ")"); int *buf = new int[n]; rc = NetCDFCpp::GetAtt(varname, attname, buf, n); for (int i = 0; i < n; i++) { values.push_back(buf[i]); } delete[] buf; return (rc); } int NetCDFCpp::GetAtt(string varname, string attname, int values[], size_t n) const { int varid; int rc = InqVarid(varname, varid); if (rc < 0) return (rc); size_t len; rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &len); MY_NC_ERR(rc, _path, "nc_inq_attlen(" + attname + ")"); int *buf = new int[len]; rc = nc_get_att_int(_ncid, varid, attname.c_str(), buf); if (rc != NC_NOERR) delete[] buf; MY_NC_ERR(rc, _path, "nc_get_att_int(" + attname + ")"); for (size_t i = 0; i < len && i < n; i++) { values[i] = buf[i]; } delete[] buf; return (NC_NOERR); } // // PutAtt - size_t // int NetCDFCpp::PutAtt(string varname, string attname, size_t value) const { return (NetCDFCpp::PutAtt(varname, attname, &value, 1)); } int NetCDFCpp::PutAtt(string varname, string attname, vector values) const { vector ivalues; for (size_t i = 0; i < values.size(); i++) ivalues.push_back(values[i]); return (NetCDFCpp::PutAtt(varname, attname, ivalues)); } int NetCDFCpp::PutAtt(string varname, string attname, const size_t values[], size_t n) const { vector ivalues; for (size_t i = 0; i < n; i++) ivalues.push_back(values[i]); return (NetCDFCpp::PutAtt(varname, attname, ivalues)); } // // GetAtt - size_t // int NetCDFCpp::GetAtt(string varname, string attname, size_t &value) const { return (NetCDFCpp::GetAtt(varname, attname, &value, 1)); } int NetCDFCpp::GetAtt(string varname, string attname, vector &values) const { values.clear(); vector ivalues; int rc = NetCDFCpp::GetAtt(varname, attname, ivalues); for (int i = 0; i < ivalues.size(); i++) values.push_back(ivalues[i]); return (rc); } int NetCDFCpp::GetAtt(string varname, string attname, size_t values[], size_t n) const { vector ivalues; int rc = NetCDFCpp::GetAtt(varname, attname, ivalues); for (int i = 0; i < ivalues.size() && i < n; i++) values[i] = ivalues[i]; return (rc); } // // PutAtt - Float // int NetCDFCpp::PutAtt(string varname, string attname, float value) const { return (NetCDFCpp::PutAtt(varname, attname, &value, 1)); } int NetCDFCpp::PutAtt(string varname, string attname, vector values) const { size_t n = values.size(); float *buf = new float[n]; for (size_t i = 0; i < n; i++) buf[i] = values[i]; int rc = NetCDFCpp::PutAtt(varname, attname, buf, n); delete[] buf; return (rc); } int NetCDFCpp::PutAtt(string varname, string attname, const float values[], size_t n) const { int varid; int rc = InqVarid(varname, varid); if (rc < 0) return (rc); rc = nc_put_att_float(_ncid, varid, attname.c_str(), NC_DOUBLE, n, values); MY_NC_ERR(rc, _path, "nc_put_att_float(" + attname + ")"); return (NC_NOERR); } // // PutAtt - Double // int NetCDFCpp::PutAtt(string varname, string attname, double value) const { return (NetCDFCpp::PutAtt(varname, attname, &value, 1)); } int NetCDFCpp::PutAtt(string varname, string attname, vector values) const { size_t n = values.size(); double *buf = new double[n]; for (size_t i = 0; i < n; i++) buf[i] = values[i]; int rc = NetCDFCpp::PutAtt(varname, attname, buf, n); delete[] buf; return (rc); } int NetCDFCpp::PutAtt(string varname, string attname, const double values[], size_t n) const { int varid; int rc = InqVarid(varname, varid); if (rc < 0) return (rc); if (attname == "_FillValue") { nc_type xtype; rc = InqVartype(varname, xtype); if (rc < 0) return (rc); if (xtype == NC_FLOAT) { float *valuesF = new float[n]; for (int i = 0; i < n; i++) valuesF[i] = (float)values[i]; rc = nc_put_att_float(_ncid, varid, attname.c_str(), NC_FLOAT, n, valuesF); delete[] valuesF; } else { rc = nc_put_att_double(_ncid, varid, attname.c_str(), NC_DOUBLE, n, values); } } else { rc = nc_put_att_double(_ncid, varid, attname.c_str(), NC_DOUBLE, n, values); } MY_NC_ERR(rc, _path, "nc_put_att_double(" + attname + ")"); return (NC_NOERR); } // // GetAtt - Float // int NetCDFCpp::GetAtt(string varname, string attname, float &value) const { return (NetCDFCpp::GetAtt(varname, attname, &value, 1)); } int NetCDFCpp::GetAtt(string varname, string attname, vector &values) const { values.clear(); int varid; int rc = InqVarid(varname, varid); if (rc < 0) return (rc); size_t n; rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &n); MY_NC_ERR(rc, _path, "nc_inq_attlen(" + attname + ")"); float *buf = new float[n]; rc = NetCDFCpp::GetAtt(varname, attname, buf, n); for (int i = 0; i < n; i++) { values.push_back(buf[i]); } delete[] buf; return (rc); } int NetCDFCpp::GetAtt(string varname, string attname, float values[], size_t n) const { int varid; int rc = InqVarid(varname, varid); if (rc < 0) return (rc); size_t len; rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &len); MY_NC_ERR(rc, _path, "nc_inq_attlen(" + attname + ")"); float *buf = new float[len]; rc = nc_get_att_float(_ncid, varid, attname.c_str(), buf); if (rc != NC_NOERR) delete[] buf; MY_NC_ERR(rc, _path, "nc_get_att_float(" + attname + ")"); for (size_t i = 0; i < len && i < n; i++) { values[i] = buf[i]; } delete[] buf; return (NC_NOERR); } // // GetAtt - Double // int NetCDFCpp::GetAtt(string varname, string attname, double &value) const { return (NetCDFCpp::GetAtt(varname, attname, &value, 1)); } int NetCDFCpp::GetAtt(string varname, string attname, vector &values) const { values.clear(); int varid; int rc = InqVarid(varname, varid); if (rc < 0) return (rc); size_t n; rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &n); MY_NC_ERR(rc, _path, "nc_inq_attlen(" + attname + ")"); double *buf = new double[n]; rc = NetCDFCpp::GetAtt(varname, attname, buf, n); for (int i = 0; i < n; i++) { values.push_back(buf[i]); } delete[] buf; return (rc); } int NetCDFCpp::GetAtt(string varname, string attname, double values[], size_t n) const { int varid; int rc = InqVarid(varname, varid); if (rc < 0) return (rc); size_t len; rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &len); MY_NC_ERR(rc, _path, "nc_inq_attlen(" + attname + ")"); double *buf = new double[len]; rc = nc_get_att_double(_ncid, varid, attname.c_str(), buf); if (rc != NC_NOERR) delete[] buf; MY_NC_ERR(rc, _path, "nc_get_att_double(" + attname + ")"); for (size_t i = 0; i < len && i < n; i++) { values[i] = buf[i]; } delete[] buf; return (NC_NOERR); } // // PutAtt - String // int NetCDFCpp::PutAtt(string varname, string attname, string value) const { size_t n = value.length(); char * buf = new char[n + 1]; strcpy(buf, value.c_str()); int rc = NetCDFCpp::PutAtt(varname, attname, buf, n); delete[] buf; return (rc); } int NetCDFCpp::PutAtt(string varname, string attname, vector values) const { string s; for (int i = 0; i < values.size(); i++) { s += values[i]; s += " "; } return (NetCDFCpp::PutAtt(varname, attname, s)); } int NetCDFCpp::PutAtt(string varname, string attname, const char values[], size_t n) const { int varid; int rc = NetCDFCpp::InqVarid(varname, varid); if (rc < 0) return (rc); rc = nc_put_att_text(_ncid, varid, attname.c_str(), n, values); MY_NC_ERR(rc, _path, "nc_put_att_text(" + attname + ")"); return (NC_NOERR); } // // GetAtt - String // int NetCDFCpp::GetAtt(string varname, string attname, string &value) const { value.clear(); int varid; int rc = InqVarid(varname, varid); if (rc < 0) return (rc); size_t n; rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &n); MY_NC_ERR(rc, _path, "nc_inq_attlen(" + attname + ")"); char *buf = new char[n + 1]; rc = NetCDFCpp::GetAtt(varname, attname, buf, n); value = buf; delete[] buf; return (rc); } int NetCDFCpp::GetAtt(string varname, string attname, char values[], size_t n) const { int varid; int rc = InqVarid(varname, varid); if (rc < 0) return (rc); size_t len; rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &len); MY_NC_ERR(rc, _path, "nc_inq_attlen(" + attname + ")"); char *buf = new char[len + 1]; rc = nc_get_att_text(_ncid, varid, attname.c_str(), buf); if (rc != NC_NOERR) delete[] buf; MY_NC_ERR(rc, _path, "nc_get_att_text(" + attname + ")"); size_t i; for (i = 0; i < len && i < n; i++) { values[i] = buf[i]; } values[i] = '\0'; delete[] buf; return (NC_NOERR); } int NetCDFCpp::GetAtt(string varname, string attname, vector &values) const { values.clear(); string s; int rc = NetCDFCpp::GetAtt(varname, attname, s); if (rc < 0) return (rc); string buf; stringstream ss(s); while (ss >> buf) values.push_back(buf); return (0); } int NetCDFCpp::InqVarid(string varname, int &varid) const { if (varname.empty()) { varid = NC_GLOBAL; return (NC_NOERR); } int my_varid = -1; int rc = nc_inq_varid(_ncid, varname.c_str(), &my_varid); MY_NC_ERR(rc, _path, "nc_inq_varid(" + varname + ")"); varid = my_varid; return (NC_NOERR); } int NetCDFCpp::InqAtt(string varname, string attname, nc_type &xtype, size_t &len) const { int varid; int rc = NetCDFCpp::InqVarid(varname, varid); if (rc < 0) return (rc); rc = nc_inq_att(_ncid, varid, attname.c_str(), &xtype, &len); MY_NC_ERR(rc, _path, "nc_inq_att(" + attname + ")"); return (NC_NOERR); } int NetCDFCpp::InqVartype(string varname, nc_type &xtype) const { int varid; int rc = NetCDFCpp::InqVarid(varname, varid); if (rc < 0) return (rc); rc = nc_inq_vartype(_ncid, varid, &xtype); MY_NC_ERR(rc, _path, "nc_inq_vartype()"); return (NC_NOERR); } size_t NetCDFCpp::SizeOf(nc_type xtype) { switch (xtype) { case NC_BYTE: case NC_UBYTE: case NC_CHAR: return (1); case NC_SHORT: case NC_USHORT: return (2); case NC_INT: // NC_LONG and NC_INT case NC_UINT: case NC_FLOAT: return (4); case NC_INT64: case NC_UINT64: case NC_DOUBLE: return (8); default: return (0); } } bool NetCDFCpp::ValidFile(string path) { bool valid = false; int ncid; int rc = nc_open(path.c_str(), 0, &ncid); if (rc == NC_NOERR) { valid = true; nc_close(ncid); } return (valid); } int NetCDFCpp::_PutVara(string varname, vector start, vector count, const void *data, string func) { VAssert(start.size() == count.size()); int varid; int rc = NetCDFCpp::InqVarid(varname, varid); if (rc < 0) return (rc); size_t mystart[NC_MAX_VAR_DIMS]; size_t mycount[NC_MAX_VAR_DIMS]; for (int i = 0; i < start.size(); i++) { mystart[i] = start[i]; mycount[i] = count[i]; } if (func == "nc_put_vara") { // The nc_put_var() function will write a variable of any type, // including // user defined type. For this function, the type of the data in memory // must match the type of the variable - no data conversion is done. // rc = nc_put_vara(_ncid, varid, mystart, mycount, (const void *)data); } else if (func == "nc_put_vara_float") { rc = nc_put_vara_float(_ncid, varid, mystart, mycount, (const float *)data); } else if (func == "nc_put_vara_double") { rc = nc_put_vara_double(_ncid, varid, mystart, mycount, (const double *)data); } else if (func == "nc_put_vara_int") { rc = nc_put_vara_int(_ncid, varid, mystart, mycount, (const int *)data); } else if (func == "nc_put_vara_long") { rc = nc_put_vara_long(_ncid, varid, mystart, mycount, (const long *)data); } else if (func == "nc_put_vara_uchar") { rc = nc_put_vara_uchar(_ncid, varid, mystart, mycount, (const unsigned char *)data); } else { VAssert(func == ""); } MY_NC_ERR(rc, _path, func); return (0); } int NetCDFCpp::PutVara(string varname, vector start, vector count, const void *data) { return (_PutVara(varname, start, count, (const void *)data, "nc_put_vara")); } int NetCDFCpp::PutVara(string varname, vector start, vector count, const float *data) { return (_PutVara(varname, start, count, (const void *)data, "nc_put_vara_float")); } int NetCDFCpp::PutVara(string varname, vector start, vector count, const double *data) { return (_PutVara(varname, start, count, (const void *)data, "nc_put_vara_double")); } int NetCDFCpp::PutVara(string varname, vector start, vector count, const int *data) { return (_PutVara(varname, start, count, (const void *)data, "nc_put_vara_int")); } int NetCDFCpp::PutVara(string varname, vector start, vector count, const long *data) { return (_PutVara(varname, start, count, (const void *)data, "nc_put_vara_long")); } int NetCDFCpp::PutVara(string varname, vector start, vector count, const unsigned char *data) { return (_PutVara(varname, start, count, (const void *)data, "nc_put_vara_uchar")); } int NetCDFCpp::_PutVar(string varname, const void *data, string func) { int varid; int rc = NetCDFCpp::InqVarid(varname, varid); if (rc < 0) return (rc); if (func == "nc_put_var") { // The nc_put_var() function will write a variable of any type, // including // user defined type. For this function, the type of the data in memory // must match the type of the variable - no data conversion is done. // rc = nc_put_var(_ncid, varid, (const void *)data); } else if (func == "nc_put_var_float") { rc = nc_put_var_float(_ncid, varid, (const float *)data); } else if (func == "nc_put_var_double") { rc = nc_put_var_double(_ncid, varid, (const double *)data); } else if (func == "nc_put_var_int") { rc = nc_put_var_int(_ncid, varid, (const int *)data); } else if (func == "nc_put_var_long") { rc = nc_put_var_long(_ncid, varid, (const long *)data); } else if (func == "nc_put_var_uchar") { rc = nc_put_var_uchar(_ncid, varid, (const unsigned char *)data); } else { VAssert(func == ""); } MY_NC_ERR(rc, _path, func); return (0); } int NetCDFCpp::PutVar(string varname, const void *data) { return (_PutVar(varname, (const void *)data, "nc_put_var")); } int NetCDFCpp::PutVar(string varname, const float *data) { return (_PutVar(varname, (const void *)data, "nc_put_var_float")); } int NetCDFCpp::PutVar(string varname, const double *data) { return (_PutVar(varname, (const void *)data, "nc_put_var_double")); } int NetCDFCpp::PutVar(string varname, const int *data) { return (_PutVar(varname, (const void *)data, "nc_put_var_int")); } int NetCDFCpp::PutVar(string varname, const long *data) { return (_PutVar(varname, (const void *)data, "nc_put_var_long")); } int NetCDFCpp::PutVar(string varname, const unsigned char *data) { return (_PutVar(varname, (const void *)data, "nc_put_var_uchar")); } int NetCDFCpp::_GetVara(string varname, vector start, vector count, void *data, string func) const { VAssert(start.size() == count.size()); int varid; int rc = NetCDFCpp::InqVarid(varname, varid); if (rc < 0) return (rc); size_t mystart[NC_MAX_VAR_DIMS]; size_t mycount[NC_MAX_VAR_DIMS]; for (int i = 0; i < start.size(); i++) { mystart[i] = start[i]; mycount[i] = count[i]; } if (func == "nc_get_vara") { // The nc_get_var() function will write a variable of any type, // including // user defined type. For this function, the type of the data in memory // must match the type of the variable - no data conversion is done. // rc = nc_get_vara(_ncid, varid, mystart, mycount, (void *)data); } else if (func == "nc_get_vara_float") { rc = nc_get_vara_float(_ncid, varid, mystart, mycount, (float *)data); } else if (func == "nc_get_vara_double") { rc = nc_get_vara_double(_ncid, varid, mystart, mycount, (double *)data); } else if (func == "nc_get_vara_int") { rc = nc_get_vara_int(_ncid, varid, mystart, mycount, (int *)data); } else if (func == "nc_get_vara_long") { rc = nc_get_vara_long(_ncid, varid, mystart, mycount, (long *)data); } else if (func == "nc_get_vara_uchar") { rc = nc_get_vara_uchar(_ncid, varid, mystart, mycount, (unsigned char *)data); } else { VAssert(func == ""); } MY_NC_ERR(rc, _path, func); return (rc); } int NetCDFCpp::GetVara(string varname, vector start, vector count, void *data) const { return (_GetVara(varname, start, count, (void *)data, "nc_get_vara")); } int NetCDFCpp::GetVara(string varname, vector start, vector count, float *data) const { return (_GetVara(varname, start, count, (void *)data, "nc_get_vara_float")); } int NetCDFCpp::GetVara(string varname, vector start, vector count, double *data) const { return (_GetVara(varname, start, count, (void *)data, "nc_get_vara_double")); } int NetCDFCpp::GetVara(string varname, vector start, vector count, int *data) const { return (_GetVara(varname, start, count, (void *)data, "nc_get_vara_int")); } int NetCDFCpp::GetVara(string varname, vector start, vector count, long *data) const { return (_GetVara(varname, start, count, (void *)data, "nc_get_vara_long")); } int NetCDFCpp::GetVara(string varname, vector start, vector count, unsigned char *data) const { return (_GetVara(varname, start, count, (void *)data, "nc_get_vara_uchar")); } int NetCDFCpp::_GetVar(string varname, void *data, string func) const { int varid; int rc = NetCDFCpp::InqVarid(varname, varid); if (rc < 0) return (rc); if (func == "nc_get_var") { // The nc_get_var() function will write a variable of any type, // including // user defined type. For this function, the type of the data in memory // must match the type of the variable - no data conversion is done. // rc = nc_get_var(_ncid, varid, (void *)data); } else if (func == "nc_get_var_float") { rc = nc_get_var_float(_ncid, varid, (float *)data); } else if (func == "nc_get_var_double") { rc = nc_get_var_double(_ncid, varid, (double *)data); } else if (func == "nc_get_var_int") { rc = nc_get_var_int(_ncid, varid, (int *)data); } else if (func == "nc_get_var_long") { rc = nc_get_var_long(_ncid, varid, (long *)data); } else if (func == "nc_get_var_uchar") { rc = nc_get_var_uchar(_ncid, varid, (unsigned char *)data); } else { VAssert(func == ""); } MY_NC_ERR(rc, _path, func); return (0); } int NetCDFCpp::GetVar(string varname, void *data) const { return (_GetVar(varname, (void *)data, "nc_get_var")); } int NetCDFCpp::GetVar(string varname, float *data) const { return (_GetVar(varname, (void *)data, "nc_get_var_float")); } int NetCDFCpp::GetVar(string varname, double *data) const { return (_GetVar(varname, (void *)data, "nc_get_var_double")); } int NetCDFCpp::GetVar(string varname, int *data) const { return (_GetVar(varname, (void *)data, "nc_get_var_int")); } int NetCDFCpp::GetVar(string varname, long *data) const { return (_GetVar(varname, (void *)data, "nc_get_var_long")); } int NetCDFCpp::GetVar(string varname, unsigned char *data) const { return (_GetVar(varname, (void *)data, "nc_get_var_uchar")); } int NetCDFCpp::CopyVar(string varname, NetCDFCpp &ncdf_out) const { nc_type xtype; int rc = NetCDFCpp::InqVartype(varname, xtype); if (rc < 0) return (-1); size_t elem_size = NetCDFCpp::SizeOf(xtype); VAssert(elem_size != 0); vector dimnames; vector dims; rc = NetCDFCpp::InqVarDims(varname, dimnames, dims); if (rc < 0) return (-1); size_t nelements = 1; for (int i = 0; i < dims.size(); i++) nelements *= dims[i]; unsigned char *data = new unsigned char[nelements * elem_size]; rc = NetCDFCpp::GetVar(varname, (void *)data); if (rc < 0) { delete[] data; return (-1); } rc = ncdf_out.PutVar(varname, (void *)data); if (rc < 0) { delete[] data; return (-1); } delete[] data; return (NC_NOERR); } bool NetCDFCpp::InqDimDefined(string dimname) { int dummy; int rc = nc_inq_dimid(_ncid, dimname.c_str(), &dummy); if (rc == NC_NOERR) return (true); return (false); } bool NetCDFCpp::InqAttDefined(string varname, string attname) { int varid = -1; if (varname.empty()) { varid = NC_GLOBAL; } else { int rc = nc_inq_varid(_ncid, varname.c_str(), &varid); if (rc != NC_NOERR) return (false); } int dummy; int rc = nc_inq_attid(_ncid, varid, attname.c_str(), &dummy); if (rc == NC_NOERR) return (true); return (false); } int NetCDFCpp::InqVarnames(vector &varnames) const { varnames.clear(); int ndims, nvars, natts, unlimitedid; int rc = nc_inq(_ncid, &ndims, &nvars, &natts, &unlimitedid); MY_NC_ERR(rc, _path, "nc_inq()"); for (int varid = 0; varid < nvars; varid++) { char namebuf[NC_MAX_NAME + 1]; nc_type xtype; int dimids[NC_MAX_VAR_DIMS]; rc = nc_inq_var(_ncid, varid, namebuf, &xtype, &ndims, dimids, &natts); MY_NC_ERR(rc, _path, "nc_inq_var()"); varnames.push_back(namebuf); } return (0); } ================================================ FILE: lib/wasp/SignificanceMap.cpp ================================================ // // $Id: SignificanceMap.cpp,v 1.12 2012/08/29 19:36:37 alannorton Exp $ // #include #include #include using namespace VAPoR; // gets the right-adjusted N bits of quantity TARG // starting from bit position POSS // #define GETBITS(TARG, POSS, N) (((TARG) >> ((POSS) + 1 - (N))) & ~(~0ULL << (N))) // set N bits of quantity TARG starting from position // POSS to the right-most N bits in integer SRC // #define PUTBITS(TARG, POSS, N, SRC) \ (TARG) &= ~(~((~0ULL) << (N)) << (((POSS) + 1) - (N))); \ (TARG) |= (((SRC) & ~((~0ULL) << (N))) << (((POSS) + 1) - (N))) using namespace std; template void swapbytes(T *ptr, size_t nelem) { for (size_t i = 0; i < nelem; i++) { unsigned char *uptr = (unsigned char *)&ptr[i]; unsigned char *p1 = uptr; unsigned char *p2 = uptr + sizeof(T) - 1; unsigned char t; for (int j = 0; j < (sizeof(T) >> 1); j++) { t = *p1; *p1 = *p2; *p2 = t; p1++; p2--; } } } size_t SignificanceMap::_GetBitsPerIdx(vector dims) { size_t size = 1; for (int i = 0; i < dims.size(); i++) { size *= dims[i]; } // Compute # bits needed per entry for encoded form of sigMapVec // size_t bits_per_idx = 1; size--; while ((size = (size >> 1))) bits_per_idx++; return (bits_per_idx); } int SignificanceMap::_SignificanceMap(vector dims) { _dimsVec.clear(); _sigMapVec.clear(); _sigMapSize = 1; _sorted = true; for (int i = 0; i < dims.size(); i++) { if (dims[i] < 1) { SetErrMsg("Zero length dimensions not permitted"); return (-1); } _sigMapSize *= dims[i]; _dimsVec.push_back(dims[i]); } _idxentry = 0; _nx = _ny = _nz = _nt = 1; if (dims.size() >= 1) _nx = dims[0]; if (dims.size() >= 2) _ny = dims[1]; if (dims.size() >= 3) _nz = dims[2]; if (dims.size() >= 4) _nt = dims[3]; // Compute # bits needed per entry for encoded form of sigMapVec // //_bits_per_idx = 1; // size_t tmpsize = _sigMapSize - 1; // while (tmpsize = (tmpsize >> 1)) _bits_per_idx++; _bits_per_idx = _GetBitsPerIdx(_dimsVec); return (0); } int SignificanceMap::_SignificanceMap(const unsigned char *map, std::vector dims) { if (_SignificanceMap(dims) < 0) return (-1); return (SetMap(map)); } SignificanceMap::SignificanceMap() { vector dims; dims.push_back(1); _sigMapEncode = NULL; _sigMapEncodeSize = 0; if (_SignificanceMap(dims) < 0) return; } SignificanceMap::SignificanceMap(size_t nx, size_t ny, size_t nz, size_t nt) { vector dims; dims.push_back(nx); dims.push_back(ny); dims.push_back(nz); dims.push_back(nt); _sigMapEncode = NULL; _sigMapEncodeSize = 0; if (_SignificanceMap(dims) < 0) return; } SignificanceMap::SignificanceMap(vector dims) { _sigMapEncode = NULL; _sigMapEncodeSize = 0; if (_SignificanceMap(dims) < 0) return; } // // Significance map constructors for 1D, 2D, 3D, and 4D maps, using // a previously created map. I.e. a map returned from GetMap() // SignificanceMap::SignificanceMap(const unsigned char *map, size_t nx, size_t ny, size_t nz, size_t nt) { vector dims; dims.push_back(nx); dims.push_back(ny); dims.push_back(nz); dims.push_back(nt); _sigMapEncode = NULL; _sigMapEncodeSize = 0; if (_SignificanceMap(map, dims) < 0) return; } SignificanceMap::SignificanceMap(const unsigned char *map, vector dims) { _sigMapEncode = NULL; _sigMapEncodeSize = 0; if (_SignificanceMap(map, dims) < 0) return; } SignificanceMap::SignificanceMap(const SignificanceMap &rhs) { if (this == &rhs) return; this->_nx = rhs._nx; this->_ny = rhs._ny; this->_nz = rhs._nz; this->_nt = rhs._nt; this->_sorted = rhs._sorted; this->_dimsVec = rhs._dimsVec; this->_sigMapSize = rhs._sigMapSize; this->_sigMapVec = rhs._sigMapVec; this->_bits_per_idx = rhs._bits_per_idx; this->_sigMapEncodeSize = rhs._sigMapEncodeSize; this->_sigMapEncode = NULL; this->_idxentry = rhs._idxentry; // handle raw pointers // if (rhs._sigMapEncode) { this->_sigMapEncode = new unsigned char[this->_sigMapEncodeSize]; memcpy(this->_sigMapEncode, rhs._sigMapEncode, this->_sigMapEncodeSize); } } SignificanceMap &SignificanceMap::operator=(const SignificanceMap &rhs) { if (this == &rhs) return (*this); this->_nx = rhs._nx; this->_ny = rhs._ny; this->_nz = rhs._nz; this->_nt = rhs._nt; this->_sorted = rhs._sorted; this->_dimsVec = rhs._dimsVec; this->_sigMapSize = rhs._sigMapSize; this->_sigMapVec = rhs._sigMapVec; this->_bits_per_idx = rhs._bits_per_idx; this->_sigMapEncodeSize = rhs._sigMapEncodeSize; this->_sigMapEncode = NULL; this->_idxentry = rhs._idxentry; // handle raw pointers // if (rhs._sigMapEncode) { this->_sigMapEncode = new unsigned char[this->_sigMapEncodeSize]; memcpy(this->_sigMapEncode, rhs._sigMapEncode, this->_sigMapEncodeSize); } return *this; } SignificanceMap::~SignificanceMap() { if (_sigMapEncode) { delete[] _sigMapEncode; } _sigMapEncode = NULL; } int SignificanceMap::Reshape(vector dims) { _dimsVec.clear(); if (dims.size() != _dimsVec.size()) { return (_SignificanceMap(dims)); } else { for (int i = 0; i < dims.size(); i++) { if (dims[i] != _dimsVec[i]) { return (_SignificanceMap(dims)); } } } return (0); // nothing to do } int SignificanceMap::Reshape(size_t nx, size_t ny, size_t nz, size_t nt) { vector dims; dims.push_back(nx); dims.push_back(ny); dims.push_back(nz); dims.push_back(nt); return Reshape(dims); } int SignificanceMap::Set(size_t idx) { if (idx >= _sigMapSize) { SetErrMsg("Coordinates out of range"); return (-1); } // if (Test(idx)) return(0); _sigMapVec.push_back(idx); // // See if sig map is still sorted // if (_sorted && (_sigMapVec.size() > 1)) { if (_sigMapVec[_sigMapVec.size() - 1] < _sigMapVec[_sigMapVec.size() - 2]) { _sorted = false; } } return (0); } int SignificanceMap::SetXYZT(size_t x, size_t y, size_t z, size_t t) { if (_dimsVec.size() > 4) { SetErrMsg("Method not implemented for dimensions greater than 4"); return (-1); } if (x >= _nx || y >= _ny || z >= _nz || t >= _nt) { SetErrMsg("Coordinates out of range"); return (-1); } size_t idx = (t * _nz * _ny * _nx) + (z * _ny * _nx) + (y * _nx) + x; return (Set(idx)); } int SignificanceMap::Clear(size_t idx) { if (idx >= _sigMapSize) { SetErrMsg("Coordinates out of range"); return (-1); } if (!Test(idx)) return (0); vector::iterator itr; for (itr = _sigMapVec.begin(); itr != _sigMapVec.end();) { if (*itr == idx) { _sigMapVec.erase(itr); // We're being overly cautious here - entries should never // be duplicated // itr = _sigMapVec.begin(); } } return (0); } int SignificanceMap::ClearXYZT(size_t x, size_t y, size_t z, size_t t) { if (_dimsVec.size() > 4) { SetErrMsg("Method not implemented for dimensions greater than 4"); return (-1); } if (x >= _nx || y >= _ny || z >= _nz || t >= _nt) { SetErrMsg("Coordinates out of range"); return (-1); } size_t idx = (t * _nz * _ny * _nx) + (z * _ny * _nx) + (y * _nx) + x; return (Clear(idx)); } void SignificanceMap::Clear() { _sigMapVec.clear(); } int SignificanceMap::GetCoordinates(size_t offset, size_t *idx) const { if (offset >= _sigMapVec.size()) { SetErrMsg("Index out of range"); return (-1); } *idx = _sigMapVec[offset]; return (0); } int SignificanceMap::GetCoordinatesXYZT(size_t offset, size_t *x, size_t *y, size_t *z, size_t *t) const { if (_dimsVec.size() > 4) { SetErrMsg("Method not implemented for dimensions greater than 4"); return (-1); } size_t idx; if (GetCoordinates(offset, &idx) < 0) return (-1); *t = idx / (_nz * _ny * _nx); idx -= (*t * _nz * _ny * _nx); *z = idx / (_ny * _nx); idx -= (*z * _ny * _nx); *y = idx / _nx; idx -= (*y * _nx); *x = idx; return (0); } void SignificanceMap::GetNextEntryRestart() { if (!_sorted) SignificanceMap::Sort(); _idxentry = 0; } int SignificanceMap::GetNextEntry(size_t *idx) { if (_idxentry >= _sigMapVec.size()) return (0); *idx = _sigMapVec[_idxentry]; _idxentry++; return (1); } int SignificanceMap::GetNextEntryXYZT(size_t *xptr, size_t *yptr, size_t *zptr, size_t *tptr) { if (_dimsVec.size() > 4) { SetErrMsg("Method not implemented for dimensions greater than 4"); return (-1); } size_t idx; if (GetNextEntry(&idx)) { size_t t = idx / (_nz * _ny * _nx); idx -= (t * _nz * _ny * _nx); size_t z = idx / (_ny * _nx); idx -= (z * _ny * _nx); size_t y = idx / _nx; idx -= (y * _nx); size_t x = idx; if (xptr) *xptr = x; if (yptr) *yptr = y; if (zptr) *zptr = z; if (tptr) *tptr = t; return (1); } return (0); } size_t SignificanceMap::GetMapSize(vector dims, size_t num_entries) { // Calculate size of encoded map // size_t mapsize; size_t tbits = num_entries * _GetBitsPerIdx(dims); if (tbits) mapsize = (tbits - 1) / BITSPERBYTE + 1 + HEADER_SIZE; else mapsize = HEADER_SIZE; return (mapsize); } size_t SignificanceMap::GetMapSize(size_t num_entries) const { return (GetMapSize(_dimsVec, num_entries)); } void SignificanceMap::GetMap(unsigned char *encodedMap) { unsigned long LSBTest = 1; bool do_swapbytes = false; if (!(*(char *)&LSBTest)) { // swap to MSBFirst do_swapbytes = true; } memset(_sigMapEncode, 0, _sigMapEncodeSize); // // Encode header // bytes[0-2] : magic // bytes[3] : version number // bytes[4-11] : _sigMapVec.size() // bytes[12-19] : _dimsVec.size() // bytes[20-] : _dimsVec[i] // encodedMap[0] = encodedMap[1] = encodedMap[2] = 'c'; encodedMap[3] = VDF_VERSION; vector header_data; header_data.push_back(_sigMapVec.size()); header_data.push_back(_dimsVec.size()); for (int i = 0; i < _dimsVec.size(); i++) header_data.push_back(_dimsVec[i]); // encode num entries and sigmap dimens // unsigned char *ucptr = &encodedMap[4]; for (int i = 0; i < header_data.size(); i++) { size_t entry = header_data[i]; VAssert(((ucptr + 8) - encodedMap) <= HEADER_SIZE); if (do_swapbytes) { swapbytes(&entry, 1); } unsigned char *cptr = (unsigned char *)&entry; for (int j = 0; j < sizeof(entry); j++) { ucptr[j] = cptr[j]; } for (int j = sizeof(entry); j < 8; j++) { ucptr[j] = 0; } ucptr += 8; } unsigned char *ptr = encodedMap + HEADER_SIZE; int bib = BITSPERBYTE; // bits available in current byte int p = BITSPERBYTE - 1; if (!_sorted) SignificanceMap::Sort(); for (size_t i = 0; i < _sigMapVec.size(); i++) { size_t idx = _sigMapVec[i]; int tbits = _bits_per_idx; while (tbits) { int n = min(tbits, bib); PUTBITS(*ptr, p, n, idx >> (tbits - n)); p -= n; tbits -= n; bib -= n; if (bib == 0) { ptr++; bib = BITSPERBYTE; p = BITSPERBYTE - 1; } } } } void SignificanceMap::GetMap(const unsigned char **map, size_t *maplen) { *map = NULL; *maplen = 0; size_t mapsize = GetMapSize(); if (_sigMapEncodeSize < mapsize) { size_t l = mapsize; // hack to allow word-size reads while (l % 4) l++; if (_sigMapEncode) { delete[] _sigMapEncode; } _sigMapEncode = new unsigned char[l]; _sigMapEncodeSize = l; } memset(_sigMapEncode, 0, _sigMapEncodeSize); *map = _sigMapEncode; *maplen = mapsize; return (GetMap(_sigMapEncode)); } int SignificanceMap::SetMap(const unsigned char *map) { if (map[0] != 'c' || map[1] != 'c' || map[2] != 'c') { SetErrMsg("Invalid significance map - bogus header"); return (-1); } if (map[3] > VDF_VERSION) { SetErrMsg("Invalid significance map - bogus header"); return (-1); } unsigned long LSBTest = 1; bool do_swapbytes = false; if (!(*(char *)&LSBTest)) { // swap to MSBFirst do_swapbytes = true; } unsigned char version = map[3]; const unsigned char *ucptr = &map[4]; size_t numentries = 0; unsigned char *cptr = (unsigned char *)&numentries; for (int i = 0; i < sizeof(numentries); i++) { cptr[i] = ucptr[i]; } ucptr += 8; if (do_swapbytes) swapbytes(&numentries, 1); size_t header_size = HEADER_SIZE; // Check for old style (version 1) encoding // if (version == 01) { if (numentries > _sigMapSize) { SetErrMsg("SignificanceMap shape does not match encoded map"); return (-1); } header_size = 16; } else { size_t ndims = 0; cptr = (unsigned char *)&ndims; for (int i = 0; i < sizeof(ndims); i++) { cptr[i] = ucptr[i]; } ucptr += 8; if (do_swapbytes) swapbytes(&ndims, 1); vector dims; for (int j = 0; j < ndims; j++) { size_t dim = 0; cptr = (unsigned char *)&dim; for (int i = 0; i < sizeof(dim); i++) { cptr[i] = ucptr[i]; } ucptr += 8; if (do_swapbytes) swapbytes(&dim, 1); dims.push_back(dim); } if (_SignificanceMap(dims) < 0) return (-1); } _sigMapVec.clear(); _sigMapVec.reserve(numentries); const unsigned char *ptr = map + header_size; int bib = BITSPERBYTE; // bits remaining in current byte _sorted = true; size_t idxprev = 0; for (size_t i = 0; i < numentries; i++) { size_t idx = 0; int tbits = _bits_per_idx; int p = _bits_per_idx - 1; while (tbits) { int n = min(tbits, bib); PUTBITS(idx, p, n, *ptr >> (bib - n)); p -= n; tbits -= n; bib -= n; if (bib == 0) { ptr++; bib = BITSPERBYTE; } } // // Should probably call SignificanceMap::Set() here so // that we check for duplicate values. But this is quicker. // _sigMapVec.push_back(idx); if (idx < idxprev) { _sorted = false; } idxprev = idx; } return (0); } int SignificanceMap::Append(const SignificanceMap &smap) { if (_sigMapVec.size() == 0) { if (_SignificanceMap(smap._dimsVec) < 0) return (-1); } if (_dimsVec.size() != smap._dimsVec.size()) { SetErrMsg("Dimension mismatch"); return (-1); } for (int i = 0; i < _dimsVec.size(); i++) { if (_dimsVec[i] != smap._dimsVec[i]) { SetErrMsg("Dimension mismatch"); return (-1); } } for (size_t i = 0; i < smap._sigMapVec.size(); i++) { int rc = this->Set(smap._sigMapVec[i]); if (rc < 0) return (-1); } return (0); } void SignificanceMap::Invert() { vector tmpvec = _sigMapVec; if (!_sorted) SignificanceMap::Sort(); _sigMapVec.clear(); size_t idx = 0; for (size_t i = 0; i < tmpvec.size(); i++) { while (idx != tmpvec[i]) { _sigMapVec.push_back(idx); idx++; } idx++; } while (idx < _sigMapSize) { _sigMapVec.push_back(idx); idx++; } } void SignificanceMap::Sort() { sort(_sigMapVec.begin(), _sigMapVec.end()); _sorted = true; } namespace VAPoR { std::ostream &operator<<(std::ostream &o, const SignificanceMap &sigmap) { o << "SignificanceMap" << endl; o << " _nx : " << sigmap._nx << endl; o << " _ny : " << sigmap._ny << endl; o << " _nz : " << sigmap._nz << endl; o << " _nt : " << sigmap._nt << endl; o << " _sorted : " << sigmap._sorted << endl; o << " _dimsVec : "; for (int i = 0; i < sigmap._dimsVec.size(); i++) { o << sigmap._dimsVec[i] << " "; } o << endl; o << " _sigMapSize : " << sigmap._sigMapSize << endl; o << " _bits_per_idx : " << sigmap._bits_per_idx << endl; o << " _sigMapEncodeSize : " << sigmap._sigMapEncodeSize << endl; o << " _idxentry : " << sigmap._idxentry << endl; o << " _sigMapVec : " << endl; for (int i = 0; i < sigmap._sigMapVec.size(); i++) { o << " " << i << " " << sigmap._sigMapVec[i] << endl; } return (o); } }; // namespace VAPoR ================================================ FILE: lib/wasp/TODO ================================================ WASP ---- # git-test vapor_3_0 # # done - Support Min/Max & clamp in decompression serialize (order) threaded I/O Should 'unlimited' dimensions be supported ? done - ***If (cratios.size() == 1 and cratios[0] == 1) do not transform variable, but still block it. This facilitates use of coordinate variables that are not compressed with data variables that are. API should be able to operate on conventional netcdf files (files without the WASP attribute). Currently most methods return error (unecessarily) if _waspFile is not true. VDCNetCDF -------- Refinement level should be supported for uncompressed variables to handle uncompressed coordinate variables. Reading a coordinate variable (that was not compressed) should do the appropriate averaging based on the wavelet (symatric vs asymetric) VDC --- Should the number of time dimensions be restricted to one? Either way needs to be tested Not sure what Uniform coordinate variables are actually doing. Their uniformness is not guaranteed (can be written to), Consider moving VDC::GetNumTimeSteps() to VarBase (or doing away with it entirely - it's redundant). Make sure open mode (RWA) is handled correctly both for supporting vdccreate and 2vdc operations Need to be consistent in interpretation of BS (e.b. bs== dimensions, bs=1, etc) for WASP.cpp, VDC* Verify that DC ensures that dimensions are always in correct order. In particular, uses of DC API don't have to verify order is correct when getting a variables dimensions. DataMgr ------- Handle derived variable coordinates error checking convert all global time steps to local Rename DataMgrV3 to DataMgr RegularGrid ----------- Iterator for bounding volume defined in user coords FILES WE DONT SYNC DataMgr.cpp DataMgrFactor.cpp WASP ---- done - integer wavelet transforms - haar and cdf5/3. Use int haar for missing value mask DCCF ---- Interpolate structured to regular grid (using weithtable) Initialize, if called multipe times, doesn't clean up. Probably true elsewhere. GetAtt*() are no-ops derived, cartographic coordinates (e.g. lonX) are not blocked. However, the geographic coordinates (e.g. lon) are. DCWRF ---- GetAtt*() are no-ops Idealized grid (MAP_PROJ = 0) not supported. Conversion of yochen data uses XLONG and XLAT, which are set to bogus values (-90 for all points). See vapor-2.x, DCReaderWRF for proper calculation using DX and DY No map projection returned ALL --- ReadSlice should work with 1D data NetCDFCollection ---------------- DerivedVar::Open returns a file descriptor which is passed into Read(), and Close(). However, most implementations igore the fd. Is it needed? Variables with reversed coordinates not supported. See /glade/p/DASG/VAPOR/Data/UKMet/GEMS* MISC ---- verify cratio=1 case works (vdc2raw, raw2vdc) unitialized memory read with hundred.nc: ../../targets/Linux_x86_64/bin/test_datamgr -nts 1 -loop 1 -memsize 2000 -var v $c/hundred.nc ================================================ FILE: lib/wasp/WASP.cpp ================================================ #include "vapor/VAssert.h" #include #include #include #include #include "vapor/utils.h" #include "vapor/MatWaveBase.h" #include "vapor/Compressor.h" #include "vapor/WASP.h" using namespace VAPoR; using namespace Wasp; namespace { // Size of header at beginning of each compression block // const size_t BLK_HDR_SZ = 2; size_t linearize_coords(vector coords, vector dims) { reverse(coords.begin(), coords.end()); reverse(dims.begin(), dims.end()); return (LinearizeCoords(coords, dims)); } // // Map possibly unaligned hyperslab coords (start and count) // into block-aligned coordinates // void block_align(const vector &start, const vector &count, const vector &bs, vector &astart, vector &acount) { astart = start; acount = count; VAssert(start.size() == count.size()); VAssert(start.size() == bs.size()); for (int i = 0; i < start.size(); i++) { size_t stop = astart[i] + acount[i] - 1; astart[i] = (astart[i] / bs[i] * bs[i]); stop = (stop / bs[i]) * bs[i] + (bs[i] - 1); acount[i] = stop - astart[i] + 1; } } vector compressor_bs(vector bs) { vector my_bs = bs; reverse(my_bs.begin(), my_bs.end()); // order fastest to slowest // Remove slowest varying dimensions of length 1 // while (my_bs.size() && my_bs[my_bs.size() - 1] == 1) { my_bs.pop_back(); } return (my_bs); } // vector subtraction. Return a - b // vector vector_sub(const vector &a, const vector &b) { VAssert(a.size() == b.size()); vector c; for (int i = 0; i < a.size(); i++) { VAssert(a[i] >= b[i]); c.push_back(a[i] - b[i]); } return (c); } // // Helper class for NetCDF style hyperslab indexing arithmetic // class vectorinc { public: // start and count define hyperslab coordinates // dims define overall dimensions of array // inc is the increment step to be added to start // vectorinc(vector start, vector count, vector dims, vector inc); // Compute next starting coordinates by adding inc to previous // starting coordinates. As a convenience return the linear offset // of the new starting coordinates coordinates. // bool next(vector &newstart, size_t &offset); // Computh i'th coordinate after 'index' increments by 'inc' // void ith(size_t index, vector &start, size_t &offset) const; // Number of iterations required to increment 'start' by 'inc' // to get to 'count' // size_t num() const { return (_num); }; private: vector _start; vector _count; vector _end; // ending coordinates (start + count) vector _dims; vector _next; vector _inc; size_t _num; }; vectorinc::vectorinc(vector start, vector count, vector dims, vector inc) { VAssert(start.size() == count.size()); VAssert(start.size() == dims.size()); VAssert(start.size() == inc.size()); for (int i = 0; i < start.size(); i++) { _end.push_back(start[i] + count[i]); // VAssert(_end[i] <= dims[i]); } _start = start; _next = start; _count = count; _dims = dims; _inc = inc; _num = 1; bool done; do { done = false; int i = start.size() - 1; while (i >= 0 && !done) { start[i] += _inc[i]; if (start[i] >= _end[i]) { start[i] = _start[i]; } else { done = true; _num++; } i--; } } while (done); } void vectorinc::ith(size_t index, vector &start, size_t &offset) const { VAssert(index < _num); start.clear(); offset = 0; start = _start; for (size_t idx = 0; idx < index; idx++) { int i = start.size() - 1; bool done = false; while (i >= 0 && !done) { start[i] += _inc[i]; if (start[i] >= _end[i]) { start[i] = _start[i]; } else { done = true; } i--; } } offset = linearize_coords(start, _dims); } #ifdef UNUSED bool vectorinc::next(vector &start, size_t &offset) { offset = 0; int i = _next.size() - 1; bool done = false; while (i >= 0 && !done) { _next[i] += _inc[i]; if (_next[i] >= _end[i]) { _next[i] = _start[i]; } else { done = true; } i--; } start = _next; offset = linearize_coords(start, _dims); return (done); } #endif // Execution thread state for data reads and writes // class thread_state { public: int _id; EasyThreads * _et; // one per thread int _nthreads; string _varname; vector _ncdfcptrs; // one for each file vector _start; vector _count; vector _bs; vector _udims; vector _ncoeffs; vector _encoded_dims; vector _compressors; // one per thread void * _data; // global (shared by all threads) int _data_type; // typeof(*_data) unsigned char * _mask; // global (shared by all threads) void * _block; // private (not shared) void * _coeffs; // private (not shared) int _block_type; // typeof(*_block) and typeof(*_coeffs) int _xtype; // external storage NetCDF storage unsigned char * _maps; // private (not shared) int _level; bool _unblock_flag; // unblock the data after reconstruction? static int _status; // error indicator thread_state(int id, EasyThreads *et, int nthreads, string &varname, const vector &ncdfcptrs, const vector &start, const vector &count, const vector &bs, const vector &udims, const vector &ncoeffs, const vector &encoded_dims, const vector &compressors, void *data, int data_type, unsigned char *mask, void *block, void *coeffs, int block_type, int xtype, unsigned char *maps, int level, bool unblock_flag) : _id(id), _et(et), _nthreads(nthreads), _varname(varname), _ncdfcptrs(ncdfcptrs), _start(start), _count(count), _bs(bs), _udims(udims), _ncoeffs(ncoeffs), _encoded_dims(encoded_dims), _compressors(compressors), _data(data), _data_type(data_type), _mask(mask), _block(block), _coeffs(coeffs), _block_type(block_type), _xtype(xtype), _maps(maps), _level(level), _unblock_flag(unblock_flag) { _status = 0; } }; int thread_state::_status = 0; // Convert voxel coordinates, 'vcoords', to block coordinates, 'bcoords', // assuming a block size of 'bs'. 'residual' is any offset within // the block if 'vcoords' is not block-aligned. // void to_block_coords(vector vcoords, vector bs, vector &bcoords, size_t &residual) { VAssert(vcoords.size() == bs.size()); bcoords = vcoords; size_t factor = 1; residual = 0; for (int i = 0; i < vcoords.size(); i++) { residual += factor * (bcoords[i] % bs[i]); factor *= bs[i]; bcoords[i] /= bs[i]; } } // // Pad a line using the appropriate boundary extension method // based on 'mode' // template void pad_line(string mode, T *line_start, size_t l1, // length of valid data size_t l2, // total length of array long stride) { T *ptr = line_start + ((long)l1 * stride); long index; int inc; VAssert(l1 > 0 && stride != 0); if (l1 == l2) return; if (l1 == 1) { int dir = stride < 0 ? -1 : 1; for (size_t l = l1; l < l2; l += dir) { *ptr = *line_start; ptr += stride; } return; } // // Symmetric-halfpoint. If a signal looks like ABCDE, the extended signal // looks like: // // EEDCBAABCDEEDCBAA // ^^^^^ // if (mode.compare("symh") == 0) { index = (long)l1 - 1; inc = 0; for (size_t l = l1; l < l2; l++) { *ptr = line_start[(size_t)index * stride]; ptr += stride; if (index == 0) { if (inc == 0) inc = 1; else inc = 0; } else if (index == (long)l1 - 1) { if (inc == 0) inc = -1; else inc = 0; } index += inc; } } // // Symmetric-wholepoint. If a signal looks like ABCDE, the extended signal // looks like: // // DEDCBABCDEDCBAB // ^^^^^ else if (mode.compare("symw") == 0) { index = (long)l1 - 2; inc = -1; for (size_t l = l1; l < l2; l++) { *ptr = line_start[(size_t)index * stride]; ptr += stride; if (index == 0) { inc = 1; } else if (index == (long)l1 - 1) { inc = -1; } index += inc; } } // // Periodic. If a signal looks like ABCDE, the extended signal // looks like: // // ...ABCDABCDEABCDABCD... // ^^^^^ else if (mode.compare("per") == 0) { index = (int)0; for (size_t l = l1; l < l2; l++) { *ptr = line_start[(size_t)index * stride]; ptr += stride; index++; } } // // SP0. If a signal looks like ABCDE, the extended signal // looks like: // // ...AAAAABCDEEEEE... // ^^^^^ else if (mode.compare("sp0") == 0) { index = (long)l1 - 1; for (size_t l = l1; l < l2; l++) { *ptr = line_start[(size_t)index * stride]; ptr += stride; } } // Default to sp0 // else { index = (long)l1 - 1; for (size_t l = l1; l < l2; l++) { *ptr = line_start[(size_t)index * stride]; ptr += stride; } } } // // Perform in-place byte swapping // void swapbytes(void *ptr, size_t ws, size_t nelem) { for (size_t i = 0; i < nelem; i++) { unsigned char *uptr = ((unsigned char *)ptr) + (i * ws); unsigned char *p1 = uptr; unsigned char *p2 = uptr + ws - 1; unsigned char t; for (int j = 0; j < (ws >> 1); j++) { t = *p1; *p1 = *p2; *p2 = t; p1++; p2--; } } } // Sum elements in a vector // size_t vsum(vector v) { size_t ntotal = 0; for (int i = 0; i < v.size(); i++) ntotal += v[i]; return (ntotal); } // Product of elements in a vector // size_t vproduct(vector a) { size_t ntotal = 1; for (int i = 0; i < a.size(); i++) ntotal *= a[i]; return (ntotal); } #ifdef UNUSED_FUNCTION // Elementwise difference between vector a and b (return (a-b)); // vector vdiff(vector a, vector b) { VAssert(a.size() == b.size()); vector c(a.size(), 0); for (int i = 0; i < a.size(); i++) c[i] = a[i] - b[i]; return (c); } #endif // Extract a single block of data from an array. Perform padding as // needed based on mode value if this is a boundary block // Handles 1D, 2D, and 3D arrays // // data : pointer to start of array // dims : dimensions of array 'data' // start: starting coordinates of block within array 'data' (need not // be block aligned) // block : pointer to start of block where data should be copied // bs : dimensions of block. // min, max : range of data values within block // template void Block(const T *data, const unsigned char *mask, vector dims, vector start, U *block, vector bs, string mode, U &min, U &max) { min = 0; max = 0; VAssert(dims.size() >= 1 && dims.size() <= 4); VAssert(dims.size() == start.size()); VAssert(dims.size() == bs.size()); size_t offset = linearize_coords(start, dims); data += offset; if (mask) mask += offset; // // Only 1D, 2D, and 3D blocks handled // while (bs.size() && bs[0] == 1) { bs.erase(bs.begin()); dims.erase(dims.begin()); start.erase(start.begin()); } int rank = bs.size(); // dimensions of volume // size_t nx = rank >= 1 ? dims[rank - 1] : 1; size_t ny = rank >= 2 ? dims[rank - 2] : 1; size_t nz = rank >= 3 ? dims[rank - 3] : 1; // dimensions of block // size_t nbx = rank >= 1 ? bs[rank - 1] : 1; size_t nby = rank >= 2 ? bs[rank - 2] : 1; size_t nbz = rank >= 3 ? bs[rank - 3] : 1; // stopping coordinates within block, handling boundary cases // for non-block-aligned regions // size_t xstop = nbx; size_t ystop = nby; size_t zstop = nbz; if (rank >= 1 && (start[rank - 1] + nbx) > dims[rank - 1]) { xstop = dims[rank - 1] - start[rank - 1]; } if (rank >= 2 && (start[rank - 2] + nby) > dims[rank - 2]) { ystop = dims[rank - 2] - start[rank - 2]; } if (rank >= 3 && (start[rank - 3] + nbz) > dims[rank - 3]) { zstop = dims[rank - 3] - start[rank - 3]; } // // These flags are true if this is a boundary block && the volume // dimensions are not block aligned. // bool xbdry = rank >= 1 && start[rank - 1] + nbx > nx; bool ybdry = rank >= 2 && start[rank - 2] + nby > ny; bool zbdry = rank >= 3 && start[rank - 3] + nbz > nz; double ave = 0.0; min = (U)data[0]; max = (U)data[0]; if (mask) { size_t n = 0; double total = 0.0; for (size_t z = 0; z < zstop; z++) { for (size_t y = 0; y < ystop; y++) { for (size_t x = 0; x < xstop; x++) { size_t index = nx * ny * z + nx * y + x; if (!mask[index]) continue; U v = (U)data[index]; if (n == 0) { min = max = (U)v; } n++; total += v; } } } if (n) { ave = total / (double)n; } } // copy data to block and handle mask if there is one // for (size_t z = 0; z < zstop; z++) { for (size_t y = 0; y < ystop; y++) { for (size_t x = 0; x < xstop; x++) { size_t index = nx * ny * z + nx * y + x; double v; if (mask && !mask[index]) { v = ave; } else { v = data[index]; if (v < min) min = (U)v; if (v > max) max = (U)v; } block[z * nbx * nby + y * nbx + x] = v; } } } if (xbdry) { U *line_start; for (size_t z = 0; z < nbz; z++) { for (size_t y = 0; y < nby; y++) { line_start = block + z * nby * nbx + y * nby; pad_line(mode, line_start, xstop, nbx, 1); } } } if (ybdry) { U *line_start; for (size_t z = 0; z < nbz; z++) { for (size_t x = 0; x < nbx; x++) { line_start = block + z * nby * nbx + x; pad_line(mode, line_start, ystop, nby, nbx); } } } if (zbdry) { U *line_start; for (size_t y = 0; y < nby; y++) { for (size_t x = 0; x < nbx; x++) { line_start = block + y * nbx + x; pad_line(mode, line_start, zstop, nbz, nby * nbx); } } } } // Copy a block of blocked data into a contiguous array (unblocking // the data). Handles 1D, 2D, and 3D arrays // // block : pointer to start of block where data should be copied from // bs : dimensions of block. // data : pointer to start of destination array // origin : coordinates of origin of data array // dims : dimensions of array // start: starting coordinates of block within array // template void UnBlock(U *block, vector bs, T *data, vector dims, vector origin, vector start) { VAssert(dims.size() >= 1 && dims.size() <= 4); VAssert(dims.size() == start.size()); VAssert(dims.size() == bs.size()); VAssert(dims.size() == origin.size()); // Deal with block dimensions of length 1 // while (bs.size() && bs[0] == 1) { bs.erase(bs.begin()); origin.erase(origin.begin()); dims.erase(dims.begin()); start.erase(start.begin()); } int rank = bs.size(); // dimensions of volume // size_t nx = rank >= 1 ? dims[rank - 1] : 1; size_t ny = rank >= 2 ? dims[rank - 2] : 1; // size_t nz = rank >= 3 ? dims[rank-3] : 1; // dimensions of block // size_t nbx = rank >= 1 ? bs[rank - 1] : 1; size_t nby = rank >= 2 ? bs[rank - 2] : 1; size_t nbz = rank >= 3 ? bs[rank - 3] : 1; // starting coordinates within 'data' // size_t x0 = (rank >= 1 && start[rank - 1] > origin[rank - 1]) ? start[rank - 1] - origin[rank - 1] : 0; size_t y0 = (rank >= 2 && start[rank - 2] > origin[rank - 2]) ? start[rank - 2] - origin[rank - 2] : 0; size_t z0 = (rank >= 3 && start[rank - 3] > origin[rank - 3]) ? start[rank - 3] - origin[rank - 3] : 0; // starting and stop coordinates within block, handling boundary cases // for non-block-aligned regions // size_t xstart = 0; size_t ystart = 0; size_t zstart = 0; if (rank >= 1 && (origin[rank - 1] > start[rank - 1])) // non-aligned boundary xstart = origin[rank - 1] - start[rank - 1]; if (rank >= 2 && (origin[rank - 2] > start[rank - 2])) // non-aligned boundary ystart = origin[rank - 2] - start[rank - 2]; if (rank >= 3 && (origin[rank - 3] > start[rank - 3])) // non-aligned boundary zstart = origin[rank - 3] - start[rank - 3]; size_t xstop = nbx; size_t ystop = nby; size_t zstop = nbz; if (rank >= 1 && (start[rank - 1] + nbx) > (origin[rank - 1] + dims[rank - 1])) { xstop = origin[rank - 1] + dims[rank - 1] - start[rank - 1]; } if (rank >= 2 && (start[rank - 2] + nby) > (origin[rank - 2] + dims[rank - 2])) { ystop = origin[rank - 2] + dims[rank - 2] - start[rank - 2]; } if (rank >= 3 && (start[rank - 3] + nbz) > (origin[rank - 3] + dims[rank - 3])) { zstop = origin[rank - 3] + dims[rank - 3] - start[rank - 3]; } for (size_t z = zstart, zz = 0; z < zstop; z++, zz++) { for (size_t y = ystart, yy = 0; y < ystop; y++, yy++) { for (size_t x = xstart, xx = 0; x < xstop; x++, xx++) { data[nx * ny * (z0 + zz) + nx * (y0 + yy) + (x0 + xx)] = block[z * nbx * nby + y * nbx + x]; } } } } // Apply forward wavelet transfor to a block of data // // cmp : Compressor for wavelet transform // block : block of data // n : number of elements in 'block' // coeffs : storage for transformed coefficients // maps : storage for encoded significance maps // ncoeffs : vector describing partitioning of coefficients in 'coeffs' // encoded_dims : vector describing dimension of encoded block at // each compression level. // template int DecomposeBlock(Compressor *cmp, const T *block, size_t n, T *coeffs, unsigned char *maps, int xtype, vector ncoeffs, vector encoded_dims ) { vector sigmaps(ncoeffs.size()); int rc = cmp->Decompose(block, coeffs, ncoeffs, sigmaps); if (rc < 0) return (-1); // // Extract signficance maps from 'sigmaps' and copy them to 'maps' // unsigned char *mapptr = maps; for (int i = 0; i < ncoeffs.size(); i++) { size_t dimlen = i == 0 ? encoded_dims[i] - BLK_HDR_SZ : encoded_dims[i]; if (dimlen != ncoeffs[i]) { // last map not stored size_t sz = NetCDFCpp::SizeOf(xtype) * (dimlen - ncoeffs[i]); memset(mapptr, 0, sz); sigmaps[i].GetMap(mapptr); mapptr += sz; } } return (0); } // Apply inverse wavelet transfor to a block of data // // cmp : Compressor for wavelet transform // coeffs : storage for transformed coefficients // maps : storage for encoded significance maps // ncoeffs : vector describing partitioning of coefficients in 'coeffs' // encoded_dims : vector describing dimension of encoded block at // each compression level. // block : block of data // n : num elements in 'block' // level : reconstruction level in wavelet hierarchy // template int ReconstructBlock(Compressor *cmp, const T *coeffs, const T *datarange, const unsigned char *maps, int xtype, vector ncoeffs, vector encoded_dims, T *block, size_t n, int level) { // Clamp reconstructed values to original data range // cmp->ClampMinOnOff() = true; cmp->ClampMaxOnOff() = true; cmp->ClampMin() = (double)datarange[0]; cmp->ClampMax() = (double)datarange[1]; vector sigmaps(ncoeffs.size()); // // Extract encoded significance maps // const unsigned char *mapptr = maps; bool reconstruct_map = false; for (int i = 0; i < ncoeffs.size(); i++) { size_t dimlen = i == 0 ? encoded_dims[i] - BLK_HDR_SZ : encoded_dims[i]; if (dimlen != ncoeffs[i]) { // last map not stored int rc = sigmaps[i].SetMap(mapptr); if (rc < 0) return (-1); size_t sz = NetCDFCpp::SizeOf(xtype) * (dimlen - ncoeffs[i]); mapptr += sz; } else { reconstruct_map = true; } } // // In some cases the significance map need not be explicity stored, // and can be reconstructed from previous sigmaps // if (reconstruct_map) { sigmaps[ncoeffs.size() - 1].Clear(); // Edge case for when sigmap isn't stored at all // if (ncoeffs.size() == 1 && encoded_dims[0] - BLK_HDR_SZ == ncoeffs[0]) { sigmaps[0].Reshape(ncoeffs[0]); for (int i = 0; i < ncoeffs[0]; i++) { sigmaps[0].Set(i); } } else { for (int i = 0; i < ncoeffs.size() - 1; i++) { sigmaps[ncoeffs.size() - 1].Append(sigmaps[i]); } sigmaps[ncoeffs.size() - 1].Sort(); sigmaps[ncoeffs.size() - 1].Invert(); } } int rc = cmp->Reconstruct(coeffs, block, sigmaps, level); if (rc < 0) return (-1); return (0); } // Write a single block (no compression) to disk // // varname : name of variable // ncdfcptr : NetCDFCpp file pointer // bcoords : coordinates of block in voxel coords relative to start of variable // bs : blocksize // block : data block // template int StoreBlock(string varname, NetCDFCpp *ncdfcptr, vector bcoords, size_t block_size, const T *block ) { vector start = bcoords; start.push_back(0); vector count(start.size(), 1); count[count.size() - 1] = block_size; int rc = ncdfcptr->NetCDFCpp::PutVara(varname, start, count, block); if (rc < 0) return (rc); return (0); } // Write a single transformed & compressed block to disk // // varname : name of variable // ncdfcptrs : NetCDFCpp file points, one for each compression level // bcoords : coordinates of block in voxel coords relative to start of variable // ncoeffs : vector describing partitioning of coefficients in 'coeffs' // encoded_dims : vector describing dimension of encoded block at // each compression level. // coeffs : transformed coefficients for each compression level // maps : encoded significance maps for each compression level // template int StoreBlockCompressed(string varname, vector ncdfcptrs, vector bcoords, vector ncoeffs, vector encoded_dims, const T *coeffs, const T *datarange, unsigned char *maps, int xtype ) { unsigned long LSBTest = 1; bool do_swapbytes = false; if (!(*(char *)&LSBTest)) { // swap to MSBFirst do_swapbytes = true; } vector start = bcoords; start.push_back(0); vector count; count.resize(start.size(), 1); // First write the min and max data value in the header // of the base file // start[start.size() - 1] = 0; count[start.size() - 1] = BLK_HDR_SZ; int rc = ncdfcptrs[0]->NetCDFCpp::PutVara(varname, start, count, datarange); if (rc < 0) return (rc); // // Current code assumes each wavelet decomposition is stored in a // different file // VAssert(ncdfcptrs.size() >= ncoeffs.size()); for (int i = 0; i < ncoeffs.size(); i++) { start[start.size() - 1] = i == 0 ? BLK_HDR_SZ : 0; // skip header count[start.size() - 1] = ncoeffs[i]; int rc = ncdfcptrs[i]->NetCDFCpp::PutVara(varname, start, count, coeffs); if (rc < 0) return (rc); coeffs += ncoeffs[i]; // Sigmap size (in words) is difference between encoded_dims and // number of coefficients // VAssert(encoded_dims[i] >= ncoeffs[i]); size_t n = encoded_dims[i] - ncoeffs[i]; if (i == 0) n -= BLK_HDR_SZ; // adjust for header // // If sigmap size is zero don't write it! // if (n != 0) { // Using untyped flavor of PutVara, which doesn't do data // conversion, so start & count arguments are in sizes of // external variable type // start[start.size() - 1] = i == 0 ? ncoeffs[i] + BLK_HDR_SZ : ncoeffs[i]; count[start.size() - 1] = n; // // Should be checking size of external type for var // if (do_swapbytes) { swapbytes((void *)maps, NetCDFCpp::SizeOf(xtype), n); } // Signficance map is concatenated to the wavelet coefficients // variable to improve IO performance // int rc = ncdfcptrs[i]->NetCDFCpp::PutVara(varname, start, count, (const void *)maps); if (rc < 0) return (rc); maps += n * NetCDFCpp::SizeOf(xtype); } } return (0); } // Read a single block (no compression) from disk // // varname : name of variable // ncdfcptrs : NetCDFCpp file pointer // bcoords : coordinates of block // bs : block size // block : data block // template int FetchBlock(string varname, NetCDFCpp *ncdfcptr, vector bcoords, size_t block_size, T *block) { vector start = bcoords; start.push_back(0); vector count(start.size(), 1); count[count.size() - 1] = block_size; int rc = ncdfcptr->NetCDFCpp::GetVara(varname, start, count, (T *)block); if (rc < 0) return (rc); return (0); } // Read a single transformed & compressed block from disk // // varname : name of variable // ncdfcptrs : NetCDFCpp file points, one for each compression level // bcoords : coordinates of block // ncoeffs : vector describing partitioning of coefficients in 'coeffs' // encoded_dims : vector describing dimension of encoded block at // each compression level. // coeffs : transformed coefficients for each compression level // maps : encoded significance maps for each compression level // template int FetchBlockCompressed(string varname, vector ncdfcptrs, vector bcoords, vector ncoeffs, vector encoded_dims, T *coeffs, T *datarange, unsigned char *maps, int xtype ) { unsigned long LSBTest = 1; bool do_swapbytes = false; if (!(*(char *)&LSBTest)) { // swap to MSBFirst do_swapbytes = true; } vector start = bcoords; start.push_back(0); vector count; count.resize(start.size(), 1); // Read header (first two elements contain data range) // start[start.size() - 1] = 0; count[start.size() - 1] = BLK_HDR_SZ; int rc = ncdfcptrs[0]->NetCDFCpp::GetVara(varname, start, count, datarange); if (rc < 0) return (rc); // // Current code assumes each wavelet decomposition is stored in a // different file // VAssert(ncdfcptrs.size() >= ncoeffs.size()); for (int i = 0; i < ncoeffs.size(); i++) { start[start.size() - 1] = i == 0 ? BLK_HDR_SZ : 0; // skip header count[start.size() - 1] = ncoeffs[i]; int rc = ncdfcptrs[i]->NetCDFCpp::GetVara(varname, start, count, coeffs); if (rc < 0) return (rc); coeffs += ncoeffs[i]; // Sigmap size (in words) is difference between encoded_dims and // number of coefficients // VAssert(encoded_dims[i] >= ncoeffs[i]); size_t n = encoded_dims[i] - ncoeffs[i]; if (i == 0) n -= BLK_HDR_SZ; // // If sigmap size is zero don't read it! // if (n != 0) { start[start.size() - 1] = i == 0 ? ncoeffs[i] + BLK_HDR_SZ : ncoeffs[i]; count[start.size() - 1] = n; // Signficance map is concatenated to the wavelet coefficients // variable to improve IO performance // int rc = ncdfcptrs[i]->NetCDFCpp::GetVara(varname, start, count, (void *)maps); if (rc < 0) return (rc); // // Should be checking size of external type for var // if (do_swapbytes) { swapbytes((void *)maps, NetCDFCpp::SizeOf(xtype), n); } maps += n * NetCDFCpp::SizeOf(xtype); } } return (0); } template void *RunWriteThreadTemplate(thread_state &s, T dummy) { vectorinc vec(s._start, s._count, s._udims, s._bs); s._status = 0; // // Process blocks of data assigned to this thread // int n = vec.num(); for (int i = s._id; i < n; i += s._nthreads) { // Get starting coordinates of i'th block // size_t offset; vector start; vec.ith(i, start, offset); // Transform coordinates from global to the region-of-interest // vector roi_start = vector_sub(start, s._start); // // Extract the block with coordinates 'start' from the // array, 'data'. // T min, max; Block((T *)s._data, NULL, s._count, roi_start, (T *)s._block, s._bs, "symh", min, max); // Convert from voxel to block coordinates // vector bcoords; size_t residual; to_block_coords(start, s._bs, bcoords, residual); VAssert(residual == 0); // Write the transformed block to disk. Need a mutex because // NetCDF library is not thread safe // // s._et->MutexLock(); int rc = StoreBlock(s._varname, s._ncdfcptrs[0], bcoords, s._encoded_dims[0], (T *)s._block); if (rc < 0) { s._status = -1; } s._et->MutexUnlock(); if (s._status < 0) break; } return (0); } void *RunWriteThread(void *arg) { thread_state &s = *(thread_state *)arg; switch (s._data_type) { case NC_FLOAT: { float dummy = 0.0; return (RunWriteThreadTemplate(s, dummy)); } case NC_DOUBLE: { double dummy = 0.0; return (RunWriteThreadTemplate(s, dummy)); } case NC_INT: { int dummy = 0.0; return (RunWriteThreadTemplate(s, dummy)); } case NC_SHORT: { int16_t dummy = 0.0; return (RunWriteThreadTemplate(s, dummy)); } default: VAssert(0); return (NULL); } } // Thread execution help function for data writes // template void *RunWriteThreadCompressedTemplate(thread_state &s, T dummy1, U dummy2) { vectorinc vec(s._start, s._count, s._udims, s._bs); s._status = 0; // // Process blocks of data assigned to this thread // int n = vec.num(); for (int i = s._id; i < n; i += s._nthreads) { // Get starting coordinates of i'th block // size_t offset; vector start; vec.ith(i, start, offset); // Transform coordinates from global to the region-of-interest // vector roi_start = vector_sub(start, s._start); // // Extract the block with coordinates 'start' from the // array, 'data'. // U datarange[2]; Block((T *)s._data, s._mask, s._count, roi_start, (U *)s._block, s._bs, s._compressors[s._id]->dwtmode(), datarange[0], datarange[1]); // // Wavelet transform the current block // int rc = DecomposeBlock(s._compressors[s._id], (const U *)s._block, vproduct(s._bs), (U *)s._coeffs, s._maps, s._xtype, s._ncoeffs, s._encoded_dims); if (rc < 0) { s._status = -1; break; } // Convert from voxel to block coordinates // vector bcoords; size_t residual; to_block_coords(start, s._bs, bcoords, residual); VAssert(residual == 0); // Write the transformed block to disk. Need a mutex because // NetCDF library is not thread safe // // s._et->MutexLock(); rc = StoreBlockCompressed(s._varname, s._ncdfcptrs, bcoords, s._ncoeffs, s._encoded_dims, (U *)s._coeffs, datarange, s._maps, s._xtype); if (rc < 0) { s._status = -1; } s._et->MutexUnlock(); if (s._status < 0) break; } return (0); } void *RunWriteThreadCompressed(void *arg) { thread_state &s = *(thread_state *)arg; VAssert(s._block_type == NC_INT64 || s._block_type == NC_DOUBLE); // Establish types for template functions. Data types aren't preserved // when passed in thread_state, which must be cast to void to support // pthread API :-( // switch (s._data_type) { case NC_FLOAT: { float dummy1 = 0.0; if (s._block_type == NC_INT64) { long dummy2 = 0; return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2)); } else { double dummy2 = 0; return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2)); } } break; case NC_DOUBLE: { double dummy1 = 0.0; if (s._block_type == NC_INT64) { long dummy2 = 0; return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2)); } else { double dummy2 = 0; return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2)); } } break; case NC_INT: case NC_UINT: { int dummy1 = 0.0; if (s._block_type == NC_INT64) { long dummy2 = 0; return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2)); } else { double dummy2 = 0; return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2)); } } break; case NC_SHORT: case NC_USHORT: { int16_t dummy1 = 0.0; if (s._block_type == NC_INT64) { long dummy2 = 0; return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2)); } else { double dummy2 = 0; return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2)); } } case NC_BYTE: case NC_UBYTE: { int8_t dummy1 = 0; if (s._block_type == NC_INT64) { long dummy2 = 0; return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2)); } else { double dummy2 = 0; return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2)); } } break; default: cerr << "Data type " << s._data_type << endl; VAssert(0 && s._data_type); return (NULL); } } // Thread execution helper function for data writes // template void *RunReadThreadTemplate(thread_state &s, T dummy) { bool unblock_flag = s._unblock_flag; // Need to unblock data? T * data = (T *)s._data; // Align start and count coordinates to block boundaries // vector aligned_start; vector aligned_count; block_align(s._start, s._count, s._bs, aligned_start, aligned_count); vectorinc vec(aligned_start, aligned_count, s._udims, s._bs); s._status = 0; int n = vec.num(); for (int i = s._id; i < n; i += s._nthreads) { size_t offset; vector start; vec.ith(i, start, offset); vector bcoords; size_t residual; to_block_coords(start, s._bs, bcoords, residual); VAssert(residual == 0); // Transform coordinates from global to the region-of-interest // vector roi_start = vector_sub(start, aligned_start); vector roi_origin = vector_sub(s._start, aligned_start); T *blockptr = (T *)s._block; // Read wavelet coefficients from disk. Need a mutex because // NetCDF API is not thread safe // s._et->MutexLock(); int rc = FetchBlock(s._varname, s._ncdfcptrs[0], bcoords, s._encoded_dims[0], blockptr); if (rc < 0) s._status = -1; s._et->MutexUnlock(); if (s._status < 0) break; if (unblock_flag) { // Unblock the current block into the destination array // UnBlock(blockptr, s._bs, data, s._count, roi_origin, roi_start); } else { // Don't unblock. Just copy // size_t offset = vproduct(s._bs) * i; for (size_t j = 0; j < vproduct(s._bs); j++) { data[offset + j] = blockptr[j]; } } } return (NULL); } void *RunReadThread(void *arg) { thread_state &s = *(thread_state *)arg; switch (s._data_type) { case NC_FLOAT: { float dummy = 0.0; return (RunReadThreadTemplate(s, dummy)); } case NC_DOUBLE: { double dummy = 0.0; return (RunReadThreadTemplate(s, dummy)); } case NC_INT: { int dummy = 0.0; return (RunReadThreadTemplate(s, dummy)); } case NC_SHORT: { int16_t dummy = 0.0; return (RunReadThreadTemplate(s, dummy)); } default: VAssert(0); return (NULL); } } // Thread execution helper function for data writes // template void *RunReadThreadCompressedTemplate(thread_state &s, T dummy1, U dummy2) { bool unblock_flag = s._unblock_flag; // Need to unblock data? T * data = (T *)s._data; // Align start and count coordinates to block boundaries // vector aligned_start; vector aligned_count; block_align(s._start, s._count, s._bs, aligned_start, aligned_count); vectorinc vec(aligned_start, aligned_count, s._udims, s._bs); s._status = 0; int n = vec.num(); for (int i = s._id; i < n; i += s._nthreads) { size_t offset; vector start; vec.ith(i, start, offset); vector bcoords; size_t residual; to_block_coords(start, s._bs, bcoords, residual); VAssert(residual == 0); // Read wavelet coefficients from disk. Need a mutex because // NetCDF API is not thread safe // U datarange[2]; s._et->MutexLock(); int rc = FetchBlockCompressed(s._varname, s._ncdfcptrs, bcoords, s._ncoeffs, s._encoded_dims, (U *)s._coeffs, datarange, s._maps, s._xtype); if (rc < 0) s._status = -1; s._et->MutexUnlock(); if (s._status < 0) break; // Transform coordinates from global to the region-of-interest // vector roi_start = vector_sub(start, aligned_start); vector roi_origin = vector_sub(s._start, aligned_start); U *blockptr = (U *)s._block; // Transform from wavelet to physical space // rc = ReconstructBlock(s._compressors[s._id], (U *)s._coeffs, datarange, s._maps, s._xtype, s._ncoeffs, s._encoded_dims, blockptr, vproduct(s._bs), s._level); if (rc < 0) { s._status = -1; break; } if (unblock_flag) { // Unblock the current block into the destination array // UnBlock(blockptr, s._bs, data, s._count, roi_origin, roi_start); } else { // Don't unblock. Just copy. // size_t offset = vproduct(s._bs) * i; for (size_t j = 0; j < vproduct(s._bs); j++) { data[offset + j] = (T)blockptr[j]; } } } return (NULL); } void *RunReadThreadCompressed(void *arg) { thread_state &s = *(thread_state *)arg; VAssert(s._block_type == NC_INT64 || s._block_type == NC_DOUBLE); // Establish types for template functions. Data types aren't preserved // when passed in thread_state, which must be cast to void to support // pthread API :-( // switch (s._data_type) { case NC_FLOAT: { float dummy1 = 0.0; if (s._block_type == NC_INT64) { long dummy2 = 0; return (RunReadThreadCompressedTemplate(s, dummy1, dummy2)); } else { double dummy2 = 0; return (RunReadThreadCompressedTemplate(s, dummy1, dummy2)); } } case NC_DOUBLE: { double dummy1 = 0.0; if (s._block_type == NC_INT64) { long dummy2 = 0; return (RunReadThreadCompressedTemplate(s, dummy1, dummy2)); } else { double dummy2 = 0; return (RunReadThreadCompressedTemplate(s, dummy1, dummy2)); } } case NC_INT: { int dummy1 = 0; if (s._block_type == NC_INT64) { long dummy2 = 0; return (RunReadThreadCompressedTemplate(s, dummy1, dummy2)); } else { double dummy2 = 0; return (RunReadThreadCompressedTemplate(s, dummy1, dummy2)); } } case NC_SHORT: { int16_t dummy1 = 0; if (s._block_type == NC_INT64) { long dummy2 = 0; return (RunReadThreadCompressedTemplate(s, dummy1, dummy2)); } else { double dummy2 = 0; return (RunReadThreadCompressedTemplate(s, dummy1, dummy2)); } } case NC_BYTE: case NC_UBYTE: { int8_t dummy1 = 0; if (s._block_type == NC_INT64) { long dummy2 = 0; return (RunReadThreadCompressedTemplate(s, dummy1, dummy2)); } else { double dummy2 = 0; return (RunReadThreadCompressedTemplate(s, dummy1, dummy2)); } } default: VAssert(0); return (NULL); } } }; // namespace WASP::WASP(int nthreads) { _ncdfcs.clear(); _ncdfcptrs.clear(); _waspFile = false; _nthreads = 1; _currentVersion = 3; _fileVersion = 0; _open = false; _open_wname.clear(); _open_bs.clear(); _open_cratios.clear(); _open_udims.clear(); _open_dims.clear(); _open_lod = 0; _open_level = 0; _open_write = false; _open_varname.clear(); _et = NULL; // Set up execution threads for parallel execution // if (nthreads < 1) nthreads = EasyThreads::NProc(); if (nthreads < 1) nthreads = 1; _et = new EasyThreads(nthreads); _nthreads = _et->GetNumThreads() > 0 ? _et->GetNumThreads() : 1; // One Compressor instance for each thread // _open_compressors.resize(nthreads, NULL); } WASP::~WASP() { for (int i = 0; i < _open_compressors.size(); i++) { if (_open_compressors[i]) delete _open_compressors[i]; } if (_et) delete _et; } int WASP::Create(string path, int cmode, size_t initialsz, size_t &bufrsizehintp, int numfiles) { int rc = WASP::Close(); if (rc < 0) return (rc); numfiles = numfiles > 0 ? numfiles : 1; _ncdfcs.clear(); _ncdfcptrs.clear(); _ncdfcptrs.push_back(this); vector paths; if (numfiles > 1) { paths = mkmultipaths(path, numfiles); } else { paths.push_back(path); } rc = NetCDFCpp::Create(paths[0], cmode, initialsz, bufrsizehintp); if (rc < 0) return (rc); for (int i = 1; i < paths.size(); i++) { NetCDFCpp netcdfcpp; rc = netcdfcpp.Create(paths[i], cmode, initialsz, bufrsizehintp); if (rc < 0) return (rc); _ncdfcs.push_back(netcdfcpp); } for (int i = 0; i < _ncdfcs.size(); i++) { _ncdfcptrs.push_back(&(_ncdfcs[i])); } _numfiles = numfiles; // Attributes describing the compressed data // rc = PutAtt("", AttNameWASP(), 1); if (rc < 0) return (rc); _waspFile = true; rc = PutAtt("", AttNameNumFiles(), numfiles); if (rc < 0) return (rc); rc = PutAtt("", AttNameVersion(), _currentVersion); if (rc < 0) return (rc); _fileVersion = _currentVersion; return (NC_NOERR); } int WASP::Open(string path, int mode) { int rc = WASP::Close(); if (rc < 0) return (rc); _ncdfcs.clear(); _ncdfcptrs.clear(); _ncdfcptrs.push_back(this); _waspFile = false; rc = NetCDFCpp::Open(path.c_str(), mode); if (rc < 0) return (rc); // Verify that this is a WASP file // int dummy; rc = GetAtt("", AttNameWASP(), dummy); if (rc < 0) { SetErrMsg("Not a WASP file"); NetCDFCpp::Close(); return (-1); } int numfiles = 1; string wname; rc = GetAtt("", AttNameNumFiles(), numfiles); if (rc < 0) return (rc); _numfiles = numfiles; int fileVersion = 0; rc = GetAtt("", AttNameVersion(), fileVersion); if (rc < 0) return (rc); _fileVersion = fileVersion; vector paths; if (numfiles > 1) { paths = mkmultipaths(path, numfiles); } for (int i = 1; i < paths.size(); i++) { NetCDFCpp netcdfcpp; // Not required that all LODs exist if open read-only // struct stat statbuf; if (mode == NC_NOWRITE && stat(paths[i].c_str(), &statbuf) < 0) break; rc = netcdfcpp.Open(paths[i], mode); if (rc < 0) return (rc); _ncdfcs.push_back(netcdfcpp); } for (int i = 0; i < _ncdfcs.size(); i++) { _ncdfcptrs.push_back(&(_ncdfcs[i])); } _waspFile = true; return (NC_NOERR); } int WASP::SetFill(int fillmode, int &old_modep) { if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } // Set old_modep only for first file // int rc = NetCDFCpp::SetFill(fillmode, old_modep); if (rc < 0) return (rc); for (int i = 1; i < _ncdfcptrs.size(); i++) { int my_old_modep; rc = _ncdfcptrs[i]->NetCDFCpp::SetFill(fillmode, my_old_modep); if (rc < 0) return (rc); } return (NC_NOERR); } int WASP::EndDef() const { if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } for (int i = 0; i < _ncdfcptrs.size(); i++) { int rc = _ncdfcptrs[i]->NetCDFCpp::EndDef(); if (rc < 0) return (rc); } return (NC_NOERR); } int WASP::Close() { int rc = 0; for (int i = 0; i < _ncdfcptrs.size(); i++) { int my_rc = _ncdfcptrs[i]->NetCDFCpp::Close(); if (my_rc < 0) rc = -1; } _ncdfcptrs.clear(); _waspFile = false; return (rc); } int WASP::DefDim(string name, size_t len) const { if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } // // Dimensions get defined identically in every file // for (int i = 0; i < _ncdfcptrs.size(); i++) { int rc = _ncdfcptrs[i]->NetCDFCpp::DefDim(name, len); if (rc < 0) return (rc); } return (NC_NOERR); } int WASP::DefVar(string name, int xtype, vector dimnames, string wname, vector bs, vector cratios) { if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } if (bs.size() == 0 || vproduct(bs) == 1) { return (NetCDFCpp::DefVar(name, xtype, dimnames)); } // Wavelet coefficients together with the signficance map // are encoded together and ultimately written with the generic // nc_put_var(), which assumes that the data type passed to nc_put_var() // matches that of the external storage type. // Supporting external storage types besides NC_FLOAT will // require changes to the packaging of the wavelet coefficients. // // if (! (xtype == NC_FLOAT || xtype == NC_DOUBLE)) { // if (! (xtype == NC_FLOAT)) { // SetErrMsg("Unsupported xtype specification"); // return(-1); // } if (!cratios.size()) cratios.push_back(1); // No transform => no compression vector // if (wname.empty()) { cratios.clear(); cratios.push_back(1); } // // Look up dimlens associated with dimnames // vector dims; for (int i = 0; i < dimnames.size(); i++) { size_t dimlen; int rc = NetCDFCpp::InqDimlen(dimnames[i], dimlen); if (rc < 0) return (rc); dims.push_back(dimlen); } while (bs.size() > dims.size()) { bs.pop_back(); } while (bs.size() < dims.size()) { bs.insert(bs.begin(), 1); } if (!_validate_compression_params(wname, dims, bs, cratios)) { SetErrMsg("Invalid compression specification"); return (-1); } sort(cratios.begin(), cratios.end()); reverse(cratios.begin(), cratios.end()); // Get dimensions for compressed, or simply blocked, version of // variable. Compressed // variables are decomposed into blocks. The dimension of the compressed // variable in blocks is given by cdimnames and cdims. The dimension // of the blocks themselves varies with compression level and is given // by encoded_dim_names and encoded_dims // // Blocked variables are simply decomposed into blocks, but do not // undergo compression // vector encoded_dim_names; vector encoded_dims; vector cdimnames; vector cdims; int rc; rc = _GetCompressedDims(dimnames, wname, bs, cratios, xtype, cdimnames, cdims, encoded_dim_names, encoded_dims); if (rc < 0) return (rc); // Implicitly define dimensions for compressed variable. One set of // dimensions for each compression level. Finally, define // compressed variable itself. // for (int j = 0; j < cdimnames.size(); j++) { size_t len; rc = _InqDimlen(cdimnames[j], len); if (len == 0) { rc = WASP::DefDim(cdimnames[j], cdims[j]); if (rc < 0) return (rc); } else if (len != cdims[j]) { SetErrMsg("Can't implicitly redefine compression dimensions"); return (-1); } } for (int i = 0; i < encoded_dim_names.size(); i++) { size_t len; rc = _InqDimlen(encoded_dim_names[i], len); if (len == 0) { rc = WASP::DefDim(encoded_dim_names[i], encoded_dims[i]); if (rc < 0) return (rc); } else if (len != encoded_dims[i]) { SetErrMsg("Can't implicitly redefine compression dimensions"); return (-1); } } // Now define the variable, one in each file // for (int i = 0; i < encoded_dim_names.size(); i++) { vector newdimnames; newdimnames = cdimnames; newdimnames.push_back(encoded_dim_names[i]); rc = _ncdfcptrs[i]->NetCDFCpp::DefVar(name, xtype, newdimnames); if (rc < 0) return (rc); } // Attributes needed to encode or decode the variable later // rc = PutAtt(name, AttNameWASP(), 1); if (rc < 0) return (rc); rc = PutAtt(name, AttNameDimNames(), dimnames); if (rc < 0) return (rc); rc = PutAtt(name, AttNameCRatios(), cratios); if (rc < 0) return (rc); rc = PutAtt(name, AttNameWavelet(), wname); if (rc < 0) return (rc); rc = PutAtt(name, AttNameBlockSize(), bs); if (rc < 0) return (rc); return (NC_NOERR); } int WASP::DefVar(string name, int xtype, vector dimnames, string wname, vector bs, vector cratios, double missing_value) { if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } if (bs.size() == 0 || vproduct(bs) == 1) { return (NetCDFCpp::DefVar(name, xtype, dimnames)); } int rc = WASP::DefVar(name, xtype, dimnames, wname, bs, cratios); if (rc < 0) return (rc); rc = PutAtt(name, AttNameMissingValue(), missing_value); if (rc < 0) return (rc); return (NC_NOERR); } int WASP::InqVarDims(string name, vector &dimnames, vector &dims) const { dimnames.clear(); dims.clear(); if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } bool waspvar; int rc = InqVarWASP(name, waspvar); if (rc < 0) return (rc); if (!waspvar) { return (NetCDFCpp::InqVarDims(name, dimnames, dims)); } rc = GetAtt(name, AttNameDimNames(), dimnames); if (rc < 0) return (rc); for (int i = 0; i < dimnames.size(); i++) { size_t len; rc = NetCDFCpp::InqDimlen(dimnames[i], len); if (rc < 0) return (rc); dims.push_back(len); } return (NC_NOERR); } int WASP::InqVarCompressionParams(string name, string &wname, vector &bs, vector &cratios) const { wname.clear(); bs.clear(); cratios.clear(); if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } bool waspvar; int rc = InqVarWASP(name, waspvar); if (rc < 0) return (rc); if (!waspvar) return (0); rc = GetAtt(name, AttNameBlockSize(), bs); if (rc < 0) return (rc); rc = GetAtt(name, AttNameCRatios(), cratios); if (rc < 0) return (rc); rc = GetAtt(name, AttNameWavelet(), wname); if (rc < 0) return (rc); return (0); } int WASP::InqVarDimlens(string name, int level, vector &dims_at_level, vector &bs_at_level) const { dims_at_level.clear(); bs_at_level.clear(); if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } vector dimnames; vector dims; int rc = WASP::InqVarDims(name, dimnames, dims); if (rc < 0) return (rc); vector bs; vector cratios; string wname; rc = WASP::InqVarCompressionParams(name, wname, bs, cratios); if (rc < 0) return (rc); _dims_at_level(dims, bs, level, wname, dims_at_level, bs_at_level); return (0); } int WASP::InqDimsAtLevel(string wname, int level, vector dims, vector bs, vector &dims_at_level, vector &bs_at_level) { dims_at_level.clear(); bs_at_level.clear(); _dims_at_level(dims, bs, level, wname, dims_at_level, bs_at_level); return (0); } bool WASP::InqCompressionInfo(vector bs, string wname, size_t &nlevels, size_t &maxcratio) { return (Compressor::CompressionInfo(compressor_bs(bs), wname, true, nlevels, maxcratio)); } int WASP::InqVarNumRefLevels(string name) const { if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } bool waspvar; int rc = InqVarWASP(name, waspvar); if (rc < 0) return (rc); if (!waspvar) return (1); vector bs; vector cratios; vector udims; vector dims; string wname; rc = _get_compression_params(name, bs, cratios, udims, dims, wname); if (rc < 0) return (rc); if (cratios.size() == 0) return (1); // no compression size_t nlevels, maxcratio; (void)WASP::InqCompressionInfo(bs, wname, nlevels, maxcratio); return (nlevels); } // static method to compute grid dimensions at a specified refinement level // // dims : dimensions of native (original) grid // bs : dimensions of native storage brick. // level : hierarchy level // wname : name of wavelet used in wavelet transform // dims_at_level : grid dimensions at given refinement level // bs_at_level : block dimensions dimensions at given refinement level // void WASP::_dims_at_level(vector dims, vector bs, int level, string wname, vector &dims_at_level, vector &bs_at_level) { dims_at_level.clear(); bs_at_level.clear(); if (wname.empty()) { dims_at_level = dims; bs_at_level = bs; return; } Compressor cmp(compressor_bs(bs), wname); if (level < 0) level = cmp.GetNumLevels(); if (level > cmp.GetNumLevels()) level = cmp.GetNumLevels(); cmp.GetDimension(bs_at_level, level); reverse(bs_at_level.begin(), bs_at_level.end()); while (bs_at_level.size() != dims.size()) { bs_at_level.insert(bs_at_level.begin(), 1); } VAssert(dims.size() == bs_at_level.size()); dims_at_level = dims; int ldelta = cmp.GetNumLevels() - level; for (int i = 0; i < bs.size(); i++) { size_t nblocks = dims[i] / bs[i]; size_t residual = dims[i] - (nblocks * bs[i]); residual = residual >> ldelta; size_t d = nblocks * bs_at_level[i] + residual; if (d < 1) d = 1; dims_at_level[i] = d; } } // Same as NetCDFCpp::InqDimlen(), but returns 0 and sets len to 0 // if dimension 'name' does not exist // int WASP::_InqDimlen(string name, size_t &len) const { len = 0; // disable error reporting // bool enabled = MyBase::EnableErrMsg(false); int rc = WASP::InqDimlen(name, len); if (rc == NC_EBADDIM) { WASP::SetErrCode(0); rc = 0; } (void)MyBase::EnableErrMsg(enabled); return (rc); } int WASP::InqVarWASP(string varname, bool &wasp) const { wasp = false; if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } int varid; int rc = NetCDFCpp::InqVarid(varname, varid); if (rc < 0) return (rc); // disable error reporting otherwise an error is generated // if the attribute doesn't exist // bool enabled = MyBase::EnableErrMsg(false); int xtype; size_t len; rc = NetCDFCpp::InqAtt(varname, AttNameWASP(), xtype, len); (void)MyBase::EnableErrMsg(enabled); // Assume att doesn't exist if InqAtt fails of if len != 1 // if (rc < 0 || len != 1) return (NC_NOERR); wasp = true; return (0); } int WASP::InqVarCompressed(string varname, bool &compressed) const { compressed = false; if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } // Make sure this is a WASP variable // bool wasp; int rc = WASP::InqVarWASP(varname, wasp); if (rc < 0) return (-1); if (!wasp) return (0); string wname; rc = GetAtt(varname, AttNameWavelet(), wname); if (rc < 0) return (rc); compressed = !wname.empty(); return (0); } int WASP::OpenVarWrite(string name, int lod) { vector bs; vector cratios; vector udims; vector dims; string wname; if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } _open_waspvar = false; int rc = InqVarWASP(name, _open_waspvar); if (rc < 0) return (rc); if (!_open_waspvar) { _open_write = true; _open_varname = name; _open = true; return (0); } if (_ncdfcptrs.size() < 1) { SetErrMsg("Invalid state"); return (-1); } if (_open) { int rc = CloseVar(); if (rc < 0) return (rc); } _open_wname.clear(); _open_bs.clear(); _open_cratios.clear(); _open_udims.clear(); _open_dims.clear(); _open_lod = 0; _open_level = 0; _open_write = false; _open_varname.clear(); _open_varxtype = 0; _open = false; nc_type xtype; rc = InqVartype(name, xtype); if (rc < 0) return (rc); rc = _get_compression_params(name, bs, cratios, udims, dims, wname); if (rc < 0) return (rc); if (lod < 0) lod = cratios.size() - 1; if (lod >= cratios.size()) { SetErrMsg("Invalid level-of-detail : (%d)", lod); return (-1); } // Create one compressor for each execution thread // if (!wname.empty()) { for (int i = 0; i < _nthreads; i++) { _open_compressors[i] = new Compressor(compressor_bs(bs), wname); } } _open_wname = wname; _open_bs = bs; _open_cratios = cratios; _open_udims = udims; _open_dims = dims; _open_lod = lod; _open_level = 0; _open_write = true; _open_varname = name; _open_varxtype = xtype; _open = true; return (NC_NOERR); } int WASP::OpenVarRead(string name, int level, int lod) { vector bs; vector cratios; vector udims; vector dims; string wname; if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } _open_waspvar = false; int rc = InqVarWASP(name, _open_waspvar); if (rc < 0) return (rc); if (!_open_waspvar) { _open_write = false; _open_varname = name; _open = true; return (0); } if (_ncdfcptrs.size() < 1) { SetErrMsg("Invalid state"); return (-1); } if (_open) { int rc = CloseVar(); if (rc < 0) return (rc); } _open_wname.clear(); _open_bs.clear(); _open_cratios.clear(); _open_udims.clear(); _open_dims.clear(); _open_lod = 0; _open_level = 0; _open_write = false; _open_varname.clear(); _open_varxtype = 0; _open = false; nc_type xtype; rc = InqVartype(name, xtype); if (rc < 0) return (rc); rc = _get_compression_params(name, bs, cratios, udims, dims, wname); if (rc < 0) return (rc); // For multi-file storage higher-numbered files may be missing // and the max LOD is determined by the number files actually present. // In general cratios.size() == _ncdfcptrs.size() // int maxlod = _numfiles > 1 ? _ncdfcptrs.size() - 1 : cratios.size() - 1; if (lod < 0) lod = maxlod; // if (lod > maxlod) { // SetErrMsg("Invalid level-of-detail : (%d)", lod); // return(-1); //} if (lod > maxlod) lod = maxlod; int numlevels = 1; if (!wname.empty()) { // May simply be blocked, not compressed for (int i = 0; i < _nthreads; i++) { _open_compressors[i] = new Compressor(compressor_bs(bs), wname); } VAssert(_nthreads >= 1); numlevels = _open_compressors[0]->GetNumLevels(); } else { numlevels = 1; } if (level < 0) level = numlevels; if (level > numlevels) { SetErrMsg("Invalid refinement level: (%d)", level); for (int i = 0; i < _nthreads; i++) { if (_open_compressors[i]) delete _open_compressors[i]; _open_compressors[i] = NULL; } return (-1); } _open_wname = wname; _open_bs = bs; _open_cratios = cratios; _open_udims = udims; _open_dims = dims; _open_lod = lod; _open_level = level; _open_write = false; _open_varname = name; _open_varxtype = xtype; _open = true; return (NC_NOERR); } int WASP::CloseVar() { if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } _open = false; _open_write = false; if (!_open_waspvar) return (0); for (int i = 0; i < _nthreads; i++) { if (_open_compressors[i]) delete _open_compressors[i]; _open_compressors[i] = NULL; } return (0); } // Validate parameters to PutVara() // bool WASP::_validate_put_vara_compressed(vector start, vector count, vector bs, vector udims, vector cratios) const { if (start.size() != udims.size() || count.size() != udims.size()) { return (false); } VAssert(bs.size() == start.size()); for (int i = 0; i < count.size(); i++) { if (count[i] < 1 || count[i] > udims[i]) return (false); } for (int i = 0; i < start.size(); i++) { if (start[i] >= udims[i]) return (false); if ((start[i] + count[i]) > udims[i]) return (false); } // Count must be block aligned, or, in the case where an array // dimension is not block aligned, count must align with the // array dimension boundary // for (int i = 0; i < bs.size(); i++) { if (((count[i] % bs[i]) != 0) && (count[i] + start[i] != udims[i])) { return (false); } } // Start must *always* be block aligned // for (int i = 0; i < bs.size(); i++) { if ((start[i] % bs[i]) != 0) return (false); } return (true); } // Validate parameters to GetVara() // bool WASP::_validate_get_vara_compressed(vector start, vector count, vector bs, vector udims, vector cratios, bool unblock) const { if (start.size() != udims.size() || count.size() != udims.size()) { return (false); } VAssert(bs.size() == start.size()); if (unblock) { for (int i = 0; i < count.size(); i++) { if (count[i] < 1 || count[i] > udims[i]) return (false); } for (int i = 0; i < start.size(); i++) { if (start[i] >= udims[i]) return (false); if ((start[i] + count[i]) > udims[i]) return (false); } } else { // make sure start and count are block-aligned // vector astart, acount; block_align(start, count, bs, astart, acount); for (int i = 0; i < start.size(); i++) { if (start[i] != astart[i]) return (false); if (count[i] != acount[i]) return (false); } } return (true); } template int WASP::_PutVara(vector start, vector count, const T *data, const unsigned char *mask, U dummy) { if (!_validate_put_vara_compressed(start, count, _open_bs, _open_udims, _open_cratios)) { SetErrMsg("Invalid parameter"); return (-1); } vector ncoeffs; vector encoded_dims; _get_encoding_vectors(_open_wname, _open_bs, _open_cratios, _open_varxtype, ncoeffs, encoded_dims); size_t block_size = vproduct(_open_bs); U * block = (U *)_blockbuf.Alloc(block_size * _nthreads * sizeof(U)); // Allocate space for coefficients and sigmap if data are compressed // size_t coeffs_size = 0; U * coeffs = NULL; size_t maps_size = 0; unsigned char *maps = NULL; if (!_open_wname.empty()) { // Handle case where not all coefficients are wanted // while (_open_lod < (ncoeffs.size() - 1)) { ncoeffs.pop_back(); encoded_dims.pop_back(); } coeffs_size = vsum(ncoeffs); coeffs = (U *)_coeffbuf.Alloc(coeffs_size * _nthreads * sizeof(U)); maps_size = vsum(encoded_dims) - vsum(ncoeffs); maps_size -= BLK_HDR_SZ; maps = (unsigned char *)_sigbuf.Alloc(maps_size * _nthreads * NetCDFCpp::SizeOf(_open_varxtype)); } // Ugh. Can't preserve type in thread_state, which has to be passed // as a void * to thread library // int data_type = _NetCDFType(*data); int block_type = _NetCDFType(*block); // // Set up thread state for parallel (threaded) execution // vector argvec; for (int i = 0; i < _nthreads; i++) { argvec.push_back((void *)new thread_state(i, _et, _nthreads, _open_varname, _ncdfcptrs, start, count, _open_bs, _open_udims, ncoeffs, encoded_dims, _open_compressors, (void *)data, data_type, (unsigned char *)mask, block + i * block_size, coeffs + i * coeffs_size, block_type, _open_varxtype, maps + i * maps_size * NetCDFCpp::SizeOf(_open_varxtype), 0, true)); } if (_nthreads == 1) { if (_open_wname.empty()) { RunWriteThread(argvec[0]); } else { RunWriteThreadCompressed(argvec[0]); } } else { int rc; if (_open_wname.empty()) { rc = _et->ParRun(RunWriteThread, argvec); } else { rc = _et->ParRun(RunWriteThreadCompressed, argvec); } if (rc < 0) { SetErrMsg("Error spawning threads"); return (-1); } } for (int i = 0; i < argvec.size(); i++) delete (thread_state *)argvec[i]; return (thread_state::_status); } template int WASP::_PutVara(vector start, vector count, const T *data, const unsigned char *mask) { if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } if (!_open || !_open_write) { SetErrMsg("Invalid state"); return (-1); } if (!_open_waspvar) { return (NetCDFCpp::PutVara(_open_varname, start, count, data)); } VAssert(_open_compressors.size() != 0); if (_open_compressors[0] && _open_compressors[0]->wavelet()->isint()) { long dummy = 0; return (_PutVara(start, count, data, mask, dummy)); } else { double dummy = 0.0; return (_PutVara(start, count, data, mask, dummy)); } } //////////////////////////////////////////////////////////////////////////// // // PutVar - float // //////////////////////////////////////////////////////////////////////////// int WASP::PutVara(vector start, vector count, const float *data, const unsigned char *mask) { return (WASP::_PutVara(start, count, data, mask)); } int WASP::PutVara(vector start, vector count, const float *data) { return (WASP::PutVara(start, count, data, NULL)); } int WASP::PutVar(const float *data) { return (WASP::PutVar(data, NULL)); } int WASP::PutVar(const float *data, const unsigned char *mask) { if (!_open_waspvar) { return (NetCDFCpp::PutVar(_open_varname, data)); } vector count = _open_udims; vector start(count.size(), 0); return (WASP::PutVara(start, count, data, mask)); } //////////////////////////////////////////////////////////////////////////// // // PutVar - double // //////////////////////////////////////////////////////////////////////////// int WASP::PutVara(vector start, vector count, const double *data, const unsigned char *mask) { return (WASP::_PutVara(start, count, data, mask)); } int WASP::PutVara(vector start, vector count, const double *data) { return (WASP::PutVara(start, count, data, NULL)); } int WASP::PutVar(const double *data) { return (WASP::PutVar(data, NULL)); } int WASP::PutVar(const double *data, const unsigned char *mask) { if (!_open_waspvar) { return (NetCDFCpp::PutVar(_open_varname, data)); } vector count = _open_udims; vector start(count.size(), 0); return (WASP::PutVara(start, count, data, mask)); } //////////////////////////////////////////////////////////////////////////// // // PutVar - int // //////////////////////////////////////////////////////////////////////////// int WASP::PutVara(vector start, vector count, const int *data, const unsigned char *mask) { return (WASP::_PutVara(start, count, data, mask)); } int WASP::PutVara(vector start, vector count, const int *data) { return (WASP::PutVara(start, count, data, NULL)); } int WASP::PutVar(const int *data) { return (WASP::PutVar(data, NULL)); } int WASP::PutVar(const int *data, const unsigned char *mask) { if (!_open_waspvar) { return (NetCDFCpp::PutVar(_open_varname, data)); } vector count = _open_udims; vector start(count.size(), 0); return (WASP::PutVara(start, count, data, mask)); } //////////////////////////////////////////////////////////////////////////// // // PutVar - int16_t // //////////////////////////////////////////////////////////////////////////// int WASP::PutVara(vector start, vector count, const int16_t *data, const unsigned char *mask) { return (WASP::_PutVara(start, count, data, mask)); } int WASP::PutVara(vector start, vector count, const int16_t *data) { return (WASP::PutVara(start, count, data, NULL)); } int WASP::PutVar(const int16_t *data) { return (WASP::PutVar(data, NULL)); } int WASP::PutVar(const int16_t *data, const unsigned char *mask) { if (!_open_waspvar) { return (NetCDFCpp::PutVar(_open_varname, data)); } vector count = _open_udims; vector start(count.size(), 0); return (WASP::PutVara(start, count, data, mask)); } //////////////////////////////////////////////////////////////////////////// // // PutVar - char // //////////////////////////////////////////////////////////////////////////// int WASP::PutVara(vector start, vector count, const unsigned char *data, const unsigned char *mask) { return (WASP::_PutVara(start, count, data, mask)); } int WASP::PutVara(vector start, vector count, const unsigned char *data) { return (WASP::PutVara(start, count, data, NULL)); } int WASP::PutVar(const unsigned char *data) { return (WASP::PutVar(data, NULL)); } int WASP::PutVar(const unsigned char *data, const unsigned char *mask) { if (!_open_waspvar) { return (NetCDFCpp::PutVar(_open_varname, data)); } vector count = _open_udims; vector start(count.size(), 0); return (WASP::PutVara(start, count, data, mask)); } template int WASP::_GetVara(vector start, vector count, bool unblock_flag, T *data, U dummy) { vector ncoeffs; vector encoded_dims; _get_encoding_vectors(_open_wname, _open_bs, _open_cratios, _open_varxtype, ncoeffs, encoded_dims); // Compute the dimension and block size at the grid hierarchy // level indicated by _open_level // vector dims_at_level; vector bs_at_level; _dims_at_level(_open_udims, _open_bs, _open_level, _open_wname, dims_at_level, bs_at_level); if (!_validate_get_vara_compressed(start, count, bs_at_level, dims_at_level, _open_cratios, unblock_flag)) { SetErrMsg("Invalid parameter"); return (-1); } size_t block_size = vproduct(bs_at_level); // Need temporary space for storing reconstructed data // U *block = NULL; block = (U *)_blockbuf.Alloc(block_size * _nthreads * sizeof(U)); size_t coeffs_size = 0; U * coeffs = NULL; size_t maps_size = 0; unsigned char *maps = NULL; if (!_open_wname.empty()) { // Handle case where not all coefficients are wanted // while (_open_lod < (ncoeffs.size() - 1)) { ncoeffs.pop_back(); encoded_dims.pop_back(); } coeffs_size = vsum(ncoeffs); coeffs = (U *)_coeffbuf.Alloc(coeffs_size * _nthreads * sizeof(U)); maps_size = vsum(encoded_dims) - vsum(ncoeffs); maps_size -= BLK_HDR_SZ; maps = (unsigned char *)_sigbuf.Alloc(maps_size * _nthreads * NetCDFCpp::SizeOf(_open_varxtype)); } // Ugh. Can't preserve type in thread_state, which has to be passed // as a void * to thread library // int data_type = _NetCDFType(*data); int block_type = _NetCDFType(*block); // // Set up thread state for parallel (threaded) execution // vector argvec; for (int i = 0; i < _nthreads; i++) { U *blkptr = block + i * block_size; argvec.push_back((void *)new thread_state(i, _et, _nthreads, _open_varname, _ncdfcptrs, start, count, bs_at_level, dims_at_level, ncoeffs, encoded_dims, _open_compressors, data, data_type, NULL, blkptr, coeffs + i * coeffs_size, block_type, _open_varxtype, maps + i * maps_size * NetCDFCpp::SizeOf(_open_varxtype), _open_level, unblock_flag)); } if (_nthreads == 1) { if (_open_wname.empty()) { RunReadThread(argvec[0]); } else { RunReadThreadCompressed(argvec[0]); } } else { int rc; if (_open_wname.empty()) { rc = _et->ParRun(RunReadThread, argvec); } else { rc = _et->ParRun(RunReadThreadCompressed, argvec); } if (rc < 0) { SetErrMsg("Error spawning threads"); return (-1); } } for (int i = 0; i < argvec.size(); i++) delete (thread_state *)argvec[i]; return (thread_state::_status); } template int WASP::_GetVara(vector start, vector count, bool unblock_flag, T *data) { if (!_waspFile) { SetErrMsg("Not a WASP file"); return (-1); } if (!_open || _open_write) { SetErrMsg("Invalid state"); return (-1); } if (!_open_waspvar) { return (NetCDFCpp::GetVara(_open_varname, start, count, data)); } VAssert(_open_compressors.size() != 0); if (_open_compressors[0] && _open_compressors[0]->wavelet()->isint()) { long dummy = 0; return (_GetVara(start, count, unblock_flag, data, dummy)); } else { double dummy = 0.0; return (_GetVara(start, count, unblock_flag, data, dummy)); } } //////////////////////////////////////////////////////////////////////////// // // GetVar - float // //////////////////////////////////////////////////////////////////////////// int WASP::GetVara(vector start, vector count, float *data) { return (WASP::_GetVara(start, count, true, data)); } int WASP::GetVaraBlock(vector start, vector count, float *data) { return (WASP::_GetVara(start, count, false, data)); } int WASP::GetVar(float *data) { if (!_open_waspvar) { return (NetCDFCpp::GetVar(_open_varname, data)); } vector count = _open_udims; vector start(count.size(), 0); return (WASP::GetVara(start, count, data)); } //////////////////////////////////////////////////////////////////////////// // // GetVar - double // //////////////////////////////////////////////////////////////////////////// int WASP::GetVara(vector start, vector count, double *data) { return (WASP::_GetVara(start, count, true, data)); } int WASP::GetVaraBlock(vector start, vector count, double *data) { return (WASP::_GetVara(start, count, false, data)); } int WASP::GetVar(double *data) { if (!_open_waspvar) { return (NetCDFCpp::GetVar(_open_varname, data)); } vector count = _open_udims; vector start(count.size(), 0); return (WASP::GetVara(start, count, data)); } //////////////////////////////////////////////////////////////////////////// // // GetVar - int // //////////////////////////////////////////////////////////////////////////// int WASP::GetVara(vector start, vector count, int *data) { return (WASP::_GetVara(start, count, true, data)); } int WASP::GetVaraBlock(vector start, vector count, int *data) { return (WASP::_GetVara(start, count, false, data)); } int WASP::GetVar(int *data) { if (!_open_waspvar) { return (NetCDFCpp::GetVar(_open_varname, data)); } vector count = _open_udims; vector start(count.size(), 0); return (WASP::GetVara(start, count, data)); } //////////////////////////////////////////////////////////////////////////// // // GetVar - int16_t // //////////////////////////////////////////////////////////////////////////// int WASP::GetVara(vector start, vector count, int16_t *data) { return (WASP::_GetVara(start, count, true, data)); } int WASP::GetVaraBlock(vector start, vector count, int16_t *data) { return (WASP::_GetVara(start, count, false, data)); } int WASP::GetVar(int16_t *data) { if (!_open_waspvar) { return (NetCDFCpp::GetVar(_open_varname, data)); } vector count = _open_udims; vector start(count.size(), 0); return (WASP::GetVara(start, count, data)); } //////////////////////////////////////////////////////////////////////////// // // GetVar - char // //////////////////////////////////////////////////////////////////////////// int WASP::GetVara(vector start, vector count, unsigned char *data) { return (WASP::_GetVara(start, count, true, data)); } int WASP::GetVaraBlock(vector start, vector count, unsigned char *data) { return (WASP::_GetVara(start, count, false, data)); } int WASP::GetVar(unsigned char *data) { if (!_open_waspvar) { return (NetCDFCpp::GetVar(_open_varname, data)); } vector count = _open_udims; vector start(count.size(), 0); return (WASP::GetVara(start, count, data)); } template int WASP::_CopyHyperSlice(string varname, NetCDFCpp &src_ncdf, NetCDFCpp &dst_ncdf, vector start, vector count, T *buf) const { int rc = -1; NetCDFCpp *src_ncdfptr = dynamic_cast(&src_ncdf); WASP * src_waspptr = dynamic_cast(&src_ncdf); if (src_waspptr) { rc = src_waspptr->GetVara(start, count, buf); } else if (src_ncdfptr) { rc = src_ncdfptr->GetVara(varname, start, count, buf); } if (rc < 0) return (-1); NetCDFCpp *dst_ncdfptr = dynamic_cast(&dst_ncdf); WASP * dst_waspptr = dynamic_cast(&dst_ncdf); if (dst_waspptr) { rc = dst_waspptr->PutVara(start, count, buf); } else if (dst_ncdfptr) { rc = dst_ncdfptr->PutVara(varname, start, count, buf); } if (rc < 0) return (-1); return (0); } int WASP::_CopyVar(string varname, NetCDFCpp &src_ncdf, NetCDFCpp &dst_ncdf) const { SmartBuf sbuf; nc_type xtype; int rc = dst_ncdf.InqVartype(varname, xtype); if (rc < 0) return (-1); vector dimnames; vector dims; rc = src_ncdf.InqVarDims(varname, dimnames, dims); if (rc < 0) return (-1); vector start, count; for (int i = 0; i < dims.size(); i++) { start.push_back(0); count.push_back(dims[i]); } // For variables with 3 or more dimensions process them one // hyperslab at a time. // int nk = 1; #ifdef VAPOR3_0_0_ALPHA // // Need to fix this so that count is block-aligned // if (dims.size() >= 3) { count[0] = 1; nk = dims[0]; } #endif size_t elem_sz = max(sizeof(double), sizeof(int)); size_t hs_size = vproduct(dims); unsigned char *data = (unsigned char *)sbuf.Alloc(elem_sz * hs_size); for (int k = 0; k < nk; k++) { if (xtype == NC_FLOAT || xtype == NC_DOUBLE) { rc = _CopyHyperSlice(varname, src_ncdf, dst_ncdf, start, count, (double *)data); } else { rc = _CopyHyperSlice(varname, src_ncdf, dst_ncdf, start, count, (int *)data); } if (dims.size() >= 3) start[0] += 1; } return (0); } int WASP::CopyVar(string varname, WASP &wasp) { bool src_waspvar; int rc = WASP::InqVarWASP(varname, src_waspvar); if (rc < 0) return (-1); bool dst_waspvar; rc = wasp.InqVarWASP(varname, dst_waspvar); if (rc < 0) return (-1); if (!src_waspvar && !dst_waspvar) { return (NetCDFCpp::CopyVar(varname, wasp)); } if (!src_waspvar) { return (wasp.CopyVarFrom(varname, *this)); } if (!dst_waspvar) { return (this->CopyVarTo(varname, wasp)); } VAssert(src_waspvar && dst_waspvar); rc = WASP::OpenVarRead(varname, -1, -1); if (rc < 0) return (-1); rc = wasp.OpenVarWrite(varname, -1); if (rc < 0) { wasp.CloseVar(); return (-1); } _CopyVar(varname, *this, wasp); WASP::CloseVar(); return (wasp.CloseVar()); } int WASP::CopyVarFrom(string varname, NetCDFCpp &ncdf) { bool waspvar; int rc = WASP::InqVarWASP(varname, waspvar); if (rc < 0) return (-1); if (!waspvar) { return (ncdf.CopyVar(varname, *this)); } rc = WASP::OpenVarWrite(varname, -1); if (rc < 0) return (-1); _CopyVar(varname, ncdf, *this); return (WASP::CloseVar()); } int WASP::CopyVarTo(string varname, NetCDFCpp &ncdf) { bool waspvar; int rc = WASP::InqVarWASP(varname, waspvar); if (rc < 0) return (-1); if (!waspvar) { return (NetCDFCpp::CopyVar(varname, ncdf)); } rc = WASP::OpenVarRead(varname, -1, -1); if (rc < 0) return (-1); _CopyVar(varname, *this, ncdf); return (WASP::CloseVar()); } // For an array with dimensions 'dimnames' and compression ratio // vector, cratios, compute the new names and lengths of the dimensions // needed to store a compressed version of a variable with dimensions, // 'dimnames' // int WASP::_GetCompressedDims(vector dimnames, string wname, vector bs, vector cratios, int xtype, vector &cdimnames, vector &cdims, vector &encoded_dim_names, vector &encoded_dims) const { VAssert(dimnames.size() == bs.size()); cdimnames.clear(); cdims.clear(); encoded_dim_names.clear(); encoded_dims.clear(); // // Look up dimlens associated with dimnames // vector dims; for (int i = 0; i < dimnames.size(); i++) { size_t dimlen; int rc = NetCDFCpp::InqDimlen(dimnames[i], dimlen); if (rc < 0) return (rc); dims.push_back(dimlen); } // // Compute dimensions of blocked array in terms of blocks. Not all // dimensions are blocked - only n fastest varying, where 'n' is // rank of 'bs'. // cdims = dims; cdimnames = dimnames; // See if dimensions are blocked // if (vproduct(bs) == 1) return (0); for (int i = 0; i < bs.size(); i++) { if (bs[i] != 1) { size_t bdim = (size_t)ceil((double)dims[i] / (double)bs[i]); string bdimname = "B_" + dimnames[i]; cdims[i] = bdim; cdimnames[i] = bdimname; } } // // Now get coefficient dimensions. Coefficient dimensions are // num coefficients + size of significance map needed to address // coefficients. There is one coefficient dimension for each LOD // vector ncoeffs; _get_encoding_vectors(wname, bs, cratios, xtype, ncoeffs, encoded_dims); string encoded_dim_base; for (int i = 0; i < cdimnames.size(); i++) { if (bs[i] == 1) continue; if (i != cdimnames.size() - 1) encoded_dim_base += cdimnames[i] + "X"; else encoded_dim_base += cdimnames[i]; } // If not compressed we're done. // // if (! wname.empty()) { for (int i = 0; i < encoded_dims.size(); i++) { ostringstream oss; oss << encoded_dim_base << i; encoded_dim_names.push_back(oss.str()); } // } // else { // encoded_dim_names.push_back(encoded_dim_base); // } return (NC_NOERR); } // For each compression level (LOD) compute the number of coefficients, // ncoeffs, and the dimension of array that will contain both the // coefficients and the significance map // // bs : dimensions of compression block // cratio : vector of compression ratios // xtype : NetCDF external storage type // ncoeffs : number of wavelet coefficients for each compression level // encoded_dims : dimension of encoded block for each compression // level. The dimension is ncoeffs + size of encoded sig map // void WASP::_get_encoding_vectors(string wname, vector bs, vector cratios, int xtype, vector &ncoeffs, vector &encoded_dims) const { ncoeffs.clear(); encoded_dims.clear(); if (wname.empty()) { ncoeffs.push_back(vproduct(bs)); encoded_dims.push_back(vproduct(bs)); return; } Compressor compressor(compressor_bs(bs), wname); // Total number of wavelet coefficients generated by a forward transform // size_t ntotal = compressor.GetNumWaveCoeffs(); long naccum = 0; for (int i = 0; i < cratios.size(); i++) { size_t header_size = 0; // Base compression block needs space for data range (min and max) // if (i == 0) header_size = BLK_HDR_SZ; size_t n = ntotal / cratios[i]; // There is a minumum number of coefficients that must be // used in reconstruction that places a lower bound on // the compression rate // if (n < compressor.GetMinCompression()) { n = compressor.GetMinCompression(); } n -= naccum; // only account for new coefficients if (n < 1) n = 1; naccum += n; ncoeffs.push_back(n); // Signifance map is encoded with the wavelet coefficients. // Size of sigmap returned by GetSigMapSize() is in bytes. Need to // convert bytes to word size of POD // if (cratios[i] != 1) { size_t s = compressor.GetSigMapSize(n); s = (s + SizeOf(xtype) - 1) / SizeOf(xtype); encoded_dims.push_back(header_size + n + s); } else { VAssert(naccum == ntotal); // Special case. Don't need to explicitly store sigmap // encoded_dims.push_back(header_size + n + 0); } } } // Make sure compression params are valid: // cratios vector is monotonic with unique values, no zero // wname is a valide wavelet // bs supports requested compression ratios // bool WASP::_validate_compression_params(string wname, vector dims, vector bs, vector cratios) const { if (bs.size() < 1 || bs.size() > 4) return (false); if (_numfiles > 1) { if (cratios.size() > _numfiles) return (false); } if (bs.size() != dims.size()) return (false); if (wname.empty()) return (true); MatWaveBase mwb(wname); if (!mwb.wavelet()) return (false); // Monotonic // for (int i = 0; i < cratios.size() - 1; i++) { if (cratios[i] == cratios[i + 1]) return (false); } sort(cratios.begin(), cratios.end()); for (int i = 0; i < cratios.size(); i++) { if (cratios[i] == 0) return (false); } size_t maxcratio; size_t nlevels; bool status = WASP::InqCompressionInfo(bs, wname, nlevels, maxcratio); if (!status) return (false); for (int i = 0; i < cratios.size(); i++) { if (cratios[i] > maxcratio) return (false); } return (true); } int WASP::_get_compression_params(string name, vector &bs, vector &cratios, vector &udims, vector &dims, string &wname) const { bs.clear(); cratios.clear(); udims.clear(); dims.clear(); vector udimnames; int rc = WASP::InqVarDims(name, udimnames, udims); if (rc < 0) return (rc); vector dimnames; rc = NetCDFCpp::InqVarDims(name, dimnames, dims); if (rc < 0) return (rc); rc = WASP::InqVarCompressionParams(name, wname, bs, cratios); if (rc < 0) return (rc); if (!_validate_compression_params(wname, udims, bs, cratios)) { SetErrMsg("Invalid cratios specification"); return (-1); } return (0); } // Generate the path names for a multipath NetCDF data set // containing 'n' paths. // vector WASP::mkmultipaths(string path, int n) { vector paths; string basename = path; size_t p = basename.rfind(".nc"); if (p != std::string::npos) basename = basename.substr(0, p); for (int i = 0; i < n; i++) { ostringstream oss; if (i == 0) { oss << basename << ".nc"; } else { oss << basename << ".nc" << i; } paths.push_back(oss.str()); } return (paths); } ================================================ FILE: lib/wasp/WaveFiltBase.cpp ================================================ #include #include using namespace std; using namespace VAPoR; WaveFiltBase::WaveFiltBase() { _lowDecomFilCoef = new double[MAX_FILTER_SIZE]; _lowReconFilCoef = new double[MAX_FILTER_SIZE]; _hiDecomFilCoef = new double[MAX_FILTER_SIZE]; _hiReconFilCoef = new double[MAX_FILTER_SIZE]; } WaveFiltBase::~WaveFiltBase() { if (_lowDecomFilCoef) delete[] _lowDecomFilCoef; _lowDecomFilCoef = NULL; if (_lowReconFilCoef) delete[] _lowReconFilCoef; _lowReconFilCoef = NULL; if (_hiDecomFilCoef) delete[] _hiDecomFilCoef; _hiDecomFilCoef = NULL; if (_hiReconFilCoef) delete[] _hiReconFilCoef; _hiReconFilCoef = NULL; } /*------------------------------------------- * Flipping Operation *-----------------------------------------*/ void WaveFiltBase::wrev(const double *sigIn, double *sigOut, int sigLength) const { int count = 0; for (count = 0; count < sigLength; count++) sigOut[count] = sigIn[sigLength - count - 1]; return; } /*------------------------------------------- * Quadrature Mirror Filtering Operation *-----------------------------------------*/ void WaveFiltBase::qmf_even(const double *sigIn, double *sigOut, int sigLength) const { int count = 0; for (count = 0; count < sigLength; count++) { sigOut[count] = sigIn[sigLength - count - 1]; if (sigLength % 2 == 0) { if (count % 2 != 0) { sigOut[count] = -1 * sigOut[count]; } } else { if (count % 2 == 0) { sigOut[count] = -1 * sigOut[count]; } } } return; } /*------------------------------------------- * Flipping and QMF at the same time *-----------------------------------------*/ void WaveFiltBase::qmf_wrev(const double *sigIn, double *sigOut, int sigLength) const { int count = 0; for (count = 0; count < sigLength; count++) { sigOut[count] = sigIn[sigLength - count - 1]; if (sigLength % 2 == 0) { if (count % 2 != 0) { sigOut[count] = -1 * sigOut[count]; } } else { if (count % 2 == 0) { sigOut[count] = -1 * sigOut[count]; } } } double tmp; for (count = 0; count < sigLength / 2; count++) { tmp = sigOut[count]; sigOut[count] = sigOut[sigLength - count - 1]; sigOut[sigLength - count - 1] = tmp; } return; } /*------------------------------------------- * Verbatim Copying *-----------------------------------------*/ void WaveFiltBase::verbatim_copy(const double *sigIn, double *sigOut, int sigLength) const { int count = 0; for (count = 0; count < sigLength; count++) sigOut[count] = sigIn[count]; } ================================================ FILE: lib/wasp/WaveFiltBior.cpp ================================================ /* * ------------------------------------------------------------------------- * Biorlet wavelets coefficents. * SWT - Scilab wavelet toolbox * Copyright (C) 2005-2006 Roger Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ------------------------------------------------------------------------- */ #include #include "vapor/VAssert.h" #include using namespace VAPoR; /********************************************* * Local Variable (Filter Coefficent) ********************************************/ namespace { const double h1[10] = {0.0, 0.0, 0.0, 0.0, 0.70710678118654752440084436210, 0.70710678118654752440084436210, 0.0, 0.0, 0.0, 0.0}; const double hm1_11[2] = {0.70710678118654752440084436210, 0.70710678118654752440084436210}; const double hm1_13[6] = {-0.0883883476483184405501055452631, 0.0883883476483184405501055452631, 0.70710678118654752440084436210, 0.70710678118654752440084436210, 0.0883883476483184405501055452631, -0.0883883476483184405501055452631}; const double hm1_15[10] = {0.0165728151840597076031447897368, -0.0165728151840597076031447897368, -0.1215339780164378557563951247368, 0.1215339780164378557563951247368, 0.70710678118654752440084436210, 0.70710678118654752440084436210, 0.1215339780164378557563951247368, -0.1215339780164378557563951247368, -0.0165728151840597076031447897368, 0.0165728151840597076031447897368}; const double h2[18] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3535533905932737622004221810524, 0.7071067811865475244008443621048, 0.3535533905932737622004221810524, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; const double hm2_22[6] = {-0.1767766952966368811002110905262, 0.3535533905932737622004221810524, 1.0606601717798212866012665431573, 0.3535533905932737622004221810524, -0.1767766952966368811002110905262}; const double hm2_24[10] = {0.0331456303681194152062895794737, -0.0662912607362388304125791589473, -0.1767766952966368811002110905262, 0.4198446513295125926130013399998, 0.9943689110435824561886873842099, 0.4198446513295125926130013399998, -0.1767766952966368811002110905262, -0.0662912607362388304125791589473, 0.0331456303681194152062895794737}; const double hm2_26[14] = {-0.0069053396600248781679769957237, 0.0138106793200497563359539914474, 0.0469563096881691715422435709210, -0.1077232986963880994204411332894, -0.1698713556366120029322340948025, 0.4474660099696121052849093228945, 0.9667475524034829435167794013152, 0.4474660099696121052849093228945, -0.1698713556366120029322340948025, -0.1077232986963880994204411332894, 0.0469563096881691715422435709210, 0.0138106793200497563359539914474, -0.0069053396600248781679769957237}; const double hm2_28[18] = {0.0015105430506304420992449678146, -0.0030210861012608841984899356291, -0.0129475118625466465649568669819, 0.0289161098263541773284036695929, 0.0529984818906909399392234421792, -0.1349130736077360572068505539514, -0.1638291834340902345352542235443, 0.4625714404759165262773590010400, 0.9516421218971785225243297231697, 0.4625714404759165262773590010400, -0.1638291834340902345352542235443, -0.1349130736077360572068505539514, 0.0529984818906909399392234421792, 0.0289161098263541773284036695929, -0.0129475118625466465649568669819, -0.0030210861012608841984899356291, 0.0015105430506304420992449678146}; const double h3[20] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1767766952966368811002110905262, 0.5303300858899106433006332715786, 0.5303300858899106433006332715786, 0.1767766952966368811002110905262, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; const double hm3_31[4] = {-0.3535533905932737622004221810524, 1.0606601717798212866012665431573, 1.0606601717798212866012665431573, -0.3535533905932737622004221810524}; const double hm3_33[8] = {0.0662912607362388304125791589473, -0.1988737822087164912377374768420, -0.1546796083845572709626847042104, 0.9943689110435824561886873842099, 0.9943689110435824561886873842099, -0.1546796083845572709626847042104, -0.1988737822087164912377374768420, 0.0662912607362388304125791589473}; const double hm3_35[12] = {-0.0138106793200497563359539914474, 0.0414320379601492690078619743421, 0.0524805814161890740766251675000, -0.2679271788089652729175074340788, -0.0718155324642587329469607555263, 0.9667475524034829435167794013152, 0.9667475524034829435167794013152, -0.0718155324642587329469607555263, -0.2679271788089652729175074340788, 0.0524805814161890740766251675000, 0.0414320379601492690078619743421, -0.0138106793200497563359539914474}; const double hm3_37[16] = {0.0030210861012608841984899356291, -0.0090632583037826525954698068873, -0.0168317654213106405344439270765, 0.0746639850740189951912512662623, 0.0313329787073628846871956180962, -0.3011591259228349991008967259990, -0.0264992409453454699696117210896, 0.9516421218971785225243297231697, 0.9516421218971785225243297231697, -0.0264992409453454699696117210896, -0.3011591259228349991008967259990, 0.0313329787073628846871956180962, 0.0746639850740189951912512662623, -0.0168317654213106405344439270765, -0.0090632583037826525954698068873, 0.0030210861012608841984899356291}; const double hm3_39[20] = {-0.0006797443727836989446602355165, 0.0020392331183510968339807065496, 0.0050603192196119810324706421788, -0.0206189126411055346546938106687, -0.0141127879301758447558029850103, 0.0991347824942321571990197448581, 0.0123001362694193142367090236328, -0.3201919683607785695513833204624, 0.0020500227115698857061181706055, 0.9421257006782067372990864259380, 0.9421257006782067372990864259380, 0.0020500227115698857061181706055, -0.3201919683607785695513833204624, 0.0123001362694193142367090236328, 0.0991347824942321571990197448581, -0.0141127879301758447558029850103, -0.0206189126411055346546938106687, 0.0050603192196119810324706421788, 0.0020392331183510968339807065496, -0.0006797443727836989446602355165}; const double hm4_44[] = {0.037828455507264, -0.023849465019557, -0.110624404418437, 0.377402855612831, 0.852698679008894, 0.377402855612831, -0.110624404418437, -0.023849465019557, 0.037828455507264}; const double h4[] = {0.0, -0.064538882628697, -0.040689417609164, 0.418092273221617, 0.788485616405583, 0.418092273221617, -0.0406894176091641, -0.0645388826286971, 0.0}; }; // namespace void WaveFiltBior::_analysis_initialize(int member) { const double *pFilterCoef = NULL; const double *pFilterCoefMirror = NULL; _filterLength = 6 * member; switch (member) { case 11: _filterLength = 2; pFilterCoef = hm1_11; pFilterCoefMirror = h1 + 4; break; case 13: _filterLength = 6; pFilterCoef = hm1_13; pFilterCoefMirror = h1 + 2; break; case 15: _filterLength = 10; pFilterCoef = hm1_15; pFilterCoefMirror = h1; break; case 22: _filterLength = 5; pFilterCoef = hm2_22; pFilterCoefMirror = h2 + 6; break; case 24: _filterLength = 9; pFilterCoef = hm2_24; pFilterCoefMirror = h2 + 4; break; case 26: _filterLength = 13; pFilterCoef = hm2_26; pFilterCoefMirror = h2 + 2; break; case 28: _filterLength = 17; pFilterCoef = hm2_28; pFilterCoefMirror = h2; break; case 31: _filterLength = 4; pFilterCoef = hm3_31; pFilterCoefMirror = h3 + 8; break; case 33: _filterLength = 8; pFilterCoef = hm3_33; pFilterCoefMirror = h3 + 6; break; case 35: _filterLength = 12; pFilterCoef = hm3_35; pFilterCoefMirror = h3 + 4; break; case 37: _filterLength = 16; pFilterCoef = hm3_37; pFilterCoefMirror = h3 + 2; break; case 39: _filterLength = 20; pFilterCoef = hm3_39; pFilterCoefMirror = h3; break; case 44: _filterLength = 9; pFilterCoef = hm4_44; pFilterCoefMirror = h4; break; default: VAssert(pFilterCoef != NULL); }; wrev(pFilterCoef, _lowDecomFilCoef, _filterLength); qmf_wrev(pFilterCoefMirror, _hiDecomFilCoef, _filterLength); return; } void WaveFiltBior::_synthesis_initialize(int member) { const double *pFilterCoef = NULL; const double *pFilterCoefMirror = NULL; switch (member) { case 11: _filterLength = 2; pFilterCoef = h1 + 4; pFilterCoefMirror = hm1_11; break; case 13: _filterLength = 6; pFilterCoef = h1 + 2; pFilterCoefMirror = hm1_13; break; case 15: _filterLength = 10; pFilterCoef = h1; pFilterCoefMirror = hm1_15; break; case 22: _filterLength = 5; pFilterCoef = h2 + 6; pFilterCoefMirror = hm2_22; break; case 24: _filterLength = 9; pFilterCoef = h2 + 4; pFilterCoefMirror = hm2_24; break; case 26: _filterLength = 13; pFilterCoef = h2 + 2; pFilterCoefMirror = hm2_26; break; case 28: _filterLength = 17; pFilterCoef = h2; pFilterCoefMirror = hm2_28; break; case 31: _filterLength = 4; pFilterCoef = h3 + 8; pFilterCoefMirror = hm3_31; break; case 33: _filterLength = 8; pFilterCoef = h3 + 6; pFilterCoefMirror = hm3_33; break; case 35: _filterLength = 12; pFilterCoef = h3 + 4; pFilterCoefMirror = hm3_35; break; case 37: _filterLength = 16; pFilterCoef = h3 + 2; pFilterCoefMirror = hm3_37; break; case 39: _filterLength = 20; pFilterCoef = h3; pFilterCoefMirror = hm3_39; break; case 44: _filterLength = 9; pFilterCoef = h4; pFilterCoefMirror = hm4_44; break; default: VAssert(pFilterCoef != NULL); }; verbatim_copy(pFilterCoef, _lowReconFilCoef, _filterLength); qmf_even(pFilterCoefMirror, _hiReconFilCoef, _filterLength); } WaveFiltBior::WaveFiltBior(const string &wavename) : WaveFiltBase() { int member = -1; if (wavename.compare("bior1.1") == 0) { member = 11; } else if (wavename.compare("bior1.3") == 0) { member = 13; } else if (wavename.compare("bior1.5") == 0) { member = 15; } else if (wavename.compare("bior2.2") == 0) { member = 22; } else if (wavename.compare("bior2.4") == 0) { member = 24; } else if (wavename.compare("bior2.6") == 0) { member = 26; } else if (wavename.compare("bior2.8") == 0) { member = 28; } else if (wavename.compare("bior3.1") == 0) { member = 31; } else if (wavename.compare("bior3.3") == 0) { member = 33; } else if (wavename.compare("bior3.5") == 0) { member = 35; } else if (wavename.compare("bior3.7") == 0) { member = 37; } else if (wavename.compare("bior3.9") == 0) { member = 39; } else if (wavename.compare("bior4.4") == 0) { member = 44; } else { member = 11; // default to bior1.1 } _analysis_initialize(member); _synthesis_initialize(member); } WaveFiltBior::~WaveFiltBior() {} ================================================ FILE: lib/wasp/WaveFiltCoif.cpp ================================================ /* * ------------------------------------------------------------------------- * Coiflet wavelets coefficents. * SWT - Scilab wavelet toolbox * Copyright (C) 2005-2006 Roger Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ------------------------------------------------------------------------- */ #include #include "vapor/VAssert.h" #include using namespace VAPoR; /********************************************* * Local Variable (Filter Coefficent) ********************************************/ namespace { const double coif1[6] = {-0.051429728471000, 0.238929728471000, 0.602859456942000, 0.272140543058000, -0.051429728471000, -0.011070271529000}; const double coif2[12] = {0.011587596739000, -0.029320137980000, -0.047639590310000, 0.273021046535000, 0.574682393857000, 0.294867193696000, -0.054085607092000, -0.042026480461000, 0.016744410163000, 0.003967883613000, -0.001289203356000, -0.000509505399000}; const double coif3[18] = { -0.002682418671000, 0.005503126709000, 0.016583560479000, -0.046507764479000, -0.043220763560000, 0.286503335274000, 0.561285256870000, 0.302983571773000, -0.050770140755000, -0.058196250762000, 0.024434094321000, 0.011229240962000, -0.006369601011000, -0.001820458916000, 0.000790205101000, 0.000329665174000, -0.000050192775000, -0.000024465734000, }; const double coif4[24] = {0.000630961046000, -0.001152224852000, -0.005194524026000, 0.011362459244000, 0.018867235378000, -0.057464234429000, -0.039652648517000, 0.293667390895000, 0.553126452562000, 0.307157326198000, -0.047112738865000, -0.068038127051000, 0.027813640153000, 0.017735837438000, -0.010756318517000, -0.004001012886000, 0.002652665946000, 0.000895594529000, -0.000416500571000, -0.000183829769000, 0.000044080354000, 0.000022082857000, -0.000002304942000, -0.000001262175000}; const double coif5[30] = {-0.000149963800000, 0.000253561200000, 0.001540245700000, -0.002941110800000, -0.007163781900000, 0.016552066400000, 0.019917804300000, -0.064997262800000, -0.036800073600000, 0.298092323500000, 0.547505429400000, 0.309706849000000, -0.043866050800000, -0.074652238900000, 0.029195879500000, 0.023110777000000, -0.013973687900000, -0.006480090000000, 0.004783001400000, 0.001720654700000, -0.001175822200000, -0.000451227000000, 0.000213729800000, 0.000099377600000, -0.000029232100000, -0.000015072000000, 0.000002640800000, 0.000001459300000, -0.000000118400000, -0.000000067300000}; }; // namespace void WaveFiltCoif::_analysis_initialize(int member) { const double *pFilterCoef = NULL; _filterLength = 6 * member; switch (member) { case 1: pFilterCoef = coif1; break; case 2: pFilterCoef = coif2; break; case 3: pFilterCoef = coif3; break; case 4: pFilterCoef = coif4; break; case 5: pFilterCoef = coif5; break; default: VAssert(pFilterCoef != NULL); } wrev(pFilterCoef, _lowDecomFilCoef, _filterLength); qmf_wrev(pFilterCoef, _hiDecomFilCoef, _filterLength); for (int count = 0; count < _filterLength; count++) _lowDecomFilCoef[count] *= sqrt(2.0); for (int count = 0; count < _filterLength; count++) _hiDecomFilCoef[count] *= sqrt(2.0); return; } void WaveFiltCoif::_synthesis_initialize(int member) { const double *pFilterCoef = NULL; _filterLength = 6 * member; switch (member) { case 1: pFilterCoef = coif1; break; case 2: pFilterCoef = coif2; break; case 3: pFilterCoef = coif3; break; case 4: pFilterCoef = coif4; break; case 5: pFilterCoef = coif5; break; default: VAssert(pFilterCoef != NULL); } verbatim_copy(pFilterCoef, _lowReconFilCoef, _filterLength); qmf_even(pFilterCoef, _hiReconFilCoef, _filterLength); for (int count = 0; count < _filterLength; count++) _lowReconFilCoef[count] *= sqrt(2.0); for (int count = 0; count < _filterLength; count++) _hiReconFilCoef[count] *= sqrt(2.0); return; } WaveFiltCoif::WaveFiltCoif(const string &wavename) : WaveFiltBase() { int member = -1; if (wavename.compare("coif1") == 0) { member = 1; } else if (wavename.compare("coif2") == 0) { member = 2; } else if (wavename.compare("coif3") == 0) { member = 3; } else if (wavename.compare("coif4") == 0) { member = 4; } else if (wavename.compare("coif5") == 0) { member = 5; } else { member = 1; // default coif1 } _analysis_initialize(member); _synthesis_initialize(member); } WaveFiltCoif::~WaveFiltCoif() {} ================================================ FILE: lib/wasp/WaveFiltDaub.cpp ================================================ /* * ------------------------------------------------------------------------- * Daublet wavelets coefficents. * SWT - Scilab wavelet toolbox * Copyright (C) 2005-2006 Roger Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ------------------------------------------------------------------------- */ #include #include "vapor/VAssert.h" #include using namespace VAPoR; /********************************************* * Local Variable (Filter Coefficent) ********************************************/ namespace { // const double db1[2] = { 0.70710678, 0.70710678 }; const double db1[2] = {sqrt(2.0) / 2.0, sqrt(2.0) / 2.0}; const double db2[4] = {0.48296291314453414337487159986, 0.83651630373780790557529378092, 0.22414386804201338102597276224, -0.12940952255126038117444941881}; const double db3[6] = {0.33267055295008261599851158914, 0.80689150931109257649449360409, 0.45987750211849157009515194215, -0.13501102001025458869638990670, -0.08544127388202666169281916918, 0.03522629188570953660274066472}; const double db4[8] = {0.23037781330889650086329118304, 0.71484657055291564708992195527, 0.63088076792985890788171633830, -0.02798376941685985421141374718, -0.18703481171909308407957067279, 0.03084138183556076362721936253, 0.03288301166688519973540751355, -0.01059740178506903210488320852}; const double db5[10] = {0.16010239797419291448072374802, 0.60382926979718967054011930653, 0.72430852843777292772807124410, 0.13842814590132073150539714634, -0.24229488706638203186257137947, -0.03224486958463837464847975506, 0.07757149384004571352313048939, -0.00624149021279827427419051911, -0.01258075199908199946850973993, 0.00333572528547377127799818342}; const double db6[12] = {0.11154074335010946362132391724, 0.49462389039845308567720417688, 0.75113390802109535067893449844, 0.31525035170919762908598965481, -0.22626469396543982007631450066, -0.12976686756726193556228960588, 0.09750160558732304910234355254, 0.02752286553030572862554083950, -0.03158203931748602956507908070, 0.00055384220116149613925191840, 0.00477725751094551063963597525, -0.00107730108530847956485262161}; const double db7[14] = {0.07785205408500917901996352196, 0.39653931948191730653900039094, 0.72913209084623511991694307034, 0.46978228740519312247159116097, -0.14390600392856497540506836221, -0.22403618499387498263814042023, 0.07130921926683026475087657050, 0.08061260915108307191292248036, -0.03802993693501441357959206160, -0.01657454163066688065410767489, 0.01255099855609984061298988603, 0.00042957797292136652113212912, -0.00180164070404749091526826291, 0.00035371379997452024844629584 }; const double db8[16] = {0.05441584224310400995500940520, 0.31287159091429997065916237551, 0.67563073629728980680780076705, 0.58535468365420671277126552005, -0.01582910525634930566738054788, -0.28401554296154692651620313237, 0.00047248457391328277036059001, 0.12874742662047845885702928751, -0.01736930100180754616961614887, -0.04408825393079475150676372324, 0.01398102791739828164872293057, 0.00874609404740577671638274325, -0.00487035299345157431042218156, -0.00039174037337694704629808036, 0.00067544940645056936636954757, -0.00011747678412476953373062823}; const double db9[18] = {0.03807794736387834658869765888, 0.24383467461259035373204158165, 0.60482312369011111190307686743, 0.65728807805130053807821263905, 0.13319738582500757619095494590, -0.29327378327917490880640319524, -0.09684078322297646051350813354, 0.14854074933810638013507271751, 0.03072568147933337921231740072, -0.06763282906132997367564227483, 0.00025094711483145195758718975, 0.02236166212367909720537378270, -0.00472320475775139727792570785, -0.00428150368246342983449679500, 0.00184764688305622647661912949, 0.00023038576352319596720521639, -0.00025196318894271013697498868, 0.00003934732031627159948068988}; const double db10[20] = {0.02667005790055555358661744877, 0.18817680007769148902089297368, 0.52720118893172558648174482796, 0.68845903945360356574187178255, 0.28117234366057746074872699845, -0.24984642432731537941610189792, -0.19594627437737704350429925432, 0.12736934033579326008267723320, 0.09305736460357235116035228984, -0.07139414716639708714533609308, -0.02945753682187581285828323760, 0.03321267405934100173976365318, 0.00360655356695616965542329142, -0.01073317548333057504431811411, 0.00139535174705290116578931845, 0.00199240529518505611715874224, -0.00068585669495971162656137098, -0.00011646685512928545095148097, 0.00009358867032006959133405013, -0.00001326420289452124481243668}; }; // namespace void WaveFiltDaub::_analysis_initialize(int member) { const double *pFilterCoef = NULL; _filterLength = 2 * member; switch (member) { case 1: pFilterCoef = db1; break; case 2: pFilterCoef = db2; break; case 3: pFilterCoef = db3; break; case 4: pFilterCoef = db4; break; case 5: pFilterCoef = db5; break; case 6: pFilterCoef = db6; break; case 7: pFilterCoef = db7; break; case 8: pFilterCoef = db8; break; case 9: pFilterCoef = db9; break; case 10: pFilterCoef = db10; break; default: VAssert(pFilterCoef != NULL); } wrev(pFilterCoef, _lowDecomFilCoef, _filterLength); qmf_wrev(pFilterCoef, _hiDecomFilCoef, _filterLength); return; } void WaveFiltDaub::_synthesis_initialize(int member) { const double *pFilterCoef = NULL; _filterLength = 2 * member; switch (member) { case 1: pFilterCoef = db1; break; case 2: pFilterCoef = db2; break; case 3: pFilterCoef = db3; break; case 4: pFilterCoef = db4; break; case 5: pFilterCoef = db5; break; case 6: pFilterCoef = db6; break; case 7: pFilterCoef = db7; break; case 8: pFilterCoef = db8; break; case 9: pFilterCoef = db9; break; case 10: pFilterCoef = db10; break; default: VAssert(pFilterCoef != NULL); } verbatim_copy(pFilterCoef, _lowReconFilCoef, _filterLength); qmf_even(pFilterCoef, _hiReconFilCoef, _filterLength); return; } WaveFiltDaub::WaveFiltDaub(const string &wavename) : WaveFiltBase() { int member = -1; if (wavename.compare("db1") == 0) { member = 1; } else if (wavename.compare("db2") == 0) { member = 2; } else if (wavename.compare("db3") == 0) { member = 3; } else if (wavename.compare("db4") == 0) { member = 4; } else if (wavename.compare("db5") == 0) { member = 5; } else if (wavename.compare("db6") == 0) { member = 6; } else if (wavename.compare("db7") == 0) { member = 7; } else if (wavename.compare("db8") == 0) { member = 8; } else if (wavename.compare("db9") == 0) { member = 9; } else if (wavename.compare("db10") == 0) { member = 10; } else { member = 1; // default db1 } _analysis_initialize(member); _synthesis_initialize(member); } WaveFiltDaub::~WaveFiltDaub() {} ================================================ FILE: lib/wasp/WaveFiltHaar.cpp ================================================ /* * ------------------------------------------------------------------------- * Haar wavelets coefficents. * SWT - Scilab wavelet toolbox * Copyright (C) 2005-2006 Roger Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ------------------------------------------------------------------------- */ #include #include #include using namespace VAPoR; /********************************************* * Local Variable (Filter Coefficent) ********************************************/ namespace { // const double haar[2] = { 0.707106781186548, 0.707106781186548 }; const double haar[2] = {sqrt(2.0) / 2.0, sqrt(2.0) / 2.0}; }; // namespace void WaveFiltHaar::_analysis_initialize() { const double *pFilterCoef; pFilterCoef = haar; _filterLength = 2; wrev(pFilterCoef, _lowDecomFilCoef, _filterLength); qmf_wrev(pFilterCoef, _hiDecomFilCoef, _filterLength); return; } void WaveFiltHaar::_synthesis_initialize() { const double *pFilterCoef; pFilterCoef = haar; _filterLength = 2; verbatim_copy(pFilterCoef, _lowReconFilCoef, _filterLength); qmf_even(pFilterCoef, _hiReconFilCoef, _filterLength); return; } WaveFiltHaar::WaveFiltHaar() : WaveFiltBase() { _analysis_initialize(); _synthesis_initialize(); } WaveFiltHaar::~WaveFiltHaar() {} ================================================ FILE: lib/wasp/WaveFiltInt.cpp ================================================ /* * ------------------------------------------------------------------------- * Haar wavelets coefficents. * SWT - Scilab wavelet toolbox * Copyright (C) 2005-2006 Roger Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ------------------------------------------------------------------------- */ #include #include #include using namespace VAPoR; /********************************************* * Local Variable (Filter Coefficent) ********************************************/ namespace { const double h2_2[] = {-1 / 8, 1 / 4, 3 / 4, 1 / 4, -1 / 8}; const double hm2_2[] = {0, -1 / 2, 1, -1 / 2, 0}; }; // namespace void WaveFiltInt::_analysis_initialize() { const double *pFilterCoef = NULL; const double *pFilterCoefMirror = NULL; if (_wavename == "intbior2.2" || _wavename == "intcdf5/3") { _filterLength = 5; pFilterCoef = h2_2; pFilterCoefMirror = hm2_2; } else { _filterLength = 5; pFilterCoef = h2_2; pFilterCoefMirror = hm2_2; } wrev(pFilterCoef, _lowDecomFilCoef, _filterLength); qmf_wrev(pFilterCoefMirror, _hiDecomFilCoef, _filterLength); } void WaveFiltInt::_synthesis_initialize() { const double *pFilterCoef = NULL; const double *pFilterCoefMirror = NULL; if (_wavename == "intbior2.2" || _wavename == "intcdf5/3") { _filterLength = 5; pFilterCoef = hm2_2; pFilterCoefMirror = h2_2; } else { _filterLength = 5; pFilterCoef = hm2_2; pFilterCoefMirror = h2_2; } verbatim_copy(pFilterCoef, _lowReconFilCoef, _filterLength); qmf_even(pFilterCoefMirror, _hiReconFilCoef, _filterLength); return; } WaveFiltInt::WaveFiltInt(const string &wavename) : WaveFiltBase() { _wavename = wavename; _analysis_initialize(); _synthesis_initialize(); } WaveFiltInt::~WaveFiltInt() {} void WaveFiltInt::Analysis(const long *sigIn, size_t sigInLen, long *cA, long *cD, bool oddlow, bool oddhigh) const { if (_wavename == "intbior2.2" || _wavename == "intcdf5/3") { _AnalysisCDF5_3(sigIn, sigInLen, cA, cD); } else { _AnalysisCDF5_3(sigIn, sigInLen, cA, cD); } } void WaveFiltInt::_AnalysisCDF5_3(const long *sigIn, size_t sigInLen, long *cA, long *cD) const { const long *x = sigIn + 2; // skip signal extension size_t nD = sigInLen >> 1; // num detail coefficients size_t nC = sigInLen >> 1; // num approximation coefficients if (sigInLen % 2) nC++; for (size_t i = 0; i < nD; i++) { cD[i] = x[2 * i + 1] - floor(0.5 * (x[2 * (i + 1)] + x[2 * i])); } // Left boundary of approximation coefficients requires special // handling (we don't have cD[i] for i==-1 // long cDm1 = x[-1] - floor(0.5 * (x[0] + x[-2])); cA[0] = x[0] + floor(0.25 * (cD[0] + cDm1) + 0.5); // For even length signals nD=nC. For odd, nD=nC-1 and we need // special handling for right boundary // for (size_t i = 1; i < nD; i++) { cA[i] = x[2 * i] + floor(0.25 * (cD[i] + cD[i - 1]) + 0.5); } // Boundary handling for odd length signals // if (sigInLen % 2) { size_t i = nC - 1; long cDp1 = x[2 * i + 1] - floor(0.5 * (x[2 * (i + 1)] + x[2 * i])); cA[i] = x[2 * i] + floor(0.25 * (cDp1 + cD[i - 1]) + 0.5); } } void WaveFiltInt::Synthesis(const long *cA, const long *cD, size_t sigInLen, long *sigOut) const { if (_wavename == "intbior2.2" || _wavename == "intcdf5/3") { _SynthesisCDF5_3(cA, cD, sigInLen, sigOut); } else { _SynthesisCDF5_3(cA, cD, sigInLen, sigOut); } } void WaveFiltInt::_SynthesisCDF5_3(const long *cA, const long *cD, size_t sigInLen, long *sigOut) const { cA += 1; // skip signal extension cD += 1; // skip signal extension size_t n = sigInLen; // Even samples // for (size_t i = 0; i < n; i++) { sigOut[2 * i] = cA[i] - floor(0.25 * (cD[i - 1] + cD[i]) + 0.5); } // Odd samples // for (size_t i = 0; i < n - 1; i++) { sigOut[2 * i + 1] = cD[i] + floor(0.5 * (sigOut[2 * (i + 1)] + sigOut[2 * i])); } // Right boundary requires special handling - we don't have // even sample for sigOut[2*(i+1)] when i==n-1 // size_t i = n - 1; long sp1 = cA[n] - floor(0.25 * (cD[n - 1] + cD[n]) + 0.5); sigOut[2 * i + 1] = cD[i] + floor(0.5 * (sp1 + sigOut[2 * i])); } ================================================ FILE: plugins/paraview/CMakeLists.txt ================================================ PROJECT(VDFReader) # Plugin that uses the Vapor libraries to read VDF files into ParaView cmake_minimum_required(VERSION 2.8) IF( COMMAND CMAKE_POLICY ) CMAKE_POLICY( SET CMP0003 NEW ) ENDIF( COMMAND CMAKE_POLICY ) IF (ParaView_SOURCE_DIR) INCLUDE_DIRECTORIES( ${PARAVIEW_INCLUDE_DIRS} ${PARAVIEW_GUI_INCLUDE_DIRS} ${PARAVIEW_KWSYS_INCLUDE_DIRS} ) ELSE (ParaView_SOURCE_DIR) FIND_PACKAGE(ParaView REQUIRED) INCLUDE(${PARAVIEW_USE_FILE}) ENDIF (ParaView_SOURCE_DIR) #find where all vapor header files live (especially vaporinternal/common.h) FIND_PATH (VAPOR_HEADERS vaporinternal/common.h PATHS /ThirdPartyLibraries/VAPOR/source/vapor-1.5.2/vapor/include DOC "NCAR Vapor source directory, where include/vaporinternal/common.h can be found" ) #include the parts of vapor that we need to compile the reader #both vapor/ and vaporinternal/ are underneath this INCLUDE_DIRECTORIES(${VAPOR_HEADERS}) #link to the parts of vapor lib that we need to run/compile the reader FIND_LIBRARY(VAPOR_VDF_LIB vdf DOC "NCAR Vapor Data Format library") FIND_LIBRARY(VAPOR_COMMON_LIB common DOC "NCAR Vapor common libary") #find expat and netcdf libs that vapor library itself uses FIND_PACKAGE(EXPAT REQUIRED) INCLUDE_DIRECTORIES(${EXPAT_INCLUDE_DIRS}) FIND_LIBRARY(VAPOR_NETCDF_LIB netcdf DOC "NetCDF library required for VAPOR plugin") ADD_PARAVIEW_PLUGIN(VDFReaderPlugin "1.0" SERVER_MANAGER_XML VDFReader.xml SERVER_MANAGER_SOURCES vtkVDFReader.cxx GUI_RESOURCE_FILES VDFReaderGUI.xml) TARGET_LINK_LIBRARIES(VDFReaderPlugin ${VAPOR_VDF_LIB} ${VAPOR_COMMON_LIB} ${EXPAT_LIBRARIES} ${VAPOR_NETCDF_LIB} ) ================================================ FILE: plugins/paraview/README ================================================ =============== How To Build =============== From the source folder, run: ccmake . Then press 'c' to configure, CMake will attempt to find ParaView and the Vapor libraries and include directory. You may need to specify these variables manually: ParaView_DIR path to your local ParaView build directory VAPOR_COMMON_LIB path to libcommon.so (from Vapor binaries) VAPOR_HEADERS path to Vapor include directory (from Vapor Source) VAPOR_NETCDF_LIB path to libnetcdf.so VAPOR_VDF_LIB path to libvdf.so (from Vapor binaries) Then press 'c' to configure again. If there are no errors, press 'g' to generate a Makefile and exit ccmake. To build the shared object (plugin) run: make ================================================ FILE: plugins/paraview/VDFReader.xml ================================================ The Vapor Data Format (VDF) reader loads wavelet compressed data files. The refinement parameter controls the resolution of the data that is read in which gives you a speed/fidelity tradeoff control. See http://www.vapor.ucar.edu. This property controls the maximum refinement level ================================================ FILE: plugins/paraview/VDFReaderGUI.xml ================================================ ================================================ FILE: plugins/paraview/vtkVDFReader.cxx ================================================ /*========================================================================= Visualization and Analysis Platform for Ocean, Atmosphere, and Solar Researchers (VAPOR) Terms of Use This VAPOR (the Software ) was developed by the University Corporation for Atmospheric Research. PLEASE READ THIS SOFTWARE LICENSE AGREEMENT ("AGREEMENT") CAREFULLY. INDICATE YOUR ACCEPTANCE OF THESE TERMS BY SELECTING THE I ACCEPT BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO ALL OF THE TERMS OF THIS AGREEMENT, SELECT THE I DON?T ACCEPT? BUTTON AND THE INSTALLATION PROCESS WILL NOT CONTINUE. 1. License. The University Corporation for Atmospheric Research (UCAR) grants you a non-exclusive right to use, create derivative works, publish, distribute, disseminate, transfer, modify, revise and copy the Software. 2. Proprietary Rights. Title, ownership rights, and intellectual property rights in the Software shall remain in UCAR. 3. Disclaimer of Warranty on Software. You expressly acknowledge and agree that use of the Software is at your sole risk. The Software is provided "AS IS" and without warranty of any kind and UCAR EXPRESSLY DISCLAIMS ALL WARRANTIES AND/OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT OF A THIRD PARTY?S INTELLECTUAL PROPERTY, MERCHANTABILITY OR SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. UCAR DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED IN THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE SOFTWARE WILL BE CORRECTED. FURTHERMORE, UCAR DOES NOT WARRANT OR MAKE ANY REPRESENTATIONS AND YOU ASSUME ALL RISK REGARDING THE USE OR THE RESULTS OF THE USE OF THE SOFTWARE OR RELATED DOCUMENTATION IN TERMS OF THEIR CORRECTNESS, ACCURACY, RELIABILITY, OR OTHERWISE. THE PARTIES EXPRESSLY DISCLAIM THAT THE UNIFORM COMPUTER INFORMATION TRANSACTIONS ACT (UCITA) APPLIES TO OR GOVERNS THIS AGREEMENT. No oral or written information or advice given by UCAR or a UCAR authorized representative shall create a warranty or in any way increase the scope of this warranty. Should the Software prove defective, you (and not UCAR or any UCAR representative) assume the cost of all necessary correction. 4. Limitation of Liability. UNDER NO CIRCUMSTANCES, INCLUDING NEGLIGENCE, SHALL UCAR OR ITS COLLABORATORS, INCLUDING OHIO STATE UNIVERSITY, BE LIABLE FOR ANY DIRECT, INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES INCLUDING LOST REVENUE, PROFIT OR DATA, WHETHER IN AN ACTION IN CONTRACT OR TORT ARISING OUT OF OR RELATING TO THE USE OF OR INABILITY TO USE THE SOFTWARE, EVEN IF UCAR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 5. Compliance with Law. All Software and any technical data delivered under this Agreement are subject to U.S. export control laws and may be subject to export or import regulations in other countries. You agree to comply strictly with all applicable laws and regulations in connection with use and distribution of the Software, including export control laws, and you acknowledge that you have responsibility to obtain any required license to export, re-export, or import as may be required. 6. No Support/Modifications. The names UCAR/NCAR and SCD may not be used in any advertising or publicity to endorse or promote any products or commercial entity unless specific written permission is obtained from UCAR. The Software is provided without any support or maintenance, and without any obligation to provide you with modifications, improvements, enhancements, or updates of the Software. 7. Controlling Law and Severability. This Agreement shall be governed by the laws of the United States and the State of Colorado. If for any reason a court of competent jurisdiction finds any provision, or portion thereof, to be unenforceable, the remainder of this Agreement shall continue in full force and effect. This Agreement shall not be governed by the United Nations Convention on Contracts for the International Sale of Goods, the application of which is hereby expressly excluded. 8. Termination. Your rights under this Agreement will terminate automatically without notice from UCAR if you fail to comply with any term(s) of this Agreement. You may terminate this Agreement at any time by destroying the Software and any related documentation and any complete or partial copies thereof. Upon termination, all rights granted under this Agreement shall terminate. The following provisions shall survive termination: Sections 2, 3, 4, 7 and 10. 9. Complete Agreement. This Agreement constitutes the entire agreement between the parties with respect to the use of the Software and supersedes all prior or contemporaneous understandings regarding such subject matter. No amendment to or modification of this Agreement will be binding unless in a writing and signed by UCAR. 10. Notices and Additional Terms. Each copy of the Software shall include a copy of this Agreement and the following notice: "The source of this material is the Science Computing Division of the National Center for Atmospheric Research, a program of the University Corporation for Atmospheric Research (UCAR) pursuant to a Cooperative Agreement with the National Science Foundation; Copyright (c)2006 University Corporation for Atmospheric Research. All Rights Reserved." This notice shall be displayed on any documents, media, printouts, and visualizations or on any other electronic or tangible expressions associated with, related to or derived from the Software or associated documentation. The Software includes certain copyrighted, segregable components listed below (the Third Party Code?), including software developed by Ohio State University. For this reason, you must check the source identified below for additional notice requirements and terms of use that apply to your use of this Software. -------------------------------------------------------------------------- Program: Visualization Toolkit Module: vtkVDFReader.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkVDFReader.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkImageAlgorithm.h" #include "vtkImageData.h" #include "vtkDataArray.h" #include "vtkFloatArray.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkStreamingDemandDrivenPipeline.h" using namespace VAPoR; vtkStandardNewMacro(vtkVDFReader); //----------------------------------------------------------------------------- vtkVDFReader::vtkVDFReader() { this->FileName = 0; this->SetNumberOfInputPorts(0); this->SetNumberOfOutputPorts(1); this->Refinement = 0; this->nTimeSteps = 0; this->TimeSteps = NULL; this->TimeStep = 0; this->vdc_md = NULL; this->data_mgr = NULL; this->vdfiobase = NULL; this->CacheSize = 1000; this->height_factor = 4; this->RefinementRange[0]=0; this->RefinementRange[1]=5; } //----------------------------------------------------------------------------- vtkVDFReader::~vtkVDFReader() { this->SetFileName(0); delete data_mgr; delete vdfiobase; delete vdc_md; delete TimeSteps; } //----------------------------------------------------------------------------- int vtkVDFReader::RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) { // extract data objects vtkImageData *image = vtkImageData::GetData(outputVector); vtkInformation *info = outputVector->GetInformationObject(0); // setup initial boundaries int ext[6] = {0, (int)ext_p[0], 0, (int)ext_p[1], 0, (int)ext_p[2]}; int ext_minus_one[6] = {0, (int)ext_p[0]-1, 0, (int)ext_p[1]-1, 0, (int)ext_p[2]-1}; int *updateExt, front_pad[] = {0,0,0}; size_t bdim[3], udim[3]; GetVarDims(udim, bdim); const size_t *bmsize=vdc_md->GetBlockSize(); size_t data_size[3] = {bmsize[0]*bdim[0], bmsize[1]*bdim[1], bmsize[2]*bdim[2]}; size_t v_min[3] = {0,0,0}; size_t v_max[3] = {bdim[0]-1, bdim[1]-1, bdim[2]-1}; // update boundaries to only load the needed data from disk updateExt = info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT()); if (/*true*/! extentsMatch(updateExt, ext)) { //printf("Recived sub-block of extents: %d %d %d %d %d %d\n", // updateExt[0], updateExt[1], updateExt[2], // updateExt[3], updateExt[4], updateExt[5]); size_t v0[]={updateExt[0],updateExt[2],updateExt[4]}; size_t v1[]={updateExt[1],updateExt[3],updateExt[5]}; vdfiobase->MapVoxToBlk(v0, v_min); vdfiobase->MapVoxToBlk(v1, v_max); for (int i=0; i<6; i+=2) { ext_minus_one[i] = updateExt[i]; ext_minus_one[i+1] = updateExt[i+1]; ext[i] = updateExt[i]; ext[i+1] = updateExt[i+1]+1; data_size[i/2] = (1 + v_max[i/2] - v_min[i/2]) * bmsize[i/2]; front_pad[i/2] = v_min[i/2] * bmsize[i/2]; } } // setup image memory image->SetExtent(ext_minus_one); image->SetScalarTypeToFloat(); image->AllocateScalars(); // get the correct timestep if (info->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEPS())) { double *TimeStepsReq = info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEPS()); TimeStep = (int)floor(TimeStepsReq[0]); SetExtents(info); //printf("Recieved updated timestep: %d\n", TimeStep); } // load data for all enabled point arrays for (vtkstd::map::iterator it = data.begin(); it !=data.end(); ++it) { if (it->second == 0) { continue; } vtkFloatArray* scalars = vtkFloatArray::New(); scalars->SetName(it->first.c_str()); scalars->SetNumberOfValues((ext[1]-ext[0])*(ext[3]-ext[2])*(ext[5]-ext[4])); SetProgressText("Loading VDC Data"); //check that data exists on disk for this var/ref/time if (!vdfiobase->VariableExists(TimeStep, it->first.c_str(), this->Refinement)) { vtkErrorMacro(<< it->first << " data does not exist at time: " << TimeStep); return 0; } //load data into memory float *vapor_data = data_mgr->GetRegion(TimeStep, it->first.c_str(), this->Refinement, v_min, v_max); //verify data pointer if (vapor_data == NULL) { vtkErrorMacro(<< "Data manager returned NULL pointer."); return 0; } //copy data to return memory (stripping block-padding) vtkIdType iReal=0; for (vtkIdType z = ext[4]; z < ext[5]; z++) { for (vtkIdType y = ext[2]; y < ext[3]; y++) { for (vtkIdType x = ext[0]; x < ext[1]; x++) { scalars->SetValue (iReal, vapor_data[(z-front_pad[2]) *data_size[1]*data_size[0] + (y-front_pad[1]) *data_size[0] + (x-front_pad[0]) ] ); iReal++; } } this->UpdateProgress((float)z/(1+ext[5])); } image->GetPointData()->AddArray(scalars); if (!image->GetPointData()->GetScalars()) { image->GetPointData()->SetScalars(scalars); } scalars->Delete(); } return 1; } //----------------------------------------------------------------------------- int vtkVDFReader::RequestInformation(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) { vtkInformation *outInfo = outputVector->GetInformationObject(0); //only perform the initial allocations once if (vdc_md == NULL) { //create metadataVDC for this file vdc_md = new Metadata(FileName); RefinementRange[1] = vdc_md->GetNumTransforms(); //create vdf base class from metadata vdfiobase = new WaveletBlock3DRegionReader(vdc_md); //create data manager from metadata data_mgr = new DataMgr(vdc_md, this->CacheSize); //add each variable to the list, intially off (i.e 0) const vtkstd::vector NamesAll = vdc_md->GetVariableNames(); for (size_t i=0; iSet(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), TimeSteps, nTimeSteps); outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), TimeRange, 2); } SetExtents(outInfo); return 1; } //----------------------------------------------------------------------------- void vtkVDFReader::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "FileName: " << (this->FileName ? this->FileName : "(NULL)") << endl; os << indent << "VariableType " << this->VariableType << endl; os << indent << "Refinement " << this->Refinement << endl; os << indent << "CacheSize " << this->CacheSize << endl; } //----------------------------------------------------------------------------- int vtkVDFReader::CanReadFile(const char *fname) { //TODO: Do some quick check on whether the file actually is in VDF format return 1; } //----------------------------------------------------------------------------- void vtkVDFReader::SetRefinement(int newref) { if (newref == this->Refinement) { return; } //printf("refinement level changed to: %d\n", newref); this->Refinement = newref; this->Modified(); } //----------------------------------------------------------------------------- void vtkVDFReader::SetCacheSize(int newSize) { if (newSize == this->CacheSize) { return; } //printf("cache size changed to: %d\n", newSize); this->CacheSize = newSize; if (data_mgr != NULL) { delete data_mgr; data_mgr = new DataMgr(vdc_md, this->CacheSize); this->Modified(); } } //----------------------------------------------------------------------------- void vtkVDFReader::SetVariableType(int newtype) { if (newtype == this->VariableType) { return; } //printf("var type changed to: %d\n", newtype); this->VariableType = newtype; data.clear(); this->Modified(); } //----------------------------------------------------------------------------- int vtkVDFReader::FillTimeSteps() { //get list of all possible variables in metadata const vtkstd::vector nms = vdc_md->GetVariableNames(); //get all possible timesteps int tmp_nTimeSteps = vdc_md->GetNumTimeSteps(); TimeSteps = new double[tmp_nTimeSteps]; //number of valid timesteps, start a 0 nTimeSteps = 0; for (int i=0; iVariableExists(i, nms[j].c_str()) != 0) { TimeSteps[nTimeSteps++] = (double)i; good=true; //exit inner loop on first valid var } } } //set current timestep to first valid time TimeStep = (int) TimeSteps[0]; return nTimeSteps; } //----------------------------------------------------------------------------- bool vtkVDFReader::extentsMatch(int *a, int *b) { for (int i=0; i<6; i++) { if (a[i] != b[i]) return false; } return true; } //----------------------------------------------------------------------------- int vtkVDFReader::GetNumberOfPointArrays() { return current_var_list.size(); } //----------------------------------------------------------------------------- const char *vtkVDFReader::GetPointArrayName(int index) { return current_var_list[index].c_str(); } //----------------------------------------------------------------------------- int vtkVDFReader::GetPointArrayStatus(const char* name) { return data[vtkstd::string(name)]; } //----------------------------------------------------------------------------- void vtkVDFReader::SetPointArrayStatus(const char* name, int en) { if (en != data[vtkstd::string(name)]) { data[vtkstd::string(name)] = en; this->Modified(); } } //----------------------------------------------------------------------------- void vtkVDFReader::GetVarDims(size_t *udims, size_t *bdims) { vdfiobase->GetDim(udims, this->Refinement); vdfiobase->GetDimBlk(bdims, this->Refinement); } //----------------------------------------------------------------------------- void vtkVDFReader::SetExtents(vtkInformation *outInfo) { //Get user extents for this variable, refinement level, and timestep const vtkstd::vector glExt = vdc_md->GetExtents(), tsExt = vdc_md->GetTSExtents(TimeStep); uExt = (vtkstd::vector) (tsExt.empty()? glExt: tsExt); vdfiobase->GetDim(ext_p, this->Refinement); int ext[6] = {0, (int)ext_p[0]-1, 0, (int)ext_p[1]-1, 0, (int)ext_p[2]-1}; vtkstd::vector var_list; switch (this->VariableType) { case 0: var_list = (vtkstd::vector) vdc_md->GetVariables3D(); break; case 1: var_list = (vtkstd::vector) vdc_md->GetVariables2DXY(); ext[5] = 0; break; case 2: var_list = (vtkstd::vector) vdc_md->GetVariables2DXZ(); ext[3] = 0; break; case 3: var_list = (vtkstd::vector) vdc_md->GetVariables2DYZ(); ext[1] = 0; break; default : vtkErrorMacro(<< " FATAL: bad type: " << this->VariableType); break; } //rearrange user extents to expected array formats, communicate down pipeline double origin[3] = {uExt[0], uExt[1], uExt[2]}; //double bbox[6] = {uExt[0], uExt[3], uExt[1], uExt[4], uExt[2], uExt[5]}; double spacing[3] = {(uExt[3]-uExt[0])/(ext[1]+1), (uExt[4]-uExt[1])/(ext[3]+1), (uExt[5]-uExt[2])/(ext[5]+1)}; outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), ext, 6); //outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_BOUNDING_BOX(), //bbox, 6); outInfo->Set(vtkDataObject::ORIGIN(), origin, 3); outInfo->Set(vtkDataObject::SPACING(), spacing, 3); //copy list of vars, excluding those for which no data exists: current_var_list.clear(); for (size_t i=0; iVariableExists(TimeStep, var_list[i].c_str(), this->Refinement) != 0) { current_var_list.push_back(var_list[i]); } } } ================================================ FILE: plugins/paraview/vtkVDFReader.h ================================================ /*========================================================================= Visualization and Analysis Platform for Ocean, Atmosphere, and Solar Researchers (VAPOR) Terms of Use This VAPOR (the Software ) was developed by the University Corporation for Atmospheric Research. PLEASE READ THIS SOFTWARE LICENSE AGREEMENT ("AGREEMENT") CAREFULLY. INDICATE YOUR ACCEPTANCE OF THESE TERMS BY SELECTING THE I ACCEPT BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO ALL OF THE TERMS OF THIS AGREEMENT, SELECT THE I DON?T ACCEPT? BUTTON AND THE INSTALLATION PROCESS WILL NOT CONTINUE. 1. License. The University Corporation for Atmospheric Research (UCAR) grants you a non-exclusive right to use, create derivative works, publish, distribute, disseminate, transfer, modify, revise and copy the Software. 2. Proprietary Rights. Title, ownership rights, and intellectual property rights in the Software shall remain in UCAR. 3. Disclaimer of Warranty on Software. You expressly acknowledge and agree that use of the Software is at your sole risk. The Software is provided "AS IS" and without warranty of any kind and UCAR EXPRESSLY DISCLAIMS ALL WARRANTIES AND/OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT OF A THIRD PARTY?S INTELLECTUAL PROPERTY, MERCHANTABILITY OR SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. UCAR DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED IN THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE SOFTWARE WILL BE CORRECTED. FURTHERMORE, UCAR DOES NOT WARRANT OR MAKE ANY REPRESENTATIONS AND YOU ASSUME ALL RISK REGARDING THE USE OR THE RESULTS OF THE USE OF THE SOFTWARE OR RELATED DOCUMENTATION IN TERMS OF THEIR CORRECTNESS, ACCURACY, RELIABILITY, OR OTHERWISE. THE PARTIES EXPRESSLY DISCLAIM THAT THE UNIFORM COMPUTER INFORMATION TRANSACTIONS ACT (UCITA) APPLIES TO OR GOVERNS THIS AGREEMENT. No oral or written information or advice given by UCAR or a UCAR authorized representative shall create a warranty or in any way increase the scope of this warranty. Should the Software prove defective, you (and not UCAR or any UCAR representative) assume the cost of all necessary correction. 4. Limitation of Liability. UNDER NO CIRCUMSTANCES, INCLUDING NEGLIGENCE, SHALL UCAR OR ITS COLLABORATORS, INCLUDING OHIO STATE UNIVERSITY, BE LIABLE FOR ANY DIRECT, INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES INCLUDING LOST REVENUE, PROFIT OR DATA, WHETHER IN AN ACTION IN CONTRACT OR TORT ARISING OUT OF OR RELATING TO THE USE OF OR INABILITY TO USE THE SOFTWARE, EVEN IF UCAR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 5. Compliance with Law. All Software and any technical data delivered under this Agreement are subject to U.S. export control laws and may be subject to export or import regulations in other countries. You agree to comply strictly with all applicable laws and regulations in connection with use and distribution of the Software, including export control laws, and you acknowledge that you have responsibility to obtain any required license to export, re-export, or import as may be required. 6. No Support/Modifications. The names UCAR/NCAR and SCD may not be used in any advertising or publicity to endorse or promote any products or commercial entity unless specific written permission is obtained from UCAR. The Software is provided without any support or maintenance, and without any obligation to provide you with modifications, improvements, enhancements, or updates of the Software. 7. Controlling Law and Severability. This Agreement shall be governed by the laws of the United States and the State of Colorado. If for any reason a court of competent jurisdiction finds any provision, or portion thereof, to be unenforceable, the remainder of this Agreement shall continue in full force and effect. This Agreement shall not be governed by the United Nations Convention on Contracts for the International Sale of Goods, the application of which is hereby expressly excluded. 8. Termination. Your rights under this Agreement will terminate automatically without notice from UCAR if you fail to comply with any term(s) of this Agreement. You may terminate this Agreement at any time by destroying the Software and any related documentation and any complete or partial copies thereof. Upon termination, all rights granted under this Agreement shall terminate. The following provisions shall survive termination: Sections 2, 3, 4, 7 and 10. 9. Complete Agreement. This Agreement constitutes the entire agreement between the parties with respect to the use of the Software and supersedes all prior or contemporaneous understandings regarding such subject matter. No amendment to or modification of this Agreement will be binding unless in a writing and signed by UCAR. 10. Notices and Additional Terms. Each copy of the Software shall include a copy of this Agreement and the following notice: "The source of this material is the Science Computing Division of the National Center for Atmospheric Research, a program of the University Corporation for Atmospheric Research (UCAR) pursuant to a Cooperative Agreement with the National Science Foundation; Copyright (c)2006 University Corporation for Atmospheric Research. All Rights Reserved." This notice shall be displayed on any documents, media, printouts, and visualizations or on any other electronic or tangible expressions associated with, related to or derived from the Software or associated documentation. The Software includes certain copyrighted, segregable components listed below (the Third Party Code?), including software developed by Ohio State University. For this reason, you must check the source identified below for additional notice requirements and terms of use that apply to your use of this Software. -------------------------------------------------------------------------- Program: Visualization Toolkit Module: vtkVDFReader.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ // .NAME vtkVDFReader - class for reader Vapor Data Format files // .Section Description // vtkVDFReader uses the Vapor library to read wavelet compressed VDF files // and produce VTK data image data. The resolution of the image data is // controlled by the refinement parameter. // #ifndef _vtkVDFReader_h #define _vtkVDFReader_h #include "vtkImageAlgorithm.h" #include "vapor/DataMgr.h" //needed for vapor datastructures #include "vapor/WaveletBlock3DRegionReader.h" //needed for vapor datastructures #include //needed for protected ivars #include //needed for protected ivars #include //needed for protected ivars // using namespace std; using namespace VAPoR; class VTK_EXPORT vtkVDFReader : public vtkImageAlgorithm { public: static vtkVDFReader *New(); vtkTypeMacro(vtkVDFReader, vtkImageAlgorithm); void PrintSelf(ostream &os, vtkIndent indent); // Description: // Choose file to read vtkSetStringMacro(FileName); vtkGetStringMacro(FileName); // Description: // Check file for suitability to this reader int CanReadFile(const char *fname); // Description: // Set resolution within range provided by data. void SetRefinement(int); vtkGetMacro(Refinement, int); vtkGetVector2Macro(RefinementRange, int); // Description: void SetVariableType(int); vtkGetMacro(VariableType, int); // Description: void SetCacheSize(int); vtkGetMacro(CacheSize, int); // Description: // Choose which arrays to load int GetPointArrayStatus(const char *); void SetPointArrayStatus(const char *, int); int GetNumberOfPointArrays(); const char *GetPointArrayName(int); protected: vtkVDFReader(); ~vtkVDFReader(); int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *); int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); int FillTimeSteps(); char *FileName; Metadata * vdc_md; DataMgr * data_mgr; VDFIOBase *vdfiobase; bool is_layered; int height_factor; int num_levels; size_t ext_p[3]; int Refinement; int VariableType; int CacheSize; double *TimeSteps; int nTimeSteps; int TimeStep; int RefinementRange[2]; // BTX vtkstd::map data; vtkstd::vector uExt; vtkstd::vector current_var_list; // ETX private: vtkVDFReader(const vtkVDFReader &); void operator=(const vtkVDFReader &); bool extentsMatch(int *, int *); void GetVarDims(size_t *, size_t *); void SetExtents(vtkInformation *); }; #endif ================================================ FILE: plugins/visit/VDC/README ================================================ VisIt VDC Reader Plugin The contents of this directory provide a VAPOR Data Collection (VDC) import plugin for VisIt (https://wci.llnl.gov/codes/visit/home.html). =============== How To Build =============== Note: That you do not need to have built your own version of Visit or VAPoR, this will work with downloaded binary version. This code has been tested Mac and Linux platforms for VisIt 2.3.0 and VAPOR 2.1 ---------------------- 1) Install VisIt and VAPOR on your system. 2) Edit the vdf.xml file and make sure that the libray and include paths are correct for your installation of Vapor. You will need to set the CFLAGS and LDFLAGS elements as appropriate. Also, make sure that you include paths to any other dependent libraries (i.e libcurl for netcdf4). You may also need to edit the LIBS element (for linux the 'rt' library is required). For more information see "Getting Data Into VisIT" available from: https://wci.llnl.gov/codes/visit/manuals.html 3) Remove the file CMakeCache.txt if it exists. 4) You may need to edit the option file VISITARCHHOME///include/PluginVsInstall.cmake There is a section called "VisIt options" which controls options like parallel execution and java. 5) Next to generate the CMakeLists.txt by running: xml2cmake -clobber vdf.xml This command is found in VISITARCHHOME/bin . 6) Use cmake to generate a Makefile, run: cmake . 7) Finally, build the binaries by running: make clean all This will build the 4 shared objects which make up the plugin (3 if MPI is not used). The plugin will be installed in the directory ~/.visit//plugins/database/ ============================== Platform Specific Notes ============================== Mac OS ------ Prior to executing visit the environment variable DYLD_FALLBACK_LIBRARY_PATH must be set to the path where VAPOR's libraries were installed. For a binary installation of VAPOR this will be /Applications/VAPOR.app/Contents/MacOS : setenv DYLD_FALLBACK_LIBRARY_PATH /Applications/VAPOR.app/Contents/MacOS Linux ----- On linux systems the library 'rt' must be added to the LIBS element of the vdf.xml configuration file. ================================================ FILE: plugins/visit/VDC/avtvdfFileFormat.C ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2009, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-400124 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ // ************************************************************************* // // avtvdfFileFormat.C // // ************************************************************************* // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //used by VisIt for Windows workaround using std::string; using std::vector; using std::map; void debug_callback(const char *msg) { printf("debug: %s\n",msg); } void err_callback(const char *msg, int n) { printf("err{%d}: %s\n",n,msg); } // **************************************************************************** // Method: avtvdfFileFormat constructor // // Programmer: dlagreca -- generated by xml2avt // Creation: Wed Feb 24 15:32:35 PST 2010 // // **************************************************************************** avtvdfFileFormat::avtvdfFileFormat(const char *filename, DBOptionsAttributes *readOpts) : avtMTMDFileFormat(filename) { size_t maxts; int buffer_size = readOpts->GetInt("Cache size [MB]"); double heightMult_layered = readOpts->GetDouble( "Layered data resampling factor"); multiDom = readOpts->GetBool("MultiDomain"); if (heightMult_layered <= 0.f || buffer_size <= 0) EXCEPTION1(InvalidDBTypeException, "Invalid Option, must be >0."); vdc_md = new VAPoR::MetadataVDC(string(filename)); vdfiobase = new VAPoR::WaveletBlock3DRegionReader(string(filename)); if (vdc_md == NULL) printf ("NULL VDC!\n"); // instantiate the correct data manager sub-type. isLayered = (vdc_md->GetGridType().compare("layered") == 0); if (isLayered) { VAPoR::DataMgrLayered *dmLayered_inst = new VAPoR::DataMgrLayered(string(filename), buffer_size ); data_mgr = dmLayered_inst; } else { VAPoR::DataMgrWB *dmWB_inst = new VAPoR::DataMgrWB(*vdc_md, buffer_size ); data_mgr = dmWB_inst; } if (data_mgr == NULL) printf("NULL Datamanager!\n"); // MyBase::SetErrMsgCB(err_callback); // MyBase::SetDiagMsgCB(debug_callback); num_levels = vdc_md->GetNumTransforms() + 1; maxts = vdc_md->GetNumTimeSteps() - 1; tsteps = new int[maxts]; ntsteps = 0; levels3D = levelsXY = levelsXZ = levelsYZ = -1; Names3D = (vector) (vdc_md->GetVariables3D()); xyNames = (vector) (vdc_md->GetVariables2DXY()); xzNames = (vector) (vdc_md->GetVariables2DXZ()); yzNames = (vector) (vdc_md->GetVariables2DYZ()); // search through all possible variables, refinement levels, // and timesteps to eliminate timesteps with no valid data, and // find the max valid refinement level for each variable (for // scalar var metadta) and variable type (for mesh metadata). for (int t=0; tVariableExists((size_t)t, Names3D[n].c_str(), l) !=0) { varTypes[Names3D[n]] = 0; levels3D = (l > levels3D)? l: levels3D; refLevel[Names3D[n]] = levels3D; thisTimeIsValid = true; } } for (int n=0; nVariableExists((size_t)t, xyNames[n].c_str(), l) !=0) { varTypes[xyNames[n]] = 1; levelsXY = (l > levelsXY)? l: levelsXY; refLevel[xyNames[n]] = levelsXY; thisTimeIsValid = true; } } for (int n=0; nVariableExists((size_t)t, xzNames[n].c_str(), l) !=0) { varTypes[xzNames[n]] = 2; levelsXZ = (l > levelsXZ)? l: levelsXZ; refLevel[xzNames[n]] = levelsXZ; thisTimeIsValid = true; } } for (int n=0; nVariableExists((size_t)t, yzNames[n].c_str(), l) !=0) { varTypes[yzNames[n]] = 3; levelsYZ = (l > levelsYZ)? l: levelsYZ; refLevel[yzNames[n]] = levelsYZ; thisTimeIsValid = true; } } } if (thisTimeIsValid) { tsteps[ntsteps] = t; ntsteps++; } } if (ntsteps == 0 || data_mgr == NULL) EXCEPTION1(InvalidDBTypeException, "No valid data."); } // **************************************************************************** // Method: avtvdfFileFormat destructor // // Programmer: dlagreca // Creation: Wed Feb 24 14:12:30 PST 2010 // // **************************************************************************** avtvdfFileFormat::~avtvdfFileFormat() { // clean up memory delete data_mgr; delete vdfiobase; delete vdc_md; delete[] tsteps; } // **************************************************************************** // Method: avtvdfFileFormat::FreeUpResources // // Purpose: // When VisIt is done focusing on a particular timestep, it asks that // timestep to free up any resources (memory, file descriptors) that // it has associated with it. This method is the mechanism for doing // that. // // Programmer: dlagreca -- generated by xml2avt // Creation: Wed Feb 24 15:32:35 PST 2010 // // **************************************************************************** void avtvdfFileFormat::FreeUpResources(void) { //data_mgr->Clear(); } // **************************************************************************** // Method: avtvdfFileFormat::PopulateDatabaseMetaData // // Purpose: // This database meta-data object is like a table of contents for the // file. By populating it, you are telling the rest of VisIt what // information it can request from you. // // Programmer: dlagreca -- generated by xml2avt // Creation: Wed Feb 24 15:32:35 PST 2010 // // **************************************************************************** void avtvdfFileFormat::PopulateDatabaseMetaData(avtDatabaseMetaData *md, int timeState) { //clear any old error messages before we start vdfiobase->SetErrCode(0); size_t ldim[3], bdim[num_levels][3]; char refNames[num_levels][20]; for (int l=0; lSetContainsGhostZones(string(Mname3D[j]),AVT_CREATED_GHOSTS); md->SetContainsOriginalCells(string(Mname3D[j]),true); refLevel[Mname3D[j]] = j; } for (int j=0; j<=levelsXY; j++) { SNPRINTF(XYMname[j], 50, "XY_%s", refNames[j]); AddMeshToMetaData(md, XYMname[j], AVT_RECTILINEAR_MESH, extents, multiDom? bdim[j][0]*bdim[j][1]: 1, 0,2,2); refLevel[XYMname[j]] = j; } for (int j=0; j<=levelsXZ; j++) { SNPRINTF(XZMname[j], 50, "XZ_%s", refNames[j]); AddMeshToMetaData(md, XZMname[j], AVT_RECTILINEAR_MESH, extents, multiDom? bdim[j][0]*bdim[j][2]: 1, 0,2,2); refLevel[XZMname[j]] = j; } for (int j=0; j<=levelsYZ; j++) { SNPRINTF(YZMname[j], 50, "YZ_%s", refNames[j]); AddMeshToMetaData(md, YZMname[j], AVT_RECTILINEAR_MESH, extents, multiDom? bdim[j][1]*bdim[j][2]: 1, 0,2,2); refLevel[YZMname[j]] = j; } char vname[100]; // create a visit variable for each valid refinement level for each // valid Vapor variable. Name it /XxYxZ/ // the '/' char tells visit to create a submenu. Attach to the correct // mesh based on dimensional type and refinement level for (int i=0; iSetErrCode(0); // Build the 3D mesh, and refactor appropriately for 2D meshes size_t dims_st[3], bdims[3]; const size_t *block_size = vdc_md->GetBlockSize(); int dim_start[3]; getVarDims(string(meshname), dims_st, bdims); size_t coordsB[3], dims_real[3]; if (multiDom){ getCoordsFromIndex(coordsB, bdims, domain); getVoxelsInBlock(dims_real, dims_st, bdims, coordsB); for (int i=0; i<3; i++) { dims_real[i] ++; dim_start[i] = (block_size[i])*(coordsB[i])-(coordsB[i]==0?0:1); } } else { for (int i=0; i<3; i++) { dim_start[i] = 0; dims_real[i] = dims_st[i] + 1; } } const vector glExtents = vdc_md->GetExtents(), tsExtents = vdc_md->GetTSExtents((size_t)tsteps[timestate]), uExtents = tsExtents.empty()? glExtents: tsExtents; // find user delta value for each dimension float dx = ((float)uExtents[3] - (float)uExtents[0])/(float)dims_st[0], dy = ((float)uExtents[4] - (float)uExtents[1])/(float)dims_st[1], dz = ((float)uExtents[5] - (float)uExtents[2])/(float)dims_st[2]; // these arrays map data coords to user coords vtkFloatArray *coordsX = vtkFloatArray::New(); vtkFloatArray *coordsY = vtkFloatArray::New(); vtkFloatArray *coordsZ = vtkFloatArray::New(); coordsX->SetNumberOfTuples(dims_real[0]); coordsY->SetNumberOfTuples(dims_real[1]); coordsZ->SetNumberOfTuples(dims_real[2]); // compute user coords for each data coord for (int i=(dim_start[0]), j=0; jSetValue(j, (float)i*dx + uExtents[0]); } for (int i=(dim_start[1]), j=0; jSetValue(j, (float)i*dy + uExtents[1]); } for (int i=(dim_start[2]), j=0; jSetValue(j, (float)i*dz + uExtents[2]); } // adjust array dimensions if var is only 2D if (!strncmp(meshname, "3D", 2)) { //already done! } else if (!strncmp(meshname, "XY", 2)) { dims_real[2] = 1; coordsZ->SetNumberOfTuples(1); coordsZ->SetValue(0, 0.f); } else if (!strncmp(meshname, "XZ", 2)) { dims_real[1] = 1; coordsY->SetNumberOfTuples(1); coordsY->SetValue(0, 0.f); } else if (!strncmp(meshname, "YZ", 2)) { dims_real[0] = 1; coordsX->SetNumberOfTuples(1); coordsX->SetValue(0, 0.f); } else { // No mesh name that we recognize. coordsX->Delete(); coordsY->Delete(); coordsZ->Delete(); EXCEPTION1(InvalidVariableException, meshname); } // apply coordinate maps and return rgrid vtkRectilinearGrid *rgrid = vtkRectilinearGrid::New(); rgrid->SetDimensions(dims_real[0], dims_real[1], dims_real[2]); rgrid->SetXCoordinates(coordsX); rgrid->SetYCoordinates(coordsY); rgrid->SetZCoordinates(coordsZ); if (multiDom) { //only add ghost data for multi-domain // Now that you have your mesh, figure out which cells need // to be removed. int nCells = rgrid->GetNumberOfCells(); // Now that we have the blanks array, create avtGhostZones. unsigned char realVal = 0, ghost = 0; size_t cell[3], cellMax[3]; for(int i=0; i<3; i++) cellMax[i] = dims_real[i]-1; avtGhostData::AddGhostZoneType(ghost, DUPLICATED_ZONE_INTERNAL_TO_PROBLEM); vtkUnsignedCharArray *ghostCells = vtkUnsignedCharArray::New(); ghostCells->SetName("avtGhostZones"); ghostCells->Allocate(nCells); for(int i = 0; i < nCells; ++i) { getCoordsFromIndex(cell, cellMax, i); bool isGhost = ((cell[0] == 0) && (coordsB[0] != 0)) || ((cell[0] == cellMax[0]-1) && (coordsB[0] != bdims[0]-1 )) || ((cell[1] == 0) && (coordsB[1] != 0)) || ((cell[1] == cellMax[1]-1) && (coordsB[1] != bdims[1]-1 )) || ((cell[2] == 0) && (coordsB[2] != 0)) || ((cell[2] == cellMax[2]-1) && (coordsB[2] != bdims[2]-1 )); if (isGhost) { ghostCells->InsertNextValue(ghost); } else { ghostCells->InsertNextValue(realVal); } } rgrid->GetCellData()->AddArray(ghostCells); rgrid->SetUpdateGhostLevel(0); ghostCells->Delete(); // Clean up coordsX->Delete(); coordsY->Delete(); coordsZ->Delete(); } return rgrid; } // **************************************************************************** // Method: avtvdfFileFormat::GetVar // // Purpose: // Gets a scalar variable associated with this file. Although VTK has // support for many different types, the best bet is vtkFloatArray, since // that is supported everywhere through VisIt. // // Arguments: // timestate The index of the timestate. If GetNTimesteps returned // 'N' time steps, this is guaranteed to be between 0 and N-1. // domain The index of the domain. If there are NDomains, this // value is guaranteed to be between 0 and NDomains-1, // regardless of block origin. // varname The name of the variable requested. // // Programmer: dlagreca -- generated by xml2avt // Creation: Wed Feb 24 15:32:35 PST 2010 // // **************************************************************************** vtkDataArray * avtvdfFileFormat::GetVar(int timestate_in, int domain, const char *varname) { //clear any old error messages before we start vdfiobase->SetErrCode(0); // Get actual timestep/varname used in vdf string varstring(varname); char *varname_clean = cleanVarname(varname); size_t timestate = (size_t) tsteps[timestate_in]; // Need to add lod value for GetRegion call for VAPOR 2.0.2 api. // Setting the value to zero, not sure if correct. int lod = 0; // Verifty that data for this var at this time and refinement exists if (!vdfiobase->VariableExists(timestate, varname_clean, refLevel[varstring])) { stringstream mesg; mesg << "Data for " << varname_clean << " does not exist in timestep " << timestate << " at refinement level " << refLevel[varstring] << "]."; EXCEPTION1(InvalidVariableException, mesg.str().c_str()); } // Get blocksize and data bounds to calculate padding datasize_t ds; size_t dmin[3], dmax[3], bdims[3], udims[3]; const size_t *bmsize = vdc_md->GetBlockSize(); getVarDims(varstring, udims, bdims); // figure out which data we need to request from data_mgr if (multiDom) { getCoordsFromIndex(dmin, bdims, domain); getDatasizeFromCoords(&ds, udims, bdims, dmin, dmax); } else { for (int i=0; i<3; i++) { dmin[i] = 0; dmax[i]=bdims[i]-1; ds.frontPad[i] = 0; ds.padded[i] = bmsize[i]*bdims[i]; ds.backPad[i] = ds.padded[i] - udims[i]; ds.real[i] = ds.padded[i] - ds.backPad[i]; } } // else // get pointer to actual data (may be padded), thow execption on error float *data_floats = data_mgr->GetRegion(timestate, varname_clean, refLevel[varstring], lod, dmin, dmax); if (data_floats == NULL) { EXCEPTION1(InvalidVariableException, "Data manager returned NULL pointer."); } // set up extents for return vector based on data type int which_dim; switch(varTypes[varstring]) { case 0: which_dim = -1; break; case 1: which_dim = 2; break; case 2: which_dim = 1; break; case 3: which_dim = 0; break; default: EXCEPTION1(InvalidVariableException, "Variable type undefined."); break; } if (which_dim != -1) { ds.frontPad[which_dim] = 0; ds.backPad[which_dim] = 0; ds.padded[which_dim] = 1; ds.real[which_dim] = 1; } // create return vector, filling with only valid data int idx = 0, numdata = ds.real[0] * ds.real[1] * ds.real[2]; vtkFloatArray *rv = vtkFloatArray::New(); rv->SetNumberOfValues(numdata); for (int z=ds.frontPad[2]; z< (ds.padded[2] - ds.backPad[2]); z++) { for (int y=ds.frontPad[1]; y< (ds.padded[1] - ds.backPad[1]); y++) { for (int x=ds.frontPad[0]; x< (ds.padded[0] - ds.backPad[0]); x++) { rv->SetValue(idx, data_floats[ z*ds.padded[1]*ds.padded[0] + y*ds.padded[0] + x ]); idx++; } } } delete varname_clean; return rv; } // **************************************************************************** // Method: avtvdfFileFormat::GetVectorVar // // Purpose: // Gets a vector variable associated with this file. Although VTK has // support for many different types, the best bet is vtkFloatArray, since // that is supported everywhere through VisIt. // // Arguments: // timestate The index of the timestate. If GetNTimesteps returned // 'N' time steps, this is guaranteed to be between 0 and N-1. // domain The index of the domain. If there are NDomains, this // value is guaranteed to be between 0 and NDomains-1, // regardless of block origin. // varname The name of the variable requested. // // Note: // although vapor data sets often contain vector data, there is no // standard representation. VisIt allows for the creation of vecotor // variables based on multiple scalar variables, so no 'vector type' // variables are reported to VisIt // // Programmer: dlagreca -- generated by xml2avt // Creation: Wed Feb 24 15:32:35 PST 2010 // // **************************************************************************** vtkDataArray * avtvdfFileFormat::GetVectorVar(int timestate, int domain,const char *varname) { return 0; } // **************************************************************************** // Method: avtvdfFileFormat::GetTimes // // Purpose: // Sets the time numbers to match the VDF user-time // // Arguments: // times double precision float vector to be filled with user time for // each valid timestep. // // Note: // I am unsure why, but reporting the vapor TSUserTime breaks streamlines // for WRF-based Vapor datasets. // // Programmer: dlagreca -- generated by xml2avt // Creation: Thu Feb 11 14:12:30 PST 2010 // // **************************************************************************** void avtvdfFileFormat::GetTimes(vector ×) { for (int i=0; iGetTSUserTime((size_t)tsteps[i])[0]); } // **************************************************************************** // Method: avtvdfFileFormat::GetCycles // // Purpose: // Sets the cycle numbers to match the timestate numbers for valid time- // states. This allows the correct 'timestep' to be shown even though // the invalid timesteps are not counted. // // Arguments: // cycles integer vector to be filled with correct cycle number for each // timestep // // Programmer: dlagreca -- generated by xml2avt // Creation: Thu Feb 11 14:12:30 PST 2010 // // **************************************************************************** void avtvdfFileFormat::GetCycles(vector &cycles) { for (int i=0; iGetBlockSize(); for (int i=0; i<3; i++) { dmax[i] = dmin[i]; if (dmin[i] == bdims[i]-1) { //last block int p = bdims[i]*bmsize[i] - udims[i]; if (dmin[i] > 0) { //other blocks before it dmin[i]--; datasize->padded[i] = bmsize[i]*2; datasize->frontPad[i] = bmsize[i]-1; datasize->backPad[i] = p; } else { //only one block in this dim datasize->padded[i] = bmsize[i]; datasize->frontPad[i] = 0; datasize->backPad[i] = p; } } else if (dmin[i] == 0) { dmax[i]++; datasize->padded[i] = bmsize[i]*2; datasize->frontPad[i] = 0; datasize->backPad[i] = bmsize[i]-1; } else { dmax[i]++; dmin[i]--; datasize->padded[i] = bmsize[i]*3; datasize->frontPad[i] = bmsize[i]-1; datasize->backPad[i] = bmsize[i]-1; } datasize->real[i] = datasize->padded[i] - datasize->backPad[i] - datasize->frontPad[i]; } } // ******************************************************** // Method: avtvdfFileFormat::cleanVarname // // Purpose: // Removes the leading characters that were added to the varname // to specifiy its correct mesh. Only the clean varname can be used to // interface with the data_mgr. // // Arguments: // varname: c-string variable name, contianing unwanted chars // // Returns: // pointer to new c-string. Be sure to call delete() when you're done // with it // // Programmer: dlagreca -- generated by xml2avt // Creation: Thu Feb 11 14:12:30 PST 2010 // // Modifications: // // ******************************************************** char* avtvdfFileFormat::cleanVarname(const char *varname) { // remove refinement tag from varname - find clean length int length = strlen(varname), start = length; while (varname[start--] != '/'); length = length-start-2; // copy applicaple part of varname to _clean char *varname_clean = new char[length]; for (int i=0; iGetDim(udims, level); vdfiobase->GetDimBlk(bdims, level); } // ******************************************************** // Method: avtvdfFileFormat::GetAuxiliaryData // // Purpose: // used by visit to access extents for each domain. This // allows visit to request only those data blocks that // are requred for rendering. // // Arguments: // var: variable for wich to return extent. // // Returns: // itree with spatial extents for each domain. // // Programmer: dlagreca -- generated by xml2avt // Creation: Thu Feb 11 14:12:30 PST 2010 // // Modifications: // // ******************************************************** void * avtvdfFileFormat::GetAuxiliaryData(const char *var, int timestate, int domain, const char *type, void *, DestructorFunction &df) { void *retval = 0; if(strcmp(type, AUXILIARY_DATA_SPATIAL_EXTENTS) == 0) { if (!multiDom) return retval; //printf("Returning spatial extents for %s @ %d in domain %d, ", var, timestate, domain); size_t dims[3], bdims[3], bcoords[3]; float delta[3]; const size_t *bsize = vdc_md->GetBlockSize(); const vector glExt = vdc_md->GetExtents(), tsExt = vdc_md->GetTSExtents((size_t)tsteps[timestate]), uExt = tsExt.empty()? glExt: tsExt; // Read the number of domains for the mesh. // Read the spatial extents for each domain of the // mesh. This information should be in a single // and should be available without having to // read the real data. The expected format for // the data in the spatialextents array is to // repeat the following pattern for each domain: // xmin, xmax, ymin, ymax, zmin, zmax. getVarDims(string(var), dims, bdims); int ndoms = multiDom? bdims[0]*bdims[1]*bdims[2]: 1; double *spatialextents = new double[ndoms * 6]; for (int i=0; i<3; i++) delta[i] = ((float)uExt[i+3] - (float)uExt[i])/(float)dims[i]; //READ ndoms*6 DOUBLE VALUES INTO spatialextents ARRAY. for (int curDom = 0; curDom < ndoms; curDom++) { getCoordsFromIndex(bcoords, bdims, curDom); //Spatial dims go from (block_start)*(voxels/block)*(units/voxel) // to (block_start + 1)*(voxels/block)*(units/voxel) for (int i=0; i<3; i++) { spatialextents[(6*curDom) + 2*i] = (float)(bcoords[i]*bsize[i])*delta[i]; spatialextents[(6*curDom) + 2*i+1] = (float)((bcoords[i]+1)*bsize[i])*delta[i]; } } // Create an interval tree avtIntervalTree *itree = new avtIntervalTree(ndoms, 3); double *extents = spatialextents; for(int dom = 0; dom < ndoms; ++dom) { itree->AddElement(dom, extents); extents += 6; } itree->Calculate(true); // Delete temporary array. delete [] spatialextents; // Set return values retval = (void *)itree; df = avtIntervalTree::Destruct; } return retval; } ================================================ FILE: plugins/visit/VDC/avtvdfFileFormat.h ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2009, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-400124 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ // ************************************************************************* // // avtvdfFileFormat.h // // ************************************************************************* // #ifndef AVT_vdf_FILE_FORMAT_H #define AVT_vdf_FILE_FORMAT_H #include #include #include #include #include #include "vapor/DataMgr.h" #include "vapor/VDFIOBase.h" #include "vapor/WaveletBlockIOBase.h" #include "vapor/WaveletBlock3DRegionReader.h" class DBOptionsAttributes; // **************************************************************************** // Class: avtvdfFileFormat // // Purpose: // Reads in vdf files as a plugin to VisIt. // // Programmer: dlagreca -- generated by xml2avt // Creation: Wed Feb 24 15:32:35 PST 2010 // // **************************************************************************** class avtvdfFileFormat : public avtMTMDFileFormat { public: avtvdfFileFormat(const char *, DBOptionsAttributes *); virtual ~avtvdfFileFormat(); // // This is used to return unconvention data -- ranging from material // information to information about block connectivity. // virtual void *GetAuxiliaryData(const char *var, int timestep, int domain, const char *type, void *args, DestructorFunction &); // // // If you know the times and cycle numbers, overload this function. // Otherwise, VisIt will make up some reasonable ones for you. // virtual void GetCycles(std::vector &); virtual void GetTimes(std::vector &); virtual int GetNTimesteps(void) { return ntsteps; }; virtual const char *GetType(void) { return "vdf"; }; virtual void FreeUpResources(void); virtual vtkDataSet * GetMesh(int, int, const char *); virtual vtkDataArray *GetVar(int, int, const char *); virtual vtkDataArray *GetVectorVar(int, int, const char *); protected: // structure used to pass info about ghost boundaries (padding) typedef struct datasize_t { size_t real[3]; // dimensions of actual voxel data size_t padded[3]; // dimensions of data with padding size_t frontPad[3]; // padding before real data size_t backPad[3]; // padding after real data }; bool isLayered, // weather or not the VDF contains layered a dataset multiDom; // weather or not we expose multiple domains to VisIt int num_levels, // max # of refinement levels ntsteps, // number of valid timesteps *tsteps, // map valid timestate (0-indexed) to dataset timestep levels3D, // Highest refinement level 3D mesh needed levelsXY, // Highest refinement level 2D XY mesh needed levelsXZ, // Highest refinement level 2D XZ mesh needed levelsYZ; // Highest refinement level 2D YZ mesh needed VAPoR::MetadataVDC * vdc_md; // determines type of datamanger is needed VAPoR::WaveletBlockIOBase *vdfiobase; // determines type of datamanger is needed VAPoR::DataMgr * data_mgr; // Pointer to subclass // relate var name to dimensional type (3D,XY,XZ,YZ) map varTypes; // relate var name to refinement level map refLevel; // Hold names of all vars in dataset, per type vector Names3D, xyNames, xzNames, yzNames, meshNames; virtual void PopulateDatabaseMetaData(avtDatabaseMetaData *, int); bool CanCacheVariable(const char *var) { return false; }; void getVoxelsInBlock(size_t *, size_t *, size_t *, size_t *); void getCoordsFromIndex(size_t *, size_t *, int); void getDatasizeFromCoords(datasize_t *, size_t *, size_t *, size_t *, size_t *); char * cleanVarname(const char *); void getVarDims(string, size_t *, size_t *); inline void getVarDims(int, size_t *, size_t *); }; #endif ================================================ FILE: plugins/visit/VDC/avtvdfOptions.C ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2009, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-400124 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ // ************************************************************************* // // avtvdfOptions.C // // ************************************************************************* // #include #include #include #include // **************************************************************************** // Function: GetvdfReadOptions // // Purpose: // Creates the options for vdf readers. // // Important Note: // The code below sets up empty options. If your format // does not require read options, no modifications are // necessary. // // Programmer: dlagreca -- generated by xml2avt // Creation: Wed Apr 7 14:43:06 PST 2010 // // **************************************************************************** DBOptionsAttributes * GetvdfReadOptions(void) { DBOptionsAttributes *rv = new DBOptionsAttributes; // The cache size parameter which will be passed the VDF Data Manager rv->SetInt("Cache size [MB]", 1000); // Resapmling factor for WRF (layered) data, which is passed to VDF Data Manager rv->SetDouble("Layered data resampling factor", 4.0); // Weather or not to report each VDC Block as it's own domain rv->SetBool("MultiDomain", false); return rv; /* EXAMPLE OF OPTIONS rv->SetBool("Binary format", true); rv->SetBool("Big Endian", false); rv->SetEnum("Dimension", 1); vector dims; dims.push_back("0D"); dims.push_back("1D"); dims.push_back("2D"); dims.push_back("3D"); rv->SetEnumStrings("Dimension", dims); rv->SetInt("Number of variables", 5); rv->SetString("Name of auxiliary file", ); rv->SetDouble("Displacement factor", 1.0); // When reading or writing the file, you can get the options out of this object like: rv->GetDouble("Displacement factor"); */ } // **************************************************************************** // Function: GetvdfWriteOptions // // Purpose: // Creates the options for vdf writers. // // Important Note: // The code below sets up empty options. If your format // does not require write options, no modifications are // necessary. // // Programmer: dlagreca -- generated by xml2avt // Creation: Wed Apr 7 14:43:06 PST 2010 // // **************************************************************************** DBOptionsAttributes * GetvdfWriteOptions(void) { DBOptionsAttributes *rv = new DBOptionsAttributes; return rv; } ================================================ FILE: plugins/visit/VDC/avtvdfOptions.h ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2009, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-400124 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ // ************************************************************************* // // avtvdfOptions.h // // ************************************************************************* // #ifndef AVT_vdf_OPTIONS_H #define AVT_vdf_OPTIONS_H class DBOptionsAttributes; #include // **************************************************************************** // Functions: avtvdfOptions // // Purpose: // Creates the options for vdf readers and/or writers. // // Programmer: dlagreca -- generated by xml2avt // Creation: Wed Apr 7 14:43:06 PST 2010 // // **************************************************************************** DBOptionsAttributes *GetvdfReadOptions(void); DBOptionsAttributes *GetvdfWriteOptions(void); #endif ================================================ FILE: plugins/visit/VDC/vdf.xml ================================================ -I/Applications/VAPOR.app/Contents/Frameworks/Headers -I/glade/proj3/DASG/VAPOR/third-party/apps-2.0.2/Darwin_x86_64/include -L/Applications/VAPOR.app/Contents/MacOS -L/glade/proj3/DASG/VAPOR/third-party/apps-2.0.2/Darwin_x86_64/lib vdf common netcdf expat *.vdf ================================================ FILE: plugins/visit/VDC/vdf2.xml ================================================ -I/Applications/VAPOR.app/Contents/Frameworks/Headers -I/glade/proj3/DASG/VAPOR/third-party/apps-2.0.2/Darwin_x86_64/include -I/Users/pearse/vapor30/include -I/opt/local/include -L/Applications/VAPOR.app/Contents/MacOS -L/glade/proj3/DASG/VAPOR/third-party/apps-2.0.2/Darwin_x86_64/lib -L/Users/pearse/vapor30/targets/Darwin_x86_64/bin -L/Applications/VAPOR/VAPOR.app/Contents/MacOS vdf common netcdf expat *.vdf ================================================ FILE: plugins/visit/VDC/vdfCommonPluginInfo.C ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2010, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-400124 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ #include #include #include #include #include // **************************************************************************** // Method: vdfCommonPluginInfo::GetDatabaseType // // Purpose: // Returns the type of a vdf database. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** DatabaseType vdfCommonPluginInfo::GetDatabaseType() { return DB_TYPE_MTMD; } // **************************************************************************** // Method: vdfCommonPluginInfo::SetupDatabase // // Purpose: // Sets up a vdf database. // // Arguments: // list A list of file names. // nList The number of timesteps in list. // nBlocks The number of blocks in the list. // // Returns: A vdf database from list. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** avtDatabase * vdfCommonPluginInfo::SetupDatabase(const char *const *list, int nList, int nBlock) { // ignore any nBlocks past 1 int nTimestepGroups = nList / nBlock; avtMTMDFileFormat **ffl = new avtMTMDFileFormat*[nTimestepGroups]; for (int i = 0 ; i < nTimestepGroups ; i++) { ffl[i] = new avtvdfFileFormat(list[i*nBlock], readOptions); } avtMTMDFileFormatInterface *inter = new avtMTMDFileFormatInterface(ffl, nTimestepGroups); return new avtGenericDatabase(inter); } // **************************************************************************** // Method: vdfCommonPluginInfo::GetReadOptions // // Purpose: // Gets the read options. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** DBOptionsAttributes * vdfCommonPluginInfo::GetReadOptions() const { return GetvdfReadOptions(); } // **************************************************************************** // Method: vdfCommonPluginInfo::GetWriteOptions // // Purpose: // Gets the write options. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** DBOptionsAttributes * vdfCommonPluginInfo::GetWriteOptions() const { return GetvdfWriteOptions(); } ================================================ FILE: plugins/visit/VDC/vdfEnginePluginInfo.C ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2010, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-400124 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ #include // **************************************************************************** // Function: GetEngineInfo // // Purpose: // Return a new EnginePluginInfo for the vdf database. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** extern "C" DBP_EXPORT EngineDatabasePluginInfo* vdf_GetEngineInfo() { return new vdfEnginePluginInfo; } // **************************************************************************** // Method: vdfEnginePluginInfo::GetWriter // // Purpose: // Sets up a vdf writer. // // Returns: A vdf writer. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** avtDatabaseWriter * vdfEnginePluginInfo::GetWriter(void) { return NULL; } ================================================ FILE: plugins/visit/VDC/vdfMDServerPluginInfo.C ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2010, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-400124 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ #include // **************************************************************************** // Function: GetMDServerInfo // // Purpose: // Return a new MDServerPluginInfo for the vdf database. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** extern "C" DBP_EXPORT MDServerDatabasePluginInfo* vdf_GetMDServerInfo() { return new vdfMDServerPluginInfo; } // this makes compilers happy... remove if we ever have functions here void vdfMDServerPluginInfo::dummy() { } ================================================ FILE: plugins/visit/VDC/vdfPluginInfo.C ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2010, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-400124 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ // ************************************************************************* // // File: vdfPluginInfo.C // ************************************************************************* // #include #include extern "C" DBP_EXPORT const char *vdfVisItPluginVersion = VISIT_VERSION; // **************************************************************************** // Function: GetGeneralInfo // // Purpose: // Return a new GeneralPluginInfo for the vdf database. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** extern "C" DBP_EXPORT GeneralDatabasePluginInfo* vdf_GetGeneralInfo() { return new vdfGeneralPluginInfo; } // **************************************************************************** // Method: vdfGeneralPluginInfo::GetName // // Purpose: // Return the name of the database plugin. // // Returns: A pointer to the name of the database plugin. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** const char * vdfGeneralPluginInfo::GetName() const { return "vdf"; } // **************************************************************************** // Method: vdfGeneralPluginInfo::GetVersion // // Purpose: // Return the version of the database plugin. // // Returns: A pointer to the version of the database plugin. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** const char * vdfGeneralPluginInfo::GetVersion() const { return "1.0"; } // **************************************************************************** // Method: vdfGeneralPluginInfo::GetID // // Purpose: // Return the id of the database plugin. // // Returns: A pointer to the id of the database plugin. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** const char * vdfGeneralPluginInfo::GetID() const { return "vdf_1.0"; } // **************************************************************************** // Method: vdfGeneralPluginInfo::EnabledByDefault // // Purpose: // Return true if this plugin should be enabled by default; false otherwise. // // Returns: true/false // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** bool vdfGeneralPluginInfo::EnabledByDefault() const { return true; } // **************************************************************************** // Method: vdfGeneralPluginInfo::HasWriter // // Purpose: // Return true if this plugin has a database writer. // // Returns: true/false // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** bool vdfGeneralPluginInfo::HasWriter() const { return false; } // **************************************************************************** // Method: vdfGeneralPluginInfo::GetDefaultFilePatterns // // Purpose: // Returns the default patterns for a vdf database. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** std::vector vdfGeneralPluginInfo::GetDefaultFilePatterns() const { std::vector defaultPatterns; defaultPatterns.push_back("*.vdf"); return defaultPatterns; } // **************************************************************************** // Method: vdfGeneralPluginInfo::AreDefaultFilePatternsStrict // // Purpose: // Returns if the file patterns for a vdf database are // intended to be interpreted strictly by default. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** bool vdfGeneralPluginInfo::AreDefaultFilePatternsStrict() const { return false; } // **************************************************************************** // Method: vdfGeneralPluginInfo::OpensWholeDirectory // // Purpose: // Returns if the vdf plugin opens a whole directory name // instead of a single file. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** bool vdfGeneralPluginInfo::OpensWholeDirectory() const { return false; } ================================================ FILE: plugins/visit/VDC/vdfPluginInfo.h ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2010, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-400124 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ // **************************************************************************** // vdfPluginInfo.h // **************************************************************************** #ifndef VDF_PLUGIN_INFO_H #define VDF_PLUGIN_INFO_H #include #include class avtDatabase; class avtDatabaseWriter; // **************************************************************************** // Class: vdfDatabasePluginInfo // // Purpose: // Classes that provide all the information about the vdf plugin. // Portions are separated into pieces relevant to the appropriate // components of VisIt. // // Programmer: generated by xml2info // Creation: omitted // // Modifications: // // **************************************************************************** class vdfGeneralPluginInfo : public virtual GeneralDatabasePluginInfo { public: virtual const char * GetName() const; virtual const char * GetVersion() const; virtual const char * GetID() const; virtual bool EnabledByDefault() const; virtual bool HasWriter() const; virtual std::vector GetDefaultFilePatterns() const; virtual bool AreDefaultFilePatternsStrict() const; virtual bool OpensWholeDirectory() const; }; class vdfCommonPluginInfo : public virtual CommonDatabasePluginInfo, public virtual vdfGeneralPluginInfo { public: virtual DatabaseType GetDatabaseType(); virtual avtDatabase * SetupDatabase(const char *const *list, int nList, int nBlock); virtual DBOptionsAttributes *GetReadOptions() const; virtual DBOptionsAttributes *GetWriteOptions() const; }; class vdfMDServerPluginInfo : public virtual MDServerDatabasePluginInfo, public virtual vdfCommonPluginInfo { public: // this makes compilers happy... remove if we ever have functions here virtual void dummy(); }; class vdfEnginePluginInfo : public virtual EngineDatabasePluginInfo, public virtual vdfCommonPluginInfo { public: virtual avtDatabaseWriter *GetWriter(void); }; #endif ================================================ FILE: plugins/visit/WASP/README ================================================ VisIt VDC Reader Plugin The contents of this directory provide a WASP import plugin for VisIt (https://wci.llnl.gov/codes/visit/home.html). =============== How To Build =============== Note: That you do not need to have built your own version of Visit or VAPoR, this will work with downloaded binary version. This code has been tested Mac and Linux platforms for VisIt 2.9.2 and VAPOR 3.0 ---------------------- 1) Install VisIt and VAPOR on your system. 2) Edit the WASP.xml file and make sure that the libray and include paths are correct for your installation of Vapor. This file is located in $VAPOR_HOME/plugins/visit/WASP. You will need to set the CXXFLAGS to include: WASP.h The LDFLAGS elements will need to point to the following vapor libs: common netcdf wasp You may also need to edit the LIBS element (for linux the 'rt' library is required). For more information see "Getting Data Into VisIT" available from: https://wci.llnl.gov/codes/visit/manuals.html 3) Navigate to $VAPOR_HOME/plugins/visit/WASP. Remove the file CMakeCache.txt if it exists. 4) Next to generate the CMakeLists.txt by running: xml2cmake -clobber WASP.xml This command is found in VISITARCHHOME/bin . 6) Use cmake to generate a Makefile, run: cmake . 7) Finally, build the binaries by running: make clean all This will build the 4 shared objects which make up the plugin (3 if MPI is not used). The plugin will be installed in the directory ~/.visit//plugins/database/ ============================== Platform Specific Notes ============================== Mac OS ------ Prior to executing visit the environment variable DYLD_FALLBACK_LIBRARY_PATH must be set to the path where VAPOR's libraries were installed. For a binary installation of VAPOR this will be /Applications/VAPOR.app/Contents/MacOS : setenv DYLD_FALLBACK_LIBRARY_PATH /Applications/VAPOR.app/Contents/MacOS Linux ----- On linux systems the library 'rt' must be added to the LIBS element of the WASP.xml configuration file. ================================================ FILE: plugins/visit/WASP/WASP.xml ================================================ -I/Users/pearse/vapor3/include -I/opt/local/include -L/Users/pearse/vapor3/targets/Darwin_x86_64/bin -L/Applications/VAPOR3/VAPOR.app/Contents/MacOS common netcdf wasp *.nc ================================================ FILE: plugins/visit/WASP/WASPCommonPluginInfo.C ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-442911 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ #include #include #include #include // **************************************************************************** // Method: WASPCommonPluginInfo::GetDatabaseType // // Purpose: // Returns the type of a WASP database. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** DatabaseType WASPCommonPluginInfo::GetDatabaseType() { return DB_TYPE_MTMD; } // **************************************************************************** // Method: WASPCommonPluginInfo::SetupDatabase // // Purpose: // Sets up a WASP database. // // Arguments: // list A list of file names. // nList The number of timesteps in list. // nBlocks The number of blocks in the list. // // Returns: A WASP database from list. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** avtDatabase * WASPCommonPluginInfo::SetupDatabase(const char *const *list, int nList, int nBlock) { // ignore any nBlocks past 1 int nTimestepGroups = nList / nBlock; avtMTMDFileFormat **ffl = new avtMTMDFileFormat*[nTimestepGroups]; for (int i = 0 ; i < nTimestepGroups ; i++) { ffl[i] = new avtWASPFileFormat(list[i*nBlock]); } avtMTMDFileFormatInterface *inter = new avtMTMDFileFormatInterface(ffl, nTimestepGroups); return new avtGenericDatabase(inter); } // **************************************************************************** // Method: WASPCommonPluginInfo::GetLicense // // Purpose: // Gets the write options. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** std::string WASPCommonPluginInfo::GetLicense() const { return std::string(); } ================================================ FILE: plugins/visit/WASP/WASPEnginePluginInfo.C ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-442911 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ #include // **************************************************************************** // Function: GetEngineInfo // // Purpose: // Return a new EnginePluginInfo for the WASP database. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** extern "C" DBP_EXPORT EngineDatabasePluginInfo* WASP_GetEngineInfo() { return new WASPEnginePluginInfo; } // **************************************************************************** // Method: WASPEnginePluginInfo::GetWriter // // Purpose: // Sets up a WASP writer. // // Returns: A WASP writer. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** avtDatabaseWriter * WASPEnginePluginInfo::GetWriter(void) { return NULL; } ================================================ FILE: plugins/visit/WASP/WASPMDServerPluginInfo.C ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-442911 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ #include // **************************************************************************** // Function: GetMDServerInfo // // Purpose: // Return a new MDServerPluginInfo for the WASP database. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** extern "C" DBP_EXPORT MDServerDatabasePluginInfo* WASP_GetMDServerInfo() { return new WASPMDServerPluginInfo; } // this makes compilers happy... remove if we ever have functions here void WASPMDServerPluginInfo::dummy() { } ================================================ FILE: plugins/visit/WASP/WASPPluginInfo.C ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-442911 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ // ************************************************************************* // // File: WASPPluginInfo.C // ************************************************************************* // #include #include VISIT_PLUGIN_VERSION(WASP,DBP_EXPORT) // **************************************************************************** // Function: GetGeneralInfo // // Purpose: // Return a new GeneralPluginInfo for the WASP database. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** extern "C" DBP_EXPORT GeneralDatabasePluginInfo* WASP_GetGeneralInfo() { return new WASPGeneralPluginInfo; } // **************************************************************************** // Method: WASPGeneralPluginInfo::GetName // // Purpose: // Return the name of the database plugin. // // Returns: A pointer to the name of the database plugin. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** const char * WASPGeneralPluginInfo::GetName() const { return "WASP"; } // **************************************************************************** // Method: WASPGeneralPluginInfo::GetVersion // // Purpose: // Return the version of the database plugin. // // Returns: A pointer to the version of the database plugin. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** const char * WASPGeneralPluginInfo::GetVersion() const { return "1.0"; } // **************************************************************************** // Method: WASPGeneralPluginInfo::GetID // // Purpose: // Return the id of the database plugin. // // Returns: A pointer to the id of the database plugin. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** const char * WASPGeneralPluginInfo::GetID() const { return "WASP_1.0"; } // **************************************************************************** // Method: WASPGeneralPluginInfo::EnabledByDefault // // Purpose: // Return true if this plugin should be enabled by default; false otherwise. // // Returns: true/false // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** bool WASPGeneralPluginInfo::EnabledByDefault() const { return true; } // **************************************************************************** // Method: WASPGeneralPluginInfo::HasWriter // // Purpose: // Return true if this plugin has a database writer. // // Returns: true/false // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** bool WASPGeneralPluginInfo::HasWriter() const { return false; } // **************************************************************************** // Method: WASPGeneralPluginInfo::GetDefaultFilePatterns // // Purpose: // Returns the default patterns for a WASP database. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** std::vector WASPGeneralPluginInfo::GetDefaultFilePatterns() const { std::vector defaultPatterns; defaultPatterns.push_back("*.nc"); return defaultPatterns; } // **************************************************************************** // Method: WASPGeneralPluginInfo::AreDefaultFilePatternsStrict // // Purpose: // Returns if the file patterns for a WASP database are // intended to be interpreted strictly by default. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** bool WASPGeneralPluginInfo::AreDefaultFilePatternsStrict() const { return false; } // **************************************************************************** // Method: WASPGeneralPluginInfo::OpensWholeDirectory // // Purpose: // Returns if the WASP plugin opens a whole directory name // instead of a single file. // // Programmer: generated by xml2info // Creation: omitted // // **************************************************************************** bool WASPGeneralPluginInfo::OpensWholeDirectory() const { return false; } ================================================ FILE: plugins/visit/WASP/WASPPluginInfo.h ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-442911 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ // **************************************************************************** // WASPPluginInfo.h // **************************************************************************** #ifndef WASP_PLUGIN_INFO_H #define WASP_PLUGIN_INFO_H #include #include class avtDatabase; class avtDatabaseWriter; // **************************************************************************** // Class: WASPDatabasePluginInfo // // Purpose: // Classes that provide all the information about the WASP plugin. // Portions are separated into pieces relevant to the appropriate // components of VisIt. // // Programmer: generated by xml2info // Creation: omitted // // Modifications: // // **************************************************************************** class WASPGeneralPluginInfo : public virtual GeneralDatabasePluginInfo { public: virtual const char * GetName() const; virtual const char * GetVersion() const; virtual const char * GetID() const; virtual bool EnabledByDefault() const; virtual bool HasWriter() const; virtual std::vector GetDefaultFilePatterns() const; virtual bool AreDefaultFilePatternsStrict() const; virtual bool OpensWholeDirectory() const; }; class WASPCommonPluginInfo : public virtual CommonDatabasePluginInfo, public virtual WASPGeneralPluginInfo { public: virtual DatabaseType GetDatabaseType(); virtual avtDatabase *SetupDatabase(const char *const *list, int nList, int nBlock); virtual std::string GetLicense() const; }; class WASPMDServerPluginInfo : public virtual MDServerDatabasePluginInfo, public virtual WASPCommonPluginInfo { public: // this makes compilers happy... remove if we ever have functions here virtual void dummy(); }; class WASPEnginePluginInfo : public virtual EngineDatabasePluginInfo, public virtual WASPCommonPluginInfo { public: virtual avtDatabaseWriter *GetWriter(void); }; #endif ================================================ FILE: plugins/visit/WASP/avtWASPFileFormat.C ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-442911 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ // ************************************************************************* // // avtWASPFileFormat.C // // ************************************************************************* // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include bool useBlocks=1; template string ToString(T val) { stringstream stream; stream << val; return stream.str(); } std::vector &split(const std::string &s, char delim, std::vector &elems) { std::stringstream ss(s); std::string item; while (std::getline(ss, item, delim)) { elems.push_back(item); } return elems; } // **************************************************************************** // Method: avtWASPFileFormat constructor // // Programmer: pearse -- generated by xml2avt // Creation: Wed Jan 20 15:04:04 PST 2016 // // **************************************************************************** avtWASPFileFormat::avtWASPFileFormat(const char *filename) : avtMTMDFileFormat(filename){ initialized = false; inFile = filename; wasp = new VAPoR::WASP(1); } avtWASPFileFormat::~avtWASPFileFormat(){ if (wasp) delete wasp; } void avtWASPFileFormat::ActivateTimestep() { Initialize(); } void avtWASPFileFormat::Initialize() { size_t nlevels, maxcratio; vector dims,bs; if(!initialized){ bool okay = false; std::vector allVars; wasp->Open(inFile,0); wasp->InqVarnames(allVars); std::vector::iterator it; for (it=allVars.begin(); it != allVars.end(); ++it){ wasp->InqVarWASP(*it,okay); if (okay){ wasp->InqVarDimlens(*it,0,dims,bs); if (dims.size() > 2) { varNames.push_back(*it); debug1 << "WASP says " << *it << " is ok!" << endl; } else { debug1 << "Ommitting 2D variable " << *it << endl; } } else debug1 << "WASP says " << *it << " is NOT ok!" << endl; } initialized = true; } else { debug1 << "We've already initialized" << endl; } } // **************************************************************************** // Method: avtEMSTDFileFormat::GetNTimesteps // // Purpose: // Tells the rest of the code how many timesteps there are in this file. // // Programmer: pearse -- generated by xml2avt // Creation: Wed Jan 20 15:04:04 PST 2016 // // **************************************************************************** int avtWASPFileFormat::GetNTimesteps(void) { // We are only supporting one timestep at a time return 1; } // **************************************************************************** // Method: avtWASPFileFormat::FreeUpResources // // Purpose: // When VisIt is done focusing on a particular timestep, it asks that // timestep to free up any resources (memory, file descriptors) that // it has associated with it. This method is the mechanism for doing // that. // // Programmer: pearse -- generated by xml2avt // Creation: Wed Jan 20 15:04:04 PST 2016 // // **************************************************************************** void avtWASPFileFormat::FreeUpResources(void) { } // **************************************************************************** // Method: avtWASPFileFormat::PopulateDatabaseMetaData // // Purpose: // This database meta-data object is like a table of contents for the // file. By populating it, you are telling the rest of VisIt what // information it can request from you. // // Programmer: pearse -- generated by xml2avt // Creation: Wed Jan 20 15:04:04 PST 2016 // // **************************************************************************** void avtWASPFileFormat::PopulateDatabaseMetaData(avtDatabaseMetaData *md, int timeState) { Initialize(); string wname; int refLevels; string varName; vector dims, bs; std::vector::iterator it; int blockedDims[3]; // Iterate over each variable for (it=varNames.begin(); it != varNames.end(); ++it){ varName = *it; int rc = wasp->OpenVarRead(varName,0,3); if (rc!=0) { debug1 << "Unable to open variable " << varName << endl; debug1 << "rc: " << rc << endl; } // Iterate over each refinement level and lod refLevels = wasp->InqVarNumRefLevels(varName); for (int i=0; iInqVarDimlens(varName,i,dims,bs); if (bs.empty()){ bs = dims; } // Swap Z and X dimension axes int tmp = bs[0]; bs[0] = bs[2]; bs[2] = tmp; tmp = dims[0]; dims[0] = dims[2]; dims[2] = tmp; if (rc) EXCEPTION1(InvalidDBTypeException,"The WASP file's dimensionality could not be read."); // Calculate number of blocks on each axis for (int j=0; j<3; j++){ blockedDims[j] = dims[j]/bs[j]; if (dims[j]%bs[j] > 0) blockedDims[j]+=1; } // Aggregate remaining metadata avtMeshType meshType = AVT_RECTILINEAR_MESH; int numBlocks = 1; if (useBlocks) numBlocks = blockedDims[0] * blockedDims[1] * blockedDims[2]; int blockOrigin = 0; int spatialDimension = dims.size(); int topologicalDimension = 3; double *extents = NULL; string meshName = varName + "-mesh-" + ToString(i); AddMeshToMetaData(md, meshName, meshType, extents, numBlocks, blockOrigin, spatialDimension, topologicalDimension); vector cratios; wasp->InqVarCompressionParams(*it,wname,bs,cratios); string visitVarName; for (size_t j=0; j components; split(meshName2, '-', components); string varName = components[0]; int level = atoi(components[2].c_str()); int rc = wasp->OpenVarRead(varName,level,1); if (rc!=0) { debug1 << "Unable to open variable " << varName << endl; debug1 << "rc: " << rc << endl; } vector dims, bs; wasp->InqVarDimlens(varName,level,dims,bs); if (bs.empty()){ bs = dims; } // Swap Z and X dimension axes int tmp = bs[0]; bs[0] = bs[2]; bs[2] = tmp; tmp = dims[0]; dims[0] = dims[2]; dims[2] = tmp; vtkFloatArray *coords[3] = {0,0,0}; int blockedDims[3], meshDims[3]; if (useBlocks) { for (int i=0; i<3; i++) meshDims[i] = bs[i]+1; } else { for (int i=0; i<3; i++) meshDims[i] = dims[i]+1; } int xStart=0, yStart=0, zStart=0; int xEnd=dims[0]+1; int yEnd=dims[1]+1; int zEnd=dims[2]+1; if (useBlocks){ for (int j=0; j<3; j++){ blockedDims[j] = dims[j]/bs[j]; if (dims[j]%bs[j] > 0) blockedDims[j] = blockedDims[j]+1; } int xBlock = domain % blockedDims[0]; int yBlock = (domain%(blockedDims[0]*blockedDims[1]))/blockedDims[0]; int zBlock = domain/(blockedDims[0]*blockedDims[1]); xStart = bs[0]*xBlock; yStart = bs[1]*yBlock; zStart = bs[2]*zBlock; xEnd = bs[0]*(xBlock+1); yEnd = bs[1]*(yBlock+1); zEnd = bs[2]*(zBlock+1); // If we are looking at the last block on either the x, y, or z axis, // we may need to trim the end point if the domain is not a multiple // of our block size (in other words, or blocks overshoot our domain) if ((xBlock == blockedDims[0]-1)&&(dims[0]%bs[0]!=0)){ xEnd -= bs[0] - dims[0]%bs[0]; meshDims[0] -= bs[0] - dims[0]%bs[0]; } if ((yBlock == blockedDims[1]-1)&&(dims[1]%bs[1]!=0)){ yEnd -= bs[1] - dims[1]%bs[1]; meshDims[1] -= bs[1] - dims[1]%bs[1]; } if ((zBlock == blockedDims[2]-1)&&(dims[2]%bs[2]!=0)){ zEnd -= bs[2] - dims[2]%bs[2]; meshDims[2] -= bs[2] - dims[2]%bs[2]; } } int xCount = xEnd-xStart+1; int yCount = yEnd-yStart+1; int zCount = zEnd-zStart+1; // Read the X coordinates from the file. coords[0] = vtkFloatArray::New(); coords[0]->SetNumberOfTuples(xCount); float *xarray = (float *)coords[0]->GetVoidPointer(0); for (int i=0; iSetNumberOfTuples(yCount); float *yarray = (float *)coords[1]->GetVoidPointer(0); for (int i=0; i 2) { coords[2]->SetNumberOfTuples(zCount); float *zarray = (float *)coords[2]->GetVoidPointer(0); for (int i=0; iSetNumberOfTuples(1); coords[2]->SetComponent(0, 0, 0.); } // Create the vtkRectilinearGrid object and set its dimensions // and coordinates. vtkRectilinearGrid *rgrid = vtkRectilinearGrid::New(); rgrid->SetDimensions(meshDims); rgrid->SetXCoordinates(coords[0]); coords[0]->Delete(); rgrid->SetYCoordinates(coords[1]); coords[1]->Delete(); rgrid->SetZCoordinates(coords[2]); coords[2]->Delete(); return rgrid; } // **************************************************************************** // Method: avtWASPFileFormat::GetVar // // Purpose: // Gets a scalar variable associated with this file. Although VTK has // support for many different types, the best bet is vtkFloatArray, since // that is supported everywhere through VisIt. // // Arguments: // timestate The index of the timestate. If GetNTimesteps returned // 'N' time steps, this is guaranteed to be between 0 and N-1. // domain The index of the domain. If there are NDomains, this // value is guaranteed to be between 0 and NDomains-1, // regardless of block origin. // varname The name of the variable requested. // // Programmer: pearse -- generated by xml2avt // Creation: Wed Jan 20 15:04:04 PST 2016 // // **************************************************************************** vtkDataArray * avtWASPFileFormat::GetVar(int timestate, int domain, const char *varname) { // Split varname to get level and lod info string inName = varname; vector components; split(inName, '/', components); string varName = components[0]; string tmpLevel = components[1].erase(0,3); string tmpLod = components[2].erase(0,3); int level = atoi(tmpLevel.c_str()); int lod = atoi(tmpLod.c_str()); size_t blockedDims[3]; // Find the index of our compression ratio std::string temp; vector cratios, temp2; wasp->InqVarCompressionParams(varName,temp,temp2,cratios); for (int i=0; iOpenVarRead(varName,level,lod); if (rc!=0) { debug1 << "Unable to open variable " << varName << endl; debug1 << "rc: " << rc << endl; } vector dims, vaporDims, bs, start, count; rc = wasp->InqVarDimlens(varName,level,vaporDims,bs); if (bs.empty()){ bs = dims; } int tmp = bs[0]; bs[0] = bs[2]; bs[2] = tmp; dims.push_back(vaporDims[2]); dims.push_back(vaporDims[1]); dims.push_back(vaporDims[0]); if (rc!=0) { debug1 << "Unable to inquire variable " << varName << endl; debug1 << "rc: " << rc << endl; } float* data; int xBlock, yBlock, zBlock; int numVaporDataPoints = 1; int numVisitDataPoints = 1; count = bs; // Number of elements in current block if (useBlocks) { // blockedDims is xyz indexed for (int j=0; j<3; j++){ blockedDims[j] = dims[j]/bs[j]; if (dims[j]%bs[j] > 0) blockedDims[j] = blockedDims[j]+1; } int xySize = blockedDims[0] * blockedDims[1]; xBlock = domain % blockedDims[0]; yBlock = (domain % xySize) / blockedDims[0]; zBlock = domain / xySize; start.push_back(bs[2]*zBlock); start.push_back(bs[1]*yBlock); start.push_back(bs[0]*xBlock); // If we are looking at the last block on either the x, y, or z axis, // we may need to trim the end point if the domain is not a multiple // of our block size (in other words, or blocks overshoot our domain) if ((xBlock == blockedDims[0]-1)&&(dims[0]%bs[0]!=0)){ count[0] -= count[0]-dims[0]%count[0]; } if ((yBlock == blockedDims[1]-1)&&(dims[1]%bs[1]!=0)){ count[1] -= count[1]-dims[1]%count[1]; } if ((zBlock == blockedDims[2]-1)&&(dims[2]%bs[2]!=0)){ count[2] -= count[2]-dims[2]%count[2]; } for (int i=0; i vaporCount; vaporCount.push_back(count[2]); vaporCount.push_back(count[1]); vaporCount.push_back(count[0]); if (useBlocks) rc = wasp->GetVara(start,vaporCount,data); else rc = wasp->GetVara(start,vaporDims,data); // Populate visit data array vtkFloatArray *rv = vtkFloatArray::New(); rv->SetNumberOfTuples(numVisitDataPoints); int visitIndex, vaporIndex, x, y, z; for (int i = 0 ; i < numVisitDataPoints ; i++){ rv->SetTuple1(i,data[i]); } if (data) delete [] data; return rv; } void* avtWASPFileFormat::GetAuxiliaryData(const char *var, int timestep, int domain, const char *type, void *, DestructorFunction &df) { void *retval = 0; if(strcmp(type, AUXILIARY_DATA_SPATIAL_EXTENTS) == 0) { vector dims,bs; string inName = var; vector components; split(inName, '-', components); string varName = components[0]; int level = atoi(components[2].c_str()); wasp->InqVarDimlens(varName,level,dims,bs); if (bs.empty() || !useBlocks){ bs = dims; } int tmp = bs[0]; bs[0] = bs[2]; bs[2] = tmp; tmp = dims[0]; dims[0] = dims[2]; dims[2] = tmp; int ndoms = 1; vector blockedDims; blockedDims.push_back(1); blockedDims.push_back(1); blockedDims.push_back(1); if (useBlocks){ for (int j=0; j<3; j++){ blockedDims[j]= dims[j]/bs[j]; if (dims[j]%bs[j] > 0) blockedDims[j] +=1; } ndoms = blockedDims[0] * blockedDims[1] * blockedDims[2]; } // Read the spatial extents for each domain of the // mesh. This information should be in a single // and should be available without having to // read the real data. The expected format for // the data in the spatialextents array is to // repeat the following pattern for each domain: // xmin, xmax, ymin, ymax, zmin, zmax. double *spatialextents = new double[ndoms * 6]; int xMin, xMax, yMin, yMax, zMin, zMax; // Create an interval tree avtIntervalTree *itree = new avtIntervalTree(ndoms, 3); double extents[6]; for(int dom = 0; dom < ndoms; dom++) { int xBlock, yBlock, zBlock; xBlock = dom % blockedDims[0]; yBlock = (dom % (blockedDims[0]*blockedDims[1])) / blockedDims[0]; zBlock = dom / (blockedDims[0]*blockedDims[1]); xMin = xBlock*bs[0]; yMin = yBlock*bs[1]; zMin = zBlock*bs[2]; xMax = (xBlock+1)*bs[0]; yMax = (yBlock+1)*bs[1]; zMax = (zBlock+1)*bs[2]; // If we are looking at the last block on either the x, y, or z axis, // we may need to trim the end point if the domain is not a multiple // of our block size (in other words, or blocks overshoot our domain) if ((xBlock == blockedDims[0]-1) && (dims[0]%bs[0]!=0)) xMax -= bs[0] - dims[0]%bs[0]; if ((yBlock == blockedDims[1]-1) && (dims[1]%bs[1]!=0)) yMax -= bs[1] - dims[1]%bs[1]; if ((zBlock == blockedDims[2]-1) && (dims[2]%bs[2]!=0)) zMax -= bs[2] - dims[2]%bs[2]; extents[0] = xMin/(float)dims[0]; extents[1] = xMax/(float)dims[0]; extents[2] = yMin/(float)dims[1]; extents[3] = yMax/(float)dims[1]; extents[4] = zMin/(float)dims[2]; extents[5] = zMax/(float)dims[2]; itree->AddElement(dom, extents); } itree->Calculate(true); // Delete temporary array. if (spatialextents) delete [] spatialextents; // Set return values retval = (void *)itree; df = avtIntervalTree::Destruct; } return retval; } ================================================ FILE: plugins/visit/WASP/avtWASPFileFormat.h ================================================ /***************************************************************************** * * Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC * Produced at the Lawrence Livermore National Laboratory * LLNL-CODE-442911 * All rights reserved. * * This file is part of VisIt. For details, see https://visit.llnl.gov/. The * full copyright notice is contained in the file COPYRIGHT located at the root * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the disclaimer (as noted below) in the * documentation and/or other materials provided with the distribution. * - Neither the name of the LLNS/LLNL nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, * LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * *****************************************************************************/ // ************************************************************************* // // avtWASPFileFormat.h // // ************************************************************************* // #ifndef AVT_WASP_FILE_FORMAT_H #define AVT_WASP_FILE_FORMAT_H #include #include #include // **************************************************************************** // Class: avtWASPFileFormat // // Purpose: // Reads in WASP files as a plugin to VisIt. // // Programmer: pearse -- generated by xml2avt // Creation: Fri Jan 22 12:20:20 PDT 2016 // // **************************************************************************** class avtWASPFileFormat : public avtMTMDFileFormat { public: avtWASPFileFormat(const char *); virtual ~avtWASPFileFormat(); // // This is used to return unconvention data -- ranging from material // information to information about block connectivity. // virtual void *GetAuxiliaryData(const char *var, int timestep, int domain, const char *type, void *args, DestructorFunction &); // // // If you know the times and cycle numbers, overload this function. // Otherwise, VisIt will make up some reasonable ones for you. // // virtual void GetCycles(std::vector &); // virtual void GetTimes(std::vector &); // virtual int GetNTimesteps(void); virtual const char *GetType(void) { return "WASP"; }; virtual void FreeUpResources(void); virtual vtkDataSet * GetMesh(int, int, const char *); virtual vtkDataArray *GetVar(int, int, const char *); // virtual void* GetAuxiliaryData(const char* var, int ts, const char* type, // void* args, DestructorFunction &); void ActivateTimestep(); void Initialize(); protected: VAPoR::WASP * wasp; const char * inFile; std::vector varNames; std::vector meshNames; size_t nlevels, maxcratio; // DATA MEMBERS bool initialized; virtual void PopulateDatabaseMetaData(avtDatabaseMetaData *, int); }; #endif ================================================ FILE: scripts/CMakeLists.txt ================================================ if (BUILD_VDC) install ( FILES vdccp DESTINATION ${INSTALL_BIN_DIR} COMPONENT Utilites ) endif () ================================================ FILE: scripts/build3rdParty.sh ================================================ #!/bin/bash # To install: Uncomment 'prerequisites' and the library name you'd like, # listed at the bottom of this file. Then run build.sh. # # To uninstall: Re-install your target library, then run the following # command from the build directory. # # xargs rm < install_manifest.txt set -xe while getopts "o:b:" flag; do case "${flag}" in o) OS=${OPTARG};; b) baseDir=${OPTARG};; esac done if [ -z "$OS" ]; then echo "Error: -o flag is required to specify the target operating system [macOSx86, appleSilicon, Ubuntu]" exit 1 elif [ -z "$baseDir" ]; then echo "No -b (base directory) option given. Defaulting to /usr/local/VAPOR-Deps" baseDir='/usr/local/VAPOR-Deps' fi #baseDir='/glade/campaign/cisl/vast/vapor/third-party' srcDir="$baseDir/2024-Sept-src" archiveName="2025-July-${OS}" installDir="$baseDir/current" echo OS ${OS} echo baseDir $baseDir echo srcDir $srcDir echo installDir $installDir macOSMinVersion="" shopt -s expand_aliases alias make='make -j8' alias configure='./configure' alias config='./config' if [[ "$OS" == "macOSx86" ]]; then alias configure='./configure --host=x86_64-apple-darwin' alias config='./config darwin64-x86_64-cc' alias brew='arch -x86_64 /usr/local/bin/brew' export PATH="/usr/local/bin:$PATH" macOSMinVersion="10.15.0" echo "Homebrew alias:" alias brew echo "PATH ${PATH}" elif [[ "$OS" == "appleSilicon" ]]; then macOSMinVersion="12.0.0" alias brew='/opt/homebrew/bin/brew' export PATH="/opt/homebrew/bin:$PATH" echo "Homebrew alias:" alias brew echo "PATH ${PATH}" fi macOSx86Prerequisites() { brew uninstall python@3.9 || true export CMAKE_OSX_ARCHITECTURES=x86_64 export CFLAGS="-arch x86_64" export LDFLAGS="-arch x86_64" macOSPrerequisites } macOSPrerequisites() { export MACOSX_DEPLOYMENT_TARGET=$macOSMinVersion export SDKROOT=$(xcrun --sdk macosx --show-sdk-path) export CC="/opt/local/bin/clang" export CXX="/opt/local/bin/clang++" export CFLAGS="$CFLAGS -isysroot $(xcrun --sdk macosx --show-sdk-path)" export LDFLAGS="$LDFLAGS -isysroot $(xcrun --sdk macosx --show-sdk-path)" export CXXFLAGS="$CFLAGS" export CPPFLAGS="$CFLAGS" brew doctor brew cleanup brew install cmake autoconf atool libtool automake brew install libxml2 xz brew install pkg-config gdbm tcl-tk brew install gettext brew uninstall --ignore-dependencies gettext #port install clang-17 +universal #sudo port select --set clang mp-clang-17 #xcode-select --install } ubuntuPrerequisites() { CC='gcc' CXX='g++' apt update -y apt upgrade -y # all for cmake apt-get update apt-get install -y gpg wget wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null DEBIAN_FRONTEND=noninteractive apt install -y software-properties-common apt-add-repository -y 'deb https://apt.kitware.com/ubuntu/ focal main' apt install -y cmake --allow-unauthenticated apt install -y \ build-essential \ libgl1-mesa-dev \ qtbase5-dev \ libicu-dev \ m4 \ libcurl4-openssl-dev \ libxau-dev \ autoconf \ libtool \ libxcb-xinerama0 \ libxcb-xinerama0-dev \ pkg-config \ unzip \ libssl-dev \ libffi-dev # Qt apt-get install -y \ '^libxcb.*-dev' \ libx11-xcb-dev \ freeglut3-dev \ libglu1-mesa-dev \ libxrender-dev \ libxi-dev \ libxkbcommon-dev \ libxkbcommon-x11-dev } windowsPrerequisites() { CC='i686-w64-mingw-gcc' CXX='i686-w64-mingw-g++' apt update -y apt upgrade -y # all for cmake apt-get update apt-get install -y gpg wget wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null DEBIAN_FRONTEND=noninteractive apt install -y software-properties-common apt-add-repository 'deb https://apt.kitware.com/ubuntu/ focal main' apt install -y cmake --allow-unauthenticated apt install mingw-64 #choco install visualstudio2019-workload-vctools python cmake -y #setx /M PATH "%PATH%;C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin" #python -m pip install gdown } libpng() { cd $srcDir local library='libpng-1.6.39' rm -rf $library || true tar xvf $srcDir/$library.tar.xz mkdir -p $srcDir/$library/build && cd $srcDir/$library/build args=( -DCMAKE_INSTALL_PREFIX=$installDir -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_LIBDIR=lib ) if [ "$OS" == "macOSx86" ] || [ "$OS" = "appleSilicon" ]; then args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion) fi if [ "$OS" == "macOSx86" ]; then args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64) fi cmake "${args[@]}" .. make && make install } assimp() { cd $srcDir local library='assimp-5.2.5' #requires c++17 compiler rm -rf $library || true tar xvf $srcDir/$library.tar.gz mkdir -p $srcDir/$library/build && cd $srcDir/$library/build args=( -DCMAKE_INSTALL_PREFIX=$installDir -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_CXX_FLAGS="-O3 -Wno-error=deprecated-declarations" -DASSIMP_BUILD_TESTS=OFF ) if [ "$OS" == "macOSx86" ] || [ "$OS" = "appleSilicon" ]; then args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion) fi if [ "$OS" == "macOSx86" ]; then args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64) fi cmake "${args[@]}" .. make && make install } zlib() { cd $srcDir local library='zlib-1.2.13' rm -rf $library || true tar xvf $srcDir/$library.tar.gz mkdir -p $srcDir/$library/build && cd $srcDir/$library/build args=( -DCMAKE_INSTALL_PREFIX=$installDir -DCMAKE_BUILD_TYPE=Release ) if [ "$OS" == "macOSx86" ] || [ "$OS" = "appleSilicon" ]; then args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion) fi if [ "$OS" == "macOSx86" ]; then args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64) fi cmake "${args[@]}" .. make && make install } #Note: After configuration, we need to make sure both zlib and szlib are enabled. szip() { cd $srcDir local library='szip-2.1.1' rm -rf $library || true tar xvf $srcDir/$library.tar.gz cd $srcDir/$library args=( --prefix=$installDir ) ./configure "${args[@]}" make && make install } #hdfVersion='1.14.0' #hdfVersion='1.13.3' hdfVersion='1.12.2' hdf5() { cd $srcDir if [ "$OS" == "macOSx86" ]; then tar xvf hdf5/hdf5-$hdfVersion-Std-macos11_64-clang.tar.gz && cd hdf ./HDF5-$hdfVersion-Darwin.sh --prefix=$installDir --exclude-subdir --skip-license elif [ "$OS" == "appleSilicon" ]; then tar xvf hdf5/hdf5-$hdfVersion-Std-macos11m1_64-clang.tar.gz && cd hdf ./HDF5-$hdfVersion-Darwin.sh --prefix=$installDir --exclude-subdir --skip-license else tar xvf hdf5/hdf5-$hdfVersion-Std-centos7_64-7.2.0.tar.gz && cd hdf ./HDF5-$hdfVersion-Linux.sh --prefix=$installDir --exclude-subdir --skip-license fi ln -fs $installDir/HDF_Group/HDF5/$hdfVersion/lib/plugin/ $installDir/share/plugins } hdf5src() { cd $srcDir local library="hdf5-${hdfVersion}" rm -rf $library || true tar xvf $srcDir/$library.tar.gz mkdir -p $srcDir/$library/build && cd $srcDir/$library/build export CMAKE_INCLUDE_PATH=/path/to/libsz/include export CMAKE_LIBRARY_PATH=/path/to/libsz/lib args=( -DCMAKE_INSTALL_PREFIX=$installDir -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_RPATH=$installDir -DCMAKE_PREFIX_PATH=$installDir -DZLIB_DIR=$installDir -DUSE_SHARED_LIBS:BOOL=ON -DBUILD_SHARED_LIBS:BOOL=ON -DHDF5_ENABLE_RPATH:BOOL=ON -DHDF5_BUILD_WITH_INSTALL_NAME:BOOL=ON -DHDF5_ENABLE_THREADSAFE:BOOL=ON -DHDF5_ENABLE_SZIP_SUPPORT:BOOL=ON -DHDF5_ENABLE_Z_LIB_SUPPORT:BOOL=ON -DHDF5_BUILD_HL_LIB:BOOL=ON -DHDF5_BUILD_TOOLS:BOOL=ON -DALLOW_UNSUPPORTED:BOOL=ON ) if [ "$OS" == "macOSx86" ]; then args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64) fi cmake "${args[@]}" .. make make install } zstd() { cd $srcDir local library='zstd-1.5.6' rm -rf $library || true tar xvf $srcDir/$library.tar mkdir -p $srcDir/$library/build/cmake/build && cd $srcDir/$library/build/cmake/build args=( -DCMAKE_INSTALL_PREFIX=$installDir ) if [ "$OS" == "macOSx86" ]; then args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion) args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64) fi if [ "$OS" == "appleSilicon" ]; then args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion) args+=(-DCMAKE_OSX_ARCHITECTURES=arm64) fi cmake "${args[@]}" .. make && make install } netcdf() { cd $srcDir local library='netcdf-c-4.9.1' rm -rf $library || true tar xvf $srcDir/$library.tar.gz mkdir -p $srcDir/$library/build && cd $srcDir/$library/build args=( -DCMAKE_INSTALL_PREFIX=$installDir -DCMAKE_PREFIX_PATH=$installDir/HDF_Group/HDF5/$hdfVersion -DHDF5_DIR=$installDir/HDF_Group/HDF5/$hdfVersion -DHDF5_ROOT=$installDir/HDF_Group/HDF5/$hdfVersion -DCMAKE_INSTALL_LIBDIR=lib -DENABLE_BYTERANGE=False -DENABLE_DAP=False -DCMAKE_BUILD_TYPE=Release ) if [ "$OS" == "macOSx86" ]; then args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion) args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64) fi if [ "$OS" == "appleSilicon" ]; then args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion) args+=(-DCMAKE_OSX_ARCHITECTURES=arm64) fi export HDF5_ROOT=$installDir/HDF_Group/HDF5/$hdfVersion export LD_LIBRARY_PATH=$HDF5_ROOT/lib export CPPFLAGS=-I$HDF5_ROOT/include export LDFLAGS=-L$HDF5_ROOT/lib cmake "${args[@]}" .. make && make install } expat() { cd $srcDir local library='expat-2.5.0' rm -rf $library || true tar xvf $srcDir/$library.tar.xz mkdir -p $srcDir/$library/build && cd $srcDir/$library/build args=( -DCMAKE_INSTALL_PREFIX=$installDir -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_LIBDIR=lib ) if [ "$OS" == "macOSx86" ] || [ "$OS" = "appleSilicon" ]; then args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion) fi if [ "$OS" == "macOSx86" ]; then args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64) fi cmake "${args[@]}" .. make && make install } udunits() { cd $srcDir local library='udunits-2.2.28' rm -rf $library || true tar xvf $srcDir/$library.tar.gz && cd $srcDir/$library args=( --prefix=$installDir ) LDFLAGS=-L$installDir/lib/ \ CPPFLAGS=-I$installDir/include/ \ CC=$CC CXX=$CXX \ ./configure "${args[@]}" make && make install } freetype() { cd $srcDir local library='freetype-2.13.0' rm -rf $library || true tar xvf $srcDir/$library.tar.xz cd $srcDir/$library args=( --prefix=$installDir --with-brotli=no --with-bzip2=no ) configure "${args[@]}" make && make install } #CC=clang CXX=clang++ ./configure --prefix=/usr/local/VAPOR-Deps/2019-Aug jpeg() { cd $srcDir rm -rf $srcDir/jpeg-9e || true tar xvf $srcDir/jpegsrc.v9e.tar.gz cd $srcDir/jpeg-9e echo target $MACOSX_DEPLOYMENT_TARGET args=( --prefix=$installDir ) if [ "$OS" == "macOSx86" ]; then args+=(--host=x86_64-apple-darwin) fi CC=$CC CXX=$CXX \ ./configure "${args[@]}" make && make install } tiff() { cd $srcDir local library='libtiff-v4.5.0' rm -rf $library || true tar xvf $srcDir/$library.tar.gz cd $srcDir/$library if [ "$OS" == "macOSx86" ] || [ "$OS" == "appleSilicon" ]; then glibtoolize --force else libtoolize --force fi aclocal autoheader automake --force-missing --add-missing autoconf args=( --prefix=$installDir --disable-dap ) LDFLAGS=-L$installDir/lib \ CPPFLAGS=-I$installDir/include \ CC=$CC CXX=$CXX \ ./configure "${args[@]}" make && make install } sqlite() { cd $srcDir local library='sqlite-autoconf-3410000' rm -rf $library || true tar xvf $srcDir/$library.tar.gz cd $srcDir/$library args=( --prefix=$installDir ) CC=$CC CXX=$CXX \ ./configure "${args[@]}" make && make install } curl() { cd $srcDir local library='curl-8.2.1' # works rm -rf $library || true tar xvf $srcDir/$library.tar.xz mkdir -p $srcDir/$library/build && cd $srcDir/$library/build args=( -DCMAKE_PREFIX_PATH=$installDir -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_INSTALL_PREFIX=$installDir -DCMAKE_LIBRARY_PATH=$installDir/lib -DCMAKE_INCLUDE_PATH=$installDir/include -DCMAKE_INSTALL_RPATH=$installDir/lib ) if [ "$OS" == "macOSx86" ]; then args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64) fi cmake "${args[@]}" .. make && make install } ssh() { cd $srcDir local library='libssh-0.11.0' rm -rf $library || true tar xvf $srcDir/$library.tar.xz mkdir -p $srcDir/$library/build && cd $srcDir/$library/build args=( -DCMAKE_PREFIX_PATH=$installDir -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_INSTALL_PREFIX=$installDir -DCMAKE_LIBRARY_PATH=$installDir/lib -DCMAKE_INCLUDE_PATH=$installDir/include ) if [ "$OS" == "macOSx86" ]; then args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64) fi cmake "${args[@]}" .. make && make install } proj() { cd $srcDir #local library='proj-9.1.0' # does not work #local library='proj-6.3.1' # works local library='proj-7.2.1' # works rm -rf $library || true tar xvf $srcDir/$library.tar.gz tar xvf proj-datumgrid-1.8.tar.gz -C $library/data mkdir -p $srcDir/$library/build && cd $srcDir/$library/build if [ "$OS" == "macOSx86" ] || [ "$OS" == "appleSilicon" ]; then local sqliteLib="-DSQLITE3_LIBRARY=$installDir/lib/libsqlite3.dylib" else local sqliteLib="-DSQLITE3_LIBRARY=$installDir/lib/libsqlite3.so" fi if [ "$OS" == "macOSx86" ]; then args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64) fi args=( -DCMAKE_PREFIX_PATH=$installDir -DEXE_SQLITE3=$installDir/bin/sqlite3 -DSQLITE3_INCLUDE_DIR=$installDir/include $sqliteLib \ -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_INSTALL_PREFIX=$installDir -DPROJ_COMPILER_NAME=$CXX -DCMAKE_LIBRARY_PATH=$installDir/lib -DCMAKE_INCLUDE_PATH=$installDir/include ) if [ "$OS" == "appleSilicon" ]; then args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion) elif [ "$OS" == "macOSx86" ]; then args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64) args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion) fi cmake "${args[@]}" .. make && make install } geotiff() { cd $srcDir local library='libgeotiff-1.7.1' rm -rf $library || true tar xvf $srcDir/$library.tar.gz && cd $srcDir/$library echo $CC echo $CXX echo $CFLAGS echo $LDFLAGS echo $SDKROOT args=( --prefix=$installDir --with-zlib=yes --with-jpeg=yes --with-proj=$installDir --with-libtiff=$installDir ) configure "${args[@]}" make && make install } xinerama() { cd $srcDir local library='xcb-proto-1.15.2' rm -rf $library || true tar xvf $srcDir/$library.tar.gz && cd $srcDir/$library ./configure --prefix=$installDir make && make install cd $srcDir library='libxcb-1.15' export PYTHONPATH=$installDir/local/lib/python3.10/dist-packages tar xvf $srcDir/$library.tar.xz && cd $srcDir/$library PYTHON=python3 PKG_CONFIG_PATH=$installDir/share/pkgconfig ./configure --without-doxygen --docdir='${datadir}'/doc/libxcb-1.15 --prefix=$installDir make && make install } openssl() { cd $srcDir local library='openssl-1.1.1w' rm -rf $library || true tar xvf $srcDir/$library.tar.gz && cd $srcDir/$library echo $CFLAGS echo $CXXFLAGS echo $LDFLAGS echo $CPPFLAGS args=( --prefix=$installDir --openssldir=$installDir ) if [ "$OS" = "macOSx86" ]; then args+=(darwin64-x86_64-cc) elif [ "$OS" = "appleSilicon" ]; then args+=(darwin64-arm64-cc) fi ./Configure shared "${args[@]}" make && make install } pythonVapor() { cd $srcDir local library='cpython-3.9.16' rm -rf $library || true tar xvf $srcDir/$library.tar.gz && cd $srcDir/$library args=( --prefix=$installDir --enable-shared --with-ensurepip=install --with-suffix=.vapor --enable-optimizations ) if [ "$OS" == "macOSx86" ] || [ "$OS" == "appleSilicon" ]; then export PKG_CONFIG_PATH="$(brew --prefix tcl-tk)/lib/pkgconfig" args+=(--prefix=/usr/local/VAPOR-Deps/current/Resources) args+=(--with-openssl=$installDir) args+=(--with-tcltk-libs="$(pkg-config --libs tcl tk)") args+=(--with-tcltk-includes="$(pkg-config --cflags tcl tk)") export LDFLAGS="$LDFLAGS -L$installDir/lib" export CPPFLAGS="$CPPFLAGS -I$installDir/include" export LLVM_PROFDATA="/opt/local/bin/llvm-profdata-mp-17" export LD_LIBRARY_PATH="$installDir/Resources" if [ "$OS" == "macOSx86" ]; then export CFLAGS="$CFLAGS -I/usr/local/include" export LDFLAGS="$LDFLAGS -L/usr/local/lib" args+=(--build=x86_64-apple-darwin) configure "${args[@]}" fi else args+=(--with-openssl=$installDir) args+=(--with-system-ffi) CC=$CC \ CXX=$CXX \ CPPFLAGS=-I$installDir/include \ LDFLAGS="-L$installDir/lib -Wl,-rpath=$installDir/lib" \ ./configure "${args[@]}" fi make && make install $installDir/bin/python3.9.vapor -m pip install --upgrade pip $installDir/bin/python3.9.vapor -m pip install numpy scipy matplotlib } ospray() { cd $srcDir if [ "$OS" == "appleSilicon" ]; then cd $srcDir/ospray/osprayM1 elif [ "$OS" == "macOSx86" ]; then local library='ospray-2.11.0.x86_64.macosx' rm -rf ospray/$library || true unzip -o $srcDir/ospray/$library && cd $srcDir/$library else local library='ospray-2.11.0.x86_64.linux' rm -rf ospray/$library || true tar xvf $srcDir/ospray/$library.tar.gz && cd $srcDir/$library fi mkdir -p $installDir/Ospray cp -rfP * $installDir/Ospray } glm() { cd $srcDir local library='glm-0.9.9.8' rm -rf glm || true unzip $srcDir/$library.zip cp -r $srcDir/glm/glm $installDir/include } gte() { cd $srcDir tar xvf GTE.tar.xz rsync -a GTE $installDir/include } images() { cd $srcDir tar xvf images.tar.xz rsync -a images $installDir/share } qt() { cd $srcDir rm -rf qt-everywhere-src-5.15.8 || true tar xf $srcDir/qt-everywhere-opensource-src-5.15.8.tar.xz mkdir -p $srcDir/qt-everywhere-src-5.15.8/build cd $srcDir/qt-everywhere-src-5.15.8/build if [ "$OS" == "macOSx86" ] || [ "$OS" == "appleSilicon" ]; then brew install gettext brew link gettext --force fi args=( -v -prefix $installDir -opensource -confirm-license -release -nomake examples -nomake tests ) if [ "$OS" == "Ubuntu" ]; then args+=(-feature-freetype) args+=(-qt-freetype) args+=(-opengl desktop) # opensuse new args args+=(-xcb) args+=(-xcb-xlib) args+=(-bundled-xcb-xinput) fi CPPFLAGS="$CPPFLAGS -I$installDir/include" \ LDFLAGS="$LDFLAGS -L$installDir/lib -Wl,-rpath=$installDir/lib" \ ../configure \ "${args[@]}" > qtConfig.txt make > qtMake.txt make install > qtInstall.txt } add_rpath() { for lib in $installDir/lib/*.dylib $installDir/Resources/lib/*.dylib; do fileName="$(basename $lib)" echo install_name_tool -id @rpath/$fileName $lib install_name_tool -id @rpath/$fileName $lib # Get the list of dependencies dependencies=$(otool -L "$lib" | awk '{print $1}' | grep -v ":") # Iterate over each dependency and replace the path with rpath for dep in $dependencies; do depName=$(basename "$dep") newPath="@rpath/$depName" if [ "$(dirname "$dep")" == "$installDir/lib" ]; then echo install_name_tool -change "$dep" "$newPath" "$installDir/lib/$lib" install_name_tool -change "$dep" "$newPath" "$lib" fi if [ "$(dirname "$dep")" == "$installDir/Resources/lib" ]; then echo install_name_tool -change "$dep" "$newPath" "$installDir/Resources/$lib" install_name_tool -change "$dep" "$newPath" "$installDir/Resources/$lib" fi done codesign --force -s - $lib done } renameAndCompress() { pwd cd $baseDir mv $installDir $archiveName tar cfJ $archiveName.tar.xz $archiveName } if [ "$OS" == "macOSx86" ]; then macOSx86Prerequisites elif [ "$OS" == "appleSilicon" ]; then macOSPrerequisites elif [ "$OS" == "Ubuntu" ]; then ubuntuPrerequisites elif [ "$OS" == "Windows" ]; then windowsPrerequisites fi openssl zlib libpng jpeg tiff sqlite ssh ### m1 needs curl for proj? #curl ### proj geotiff assimp szip hdf5 #zstd netcdf expat udunits freetype if [ "$OS" == "Ubuntu" ] ; then xinerama fi ospray glm gte images pythonVapor qt if [ "$OS" == "macOSx86" ] || [ "$OS" == "appleSilicon" ]; then add_rpath fi renameAndCompress ================================================ FILE: scripts/getWMSImage.sh ================================================ #!/bin/bash # # defaults minLon="" maxLon="" minLat="" maxLat="" xres=1024 yres=768 styles="default" version="1.1" imageFile="" imageFormat="image/tiff" tempFile="tmpImage" layer="bmng200406" host="http://data.worldwind.arc.nasa.gov/wms" amp="&" decLLRegEx=^[\-+]?[0-9]+[\.]?[0-9]*$ transparent="FALSE" debugMode=0 map="" compression="-compress none" depth="" printUsage() { echo "Usage: " $0 "{optional parameters} minLon minLat maxLon maxLat" echo "Optional parameters:" echo " -r xres yres" echo " resolution of requested image; default is " ${xres}"x"${yres} echo " -o imageFilename" echo " name for the requested image file; default is named after requested image layer" echo " -m map_name" echo " Requests a predefined map from a well-known server (overrides any expert options)." echo " Available map names:" echo " \"BMNG\" (NASA BlueMarble, the default)" echo " \"landsat\" (Landsat imagery)" echo " \"USstates\" (US state boundaries)" echo " \"UScounties\" (US state and county boundaries)" echo " \"world\" (world political boundaries)" echo " \"rivers\" (major rivers)" echo " -t" echo " request a transparent background" echo "" echo "Expert-only parameters (see documentation):" echo " -s URL" echo " URL for WMS server" echo " -l layerName" echo " arbitrary image-layer name to fetch" echo " -f format" echo " image format; default is \"image/tiff\"" echo " -z" echo " compress the resultant geotiff file" echo " (may not work on all platforms)" echo " -d" echo " debug mode; do not delete temporary files" } realValGT() { a=`bc < $2 EOF ` echo $a } realRange() { a=`bc </dev/null` if [ $? -eq 0 ]; then fetchProg="curl -w HTTP_RESPONSE:%{http_code}\n -L -o" fi nosave=`which wget 2>/dev/null` if [ $? -eq 0 ]; then fetchProg="wget -O" fi if [ "$fetchProg" = "" ]; then echo "Could not find \"wget\" or \"curl\"; needed to retrieve requested images." exit 1 fi nosave=`which tiff2geotiff 2>/dev/null` if ! [ $? -eq 0 ]; then echo "Could not find \"tiff2geotiff\"; needed to convert requested image into geotiff." exit 1 fi # parse command-line options... # while [ $# -gt 4 ] do case $1 in -r) if ! ( [[ $2 =~ ^[0-9]+$ ]] && [[ $3 =~ ^[0-9]+$ ]]) ; then echo "bad resolution values given: " $2 " x " $3 exit 1 fi xres=$2 yres=$3 shift; shift ;; -s) host=$2 shift ;; -o) imageFile=$2 shift ;; -l) layer=$2 shift ;; -m) map=$2 shift ;; -f) imageFormat=$2 shift ;; -d) debugMode=1 ;; -t) transparent="TRUE" ;; -z) compression="-compress lzw" ;; -8) depth="-depth 8" ;; *) printUsage exit 0 esac shift done # remaining parameters form a possible bounding box? # for i in $1 $2 $3 $4 do if ! [[ $i =~ ${decLLRegEx} ]] ; then echo $i " is not a valid decimal lon/lat string" exit 1 fi done minLon=$1 minLat=$2 maxLon=$3 maxLat=$4 # further test bounds for sanity... # if [ `realValGT ${minLon} ${maxLon}` -eq 1 ] then echo "Invalid bounding box: minLon > maxLon" exit 1 fi if [ `realValGT ${minLon} 180` -eq 1 ] || [ `realValGT ${maxLon} 180` -eq 1 ] then minLon=`realSub ${minLon} 180` maxLon=`realSub ${maxLon} 180` echo "min/max lon remapped to: " ${minLon} ${maxLon} fi if [ `realValGT -180 ${minLon}` -eq 1 ] || [ `realValGT ${maxLon} 180` -eq 1 ] then echo "Invalid bounding box:" echo " longitudes must range from -180 to 180, or 0 to 360" exit 1 fi if [ `realValGT -90 ${minLat}` -eq 1 ] || [ `realValGT ${maxLat} 90` -eq 1 ] || \ [ `realValGT ${minLat} ${maxLat}` -eq 1 ] then echo "Invalid bounding box:" echo " latitudes must range from -90 to 90, with minLat < maxLat" exit 1 fi wmsLayer=${layer} # Did the user specify a predefined map? # if [ "${map}" = "BMNG" ] ; then wmsLayer="bmng200406" host="http://www.nasa.network.com/wms" imageFormat="image/tiff" elif [ "${map}" = "landsat" ] ; then wmsLayer="esat" host="http://www.nasa.network.com/wms" imageFormat="image/tiff" elif [ "${map}" = "USstates" ] ; then # these range vs. scale factors are empirically determined! # This server has been deemed unreliable; substituting the worldwind server below... # lonRange=`realRange ${minLon} ${maxLon}` # if [ `realValGT ${lonRange} 59` -eq 1 ] ; then # wmsLayer="ATLAS_STATES_150" # elif [ `realValGT ${lonRange} 25` -eq 1 ] ; then # wmsLayer="ATLAS_STATES_075" # else # wmsLayer="ATLAS_STATES" # fi # host="http://imsref.cr.usgs.gov:80/wmsconnector/com.esri.wms.Esrimap/USGS_EDC_National_Atlas" # imageFormat="image/png" # depth="-depth 8" wmsLayer="topp:states" host="http://worldwind22.arc.nasa.gov/geoserver/wms" styles="countryboundaries" transparent="TRUE" elif [ "${map}" = "UScounties" ] ; then # these range vs. scale factors are empirically determined! lonRange=`realRange ${minLon} ${maxLon}` if [ `realValGT ${lonRange} 59` -eq 1 ] ; then wmsLayer="ATLAS_STATES_150" elif [ `realValGT ${lonRange} 25` -eq 1 ] ; then wmsLayer="ATLAS_STATES_075" else wmsLayer="ATLAS_STATES" fi wmsLayer="ATLAS_COUNTIES_2000,"${wmsLayer} host="http://imsref.cr.usgs.gov:80/wmsconnector/com.esri.wms.Esrimap/USGS_EDC_National_Atlas" imageFormat="image/png" depth="-depth 8" elif [ "${map}" = "world" ] ; then # This server has been ddeemed unreliable; substituting the worldwind server instead --RLB # wmsLayer="1:1" # host="http://columbo.nrlssc.navy.mil/ogcwms/servlet/WMSServlet/Earth_Satellite_Corp_Maps.wms" # imageFormat="image/png" # version="1.1.0" # styles="" wmsLayer="topp:cia" host="http://worldwind22.arc.nasa.gov/geoserver/wms" styles="countryboundaries" transparent="TRUE" elif [ "${map}" = "rivers" ] ; then wmsLayer="RIVERS" host="http://viz.globe.gov/viz-bin/wmt.cgi" imageFormat="image/png" elif [ "${map}" != "" ] ; then echo "unknown map name: " ${map} exit 1 fi # If image-format is not tiff, we'll need the convert utility from # Imagemagick... if [ "${imageFormat}" != "image/tiff" ] ; then nosave=`which convert 2>/dev/null` if ! [ $? -eq 0 ]; then echo "Could not find Imagemagick's \"convert\" utility, which is required when requesting non-tiff images." echo "See http://www.imagemagick.org" exit 1 fi fi # If no image filename specified, name it after the layer... # if [ "${imageFile}" = "" ] ; then if [ "${map}" != "" ] ; then imageFile=${map}.tiff else imageFile=${layer}.tiff fi fi echo "Extent: " $minLon","$minLat " (LL) " $maxLon","$maxLat "(UR)" echo "Image resolution: " $xres "X" $yres echo "Image filename: " $imageFile echo "Image layer: " $wmsLayer echo "WMS URL: " $host # compose the URL # url1=${host}"?""request=GetMap"${amp}"service=wms"${amp}"version="${version}${amp}"layers="${wmsLayer} url2="styles="${styles}${amp}"bbox="${minLon}","${minLat}","${maxLon}","${maxLat} url3="format="${imageFormat}${amp}"height="${yres}${amp}"width="${xres}${amp}"srs=epsg:4326"${amp}"transparent="${transparent} url=${url1}${amp}${url2}${amp}${url3} cmd="${fetchProg} ${tempFile} ${url}" echo ${cmd} ${cmd} if ( grep -s "ServiceException" ${tempFile} ); then echo "Received WMS ServiceException:" cat ${tempFile} exit 1 fi # Need to convert non-tiffs into tiff; this is where the dependency on # Imagemagick comes from # if [ "${imageFormat}" != "image/tiff" ] ; then mv ${tempFile} ${tempFile}2 cmd="convert ${compression} ${depth} ${tempFile}2 tiff:${tempFile}" echo ${cmd} ${cmd} if [ ${debugMode} -ne 1 ] ; then rm ${tempFile}2 fi fi # build this command in pieces -- the lon/lat min/max parameters need to appear # as one logical token on the command-line # cmd1="tiff2geotiff -4 +proj=longlat -n" cmd2="${minLon} ${minLat} ${maxLon} ${maxLat}" cmd3="${tempFile} ${imageFile}" echo ${cmd1} ${cmd2} ${cmd3} ${cmd1} "${cmd2}" ${cmd3} if [ -f ${imageFile} ] ; then echo "Image filename is: " ${imageFile} else echo "Image fetch seems to have failed." fi if [ ${debugMode} -ne 1 ] ; then rm -f ${tempFile} fi ================================================ FILE: scripts/ptcl2vms.py ================================================ #!/usr/bin/python #imports import string import sys import os import shutil import copy import math #the usage string, printed when the user is abusing our tool, lol usage = """usage: ptcl2vms.py [options] [[options] ] ... valid options are... -stride (int) adjusts with what stride we read and generate points -radius (float) adjusts the diameter of the generated point meshes -ref (int) adjusts tesselation level of point meshes -startts (int) sets the starting timestep of the output """ #TODO: try it with more than one timestep #TODO: fix stride problem #a bunch of vector manipulation functions! :D def dot(a, b): return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]) def mag2(v): return dot(v, v) def mag(v): return math.sqrt(mag2(v)) def div(v, n): return v[0] / n, v[1] / n, v[2] / n def mul(v, n): return v[0] * n, v[1] * n, v[2] * n def add(a, b): return a[0] + b[0], a[1] + b[1], a[2] + b[2] def sub(a, b): return a[0] - b[0], a[1] - b[1], a[2] - b[2] def norm(a): return div(a, mag(a)) def resize(a, n): return mul(a, n / mag(a)) def centroid(points): c = (0.0, 0.0, 0.0) for p in points: c = add(c, p) c = div(c, len(points)) return c #A tetrahedron for subdivision by subdivnorm overts = [ \ norm((-1, -1, 1)), norm(( 1, 1, 1)), norm((-1, 1, -1)), norm(( 1, -1, -1))] ofaces = [ \ (0, 1, 2), (3, 2, 1), (0, 3, 1), (3, 0, 2)] def subdivnorm(verts, faces): nfaces = len(faces) for faceIndex in range(0, nfaces) : face = faces[faceIndex] #choose a face to subdivide fverts = [] #get the vertices of the face for i in face: fverts.append(verts[i]) #ctr = norm(centroid(fverts)) #get the centroid of the face everts = [] #get and normalize the new edge vertices for i in range(0, len(fverts)): ni = (i + 1) % len(fverts) everts.append(norm(centroid([fverts[i], fverts[ni]]))) #add all the new vertices, remembering where we stored them eidx = len(verts) verts.extend(everts) #replace the existing face with the first new face faces[faceIndex] = (eidx, eidx + 1, eidx + 2) #build new faces, appending them to the faces array for i in range(0, len(face)): ni = (i + 1) % len(face) faces.append((eidx + i, face[ni], eidx + ni)) def catmullnorm(verts, faces) : nfaces = len(faces) for faceIndex in xrange(nfaces) : face = faces[faceIndex] #choose a face to subdivide fverts = [] #get the vertices of the face for i in face: fverts.append(verts[i]) ctr = norm(centroid(fverts)) #get the centroid of the face everts = [] #get and normalize the new edge vertices for i in range(0, len(fverts)): ni = (i + 1) % len(fverts) everts.append(norm(centroid([fverts[i], fverts[ni]]))) #add all the new vertices, remembering where we stored them cidx = len(verts) verts.append(ctr) eidx = len(verts) verts.extend(everts) #rebuild the existing face as the first new face faces[faceIndex] = (eidx, face[1], eidx + 1, cidx) #build new quads, appending them to the faces array for i in range(1, len(face)): ni = (i + 1) % len(face) faces.append((eidx + i, face[ni], eidx + ni, cidx)) def showMesh(verts, faces): for v in verts: print("v " + str(v[0]) + " " + str(v[1]) + " " + str(v[2])) for f in faces: if len(f) == 3: print("f "+str(f[0]+1)+" "+str(f[1]+1)+" "+str(f[2]+1)) else: print("f "+str(f[0]+1)+" "+str(f[1]+1)+" "+str(f[2]+1)+" "+str(f[3]+1)) print("") #remove the scriptname from argv, but store it just in case :P scriptname = sys.argv.pop(0) #check for valid number of arguments if len(sys.argv) < 2 : print(">>>ERROR: not enough arguments!\n" + usage) exit(-1) #get the name of output file and directory vmsname = sys.argv.pop() print(">>>OUTFILE: " + vmsname) dirname = vmsname[0:vmsname.rfind('.')] + "_data" #remove any preexisting data by the same name if os.path.exists(dirname) : shutil.rmtree(dirname, ignore_errors=False, onerror=None) if os.path.exists(vmsname) : os.remove(vmsname) #make data directory os.mkdir(dirname) #process each option or file stride = 1 ref = 0 radius = 1 startts = 0 plylist = [] while len(sys.argv) > 0 : #get the next argument arg = sys.argv.pop(0) #handle options if arg[:1] == "-" : if arg == "-stride" : stride = int(sys.argv.pop(0)) print("stride = " + str(stride)) elif arg == "-radius" : radius = float(sys.argv.pop(0)) print("radius = " + str(radius)) elif arg == "-ref" : ref = int(sys.argv.pop(0)) print("refinement = " + str(ref)) elif arg == "-startts" : startts = int(sys.argv.pop(0)) print("startts = " + str(startts)) else: print(">>>ERROR: unknown option: '" + arg + "'\n" + usage) exit(-1) continue #open input and output files print(">>>READING: " + arg) infile = open(arg) #get input from input file counter = 1 points = [] for line in infile.readlines() : strc = line.split() if len(strc) < 3: continue coords = [] for i in strc: coords.append(float(i)) counter += 1 if counter >= stride : points.append(coords) counter = 1 infile.close() #generate a sphere with specified refinement, starting with our tetrahedron lverts = copy.deepcopy(overts) lfaces = copy.deepcopy(ofaces) for i in range(ref) : subdivnorm(lverts, lfaces) lnorms = copy.deepcopy(lverts) for i in range(0, len(lverts)) : lverts[i] = resize(lverts[i], radius) #copy the sphere to various positions! :D verts = [] faces = [] norms = [] offset = 0 #this loop runs once for each copy (each must be at a different position) for pos in range(0, len(points), stride) : #add the current position to each point before appending it to verts for vert in lverts : verts.append(add(vert, points[pos])) for nm in lnorms : norms.append(nm) for face in lfaces : faces.append((face[0] + offset, face[1] + offset, face[2] + offset)) #the next face will index its verts from the next starting position offset = len(verts) #write the model to a file! plyname = dirname+"/"+os.path.basename(arg[0:arg.rfind(".")])+".ply" print(">>>WRITING: " + plyname) ply = open(plyname, "w") ply.write('ply\nformat ascii 1.0\nelement vertex ' + str(len(verts)) + '\nproperty float x\nproperty float y\nproperty float z\nproperty float nx\nproperty float ny\nproperty float nz\nelement face ' + str(len(faces)) + '\nproperty list uchar int vertex_indices\nend_header\n') for vi in range(len(verts)): v = verts[vi] n = norms[vi] ply.write(str(v[0])+" "+str(v[1])+" "+str(v[2])+" "\ +str(n[0])+" "+str(n[1])+" "+str(n[2])+"\n") for f in faces: ply.write("3 "+str(f[0])+" "+str(f[1])+" "+str(f[2])+"\n") ply.close() plylist.append(plyname) #write the VMS file, listing all our outputs in it! if len(plylist) < 1: print("ERROR: No input files specified,\n or one input and no outputs!\n") exit(1) vms = open(vmsname, "w") counter = 0 vms.write('\n\n') for i in range(startts) : vms.write('\n') vms.write('\n') vms.write('\n') counter += 1 for ply in plylist : vms.write('\n') vms.write('\n') vms.write('' + ply + '\n') vms.write('\n') counter += 1 vms.write('\n') vms.close() ================================================ FILE: scripts/vapor-setup-win32.csh ================================================ #!/bin/csh -f if !($?VAPOR3_HOME) then echo "VAPOR3_HOME enviroment variable not set" exit 1 endif if !($?PATH) then setenv PATH "${VAPOR3_HOME}\bin" else setenv PATH "${VAPOR3_HOME}\bin:$PATH" endif ================================================ FILE: scripts/vapor-setup-win32.sh ================================================ #!/bin/sh if [ -z "${VAPOR3_HOME}" ] then echo "VAPOR3_HOME enviroment variable not set" exit 1 fi if [ -z "${PATH}" ] then PATH="${VAPOR3_HOME}\\bin"; export PATH else PATH="${VAPOR3_HOME}\\bin:$PATH"; export PATH fi ================================================ FILE: scripts/vapor-setup.bat ================================================ @ECHO OFF SET PATH="%VAPOR3_HOME%/bin";%PATH% ================================================ FILE: scripts/vapor-setup.csh.sed ================================================ #! /bin/csh -f set arch = SYSTEM_ARCH set root = INSTALL_PREFIX_DIR set idl = BUILD_IDL_WRAPPERS set bindir = INSTALL_BINDIR set mandir = INSTALL_MANDIR set lib_search_dirs = LIB_SEARCH_DIRS setenv VAPOR_HOME $root if !($?PATH) then setenv PATH "$bindir" else setenv PATH "${bindir}:$PATH" endif if ( "$arch" == "Darwin" ) then if !($?DYLD_FALLBACK_LIBRARY_PATH) then setenv DYLD_FALLBACK_LIBRARY_PATH "$lib_search_dirs" else setenv DYLD_FALLBACK_LIBRARY_PATH "${lib_search_dirs}:$DYLD_FALLBACK_LIBRARY_PATH" endif else if ( "$arch" == "AIX" ) then if !($?LIBPATH) then setenv LIBPATH "$lib_search_dirs" else setenv LIBPATH "${lib_search_dirs}:$LIBPATH" endif else if !($?LD_LIBRARY_PATH) then setenv LD_LIBRARY_PATH "$lib_search_dirs" else setenv LD_LIBRARY_PATH "${lib_search_dirs}:$LD_LIBRARY_PATH" endif endif if !($?MANPATH) then if ( "$arch" == "AIX" ) then setenv MANPATH "$mandir" else setenv MANPATH "${mandir}":`man -w` endif else setenv MANPATH "${mandir}:${MANPATH}" endif if ( "$idl" == 1 ) then if !($?IDL_DLM_PATH) then setenv IDL_DLM_PATH "${lib_search_dirs}:" else setenv IDL_DLM_PATH "${lib_search_dirs}:$IDL_DLM_PATH" endif endif ================================================ FILE: scripts/vapor-setup.sh.sed ================================================ #! /bin/sh arch=SYSTEM_ARCH root=INSTALL_PREFIX_DIR idl=BUILD_IDL_WRAPPERS bindir=INSTALL_BINDIR mandir=INSTALL_MANDIR lib_search_dirs=LIB_SEARCH_DIRS VAPOR_HOME="$root"; export VAPOR_HOME if [ -z "${PATH}" ] then PATH="$bindir"; export PATH else PATH="$bindir:$PATH"; export PATH fi if [ "$arch" = "Darwin" ] then if [ -z "${DYLD_FALLBACK_LIBRARY_PATH}" ] then DYLD_FALLBACK_LIBRARY_PATH="${lib_search_dirs}"; export DYLD_FALLBACK_LIBRARY_PATH else DYLD_FALLBACK_LIBRARY_PATH="${lib_search_dirs}:$DYLD_FALLBACK_LIBRARY_PATH"; export DYLD_FALLBACK_LIBRARY_PATH fi else if [ "$arch" = "AIX" ] then if [ -z "${LIBPATH}" ] then LIBPATH="${lib_search_dirs}"; export LIBPATH else LIBPATH="${lib_search_dirs}:$LIBPATH"; export LIBPATH fi else if [ -z "${LD_LIBRARY_PATH}" ] then LD_LIBRARY_PATH="${lib_search_dirs}"; export LD_LIBRARY_PATH else LD_LIBRARY_PATH="${lib_search_dirs}:$LD_LIBRARY_PATH"; export LD_LIBRARY_PATH fi fi fi if [ -z "${MANPATH}" ] then if [ "$arch" = "AIX" ] then MANPATH="$mandir"; export MANPATH else MANPATH="$mandir":$(man -w); export MANPATH fi else MANPATH="$mandir:${MANPATH}"; export MANPATH fi if [ "$idl" -eq 1 ] then if [ -z "${IDL_DLM_PATH}" ] then IDL_DLM_PATH="${lib_search_dirs}:"; export IDL_DLM_PATH else IDL_DLM_PATH="${lib_search_dirs}:$IDL_DLM_PATH"; export IDL_DLM_PATH fi fi ================================================ FILE: scripts/vaporBatchFuncs.py ================================================ #!/bin/python #$ -S /bin/python # -m bes # -noshell /bin/python import os import sys import subprocess def usage(): print "Usage:" print "[scheduler options] parallelScript vaporTool : [vaporToolFlags] [-files fileList.txt] : [inputFiles vdfFile]" print "" print "[scheduler options] - Options taken by the scheduler (SGE, LSF, etc)" print " to set up the environment for the array job." print "vaporTool - One of Vapor's data conversion tools, such as" print " wrf2vdf, grib2vdf, etc." print "[vaporToolFlags] - Vapor's data conversion tools each have their" print " own set of options that can be applied for " print " data conversion (such as -numts to specify the" print " number of timesteps to convert). These options" print " may be also be applied here to be used by the" print " parallel script." print "[-files, fileList] - Users can specify a text-file that contains a" print " list of data-files (fileList) they want to" print " perform their conversion on. If used, the .vdf" print " file needs to be included as well." print "[-grid, gridFile] - (For ROMS datasets only) ROMS requires a grid" print " file for each individual conversion that is run." print " ROMS conversions must specify that grid file here." print "[inputFiles, .vdfFile] - If the -files flag is not applied, users may" print " list their data files on the command line." def parseVapor(args): vaporFlags = [] grid = '' # remove vapor[tool].py from argument list args.pop(0) myTool = '' if args.count(":") != 2: print "Command line must contain two ':' delimiters" return -1,[],'',[] # remove the vapor tool and its delimiting ':' from argument list i = args.index(':') myTool = args[i-1] args.pop(i) i = args.index(myTool) args.pop(i) # parse all command-line flags that are going to be applied # to the *2vdf script. A ':' can separate user flags from # user files. If the '-inputFiles' flag is used, then files # are listed in a single text file and any ':' will be ignored try: i = args.index(':') vaporFlags = args[0:i] myFiles = args[i+1:] except: vaporFlags = args if "-files" in vaporFlags: i = args.index('-files') inFile = args[i+1] f = open(inFile,'r') myFiles = f.read().splitlines() vaporFlags.remove('-files') vaporFlags.remove(inFile) if "-grid" in vaporFlags: i = args.index('-grid') grid = args[i+1] vaporFlags.remove('-grid') vaporFlags.remove(grid) vaporFlags = ' '.join(vaporFlags) if len(myFiles) < 2: print "No input files specified." return -1, [],'',[] # 'args' is now just a list of our input files return 1, vaporFlags, myTool, myFiles, grid def allocateFiles(files,first,last,myId): # identify our .vdf file within our 'files' list myVDF = '' r = range(0,len(files)) for i in r: if '.vdf' in files[i]: myVDF = files[i] files.pop(i) break stride = (len(files)) / (last - first + 1) if stride == 0: stride = 1 myFiles = files[myId*stride : (myId+1)*stride] leftovers = (len(files))%stride if (myId == last) and (leftovers != 0): myFiles = myFiles + files[(leftovers*-1):] return myFiles, myVDF def generateCall(myVDF, myFiles, myTool, flags, binDir): command = myTool + ' ' + flags + ' ' if 'wrf2vdf' in myTool: command += ' ' + myVDF + ' ' + ' '.join(myFiles) else: command += ' '.join(myFiles) + ' ' + myVDF sourceString = "sh;. " + binDir + r"/vapor-setup.sh;" call = sourceString + command print call return call ================================================ FILE: scripts/vaporLSF.py ================================================ #!/usr/bin/python #################################################################### # # Copyright (C) 2015 # University Corporation for Atmospheric Research # All Rights Reserved # # File: vaporLSF.py # # Author: Scott Pearse # National Center for Atmospheric Research # PO 3000, Boulder, Colorado # # Date: July 2015 # #################################################################### import os import sys import subprocess sys.path.append("..") from vaporBatchFuncs import * ##################### USER DEFINED VARIABLES ####################### # The variable 'vaporBinDir' needs to point to where vapor's binary # applications have been installed vaporBinDir = '/glade/p/DASG/pearse/parallelConverter/vapor-2.4.2/bin' # The variables first, last, and myId are used to divide a set # of files amongst the tasks in a given batch job. These are # derived from environment variables that are assigned by the # scheduler being used. These variables must be indexed starting # at zero. # first - the index of the first task in the batch submission # last - the index of the last task in the batch submission # myId - the index of the current task try: first = 0 last = int(os.environ["LSB_JOBINDEX_END"]) -1 myId = int(os.environ["LSB_JOBINDEX"]) -1 except: print "Unable to locate array job environment variables. Aboring." usage() sys.exit(-1) ################################################################### def main(): args = sys.argv myVDF = '' grid = '' rc, vaporFlags, myTool, files, grid = parseVapor(args) if rc != 1: print "Input error. Aborting." usage() return myFiles, myVDF = allocateFiles(files,first,last,myId) if myVDF == '': print "Could not locate .vdf metadata file. Aborting." return if grid != '': myFiles.append(grid) call = generateCall(myVDF, myFiles, myTool, vaporFlags, vaporBinDir) subprocess.call(call, shell=True) if __name__ == '__main__': main() ================================================ FILE: scripts/vaporSGE.py ================================================ #!/usr/bin/python #$ -S /bin/python #################################################################### # # Copyright (C) 2015 # University Corporation for Atmospheric Research # All Rights Reserved # # File: vaporSGE.py # # Author: Scott Pearse # National Center for Atmospheric Research # PO 3000, Boulder, Colorado # # Date: July 2015 # #################################################################### import os import sys import subprocess sys.path.insert(0,'.') from vaporBatchFuncs import * ##################### USER DEFINED VARIABLES ####################### # The variable 'vaporBinDir' needs to point to where vapor's binary # applications have been installed vaporBinDir = '/users/pearse/vapor/vapor-2.4.2/bin' # The variables first, last, and myId are used to divide a set # of files amongst the tasks in a given batch job. These are # derived from environment variables that are assigned by the # scheduler being used. # first - the index of the first task in the batch submission # last - the index of the last task in the batch submission # myId - the index of the current task try: first = 0 last = int(os.environ["SGE_TASK_LAST"]) - int(os.environ["SGE_TASK_FIRST"]) myId = int(os.environ["SGE_TASK_ID"]) - int(os.environ["SGE_TASK_FIRST"]) except: print "Unable to locate array job environment variables. Aboring." usage() sys.exit(-1) ################################################################### def main(): args = sys.argv myVDF = '' grid = '' rc, vaporFlags, myTool, files, grid = parseVapor(args) if rc != 1: print "Input error. Aborting." usage() return myFiles, myVDF = allocateFiles(files,first,last,myId) if myVDF == '': print "Could not locate .vdf metadata file. Aborting." return call = generateCall(myVDF, myFiles, myTool, vaporFlags, vaporBinDir) subprocess.call(call, shell=True) if __name__ == '__main__': main() ================================================ FILE: scripts/vdccp ================================================ #!/usr/bin/env python2 #################################################################### # # # Copyright (C) 2016 # # University Corporation for Atmospheric Research # # All Rights Reserved # # # # File: vdccp.py # # # # Author: Stanislaw Jaroszynski # # National Center for Atmospheric Research # # PO 3000, Boulder, Colorado # # # # Date: June 2016 # # # #################################################################### import os import sys import argparse import shutil import errno ################## Utility Functions and Classes ################### # # Prints error message and exits program if condition fails # def Assert(cond, mesg): if not cond: print "vdccp.py:", mesg quit() # # Holds information about a single variable or coordinate # class VDCVar(): def __init__(s, name): s.name = name s.timesteps = [] s.minFrame = -1 s.maxFrame = -1 s.minCompression = -1 s.maxCompression = -1 # # Holds information about a file's path relative to the database and its size in bytes # class File(): def __init__(s, relPath): global srcDir s.relPath = relPath s.size = os.path.getsize(os.path.join(srcDir, relPath)) ######################## Global Variables ########################## # # Variables and coordinates are stored seperately because they have # different options and follow different rules for copying. # Min/max frames and compression is stored both for each variable # as well as a global min/max. # minFrameGlobal = sys.maxint maxFrameGlobal = -sys.maxint - 1 minCompressionGlobal = sys.maxint maxCompressionGlobal = -sys.maxint - 1 totalSizeGlobal = 0 totalCopySize = 0 allVars = [] allCoords = [] copyVars = [] copyCoords = [] filesToCopy = [] ######################## Primary Functions ######################### # # Returns object containing argument strings and flags # def SetupAndParseArgs(): ap = argparse.ArgumentParser(prog="vdccp.py", description="Copies a user defined portion of a vdc database.") ap.add_argument("source", type=argparse.FileType("r"), help="Source database.nc file.") ap.add_argument("destination", nargs="?", help="Destination directory.") ap.add_argument("-v", "--var", action="append", help="Variable(s) to be copied. All coordinates selected by default and can be removed with -x. Multiple can be grouped together if colon separated. If none specified, all variables selected.") ap.add_argument("-x", "--exclude", action="append", help="Variable(s) or coordinate(s) to be excluded. Multiple can be grouped together if colon separated. Overrides any variables added with -v.") ap.add_argument("-s", "--start-frame", default=0, type=int, help="Start frame. Default first frame. (Frames do not correspond directly to time steps. A single frame can contain multiple time steps.") ap.add_argument("-e", "--end-frame", type=int, help="End frame. Default last frame. Overrides -d. If neither -e or -d is specified, the entire data set after the start is copied.") ap.add_argument("-d", "--frame-count", type=int, help="Number of time frames from Start to copy. Overridden by -e.") ap.add_argument("-c", "--compression", type=int, help="Compression level to copy. Default maximum detail.") ap.add_argument("-f", "--force", action="store_true", help="Overwrites existing data if necessary.") ap.add_argument("-n", "--dry-run", action="store_true", help="Show what would have been transferred.") ap.add_argument("--coord-start-frame", default=0, type=int, help="Start frame for coordinates. All coordinate frames copied by default. -s does not affect coordinate frames.") ap.add_argument("--coord-end-frame", default=sys.maxint, type=int, help="End frame for coordinates. All coordinate frames copied by default. -s does not affect coordinate frames.") ap.add_argument("--info", action="store_true", help="Prints available variables, coordinates, compression levels, and maximum/minimum timesteps for data set and exits.") ap.add_argument("--info-var", nargs=1, action="append", help="Prints available variables, coordinates, compression levels, and maximum/minimum timesteps for a specific variable and exits.") ap.add_argument("--version", action="version", version="%(prog)s 0.9") return ap.parse_args() # # Create utility strings with relative and absolute paths to folders # used. Assert that the expected database folders exist. # def GeneratePertinentPaths(): global vdcName global srcDir global relDataDir global relVarDir global relCoordDir global dataDir global varDir global coordDir global destDir global hasVarDir global hasCoordDir vdcName = os.path.splitext(os.path.basename(args.source.name))[0] srcDir = os.path.dirname(os.path.realpath(args.source.name)) relDataDir = vdcName + "_data" relVarDir = os.path.join(relDataDir, "data") relCoordDir = os.path.join(relDataDir, "coordinates") dataDir = os.path.join(srcDir, relDataDir) varDir = os.path.join(srcDir, relVarDir) coordDir = os.path.join(srcDir, relCoordDir) destDir = args.destination hasVarDir = False hasCoordDir = False if os.path.isdir(dataDir) and os.path.isdir(varDir): hasVarDir = True else: print "vdccpy.py: Warning: Data is missing" if os.path.isdir(coordDir): hasCoordDir = True # # Obtains the min/max frame and compressions for a var and updates # global values if necessary. Information is determined only from # file names. # Variable directory argument is to allow the same function to be # used for both variables and coordinates. # def getVarInfo(var, directory): global minFrameGlobal global maxFrameGlobal global minCompressionGlobal global maxCompressionGlobal global totalSizeGlobal for fn in os.listdir(os.path.join(directory, var.name)): if fn[0] == ".": continue # Ignores Finder metadata in OS X totalSizeGlobal += os.path.getsize(os.path.join(directory, var.name, fn)) fn, comp = os.path.splitext(fn) comp = comp[3:] if comp == "": comp = 0 else: comp = int(comp) time = int(os.path.splitext(fn)[1][1:]) if not time in var.timesteps: var.timesteps.append(time) if var.minFrame == -1 or var.minFrame > time: var.minFrame = time if var.maxFrame == -1 or var.maxFrame < time: var.maxFrame = time if var.minCompression == -1 or var.minCompression > comp: var.minCompression = comp if var.maxCompression == -1 or var.maxCompression < comp: var.maxCompression = comp minFrameGlobal = min(minFrameGlobal, var.minFrame) maxFrameGlobal = max(maxFrameGlobal, var.maxFrame) minCompressionGlobal = min(minCompressionGlobal, var.minCompression) maxCompressionGlobal = max(maxCompressionGlobal, var.maxCompression) # # Obtains variable metadata for all variables and coordinates # def ScanVariableMetadata(): global allVars global allCoords global totalSizeGlobal global varDir global coordDir global hasVarDir global hasCoordDir if hasVarDir: for fn in os.listdir(varDir): if fn[0] == ".": continue var = VDCVar(fn) getVarInfo(var, varDir) allVars.append(var) if hasCoordDir: for fn in os.listdir(coordDir): if fn[0] == ".": continue var = VDCVar(fn) getVarInfo(var, coordDir) allCoords.append(var) totalSizeGlobal /= (2**30) * 1.0 # Convert from bytes to GB # # Bound frames to available and set to bounds if not specified. # def CheckArgumentValidity(args): if args.end_frame == None: if args.frame_count != None: args.end_frame = args.start_frame + args.frame_count else: args.end_frame = maxFrameGlobal if args.start_frame < minFrameGlobal: args.start_frame = minFrameGlobal if args.end_frame > maxFrameGlobal: args.end_frame = maxFrameGlobal if args.compression == None: args.compression = maxCompressionGlobal if args.coord_start_frame < minFrameGlobal: args.coord_start_frame = minFrameGlobal if args.coord_end_frame > maxFrameGlobal: args.coord_end_frame = maxFrameGlobal if destDir == None and not args.info and not args.info_var: Assert(0, "Error: Copy destination not set.") # # Create list of variables to be copied from args. If none specified, # add all variables. # All coordinates are added by default. # def AddVariablesFromArguments(): global args global copyVars global copyCoords copyCoords = allCoords[:] # All coordinates copied by default copyVarsNames = [] if args.var != None: for varName in args.var: if ':' in varName: copyVarsNames += varName.split(':') else: copyVarsNames.append(varName) copyVarsNames = list(set(copyVarsNames)) for var in allVars: for name in copyVarsNames: if var.name == name: copyVars.append(var) copyVarsNames.remove(name) break Assert(len(copyVarsNames) == 0, "Error: Variable(s) {0} not found.".format('"'+copyVarsNames[0]+'"' if len(copyVarsNames) == 1 else copyVarsNames)) else: copyVars = allVars[:] # # Remove any excluded variables or coordinates from list. # def ExcludeVariablesFromArguments(): global args global copyVars global copyCoords excludeVarsNames = [] if args.exclude != None: for varName in args.exclude: if ':' in varName: excludeVarsNames += varName.split(':') else: excludeVarsNames += varName.split(':') excludeVarsNames = list(set(excludeVarsNames)) checkList = excludeVarsNames[:] for var in allVars + allCoords: for name in checkList: if var.name == name: checkList.remove(name) break Assert(len(checkList) == 0, "Error: Variable(s) {0} not found.".format('"'+checkList[0]+'"' if len(checkList) == 1 else checkList)) for name in excludeVarsNames: for var in copyVars: if var.name == name: copyVars.remove(var) break for coord in copyCoords: if coord.name == name: copyCoords.remove(coord) break def PrintDatabaseInfo(): print "name:", vdcName print "time frames:", minFrameGlobal, "-", maxFrameGlobal print "compression levels:", minCompressionGlobal, "-", maxCompressionGlobal print "total size: {0:.2f}Gb".format(totalSizeGlobal) print "variables:", [var.name for var in allVars] print "coordinates:", [var.name for var in allCoords] def PrintVariableInfo(name): search = [x for x in allVars + allCoords if x.name == name] Assert(len(search) == 1, "Error: variable \"{0}\" not found.".format(name)) var = search[0] print "Variable \"{0}\":".format(var.name) print "\ttime frames: {0} - {1}".format(var.minFrame, var.maxFrame) def CreateCopyFileList(): global copyVars global copyCoords global vdcName global relVarDir global relCoordDir global totalCopySize # Add .nc database metadata file. filesToCopy.append(File(vdcName + ".nc")) # Add variable files for var in copyVars: for frame in xrange(max(var.minFrame, args.start_frame), min(var.maxFrame, args.end_frame) + 1): for level in xrange(var.minCompression, min(args.compression, var.maxCompression) + 1): relPath = os.path.join(relVarDir, var.name, "{0}.{1:04}.nc{2}".format(var.name, frame, "" if level == 0 else level)) if os.path.exists(os.path.join(srcDir, relPath)): filesToCopy.append(File(relPath)) # Add coordinate files for coord in copyCoords: for frame in xrange(max(coord.minFrame, args.coord_start_frame), min(coord.maxFrame, args.coord_end_frame) + 1): for level in xrange(coord.minCompression, coord.maxCompression + 1): relPath = os.path.join(relCoordDir, coord.name, "{0}.{1:04}.nc{2}".format(coord.name, frame, "" if level == 0 else level)) if os.path.exists(os.path.join(srcDir, relPath)): filesToCopy.append(File(relPath)) # Get total size of files to copy to show progress. for x in filesToCopy: totalCopySize += x.size # # Copy all files from list. If --dry-run specified, only print file # copy info. If file already exists, show prompt to overwrite unless # --force. Any missing directories are created. After a file is # copied, its size is added to copiedSize and this is used to show # a percent copied. # def CopyFiles(): global filesToCopy global srcDir global destDir global totalCopySize global args copiedSize = 0 for f in filesToCopy: destPath = os.path.join(destDir, f.relPath) if not os.path.exists(os.path.dirname(destPath)) and not args.dry_run: # Race condition where folder is created try: os.makedirs(os.path.dirname(destPath)) except OSError as err: if err.errno != errno.EEXIST: raise if os.path.exists(destPath) and not args.force and not args.dry_run: response = raw_input("File \"{0}\" already exists. Overwrite? (y/n)".format(destPath)) if not (response == "y" or response == "Y"): copiedSize += f.size continue sys.stdout.write("{0:3d}% Copying {1}\n".format(copiedSize * 100 / totalCopySize, f.relPath)) if not args.dry_run: shutil.copy(os.path.join(srcDir, f.relPath), destPath) copiedSize += f.size print "100%" ############################### Main ############################### def main(): global args args = SetupAndParseArgs() GeneratePertinentPaths() ScanVariableMetadata() CheckArgumentValidity(args) AddVariablesFromArguments() ExcludeVariablesFromArguments() if args.info or args.info_var != None: if args.info: PrintDatabaseInfo() if args.info_var != None: for name in [x[0] for x in args.info_var]: PrintVariableInfo(name) quit() CreateCopyFileList() CopyFiles() if __name__ == "__main__": main() ================================================ FILE: scripts/vdfbkup.pl ================================================ #!/usr/bin/perl # # $Id$ # ######################################################################### # # # Copyright (C) 2007 # # University Corporation for Atmospheric Research # # All Rights Reserved # # # ######################################################################### # # File: vdfbkup.pl # # Author: John Clyne # National Center for Atmospheric Research # PO 3000, Boulder, Colorado # # Date: Fri Jan 13 18:00:32 MST 1995 # # Description: # # Usage: # # Environment: # # Files: # # # Options: use English; use POSIX; use File::Basename; use File::Spec; use File::Copy; use Cwd 'abs_path'; use Cwd; $tmpdirdef = defined($ENV{'TMPDIR'}) ? $ENV{'TMPDIR'} : "/tmp"; # # Options is a table of *configurable* options supported by # vdfbkup.pl. The fields contained within are: option name, perl variable # name, default option values, number of option arguments (0 or 1), and # a description of the option. # @Options = ( "maxtarsize", "MaxTarSize", "5000", '1', "Max size of tar file(MBytes)", "maxsize", "MaxSize", "500", '1', "Max size of file to tar (MBytes)", "maxarg", "MaxArg", "70000",'1', "Max size of unix cmd line(bytes)", "bs", "BS", "512",'1', "Tar blocking factor (bs*512 bytes)", "nr", "NotReally", "0", '0', "Echo, but do not execute cmds", "quiet", "Quiet", "0", '0', "Operate quitely", "nolog", "NoLog", "0", '0', "Do not create a log file", "restart", "Restart", "0", '0', "Restart using the ./vdfbkup_restart.txt restart file", ); sub usage { local($s) = @_; local($format) = "\t%-12.12s %-12.12s %-5.5s %s\n"; if (defined ($s)) { print STDERR "$ProgName: $s\n"; } print STDERR "Usage: $ProgName [options] vdffile (directory|command)\n"; print STDERR "Usage: $ProgName -restart\n"; print STDERR "\nWhere \"options\" are:\n\n"; printf STDERR $format, "Option name", "Default", '#args', "Description"; printf STDERR $format, "------ ----", "-------", '-----', "-----------"; print STDERR "\n"; for($i=0; $i<=$#Options; $i+=5) { printf STDERR $format, "-$Options[$i]", $Options[$i+2], $Options[$i+3], $Options[$i+4]; } exit(1); } # # Set a variable, whose name is given by `$name', to the value # given by `$value' # sub set_var_by_name { local($name, $value) = @_; eval '$' . $name . " = \'$value\'"; } sub get_var_by_name { local($name) = @_; local($value); eval '$value = ' . '$' . "$name"; return($value); } sub configure { my (@argv) = @_; my ($i); my ($match); # # Set defaults # # This nonsense creates a variable named by the second # field of @Options (the option name) and assigns it # the value of the third field of @Options (the default option # argument). # for($i=0; $i<=$#Options; $i+=5) { do set_var_by_name($Options[$i+1], $Options[$i+2]); } # # Next, parse the command line, overriding anything # set by default above. # while ($argv[0] =~ /^-/) { $opt = shift @argv; $match = -1; # index of matching option # # Look for an option name that matches the # option specifier given on the command line. Exact # matches aren't required. The shortes unique string # is sufficient # for($i=0; $i<=$#Options; $i+=5) { $_ = "-" . $Options[$i]; # option name if (/^$opt/) { # # Do we already have a match? If so the # option specifier is ambiguous # if ($match >= 0) { do usage("Ambiguous option: \"$opt\""); } $match = $i; } } if ($match < 0) { do usage ("Unknown option: \"$opt\""); } # # does the option take an argument? If not the option's # value is given by the table, "Options" # if ($Options[$match+3]) { defined($value = shift @argv) || do usage("Missing offset"); } else { $value = ! $Options[$match+2]; } do set_var_by_name($Options[$match+1], $value); } return(@argv); } sub mysystem { my(@cmd) = @_; if (! $Quiet) { smsg(*STDOUT, "Executing -> @cmd"); } if (! $NotReally) { system(@cmd); if ($? != 0) { smsg(*STDERR, "Command \"@cmd\" exited with error"); exit(1); } } } sub Cleanup { my($sig) = @_; close RESTART; print STDERR "$ProgName: Caught a SIG$sig -- Shutting down\n"; exit(0); } sub timestamp { my($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(); $year -= 100; # y2k return(sprintf( "%2.2d%2.2d%2.2d%2.2d%2.2d%2.2d", $year, $mon, $mday, $hour, $min, $sec) ); } sub smsg { my($fh, $msg) = @_; my($str); my($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(); $timestr = POSIX::strftime( "%a, %b %d %H:%M:%S", $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ); $msg = sprintf("$ProgName: ($timestr): %s\n", $msg); if (length($msg) < $MaxMsg) { printf $fh "%s\n", "$msg"; } else { my($maxmsg); my($elipses) = "..."; $maxmsg = $MaxMsg - length($elipses); printf $fh "%-${MaxMsg}.${MaxMsg}s", "$msg"; printf $fh "%s\n", $elipses; } } sub copyit { local($src, $dst) = @_; #if (-d $dst) { # $dst = File::Spec->catfile($dst, $src); #} if (! $Quiet) { printf STDOUT "Copying file $src to $dst\n"; } if (! $NotReally) { if (! copy($src, $dst)) { smsg (*STDERR, "Can't copy $src to $dst"); exit(1); } } if (! $NoLog) { if (-f $src) { ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($src); print FILE "$src - $size\n"; } } } sub vdfsplit { my($file) = @_; my($dummy1, $varname) = File::Spec->splitdir($file); my($dummy1, $dummy2, $filebase) = File::Spec->splitpath($file); my($dummy, $ts, $level) = split(/\./, $filebase); $level =~s/nc//; return($varname, $ts, $level); } sub tarit { local($tarfile, @files) = @_; my(@cmd) = ("tar", "-c", "-b", $BS, "-f", $tarfile, @files); mysystem(@cmd); if (! $NoLog) { print FILE "\n------------------\n$tarfile contents\n------------------\n"; foreach $file (@files) { if (-f $file) { ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($file); print FILE "$file - $size\n"; } } } } # # Save state of @CmdLineArgs, $VDFFile, @FilesToTar, @TarNames, and # @FilesToCopy variables # sub save_state { if (! open (RESTART, "> $RestartFile")) { print STDERR "Can't open state file $RestartFile\n"; return; } foreach $arg (@CmdLineArgs) { print RESTART "$arg\n"; } print RESTART "END_CMD_LINE_ARGS\n"; $vdffile = abs_path($VDFFile); print RESTART "$vdffile\n"; foreach $file (@FilesToCopy) { print RESTART "$file\n"; } my(@tar_names) = @TarNames; foreach $listref (@FilesToTar) { @a = @$listref; $tarfile = shift @tar_names; print RESTART "$tarfile\n"; foreach $file (@a) { print RESTART "$file\n"; } } close RESTART; } # # Restore state of @CmdLineArgs, $VDFFile, @FilesToTar, @TarNames, and # @FilesToCopy variables # sub restore_state { if (! open (RESTART, "< $RestartFile")) { print STDERR "Can't open state file $RestartFile\n"; return (); } my($done) = 0; while ((!$done) && ($_ = )) { chop $_; if ($_ =~ /^END_CMD_LINE_ARGS$/) { $done = 1; next; } push @CmdLineArgs, $_; } if (! defined($VDFFile = )) { print STDERR "Bogus restart file\n"; return(); } chop $VDFFile; @FilesToCopy = (); @TarNames = (); my($done) = 0; while ((!$done) && ($_ = )) { chop $_; if ($_ =~ /\.tar$/) { push @TarNames, $_; $done = 1; next; } push @FilesToCopy, $_; } @FilesToTar = (); @list = (); while ($_ = ) { chop $_; if ($_ =~ /\.tar$/) { push @TarNames, $_; push @FilesToTar, [@list]; @list = (); next; } push @list, $_; } if (@list) { push @FilesToTar, [@list]; } close RESTART; } sub tar_create { my($vdfbase) = @_; if (! $Quiet) { printf "%-30.30s: %s\n", "Max tar file size (MB's)", $MaxTarSize; printf "%-30.30s: %s\n", "Max tar file element size (MB's)", $MaxSize; printf "%-30.30s: %s\n", "Max arg length (bytes)", $MaxArg; printf "\n"; } $MaxTarSize *= 0.95; # allow for tar overhead. if (! $Restart) { $data_dir = $vdfbase; $data_dir =~ s/\.vdf/_data/; $cmd = join(' ', @VDFLSCmd, $vdfbase); if (! $Quiet) { smsg(*STDOUT, "Executing -> $cmd"); } $_ = `$cmd`; if ($?>>8) { printf STDERR "$ProgName: Command \"$cmd\" failed\n"; exit(1); } my(@files) = (); @lines = split /\n/, $_; foreach $_ (@lines) { push @files, $data_dir . "/" . $_; } @FilesToTar = (); # list of lists of files to tar @FilesToCopy = ();# list of files to copy without tarring $targlen = 0; $tsize = $tsize_all = 0; @list = (); @TarNames = (); foreach $file (@files) { if (-f $file) { ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($file); } else { next; } $size = $blocks / 2048; # convert from 512-byte blocks to mbytes $arglen = length("$file "); if ($size > $MaxSize) { push @FilesToCopy, $file; $tsize_all += $size; next; } if (! @list) { ($varname0, $ts0, $level0) = vdfsplit($file); ($varname1, $ts1, $level1) = vdfsplit($file); } ($varname, $ts, $level) = vdfsplit($file); if ( (($targlen + $arglen) >= $MaxArg) || (($tsize + $size) >= $MaxTarSize) || ($varname0 ne $varname) || ($level0 != $level)) { push @FilesToTar, [@list]; push @TarNames, sprintf("%s_%4.4d-%4.4d.nc%d.tar", $varname0, $ts0, $ts1, $level0); @list = (); ($varname0, $ts0, $level0) = vdfsplit($file); ($varname1, $ts1, $level1) = vdfsplit($file); $targlen = 0; $tsize = 0; } ($varname1, $ts1, $level1) = vdfsplit($file); push @list, $file; $targlen += $arglen; $tsize += $size; $tsize_all += $size } if (@list) { push @FilesToTar, [@list]; push @TarNames, sprintf("%s_%4.4d-%4.4d.nc%d.tar", $varname0, $ts0, $ts1, $level0); } } # # back up the vdf file # if (defined ($TargetDirectory)) { copyit($vdfbase, $TargetDirectory); } else { my(@cmd) = (@BackupCmd); foreach $_ (@cmd) { my($dummy1, $dummy2, $filebase) = File::Spec->splitpath($vdfbase); $_ =~ s/%s/$vdfbase/; $_ =~ s/%b/$filebase/; } mysystem(@cmd); } save_state(); while ($file = shift(@FilesToCopy)) { if (defined ($TargetDirectory)) { copyit($file, $TargetDirectory); } else { my(@cmd) = (@BackupCmd); foreach $_ (@cmd) { my($dummy1, $dummy2, $filebase) = File::Spec->splitpath($file); $_ =~ s/%s/$file/; $_ =~ s/%b/$filebase/; } mysystem(@cmd); } save_state(); } while ($listref = shift(@FilesToTar)) { $tarbase = shift(@TarNames); if (defined ($TargetDirectory)) { $tarfile = File::Spec->catfile($TargetDirectory, $tarbase); } else { $tarfile = $tarbase; } @files = @$listref; tarit($tarfile, @files); if (defined (@BackupCmd)) { my(@cmd) = (@BackupCmd); foreach $_ (@cmd) { my($dummy1, $dummy2, $filebase) = File::Spec->splitpath($tarfile); $_ =~ s/%s/$tarfile/; $_ =~ s/%b/$filebase/; } mysystem(@cmd); unlink $tarfile; } save_state(); } } ################################################################# ## ## M A I N P R O G R A M ## ################################################################# $0 =~ s/.*\///; $ProgName = $0; $MBYTE = 1024 * 1024; $MaxMsg = "256"; @VDFLSCmd = ("vdfls", "-sort", "varname"); $RestartFile = File::Spec->catfile(cwd(), ".vdfbkup_restart.txt"); @CmdLineArgs = @ARGV; @ARGV = configure(@ARGV); if ($Restart) { if (@ARGV != 0) { usage("Wrong # of arguments"); } restore_state(); @ARGV = @CmdLineArgs; @ARGV = configure(@ARGV); } else { if (-f $RestartFile) { print STDERR "A restart file, $RestartFile,\n"; print STDERR "was found from a previous\n"; print STDERR "session, but the -restart option was not present. You \n"; print STDERR "must remove the restart file or use the -restart option.\n"; exit (1); } } if (@ARGV < 2) { usage("Wrong # of arguments - no files specified"); } $VDFFile = shift @ARGV; if (defined $TargetDirectory) {undef $TargetDirectory;} if (defined @BackupCmd) {undef @BackupCmd;} if (-d $ARGV[0]) { $TargetDirectory = abs_path(shift @ARGV); } else { @BackupCmd = @ARGV; } $SIG{INT} = 'Cleanup'; if (defined $TargetDirectory) { $LogFile = File::Spec->catfile($TargetDirectory, "vdfbkup.log"); } else { $LogFile = "vdfbkup.log"; } my($volume, $directory, $vdfbase) = File::Spec->splitpath($VDFFile); if ($directory ne "") { chdir $directory or die "$ProgName: Can't cd to $directory: $!\n"; } if (! $NoLog) { open (FILE, "> $LogFile") || die "Can't open log file $LogFile for writing!"; } tar_create($vdfbase); if (! $NoLog) { close FILE; } if (defined @BackupCmd && ! $NoLog) { my(@cmd) = (@BackupCmd); foreach $_ (@cmd) { my($dummy1, $dummy2, $filebase) = File::Spec->splitpath($LogFile); $_ =~ s/%s/$LogFile/; $_ =~ s/%b/$filebase/; } mysystem(@cmd); unlink $LogFile if (! $NotReally); } unlink $RestartFile; ================================================ FILE: scripts/wrf2vdfbatch ================================================ #!/usr/bin/perl # This variable will be most of the command we execute $stub = "wrf2vdf"; # This is a switch to say how much output to make $quietScript = 0; # This variable holds the entire help screen $helpScreen = " Usage: wrf2vdfbatch [options] metafile wrfFiles wrfFiles may be a single WRF netCDF output file, a list of such files, or a file name containing wildcards. Options are: -varnames arg Colon delimited list of variable names in metadata to convert -atypvars arg Colon delimited list of atypical names for variables U:V:W:PH:PHB:P:PB:T that appear in WRF file(s) -dervars arg Colon delimited list of derived variables to convert. Choices are: phnorm: normalized geopotential (PH+PHB)/PHB wind3d: 3D wind speed (U^2+V^2+W^2)^1/2 wind2d: 2D wind speed (U^2+V^2)^1/2 pfull: full pressure P+PB pnorm: normalized pressure (P+PB)/PB theta: potential temperature T+300 tk: temperature in Kelvin 0.037(T+300)(P+PB)^0.29 -tsincr arg Increment between Vapor time steps to convert (e.g., 3=every third), from Vapor time step 0 -tsstart arg Starting time stamp for conversion, in format yyyy-mm-dd_hh:mm:ss -tsend arg Last time stamp to convert, in format yyyy-mm-dd_hh:mm:ss -level arg Refinement levels saved. 0=coarsest, 1=next refinement, etc. -1=finest (full resolution). -quiet Only output suggested vertical extents at end of conversion -help Print this help screen and exit "; if ( $#ARGV == -1 ) # Print help and exit if no arguments are given { print( "$helpScreen" ); exit 0; } # Parse command line arguments $i = 0; for ( ; $i <= $#ARGV ; $i++ ) { if ( $ARGV[$i] eq "-varnames" ) { $i++; if ( $ARGV[$i] =~ /^-/ ) { print( "wrf2vdfbatch: -varnames option requires argument\n" ); exit 1; } $stub = $stub . " -varnames $ARGV[$i]"; next; } if ( $ARGV[$i] eq "-atypvars" ) { $i++; if ( $ARGV[$i] =~ /^-/ ) { print( "wrf2vdfbatch: -atypvars option requires argument\n" ); exit 1; } $stub = $stub . " -atypvars $ARGV[$i]"; next; } if ( $ARGV[$i] eq "-dervars" ) { $i++; if ( $ARGV[$i] =~ /^-/ ) { print( "wrf2vdfbatch: -dervars option requires argument\n" ); exit 1; } $stub = $stub . " -dervars $ARGV[$i]"; next; } if ( $ARGV[$i] eq "-tsincr" ) { $i++; if ( $ARGV[$i] =~ /^-/ ) { print( "wrf2vdfbatch: -tsincr option requires argument\n" ); exit 1; } $stub = $stub . " -tsincr $ARGV[$i]"; next; } if ( $ARGV[$i] eq "-tsstart" ) { $i++; if ( $ARGV[$i] =~ /^-/ ) { print( "wrf2vdfbatch: -tsstart option requires argument\n" ); exit 1; } $stub = $stub . " -tsstart $ARGV[$i]"; next; } if ( $ARGV[$i] eq "-tsend" ) { $i++; if ( $ARGV[$i] =~ /^-/ ) { print( "wrf2vdfbatch: -tsend option requires argument\n" ); exit 1; } $stub = $stub . " -tsend $ARGV[$i]"; next; } if ( $ARGV[$i] eq "-level" ) { $i++; if ( $ARGV[$i] =~ /^-/ && $ARGV[$i] ne "-1" ) { print( "wrf2vdfbatch: -level option requires argument\n" ); exit 1; } $stub = $stub . " -level $ARGV[$i]"; next; } if ( $ARGV[$i] eq "-quiet" ) { $quietScript = 1; $stub = $stub . " -quiet"; next; } if ( $ARGV[$i] eq "-help" || $ARGV[$i] eq "-h" || $ARGV[$i] eq "--h" || $ARGV[$i] eq "--help" ) { print( "$helpScreen" ); exit 0; } if ( $ARGV[$i] =~ /^-/ ) { print( "wrf2vdfbatch: Unrecognized option $ARGV[$i]\n" ); exit 1; } last; # If we get down here, we're done with options and we've moved on # to files } # Get the metafile name $stub = $stub . " $ARGV[$i]"; # These are the bottom of the bottom and top layers. Start with high values # so that they are sure to change. $bottomBottom = 400000.0; $bottomTop = 400000.0; # These are the total number of time steps actually converted and the total # number of time steps in the WRF files. $tsConverted = 0; $tsInFiles = 0; # The starting index of the WRF file list $i++; $firstWrfIndex = $i; # Loop over WRF files for ( ; $i <= $#ARGV ; $i++ ) { $command = $stub . " $ARGV[$i]"; # Normal output if ( $quietScript != 1 ) { print( "For WRF output file $ARGV[$i]:\n" ); } $result = `$command`; $exitStat = `echo $?`; # Handle errors if ( $exitStat != 0 ) { print( "wrf2vdfbatch: wrf2vdf exited with non-zero exit status\n" ); print( "Command executed was: $command\n" ); exit 1; } # Normal output if ( $quietScript != 1 ) { print( "$result\n" ); } # Extract the most restrictive vertical extents and maybe the number of # time steps converted. Two different formats to deal with, depending on the # -quiet option if ( $quietScript == 1 ) # What to do if quiet option is on { @newExts = split( / /, $result ); } else # What to do if quiet option is off { # This gathers the extents # Index where a key phrase begins $mostIndex = index( $result, "Most restrictive vertical extents: " ); if ( $mostIndex < 0 ) # Handle errors { print( "wrf2vdfbatch: Problem finding most restrictive vertical " ); print( "extents\nin wrf2vdf output\n" ); exit 1; } # Index of the first newline found after that index $nIndex = index( $result, "\n", $mostIndex ); if ( $nIndex < $mostIndex ) # Handle errors { print( "wrf2vdfbatch: Problem finding newline after most "); print( "restrictive\nvertical extents\n" ); exit 1; } # Length of substring to take $strLength = $nIndex - $mostIndex - 35; # Take the extents $extsStr = substr( $result, $mostIndex + 35, $strLength ); # Split them up @newExts = split( / to /, $extsStr ); # Done getting extents. Now get time step info. # Index where a key phrase begins $timeIndex = index( $result, "Time steps converted: " ); if ( $timeIndex < 0 ) # Handle errors { print( "wrf2vdfbatch: Problem finding time step information in\n" ); print( "wrf2vdf output\n" ); exit 1; } # Index of the first newline found after that index $nIndex = index( $result, "\n", $timeIndex ); if ( $nIndex < $timeIndex ) # Handle errors { print( "wrf2vdfbatch: Problem finding newline after time steps " ); print( "converted\n" ); exit 1; } # Length of the substring to take $strLength = $nIndex - $timeIndex - 22; # Take the time step info $tsInfoStr = substr( $result, $timeIndex + 22, $strLength ); # Split up it up and add to the tally @tsInfo = split( / of /, $tsInfoStr ); $tsConverted += $tsInfo[0]; $tsInFiles += $tsInfo[1]; } # Compare old and new extents if ( $newExts[0] < $bottomBottom ) { $bottomBottom = $newExts[0]; } if ( $newExts[1] < $bottomTop ) { $bottomTop = $newExts[1]; } } # Report how many time steps were converted and number of files, if desired if ( $quietScript != 1 ) { print( "Time steps converted: $tsConverted\n" ); print( "Total time steps in files: $tsInFiles\n" ); print( "Total number of WRF files \(converted or not\): " ); $totalFiles = $#ARGV + 1 - $firstWrfIndex; print( "$totalFiles\n" ); } # Report most restrictive extents print( "Bottom of bottom layer: $bottomBottom\n" ); print( "Bottom of top layer: $bottomTop\n" ); print( "You may want to change the vertical extents in your .vdf file.\n" ); ================================================ FILE: share/CMakeLists.txt ================================================ add_subdirectory (Doxygen) if (BUILD_VDC) file (GLOB SHADERS_SRC shaders/*.vert shaders/*.frag shaders/*.geom) add_custom_target ( shaders ALL SOURCES ${SHADERS_SRC} ) endif () if (BUILD_VDC AND ${GENERATE_FULL_INSTALLER}) set (SHARE_DIRS doc fonts images shaders udunits python palettes examples ) if (NOT INSTALLER_OMIT_MAPS) set (SHARE_DIRS ${SHARE_DIRS} "${MAP_IMAGES_PATH}") endif() install ( DIRECTORY ${SHARE_DIRS} DESTINATION ${INSTALL_SHARE_DIR} COMPONENT Share ) endif () ================================================ FILE: share/Doxygen/.gitignore ================================================ Doxyfile ================================================ FILE: share/Doxygen/CMakeLists.txt ================================================ set (DOC_DEST_DIR ${PROJECT_BINARY_DIR}/doc) if (BUILD_DOC) find_package (Doxygen) if (DOXYGEN_FOUND) if (BUILD_PYTHON) set (DOXYGEN_GENERATE_XML "YES") set (DOXYGEN_GENERATE_HTML "NO") else() set (DOXYGEN_GENERATE_XML "NO") set (DOXYGEN_GENERATE_HTML "YES") endif () configure_file (Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) add_custom_target(doc ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile DEPENDS Doxyfile.in COMMENT "Generating API documentation with Doxygen" ) add_custom_command( OUTPUT ${DOC_DEST_DIR} COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile COMMENT "Generating API documentation with Doxygen" VERBATIM ) # add_custom_command( # TARGET ${DOC_DEST_DIR} # COMMAND ${DOXYGEN_EXECUTABLE} # ARGS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile # ) if (BUILD_PYTHON) install ( DIRECTORY ${DOC_DEST_DIR} DESTINATION ${INSTALL_SHARE_DIR} COMPONENT Share ) endif () endif (DOXYGEN_FOUND) endif (BUILD_DOC) ================================================ FILE: share/Doxygen/Doxyfile.in ================================================ # Doxyfile 1.3.9.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = @PROJECT_NAME@ # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @VERSION_STRING@ # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = @DOC_DEST_DIR@ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of source # files, where putting all generated files in the same directory would otherwise # cause performance problems for the file system. CREATE_SUBDIRS = YES # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, # Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, # Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, # Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, # Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is used # as the annotated text. Otherwise, the brief description is used as-is. If left # blank, the following values are used ("$name" is automatically replaced with the # name of the entity): "The $name class" "The $name widget" "The $name file" # "is" "provides" "specifies" "contains" "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited # members of a class in the documentation of that class as if those members were # ordinary class members. Constructors, destructors and assignment operators of # the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources # only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = NO # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = @CMAKE_CURRENT_SOURCE_DIR@/mainpage.dox \ @PROJECT_SOURCE_DIR@/include/vapor \ @PROJECT_SOURCE_DIR@/apps/vaporgui # @PROJECT_SOURCE_DIR@/apps/vaporgui/VizWinMgr.h \ # @PROJECT_SOURCE_DIR@/apps/vaporgui/TabManager.h \ # @PROJECT_SOURCE_DIR@/apps/vaporgui/VizWin.h \ # @PROJECT_SOURCE_DIR@/apps/vaporgui/EventRouter.h \ # @PROJECT_SOURCE_DIR@/apps/vaporgui/BarbEventRouter.h \ # @PROJECT_SOURCE_DIR@/apps/vaporgui/HelloEventRouter.h \ # @PROJECT_SOURCE_DIR@/apps/vaporgui/MappingFrame.h \ # @PROJECT_SOURCE_DIR@/apps/vaporgui/VariablesWidget.h \ # @PROJECT_SOURCE_DIR@/apps/vaporgui/RenderHolder.h \ # @PROJECT_SOURCE_DIR@/apps/vaporgui/ErrorReporter.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp # *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm FILE_PATTERNS = *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories # that are symbolic links (a Unix filesystem feature) are excluded from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 3 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = @DOXYGEN_GENERATE_HTML@ # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = @DOXYGEN_GENERATE_XML@ # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = DOXYGEN_SKIP_THIS # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse the # parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or # super classes. Setting the tag to NO turns the diagrams off. Note that this # option is superseded by the HAVE_DOT option below. This is only a fallback. It is # recommended to install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes that # lay further from the root node will be omitted. Note that setting this option to # 1 or 2 may greatly reduce the computation time needed for large code bases. Also # note that a graph may be further truncated if the graph's image dimensions are # not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). # If 0 is used for the depth value (the default), the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO ================================================ FILE: share/Doxygen/TODO ================================================ Autogenerate config file to contain correct paths ================================================ FILE: share/Doxygen/mainpage.dox ================================================ //! //! \mainpage The VAPOR project developer API //! //! Documentation for the VAPOR project's C++ API //! //! \defgroup Public_Params VAPOR Params Developer API //! \defgroup Public_Render VAPOR Render Developer API //! \defgroup Public_VDC VAPOR VDC Developer API //! \defgroup Public_GUI VAPOR GUI Developer API ================================================ FILE: share/doc/DCP_Format.md ================================================ # DCP Particle Data Format **D**ata **C**ollection **P**articles is a simple data format built upon NetCDF for importing particle data into VAPoR. ## Dimensions ### P P is on only required dimension. The size of the dimension P represents the number of particles at this timestep. If the number of particles varies between timesteps, every timestep must be in its own file since each NetCDF file can only define a single length for a dimension. ### T T is the time dimension and it is required for time-varying data. It should be set to *unlimited*. ### axis This optional dimension is must have a length of 3 and it is used to pack 3 component values such as position or velocity into a single variable for convenience. ## Variables The only required variable is Position. Non-time-varying data should have a single dimension of `P`. If the data is time-varying, it should have the dimensions `(T, P)`. 3D particles will often have 3-component data associated with them, for example their velocity would have 3 components, one for each dimension. Since this is a common use case, variables can have 3 components per particle and this is done by setting the fastest-varying dimension to `axis` which as a size of 3. For an example, look at the position variable description below. ### Position This variable contains the position data for the particles. The data can be stored in either of the below methods: ``` float Position(T, P, axis) ; ``` ``` float Position_x(T, P) ; float Position_y(T, P) ; float Position_z(T, P) ; ``` ## Examples ### Python Script `vapor/share/examples/generateExampleDCP.py` shows how to generate a DCP dataset from a particle simulation. ### Basic NetCDF File This is an example of a NetCDF file containing 2 particles with time-varying position and particle speed data. ``` netcdf particles_000 { dimensions: P = 2 ; T = UNLIMITED ; // (1 currently) axis = 3 ; variables: double T(T) ; T:units = "seconds" ; float Position(T, P, axis) ; float speed(T, P) ; data: T = 0 ; Position = 9.762701, 43.03787, 20.55268, 8.976637, -15.26904, 29.17882 ; speed = 26.02757, 18.87516 ; } ``` ================================================ FILE: share/doc/help/FieldLineAdvectionHelp.html ================================================ Field Line Advection Setup

How to Set Up Field Line Advection

  1. Load a Metadata file (*.vdf file) into VAPOR.
  2. In the Basic Flow Settings:
    1. Specify "Field Line Advection" as the flow type
    2. Specify three variables for the unsteady (e.g. velocity) field
    3. Specify three variables for the steady (e.g. magnetic) field
    4. Specify the "Unsteady field scale factor".  (Normally with WRF datasets this factor is 1.) This depends on the space and time scales that were used when the data was generated.  It is the product: (spatial-correction-factor)*(time-correction-factor), where:
      • (time-correction-factor) is the number of simulation time units (e.g. seconds) per Vapor (.vdf) time step. If the user times are correctly set in the metadata (vdf file) then this factor should be 1.
      • (spatial-correction-factor) is the ratio of the full domain size in VAPOR (see the VAPOR region panel) to the actual user domain extent that was used in the simulation. If the data extents in the metadata (vdf file) are correctly set to the actual user coordinates then this factor should be 1.
  3. Set up flow seeding as follows:
    1. Decide whether to use a random rake, nonrandom rake, or a list of seeds, as the starting seed points for the field lines to be advected.
      • If you are using a rake,  the position and size of the rake can be established by using sliders, typing in numerical values, or by using the rake tool in the visualizer window.
      • To use a list of seeds, either type it in (using the "edit seed list" button), or read the seeds from a text file, or specify the seed points with the probe tool.  Each seed in the list has (x,y,z)-coordinates, as well as a time.  If the time is negative, that seed point is valid for any time step; otherwise it will only be used to seed the flow at the specified time step.
    2. Under the "Unsteady Flow Time Settings", Specify the one time step when the seed points are to be injected into the flow, using the first of the three values labeled "Seed time start, end, increment".  Only one time step is used for seed injection.
      • If the unsteady field data is not available at every time step, you must specify the time steps that will be sampled, using the “Unsteady Flow Time Settings."  By default, every time step is sampled from beginning to end, using values in “Time step sample start, end, increment".  Check the optional “Use time step list" to specify an arbitrary set of time steps that will be sampled.

Optional Settings to Consider


Nonuniform random seed placement:
    If you are using the “Random Rake" for seed placement, the distribution of random seeds can be biased by a field magnitude in the “Flow Seeding Settings. "     As you increase the bias (above 0), the seeds are chosen at larger field magnitude values, approaching the maximum field magnitude within the rake bounds.  Bias values below zero result in seed points having field magnitude nearer zero.  The three variables labeled “Seed Distrib. Field" identify the vector field whose magnitude is used to determine the seed distribution.
 
Seed Prioritization:
    The field line advection algorithm maximizes a field magnitude along each field line to determine the points that will be advected to the next time step.  The field that is used for this prioritization is specified as the "Seed Priority Field".  Also, values labeled "Priority Field Min, Max" can be specified.   The search for the largest field value is terminated when field magnitude exceeds the value of “Priority Field Max". If the priority field magnitude at a point is less than its magnitude at the seed point multiplied by the “Priority Field Min," then the search is terminated and the field line is truncated at that point.
You can choose whether the seed prioritization occurs before or after the time-advection. If you select "Prioritize before advection", then the seed for a field line at the next time step is chosen by maximizing the priority field along the field line at the current time step. If you select "Prioritize after advection", then several points (their number is specified as the No. of samples) along the field line at the current time step are all advected to the next time step, and the seed to be used at the next time step is selected by maximizing the priority field among the points that were advected to the next time step. The second approach, "Prioritize after advection" is useful when the seeds from the first approach exit the current region, resulting in early termination of the field line advection.

Color and opacity settings:
    By default, path lines have a constant color and opacity.   Using the Color/Opacity mapping, you can make the color and opacity depend on any of the following:

    1. Position along Flow (This is a value between 0 and 1 along a steady field line indicating the integration position at that point relative to the full integration)
    2. Field Magnitude (The magnitude of the steady field at the position along the path line)
    3. Seed Index.  The seeds are numbered from 0 to N-1 where N is the number of different seed points.  If this option is selected, each field line has color or opacity determined by its seed point.
    4.  Variable.  The color or opacity is a mapping of an arbitrary variable at the position of the point in the current VAPOR data collection.
When one of these mappings is selected, be sure to specify the color (or opacity) map endpoints to include the range of values to be mapped.  Then use the color editor or the opacity editor to specify the color or opacity at specific points along that range.

================================================ FILE: share/doc/help/UnsteadyHelp.html ================================================ Field Line Advection Setup

How to Set Up Unsteady Flow

  1. Load a Metadata file (*.vdf file) into VAPOR.
  2. In the Basic Flow Settings:
    1. Specify "Unsteady" as the flow type
    2. Specify three variables for the unsteady (e.g. velocity) field
    3. Specify the "Unsteady Integration Direction" as either "Forward" or "Backward".  Seeds will be advected in the specified direction by integrating the unsteady field either forwards or backwards in time.
    4. Specify the "Unsteady field scale factor".  (Normally with WRF datasets this factor is 1.) This depends on the space and time scales that were used when the data was generated.  It is the product: (spatial-correction-factor)*(time-correction-factor), where:
      • (time-correction-factor) is the number of simulation time units (e.g. seconds) per vapor (.vdf) time step. If the user times are correctly specified in the metadata (vdf file) then this factor should be 1.
      • (spatial-correction-factor) is the ratio of the full domain size in VAPOR (see the VAPOR region panel) to the actual user domain extents that were used in the simulation. If the data extents in the metadata (vdf file) are correctly specified to the actual user coordinates, then this factor should be 1.
  3. Set up flow seeding as follows:
    1. Decide whether to use a random rake, nonrandom rake, or a list of seeds, as the starting seeds for the field lines to be advected.
      • If you are using a rake,  the position and size of the rake can be established by using sliders, by typing in numerical values, or by using the rake tool in the visualizer window.
      • To use a list of seeds, either type it in (using the "edit seed list" button), read the seeds from a text file, or insert them using the probe tool.  Each seed in the list has (x,y,z)-coordinates, as well as a time.  If the time is negative, that seed point is valid for all seed time steps.
    2. Under the "Unsteady Flow Time Settings", specify the time steps when the seed points are to be injected into the flow, using the three values labeled "Seed time start, end, increment".  These determine an increasing sequence of integers evenly spaced in time, of the form: a, a+b, a+2b,...,a+kb, where a is the "Seed Time Start", b is the "increment" and the largest injection time, a+kb, is no greater than the "Seed Time End".  If the seeds are from a seed list, and the seed time is nonnegative, then that seed is only injected at its specified time step.
    3. In the Unsteady Flow Time Settings:
      1. Set the "Unsteady samples per time step" to be the number of separate positions along a path line that will be displayed in the interval from one time step to the next.  Increase this to get a smoother path line.
      2. “Display interval min, max” determines the portion of each path that is displayed at a given time.  If T is the current time step (as specified in the Animation Panel), then the portion of the flow line from T+min to T+max will be displayed.  For example:
        •  To see the entire path line at once, make min very negative and max very positive (e.g. -1000 and +1000).
        • To see the path line evolve (grow) over time, with the unsteady integration = forward, set min to be very negative (e.g. min = -1000) and set max = 0. The animation panel can later be used to animate the path line evolution.
    4. If the unsteady field data is not available at every time step, you must specify the time steps that will be sampled, using the "Unsteady Flow Time Settings".  By default, every time step is sampled from beginning to end, using values in "Time step sample start, end, increment".  Check the optional "Use time step list" to specify an arbitrary set of time steps that will be sampled.

    Nonuniform random seed placement:
        If you are using the “Random Rake” for seed placement, the distribution of random seeds can be biased by a field magnitude using bias settings in the "Flow Seeding Settings".    As you increase the bias (above 0), the seeds are chosen at larger field magnitude values, approaching the maximum field magnitude within the rake bounds.  Bias values below zero result in seeds to be distributed with field magnitudes nearer zero.  The three variables labeled "Seed Distrib. Field" identify the vector field whose magnitude is used to determine the seed distribution.
     
    Color and opacity settings
        By default, path lines have a constant color and opacity.   Using the Color/Opacity mapping, you can make the color and opacity depend on any of the following:
    • Time Step (i.e. the specific time step associated with a particle as it moves along the path line)
    • Field Magnitude (The magnitude of the unsteady field at the position along the path line)
    • Seed Index.  The seeds are numbered from 0 to N-1 where N is the number of different seed points.  If this option is selected, each field line has color or opacity determined by its seed point.
    •  Variable.  The color or opacity is a mapping of an arbitrary variable at the position of the point in the current VAPOR data collection.
    When one of these mappings is selected, be sure to specify the color (or opacity) map endpoints to include the range of values to be mapped.  Then use the color editor or the opacity editor to specify the color or opacity at specific points along that range.

================================================ FILE: share/doc/man/asciitf2vtf.pod ================================================ =begin comment $Id$ =end comment =head1 NAME asciitf2vtf - Convert an ASCII description of a Lookup Transfer table to VAPOR's vtf format =head1 SYNOPSIS B [options] I =head1 DESCRIPTION B is a translator for converting an ASACII representation of a color and opacity transfer funciton into VAPOR's .vtf format. The resulting .vtf file may be loaded into a VAPOR session. The ASCII transfer function files input into B are whitespace-separted lists of n-tuples of floating point values. The first element of each tuple specifies the data value that the opacity or color will be mapped to. The domain of the first tuple element is the set of real numbers, but most typically set to the user data domain. The remaining tuple elements specify opacity or color values in the normalized range [0.0..1.0]. The translated file is written to the path specified by I. =head1 OPTIONS =over 4 =item -cmap Ecmap_fileE Path to an ASCII file containing a color transfer function description. Presently only the Hue-Saturation-Value (HSV) color model is supported: each tuple is of the form (D, H, S, V), where I is the data value, I is the normalized hue, I is normalized color saturation, and I is normalized color value. =item -omap Eomap_fileE Path to an ASCII file containing an opacity transfer function description. Each tuple is of the form (D, O), where I is the data value and I is the normalized opacity: a value of 0.0 is fully transparent, and a value of 1.0 is fully opaque. =item -help Print a help message and then exit. =back =head1 EXAMPLES To create a linear opacity ramp with a fully transparent opacity at the data value 0.0 and a fully opaque opacity at the data value 100.0, an ASCII opacity transfer function file named "opacity.txt" would contain: =over 4 0.0 0.0 100.0 1.0 =back To convert B to a .vtf file named "map.vtf", the following invocation would be used: =over 4 asciitf2vtf -omap opacity.txt map.vtf =back If in addition to an opacity transfer function a color transfer function is to be included that linearly ramps the Hue from 0 to 360 degrees, and has constant, full saturation and value, an ASCII transfer function file named "color.txt" would contain: =over 4 0.0 0.0 1.0 1.0 100.0 1.0 1.0 1.0 =back Note that all HSV elements are normalized. The following invocation would be used to convert both opacity and color transfer function files: =over 4 asciitf2vtf -cmap color.txt -omap opacity.txt map.vtf =back =head1 SEE ALSO =head1 NOTES =head1 HISTORY Last updated on $Date$ ================================================ FILE: share/doc/man/getWMSImage.pod ================================================ =begin comment $Id$ =end comment =head1 NAME getWMSImage.sh - Retrieve maps and imagery from a Web Mapping Server =head1 SYNOPSIS B [options] I =head1 DESCRIPTION B is a bash-shell script for retrieving maps and imagery from an OGC-compliant Web Mapping Server (WMS). It operates in two modes: default mode and expert mode. The default mode is intended to help most users acquire typical base-map images, choosing from a small set of predefined map types. The existing map types include NASA Blue Marble and Landsat imagery, maps of political boundaries, rivers, etc. Expert mode can be used to extract arbitrary imagery from any OGC-compliant server. It is intended only for users who are highly knowledgeable about WMS protocol and servers. In general, this requires knowing how to acquire and interpret the so-called "GetCapabilities" document for a server, and using the information to determine the "GetMap" URL, the map layers that are available, and the image formats that are supported. Consult the WMS specifications for details (http://www.opengeospatial.org/standards/wms). In either mode, the bounding box of the area of interest must be specified through the I parameters. These are given in decimal-degrees, and must be in the range og [-180..180] for longitudinal values, and [-90..90] for latitudes. To specify a region encompassing one of the poles, use -180 and 180 for I, and either -90 as I for the south pole, or 90 as I for the north pole. By default, if the script is run without options, an image of NASA's Blue Marble Next-Generation imagery is downloaded for the area of interest, at a resolution of 1025x768 pixels, and placed in a file named BMNG.tiff. A number of options can be used in both modes to override this behavior. =head1 OPTIONS =head2 Default Mode Options =over 4 =item -m I Specifies which of the predetermined map-types to download. Must be one of: BMNG : Blue Marble Next-Generation; the default landsat : Landsat imagery USstates : US state boundaries UScounties : US state and county boundaries world : World political boundaries rivers : major world rivers (scale-dependent) Use of this option overrides expert options. =item -r I Specify the pixel resolution of the requested image/map. The default is 1024x768. =item -o I Specify the name for the request image/map file. By default, it is I.tiff. =item -t Request that the image background should be transparent. This may or may not be honored by a given WMS. Note that foreground colors are determined by the server. =back =head2 Expert Mode Options Expert mode operates in lieu of the B<-m map_name> option of default mode, where the server URL, image layer name(s), and image format must be explictly specified. =over 4 =item -s I Specifies the URL for the desired WMS "GetMap" request. =item -l I Specifies the layer name (or comma-separated names) of the map/image feature(s) to be retrieved. =item -f I Specifies the format for the requested image, as advertised by the WMS server. =item -r I Specify the pixel resolution of the requested image/map. The default is 1024x768. =item -o I Specify the name for the request image/map file. By default, it is I.tiff. =item -t Request that the image background should be transparent. This may or may not be honored by a given WMS. Note that foreground colors are determined by the server. =item -z Request that the resultant image file is compressed (not supported on all platforms). =item -d Debug mode; does not delete intermediate files. =back =head1 EXAMPLES C will return an image file named I that is a Blue Marble image of Europe, part of Eurasia, and the north pole. C will return an image file named I that depicts state and county boundaries of the western half of the United States. =head1 HISTORY Last updated on $Date$ ================================================ FILE: share/doc/man/ptcl2vms.pod ================================================ =begin comment $Id$ =end comment =head1 NAME ptcl2vms - Transform lists of points into vms model files =head1 SYNOPSIS B [options] I I =head1 DESCRIPTION B reads newline-delimited 3D points from text files, where coordinates are delimited with spaces, and stores a sequence of sphere models in I. The file I will be created if it doesn't already exist. Each sphere in the output represents a single point from the inputs. Each input file is placed in its own timestep of the output vms. =head1 OPTIONS =over 4 =item -radius EsizeE Radius of spheres to produce (default 0.5) =item -ref EnumberE Specify the number of refinement passes to do on sphere models (default 0) =item -startts EtsE Integer offset of first time step to produce in vms file. (default 0) =item -stride EcountE Read one in every EcountE points from the input files. (default 1) =item -help Print a usage statement and then exit. =item -quiet Operate quietly, only reporting fatal errors. =back =head1 EXAMPLES ptcl2vms -help ptcl2vms -radius 300 -ref 2 ts0points ts1points ts2points points.vms ptcl2vms -startts 1 -radius 300 -ref 2 ts1points ts2points points.vms ptcl2vms -stride 3 ts0points ts2points ts3points ts4points points.vms ptcl2vms -quiet -startts 1 -radius 300 -ref 2 -stride 3 ts1points points.vms =head1 SEE ALSO I =head1 HISTORY Last updated on $Date$ ================================================ FILE: share/doc/man/raw2wasp.pod ================================================ =begin comment $Id$ =end comment =head1 NAME raw2wasp - Transform and write a raw data volume into a NetCDF WASP file. =head1 SYNOPSIS B [options] I I =head1 DESCRIPTION B reads a 3D or 2D volume of data from disk, wavelet transforms the data, and stores it in file I. The data volume must be stored on disk as a contiguous array of unformatted binary floating point values (32bit precision by default) with no header or trailer information. The dimensions of the raw data volume must match those specified in I. The file indicated by I must be a valid WASP file created, for example, by the B command. =head1 OPTIONS =over 4 =item -debug Enable diagnostics. =item -varname EnameE This option specifies name of the variable that the raw data volume corresponds too. The name must match either a 2D or 3D variable name in the WASP indicated by I. If I matches a 2D variable, a 2D slice of data expected to be contained in I. If I matches a 3D variable, B will attempt to read a 3D data volume from I. The dimensions of the volume/slice contained in I must match those of the corresponding variable defined in I. =item -type EtypeE Primitive data type of the data stored in I. Supported values are 'float32', 'float64', and 'int32'. =item -lod EnE Compressed variables are stored with a finite number of fixed refinement levels determined by the number of compression ratios specified in the I file. By default all refinement levels are output. This option can be used to reduce the refinement levels output. A value 0 implies coarsest, 1 => next refinement, and so on. The value -1 is synonymous with the highest refinement level available. =item -nthreads EnE This option can be used to specify the number of execution threads to be employed when transforming data. The default value of I is 0, which causes the application to query the operating system to find the number of processors available, and then use that value. For most platforms the number of processors available is the result of the system call, sysconf(_SC_NPROCESSORS_ONLN). =back =head1 EXAMPLES The command C followed by C would transform the volume stored in the file B and write it into the WASP file associated with the B file. This assumes that the array stored in file B has dimensions 256x256x256 and the elements are stored as 32-bit floats. =head1 SEE ALSO waspcreate, wasp2raw =head1 HISTORY Last updated on $Date$ ================================================ FILE: share/doc/man/tiff2geotiff.pod ================================================ =begin comment $Id$ =end comment =head1 NAME tiff2geotiff - Insert georeferencing and dates into a tiff file =head1 SYNOPSIS B [options] I I =head1 DESCRIPTION B reads a tiff file and converts it to a geotiff (georeferenced tiff) file. B can insert geo-referencing as well as date/time stamps into the input file. The geo-referencing and date information can be specified for a single image, or for a sequence of images in a multi-directory tiff file. B is modified from the geo-tiff application geotifcp, and it supports many options of that program. Type "tiff2geotiff -h" to see all the available command-line options. Below are listed all the options needed for doing the tiff to geotiff conversion needed by VAPOR. =head1 OPTIONS =over 4 =item -4 E"proj string"E This option specifies a map projection using a PROJ4 projection string. This string must be enclosed in quotes, and consists of several keyword/value pairs of the form "+key=value". The full set of PROJ4 key/value pairs can be found at the PROJ4 wiki http://trac.osgeo.org/proj/wiki . For example, a longitude/latitude projection on a spherical earth is specified as "+proj=latlong +ellps=sphere". B supports Lambert conformal conic, Mercator, Longitude/Latitude, and polar stereographic projections. =item -m Edate/time-position_filenameE This option requires option -4 above. This option specifies a file that contains georeferencing information and date/time stamps for each of the directories in the tiff file. Each line of the file B is of the form: Date/Time llx lly urx ury pllx plly purx pury Where: Date/Time is a WRF-style date/time stamp in the form yyyy-mm-dd_hh:mm:ss llx lly urx ury are the longitude (x) and latitude (y) of the lower-left and upper-right corners of the plot area in the image. This supports georeferencing of images that consist of a plot area surrounded by additional annotation, enabling the latitude and longitude of the plot area to be specified. pllx plly purx pury are the relative positions of the plot area corners in the full page, and are values between 0.0 and 1.0 . The georeferencing is such that the plot area will fit exactly at the specified latitude and longitude; however the image will extend further than the plot area if pllx, plly, purx, and pury are not 0.0, 0.0, 1.0, and 1.0 respectively. =item -M Edate/time_filenameE This option specifies a file that contains a date/time stamp for each directory in the tiff file. The option "-4" must not be specified. Each line of the file B is a WRF-style date time stamp of the form: yyyy-mm-dd_hh:mm:ss =item -n E"llx lly urx ury"E This option requires four values in quotes. This specifies the same latitude and longitude extents for all directories in the file. Option -4 must be specified. This option is ignored if option -m is specified. =item -c compressOption This option (inherited from geotifcp) is useful in controlling the compression of the resulting geotiff file. Useful values of B, for use with VAPOR, include: none will result in no compression in the output file lzw will result in Lempel-Ziv & Welch encoding =item -h Print a usage statement and then exit. =back =head1 EXAMPLES The command C will produce an output geotiff file outfile.gtif that will have the same images as infile.tif, but will in addition be geo-referenced to use a long/lat map projection, and will map the images to the rectangle with lon/lat corners at (0,-60) and (90,-30). C will produce an output geotiff file outfile.gtif that will contain the same image or images as infile.tif, but will in addition be geo-referenced to use a Lambert conformal conic map projection. The Lambert projection will be centered at longitude -30, with the projection being true at latitudes 40 and 60. The resulting geotiff image will have date/time stamps and lon/lat extents as specified in the file datetimecoordfile.txt. The file datetimecoordfile.txt must have one line for each image in the tiff file, and each line must consist of a date/time stamp followed by 8 floating point values as in the following: 2009-07-21_13:30:00 -100 30 -50 50 0.1 0.1 0.9 0.9 In the above line the first value is a date/time stamp. The next four values indicate that the longitude of the plot area of the image goes from -100 to -50 and the latitude goes from 30 to 50. The last four values indicate that the actual image is larger than the plot area, with the plot area going from 10% inside the lower-left corner of the image to 10% inside the upper-right corner. =head1 SEE ALSO The PROJ4 wiki http://trac.osgeo.org/proj/wiki =head1 HISTORY Last updated on $Date$ ================================================ FILE: share/doc/man/vdccp.py.pod ================================================ =begin comment $Id$ =end comment =head1 NAME vdccp.py - Copies a user defined portion of a vdc database. =head1 SYNOPSIS B [options] I I B -list I B -info I B [-h] [-v VAR] [-x EXCLUDE] [-s START_FRAME] [-e END_FRAME] [-d FRAME_COUNT] [-c COMPRESSION] [-f] [-n] [--coord-start-frame COORD_START_FRAME] [--coord-end-frame COORD_END_FRAME] [--info] [--info-var INFO_VAR] [--version] -I [-I] =head1 DESCRIPTION B copies I, or part of I, to I. The first form does this. The second form is used to obtain a list of the files that would be copied if the first form were used on I. The third form prints a human-readable message detailing the available ranges of timesteps, variables and refinement available in I. B copies a user defined portion of a VDC database, -I, to I. With no options set, the entire database is copied. If a variable is chosen with -v, only those chosen are copied. All coordinates are copied unless excluded with -x. This utility can also show information about the database or a specific variable/coordinate by passing the option --info and --info-var respectively. =head1 OPTIONS =over 4 =item -v, --var Variable(s) to be copied. All coordinates selected by default and can be removed with -x. Multiple can be grouped together if colon separated. If none specified, all variables selected. =item -x, --exclude Variable(s) or coordinate(s) to be excluded. Multiple can be grouped together if colon separated. Overrides any variables added with -v. =item -s, --start-frame Start frame. Default first frame. (Frames do not correspond directly to time steps. A single frame can contain multiple time steps. =item -e, --end-frame End frame. Default last frame. Overrides -d. If neither -e or -d is specified, the entire data set after the start is copied. =item -d, --frame-count Number of time frames from Start to copy. Overridden by -e. =item -c, --compression Compression level to copy. Default maximum detail. =item -f, --force Overwrites existing data if necessary. =item -n, --dry-run Show what would have been transferred. =item --coord-start-frame Start frame for coordinates. All coordinate frames copied by default. -s does not affect coordinate frames. =item --coord-end-frame End frame for coordinates. All coordinate frames copied by default. -s does not affect coordinate frames. =item --info Prints available variables, coordinates, compression levels, and maximum/minimum timesteps for data set and exits. =item --info-var Prints available variables, coordinates, compression levels, and maximum/minimum timesteps for a specific variable and exits. =item --version Prints version number and exits =item -h, --help Shows usage and description and exits. =back =head1 EXAMPLES The command... C ...will copy source.vdc and its associated dataset to the path/to/data directory. Only the variables P and T will be copied, only levels 0, 1 and 2, and timesteps 10 through 30 will be copied to the new dataset. This command... C ...will show the range of levels in source.vdf's dataset, as well as all timesteps, variables and coordinates. It will also list information specific to the variables bx and bz. =head1 SEE ALSO vdfcreate, wrf2vdf, I =head1 HISTORY Last updated on $Date$ ================================================ FILE: share/doc/man/vdcdump.pod ================================================ =begin comment $Id$ =end comment =head1 NAME vdcdump - Outputs information about a VDC Database =head1 SYNOPSIS B [options] I B [-h] [-v] [-nc-order] -I =head1 DESCRIPTION B prints information about data stored in a VDC database, I. By default, it prints coordinates, dimensions, and user-defined attributes. Additional information pertaining to the VDC data format can be outputted with the -v verbose option. =head1 OPTIONS =over 4 =item -v Verbose output. Prints additional information specific to the VDC data format. =item -nc-order Reverses order of dimensions to match that of the NetCDF format (slowest to fastest varying). By default, dimensions are ordered from fastest to slowest varying. =head1 EXAMPLES C =head1 SEE ALSO I =head1 HISTORY Last updated on $Date$ ================================================ FILE: share/doc/man/wasp2raw.pod ================================================ =begin comment $Id$ =end comment =head1 NAME wasp2raw - Inverse transform a variable found in a NetCDF WASP file and store the results in output file as a raw binary array. =head1 SYNOPSIS B [options] I I =head1 DESCRIPTION B extracts a variable from the WASP file I, decompresses the variable (if compressed), and stores the results in the file indicated by I. The data are written as a contiguous array of unformatted binary floating point values. The X dimension varies fastest, followed by Y, then Z. Data are written at 32 bit precision in the native format of the machine where B is run. =head1 OPTIONS =over 4 =item -varname EnameE This option specifies name of the variable to extract. =item -lod EnE Compressed variables are stored with a finite number of fixed refinement levels determined by the number of compression ratios specified in the I file. By default the maximum refinement level is output. This option can be used to reduce the refinement level output. A value 0 implies coarsest, 1 => next refinement, and so on. The value -1 is synonymous with the highest refinement level available. =item -level ElevelE Compressed variables in a WASP file are represented by a multiresolution hierarchy. This option specifies which level in the hierarchy to extract the variable from. A value of 0, the default, indicates the coarsest level in hierarchy. A value of 1 implies the first refinement level, and so on. The special value, -1, is synonymous with the native data resolution, whatever level that may be. =item -nthreads EnE This option can be used to specify the number of execution threads to be employed when transforming data. The default value of I is 0, which causes the application to query the operating system to find the number of processors available, and then use that value. For most platformsthe number of processors available is the result of the system call, sysconf(_SC_NPROCESSORS_ONLN). =item -start EstartE A colon-delimited NetCDF style I coordinate vector used to select an offset into the array. This option together with the I<-count> option can be used to restrict output to a rectangular subset of the array. =item -count EcountE A colon-delimited NetCDF style I coordinate vector used to specify dimensions of a subset of the array to output. This option together with the I<-count> option can be used to restrict output to a rectangular subset of the array. =item -type EtypeE Primitive data type of the data to be output to I. Supported values are 'float32', 'float64', and 'int32'. =back =head1 EXAMPLES The command C would reconstruct the variable with name B from the file indicated by B, and write the results to the file B. The data would be extracted at their native grid resolution, and maximum refinement level. The command C would perform identically to the one above except that the coarsest approximation would be extracted for variable B. =head1 SEE ALSO waspcreate, raw2wasp I =head1 HISTORY Last updated on $Date$ ================================================ FILE: share/doc/man/waspcreate.pod ================================================ =begin comment $Id$ =end comment =head1 NAME waspcreate - Generate a WASP file =head1 SYNOPSIS B [options] [name:xtype:count[:dimname]+]+ =head1 DESCRIPTION B generates an empty NetCDF file, suitable for containing compressed arrays (NetCDF variables) following the WASP conventions. The resulting file contains the definitions of NetCDF dimensions, and 1D, 2D, and 3D variables that may subsequently be populated using, for example, the B command. Variable names, external storage type, and associated dimension names are specified by repeated instances of the pattern: [name:xtype:count[:dimname]+], defined as follows: =over 4 =item name The variable's name. Any string permitted by NetCDF. =item xtype A valid NetCDF external data type (e.g NC_FLOAT, NC_DOUBLE). =item ncdims The number of compressed dimensions. If the number of compressed dimensions is less than the total number of variable dimensions then compression will take place along only the I fastest-varying dimensions. If I is zero the variable will not be compressed. The maximum value for I is 3. =item [:dimname] A colon-seperated list of the variable's dimension names. The dimension names are specified in the order from slowest to fastest varying. The dimension names must be defined with the B<-dimlens> option. =back =head1 OPTIONS =over 4 =item -dimlens A Colon delimited list of dimension lengths. =item -dimnames A Colon delimited list of dimension names for the dimension lengths specified by I<-dimlens>. The number of elements specified by I<-dimlens> and I<-dimnames> must be identical. =item -help Print a usage statement and then exit. =item -help Print a usage statement and then exit. =item -ofile Specify an alternate NetCDF output file name. The default is to create a file names B. =item -wname Ewave_nameE Specify the name of the wavelet to use for the wavelet transform. Valid values are: bior1.1, bior1.3, bior1.5, bior2.2, bior2.4 ,bior2.6, bior2.8, bior3.1, bior3.3, bior3.5, bior3.7, bior3.9, bior4.4. The default is bior 4.4 (aka CDF 9/7). =back =head1 EXAMPLES The command C will create a file named test.nc containing the definition of a single compressed variable named 'temp', with dimensions 256x256x256. =head1 SEE ALSO raw2wasp, wasp2raw =head1 HISTORY Last updated on $Date$ ================================================ FILE: share/docker/centos7/Dockerfile ================================================ # To build: # docker image build -t centos7:1.0 . FROM centos:7.4.1708 MAINTAINER The CentOS Project CMD [ "/bin/bash" ] # Do not update yum! updating system libraries renders Vapor incompatible on older # CentOS versions, such as those run on Casper and Hera #RUN yum -y clean all \ # && yum -y clean metadata \ # && yum -y update RUN yum -y install epel-release \ && yum -y install dbus \ && yum -y install cmake3 \ && yum -y install make \ && yum -y install bsdtar \ && yum -y install gcc-c++ \ && yum -y install curl \ && yum -y install xz-devel \ && yum -y install git \ && yum -y install freeglut-devel \ # Aren't we supposed to be distributing libexpat in our third-party tar??? && yum -y install expat-devel \ && yum -y install libquadmath-devel \ && yum -y install python3-pip \ && yum -y install libXrender-devel \ && yum -y install libSM-devel \ && yum -y install fontconfig-devel \ && pip3 install gdown # All this to default to CMake3 RUN alternatives --install /usr/local/bin/cmake cmake /usr/bin/cmake 10 \ --slave /usr/local/bin/ctest ctest /usr/bin/ctest \ --slave /usr/local/bin/cpack cpack /usr/bin/cpack \ --slave /usr/local/bin/ccmake ccmake /usr/bin/ccmake \ --family cmake RUN alternatives --install /usr/local/bin/cmake cmake /usr/bin/cmake3 20 \ --slave /usr/local/bin/ctest ctest /usr/bin/ctest3 \ --slave /usr/local/bin/cpack cpack /usr/bin/cpack3 \ --slave /usr/local/bin/ccmake ccmake /usr/bin/ccmake3 \ --family cmake RUN mkdir -p /usr/local/VAPOR-Deps # Qt 5.12.4 #RUN fileid="1q9U5FJIvWLvwNbKLVluCiSH-uAnQVgU1" \ # Qt 5.13.2 #RUN fileid="1e7F3kDoKctBmB3NOF4dES2395oScb9_0" \ # Ospray RUN fileid="1S9DwySMnQrBuUUZGKolD__WQrjTmLgyn" \ && filename="/usr/local/VAPOR-Deps/2019-Aug-CentOS.tar.xz" \ && curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" > /dev/null \ && curl -Lb ./cookie \ "https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}" \ -o ${filename} RUN ls -lrth /usr/local/VAPOR-Deps/ #RUN bsdtar -xf /usr/local/VAPOR-Deps/2019-Aug-CentOS.tar.xz -C /usr/local/VAPOR-Deps RUN chown -R root:root /usr/local/VAPOR-Deps/2019-Aug-CentOS.tar.xz RUN chmod -R 777 /usr/local/VAPOR-Deps/2019-Aug-CentOS.tar.xz RUN bsdtar -xf /usr/local/VAPOR-Deps/2019-Aug-CentOS.tar.xz -C /usr/local/VAPOR-Deps RUN rm /usr/local/VAPOR-Deps/2019-Aug-CentOS.tar.xz RUN chown -R root:root /usr/local/VAPOR-Deps RUN chmod -R 777 /usr/local/VAPOR-Deps RUN git clone https://github.com/NCAR/VAPOR.git /root/project RUN chown -R root:root /root/project RUN chmod -R 777 /root/project RUN cp /root/project/site_files/site.NCAR /root/project/site.local \ RUN chown -R root:root /root/project RUN chmod -R 777 /root/project && mkdir -p /root/project/build RUN chown -R root:root /root/project RUN chmod -R 777 /root/project && export CMAKE_CXX_COMPILER=g++ \ && cd /root/project/build \ && cmake3 .. \ && make && pwd && ls && ls bin WORKDIR /root/project ================================================ FILE: share/docker/ubuntu18/Dockerfile ================================================ from ubuntu:18.04 ################################# # # # Vapor configuration and build # # # ################################# RUN apt-get update \ && apt-get install -y curl \ && apt-get install -y xz-utils \ && apt-get install -y git \ && apt-get install -y cmake \ && apt-get install -y g++ \ # need freglut3-dev due to error Could NOT find OpenGL (missing: OPENGL_gl_LIBRARY OPENGL_INCLUDE_DIR) # https://stackoverflow.com/questions/31170869/cmake-could-not-find-opengl-in-ubuntu && apt-get install -y freeglut3-dev \ # Aren't we supposed to be distributing libexpat in our third-party tar??? && apt-get install -y libexpat1-dev \ && apt-get install -y libglib2.0-0 \ && apt-get install -y libdbus-1-3 \ && apt-get install -y valgrind \ && apt-get install -y clang-tidy \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Acquire 3rd party libraries # RUN mkdir -p /usr/local/VAPOR-Deps RUN fileid="1v0AwfOnDsf8hMzBqg4OcEtcEyH5YpnIn" \ && filename="/usr/local/VAPOR-Deps/2019-Aug-Ubuntu.tar.xz" \ && curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" > /dev/null \ && curl -Lb ./cookie \ "https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}" \ -o ${filename} RUN chmod -R 777 /usr RUN chown -R root:root /usr RUN tar -xf /usr/local/VAPOR-Deps/2019-Aug-Ubuntu.tar.xz \ -C /usr/local/VAPOR-Deps \ && chown -R root:root /usr RUN chmod -R 777 /usr #RUN ls -lrth /usr/local/VAPOR-Deps/2019-Aug # Acquire smokeTest data # RUN mkdir -p /smokeTestData RUN fileid="1w8CLOohQuVrhcDbmIyU68whvqaoiCx9t" \ && filename="/tmp/smokeTestData.tar.gz" \ && curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" > /dev/null \ && curl -Lb ./cookie \ "https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}" \ -o ${filename} RUN tar -xf /tmp/smokeTestData.tar.gz \ -C /smokeTestData \ && chown -R root:root /smokeTestData RUN chmod -R 777 /smokeTestData RUN cd / \ && git clone https://github.com/NCAR/VAPOR.git /root/project \ && cd /root/project \ && cp site_files/site.NCAR site.local \ && mkdir build RUN cd /root/project/build \ && export CMAKE_CXX_COMPILER=g++ \ && cmake .. && make WORKDIR /root/project ================================================ FILE: share/examples/.vapor3_prefs ================================================ 0 2000 0 128 0 -1 1280 1024 0 2 2 4 4 C:\Vapor\vapor3-0Release\share\examples\\.vapor3_prefs . . . . . . 1 10 1 10 99 0 0 1 1 1 0 99 0 0 0 1 1 1 -1 0 /tmp/vapor_autosave.vs3 /tmp/vapor_autosave.vs3 /tmp/vaporLog.txt /tmp/vaporLog.txt ================================================ FILE: share/examples/.vapor_prefs ================================================ vaporAutosave.vss /tmp/vapor.003911.xml . . vaporlog.txt . . . ================================================ FILE: share/examples/NCL/USFilled.ncl ================================================ ; ; This NCL script generates a global, geo-referenced map image with color ; filled political boundaries. The resulting image can be correctly ; registered and displayed by vaporgui using the "Image" tab ; ; N.B. as of version 6.0 of NCL support for rendering to a raster ; image is limited. Hence, we have to render to postscript, and then ; rasterize the image. Getting the process right is somewhat tricky, ; and the reason for much of the complexity of this code. load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" begin wks_type = "ps" wks_type@wkForegroundColor = "white" wks = gsn_open_wks(wks_type,"temp") ; ; Set up some map resources. ; mpres = True ; ; Take up as much of viewport as possible. ; ; This is not really necessary since we're going to remove ; the white space later with "convert". ; mpres@vpXF = 0.0 mpres@vpYF = 1.0 mpres@vpWidthF = 1.0 mpres@vpHeightF = 1.0 ; ; The perimeter boarder is necessary so that later we can use ; "convert's", -trim option to remove PostScripts page margins ; mpres@gsnTickMarksOn = False mpres@mpPerimDrawOrder = "PostDraw" mpres@mpPerimLineColor = "blue" mpres@mpPerimOn = True ; ; Select the map projection. This must match the "+proj" option we ; use later when we call tiff2geotif. Note, an NCL CylindricalEquidistant ; projection is a "latlong" projection in tiff2geotiff speak ; mpres@mpProjection = "CylindricalEquidistant" mpres@mpLimitMode = "LatLon" ; ; Select the map database ; mpres@mpDataBaseVersion = "MediumRes" ; Use the high-res database mpres@mpDataSetName = "Earth..4" ; Use the high-res database mpres@mpDataResolution = "Fine" ; ; turn on country filling ; mpres@mpFillOn = True mpres@mpFillBoundarySets = "AllBoundaries" ; turn on country boundaries mpres@mpOutlineOn = True mpres@mpOutlineBoundarySets = "USStates" ; turn on country boundaries ; ; Specify the map coordinates. The whole world ; ; N.B. There is a bug in vaporgui that prevents true periodic boundaries. I.e ; MaxLon cannot equal MinLat + 360, for example ; mpres@mpMinLonF = -180.0 mpres@mpMaxLonF = -60.0 mpres@mpMinLatF = 15.0 mpres@mpMaxLatF = 80.0 map = gsn_csm_map(wks,mpres) ;---Close workstation (PS file) so we can convert to png delete(wks) ; ; Convert to png with no margins. You might need to increase ; the -density value if you increase the size of the image. ; cmd = "convert -trim -density 600 -compress lzw temp.ps temp.tif" system(cmd) ; ; Now insert the projection string into the tiff image. Note, the ; coordinates specified here should match those specified above ; cmd = "tiff2geotiff -4 +proj=latlong -n'-180.0 15.0 -60.0 80.0' temp.tif USFilled.tif" system(cmd) end ================================================ FILE: share/examples/NCL/USOutline.ncl ================================================ ; ; This NCL script generates a global, geo-referenced map image with color ; filled political boundaries. The resulting image can be correctly ; registered and displayed by vaporgui using the "Image" tab ; ; N.B. as of version 6.0 of NCL support for rendering to a raster ; image is limited. Hence, we have to render to postscript, and then ; rasterize the image. Getting the process right is somewhat tricky, ; and the reason for much of the complexity of this code. load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" begin wks_type = "ps" wks_type@wkForegroundColor = "white" wks = gsn_open_wks(wks_type,"temp") ; ; Set up some map resources. ; mpres = True ; ; Take up as much of viewport as possible. ; ; This is not really necessary since we're going to remove ; the white space later with "convert". ; mpres@vpXF = 0.0 mpres@vpYF = 1.0 mpres@vpWidthF = 1.0 mpres@vpHeightF = 1.0 ; ; The perimeter boarder is necessary so that later we can use ; "convert's", -trim option to remove PostScripts page margins ; mpres@gsnTickMarksOn = False mpres@mpPerimDrawOrder = "PostDraw" mpres@mpPerimLineColor = "blue" mpres@mpPerimOn = True ; ; Select the map projection. This must match the "+proj" option we ; use later when we call tiff2geotif. Note, an NCL CylindricalEquidistant ; projection is a "latlong" projection in tiff2geotiff speak ; mpres@mpProjection = "CylindricalEquidistant" mpres@mpLimitMode = "LatLon" ; ; Select the map database ; mpres@mpDataBaseVersion = "MediumRes" ; Use the high-res database mpres@mpDataSetName = "Earth..4" ; Use the high-res database mpres@mpDataResolution = "Fine" mpres@mpFillOn = False mpres@mpOutlineOn = True mpres@mpOutlineBoundarySets = "AllBoundaries" ; turn on country boundaries mpres@mpUSStateLineColor = "yellow" mpres@mpGeophysicalLineColor = "yellow" ; ; Specify the map coordinates. The whole world ; ; N.B. There is a bug in vaporgui that prevents true periodic boundaries. I.e ; MaxLon cannot equal MinLat + 360, for example ; mpres@mpMinLonF = -180.0 mpres@mpMaxLonF = -60.0 mpres@mpMinLatF = 15.0 mpres@mpMaxLatF = 80.0 map = gsn_csm_map(wks,mpres) ;---Close workstation (PS file) so we can convert to png delete(wks) ; ; Convert to png with no margins. You might need to increase ; the -density value if you increase the size of the image. ; cmd = "convert -trim -density 600 -compress lzw temp.ps temp.tif" system(cmd) ; ; Now insert the projection string into the tiff image. Note, the ; coordinates specified here should match those specified above ; cmd = "tiff2geotiff -4 +proj=latlong -n'-180.0 15.0 -60.0 80.0' temp.tif USOutline.tif" system(cmd) end ================================================ FILE: share/examples/NCL/WrfTestScripts.Notes ================================================ The following NCL scripts where taken directly from the WRF NCL-Examples page and adapted to output a geotiff image of their plot output: 1. wrf_cloud.ncl 2. wrf_Surface1.ncl 3. wrf_EtaLevels.ncl 4. wrf_pv.ncl 5. wrf_crossSection4.ncl Each was modified to: - output to a geotiff file - generate only one plot per time stamp (several originally iterated over a "level" and/or generated several distinct plots per time stamp - accept an optional command-line parameter to crop/nocrop at the plot frame in the resultant geotiff; plots are cropped by default ex. usage: ncl "cropPlot=False" wrf_cloud.ncl Typically these must be edited further to reflect the location of the WRF file(s) of interest. wrf_crossSection4.ncl produces plot that are vertical slices through the data. For these plots, only timestamps are placed into the resultant tiff file (i.e., there is no explicit georeferencing). ================================================ FILE: share/examples/NCL/worldFilled.ncl ================================================ ; ; This NCL script generates a global, geo-referenced map image with color ; filled political boundaries. The resulting image can be correctly ; registered and displayed by vaporgui using the "Image" tab ; ; N.B. as of version 6.0 of NCL support for rendering to a raster ; image is limited. Hence, we have to render to postscript, and then ; rasterize the image. Getting the process right is somewhat tricky, ; and the reason for much of the complexity of this code. load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" begin wks_type = "ps" wks_type@wkForegroundColor = "white" wks = gsn_open_wks(wks_type,"temp") ; ; Set up some map resources. ; mpres = True ; ; Take up as much of viewport as possible. ; ; This is not really necessary since we're going to remove ; the white space later with "convert". ; mpres@vpXF = 0.0 mpres@vpYF = 1.0 mpres@vpWidthF = 1.0 mpres@vpHeightF = 1.0 ; ; The perimeter boarder is necessary so that later we can use ; "convert's", -trim option to remove PostScripts page margins ; mpres@gsnTickMarksOn = False mpres@mpPerimDrawOrder = "PostDraw" mpres@mpPerimLineColor = "blue" mpres@mpPerimOn = True ; ; Select the map projection. This must match the "+proj" option we ; use later when we call tiff2geotif. Note, an NCL CylindricalEquidistant ; projection is a "latlong" projection in tiff2geotiff speak ; mpres@mpProjection = "CylindricalEquidistant" mpres@mpLimitMode = "LatLon" ; ; Select the map database ; mpres@mpDataBaseVersion = "MediumRes" ; Use the high-res database mpres@mpDataSetName = "Earth..4" ; Use the high-res database mpres@mpDataResolution = "Fine" ; ; turn on country filling ; mpres@mpFillOn = True mpres@mpFillBoundarySets = "National" ; turn on country boundaries mpres@mpFillAreaSpecifiers = (/"Mexico:states", "canada:states", "china:states", "australia:states", "brazil:states", "india:states", "united states:states" /) ; ; Specify the map coordinates. The whole world ; ; N.B. There is a bug in vaporgui that prevents true periodic boundaries. I.e ; MaxLon cannot equal MinLat + 360, for example ; mpres@mpMinLonF = -179.99 mpres@mpMaxLonF = 179.99 mpres@mpMinLatF = -89.99 mpres@mpMaxLatF = 89.99 map = gsn_csm_map(wks,mpres) ;---Close workstation (PS file) so we can convert to png delete(wks) ; ; Convert to png with no margins. You might need to increase ; the -density value if you increase the size of the image. ; cmd = "convert -trim -density 600 -compress lzw temp.ps temp.tif" system(cmd) ; ; Now insert the projection string into the tiff image. Note, the ; coordinates specified here should match those specified above ; cmd = "tiff2geotiff -4 +proj=latlong -n'-179.99 -89.99 179.99 89.99' temp.tif worldFilled.tif" system(cmd) end ================================================ FILE: share/examples/NCL/worldOutline.ncl ================================================ ; ; This NCL script generates a global, geo-referenced map image with color ; filled political boundaries. The resulting image can be correctly ; registered and displayed by vaporgui using the "Image" tab ; ; N.B. as of version 6.0 of NCL support for rendering to a raster ; image is limited. Hence, we have to render to postscript, and then ; rasterize the image. Getting the process right is somewhat tricky, ; and the reason for much of the complexity of this code. load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" begin wks_type = "ps" wks_type@wkForegroundColor = "white" wks = gsn_open_wks(wks_type,"temp") ; ; Set up some map resources. ; mpres = True ; ; Take up as much of viewport as possible. ; ; This is not really necessary since we're going to remove ; the white space later with "convert". ; mpres@vpXF = 0.0 mpres@vpYF = 1.0 mpres@vpWidthF = 1.0 mpres@vpHeightF = 1.0 ; ; The perimeter boarder is necessary so that later we can use ; "convert's", -trim option to remove PostScripts page margins ; mpres@gsnTickMarksOn = False mpres@mpPerimDrawOrder = "PostDraw" mpres@mpPerimLineColor = "blue" mpres@mpPerimOn = True ; ; Select the map projection. This must match the "+proj" option we ; use later when we call tiff2geotif. Note, an NCL CylindricalEquidistant ; projection is a "latlong" projection in tiff2geotiff speak ; mpres@mpProjection = "CylindricalEquidistant" mpres@mpLimitMode = "LatLon" ; ; Select the map database ; mpres@mpDataBaseVersion = "MediumRes" ; Use the high-res database mpres@mpDataSetName = "Earth..4" ; Use the high-res database mpres@mpDataResolution = "Fine" ; ; turn on boundaries ; mpres@mpFillOn = False ; apparently we need to turn off area fill mpres@mpOutlineOn = True mpres@mpOutlineBoundarySets = "National" ; turn on country boundaries mpres@mpOutlineSpecifiers = (/"Mexico:states", "canada:states", "china:states", "australia:states", "brazil:states", "india:states", "united states:states" /) ; ; Specify the map coordinates. The whole world ; ; N.B. There is a bug in vaporgui that prevents true periodic boundaries. I.e ; MaxLon cannot equal MinLat + 360, for example ; mpres@mpMinLonF = -179.99 mpres@mpMaxLonF = 179.99 mpres@mpMinLatF = -89.99 mpres@mpMaxLatF = 89.99 map = gsn_csm_map(wks,mpres) ;---Close workstation (PS file) so we can convert to png delete(wks) ; ; Convert to png with no margins. You might need to increase ; the -density value if you increase the size of the image. ; cmd = "convert -trim -density 600 -compress lzw temp.ps temp.tif" system(cmd) ; ; Now insert the projection string into the tiff image. Note, the ; coordinates specified here should match those specified above ; cmd = "tiff2geotiff -4 +proj=latlong -n'-179.99 -89.99 179.99 89.99' temp.tif worldOutline.tif" system(cmd) end ================================================ FILE: share/examples/NCL/wrf2geotiff.ncl ================================================ load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" ; Set this to true to save intermediate files... _wrf2geotiff_DEBUG = False ; Some symbolic constants (hopefully these don't collide with anything else!) _wrf2geotiff_LANDSCAPE = 6 _wrf2geotiff_PSMINXY = 0 _wrf2geotiff_PSMAXX = 612 ; 8.5" _wrf2geotiff_PSMAXY = 792 ; 11" _wrf2geotiff_GROWSIZE = 10 ; ------------------------------------------------------------------------------------ ; ; wrf2geotiff_open() ; ; Called once to prime the plot capture process. ; ; ; NOTE: at present, only postscript workstations are supported. We'd like to support ; either PS or PDF, but are currently lacking a means to split a multi-page plotfile ; into separate pages for PDF (Imagemagick's convert program introduces noise and minor ; translations per-page). ; undef("wrf2geotiff_open") function wrf2geotiff_open(wks) local class begin if (_wrf2geotiff_DEBUG .eq. True) then print("wrf2geotiff_open") end if ; make sure we're dealing with postscript... class = NhlClassName(wks) if (class.ne."psWorkstationClass") then print("wrf2geotiff_open(): Workstation type not PS") print("wrf2geotiff processes will fail") return False end if ; We create this "opaque" state variable that gets returned to the client code that then uses ; it on subsequent calls to this API. All of the per-plot state is kept in array attributes, which ; are sized initially and expand dynamically as needed. tcVar = True tcVar@numPlots = 0 if (class.eq."pdfWorkstationClass") then getvalues wks "wkPDFFileName": filename end getvalues else getvalues wks "wkPSFileName": filename end getvalues end if tcVar@plotFilename = filename tcVar@outputScale = 2 ; default scaling factor for tiff images made from postscript versions tcVar@disableGeoTags = False ; array attributes... tcVar@times = new(_wrf2geotiff_GROWSIZE, string) tcVar@orient = new(_wrf2geotiff_GROWSIZE, string) tcVar@proj4Str = new(_wrf2geotiff_GROWSIZE, string) tcVar@pageMinX = new(_wrf2geotiff_GROWSIZE, float) tcVar@pageMaxX = new(_wrf2geotiff_GROWSIZE, float) tcVar@pageMinY = new(_wrf2geotiff_GROWSIZE, float) tcVar@pageMaxY = new(_wrf2geotiff_GROWSIZE, float) tcVar@minLon = new(_wrf2geotiff_GROWSIZE, float) tcVar@maxLon = new(_wrf2geotiff_GROWSIZE, float) tcVar@minLat = new(_wrf2geotiff_GROWSIZE, float) tcVar@maxLat = new(_wrf2geotiff_GROWSIZE, float) tcVar@cropFrame = new(_wrf2geotiff_GROWSIZE, logical) return tcVar end ; -------------------------------------------------------------------- ; ; _wrf2geotiff_growArrays ; ; Intended as a private function; used to resize the array attributes that keep track of ; per-plot state. ; undef("_wrf2geotiff_growArrays") procedure _wrf2geotiff_growArrays(tcVar) local atts, i, currSize, newSize, tmp begin if (_wrf2geotiff_DEBUG .eq. True) then print("_wrf2geotiff_growArrays(): growing arrays sizes...") end if atts = getvaratts(tcVar) do i=0,dimsizes(atts)-1 currSize = dimsizes( tcVar@$atts(i)$ ) ; By design, anything that reports a dimsize of "1" is a scalar attribute, ; and we won't attempt to grow it. if (currSize .ne. 1) then newSize = currSize + _wrf2geotiff_GROWSIZE tmp = new(newSize, typeof( tcVar@$atts(i)$ )) tmp(0:currSize-1) = tcVar@$atts(i)$ delete(tcVar@$atts(i)$) tcVar@$atts(i)$ = tmp delete(tmp) ; very important to "clear" this for next time through the loop... end if end do end ; ------------------------------------------------------------------------------ ; ; _wrf2geotiff_getProj4Str() ; ; Intended as a private function; given a wrf filevariable, extracts the ; geographical projection information and returns it as a PROJ4 string. ; undef("_wrf2geotiff_getProj4Str") function _wrf2geotiff_getProj4Str(wrfFile) local proj, lon0, lat0, lat1, lat2, projStr, northSouth, stdLon, trueLat, poleLat begin proj = wrfFile@MAP_PROJ if (proj .eq. 1) then ; Lambert Conformal lon0 = " +lon_0=" + wrfFile@STAND_LON lat0 = " +lat_0=" + wrfFile@MOAD_CEN_LAT lat1 = " +lat_1=" + wrfFile@TRUELAT1 lat2 = " +lat_2=" + wrfFile@TRUELAT2 projStr = " +proj=lcc +ellps=sphere" + lon0 + lat0 + lat1 + lat2 return projStr end if if (proj .eq. 3) then ; Mercator latTs = " +lat_ts=" + wrfFile@TRUELAT1 lon0 = " +lon_0=" + wrfFile@STAND_LON projStr = " +proj=merc +ellps=sphere" + lon0 + latTs return projStr end if if (proj .eq. 2) then ; Polar Stereographic if (wrfFile@MOAD_CEN_LAT .lt. 0) then northSouth = " +lat_0=-90" else northSouth = " +lat_0=90" end if stdLon = " +lon_0=" + wrfFile@STAND_LON trueLat = " +lat_ts=" + wrfFile@TRUELAT1 projStr = " +proj=stere +ellps=sphere" + stdLon + northSouth + trueLat return projStr end if if (proj .eq. 6) then ; rotated Cassini ;: as of 4/29/2009, WRF files are not yet wired with these attributes. ;;poleLat = " +o_lat_p=" + wrfFile@POLE_LAT ;;poleLon = " +o_lon_p=" + wrfFile@POLE_LON ; Hardcode values for testing... poleLat = " +o_lat_p=50" poleLon = " +o_lon_p=180" lon0 = " +lon_0=" + wrfFile@STAND_LON projStr = " +proj=ob_tran +ellps=sphere +o_proj=cass " + poleLon + poleLat + lon0 return projStr end if print("wrf2geotiff: Unknown map projection: " + proj) print("wrf2geotiff: georeferencing will fail "); return "" end ; ---------------------------------------------------------------------------------- ; ; _wrf2geotiff_validateProj4String() ; ; Intended as a private function. Perhaps a sanity check on our assumptions by ; looping though the various proj4 strings collected during process, and verifying ; that they are all the same. A warning is printed if they are not, and in any case ; the first such instance is returned as a quoted string. ; undef("_wrf2geotiff_validateProj4String") function _wrf2geotiff_validateProj4String(tcVar) local quote, proj4Str begin quote = inttochar(34) if (tcVar@numPlots .eq. 0) then return " " end if proj4Str = tcVar@proj4Str(0) do i=1,tcVar@numPlots-1 if (tcVar@proj4Str(i) .ne. proj4Str) then print("WARNING: inconsistent projections across image collection: " + \ proj4Str + " --versus-- " + tcVar@proj4Str(i)) end if end do return quote + proj4Str + quote end ; -------------------------------------------------------------------- ; ; _wrf2geotiff_getDevVP() ; ; This function was contributed by Dave Brown (originally named get_dev_vp()). ; Gets the location of the viewport in a workstation-independent fashion. ; Intended as a private function. ; undef("_wrf2geotiff_getDevVP") function _wrf2geotiff_getDevVP(wks:graphic,plot:graphic) local class, vp, dc, orient, dvp begin vp = new(4,float) getvalues plot "vpXF" : vp(0) "vpYF" : vp(1) "vpWidthF" : vp(2) "vpHeightF" : vp(3) end getvalues dc = new(4,integer) orient = 0 class = NhlClassName(wks) if((class.eq."psWorkstationClass").or. \ (class.eq."pdfWorkstationClass")) then getvalues wks "wkDeviceLowerX" : dc(0) "wkDeviceLowerY" : dc(1) "wkDeviceUpperX" : dc(2) "wkDeviceUpperY" : dc(3) "wkOrientation" : orient end getvalues else if class .eq. "ncgmWorkstationClass" then dc(0) = 0 dc(1) = 0 dc(2) = 1 dc(3) = 1 else dc(0) = 0 dc(1) = 0 getvalues wks "wkVSWidthDevUnits" : dc(2) end getvalues dc(3) = dc(2) end if end if if (_wrf2geotiff_DEBUG .eq. True) then print(vp) print(dc) print(orient) end if dvp = new(4,float) if (orient .eq. 0) then dvp(0) = dc(0) + vp(0) * (dc(2) - dc(0)) dvp(1) = dc(1) + (vp(1) - vp(3)) * (dc(3) - dc(1)) dvp(2) = dc(0) + (vp(0) + vp(2)) * (dc(2) - dc(0)) dvp(3) = dc(1) + vp(1) * (dc(3) - dc(1)) else dvp(0) = dc(1) + (1.0 - vp(0)) * (dc(3) - dc(1)) dvp(1) = dc(0) + (vp(1) - vp(3)) * (dc(2) - dc(0)) dvp(2) = dc(1) + (1.0 - (vp(0) + vp(2))) * (dc(3) - dc(1)) dvp(3) = dc(0) + vp(1) * (dc(2) - dc(0)) end if if (_wrf2geotiff_DEBUG .eq. True) then print(dvp) end if dvp@orientation = orient return (dvp) end ; ------------------------------------------------------------------------------ ; ; wrf2geotiff_write() ; ; Called by client code on a per-plot basis. This method captures information about the ; plot in an opaque state-variable created by a call to "wrf2geotiff_open()". ; undef("wrf2geotiff_write") procedure wrf2geotiff_write(tcVar, wrfFile, time, wks:graphic, plot:graphic, crop:logical) local plotNum, currSizes, vp, xy, yf, width, height, xNDC, yNDC, xWorld, yWorld, slop begin if (_wrf2geotiff_DEBUG .eq. True) then print("wrf2geotiff_write") end if plotNum = tcVar@numPlots ; dereference this for convenient use below currSizes = dimsizes(tcVar@times) if (plotNum .ge. currSizes(0)) then _wrf2geotiff_growArrays(tcVar) end if ; get the location of the viewport on the page... vp = _wrf2geotiff_getDevVP(wks,plot) ; We want the page coords that correspond to LL,LR,UR,UL corners in ; world coordinates; this depends on orientation of the plot on the page. tcVar@orient(plotNum) = vp@orientation if (vp@orientation .eq. _wrf2geotiff_LANDSCAPE) then tcVar@pageMinX(plotNum) = vp(1) tcVar@pageMaxX(plotNum) = vp(3) tcVar@pageMinY(plotNum) = vp(2) tcVar@pageMaxY(plotNum) = vp(0) else tcVar@pageMinX(plotNum) = vp(0) ;min x tcVar@pageMaxX(plotNum) = vp(2) ;max x tcVar@pageMinY(plotNum) = vp(1) ;min y tcVar@pageMaxY(plotNum) = vp(3) ;max y end if ; get the world-coords of the view port. Note that if we use the viewport ; extremes exactly, ndctodata() fails. So we add some slop to make sure the ; values passed in are inside the viewport. OBVIOUSLY A STOP-GAP MEASURE! getvalues plot "vpXF": xf; "vpYF": yf; "vpWidthF": width; "vpHeightF": height; end getvalues slop = .0000005 ; NOTE: one more decimal-place right is too much xNDC = (/ xf+slop, xf+width-slop, xf+width-slop, xf+slop /) yNDC = (/ yf-slop, yf-slop, yf-height+slop, yf-height+slop /) xWorld = new(dimsizes(xNDC), float) yWorld = new(dimsizes(yNDC), float) ndctodata(plot, xNDC, yNDC, xWorld, yWorld) tcVar@minLon(plotNum) = xWorld(3) tcVar@maxLon(plotNum) = xWorld(1) tcVar@minLat(plotNum) = yWorld(3) tcVar@maxLat(plotNum) = yWorld(1) tcVar@proj4Str(plotNum) = _wrf2geotiff_getProj4Str(wrfFile) tcVar@times(plotNum) = time tcVar@cropFrame(plotNum) = crop tcVar@numPlots = plotNum + 1 end ; ------------------------------------------------------------------------------ ; ; wrf2geotiff_setOutputScale() ; ; Called by client code to change the default scale-factor for the tiff images. ; The default is 2-times the resolution of the postscript image. ; undef("wrf2geotiff_setOutputScale") procedure wrf2geotiff_setOutputScale(tcVar, scaleFactor:float) begin tcVar@outputScale = scaleFactor end ; ------------------------------------------------------------------------------ ; ; wrf2geotiff_disableGeoTags() ; ; Called by client code to disable writing of geotags in the tiff image; only timestamps ; are written. This is useful for plots that are vertical cross-sections through the data. ; undef("wrf2geotiff_disableGeoTags") procedure wrf2geotiff_disableGeoTags(tcVar) begin tcVar@disableGeoTags = True end ; -------------------------------------------------------------------- ; ; wrf2geotiff_close() ; ; Called by client code after all plots have been captured and/or sent to ; the workstation. Using the information contained in the opaque state variable ; "tcVar", the following tasks are performed: ; 1. splits a potentially multi-page plot file into separate pages ; 2. Converts each postscript page into a tiff file. ; 3. Computes georeferencing info for each tiff file. ; 4. Injects georeferencing and the timestamp into each tiff file ; 5. Copies individual geotiffs into one multi-image geotiff. ; ; NOTE: this function causes the workstation to be closed and the plot output ; to be flushed to the filesystem. ; undef("wrf2geotiff_close") procedure wrf2geotiff_close(tcVar, wks:graphic) local plotFile, outputScale, wksId, tmpfile, tmpfileRoot, cmd, outStrings, quote, numPages, i, rotation, \ cropStr, w, h, x, y, pageLX, pageRX, pageTY, pageBY, \ outFilesRoot, suffix, plotFileLen, chr, multiTiff, multiGTiff, dataFile, proj4String begin if (_wrf2geotiff_DEBUG .eq. True) then print("wrf2geotiff_close") print(tcVar) end if plotFile = tcVar@plotFilename outputScale = tcVar@outputScale ; generate a filename root for a set of tmp files, based on the workstation ID... getvalues wks "wkGksWorkId": wksId end getvalues ; We need to ensure the plotfile is closed before attempting to split it up; ; otherwise, the "psplit" command fails. destroy(wks) ; split the postscript plotfile into multiple pieces... tmpfileRoot = "/tmp/tiffcap" + wksId + "_" cmd = "psplit " + plotFile + " " + tmpfileRoot print(cmd) system(cmd) ;;; Attempts to use Imagemagick's tools to split PS file, or to perform operations ;;; on frames within a multi=page file have generally been unsuccessful (perhaps missing ;;; something?) ;;; tmpfileRoot = "/tmp/tiffcap" + wksId + "_" ;;; cmd = "convert -page letter +adjoin " + plotFile + " ps:" + tmpfileRoot + "%04d.ps" ;;; system(cmd) ; Container for the strings to be written to the vapor-data file... outStrings = new(tcVar@numPlots, string) quote = inttochar(34) numPages = tcVar@numPlots do i=0,numPages-1 ; ; pick up the next postscript page a convert to a tiff, rotating if necessary... ; tmpfile = tmpfileRoot + sprinti("%0.4i", i+1) rotation = 0 if (tcVar@orient(i) .ne. 0) then rotation = -90 end if cropStr = "" if (tcVar@cropFrame(i) .eq.True) then w = (tcVar@pageMaxX(i) - tcVar@pageMinX(i)) * outputScale h = (tcVar@pageMaxY(i) - tcVar@pageMinY(i)) * outputScale x = tcVar@pageMinX(i) * outputScale y = (_wrf2geotiff_PSMAXY - tcVar@pageMaxY(i)) * outputScale cropStr = " -crop " + w + "x" + h + "+" + x + "+" + y + " " end if ; Note the ordering of the -density and -crop arguments is important in older versions ; of Imagemagick (e.g., 6.0.7 04/20/08). As of vers. 6.2.8 06/10/08, the ordering does not ; matter. cmd = "convert -depth 8 -rotate " + rotation + " -density " + (72*outputScale) + " " + cropStr + " " cmd = cmd + " " + tmpfile + ".ps tiff:" + tmpfile + ".tiff" print(cmd) system(cmd) if (tcVar@cropFrame(i) .eq. True) then pageLX = 0. pageRX = 1. pageBY = 0. pageTY = 1. else ; compute "normalized" page coordinates of the plot corners... pageLX = tcVar@pageMinX(i) / _wrf2geotiff_PSMAXX pageRX = tcVar@pageMaxX(i) / _wrf2geotiff_PSMAXX pageBY = tcVar@pageMinY(i) / _wrf2geotiff_PSMAXY pageTY = tcVar@pageMaxY(i) / _wrf2geotiff_PSMAXY end if if (tcVar@disableGeoTags) then outStrings(i) = tcVar@times(i) else outStrings(i) = tcVar@times(i) + " " + tcVar@minLon(i) + " " + tcVar@minLat(i) + " " + \ tcVar@maxLon(i) + " " + tcVar@maxLat(i) + " " + pageLX + " " + pageBY + " " + \ pageRX + " " + pageTY end if end do ; need a filename root for naming several files in the following... outFilesRoot = plotFile suffix = indStrSubset(str_lower(plotFile), ".ps") ; furthermore, make sure our substring is indeed a suffix... plotFileLen = strlen(plotFile) if (.not.any(ismissing(suffix)) .and. ((plotFileLen-1) .eq. suffix(dimsizes(suffix)-1))) then ; a bit messy; is there a better way to do these string ops? chr = stringtocharacter(plotFile) outFilesRoot = charactertostring( chr(0:suffix(0)-1) ) end if multiTiff = outFilesRoot + "_temp.tiff" multiGTiff = outFilesRoot + ".tiff" dataFile = outFilesRoot + ".dat" ; append all the intermediate tiff files into one multi-image tiff... cmd = "convert -adjoin " + tmpfileRoot + "[0-9]*.tiff " + multiTiff print(cmd) system(cmd) ; write the georeferencing info into a temporary file... asciiwrite(dataFile, outStrings) ; call a custom utility to create a geotiff... if (tcVar@disableGeoTags) then cmd = "tiff2geotiff -M " + dataFile + " " + multiTiff + " " + multiGTiff else proj4String = _wrf2geotiff_validateProj4String(tcVar) cmd = "tiff2geotiff -4 " + proj4String + " -m " + dataFile + " " + \ multiTiff + " " + multiGTiff end if print(cmd) system(cmd) ; cleanup cmd = "rm -f " + tmpfileRoot + "[0-9]*.* " + dataFile + " " + multiTiff print(cmd) if (_wrf2geotiff_DEBUG .ne. True) then system(cmd) end if end ================================================ FILE: share/examples/NCL/wrf_CrossSection2.ncl ================================================ ; Example script to produce plots for a WRF real-data run, ; with the ARW coordinate dynamics option. ; Plot data on a cross section ; This script will plot data from a a given point A to point B ; Vertical coordinate is height load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" begin ; ; The WRF ARW input file. ; This needs to have a ".nc" appended, so just do it. a = addfile("./wrfout_d01_2000-01-24_12:00:00.nc","r") ; We generate plots, but what kind do we prefer? type = "x11" ; type = "pdf" ; type = "ps" ; type = "ncgm" wks = gsn_open_wks(type,"plt_CrossSection2") ; Set some basic resources res = True res@MainTitle = "REAL-TIME WRF" pltres = True ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; FirstTime = True times = wrf_user_list_times(a) ; get times in the file ntimes = dimsizes(times) ; number of times in the file mdims = getfilevardimsizes(a,"P") ; get some dimension sizes for the file nd = dimsizes(mdims) ;--------------------------------------------------------------- do it = 0,ntimes-1,2 ; TIME LOOP print("Working on time: " + times(it) ) res@TimeLabel = times(it) ; Set Valid time to use on plots tc = wrf_user_getvar(a,"tc",it) ; T in C rh = wrf_user_getvar(a,"rh",it) ; relative humidity z = wrf_user_getvar(a, "z",it) ; grid point height if ( FirstTime ) then ; get height info for labels zmin = 0. zmax = max(z)/1000. nz = floattoint(zmax/2 + 1) FirstTime = False end if ;--------------------------------------------------------------- do ip = 1, 3 ; we are doing 3 plots, specifying different start and end points opts = True ; setting start and end times plane = new(4,float) if(ip .eq. 1) then plane = (/ 40,81, 259,81 /) ; start x;y & end x;y point end if if(ip .eq. 2) then plane = (/ 130,1, 130,162 /) ; start x;y & end x;y point end if if(ip .eq. 3) then plane = (/ 49,1, 210,162 /) ; start x;y & end x;y point end if rh_plane = wrf_user_intrp3d(rh,z,"v",plane,0.,opts) tc_plane = wrf_user_intrp3d(tc,z,"v",plane,0.,opts) dim = dimsizes(rh_plane) ; Find the data span - for use in labels zspan = dim(0) ; Options for XY Plots opts_xy = res opts_xy@tiYAxisString = "Height (km)" opts_xy@AspectRatio = 0.75 opts_xy@cnMissingValPerimOn = True opts_xy@cnMissingValFillColor = 0 opts_xy@cnMissingValFillPattern = 11 opts_xy@tmYLMode = "Explicit" opts_xy@tmYLValues = fspan(0,zspan,nz) ; Create tick marks opts_xy@tmYLLabels = sprintf("%.1f",fspan(zmin,zmax,nz)) ; Create labels opts_xy@tiXAxisFontHeightF = 0.020 opts_xy@tiYAxisFontHeightF = 0.020 opts_xy@tmXBMajorLengthF = 0.02 opts_xy@tmYLMajorLengthF = 0.02 opts_xy@tmYLLabelFontHeightF = 0.015 opts_xy@PlotOrientation = tc_plane@Orientation ; Plotting options for RH opts_rh = opts_xy opts_rh@pmLabelBarOrthogonalPosF = -0.07 opts_rh@ContourParameters = (/ 10., 90., 10. /) opts_rh@cnFillOn = True opts_rh@cnFillColors = (/"White","White","White", \ "White","Chartreuse","Green", \ "Green3","Green4", \ "ForestGreen","PaleGreen4"/) ; Plotting options for Temperature opts_tc = opts_xy opts_tc@cnInfoLabelOrthogonalPosF = 0.00 opts_tc@ContourParameters = (/ 5. /) ; Get the contour info for the rh and temp contour_tc = wrf_contour(a,wks,tc_plane,opts_tc) contour_rh = wrf_contour(a,wks,rh_plane,opts_rh) ; MAKE PLOTS plot = wrf_overlays(a,wks,(/contour_rh,contour_tc/),pltres) ; Delete options and fields, so we don't have carry over delete(opts_tc) delete(opts_rh) delete(tc_plane) delete(rh_plane) end do ; make next cross section ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; end do ; END OF TIME LOOP end ================================================ FILE: share/examples/NCL/wrf_CrossSection2_Final.ncl ================================================ ; Example script to produce plots for a WRF real-data run, ; with the ARW coordinate dynamics option. ; Plot data on a cross section ; This script will plot data from a a given point A to point B ; Modified to produce only one vertical plot, in the X-Z plane ; at grid y-coordinate 84 ; Vertical coordinate is height ; From the "Using NCL with VAPOR to Visualize WRF-ARW data" ; tutorial. load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" ; Load the wrf2geotiff.ncl library from VAPOR installation: load "$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl" begin ; ; The WRF ARW input file. ; Use all the Jangmi typhoon files: wrffiles = systemfunc("ls wrfout_d02_2008-09-28*") numFiles = dimsizes(wrffiles) do i = 0, numFiles -1 wrffiles(i) = wrffiles(i)+".nc" end do inpFiles = addfiles(wrffiles,"r") ; We generate plots, but what kind do we prefer? ; type = "x11" ; type = "pdf" type = "ps" ; type = "ncgm" wks = gsn_open_wks(type,"plt_CrossSection2") ; Create the opaque pointer for wrf2geotiff: wrf2gtiff = wrf2geotiff_open(wks) ; Since this is a vertical plot, turn off georeferencing: wrf2geotiff_disableGeoTags(wrf2gtiff) ; Set some basic resources res = True res@MainTitle = "REAL-TIME WRF" pltres = True ; Control the frame advance manually: pltres@gsnFrame = False ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; FirstTime = True ; What times and how many time steps are in the data set? do ifile = 0, numFiles-1 ; LOOP OVER FILES a = inpFiles[ifile] times = wrf_user_list_times(a) ; get times in the file ntimes = dimsizes(times) ; number of times in the file mdims = getfilevardimsizes(a,"P") ; get some dimension sizes for the file nd = dimsizes(mdims) ;--------------------------------------------------------------- ; Modify time loop to loop over all times in the files: do it = 0,ntimes-1 ; TIME LOOP print("Working on time: " + times(it) ) res@TimeLabel = times(it) ; Set Valid time to use on plots tc = wrf_user_getvar(a,"tc",it) ; T in C rh = wrf_user_getvar(a,"rh",it) ; relative humidity z = wrf_user_getvar(a, "z",it) ; grid point height if ( FirstTime ) then ; get height info for labels zmin = 0. zmax = max(z)/1000. nz = floattoint(zmax/2 + 1) FirstTime = False end if ;--------------------------------------------------------------- ; Modify loop over plots to just do one plot ip = 1 ; Just do the one (constant y coord) plot opts = True ; setting start and end times plane = new(4,float) if(ip .eq. 1) then ; Modify start and end x coordinates to match WRF D02 grid size: ; The jangmi data is on a grid from 0 to 200 plane = (/ 0,84, 200,84 /) ; start x;y & end x;y point end if if(ip .eq. 2) then plane = (/ 130,1, 130,162 /) ; start x;y & end x;y point end if if(ip .eq. 3) then plane = (/ 49,1, 210,162 /) ; start x;y & end x;y point end if rh_plane = wrf_user_intrp3d(rh,z,"v",plane,0.,opts) tc_plane = wrf_user_intrp3d(tc,z,"v",plane,0.,opts) dim = dimsizes(rh_plane) ; Find the data span - for use in labels zspan = dim(0) ; Options for XY Plots opts_xy = res opts_xy@tiYAxisString = "Height (km)" opts_xy@AspectRatio = 0.75 opts_xy@cnMissingValPerimOn = True opts_xy@cnMissingValFillColor = 0 opts_xy@cnMissingValFillPattern = 11 opts_xy@tmYLMode = "Explicit" opts_xy@tmYLValues = fspan(0,zspan,nz) ; Create tick marks opts_xy@tmYLLabels = sprintf("%.1f",fspan(zmin,zmax,nz)) ; Create labels opts_xy@tiXAxisFontHeightF = 0.020 opts_xy@tiYAxisFontHeightF = 0.020 opts_xy@tmXBMajorLengthF = 0.02 opts_xy@tmYLMajorLengthF = 0.02 opts_xy@tmYLLabelFontHeightF = 0.015 opts_xy@PlotOrientation = tc_plane@Orientation ; Plotting options for RH opts_rh = opts_xy opts_rh@pmLabelBarOrthogonalPosF = -0.07 opts_rh@ContourParameters = (/ 10., 90., 10. /) opts_rh@cnFillOn = True opts_rh@cnFillColors = (/"White","White","White", \ "White","Chartreuse","Green", \ "Green3","Green4", \ "ForestGreen","darkorchid3"/) ; Plotting options for Temperature opts_tc = opts_xy opts_tc@cnInfoLabelOrthogonalPosF = 0.00 opts_tc@ContourParameters = (/ 5. /) ; Get the contour info for the rh and temp contour_tc = wrf_contour(a,wks,tc_plane,opts_tc) contour_rh = wrf_contour(a,wks,rh_plane,opts_rh) ; MAKE PLOTS plot = wrf_overlays(a,wks,(/contour_rh,contour_tc/),pltres) ; save the info for the geotiff, and end the frame. ; Do crop to bounds wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, True) frame(wks) ; Delete options and fields, so we don't have carry over delete(opts_tc) delete(opts_rh) delete(tc_plane) delete(rh_plane) ; Comment out the loop over ip: ; end do ; make next cross section ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; end do ; END OF TIME LOOP end do ; END OF FILE LOOP ; Close wrf2geotiff: wrf2geotiff_close(wrf2gtiff,wks) end ================================================ FILE: share/examples/NCL/wrf_CrossSection2_FirstMod.ncl ================================================ ; Example script to produce plots for a WRF real-data run, ; with the ARW coordinate dynamics option. ; Plot data on a cross section ; This script will plot data from a a given point A to point B ; Modified to produce only one vertical plot, in the X-Z plane ; at grid y-coordinate 84 ; Vertical coordinate is height ; From the "Using NCL with VAPOR to Visualize WRF-ARW data" ; tutorial. load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" begin ; ; The WRF ARW input file. ; Use all the Jangmi typhoon files: wrffiles = systemfunc("ls wrfout_d02_2008-09-28*") numFiles = dimsizes(wrffiles) do i = 0, numFiles -1 wrffiles(i) = wrffiles(i)+".nc" end do inpFiles = addfiles(wrffiles,"r") ; We generate plots, but what kind do we prefer? type = "x11" ; type = "pdf" ; type = "ps" ; type = "ncgm" wks = gsn_open_wks(type,"plt_CrossSection2") ; Set some basic resources res = True res@MainTitle = "REAL-TIME WRF" pltres = True ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; FirstTime = True ; What times and how many time steps are in the data set? do ifile = 0, numFiles-1 ; LOOP OVER FILES a = inpFiles[ifile] times = wrf_user_list_times(a) ; get times in the file ntimes = dimsizes(times) ; number of times in the file mdims = getfilevardimsizes(a,"P") ; get some dimension sizes for the file nd = dimsizes(mdims) ;--------------------------------------------------------------- ; Modify time loop to loop over all times in the files: do it = 0,ntimes-1 ; TIME LOOP print("Working on time: " + times(it) ) res@TimeLabel = times(it) ; Set Valid time to use on plots tc = wrf_user_getvar(a,"tc",it) ; T in C rh = wrf_user_getvar(a,"rh",it) ; relative humidity z = wrf_user_getvar(a, "z",it) ; grid point height if ( FirstTime ) then ; get height info for labels zmin = 0. zmax = max(z)/1000. nz = floattoint(zmax/2 + 1) FirstTime = False end if ;--------------------------------------------------------------- ; Modify loop over plots to just do one plot ip = 1 ; Just do the one (constant y coord) plot opts = True ; setting start and end times plane = new(4,float) if(ip .eq. 1) then ; Modify start and end x coordinates to match WRF D02 grid size: ; The jangmi data is on a grid from 0 to 200 plane = (/ 0,84, 200,84 /) ; start x;y & end x;y point end if if(ip .eq. 2) then plane = (/ 130,1, 130,162 /) ; start x;y & end x;y point end if if(ip .eq. 3) then plane = (/ 49,1, 210,162 /) ; start x;y & end x;y point end if rh_plane = wrf_user_intrp3d(rh,z,"v",plane,0.,opts) tc_plane = wrf_user_intrp3d(tc,z,"v",plane,0.,opts) dim = dimsizes(rh_plane) ; Find the data span - for use in labels zspan = dim(0) ; Options for XY Plots opts_xy = res opts_xy@tiYAxisString = "Height (km)" opts_xy@AspectRatio = 0.75 opts_xy@cnMissingValPerimOn = True opts_xy@cnMissingValFillColor = 0 opts_xy@cnMissingValFillPattern = 11 opts_xy@tmYLMode = "Explicit" opts_xy@tmYLValues = fspan(0,zspan,nz) ; Create tick marks opts_xy@tmYLLabels = sprintf("%.1f",fspan(zmin,zmax,nz)) ; Create labels opts_xy@tiXAxisFontHeightF = 0.020 opts_xy@tiYAxisFontHeightF = 0.020 opts_xy@tmXBMajorLengthF = 0.02 opts_xy@tmYLMajorLengthF = 0.02 opts_xy@tmYLLabelFontHeightF = 0.015 opts_xy@PlotOrientation = tc_plane@Orientation ; Plotting options for RH opts_rh = opts_xy opts_rh@pmLabelBarOrthogonalPosF = -0.07 opts_rh@ContourParameters = (/ 10., 90., 10. /) opts_rh@cnFillOn = True opts_rh@cnFillColors = (/"White","White","White", \ "White","Chartreuse","Green", \ "Green3","Green4", \ "ForestGreen","darkorchid3"/) ; Plotting options for Temperature opts_tc = opts_xy opts_tc@cnInfoLabelOrthogonalPosF = 0.00 opts_tc@ContourParameters = (/ 5. /) ; Get the contour info for the rh and temp contour_tc = wrf_contour(a,wks,tc_plane,opts_tc) contour_rh = wrf_contour(a,wks,rh_plane,opts_rh) ; MAKE PLOTS plot = wrf_overlays(a,wks,(/contour_rh,contour_tc/),pltres) ; Delete options and fields, so we don't have carry over delete(opts_tc) delete(opts_rh) delete(tc_plane) delete(rh_plane) ; Comment out the loop over ip: ; end do ; make next cross section ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; end do ; END OF TIME LOOP end do ; END OF FILE LOOP end ================================================ FILE: share/examples/NCL/wrf_EtaLevels.ncl ================================================ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Adapted from the script "wrf_EtaLevels.ncl" at: ;; http://www.mmm.ucar.edu/wrf/OnLineTutorial/Graphics/NCL/Examples/LEVELS_MODEL/wrf_EtaLevels.htm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Example script to produce plots for a WRF real-data run, ; with the ARW coordinate dynamics option. load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" load "$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl" begin ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Add your own data here.... ; ; The WRF ARW input file. ; This needs to have a ".nc" appended, so just do it. ;;;a = addfile("./wrfout_d01_2000-01-24_12:00:00.nc","r") wrffiles = systemfunc("ls ./HurricaneIKE/wrfout_d03_2008*") numFiles = dimsizes(wrffiles) do i=0,numFiles-1 wrffiles(i) = wrffiles(i) + ".nc" end do inpFiles = addfiles(wrffiles,"r") ; Output type must be postscript... type = "ps" wks = gsn_open_wks(type,"plt_EtaLevels") ; Do we want the Geotiffs cropped? if (.not.isdefined("cropPlot")) then cropPlot = True end if ; initialize our tiff-capture process... wrf2gtiff = wrf2geotiff_open(wks) ; Set some Basic Plot options res = True res@MainTitle = "REAL-TIME WRF" pltres = True pltres@FramePlot = False mpres = True mpres0 = True mpres0@mpGeophysicalLineColor = "Black" mpres0@mpNationalLineColor = "Black" mpres0@mpUSStateLineColor = "Black" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; loop over files... do ifile=0, numFiles-1 a = inpFiles[ifile] ; What times and how many time steps are in the data set? times = wrf_user_list_times(a) ; get times in the file ntimes = dimsizes(times) ; number of times in the file do it = 0,ntimes-1,2 ; TIME LOOP print("Working on time: " + times(it) ) res@TimeLabel = times(it) ; Set Valid time to use on plots ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; First get the variables we will need th = wrf_user_getvar(a,"theta",it) ; theta qv = wrf_user_getvar(a,"QVAPOR",it) ; Qv qv = qv*1000. qv@units = "g/kg" u = wrf_user_getvar(a,"ua",it) ; u averaged to mass points v = wrf_user_getvar(a,"va",it) ; v averaged to mass points spd = (u*u + v*v)^(0.5) ; speed in m/sec spd@description = "Wind Speed" spd@units = "m/s" u = u*1.94386 ; winds now in kts v = v*1.94386 ; winds now in kts u@units = "kts" v@units = "kts" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; dimsv = dimsizes(th) ; Get levels ;; original script looped over levels... ;;;do level =0,dimsv(0)-1,5 ; LOOP OVER LEVELS level = 9 display_level = level + 1 res@PlotLevelID = "Eta Level " + display_level ; Theta ;opts = res ;opts@cnLineColor = "Red" ;opts@cnInfoLabelOn = False ;opts@lbLabelsOn = False ;opts@ContourParameters = (/ 5.0 /) ;opts@gsnContourLineThicknessesScale = 2.0 ;contour = wrf_contour(a,wks,th(level,:,:),opts) ;plot = wrf_map_overlays(a,wks,(/contour/),pltres,mpres0) ;delete(opts) ; Qv ;opts = res ;opts@cnLineColor = "Blue" ;opts@cnFillOn = True ;opts@lbLabelsOn = False ;contour = wrf_contour(a,wks,qv(level,:,:),opts) ;plot = wrf_map_overlays(a,wks,(/contour/),pltres,mpres) ;delete(opts) ; Wind Vectors and Speed opts = res opts@ContourParameters = (/ 15., 60., 5. /) opts@cnFillOn = True contour = wrf_contour(a,wks,spd(level,:,:),opts) delete(opts) opts = res opts@FieldTitle = "Wind" ; Overwrite Field Title opts@NumVectors = 47 ; wind barb density vector = wrf_vector(a,wks,u(level,:,:),v(level,:,:),opts) delete(opts) plot = wrf_map_overlays(a,wks,(/contour, vector/),pltres,mpres) wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, cropPlot) frame(wks) ; Now that we are done drawing, draw the frame ;;;;end do ; END OF LEVEL LOOP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; end do ; END OF TIME LOOP end do ; END OF FILES LOOP wrf2geotiff_close(wrf2gtiff, wks) end ================================================ FILE: share/examples/NCL/wrf_Height.ncl ================================================ ; The following NCL script was copied from the WRF/NCL site: ; http://www.mmm.ucar.edu/wrf/OnLineTutorial/Graphics/NCL/NCL_examples.htm ; Example script to produce plots for a WRF real-data run, ; with the ARW coordinate dynamics option. ; Interpolating to specified height levels load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" begin ; ; The WRF ARW input file. ; This needs to have a ".nc" appended, so just do it. a = addfile("./wrfout_d01_2000-01-24_12:00:00.nc","r") ; We generate plots, but what kind do we prefer? type = "x11" ; type = "pdf" ; type = "ps" ; type = "ncgm" wks = gsn_open_wks(type,"plt_HeightLevel") ; Set some basic resources res = True res@MainTitle = "REAL-TIME WRF" res@Footer = False pltres = True mpres = True mpres@mpGeophysicalLineColor = "Black" mpres@mpNationalLineColor = "Black" mpres@mpUSStateLineColor = "Black" mpres@mpGridLineColor = "Black" mpres@mpLimbLineColor = "Black" mpres@mpPerimLineColor = "Black" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; What times and how many time steps are in the data set? times = wrf_user_list_times(a) ; get times in the file ntimes = dimsizes(times) ; number of times in the file ; The specific height levels that we want the data interpolated to. height_levels = (/ 250., 2000./) ; height levels to plot - in meter nlevels = dimsizes(height_levels) ; number of height levels ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; do it = 0,ntimes-1,2 ; TIME LOOP print("Working on time: " + times(it) ) res@TimeLabel = times(it) ; Set Valid time to use on plots ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; First get the variables we will need tc = wrf_user_getvar(a,"tc",it) ; T in C u = wrf_user_getvar(a,"ua",it) ; u averaged to mass points v = wrf_user_getvar(a,"va",it) ; v averaged to mass points p = wrf_user_getvar(a, "pressure",it) ; pressure is our vertical coordinate z = wrf_user_getvar(a, "z",it) ; grid point height rh = wrf_user_getvar(a,"rh",it) ; relative humidity ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; do level = 0,nlevels-1 ; LOOP OVER LEVELS height = height_levels(level) p_plane = wrf_user_intrp3d( p,z,"h",height,0.,False) tc_plane = wrf_user_intrp3d(tc,z,"h",height,0.,False) rh_plane = wrf_user_intrp3d(rh,z,"h",height,0.,False) u_plane = wrf_user_intrp3d( u,z,"h",height,0.,False) v_plane = wrf_user_intrp3d( v,z,"h",height,0.,False) u_plane = u_plane*1.94386 ; kts v_plane = v_plane*1.94386 ; kts u_plane@units = "kts" v_plane@units = "kts" ; Plotting options for T opts = res opts@cnLineColor = "Red" opts@ContourParameters = (/ 5.0 /) opts@cnInfoLabelOrthogonalPosF = 0.07 ; offset second label info opts@gsnContourLineThicknessesScale = 2.0 contour_tc = wrf_contour(a,wks,tc_plane,opts) delete(opts) ; Plotting options for Pressure opts = res opts@cnLineColor = "Blue" opts@gsnContourLineThicknessesScale = 3.0 contour_p = wrf_contour(a,wks,p_plane,opts) delete(opts) ; Plotting options for RH opts = res opts@cnFillOn = True opts@ContourParameters = (/ 10., 90., 10./) opts@cnFillColors = (/"White","White","White", \ "White","Chartreuse","Green",\ "Green3","Green4", \ "ForestGreen","PaleGreen4"/) contour_rh = wrf_contour(a,wks,rh_plane,opts) delete(opts) ; Plotting options for Wind Vectors opts = res opts@FieldTitle = "Wind" ; overwrite Field Title opts@NumVectors = 47 ; wind barb density vector = wrf_vector(a,wks,u_plane,v_plane,opts) delete(opts) ; MAKE PLOTS plot = wrf_map_overlays(a,wks,(/contour_rh,contour_tc,contour_p, \ vector/),pltres,mpres) end do ; END OF LEVEL LOOP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; end do ; END OF TIME LOOP end ================================================ FILE: share/examples/NCL/wrf_Height_Final.ncl ================================================ ; Example script to produce plots for a WRF real-data run, ; with the ARW coordinate dynamics option. ; Interpolating to specified height levels ; From the "Using NCL with VAPOR to Visualize WRF-ARW data" ; tutorial. load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" ; Load the wrf2geotiff library. ; The wrf2geotiff library is installed with VAPOR: load "$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl" begin ; ; The WRF ARW input file. ; This needs to have a ".nc" appended, so just do it. ; Create a list of all the WRF output files we are using ; from the typhoon Jangmi simulation: wrffiles = systemfunc("ls wrfout_d02_2008-09-28*") numFiles = dimsizes(wrffiles) do i = 0, numFiles-1 wrffiles(i) = wrffiles(i) + ".nc" end do inpFiles = addfiles(wrffiles,"r") ; We generate plots, but what kind do we prefer? ; When using wrf2geotiff, type must be ps ; type = "x11" ; type = "pdf" type = "ps" ; type = "ncgm" wks = gsn_open_wks(type,"plt_HeightLevel") ; Create the wrf2gtiff opaque pointer, which will ; be referenced in all geotiff changes wrf2gtiff = wrf2geotiff_open(wks) ; Set some basic resources res = True res@MainTitle = "REAL-TIME WRF" res@Footer = False ; For wrf2geotiff we need to control frame advance: pltres = True pltres@gsnFrame = False pltres = True mpres = True mpres@mpGeophysicalLineColor = "Black" mpres@mpNationalLineColor = "Black" mpres@mpUSStateLineColor = "Black" mpres@mpGridLineColor = "Black" mpres@mpLimbLineColor = "Black" mpres@mpPerimLineColor = "Black" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; What times and how many time steps are in the data set? do ifile = 0, numFiles-1 ; LOOP OVER FILES a = inpFiles[ifile] times = wrf_user_list_times(a) ; get times in the file ntimes = dimsizes(times) ; number of times in the file ; The specific height levels that we want the data interpolated to. ; We use height of 5000m in the plot for VAPOR ; That height is near the top of the typhoon height_levels = (/ 250., 5000./) ; height levels to plot - in meter nlevels = dimsizes(height_levels) ; number of height levels ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Modify the time loop to include all time steps, not just every odd one do it = 0,ntimes-1 ; TIME LOOP print("Working on time: " + times(it) ) res@TimeLabel = times(it) ; Set Valid time to use on plots ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; First get the variables we will need tc = wrf_user_getvar(a,"tc",it) ; T in C u = wrf_user_getvar(a,"ua",it) ; u averaged to mass points v = wrf_user_getvar(a,"va",it) ; v averaged to mass points p = wrf_user_getvar(a, "pressure",it) ; pressure is our vertical coordinate z = wrf_user_getvar(a, "z",it) ; grid point height rh = wrf_user_getvar(a,"rh",it) ; relative humidity ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Modify loop over level to just do one level = 1 level = 1 ; just one level for the georeferenced plot height = height_levels(level) p_plane = wrf_user_intrp3d( p,z,"h",height,0.,False) tc_plane = wrf_user_intrp3d(tc,z,"h",height,0.,False) rh_plane = wrf_user_intrp3d(rh,z,"h",height,0.,False) u_plane = wrf_user_intrp3d( u,z,"h",height,0.,False) v_plane = wrf_user_intrp3d( v,z,"h",height,0.,False) u_plane = u_plane*1.94386 ; kts v_plane = v_plane*1.94386 ; kts u_plane@units = "kts" v_plane@units = "kts" ; Plotting options for T opts = res opts@cnLineColor = "Red" opts@ContourParameters = (/ 5.0 /) opts@cnInfoLabelOrthogonalPosF = 0.07 ; offset second label info opts@gsnContourLineThicknessesScale = 2.0 contour_tc = wrf_contour(a,wks,tc_plane,opts) delete(opts) ; Plotting options for Pressure opts = res opts@cnLineColor = "Blue" opts@gsnContourLineThicknessesScale = 3.0 contour_p = wrf_contour(a,wks,p_plane,opts) delete(opts) ; Plotting options for RH opts = res opts@cnFillOn = True opts@ContourParameters = (/ 10., 90., 10./) opts@cnFillColors = (/"White","White","White", \ "White","Chartreuse","Green",\ "Green3","Green4", \ "ForestGreen","darkorchid3"/) contour_rh = wrf_contour(a,wks,rh_plane,opts) delete(opts) ; Plotting options for Wind Vectors opts = res opts@FieldTitle = "Wind" ; overwrite Field Title opts@NumVectors = 47 ; wind barb density vector = wrf_vector(a,wks,u_plane,v_plane,opts) delete(opts) ; MAKE PLOTS plot = wrf_map_overlays(a,wks,(/contour_rh,contour_tc,contour_p, \ vector/),pltres,mpres) ; capture plot georeferencing information ; then change the frame ; Don’t crop (leave annotation intact) wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, False) frame(wks) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; end do ; END OF TIME LOOP end do ; END OF LEVEL LOOP ; Call wrf2geotiff_close at the end wrf2geotiff_close(wrf2gtiff, wks) end ================================================ FILE: share/examples/NCL/wrf_Height_FirstMod.ncl ================================================ ; Example script to produce plots for a WRF real-data run, ; with the ARW coordinate dynamics option. ; Interpolating to specified height levels ; From the "Using NCL with VAPOR to Visualize WRF-ARW data" ; tutorial. load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" begin ; ; The WRF ARW input file. ; This needs to have a ".nc" appended, so just do it. ; Create a list of all the WRF output files we are using ; from the typhoon Jangmi simulation: wrffiles = systemfunc("ls wrfout_d02_2008-09-28*") numFiles = dimsizes(wrffiles) do i = 0, numFiles-1 wrffiles(i) = wrffiles(i) + ".nc" end do inpFiles = addfiles(wrffiles,"r") ; We generate plots, but what kind do we prefer? type = "x11" ; type = "pdf" ; type = "ps" ; type = "ncgm" wks = gsn_open_wks(type,"plt_HeightLevel") ; Set some basic resources res = True res@MainTitle = "REAL-TIME WRF" res@Footer = False pltres = True mpres = True mpres@mpGeophysicalLineColor = "Black" mpres@mpNationalLineColor = "Black" mpres@mpUSStateLineColor = "Black" mpres@mpGridLineColor = "Black" mpres@mpLimbLineColor = "Black" mpres@mpPerimLineColor = "Black" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; What times and how many time steps are in the data set? do ifile = 0, numFiles-1 ; LOOP OVER FILES a = inpFiles[ifile] times = wrf_user_list_times(a) ; get times in the file ntimes = dimsizes(times) ; number of times in the file ; The specific height levels that we want the data interpolated to. ; We use height of 5000m in the plot for VAPOR ; That height is near the top of the typhoon height_levels = (/ 250., 5000./) ; height levels to plot - in meter nlevels = dimsizes(height_levels) ; number of height levels ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Modify the time loop to include all time steps, not just every odd one do it = 0,ntimes-1 ; TIME LOOP print("Working on time: " + times(it) ) res@TimeLabel = times(it) ; Set Valid time to use on plots ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; First get the variables we will need tc = wrf_user_getvar(a,"tc",it) ; T in C u = wrf_user_getvar(a,"ua",it) ; u averaged to mass points v = wrf_user_getvar(a,"va",it) ; v averaged to mass points p = wrf_user_getvar(a, "pressure",it) ; pressure is our vertical coordinate z = wrf_user_getvar(a, "z",it) ; grid point height rh = wrf_user_getvar(a,"rh",it) ; relative humidity ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Modify loop over level to just do one level = 1 level = 1 ; just one level for the georeferenced plot height = height_levels(level) p_plane = wrf_user_intrp3d( p,z,"h",height,0.,False) tc_plane = wrf_user_intrp3d(tc,z,"h",height,0.,False) rh_plane = wrf_user_intrp3d(rh,z,"h",height,0.,False) u_plane = wrf_user_intrp3d( u,z,"h",height,0.,False) v_plane = wrf_user_intrp3d( v,z,"h",height,0.,False) u_plane = u_plane*1.94386 ; kts v_plane = v_plane*1.94386 ; kts u_plane@units = "kts" v_plane@units = "kts" ; Plotting options for T opts = res opts@cnLineColor = "Red" opts@ContourParameters = (/ 5.0 /) opts@cnInfoLabelOrthogonalPosF = 0.07 ; offset second label info opts@gsnContourLineThicknessesScale = 2.0 contour_tc = wrf_contour(a,wks,tc_plane,opts) delete(opts) ; Plotting options for Pressure opts = res opts@cnLineColor = "Blue" opts@gsnContourLineThicknessesScale = 3.0 contour_p = wrf_contour(a,wks,p_plane,opts) delete(opts) ; Plotting options for RH opts = res opts@cnFillOn = True opts@ContourParameters = (/ 10., 90., 10./) opts@cnFillColors = (/"White","White","White", \ "White","Chartreuse","Green",\ "Green3","Green4", \ "ForestGreen","darkorchid3"/) contour_rh = wrf_contour(a,wks,rh_plane,opts) delete(opts) ; Plotting options for Wind Vectors opts = res opts@FieldTitle = "Wind" ; overwrite Field Title opts@NumVectors = 47 ; wind barb density vector = wrf_vector(a,wks,u_plane,v_plane,opts) delete(opts) ; MAKE PLOTS plot = wrf_map_overlays(a,wks,(/contour_rh,contour_tc,contour_p, \ vector/),pltres,mpres) ; comment out the end of the level loop: ;end do ; END OF LEVEL LOOP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; end do ; END OF TIME LOOP ; End loop over files that we introduced: end do ; END OF LEVEL LOOP end ================================================ FILE: share/examples/NCL/wrf_Precip.ncl ================================================ ; Example script to produce plots for a WRF real-data run, ; with the ARW coordinate dynamics option. load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" begin ; ; The WRF ARW input file. ; This needs to have a ".nc" appended, so just do it. a = addfile("./wrfout_d01_2000-01-24_12:00:00.nc","r") ; We generate plots, but what kind do we prefer? type = "x11" type = "pdf" ; type = "ps" ; type = "ncgm" wks = gsn_open_wks(type,"plt_Precip") ; Set some basic resources res = True res@MainTitle = "REAL-TIME WRF" pltres = True mpres = True mpres@mpGeophysicalLineColor = "Black" mpres@mpNationalLineColor = "Black" mpres@mpUSStateLineColor = "Black" mpres@mpGridLineColor = "Black" mpres@mpLimbLineColor = "Black" mpres@mpPerimLineColor = "Black" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; What times and how many time steps are in the data set? FirstTime = True times = wrf_user_list_times(a) ; get times in the file ntimes = dimsizes(times) ; number of times in the file ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; do it = 0,ntimes-1,2 ; TIME LOOP print("Working on time: " + times(it) ) if (FirstTime) then ; Save some times for tracking tendencies times_sav = times(it) end if res@TimeLabel = times(it) ; Set Valid time to use on plots ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; First get the variables we will need slp = wrf_user_getvar(a,"slp",it) ; slp wrf_smooth_2d( slp, 3 ) ; smooth slp ; Get non-convective, convective and total precipitation ; Calculate tendency values rain_exp = wrf_user_getvar(a,"RAINNC",it) rain_con = wrf_user_getvar(a,"RAINC",it) rain_tot = rain_exp + rain_con rain_tot@description = "Total Precipitation" if( FirstTime ) then if ( it .eq. 0 ) then rain_exp_save = rain_exp rain_con_save = rain_con rain_tot_save = rain_tot else rain_exp_save = wrf_user_getvar(a,"RAINNC",it-1) rain_con_save = wrf_user_getvar(a,"RAINC",it-1) rain_tot_save = rain_exp_save + rain_con_save FirstTime = False times_sav = times(it-1) end if end if rain_exp_tend = rain_exp - rain_exp_save rain_con_tend = rain_con - rain_con_save rain_tot_tend = rain_tot - rain_tot_save rain_exp_tend@description = "Explicit Precipitation Tendency" rain_con_tend@description = "Param Precipitation Tendency" rain_tot_tend@description = "Precipitation Tendency" ; Bookkeeping, just to allow the tendency at the next time step rain_exp_save = rain_exp rain_con_save = rain_con rain_tot_save = rain_tot ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if( .not. FirstTime ) then ; We will skip the first time ; Plotting options for Sea Level Pressure opts_psl = res opts_psl@ContourParameters = (/ 900., 1100., 2. /) opts_psl@cnLineColor = "Blue" opts_psl@cnInfoLabelOn = False opts_psl@cnLineLabelFontHeightF = 0.01 opts_psl@cnLineLabelPerimOn = False opts_psl@gsnContourLineThicknessesScale = 1.5 contour_psl = wrf_contour(a,wks,slp,opts_psl) delete(opts_psl) ; Plotting options for Precipitation opts_r = res opts_r@UnitLabel = "mm" opts_r@cnLevelSelectionMode = "ExplicitLevels" opts_r@cnLevels = (/ .1, .2, .4, .8, 1.6, 3.2, 6.4, \ 12.8, 25.6, 51.2, 102.4/) opts_r@cnFillColors = (/"White","White","DarkOliveGreen1", \ "DarkOliveGreen3","Chartreuse", \ "Chartreuse3","Green","ForestGreen", \ "Yellow","Orange","Red","Violet"/) opts_r@cnInfoLabelOn = False opts_r@cnConstFLabelOn = False opts_r@cnFillOn = True ; Total Precipitation (color fill) contour_tot = wrf_contour(a,wks, rain_tot, opts_r) ; Precipitation Tendencies opts_r@SubFieldTitle = "from " + times_sav + " to " + times(it) contour_tend = wrf_contour(a,wks, rain_tot_tend,opts_r) ; total (color) contour_res = wrf_contour(a,wks,rain_exp_tend,opts_r) ; exp (color) opts_r@cnFillOn = False opts_r@cnLineColor = "Red4" contour_prm = wrf_contour(a,wks,rain_con_tend,opts_r) ; con (red lines) delete(opts_r) ; MAKE PLOTS ; Total Precipitation plot = wrf_map_overlays(a,wks,contour_tot,pltres,mpres) ; Total Precipitation Tendency + SLP plot = wrf_map_overlays(a,wks,(/contour_tend,contour_psl/),pltres,mpres) ; Non-Convective and Convective Precipiation Tendencies plot = wrf_map_overlays(a,wks,(/contour_res,contour_prm/),pltres,mpres) end if ; END IF FOR SKIPPING FIRST TIME ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; times_sav = times(it) FirstTime = False end do ; END OF TIME LOOP end ================================================ FILE: share/examples/NCL/wrf_Precip_Final.ncl ================================================ ; Example script to produce plots for a WRF real-data run, ; with the ARW coordinate dynamics option. ; From the "Using NCL with VAPOR to Visualize WRF-ARW data" ; tutorial. load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" ; load the wrf2geotiff library from the VAPOR distribution: load "$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl" begin ; ; The WRF ARW input file. ; This needs to have a ".nc" appended, so just do it. ; Instead of selecting one file, make a variable that has ; all the names of the WRF output files in it: ; a = addfile("wrfout_d02_2008-09-28_00.nc","r") wrffiles = systemfunc("ls wrfout_d02_2008-09-28*") numFiles = dimsizes(wrffiles) do i = 0, numFiles-1 wrffiles(i) = wrffiles(i)+".nc" end do inpFiles = addfiles(wrffiles,"r") ; We generate plots, but what kind do we prefer? ; For wrf2geotiff, the type MUST be ps ; type = "x11" ; type = "pdf" type = "ps" ; type = "ncgm" wks = gsn_open_wks(type,"plt_Precip") ; wrf2geotiff_open() creates the opaque pointer wrf2gtiff: wrf2gtiff = wrf2geotiff_open(wks) ; Set some basic resources res = True res@MainTitle = "REAL-TIME WRF" ; Following are needed for control of frame advance: pltres = True pltres@gsnFrame = False pltres = True mpres = True mpres@mpGeophysicalLineColor = "Black" mpres@mpNationalLineColor = "Black" mpres@mpUSStateLineColor = "Black" mpres@mpGridLineColor = "Black" mpres@mpLimbLineColor = "Black" mpres@mpPerimLineColor = "Black" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; What times and how many time steps are in the data set? FirstTime = True ; Make a loop over all the files: do ifile = 0,numFiles -1 a = inpFiles[ifile] times = wrf_user_list_times(a) ; get times in the file ntimes = dimsizes(times) ; number of times in the file ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Loop over all the times, not just the odd times: ; do it = 0,ntimes-1,2 ; TIME LOOP do it = 0, ntimes-1 ; Modified to do every time step print("Working on time: " + times(it) ) if (FirstTime) then ; Save some times for tracking tendencies times_sav = times(it) end if res@TimeLabel = times(it) ; Set Valid time to use on plots ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; First get the variables we will need slp = wrf_user_getvar(a,"slp",it) ; slp wrf_smooth_2d( slp, 3 ) ; smooth slp ; Get non-convective, convective and total precipitation ; Calculate tendency values rain_exp = wrf_user_getvar(a,"RAINNC",it) rain_con = wrf_user_getvar(a,"RAINC",it) rain_tot = rain_exp + rain_con rain_tot@description = "Total Precipitation" if( FirstTime ) then if ( it .eq. 0 ) then rain_exp_save = rain_exp rain_con_save = rain_con rain_tot_save = rain_tot else rain_exp_save = wrf_user_getvar(a,"RAINNC",it-1) rain_con_save = wrf_user_getvar(a,"RAINC",it-1) rain_tot_save = rain_exp_save + rain_con_save FirstTime = False times_sav = times(it-1) end if end if rain_exp_tend = rain_exp - rain_exp_save rain_con_tend = rain_con - rain_con_save rain_tot_tend = rain_tot - rain_tot_save rain_exp_tend@description = "Explicit Precipitation Tendency" rain_con_tend@description = "Param Precipitation Tendency" rain_tot_tend@description = "Precipitation Tendency" ; Bookkeeping, just to allow the tendency at the next time step rain_exp_save = rain_exp rain_con_save = rain_con rain_tot_save = rain_tot ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Don't skip the first time: we need an image at each time stamp ; This will result in a warning message on the first plot ; if( .not. FirstTime ) then ; We don’t skip the first time ; Plotting options for Sea Level Pressure opts_psl = res opts_psl@ContourParameters = (/ 900., 1100., 2. /) opts_psl@cnLineColor = "Blue" opts_psl@cnInfoLabelOn = False opts_psl@cnLineLabelFontHeightF = 0.01 opts_psl@cnLineLabelPerimOn = False opts_psl@gsnContourLineThicknessesScale = 1.5 contour_psl = wrf_contour(a,wks,slp,opts_psl) delete(opts_psl) ; Plotting options for Precipitation opts_r = res opts_r@UnitLabel = "mm" opts_r@cnLevelSelectionMode = "ExplicitLevels" opts_r@cnLevels = (/ .1, .2, .4, .8, 1.6, 3.2, 6.4, \ 12.8, 25.6, 51.2, 102.4/) opts_r@cnFillColors = (/"White","White","DarkOliveGreen1", \ "DarkOliveGreen3","Chartreuse", \ "Chartreuse3","Green","ForestGreen", \ "Yellow","Orange","Red","Violet"/) opts_r@cnInfoLabelOn = False opts_r@cnConstFLabelOn = False opts_r@cnFillOn = True ; Total Precipitation (color fill) contour_tot = wrf_contour(a,wks, rain_tot, opts_r) ; Precipitation Tendencies opts_r@SubFieldTitle = "from " + times_sav + " to " + times(it) contour_tend = wrf_contour(a,wks, rain_tot_tend,opts_r) ; total (color) contour_res = wrf_contour(a,wks,rain_exp_tend,opts_r) ; exp (color) opts_r@cnFillOn = False opts_r@cnLineColor = "Red4" contour_prm = wrf_contour(a,wks,rain_con_tend,opts_r) ; con (red lines) delete(opts_r) ; MAKE PLOTS ; Total Precipitation ; Don’t do this plot for geotiff: ; plot = wrf_map_overlays(a,wks,contour_tot,pltres,mpres) ; Total Precipitation Tendency + SLP ; Do just this one plot: plot = wrf_map_overlays(a,wks,(/contour_tend,contour_psl/),pltres,mpres) ; Then put it in geotiff ; Do crop the image to the domain bounds wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, True) ; The frame is needed between time steps after the wrf2geotiff_write frame(wks) ; Non-Convective and Convective Precipiation Tendencies ; plot = wrf_map_overlays(a,wks,(/contour_res,contour_prm/),pltres,mpres) ; end if ; END IF FOR SKIPPING FIRST TIME ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; times_sav = times(it) FirstTime = False end do ; END OF TIME LOOP end do ; END OF LOOP OVER FILES ; At the end, close the wrf2geotiff ; This is where the tiff writing takes place: wrf2geotiff_close(wrf2gtiff,wks) end ================================================ FILE: share/examples/NCL/wrf_Precip_FirstMod.ncl ================================================ ; Example script to produce plots for a WRF real-data run, ; with the ARW coordinate dynamics option. ; From the "Using NCL with VAPOR to Visualize WRF-ARW data" ; tutorial. load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" begin ; ; The WRF ARW input file. ; This needs to have a ".nc" appended, so just do it. ; Instead of selecting one file, make a variable that has ; all the names of the WRF output files in it: ; a = addfile("wrfout_d02_2008-09-28_00.nc","r") wrffiles = systemfunc("ls wrfout_d02_2008-09-28*") numFiles = dimsizes(wrffiles) do i = 0, numFiles-1 wrffiles(i) = wrffiles(i)+".nc" end do inpFiles = addfiles(wrffiles,"r") ; We generate plots, but what kind do we prefer? type = "x11" ; type = "pdf" ; type = "ps" ; type = "ncgm" wks = gsn_open_wks(type,"plt_Precip") ; Set some basic resources res = True res@MainTitle = "REAL-TIME WRF" pltres = True mpres = True mpres@mpGeophysicalLineColor = "Black" mpres@mpNationalLineColor = "Black" mpres@mpUSStateLineColor = "Black" mpres@mpGridLineColor = "Black" mpres@mpLimbLineColor = "Black" mpres@mpPerimLineColor = "Black" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; What times and how many time steps are in the data set? FirstTime = True ; Make a loop over all the files: do ifile = 0,numFiles -1 a = inpFiles[ifile] times = wrf_user_list_times(a) ; get times in the file ntimes = dimsizes(times) ; number of times in the file ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Loop over all the times, not just the odd times: ; do it = 0,ntimes-1,2 ; TIME LOOP do it = 0, ntimes-1 ; Modified to do every time step print("Working on time: " + times(it) ) if (FirstTime) then ; Save some times for tracking tendencies times_sav = times(it) end if res@TimeLabel = times(it) ; Set Valid time to use on plots ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; First get the variables we will need slp = wrf_user_getvar(a,"slp",it) ; slp wrf_smooth_2d( slp, 3 ) ; smooth slp ; Get non-convective, convective and total precipitation ; Calculate tendency values rain_exp = wrf_user_getvar(a,"RAINNC",it) rain_con = wrf_user_getvar(a,"RAINC",it) rain_tot = rain_exp + rain_con rain_tot@description = "Total Precipitation" if( FirstTime ) then if ( it .eq. 0 ) then rain_exp_save = rain_exp rain_con_save = rain_con rain_tot_save = rain_tot else rain_exp_save = wrf_user_getvar(a,"RAINNC",it-1) rain_con_save = wrf_user_getvar(a,"RAINC",it-1) rain_tot_save = rain_exp_save + rain_con_save FirstTime = False times_sav = times(it-1) end if end if rain_exp_tend = rain_exp - rain_exp_save rain_con_tend = rain_con - rain_con_save rain_tot_tend = rain_tot - rain_tot_save rain_exp_tend@description = "Explicit Precipitation Tendency" rain_con_tend@description = "Param Precipitation Tendency" rain_tot_tend@description = "Precipitation Tendency" ; Bookkeeping, just to allow the tendency at the next time step rain_exp_save = rain_exp rain_con_save = rain_con rain_tot_save = rain_tot ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Don't skip the first time: we need an image at each time stamp ; This will result in a warning message on the first plot ; if( .not. FirstTime ) then ; We don’t skip the first time ; Plotting options for Sea Level Pressure opts_psl = res opts_psl@ContourParameters = (/ 900., 1100., 2. /) opts_psl@cnLineColor = "Blue" opts_psl@cnInfoLabelOn = False opts_psl@cnLineLabelFontHeightF = 0.01 opts_psl@cnLineLabelPerimOn = False opts_psl@gsnContourLineThicknessesScale = 1.5 contour_psl = wrf_contour(a,wks,slp,opts_psl) delete(opts_psl) ; Plotting options for Precipitation opts_r = res opts_r@UnitLabel = "mm" opts_r@cnLevelSelectionMode = "ExplicitLevels" opts_r@cnLevels = (/ .1, .2, .4, .8, 1.6, 3.2, 6.4, \ 12.8, 25.6, 51.2, 102.4/) opts_r@cnFillColors = (/"White","White","DarkOliveGreen1", \ "DarkOliveGreen3","Chartreuse", \ "Chartreuse3","Green","ForestGreen", \ "Yellow","Orange","Red","Violet"/) opts_r@cnInfoLabelOn = False opts_r@cnConstFLabelOn = False opts_r@cnFillOn = True ; Total Precipitation (color fill) contour_tot = wrf_contour(a,wks, rain_tot, opts_r) ; Precipitation Tendencies opts_r@SubFieldTitle = "from " + times_sav + " to " + times(it) contour_tend = wrf_contour(a,wks, rain_tot_tend,opts_r) ; total (color) contour_res = wrf_contour(a,wks,rain_exp_tend,opts_r) ; exp (color) opts_r@cnFillOn = False opts_r@cnLineColor = "Red4" contour_prm = wrf_contour(a,wks,rain_con_tend,opts_r) ; con (red lines) delete(opts_r) ; MAKE PLOTS ; Total Precipitation ; Don’t do this plot for geotiff: ; plot = wrf_map_overlays(a,wks,contour_tot,pltres,mpres) ; Total Precipitation Tendency + SLP ; Do just this one plot: plot = wrf_map_overlays(a,wks,(/contour_tend,contour_psl/),pltres,mpres) ; Non-Convective and Convective Precipiation Tendencies ; plot = wrf_map_overlays(a,wks,(/contour_res,contour_prm/),pltres,mpres) ; end if ; END IF FOR SKIPPING FIRST TIME ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; times_sav = times(it) FirstTime = False end do ; END OF TIME LOOP end do ; END OF LOOP OVER FILES end ================================================ FILE: share/examples/NCL/wrf_Surface1.ncl ================================================ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Adapted from the script "wrf_Surface1.ncl" at: ;; http://www.mmm.ucar.edu/wrf/OnLineTutorial/Graphics/NCL/Examples/BASIC_SFC/wrf_Surface1.ncl ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Example script to produce plots for a WRF real-data run, ; with the ARW coordinate dynamics option. load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" load "$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl" begin ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Add your own data here.... ; ; The WRF ARW input file. ; This needs to have a ".nc" appended, so just do it. ;;;a = addfile("./wrfout_d01_2000-01-24_12:00:00.nc","r") wrffiles = systemfunc("ls ./HurricaneIKE/wrfout_d03_2008*") numFiles = dimsizes(wrffiles) do i=0,numFiles-1 wrffiles(i) = wrffiles(i) + ".nc" end do inpFiles = addfiles(wrffiles,"r") ; Output type must be postscript... type = "ps" wks = gsn_open_wks(type,"plt_Surface1") ; Do we want the Geotiffs cropped? if (.not.isdefined("cropPlot")) then cropPlot = True end if ; initialize our tiff-capture process... wrf2gtiff = wrf2geotiff_open(wks) ; Set some basic resources res = True res@MainTitle = "REAL-TIME WRF" pltres = True pltres@FramePlot = False ; Extremely important for geotiff output process mpres = True ; loop over files... do ifile = 0, numFiles-1 a = inpFiles[ifile] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; What times and how many time steps are in the data set? times = wrf_user_list_times(a) ; get times in the file ntimes = dimsizes(times) ; number of times in the file ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; do it = 0,ntimes-1,2 ; TIME LOOP print("Working on time: " + times(it) ) res@TimeLabel = times(it) ; Set Valid time to use on plots ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; First get the variables we will need slp = wrf_user_getvar(a,"slp",it) ; slp wrf_smooth_2d( slp, 3 ) ; smooth slp tc = wrf_user_getvar(a,"tc",it) ; 3D tc td = wrf_user_getvar(a,"td",it) ; 3D td u = wrf_user_getvar(a,"ua",it) ; 3D U at mass points v = wrf_user_getvar(a,"va",it) ; 3D V at mass points td2 = wrf_user_getvar(a,"td2",it) ; Td2 in C tc2 = wrf_user_getvar(a,"T2",it) ; T2 in Kelvin tc2 = tc2-273.16 ; T2 in C u10 = wrf_user_getvar(a,"U10",it) ; u at 10 m, mass point v10 = wrf_user_getvar(a,"V10",it) ; v at 10 m, mass point tf2 = 1.8*tc2+32. ; Turn temperature into Fahrenheit tf2@description = "Surface Temperature" tf2@units = "F" td_f = 1.8*td2+32. ; Turn temperature into Fahrenheit td_f@description = "Surface Dew Point Temp" td_f@units = "F" u10 = u10*1.94386 ; Turn wind into knots v10 = v10*1.94386 u10@units = "kts" v10@units = "kts" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Plotting options for T opts = res opts@cnFillOn = True opts@ContourParameters = (/ -20., 90., 5./) opts@gsnSpreadColorEnd = -3 ; End third from the last color in color map contour_tc = wrf_contour(a,wks,tf2,opts) delete(opts) ; Plotting options for Td opts = res opts@cnFillOn = True opts@cnLinesOn = True opts@cnLineLabelsOn = True opts@ContourParameters = (/ -20., 90., 5./) opts@cnLineLabelBackgroundColor = -1 opts@gsnSpreadColorEnd = -3 ; End third from the last color in color map contour_td = wrf_contour(a,wks,td_f,opts) delete(opts) ; Plotting options for SLP opts = res opts@cnLineColor = "Blue" opts@cnHighLabelsOn = True opts@cnLowLabelsOn = True opts@ContourParameters = (/ 900., 1100., 4. /) opts@cnLineLabelBackgroundColor = -1 opts@gsnContourLineThicknessesScale = 2.0 contour_psl = wrf_contour(a,wks,slp,opts) delete(opts) ; Plotting options for Wind Vectors opts = res opts@FieldTitle = "Wind" ; overwrite Field Title opts@NumVectors = 47 ; density of wind barbs vector = wrf_vector(a,wks,u10,v10,opts) delete(opts) ; MAKE PLOTS plot = wrf_map_overlays(a,wks,(/contour_tc,contour_psl,vector/),pltres,mpres) wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, cropPlot) frame(wks) ; Now that we are done drawing, draw the frame ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; end do ; END OF TIME LOOP end do ; END OF FILES LOOP wrf2geotiff_close(wrf2gtiff, wks) end ================================================ FILE: share/examples/NCL/wrf_cloud.ncl ================================================ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Adapted from the script "wrf_cloud.ncl" at: ;; http://www.mmm.ucar.edu/wrf/OnLineTutorial/Graphics/NCL/Examples/LEVELS_MODEL/wrf_Cloud.htm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Example script to produce plots for a WRF real-data run, ; with the ARW coordinate dynamics option. load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" ;load "./WRFUserARW.ncl" load "$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl" begin ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Add your own data here.... ; ; ; The WRF ARW input file. ; This needs to have a ".nc" appended, so just do it. ;;;;a = addfile("./wrfout_d03_2008-09-14_18:00:00.nc","r") wrffiles = systemfunc("ls ./HurricaneIKE/wrfout_d03_2008*") numFiles = dimsizes(wrffiles) do i=0,numFiles-1 wrffiles(i) = wrffiles(i) + ".nc" end do inpFiles = addfiles(wrffiles,"r") ; Do we want the Geotiffs cropped? if (.not.isdefined("cropPlot")) then cropPlot = True end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Output type must be postscript... type = "ps" wks = gsn_open_wks(type,"plt_Cloud") gsn_define_colormap(wks,"WhBlGrYeRe") ; overwrite the .hluresfile color map ; initialize our tiff-capture process... wrf2gtiff = wrf2geotiff_open(wks) ; Set some basic resources res = True res@MainTitle = "REAL-TIME WRF" mpres = True ; Map resources pltres = True ; Plot resources pltres@FramePlot = False ; Extremely important for geotiff output process ; Loop over files... do ifile = 0, numFiles-1 a = inpFiles[ifile] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; What times and how many time steps are in the data set? times = wrf_user_list_times(a) ; get times in the file ntimes = dimsizes(times) ; number of times in the file ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; do it = ntimes-1,ntimes-1 ; TIME LOOP print("Working on time: " + times(it) ) res@TimeLabel = times(it) ; Set Valid time to use on plots ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; First get the variables we will need ;; original script generated several different plots per timestep if(isfilevar(a,"QVAPOR")) qv = wrf_user_getvar(a,"QVAPOR",it) qv = qv*1000. qv@units = "g/kg" end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; original script looped over levels ;;;;do level = 0,24,5 ; LOOP OVER LEVELS level = 4 display_level = level + 1 opts = res opts@cnFillOn = True opts@gsnSpreadColors = False opts@PlotLevelID = "Eta Level " + display_level if (isvar("qv")) contour = wrf_contour(a,wks,qv(level,:,:),opts) plot = wrf_map_overlays(a,wks,(/contour/),pltres,mpres) wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, cropPlot) frame(wks) ; Now that we are done drawing, draw the frame delete(contour) end if delete(opts) ;;;;end do ; END OF LEVEL LOOP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; end do ; END OF TIME LOOP end do ; END OF FILE LOOP wrf2geotiff_close(wrf2gtiff, wks) end ================================================ FILE: share/examples/NCL/wrf_crossSection4.ncl ================================================ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Adapted from the script "wrf_CrossSection_4.ncl" at: ;; http://www.mmm.ucar.edu/wrf/OnLineTutorial/Graphics/NCL/Examples/CROSS_SECTION/wrf_CrossSection_4.ncl ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Example script to produce plots for a WRF real-data run, ; with the ARW coordinate dynamics option. ; Plot data on a cross section ; This script will plot data at a set angle through a specified point ; This script adds lon/lat info along X-axis load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" load "$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl" begin ; ; The WRF ARW input file. ; This needs to have a ".nc" appended, so just do it. ;;a = addfile("./wrfout_d01_2000-01-24_12:00:00.nc","r") wrffiles = systemfunc("ls ./HurricaneIKE/wrfout_d03_2008*") numFiles = dimsizes(wrffiles) do i=0,numFiles-1 wrffiles(i) = wrffiles(i) + ".nc" end do inpFiles = addfiles(wrffiles,"r") ; We generate plots, but what kind do we prefer? ; type = "x11" ; type = "pdf" type = "ps" ; type = "ncgm" wks = gsn_open_wks(type,"plt_CrossSection4") ; initialize our tiff-capture process... wrf2gtiff = wrf2geotiff_open(wks) ; These vertical cross sections make improper geotiffs; disable georeference in tiff-capture... wrf2geotiff_disableGeoTags(wrf2gtiff) ; Set some basic resources res = True res@MainTitle = "REAL-TIME WRF" res@Footer = False pltres = True pltres@FramePlot = False ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; FirstTime = True FirstTimeMap = True do ifile=0, numFiles-1 a = inpFiles[ifile] times = wrf_user_list_times(a) ; get times in the file ntimes = dimsizes(times) ; number of times in the file mdims = getfilevardimsizes(a,"P") ; get some dimension sizes for the file nd = dimsizes(mdims) xlat = wrf_user_getvar(a, "XLAT",0) xlon = wrf_user_getvar(a, "XLONG",0) ter = wrf_user_getvar(a, "HGT",0) ;--------------------------------------------------------------- do it = 0,ntimes-1,2 ; TIME LOOP print("Working on time: " + times(it) ) res@TimeLabel = times(it) ; Set Valid time to use on plots tc = wrf_user_getvar(a,"tc",it) ; T in C rh = wrf_user_getvar(a,"rh",it) ; relative humidity z = wrf_user_getvar(a, "z",it) ; grid point height if ( FirstTime ) then ; get height info for labels zmin = 0. zmax = 6. ; We are only interested in the first 6km nz = floattoint(zmax + 1) end if ;--------------------------------------------------------------- ;;; Original script made 3 cross-sectional slices per timestamp. ;;; For use in Vapor, we want all plots across all files to be the same type. ;;; Set "ip" appropriately to get the desired slice. ;;; do ip = 1, 3 ; we are doing 3 plots ;;; ; all with the pivot point (plane) in the center of the domain ;;; ; at angles 0, 45 and 90 ip=1 ; 90-degree slice ;ip=2 ; 0-degree slice ;ip=3 ; 45-degree slice ; ; | ; angle=0 is | ; | ; plane = new(2,float) plane = (/ mdims(nd-1)/2, mdims(nd-2)/2 /) ; pivot point is center of domain (x,y) opts = False if(ip .eq. 1) then angle = 90. X_plane = wrf_user_intrp2d(xlon,plane,angle,opts) X_desc = "longitude" end if if(ip .eq. 2) then angle = 0. X_plane = wrf_user_intrp2d(xlat,plane,angle,opts) X_desc = "latitude" end if if(ip .eq. 3) then angle = 45. X_plane = wrf_user_intrp2d(xlon,plane,angle,opts) X_desc = "longitude" end if rh_plane = wrf_user_intrp3d(rh,z,"v",plane,angle,opts) tc_plane = wrf_user_intrp3d(tc,z,"v",plane,angle,opts) ; Find the index where 6km is - only need to do this once if ( FirstTime ) then zz = wrf_user_intrp3d(z,z,"v",plane,angle,opts) b = ind(zz(:,0) .gt. zmax*1000. ) zmax_pos = b(0) - 1 if ( abs(zz(zmax_pos,0)-zmax*1000.) .lt. abs(zz(zmax_pos+1,0)-zmax*1000.) ) then zspan = b(0) - 1 else zspan = b(0) end if delete(zz) delete(b) FirstTime = False end if ; X-axis lables dimsX = dimsizes(X_plane) xmin = X_plane(0) xmax = X_plane(dimsX(0)-1) xspan = dimsX(0)-1 nx = floattoint( (xmax-xmin)/2 + 1) ;--------------------------------------------------------------- ; Options for XY Plots opts_xy = res opts_xy@tiXAxisString = X_desc opts_xy@tiYAxisString = "Height (km)" opts_xy@cnMissingValPerimOn = True opts_xy@cnMissingValFillColor = 0 opts_xy@cnMissingValFillPattern = 11 opts_xy@tmXTOn = False opts_xy@tmYROn = False opts_xy@tmXBMode = "Explicit" opts_xy@tmXBValues = fspan(0,xspan,nx) ; Create tick marks opts_xy@tmXBLabels = sprintf("%.1f",fspan(xmin,xmax,nx)) ; Create labels opts_xy@tmXBLabelFontHeightF = 0.015 opts_xy@tmYLMode = "Explicit" opts_xy@tmYLValues = fspan(0,zspan,nz) ; Create tick marks opts_xy@tmYLLabels = sprintf("%.1f",fspan(zmin,zmax,nz)) ; Create labels opts_xy@tiXAxisFontHeightF = 0.020 opts_xy@tiYAxisFontHeightF = 0.020 opts_xy@tmXBMajorLengthF = 0.02 opts_xy@tmYLMajorLengthF = 0.02 opts_xy@tmYLLabelFontHeightF = 0.015 opts_xy@PlotOrientation = tc_plane@Orientation ; Plotting options for RH opts_rh = opts_xy opts_rh@ContourParameters = (/ 10., 90., 10. /) opts_rh@pmLabelBarOrthogonalPosF = -0.1 opts_rh@cnFillOn = True opts_rh@cnFillColors = (/"White","White","White", \ "White","Chartreuse","Green", \ "Green3","Green4", \ "ForestGreen","PaleGreen4"/) ; Plotting options for Temperature opts_tc = opts_xy opts_tc@cnInfoLabelZone = 1 opts_tc@cnInfoLabelSide = "Top" opts_tc@cnInfoLabelPerimOn = True opts_tc@cnInfoLabelOrthogonalPosF = -0.00005 opts_tc@ContourParameters = (/ 5. /) ; Get the contour info for the rh and temp contour_tc = wrf_contour(a,wks,tc_plane(0:zmax_pos,:),opts_tc) contour_rh = wrf_contour(a,wks,rh_plane(0:zmax_pos,:),opts_rh) ;--------------------------------------------------------------- ; MAKE PLOTS if (FirstTimeMap) then lat_plane = wrf_user_intrp2d(xlat,plane,angle,opts) lon_plane = wrf_user_intrp2d(xlon,plane,angle,opts) mpres = True pltres = True pltres@FramePlot = False optsM = res optsM@NoHeaderFooter = True optsM@cnFillOn = True optsM@lbTitleOn = False ;;; contour = wrf_contour(a,wks,ter,optsM) ;;; plot = wrf_map_overlays(a,wks,(/contour/),pltres,mpres) lnres = True lnres@gsLineThicknessF = 3.0 lnres@gsLineColor = "Red" ;;; do ii = 0,dimsX(0)-2 ;;; gsn_polyline(wks,plot,(/lon_plane(ii),lon_plane(ii+1)/),(/lat_plane(ii),lat_plane(ii+1)/),lnres) ;;; end do ;;; wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, True) ;;; frame(wks) delete(lon_plane) delete(lat_plane) ;;???? pltres@FramePlot = True end if plot = wrf_overlays(a,wks,(/contour_rh,contour_tc/),pltres) ; plot x-section wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, True) frame(wks) ; Now that we are done drawing, draw the frame ; Delete options and fields, so we don't have carry over delete(opts_xy) delete(opts_tc) delete(opts_rh) delete(tc_plane) delete(rh_plane) delete(X_plane) ;;; end do ; make next cross section ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; FirstTimeMap = False end do ; END OF TIME LOOP end do ; END OF FILES LOOP wrf2geotiff_close(wrf2gtiff, wks) end ================================================ FILE: share/examples/NCL/wrf_pv.ncl ================================================ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Adapted from the script "wrf_pv.ncl" at: ;; http://www.mmm.ucar.edu/wrf/OnLineTutorial/Graphics/NCL/Examples/DIAGNOSTICS/wrf_pv.htm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Example script to produce Vorticity plots from WRF ARW model data ; November 2008 load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" load "$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl" begin ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Add your own data here.... ; ; The WRF ARW input file. ; This needs to have a ".nc" appended, so just do it. ;;;a = addfile("./wrfout_d01_2005-08-28_00.nc","r") wrffiles = systemfunc("ls ./HurricaneIKE/wrfout_d03_2008*") numFiles = dimsizes(wrffiles) do i=0,numFiles-1 wrffiles(i) = wrffiles(i) + ".nc" end do inpFiles = addfiles(wrffiles,"r") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Output type must be postscript... type = "ps" wks = gsn_open_wks(type,"plt_pv") ; Do we want the Geotiffs cropped? if (.not.isdefined("cropPlot")) then cropPlot = True end if ; initialize our tiff-capture process... wrf2gtiff = wrf2geotiff_open(wks) ; Set some basic resources res = True res@MainTitle = "REAL-TIME WRF" mpres = True pltres = True pltres@FramePlot = False ; Extremely important for geotiff output process ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; loop over files... do ifile = 0, numFiles-1 a = inpFiles[ifile] ; What times and how many time steps are in the data set? times = wrf_user_list_times(a) ; get times in the file ntimes = dimsizes(times) ; number of times in the file ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; do it = 0,ntimes-1,2 ; TIME LOOP print("Working on time: " + times(it) ) res@TimeLabel = times(it) ; Set Valid time to use on plots ; Get the data pvo = wrf_user_getvar(a,"pvo",it) avo = wrf_user_getvar(a,"avo",it) p = wrf_user_getvar(a,"pressure",it) ; Interpolate to pressure pv_plane = wrf_user_intrp3d(pvo,p,"h",300.,0,False) av_plane = wrf_user_intrp3d(avo,p,"h",500.,0,False) ; Plotting options opts = res opts@cnFillOn = True opts@gsnSpreadColorEnd = -3 ; End third from the last color in color map opts@ContourParameters = (/ 0., 100., 10./) ;; Original script generated two distinct plots per timestep... ;;contour_a = wrf_contour(a,wks,av_plane,opts) opts@ContourParameters = (/ 0., 5., 1./) contour = wrf_contour(a,wks,pv_plane,opts) delete(opts) ; MAKE PLOTS ;; Original script generated two distinct plots per timestep... ;;plot = wrf_map_overlays(a,wks,(/contour_a/),pltres,mpres) plot = wrf_map_overlays(a,wks,(/contour/),pltres,mpres) wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, cropPlot) frame(wks) ; Now that we are done drawing, draw the frame end do ; END OF TIME LOOP end do ; END OF FILES LOOP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; wrf2geotiff_close(wrf2gtiff, wks) end ================================================ FILE: share/examples/VDC/amr_ex.cpp ================================================ // // $Id$ // //*********************************************************************** // * // Copyright (C) 2006 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //*********************************************************************** // // File: amr.cpp // // Author: John Clyne // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: Thu Apr 9 11:42:00 MDT 2009 // // Description: This example demonstrates the construction of // a VDC AMR data set. The example data are synthesized by sampling // a regular Cartesian grid. Prior to executing this code a suitable // .vdf file must be created using the command: // // vdfcreate -gridtype block_amr -dimension NxNxN -bs // CellDimxCellDimxCellDim -level NLevels // -varnames ml:checker test.vdf // // where N, CellDim, and NLevels are the values defined below. For example: // // vdfcreate -gridtype block_amr -dimension 256x256x256 -bs // 8x8x8 -level 2 -varnames ml:checker test.vdf // // Once a .vdf file has been created, the example can be invoked with // the command: // // $VAPOR_HOME/bin/amr_ex test.vdf // // #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; // // Dimension of AMR grid if all cells are fully refined, creating // a rectilinear Cartesian grid. // const int N = 256; // // Dimension of AMR block. Must be at least 2. This restriction could // be relaxed if AMRData::ReGrid were modified. // const int CellDim = 8; // // Maximum number of refinement levels. Must be hardcoded to 2 in this example // const int NLevels = 2; // // Command line argument stuff // struct opt_t { OptionParser::Boolean_T help; OptionParser::Boolean_T debug; } opt; OptionParser::OptDescRec_T set_opts[] = {{"help", 0, "", "Print this message and exit"}, {"debug", 0, "", "Enable verbose debugging output"}, {NULL}}; OptionParser::Option_T get_options[] = {{"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {NULL}}; // // The marschner lobb function for synthesizing data // double marschner_lobb(double x, double y, double z, double alpha, double fm) { double pr; double r; double v; r = sqrt(x * x + y * y); pr = cos(2 * M_PI * fm * cos(M_PI * r / 2.0)); v = (1.0 - sin(M_PI * z / 2.0) + (alpha * (1.0 + pr))) / (2 * (1 + alpha)); return (v); } #define ALPHA (double)0.25 #define FM (double)6.0 float *make_marschner_lobb(int nx, int ny, int nz) { float *grid = new float[nx * ny * nz]; for (int z = 0; z < nz; z++) { for (int y = 0; y < ny; y++) { for (int x = 0; x < nx; x++) { double xf, yf, zf; xf = (x - nx / 2) * 2.0 / (double)(nx - 1.0); yf = (y - ny / 2) * 2.0 / (double)(ny - 1.0); zf = (z - nz / 2) * 2.0 / (double)(nz - 1.0); grid[x + (nx * y) + (nx * ny * z)] = (float)marschner_lobb(xf, yf, zf, ALPHA, FM); } } } return (grid); } // // another function for synthesizing data // #define ISODD(X) ((X) % 2) float *make_checker(int nx, int ny, int nz, int chksz) { float *grid = new float[nx * ny * nz]; for (int z = 0; z < nz; z++) { for (int y = 0; y < ny; y++) { for (int x = 0; x < nx; x++) { if (ISODD((x / chksz) + (y / chksz) + (z / chksz))) { grid[x + (nx * y) + (nx * ny * z)] = 1.0; } else { grid[x + (nx * y) + (nx * ny * z)] = 0.0; } } } } return (grid); } // // This function interpolates data on a 3D Cartesian grid using Nearest // Neighbor // float resample_grid_point(float *grid, double x, double y, double z) { int xi, yi, zi; double delta = 1.0 / (double)N; double start = delta / 2.0; xi = (int)rint((x - start) * (double)N); yi = (int)rint((y - start) * (double)N); zi = (int)rint((z - start) * (double)N); VAssert(xi >= 0 && xi < N); VAssert(yi >= 0 && yi < N); VAssert(zi >= 0 && zi < N); return (grid[zi * N * N + yi * N + xi]); } // // This function will write a single AMR variable to a Vapor Data // Collection (VDC) // const char *ProgName; void process_variable(AMRIO *amrio, AMRTree *tree, AMRData *amrdata, float *grid, const char *varname) { AMRTree::cid_t cellid; size_t cell_dim[] = {CellDim, CellDim, CellDim}; // // Treverse the AMR tree hierarchy. For each cell in the tree, whether // it is a leaf or internal node, we provide data by sampling // a function defined on a Cartesian grid. // bool first = true; while ((cellid = tree->GetNextCell(first)) >= 0) { first = false; double minu[3], maxu[3]; // Get the bounds of the cell (min and max extent) defined in // in user coordinates. In this example user coordinates run // from 0.0 to 1.0. // int rc = tree->GetCellBounds(cellid, minu, maxu); if (rc < 0) { cerr << ProgName << " : " << tree->GetErrMsg() << endl; exit(1); } // Get a pointer to a block of data associated with this cell. // float *block = amrdata->GetBlock(cellid); // For each grid point in the cell block assign a value // for (int k = 0; k < cell_dim[2]; k++) { for (int j = 0; j < cell_dim[1]; j++) { for (int i = 0; i < cell_dim[0]; i++) { double deltax = (maxu[0] - minu[0]) / (double)cell_dim[0]; double deltay = (maxu[1] - minu[1]) / (double)cell_dim[1]; double deltaz = (maxu[2] - minu[2]) / (double)cell_dim[2]; double startx = minu[0] + (deltax / 2.0); double starty = minu[1] + (deltay / 2.0); double startz = minu[2] + (deltaz / 2.0); block[k * cell_dim[0] * cell_dim[1] + j * cell_dim[0] + i] = resample_grid_point(grid, startx + i * deltax, starty + j * deltay, startz + k * deltaz); } } } } // // Write the data to the VDC giving it the name, 'varname' // if (amrio->OpenVariableWrite(0, varname, -1) < 0) { cerr << ProgName << " : " << amrio->GetErrMsg() << endl; exit(1); } if (amrio->VariableWrite(amrdata) < 0) { cerr << ProgName << " : " << amrio->GetErrMsg() << endl; exit(1); } if (amrio->CloseVariable() < 0) { cerr << ProgName << " : " << amrio->GetErrMsg() << endl; exit(1); } } int main(int argc, char **argv) { OptionParser op; const char * metafile; ProgName = Basename(argv[0]); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage : " << ProgName << " [options] metafile " << endl; op.PrintOptionHelp(stderr); exit(0); } if (argc != 2) { cerr << "Usage : " << ProgName << " [options] metafile " << endl; op.PrintOptionHelp(stderr); exit(1); } metafile = argv[1]; // Path to a suitably defined vdf file MyBase::SetErrMsgFilePtr(stderr); if (opt.debug) MyBase::SetDiagMsgFilePtr(stderr); // Create an AMRIO object to write the AMR grid to the VDC // AMRIO *amrio = new AMRIO(metafile); if (amrio->GetErrCode() != 0) { cerr << ProgName << " : " << amrio->GetErrMsg() << endl; exit(1); } // // Verify .vdf metafile was properly setup with vdfcreate command // const size_t *bs = amrio->GetBlockSize(); for (int i = 0; i < 3; i++) { if (bs[i] != CellDim) { cerr << ProgName << " : Invalid block size" << endl; exit(1); } } const size_t *dim = amrio->GetDimension(); for (int i = 0; i < 3; i++) { if (dim[i] != N) { cerr << ProgName << " : Invalid dimension : " << dim[i] << endl; exit(1); } } int nlevels = amrio->GetNumTransforms(); if (nlevels != NLevels) { cerr << ProgName << " : Invalid number of refinment levels" << endl; exit(1); } // The dimensions of the base level AMR mesh specified in blocks (cells) size_t basedim = (N / CellDim) >> NLevels; VAssert(basedim >= 5); // we' going to refine the boundaries twice size_t basedimv[3] = {basedim, basedim, basedim}; // User coordinate system extents. Can be set to anything // double min[3] = {0.0, 0.0, 0.0}; double max[3] = {1.0, 1.0, 1.0}; // // Create an AMRTree object to express the AMR refinement hierarchy // // The tree starts out as a rectilinear grid of cells with dimension // given by basedim // cout << ProgName << " : Tree create start" << endl; AMRTree *tree = new AMRTree(basedimv, min, max); if (AMRTree::GetErrCode() != 0) { fprintf(stderr, "AMRTree() : %s\n", AMRTree::GetErrMsg()); exit(1); } // Refine the tree: The boundary cells are left unrefined. The cells // boardering the boundary cells are refined once. Everything else is // refined twice. // for (AMRTree::cid_t z = 1; z < basedim - 1; z++) { for (AMRTree::cid_t y = 1; y < basedim - 1; y++) { for (AMRTree::cid_t x = 1; x < basedim - 1; x++) { size_t xyz[] = {x, y, z}; AMRTree::cid_t cellid = tree->GetCellID(xyz, 0); tree->RefineCell(cellid); } } } for (AMRTree::cid_t z = 2; z < basedim - 2; z++) { for (AMRTree::cid_t y = 2; y < basedim - 2; y++) { for (AMRTree::cid_t x = 2; x < basedim - 2; x++) { size_t xyz[] = {x, y, z}; AMRTree::cid_t cellid = tree->GetCellID(xyz, 0); AMRTree::cid_t child = tree->GetCellChildren(cellid); for (AMRTree::cid_t i = 0; i < 8; i++) { tree->RefineCell(child + i); } } } } // // Calling EndRefinement() is optional, but it can signficantly // improve performance, namely when calling AMRData::GetBlock // tree->EndRefinement(); cout << ProgName << " : Tree create finished" << endl; // Print out info about the tree hierarchy // if (opt.debug) { int level; bool first = true; AMRTree::cid_t cellid; while ((cellid = tree->GetNextCell(first)) >= 0) { size_t xyz[3], xyz_b[3]; AMRTree::cid_t baseblockidx; AMRTree::cid_t nodeidx; first = false; tree->GetCellLocation(cellid, xyz, &level); tree->DecodeCellID(cellid, &baseblockidx, &nodeidx); xyz_b[0] = xyz[0] >> level; xyz_b[1] = xyz[1] >> level; xyz_b[2] = xyz[2] >> level; cerr << "level, id, location base_location " << level << " (" << baseblockidx << " " << nodeidx << ") (" << xyz[0] << " " << xyz[1] << " " << xyz[2] << ") (" << xyz_b[0] << " " << xyz_b[1] << " " << xyz_b[2] << ")" << endl; } } // // Open a tree for writing at the indicated time step. Only one // tree is needed per time step (all variables at a given // time step must have the same hierarchy). // if (amrio->OpenTreeWrite(0) < 0) { cerr << ProgName << " : " << amrio->GetErrMsg() << endl; exit(1); } if (amrio->TreeWrite(tree) < 0) { cerr << ProgName << " : " << amrio->GetErrMsg() << endl; exit(1); } if (amrio->CloseTree() < 0) { cerr << ProgName << " : " << amrio->GetErrMsg() << endl; exit(1); } // Create an AMRData object to store the sampled solution data. Each // cell in the AMR tree is of dimension CellDim by CellDim by CellDim // size_t cell_dim[] = {CellDim, CellDim, CellDim}; AMRData *amrdata = new AMRData(tree, cell_dim); // Create a synthetic data set and place it in the tree // float *grid = make_marschner_lobb(N, N, N); cout << ProgName << " : variable 1 create start" << endl; process_variable(amrio, tree, amrdata, grid, "ml"); cout << ProgName << " : variable 1 create finished" << endl; delete[] grid; grid = make_checker(N, N, N, 8); cout << ProgName << " : variable 2 create start" << endl; process_variable(amrio, tree, amrdata, grid, "checker"); cout << ProgName << " : variable 2 create finished" << endl; delete[] grid; exit(0); } ================================================ FILE: share/examples/generateExampleDCP.py ================================================ # Run this file to create an example DCP dataset from netCDF4 import Dataset import numpy as np N = 2000 dim = 3 np.random.seed(0) pos = np.random.random_sample((N,dim))*200-100 vel = np.random.random_sample((N,dim))*20-1 # Generate example particles for next timestep def StepSimulation() -> None: global pos, vel G = 3000 r = np.sqrt(np.sum(pos**2, axis=-1)) r = np.clip(r, 10, 100**2) d = -pos/r[:,None] vel += d*(G/r**2)[:,None] pos += vel * 0.1 filt = np.column_stack((pos,vel))[np.all((pos>-100) & (pos<100), axis=1)] pos = filt[:, 0:dim] vel = filt[:, dim:dim*2] # Wraps an array in an additional dimension # This is required for data time varying data that is only spacial # as is this case in this demo def AddTimeDim(data: np.ndarray) -> np.ndarray: return np.expand_dims(data, axis=0) def WriteTimestep(ts: float, positionData: np.ndarray, **kwargs: np.ndarray) -> None: dataset = Dataset(f"particles_{ts:03}.nc", "w", format="NETCDF4") particleCount:int = positionData.shape[0] dataset.createDimension("P", particleCount) # The P dimension represents the number of particles at this timestep dataset.createDimension("T", None) # Time dimension dataset.createDimension("axis", 3) # Utility dimension for packing 3 components for 3D particles into a single variable # Time coordinate T = dataset.createVariable("T", "f8", ("T",)) T.units = "seconds" T[:] = np.array([ts]) # 3D vars can be packed in a single variable by adding the axis dimension Position = dataset.createVariable("Position", "f4", ("T", "P", "axis"), zlib=True) # positionData is 2D (numParticles * axis) whereas Position is 3D (time * numParticles * axis) Position[:] = AddTimeDim(positionData) # Alternatively, you could do the following: # Position_x = dataset.createVariable("Position_x", "f4", ("T", "P"), zlib=True) # Position_x[:] = AddTimeDim(positionData_x:1d array) # and so on for the other 2 axes # Save all remaining particle properties passed in to nc file for name, data in kwargs.items(): var = dataset.createVariable(name, "f4", ("T", "P", "axis")[0:data.ndim + 1], zlib=True) var[:] = AddTimeDim(data) dataset.close() for ts in range(400): # Compute magnitude of velocity for each particle speed = np.sqrt(np.sum(vel**2, axis=-1)) # Since 3-component properties such as velocity are common for 3D particles, # DCP allows packing them as a 2D array of size N_particles by 3 # vel is an array of size Nx3 and speed is an array of size N WriteTimestep(ts, pos, vel=vel, speed=speed) # The following would also work # WriteTimestep(ts, pos, vel_x=vel[:,0], vel_y=vel[:,1], vel_z=vel[:,2], speed=speed) StepSimulation() ================================================ FILE: share/examples/idl/AddCurlVDF.pro ================================================ ; AddCurlVDF.pro ; ; Utility to read three variables from a VDF, calculate their curl ; and optionally the curl's magnitude, and put them back into the VDF. ; All three variables must be present at full resolution. ; ; The .pro files curl_findiff.pro and deriv_findiff.pro must be in the ; directory from which you started idl. ; ; The vdf file is replaced. The previous vdf file is saved, with ; _saved appended to its name, in case of catastrophic failure ; ; Arguments are: ; vdffile = file path of the metadata file ; varx, vary, varz = the 3 variables defining the field ; whose curl is being calculated ; curlx,curly,curlz = the names for the three components ; of the curl being calculated ; tsstart = the time step to start with (or the only time step) ; tsmax = (keyword parameter) the time step to stop with (don't specify ; if you only want the one time step, tsstart) ; tsival = (keyword parameter) the interval between time steps (will compute ; info for tsstart, tsstart + tsival, etc.) (again, don't specify if ; you only want the one time step, tsstart) ; mag = (keyword parameter) name of curl's magnitude (do not specify if you ; don't want the ; magnitude of the curl written) ; onlymag = (keyword parameter) set this to anything if you only want the ; curl's magnitude and not the actual vector field (note that you ; must still supply names for curlx, curly, curlz) ; ; Note: if you want to add the magnitude later, use AddMagVDF ; PRO AddCurlVDF, vdffile,varx,vary,varz,curlx,curly,curlz,tsstart, $ TSMAX=tsmax,TSIVAL=tsival,MAG=mag,ONLYMAG=onlymag ; Make sure we're actually doing something IF ( ~keyword_set(mag) && keyword_set(onlymag) ) THEN BEGIN print, "Neither curl nor curl's magnitude requested. Nothing modified." RETURN ENDIF ; ; Variable timestep now functions as a switch and initializer ; timestep = tsstart IF ( ~keyword_set(tsmax) ) THEN tsmax=tsstart IF ( ~keyword_set(tsival) ) THEN tsival=1 ; ; Start with the current metadata: ; mfd = vdf_create(vdffile) ; ; save the current vdf file (in case we screw up) ; savedvdffile = STRING(vdffile,'_saved') vdf_write,mfd,savedvdffile ; ; Add the new variable names to the current variable names: ; ; ; How many variable names? ; IF ( keyword_set(mag) && ~keyword_set(onlymag) ) THEN newnum = 4 IF ( keyword_set(mag) && keyword_set(onlymag) ) THEN newnum = 1 IF ( ~keyword_set(mag) ) THEN newnum = 3 nvarnames3d = 0 if (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin varnames = vdf_getvariables3d(mfd) nvarnames3d = n_elements(varnames) endif nvarnames2dxy = 0 if (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin varnames2dxy = vdf_getvariables2dxy(mfd) nvarnames2dxy = n_elements(varnames2dxy) endif numvarsarray = size(varnames) numvars = newnum + numvarsarray[1] newvarnames = strarr(numvars) ; Need to make sure the new var names are not in the list! repeatvariables = 0 print, 'num 3D vars = ',numvars FOR I = 0, numvars-newnum-1 DO BEGIN newvarnames[I] = varnames[I] IF ( ~keyword_set(onlymag) ) THEN BEGIN IF (varnames[I] EQ curlx) THEN repeatvariables = 1+repeatvariables IF (varnames[I] EQ curly) THEN repeatvariables = 1+repeatvariables IF (varnames[I] EQ curlz) THEN repeatvariables = 1+repeatvariables ENDIF IF ( keyword_set(mag) ) THEN BEGIN IF ( varnames [I] EQ mag ) THEN repeatvariables += 1 ENDIF ENDFOR IF (repeatvariables GT 0 AND repeatvariables LT newnum) THEN BEGIN print, 'ERROR: some but not all curl variable names exist already' STOP ENDIF IF (repeatvariables EQ 0) THEN BEGIN IF ( ~keyword_set(onlymag) ) THEN BEGIN newvarnames[numvars-newnum] = curlx newvarnames[numvars-newnum+1] = curly newvarnames[numvars-newnum+2] = curlz ENDIF IF ( keyword_set(mag) && ~keyword_set(onlymag) ) THEN $ newvarnames[numvars-newnum+3] = mag IF ( keyword_set(onlymag) ) THEN newvarnames[numvars-newnum] = mag ENDIF IF (repeatvariables EQ newnum) THEN newvarnames = varnames ; ; reset the varnames in mfd to the new value: ; provided not all variables are repeated ; Note that by default all variable names are 3D ; if (repeatvariables NE newnum) THEN BEGIN if (nvarnames2dxy gt 0) THEN BEGIN vdf_setvarnames,mfd,[newvarnames,varnames2dxy] vdf_setvariables2DXY,mfd,varnames2dxy ENDIF ELSE BEGIN vdf_setvarnames,mfd,newvarnames ENDELSE ENDIF reflevel = vdf_getnumtransforms(mfd) ; ; Begin loop that iterates over time steps ; REPEAT BEGIN print, "Working on time step ", timestep ; ; Create "Buffered Read" objects for each variable to read the data, passing the ; metadata object handle created by vdf_create() as an argument ; dfdx = vdc_bufreadcreate(mfd) dfdy = vdc_bufreadcreate(mfd) dfdz = vdc_bufreadcreate(mfd) ; ; ; Determine the dimensions of the x-variable at the full transformation ; level. ; This is used as the dimension of all the variables ; dim = vdc_getdim(dfdx, reflevel) ; ; Create appropriately sized arrays to hold the source and result data ; srcx = fltarr(dim[0],dim[1],dim[2]) srcy = fltarr(dim[0],dim[1],dim[2]) srcz = fltarr(dim[0],dim[1],dim[2]) dstx = fltarr(dim[0],dim[1],dim[2]) dsty = fltarr(dim[0],dim[1],dim[2]) dstz = fltarr(dim[0],dim[1],dim[2]) ; ; Prepare to read the indicated time step and variables ; vdc_openvarread, dfdx, timestep, varx, reflevel ; ; Read the volume one slice at a time ; slcx = fltarr(dim[0],dim[1]) slcy = fltarr(dim[0],dim[1]) slcz = fltarr(dim[0],dim[1]) ; Determine the grid spacing extents = VDF_GETEXTENTS(mfd) deltax = (extents[3] - extents[0])/FLOAT(dim[0]) deltay = (extents[4] - extents[1])/FLOAT(dim[1]) deltaz = (extents[5] - extents[2])/FLOAT(dim[2]) FOR z = 0, dim[2]-1 DO BEGIN vdc_bufreadslice, dfdx, slcx ; copy to 3d array srcx[*,*,z] = slcx ; Report every 100 reads: IF ((z MOD 100) EQ 0) THEN print,'reading x slice ',z ENDFOR vdc_closevar, dfdx vdc_bufreaddestroy, dfdx vdc_openvarread, dfdy, timestep, vary, reflevel FOR z = 0, dim[2]-1 DO BEGIN vdc_bufreadslice, dfdy, slcy ; copy to 3d array srcy[*,*,z] = slcy ; Report every 100 reads: IF ((z MOD 100) EQ 0) THEN print,'reading y slice ',z ENDFOR vdc_closevar, dfdy vdc_bufreaddestroy, dfdy vdc_openvarread, dfdz, timestep, varz, reflevel FOR z = 0, dim[2]-1 DO BEGIN vdc_bufreadslice, dfdz, slcz ; copy to 3d array srcz[*,*,z] = slcz ; Report every 100 reads: IF ((z MOD 100) EQ 0) THEN print,'reading z slice ',z ENDFOR vdc_closevar, dfdz vdc_bufreaddestroy, dfdz ; Now perform the curl on the data curl_findiff,srcx,srcy,srcz,dstx,dsty,dstz,deltax,deltay,deltaz print,'performed the curl on ',varx,' ', vary,' ', varz IF ( ~keyword_set(onlymag) ) THEN BEGIN dfdcurlx = vdc_bufwritecreate(mfd) vdc_openvarwrite, dfdcurlx, timestep, curlx, reflevel ; write the data one slice at a time FOR z = 0, dim[2]-1 DO BEGIN slcx = dstx[*,*,z] vdc_bufwriteslice,dfdcurlx, slcx ; Report every 100 writes: IF ((z MOD 100) EQ 0) THEN print,'writing x slice ',z ENDFOR vdc_closevar, dfdcurlx vdc_bufwritedestroy, dfdcurlx dfdcurly = vdc_bufwritecreate(mfd) vdc_openvarwrite, dfdcurly, timestep, curly, reflevel FOR z = 0, dim[2]-1 DO BEGIN slcy = dsty[*,*,z] vdc_bufwriteslice,dfdcurly, slcy ; Report every 100 writes: IF ((z MOD 100) EQ 0) THEN print,'writing y slice ',z ENDFOR vdc_closevar, dfdcurly vdc_bufwritedestroy, dfdcurly dfdcurlz = vdc_bufwritecreate(mfd) vdc_openvarwrite, dfdcurlz, timestep, curlz, reflevel FOR z = 0, dim[2]-1 DO BEGIN slcz = dstz[*,*,z] vdc_bufwriteslice,dfdcurlz, slcz ; Report every 100 writes: IF ((z MOD 100) EQ 0) THEN print,'writing z slice ',z ENDFOR vdc_closevar, dfdcurlz vdc_bufwritedestroy, dfdcurlz ENDIF ; ; If desired, compute and write the magnitude of the curl ; IF ( keyword_set(mag) ) THEN BEGIN dfdmag = vdc_bufwritecreate(mfd) allMag = fltarr(dim[0],dim[1],dim[2]) allMag = sqrt( dstx^2 + dsty^2 + dstz^2 ) slcmag = fltarr(dim[0],dim[1]) vdc_openvarwrite, dfdmag, timestep, mag, reflevel FOR z = 0, dim[2]-1 DO BEGIN slcmag = allMag[*,*,z] vdc_bufwriteslice, dfdmag, slcmag ; Report every 100 writes IF ( (z MOD 100) EQ 0) THEN print, "Writing magnitude's z slice ", z ENDFOR vdc_closevar, dfdmag vdc_bufwritedestroy, dfdmag ENDIF ; ; First time, replace the vdf file with the new one ; IF (timestep EQ tsstart AND repeatvariables NE newnum) THEN vdf_write,mfd,vdffile print,'Curl completed' timestep += tsival ENDREP UNTIL ( timestep GT tsmax ) vdf_destroy, mfd END ================================================ FILE: share/examples/idl/AddDivVDF.pro ================================================ ; AddDivVDF.pro ; ; Utility to read three variables from a VDF, calculate their divergence ; and put it back into the VDF. ; All three variables must be present at full resolution. ; ; The .pro files deriv_findiff.pro and div_findiff.pro must be in the ; directory from which you started idl. ; ; The vdf file is replaced. The previous vdf file is saved, with ; _saved appended to its name, in case of catastrophic failure ; ; Arguments are: ; vdffile = file path of the metadata file ; varx, vary, varz = the 3 variables defining the field ; whose divergence is being calculated ; divvar = the name for the divergence variable being calculated ; tsstart = the time step to start with (or the only time step) ; tsmax = (keyword parameter) the time step to stop with (don't specify ; if you only want the one time step, tsstart) ; tsival = (keyword parameter) the interval between time steps (will compute ; info for tsstart, tsstart + tsival, etc.) (again, don't specify if ; you only want the one time step, tsstart) ; PRO AddDivVDF, vdffile,varx,vary,varz,divvar,tsstart, $ TSMAX=tsmax,TSIVAL=tsival ; ; Variable timestep now functions as a switch and initializer ; timestep = tsstart IF ( ~keyword_set(tsmax) ) THEN tsmax=tsstart IF ( ~keyword_set(tsival) ) THEN tsival=1 ; ; Start with the current metadata: ; mfd = vdf_create(vdffile) ; ; save the current vdf file (in case we screw up) ; savedvdffile = STRING(vdffile,'_saved') vdf_write,mfd,savedvdffile ; ; Add the new variable name to the current variable names: ; nvarnames3d = 0 if (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin varnames = vdf_getvariables3d(mfd) nvarnames3d = n_elements(varnames) endif nvarnames2dxy = 0 if (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin varnames2dxy = vdf_getvariables2dxy(mfd) nvarnames2dxy = n_elements(varnames2dxy) endif numvarsarray = size(varnames) numvars = 1 + numvarsarray[1] newvarnames = strarr(numvars) ; Need to make sure the new var name is not in the list! isinvariables = 0 FOR I = 0, numvars-2 DO BEGIN newvarnames[I] = varnames[I] if (varnames[I] EQ divvar) THEN isinvariables = 1 ENDFOR IF (isinvariables EQ 0) THEN newvarnames[numvars-1] = divvar ELSE newvarnames = varnames print,'The 3D variable names in the vdf will be: ',newvarnames ; ; reset the varnames in mfd to the new value: ; provided not all variables are repeated ; Note that by default all variable names are 3D ; if (isinvariables EQ 0) THEN BEGIN if (nvarnames2dxy gt 0) THEN BEGIN vdf_setvarnames,mfd,[newvarnames,varnames2d] vdf_setvariables2DXY,mfd,varnames2d ENDIF ELSE BEGIN vdf_setvarnames,mfd,newvarnames ENDELSE ENDIF reflevel = vdf_getnumtransforms(mfd) ; ; Begin loop that iterates over time steps ; REPEAT BEGIN print, "Working on time step ", timestep ; ; Create "Buffered Read" objects for each variable to read the data, passing the ; metadata object handle created by vdf_create() as an argument ; dfdx = vdc_bufreadcreate(mfd) dfdy = vdc_bufreadcreate(mfd) dfdz = vdc_bufreadcreate(mfd) dfddiv = vdc_bufwritecreate(mfd) ; ; ; Determine the dimensions of the x-variable at the full transformation ; level. ; This is used as the dimension of all the variables ; dim = vdc_getdim(dfdx, reflevel) ; ; Create appropriately sized arrays to hold the source and result data ; srcx = fltarr(dim[0],dim[1],dim[2]) srcy = fltarr(dim[0],dim[1],dim[2]) srcz = fltarr(dim[0],dim[1],dim[2]) divarray = fltarr(dim[0],dim[1],dim[2]) ; ; Prepare to read the indicated time step and variables ; vdc_openvarread, dfdx, timestep, varx, reflevel vdc_openvarread, dfdy, timestep, vary, reflevel vdc_openvarread, dfdz, timestep, varz, reflevel vdc_openvarwrite, dfddiv, timestep,divvar , reflevel ; ; Read the volume one slice at a time ; slcx = fltarr(dim[0],dim[1]) slcy = fltarr(dim[0],dim[1]) slcz = fltarr(dim[0],dim[1]) ; Determine the grid spacing extents = VDF_GETEXTENTS(mfd) deltax = (extents[3] - extents[0])/FLOAT(dim[0]) deltay = (extents[4] - extents[1])/FLOAT(dim[1]) deltaz = (extents[5] - extents[2])/FLOAT(dim[2]) FOR z = 0, dim[2]-1 DO BEGIN vdc_bufreadslice, dfdx, slcx ; copy to 3d array srcx[*,*,z] = slcx vdc_bufreadslice, dfdy, slcy srcy[*,*,z] = slcy vdc_bufreadslice, dfdz, slcz srcz[*,*,z] = slcz ; Report every 100 reads: IF ((z MOD 100) EQ 0) THEN print,'reading x slice ',z ENDFOR vdc_closevar, dfdx vdc_bufreaddestroy, dfdx vdc_closevar, dfdy vdc_bufreaddestroy, dfdy vdc_closevar, dfdz vdc_bufreaddestroy, dfdz ; Now perform the divergence on the data div_findiff,srcx,srcy,srcz,divarray,deltax,deltay,deltaz print,'performed the divergence on ',varx,' ', vary,' ', varz ; write the data one slice at a time FOR z = 0, dim[2]-1 DO BEGIN slc = divarray[*,*,z] vdc_bufwriteslice,dfddiv, slc ; Report every 100 writes: IF ((z MOD 100) EQ 0) THEN print,'writing x slice ',z ENDFOR vdc_closevar, dfddiv vdc_bufwritedestroy, dfddiv ; ; First time, replace the vdf file with the new one ; IF (timestep EQ tsstart AND isinvariables EQ 0) THEN vdf_write,mfd,vdffile print,'Divergence completed' timestep += tsival ENDREP UNTIL ( timestep GT tsmax ) vdf_destroy, mfd END ================================================ FILE: share/examples/idl/AddMagVDF.pro ================================================ ; ; AddMagVDF.pro ; ; Utility to read three 3D variables from a VDF and calculate their magnitude ; and put it back into the VDF. ; All three variables must be present at full resolution. ; This is performed one time-step at a time. ; The vdf file is replaced. The previous vdf file is saved, with ; _saved appended to its name, in case of catastrophic failure ; ; Arguments are: ; vdffile = file path of the metadata file ; varx, vary, varz = the 3 3D variables defining the field ; whose magnitude is being calculated ; magvarname is the name for the field magnitude being calculated ; tsstart specifies the first timestep for which the magnitude ; is calculated. If multiple timesteps are needed, ; keyword variables: ; tsmax = largest time step ; tsival = increment between time steps ; PRO AddMagVDF,vdffile,varx,vary,varz,magvarname,tsstart,$ TSMAX=tsmax,TSIVAL=tsival ; ; Set up timesteps ; timestep = tsstart IF (~keyword_set(tsmax)) THEN tsmax = tsstart IF (~keyword_set(tsival)) THEN tsival = 1 ; ; Start with the current metadata: ; mfd = vdf_create(vdffile) ; ; save the current vdf file (in case we screw up) ; savedvdffile = STRING(vdffile,'_saved') vdf_write,mfd,savedvdffile ; ; Add the new variable name to the current variable names: ; nvarnames3d = 0 if (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin varnames = vdf_getvariables3d(mfd) nvarnames3d = n_elements(varnames) endif nvarnames2dxy = 0 if (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin varnames2dxy = vdf_getvariables2dxy(mfd) nvarnames2dxy = n_elements(varnames2dxy) endif numvarsarray = size(varnames) numvars = 1 + numvarsarray[1] newvarnames = strarr(numvars) ; Need to make sure this is not in the list! isinvariables = 0 FOR I = 0, numvars-2 DO BEGIN newvarnames[I] = varnames[I] if (varnames[I] EQ magvarname) THEN isinvariables = 1 ENDFOR IF (isinvariables EQ 0) THEN newvarnames[numvars-1] = magvarname ELSE newvarnames = varnames print,'The 3D variable names in the vdf will be: ',newvarnames ; ; reset the varnames in mfd to the new value: ; and set the 2d vars if there are any ; if (isinvariables EQ 0) THEN BEGIN if (nvarnames2dxy gt 0) THEN BEGIN vdf_setvarnames,mfd,[newvarnames,varnames2dxy] vdf_setvariables2dxy,mfd,varnames2dxy ENDIF ELSE BEGIN vdf_setvarnames,mfd,newvarnames ENDELSE ENDIF reflevel = vdf_getnumtransforms(mfd) numtimesteps = vdf_getnumtimesteps(mfd) REPEAT BEGIN ; ; Create "Buffered Read" objects for each variable to read the data, passing the ; metadata object handle created by vdf_create() as an argument ; dfdx = vdc_bufreadcreate(mfd) dfdy = vdc_bufreadcreate(mfd) dfdz = vdc_bufreadcreate(mfd) dfdmag = vdc_bufwritecreate(mfd) ; ; ; Determine the dimensions of the x-variable at the full transformation ; level. ; This is used as the dimension of all the variables ; Note. vdc_getdim() correctly handles dimension calucation for ; volumes with non-power-of-two dimensions. ; dim = vdc_getdim(dfdx, reflevel) ; ; Create appropriately sized arrays to hold the volume slices: ; slicex = fltarr(dim[0], dim[1]) slicey = fltarr(dim[0], dim[1]) slicez = fltarr(dim[0], dim[1]) slicemag = fltarr(dim[0], dim[1]) slicemagsq = fltarr(dim[0], dim[1]) ; ; Prepare to read and write the indicated time step and variables ; vdc_openvarread, dfdx, timestep, varx, reflevel vdc_openvarread, dfdy, timestep, vary, reflevel vdc_openvarread, dfdz, timestep, varz, reflevel vdc_openvarwrite,dfdmag, timestep, magvarname, reflevel ; ; Read the volume one slice at a time ; FOR z = 0, dim[2]-1 DO BEGIN vdc_bufreadslice, dfdx, slicex vdc_bufreadslice, dfdy, slicey vdc_bufreadslice, dfdz, slicez slicemagsq = slicex*slicex + slicey*slicey + slicez*slicez slicemag = sqrt(slicemagsq) vdc_bufwriteslice, dfdmag, slicemag ; Report every 100 writes: IF ((Z MOD 100) EQ 0) THEN print,'wrote slice ',z ENDFOR vdc_closevar, dfdmag vdc_closevar, dfdx vdc_closevar, dfdy vdc_closevar, dfdz vdc_bufwritedestroy, dfdmag vdc_bufreaddestroy, dfdx vdc_bufreaddestroy, dfdy vdc_bufreaddestroy, dfdz ; ; Replace the vdf file with the new one, the first time through: ; IF (timestep EQ tsstart AND isinvariables EQ 0) THEN vdf_write,mfd,vdffile print,'Magnitude calculated of timestep ', timestep timestep += tsival ENDREP UNTIL (timestep GT tsmax) vdf_destroy, mfd end ================================================ FILE: share/examples/idl/AddWRFCurl.pro ================================================ ; ; AddWRFCurl.pro ; ; Utility to read three variables from a WRF VDF, calculate their curl ; and put them back into the VDF. ; All three variables and ELEVATION must be present at full resolution. ; ; The .pro files wrf_curl_findiff.pro and deriv_findiff.pro ; and elev_deriv.pro must be in the ; directory from which you started idl. ; ; The vdf file is replaced. The previous vdf file is saved, with ; _saved appended to its name, in case of catastrophic failure ; ; Arguments are: ; vdffile = file path of the metadata file ; varx, vary, varz = the 3 variables defining the file ; whose magnitude is being calculated ; curlx,curly,curlz = the names for the three components ; of the curl being calculated ; tsstart = the first (smallest) time step this is applied to ; keyword args: ; tsmax = the largest time step this is applied to ; tsival = the increment between successive time steps ; mag = (keyword parameter) name of curl's magnitude (do not specify if you ; don't want the ; magnitude of the curl written) ; onlymag = (keyword parameter) set this to anything if you only want the ; curl's magnitude and not the actual vector field (note that you ; must still supply names for curlx, curly, curlz) ; ; Note: if you want to add the magnitude later, use AddMagVDF ; ; ; PRO AddWRFCurl, vdffile,varx,vary,varz,curlx,curly,curlz,tsstart, $ TSMAX=tsmax,TSIVAL=tsival,MAG=mag,ONLYMAG=onlymag ; Make sure we're actually doing something IF ( ~keyword_set(mag) && keyword_set(onlymag) ) THEN BEGIN print, "Neither curl nor curl's magnitude requested. Nothing modified." RETURN ENDIF ; ; Set up timesteps ; timestep = tsstart IF (~keyword_set(tsmax)) THEN tsmax = tsstart IF (~keyword_set(tsival)) THEN tsival = 1 ; ; Start with the current metadata: ; mfd = vdf_create(vdffile) ; ; save the current vdf file (in case we screw up) ; savedvdffile = STRING(vdffile,'_saved') vdf_write,mfd,savedvdffile ; ; Add the new variable names to the current variable names: ; ; ; How many variable names? ; IF ( keyword_set(mag) && ~keyword_set(onlymag) ) THEN newnum = 4 IF ( keyword_set(mag) && keyword_set(onlymag) ) THEN newnum = 1 IF ( ~keyword_set(mag) ) THEN newnum = 3 nvarnames3d = 0 if (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin varnames = vdf_getvariables3d(mfd) nvarnames3d = n_elements(varnames) endif nvarnames2dxy = 0 if (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin varnames2dxy = vdf_getvariables2dxy(mfd) nvarnames2dxy = n_elements(varnames2dxy) endif numvarsarray = size(varnames) numvars = newnum + numvarsarray[1] newvarnames = strarr(numvars) ; Need to make sure these are not in the list! repeatvariables = 0 print, 'numvars = ',numvars FOR I = 0, numvars-newnum-1 DO BEGIN newvarnames[I] = varnames[I] IF ( ~keyword_set(onlymag) ) THEN BEGIN IF (varnames[I] EQ curlx) THEN repeatvariables = 1+repeatvariables IF (varnames[I] EQ curly) THEN repeatvariables = 1+repeatvariables IF (varnames[I] EQ curlz) THEN repeatvariables = 1+repeatvariables ENDIF IF ( keyword_set(mag) ) THEN BEGIN IF ( varnames [I] EQ mag ) THEN repeatvariables += 1 ENDIF ENDFOR IF (repeatvariables GT 0 AND repeatvariables LT newnum) THEN BEGIN print, 'ERROR: some but not all curl variable names exist already' STOP ENDIF IF (repeatvariables EQ 0) THEN BEGIN IF ( ~keyword_set(onlymag) ) THEN BEGIN newvarnames[numvars-newnum] = curlx newvarnames[numvars-newnum+1] = curly newvarnames[numvars-newnum+2] = curlz ENDIF IF ( keyword_set(mag) && ~keyword_set(onlymag) ) THEN $ newvarnames[numvars-newnum+3] = mag IF ( keyword_set(onlymag) ) THEN newvarnames[numvars-newnum] = mag ENDIF ; ; reset the varnames in mfd to the new value: ; IF (repeatvariables EQ 0) THEN BEGIN if(nvarnames2dxy gt 0) THEN BEGIN vdf_setvarnames,mfd,[newvarnames,varnames2dxy] vdf_setvariables2dXY,mfd,varnames2dxy ENDIF ELSE BEGIN vdf_setvarnames,mfd,newvarnames ENDELSE ENDIF reflevel = vdf_getnumtransforms(mfd) REPEAT BEGIN print, "Working on time step ", timestep ; ; Create "Buffered Read" objects for each variable to read the data, passing the ; metadata object handle created by vdf_create() as an argument ; dfdx = vdc_bufreadcreate(mfd) dfdy = vdc_bufreadcreate(mfd) dfdz = vdc_bufreadcreate(mfd) dfde = vdc_bufreadcreate(mfd) ; ; ; Determine the dimensions of the x-variable at the full transformation ; level. ; This is used as the dimension of all the variables ; Note. vdc_getdim() correctly handles dimension calucation for ; volumes with non-power-of-two dimensions. ; dim = vdc_getdim(dfdx, reflevel) ; ; Create appropriately sized arrays to hold the source and result data ; srcx = fltarr(dim[0],dim[1],dim[2]) srcy = fltarr(dim[0],dim[1],dim[2]) srcz = fltarr(dim[0],dim[1],dim[2]) srce = fltarr(dim[0],dim[1],dim[2]) dstx = fltarr(dim[0],dim[1],dim[2]) dsty = fltarr(dim[0],dim[1],dim[2]) dstz = fltarr(dim[0],dim[1],dim[2]) ; ; Prepare to read the indicated time step and variables ; vdc_openvarread, dfdx, timestep, varx, reflevel vdc_openvarread, dfdy, timestep, vary, reflevel vdc_openvarread, dfdz, timestep, varz, reflevel vdc_openvarread, dfde, timestep, 'ELEVATION', reflevel ; ; Read the volume one slice at a time ; slcx = fltarr(dim[0],dim[1]) slcy = fltarr(dim[0],dim[1]) slcz = fltarr(dim[0],dim[1]) slce = fltarr(dim[0],dim[1]) ; Determine the grid spacing extents = VDF_GETEXTENTS(mfd) deltax = (extents[3] - extents[0])/FLOAT(dim[0]) deltay = (extents[4] - extents[1])/FLOAT(dim[1]) FOR z = 0, dim[2]-1 DO BEGIN vdc_bufreadslice, dfdx, slcx ; copy to 3d array srcx[*,*,z] = slcx vdc_bufreadslice, dfdy, slcy srcy[*,*,z] = slcy vdc_bufreadslice, dfdz, slcz srcz[*,*,z] = slcz vdc_bufreadslice, dfde, slce srce[*,*,z] = slce ; Report every 100 reads: IF ((z MOD 100) EQ 0) THEN print,'reading slice ',z ENDFOR vdc_closevar, dfdx vdc_bufreaddestroy, dfdx vdc_closevar, dfdy vdc_bufreaddestroy, dfdy vdc_closevar, dfdz vdc_bufreaddestroy, dfdz vdc_closevar, dfde vdc_bufreaddestroy, dfde ; Now perform the curl on the data wrf_curl_findiff,srcx,srcy,srcz,dstx,dsty,dstz,deltax,deltay,srce ; If requested, write out the components of the curl: IF (~keyword_set(onlymag) ) THEN BEGIN dfdcurlx = vdc_bufwritecreate(mfd) vdc_openvarwrite, dfdcurlx, timestep, curlx, reflevel dfdcurly = vdc_bufwritecreate(mfd) vdc_openvarwrite, dfdcurly, timestep, curly, reflevel dfdcurlz = vdc_bufwritecreate(mfd) vdc_openvarwrite, dfdcurlz, timestep, curlz, reflevel ; write the data one slice at a time FOR z = 0, dim[2]-1 DO BEGIN slcx = dstx[*,*,z] vdc_bufwriteslice,dfdcurlx, slcx slcy = dsty[*,*,z] vdc_bufwriteslice,dfdcurly, slcy slcz = dstz[*,*,z] vdc_bufwriteslice,dfdcurlz, slcz ; Report every 100 writes: IF ((z MOD 100) EQ 0) THEN print,'writing slice ',z ENDFOR vdc_closevar, dfdcurlx vdc_bufwritedestroy, dfdcurlx vdc_closevar, dfdcurly vdc_bufwritedestroy, dfdcurly vdc_closevar, dfdcurlz vdc_bufwritedestroy, dfdcurlz ENDIF ; ; If desired, compute and write the magnitude of the curl ; IF ( keyword_set(mag) ) THEN BEGIN dfdmag = vdc_bufwritecreate(mfd) allMag = fltarr(dim[0],dim[1],dim[2]) allMag = sqrt( dstx^2 + dsty^2 + dstz^2 ) slcmag = fltarr(dim[0],dim[1]) vdc_openvarwrite, dfdmag, timestep, mag, reflevel FOR z = 0, dim[2]-1 DO BEGIN slcmag = allMag[*,*,z] vdc_bufwriteslice, dfdmag, slcmag ; Report every 100 writes IF ( (z MOD 100) EQ 0) THEN print, "Writing magnitude's z slice ", z ENDFOR vdc_closevar, dfdmag vdc_bufwritedestroy, dfdmag ENDIF ; ; Replace the vdf file with the new one, the first time through: ; IF (timestep EQ tsstart AND repeatvariables NE newnum) THEN vdf_write,mfd,vdffile print,'Curl completed of timestep ', timestep timestep += tsival ENDREP UNTIL (timestep GT tsmax) vdf_destroy, mfd END ================================================ FILE: share/examples/idl/AddWRFDiv.pro ================================================ ; AddWRFDiv.pro ; ; Utility to read three variables from a WRF VDF, calculate their divergence ; and put it back into the VDF. ; All three variables must be present at full resolution. ; ; The .pro files deriv_findiff.pro and wrf_div_findiff.pro ; and elev_deriv.pro must be in the ; directory from which you started idl. ; ; The vdf file is replaced. The previous vdf file is saved, with ; _saved appended to its name, in case of catastrophic failure ; ; Arguments are: ; vdffile = file path of the metadata file ; varx, vary, varz = the 3 variables defining the field ; whose divergence is being calculated ; divVar = the name for the divergence variable being calculated ; tsstart = the time step to start with (or the only time step) ; tsmax = (keyword parameter) the time step to stop with (don't specify ; if you only want the one time step, tsstart) ; tsival = (keyword parameter) the interval between time steps (will compute ; info for tsstart, tsstart + tsival, etc.) (again, don't specify if ; you only want the one time step, tsstart) ; PRO AddWRFDiv, vdffile,varx,vary,varz,divvar,tsstart, $ TSMAX=tsmax,TSIVAL=tsival ; ; Variable timestep now functions as a switch and initializer ; timestep = tsstart IF ( ~keyword_set(tsmax) ) THEN tsmax=tsstart IF ( ~keyword_set(tsival) ) THEN tsival=1 ; ; Start with the current metadata: ; mfd = vdf_create(vdffile) ; ; save the current vdf file (in case we screw up) ; savedvdffile = STRING(vdffile,'_saved') vdf_write,mfd,savedvdffile ; ; Add the new variable name to the current variable names: ; ; ; How many variable names? ; nvarnames3d = 0 if (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin varnames = vdf_getvariables3d(mfd) nvarnames3d = n_elements(varnames) endif nvarnames2dxy = 0 if (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin varnames2dxy = vdf_getvariables2dxy(mfd) nvarnames2dxy = n_elements(varnames2dxy) endif numvarsarray = size(varnames) numvars = 1 + numvarsarray[1] newvarnames = strarr(numvars) ; Need to make sure the new var name is not in the list! isinvariables = 0 FOR I = 0, numvars-2 DO BEGIN newvarnames[I] = varnames[I] if (varnames[I] EQ divvar) THEN isinvariables = 1 ENDFOR IF (isinvariables EQ 0) THEN newvarnames[numvars-1] = divvar ELSE newvarnames = varnames print,'The 3D variable names in the vdf will be: ',newvarnames ; ; reset the varnames in mfd to the new value: ; provided not all variables are repeated ; Note that by default all variable names are 3D ; if (isinvariables EQ 0) THEN BEGIN if (nvarnames2dxy gt 0) THEN BEGIN vdf_setvarnames,mfd,[newvarnames,varnames2dxy] vdf_setvariables2DXY,mfd,varnames2dxy ENDIF ELSE BEGIN vdf_setvarnames,mfd,newvarnames ENDELSE ENDIF reflevel = vdf_getnumtransforms(mfd) ; ; Begin loop that iterates over time steps ; REPEAT BEGIN print, "Working on time step ", timestep ; ; Create "Buffered Read" objects for each variable to read the data, passing the ; metadata object handle created by vdf_create() as an argument ; dfdx = vdc_bufreadcreate(mfd) dfdy = vdc_bufreadcreate(mfd) dfdz = vdc_bufreadcreate(mfd) dfde = vdc_bufreadcreate(mfd) dfddiv = vdc_bufwritecreate(mfd) ; ; ; Determine the dimensions of the x-variable at the full transformation ; level. ; This is used as the dimension of all the variables ; dim = vdc_getdim(dfdx, reflevel) ; ; Create appropriately sized arrays to hold the source and result data ; srcx = fltarr(dim[0],dim[1],dim[2]) srcy = fltarr(dim[0],dim[1],dim[2]) srcz = fltarr(dim[0],dim[1],dim[2]) srce = fltarr(dim[0],dim[1],dim[2]) divarray = fltarr(dim[0],dim[1],dim[2]) ; ; Prepare to read the indicated time step and variables ; vdc_openvarread, dfdx, timestep, varx, reflevel vdc_openvarread, dfdy, timestep, vary, reflevel vdc_openvarread, dfdz, timestep, varz, reflevel vdc_openvarread, dfde, timestep, 'ELEVATION', reflevel vdc_openvarwrite, dfddiv, timestep, divvar, reflevel ; ; Read the volume one slice at a time ; slcx = fltarr(dim[0],dim[1]) slcy = fltarr(dim[0],dim[1]) slcz = fltarr(dim[0],dim[1]) slce = fltarr(dim[0],dim[1]) ; Determine the grid spacing extents = VDF_GETEXTENTS(mfd) deltax = (extents[3] - extents[0])/FLOAT(dim[0]) deltay = (extents[4] - extents[1])/FLOAT(dim[1]) FOR z = 0, dim[2]-1 DO BEGIN vdc_bufreadslice, dfdx, slcx ; copy to 3d array srcx[*,*,z] = slcx vdc_bufreadslice, dfdy, slcy ; copy to 3d array srcy[*,*,z] = slcy vdc_bufreadslice, dfdz, slcz ; copy to 3d array srcz[*,*,z] = slcz vdc_bufreadslice, dfde, slce ; copy to 3d array srce[*,*,z] = slce ; Report every 100 reads: IF ((z MOD 100) EQ 0) THEN print,'reading slice ',z ENDFOR vdc_closevar, dfdx vdc_closevar, dfdy vdc_closevar, dfdz vdc_closevar, dfde vdc_bufreaddestroy, dfdx vdc_bufreaddestroy, dfdy vdc_bufreaddestroy, dfdz vdc_bufreaddestroy, dfde ; Now perform the divergence on the data wrf_div_findiff,srcx,srcy,srcz,divarray,deltax,deltay,srce print,'performed the divergence on ',varx,' ', vary,' ', varz ; write the data one slice at a time FOR z = 0, dim[2]-1 DO BEGIN slc = divarray[*,*,z] vdc_bufwriteslice,dfddiv, slc ; Report every 100 writes: IF ((z MOD 100) EQ 0) THEN print,'writing x slice ',z ENDFOR vdc_closevar, dfddiv vdc_bufwritedestroy, dfddiv ; ; First time, replace the vdf file with the new one ; IF (timestep EQ tsstart AND isinvariables EQ 0) THEN vdf_write,mfd,vdffile print,'Divergence completed' timestep += tsival ENDREP UNTIL ( timestep GT tsmax ) vdf_destroy, mfd END ================================================ FILE: share/examples/idl/AddWRFETH.pro ================================================ ; ; AddWRFETH.pro ; ; Utility to calculate Equivalent Potential Temperature ; and put it back into the VDF, as the variable named ETH_. ; The VDC must have TK_, QVAPOR, P, and PB already ; with the usual meanings in a WRF dataset ; Formula was provided by Yongsheng Chen ; ; The vdf file is replaced. The previous vdf file is saved, with ; _saved appended to its name, in case of catastrophic failure ; ; Arguments are: ; vdffile = file path of the metadata file ; tsstart = the first (smallest) time step this is applied to ; keyword args: ; tsmax = the largest time step this is applied to ; tsival = the increment between successive time steps ; PRO AddWRFETH, vdffile,tsstart, $ TSMAX=tsmax,TSIVAL=tsival ; ; Set up timesteps ; timestep = tsstart IF (~keyword_set(tsmax)) THEN tsmax = tsstart IF (~keyword_set(tsival)) THEN tsival = 1 ; ; Start with the current metadata: ; mfd = vdf_create(vdffile) ; ; save the current vdf file (in case we screw up) ; savedvdffile = STRING(vdffile,'_saved') vdf_write,mfd,savedvdffile ; ; Add the new variable name to the current variable names: ; But need to know if it's already there ; How many variable names? ; nvarnames3d = 0 if (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin varnames = vdf_getvariables3d(mfd) nvarnames3d = n_elements(varnames) endif nvarnames2dxy = 0 if (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin varnames2dxy = vdf_getvariables2dxy(mfd) nvarnames2dxy = n_elements(varnames2dxy) endif numvarsarray = size(varnames) numvars = 1 + numvarsarray[1] newvarnames = strarr(numvars) ; Need to make sure these are not in the list! repeatvariables = 0 FOR I = 0, numvars-2 DO BEGIN newvarnames[I] = varnames[I] IF (varnames[I] EQ 'ETH_') THEN repeatvariables = 1+repeatvariables ENDFOR IF (repeatvariables EQ 0) THEN newvarnames[numvars-1] = 'ETH_' ; ; reset the varnames in mfd to the new value: ; unless it's already in the vdf ; if (repeatvariables EQ 0) THEN BEGIN if(nvarnames2dxy gt 0) THEN BEGIN vdf_setvarnames,mfd,[newvarnames,varnames2dxy] vdf_setvariables2dXY,mfd,varnames2dxy ENDIF ELSE BEGIN vdf_setvarnames,mfd,newvarnames ENDELSE ENDIF reflevel = vdf_getnumtransforms(mfd) REPEAT BEGIN print, "Working on time step ", timestep ; ; Create "Buffered Read" objects for each variable to read the data, passing the ; metadata object handle created by vdf_create() as an argument ; dfdP = vdc_bufreadcreate(mfd) dfdPB = vdc_bufreadcreate(mfd) dfdQV = vdc_bufreadcreate(mfd) dfdTK = vdc_bufreadcreate(mfd) dfdETH = vdc_bufwritecreate(mfd) ; ; ; Determine the dimensions of the P-variable at the full transformation ; level. ; This is used as the dimension of all the variables ; dim = vdc_getdim(dfdP, reflevel) ; ; Prepare to read the indicated time step and variables ; vdc_openvarread, dfdP, timestep, 'P', reflevel vdc_openvarread, dfdPB, timestep, 'PB', reflevel vdc_openvarread, dfdQV, timestep, 'QVAPOR', reflevel vdc_openvarread, dfdTK, timestep, 'TK_', reflevel vdc_openvarwrite, dfdETH, timestep, 'ETH_', reflevel ; ; Read the volume one slice at a time ; slcP = fltarr(dim[0],dim[1]) slcPB = fltarr(dim[0],dim[1]) slcQV = fltarr(dim[0],dim[1]) slcTK = fltarr(dim[0],dim[1]) ; Determine the grid spacing extents = VDF_GETEXTENTS(mfd) ; establish some constants: eps = 0.622 gamm = 287.04/1004. rgasmd=0.608 cpmd=0.887 gammamd=rgasmd-cpmd tlclc1=2840. tlclc2=3.5 tlclc3=4.805 tlclc4=55. thtecon1=3376. thtecon2=2.54 thtecon3=.81 ; process the data one slice at a time: maxslcETH = 0.0 minslcETH = 10000000. FOR z = 0, dim[2]-1 DO BEGIN vdc_bufreadslice, dfdP, slcP vdc_bufreadslice, dfdPB, slcPB vdc_bufreadslice, dfdQV, slcQV vdc_bufreadslice, dfdTK, slcTK PR = (slcP + slcPB)*0.01 Q = slcQV > 1.e-15 E = Q*PR/(eps+Q) tlcl = tlclc1/(alog(slcTK^tlclc2/E)-tlclc3)+tlclc4 slcETH = slcTK*(1000./PR)^(gamm*(1.+gammamd*Q))*EXP((thtecon1/tlcl-thtecon2)*Q*(1.+thtecon3*Q)) ; Report every 20 slices IF ((z MOD 20) EQ 0) THEN print,'reading slice ',z vdc_bufwriteslice, dfdETH, slcETH ENDFOR vdc_closevar, dfdP vdc_bufreaddestroy, dfdP vdc_closevar, dfdPB vdc_bufreaddestroy, dfdPB vdc_closevar, dfdQV vdc_bufreaddestroy, dfdQV vdc_closevar, dfdTK vdc_bufreaddestroy, dfdTK vdc_closevar, dfdETH vdc_bufwritedestroy, dfdETH ; ; Replace the vdf file with the new one, the first time through: ; IF (timestep EQ tsstart AND repeatvariables EQ 0) THEN vdf_write,mfd,vdffile print,'ETH_ completed of timestep ', timestep timestep += tsival ENDREP UNTIL (timestep GT tsmax) vdf_destroy, mfd END ================================================ FILE: share/examples/idl/MakeCmbo.pro ================================================ ; ; MakeCombo.pro ; ; Utility to calculate a combination of 3D variables in a vdf, ; and put it back into the VDF. ; i.e. calculate A*U/W+B*V/T+C/S, where U, V, W, T, and S are 3D variables and ; A, B, and C are constants. ; All variables involved must be present at full resolution, ; ; The vdf file is replaced. The previous vdf file is saved, with ; _saved appended to its name, in case of catastrophic failure ; ; Arguments are: ; vdffile = file path of the metadata file ; uVar, vVar, wVar, tVar, sVar = (keyword parameters) the 5 3D variable names. ; To add a constant, omit S and set C to your constant ; resVar = name for the combination ; A,B,C = coefficients ; tsstart = first time step for which to calculate the combination. If tsmax ; and tsival are not specified, then only tsstart is computed ; tsmax = (keyword parameter) last time step for which to compute combination ; tsival = (keyword parameter) interval between desired time steps ; PRO MakeCmbo, vdffile,U=uVar,V=vVar,W=wVar,T=tVar,S=sVar,A,B,C, $ resVar,tsstart,TSMAX=tsmax,TSIVAL=tsival ; ; Define some logical variables for conciseness ; gotU = keyword_set(uVar) gotW = keyword_set(wVar) gotV = keyword_set(vVar) gotT = keyword_set(tVar) gotS = keyword_set(sVar) ; ; Make sure we're using at least one variable ; IF ( ~( gotU || gotW || gotV || gotT || gotS ) ) THEN BEGIN print, "No variables added and no files modified" return ENDIF ; ; What to do if timestep keywords aren't defined ; IF ( ~keyword_set(tsmax) ) THEN tsmax = tsstart IF ( ~keyword_set(tsival) ) THEN tsival = 1 ; ; Initialize timestep ; timestep = tsstart ; ; Start with the current metadata: ; mfd = vdf_create(vdffile) ; ; save the current vdf file (in case we screw up) ; savedvdffile = STRING(vdffile,'_saved') vdf_write,mfd,savedvdffile ; ; Add the new variable name to the current variable names, if it's ; not already there ; nvarnames3d = 0 if (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin varnames = vdf_getvariables3d(mfd) nvarnames3d = n_elements(varnames) endif nvarnames2dxy = 0 if (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin varnames2dxy = vdf_getvariables2dxy(mfd) nvarnames2dxy = n_elements(varnames2dxy) endif numvarsarray = size(varnames) numvars = 1 + numvarsarray[1] newvarnames = strarr(numvars) ; Need to make sure this is not in the list! isinvariables = 0 FOR I = 0, numvars-2 DO BEGIN newvarnames[I] = varnames[I] if (varnames[I] EQ resVar) THEN isinvariables = 1 ENDFOR IF (isinvariables EQ 0) THEN newvarnames[numvars-1] = resVar ELSE newvarnames = varnames print,'The 3D variable names in the vdf will be: ',newvarnames ; ; reset the varnames in mfd to the new value: ; if (isinvariables EQ 0) THEN BEGIN if(nvarnames2dxy gt 0) THEN BEGIN vdf_setvarnames,mfd,[newvarnames,varnames2dxy] vdf_setvariables2dxy,mfd,varnames2dxy ENDIF ELSE BEGIN vdf_setvarnames,mfd,newvarnames ENDELSE ENDIF reflevel = vdf_getnumtransforms(mfd) numtimesteps = vdf_getnumtimesteps(mfd) ; ; Begin loop that iterates over time steps ; REPEAT BEGIN print, "Working on time step ", timestep ; ; Create "Buffered Read" objects for each variable to read the data, passing the ; metadata object handle created by vdf_create() as an argument ; IF ( gotU ) then dfdu = vdc_bufreadcreate(mfd) IF ( gotW ) then dfdw = vdc_bufreadcreate(mfd) IF ( gotV ) then dfdv = vdc_bufreadcreate(mfd) IF ( gotT ) then dfdt = vdc_bufreadcreate(mfd) IF ( gotS ) then dfds = vdc_bufreadcreate(mfd) dfdres = vdc_bufwritecreate(mfd) ; ; ; Determine the dimensions of one of the variables at the full transformation ; level. ; This is used as the dimension of all the variables ; Note. vdc_getdim() correctly handles dimension calucation for ; volumes with non-power-of-two dimensions. ; IF ( gotU ) THEN $ dim = vdc_getdim(dfdu, reflevel) ELSE $ IF ( gotW ) THEN $ dim = vdc_getdim(dfdw, reflevel) ELSE $ IF ( gotV ) THEN $ dim = vdc_getdim(dfdv, reflevel) ELSE $ IF ( gotT ) THEN $ dim = vdc_getdim(dfdt, reflevel) ELSE $ IF ( gotS ) THEN $ dim = vdc_getdim(dfds, reflevel) ELSE $ BEGIN print, "No variables present, early error detection failed" return ENDELSE ; ; Create appropriately sized arrays to hold the volume slices: ; IF ( gotU ) THEN sliceu = fltarr(dim[0], dim[1]) IF ( gotW ) THEN slicew = fltarr(dim[0], dim[1]) IF ( gotV ) THEN slicev = fltarr(dim[0], dim[1]) IF ( gotT ) THEN slicet = fltarr(dim[0], dim[1]) IF ( gotS ) THEN slices = fltarr(dim[0], dim[1]) sliceres = fltarr(dim[0], dim[1]) ; ; Prepare to read and write the indicated time step and variables ; IF ( gotU ) THEN vdc_openvarread, dfdu, timestep, uVar, reflevel IF ( gotW ) THEN vdc_openvarread, dfdw, timestep, wVar, reflevel IF ( gotV ) THEN vdc_openvarread, dfdv, timestep, vVar, reflevel IF ( gotT ) THEN vdc_openvarread, dfdt, timestep, tVar, reflevel IF ( gotS ) THEN vdc_openvarread, dfds, timestep, sVar, reflevel vdc_openvarwrite,dfdres, timestep, resVar, reflevel ; ; Read the volume one slice at a time ; FOR z = 0, dim[2]-1 DO BEGIN IF ( gotU ) THEN BEGIN vdc_bufreadslice, dfdu, sliceu sliceres = A*sliceu IF ( gotW ) THEN BEGIN vdc_bufreadslice, dfdw, slicew sliceres /= slicew ENDIF ENDIF ELSE BEGIN IF ( gotW ) THEN BEGIN vdc_bufreadslice, dfdw, slicew sliceres = A/slicew ENDIF ENDELSE IF ( gotV ) THEN BEGIN vdc_bufreadslice, dfdv, slicev IF ( gotT ) THEN BEGIN vdc_bufreadslice, dfdt, slicet sliceres += B*slicev/slicet ENDIF ELSE sliceres += B*slicev ENDIF ELSE BEGIN IF ( gotT ) THEN BEGIN vdc_bufreadslice, dfdt, slicet sliceres += B/slicet ENDIF ENDELSE IF ( gotS ) THEN BEGIN vdc_bufreadslice, dfds, slices sliceres += C/slices ENDIF ELSE sliceres += C vdc_bufwriteslice, dfdres, sliceres ; Report every 100 writes: IF ((Z MOD 100) EQ 0) THEN print,'wrote slice ',z ENDFOR vdc_closevar, dfdres IF ( gotU ) THEN BEGIN vdc_closevar, dfdu vdc_bufreaddestroy, dfdu ENDIF IF ( gotW ) THEN BEGIN vdc_closevar, dfdw vdc_bufreaddestroy, dfdw ENDIF IF ( gotV ) THEN BEGIN vdc_closevar, dfdv vdc_bufreaddestroy, dfdv ENDIF IF ( gotT ) THEN BEGIN vdc_closevar, dfdt vdc_bufreaddestroy, dfdt ENDIF IF ( gotS ) THEN BEGIN vdc_closevar, dfds vdc_bufreaddestroy, dfds ENDIF vdc_bufwritedestroy, dfdres ; ; Replace the vdf file with the new one ; vdf_write,mfd,vdffile ;vdf_destroy, mfd print,dim[2],' slices written to output file' timestep += tsival ENDREP UNTIL ( timestep GT tsmax ) vdf_destroy, mfd END ================================================ FILE: share/examples/idl/MakeLinCmb.pro ================================================ ; ; MakeLinCmb.pro ; ; Utility to calculate a linear combination of 3D variables in a vdf, ; and put it back into the VDF. ; i.e. calculate A*U+B*V+C, where U and V are 3D variables and ; A, B, and C are constants. If B is 0, V is ignored. ; U must be present at full resolution, ; If B != 0, then V must be present at full resolution ; ; This is performed one time-step at a time. ; The vdf file is replaced. The previous vdf file is saved, with ; _saved appended to its name, in case of catastrophic failure ; ; Arguments are: ; vdffile = file path of the metadata file ; uVar, vVar the 2 variable names (of U and V) ; resVar is the name for the linear combination ; A,B,C are the coefficients ; timestep specifies the (only) timestep for which the lin comb ; is calculated. If multiple timesteps are needed, ; the calculation must be repeated for each of them. ; PRO MakeLinCmb,vdffile,uVar,vVar,A,B,C,resVar,timestep ; ; Start with the current metadata: ; mfd = vdf_create(vdffile) ; ; save the current vdf file (in case we screw up) ; savedvdffile = STRING(vdffile,'_saved') vdf_write,mfd,savedvdffile ; ; Add the new variable name to the current variable names, if it's ; not already there ; nvarnames3d = 0 if (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin varnames = vdf_getvariables3d(mfd) nvarnames3d = n_elements(varnames) endif nvarnames2dxy = 0 if (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin varnames2dxy = vdf_getvariables2dxy(mfd) nvarnames2dxy = n_elements(varnames2dxy) endif numvarsarray = size(varnames) numvars = 1 + numvarsarray[1] newvarnames = strarr(numvars) ; Need to make sure this is not in the list! isinvariables = 0 FOR I = 0, numvars-2 DO BEGIN newvarnames[I] = varnames[I] if (varnames[I] EQ resVar) THEN isinvariables = 1 ENDFOR IF (isinvariables EQ 0) THEN newvarnames[numvars-1] = resVar ELSE newvarnames = varnames print,'The 3D variable names in the vdf will be: ',newvarnames ; ; reset the varnames in mfd to the new value: ; if (isinvariables EQ 0) THEN BEGIN if(nvarnames2dxy gt 0) THEN BEGIN vdf_setvarnames,mfd,[newvarnames,varnames2dxy] vdf_setvariables2dxy,mfd,varnames2dxy ENDIF ELSE BEGIN vdf_setvarnames,mfd,newvarnames ENDELSE ENDIF reflevel = vdf_getnumtransforms(mfd) numtimesteps = vdf_getnumtimesteps(mfd) ; ; Create "Buffered Read" objects for each variable to read the data, passing the ; metadata object handle created by vdf_create() as an argument ; dfdu = vdc_bufreadcreate(mfd) if ( B NE 0) then dfdv = vdc_bufreadcreate(mfd) dfdres = vdc_bufwritecreate(mfd) ; ; ; Determine the dimensions of the u-variable at the full transformation ; level. ; This is used as the dimension of all the variables ; Note. vdc_getdim() correctly handles dimension calucation for ; volumes with non-power-of-two dimensions. ; dim = vdc_getdim(dfdu, reflevel) ; ; Create appropriately sized arrays to hold the volume slices: ; sliceu = fltarr(dim[0], dim[1]) IF ( B NE 0) then slicev = fltarr(dim[0], dim[1]) sliceres = fltarr(dim[0], dim[1]) ; ; Prepare to read and write the indicated time step and variables ; vdc_openvarread, dfdu, timestep, uVar, reflevel IF ( B NE 0) then vdc_openvarread, dfdv, timestep, vVar, reflevel vdc_openvarwrite,dfdres, timestep, resVar, reflevel ; ; Read the volume one slice at a time ; FOR z = 0, dim[2]-1 DO BEGIN vdc_bufreadslice, dfdu, sliceu IF ( B NE 0) then vdc_bufreadslice, dfdv, slicev sliceres = sliceu*A + C IF ( B NE 0) then sliceres = sliceres + slicev*B vdc_bufwriteslice, dfdres, sliceres ; Report every 100 writes: IF ((Z MOD 100) EQ 0) THEN print,'wrote slice ',z ENDFOR vdc_closevar, dfdres vdc_closevar, dfdu IF ( B NE 0) then vdc_closevar, dfdv vdc_bufwritedestroy, dfdres vdc_bufreaddestroy, dfdu IF ( B NE 0) then vdc_bufreaddestroy, dfdv ; ; Replace the vdf file with the new one ; vdf_write,mfd,vdffile vdf_destroy, mfd print,dim[2],' slices written to output file' end ================================================ FILE: share/examples/idl/PrintMetaVDF.pro ================================================ ; $Id$ ; ; This example shows how to extact various bits of metadata information ; from a from a VDF data collection. ; ; Note: in order to run this example you must have first created ; a VDF data collection by running either the WriteVDF.pro ; or WriteTimeVaryVDF.pro example programs ; ; Create a VDF metadata object from an existing metadata file. The ; metadata file must already exist on disk, having been created from ; one of the example programs that generates a .vdf file. ; vdffile = 'test.vdf' mfd = vdf_create(vdffile) print, 'Block size = ', vdf_getblocksize(mfd) bs = vdf_getblocksize(mfd) print, 'Dimension = ', vdf_getdimension(mfd) print, 'Num Filter Coefficients = ', vdf_getfiltercoef(mfd) print, 'Num Lifting Coefficients = ', vdf_getliftingcoef(mfd) print, 'Num Wavelet Transforms = ', vdf_getnumtransforms(mfd) print, 'Grid Type = ', vdf_getgridtype(mfd) print, 'Coordinate Type = ', vdf_getcoordtype(mfd) print, 'Volume extents = ', vdf_getextents(mfd) print, 'Num Time Steps = ', vdf_getnumtimesteps(mfd) print, 'Variable Names = ', vdf_getvarnames(mfd) nvarnames3d = 0 if (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin varnames3d = vdf_getvariables3d(mfd) nvarnames3d = n_elements(varnames3d) print, '3D Variable Names = ', varnames3d endif nvarnames2dxy = 0 if (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin varnames2dxy = vdf_getvariables2dxy(mfd) nvarnames2dxy = n_elements(varnames2dxy) print, '2DXY Variable Names = ', varnames2dxy endif print, 'Global comment = ', vdf_getcomment(mfd) timesteps = vdf_getnumtimesteps(mfd) for ts = 0, timesteps[0]-1 do begin print, 'Time step ', ts, ' metadata' print, ' User Time = ', vdf_gettusertime(mfd, ts) if (n_elements(vdf_gettxcoords(mfd, ts)) ne 0) then print, ' XCoords = ', vdf_gettxcoords(mfd, ts) if (n_elements(vdf_gettycoords(mfd, ts)) ne 0) then print, ' YCoords = ', vdf_gettycoords(mfd, ts) if (n_elements(vdf_gettzcoords(mfd, ts)) ne 0) then print, ' ZCoords = ', vdf_gettzcoords(mfd, ts) if (n_elements(vdf_gettcomment(mfd, ts)) ne 0) then print, ' Comment = ', vdf_gettcomment(mfd, ts) for v = 0, nvarnames3d-1 do begin print, ' 3D Variable ', varnames3d[v], ':' if (n_elements(vdf_getvcomment(mfd, ts, varnames3d[v])) ne 0) then print, ' Comment = ', vdf_getvcomment(mfd, ts, varnames3d[v]) endfor for v = 0, nvarnames2dxy-1 do begin print, ' 2D Variable ', varnames2dxy[v], ':' if (n_elements(vdf_getvcomment(mfd, ts, varnames2dxy[v])) ne 0) then print, ' Comment = ', vdf_getvcomment(mfd, ts, varnames2dxy[v]) endfor endfor vdf_destroy, mfd end ================================================ FILE: share/examples/idl/QuickStartEx1.pro ================================================ ; $Id$ ; ; ; ; This example is referenced by the VAPOR Quick Start guide. It ; demonstrates VAPOR's interaction with IDL by importing a data ; subregion from VAPOR, calculating the Z component of vorticity, ; and exporting the new quantity back to VAPOR. ; ; ; Import a region of data previously exported by vaporgui. ; In this case, the components of the velocity field, scaled by ro ; ru = impregion(STATEINFO=stateinfo, VARNAME='ru') rv = impregion(STATEINFO=stateinfo, VARNAME='rv') rw = impregion(STATEINFO=stateinfo, VARNAME='rw') ro = impregion(STATEINFO=stateinfo, VARNAME='ro') ru = ru/ro rv = rv/ro rw = rw/ro dim = size(ru, /DIMENSIONS) ; ; Compute vorticity ; x=findgen(dim[0]) y=findgen(dim[1]) dvu=fltarr(dim[0], dim[1], dim[2]) omz=fltarr(dim[0], dim[1], dim[2]) for k=0,dim[2]-1 do begin tmp=reform(ru(*,*,k)) ; dvu(*,*,k)=myderiv(x,tmp,1,1) omz(*,*,k)=myderiv(y,tmp,2,1) tmp=reform(rv(*,*,k)) ; dvu(*,*,k)=dvu(*,*,k)+myderiv(y,tmp,2,1) omz(*,*,k)=myderiv(x,tmp,1,1)-omz(*,*,k) endfor ; ; Finally, export the region to a new VDC, named 'QuickStartEx1.vdf'. ; The new variable we have created will be named 'omz'. The new VDC maybe ; either merged into a running vaporgui session from whence the original ; data came, or may simply be loaded as a new data set ; ; Note there's an arithmetic error we can ignore... tmpvdf = 'QuickStartEx1.vdf' varname = 'omz' expregion, tmpvdf, stateinfo, varname, omz end ================================================ FILE: share/examples/idl/README.txt ================================================ This directory contains a number of examples demonstrating how to read and write VDF files from IDL ================================================ FILE: share/examples/idl/ReadRegionVDF.pro ================================================ ; $Id$ ; ; This example shows how to read a single data volume ; from a VDF data collection using a "Region Read" object. The data ; volume is not read in its entirety -- a spatial subregion (the first ; octant) is extracted from the full spatial domain. The volume ; resolution, however, is the native data resolution. ; ; Note: in order to run this example you must have first created ; a VDF data collection by running either the WriteVDF.pro ; or WriteTimeVaryVDF.pro example programs ; ; The refinement level of the multiresolution data ; A value of 0 indicates that the data should be read at the ; coarsest resolution, a value of 1 indicates the next refinement ; level, and so on ; A value of -1 implies a the finest (native) resolution ; reflevel = -1 ; ; Create a VDF metadata object from an existing metadata file. The ; metadata file must already exist on disk, having been created from ; one of the example programs that generates a .vdf file. ; vdffile = 'test.vdf' mfd = vdf_create(vdffile) ; ; Create a "Buffered Read" object to read the data, passing the ; metadata object handle created by vdf_create() as an argument ; dfd = vdc_regreadcreate(mfd) ; ; Determine the dimensions of the volume at the given transformation ; level. ; ; Note. vdc_getdim() correctly handles dimension calucation for ; volumes with non-power-of-two dimensions. ; dim = vdc_getdim(dfd, reflevel) ; ; Compute the coordinates for the desired subregion. In this case, the ; first octant will be read min = [0,0,0] max = (dim / 2) - 1 ; ; Create an appropriately sized array to hold the volume ; f = fltarr(dim/2) ; ; Prepare to read the indicated time step and variable ; varnames = ['ml'] vdc_openvarread, dfd, 0, varnames[0], reflevel ; ; Read the volume subregion. Note, unlike the buffered read/write ; objects, the "Region Reader" object does not read a single slice ; at a time -- it slurps in the entire in single call. ; vdc_regread, dfd, min, max, f ; ; Close the currently opened variable/time-step. ; vdc_closevar, dfd ; ; Destroy the "buffered read" data transformation object. ; We're done with it. ; vdc_regreaddestroy, dfd vdf_destroy, mfd end ================================================ FILE: share/examples/idl/ReadVDF.pro ================================================ ; $Id$ ; ; This example shows how to read a single data volume ; from a VDF data collection using a "Buffered Read" object. The entire ; spatial domain of the volume is retrieved (as opposed to fetching ; a spatial subregion). However, the volume is extracted at 1/8th ; its native spatial resolution (1/2 resolution along each dimension). ; ; Note: in order to run this example you must have first created ; a VDF data collection by running either the WriteVDF.pro ; or WriteTimeVaryVDF.pro example programs ; A value of 0 indicates that the data should be read at the ; coarsest resolution, a value of 1 indicates the next refinement ; level, and so on ; A value of -1 implies a the finest (native) resolution ; reflevel = 1 ; ; Create a VDF metadata object from an existing metadata file. The ; metadata file must already exist on disk, having been created from ; one of the example programs that generates a .vdf file. ; vdffile = 'test.vdf' mfd = vdf_create(vdffile) ; ; Create a "Buffered Read" object to read the data, passing the ; metadata object handle created by vdf_create() as an argument ; dfd = vdc_bufreadcreate(mfd) ; ; Determine the dimensions of the volume at the given transformation ; level. ; ; Note. vdc_getdim() correctly handles dimension calucation for ; volumes with non-power-of-two dimensions. ; dim = vdc_getdim(dfd, reflevel) ; ; Create an appropriately sized array to hold the volume ; f = fltarr(dim) slice = fltarr(dim[0], dim[1]) ; ; Prepare to read the indicated time step and variable ; varnames = ['ml'] vdc_openvarread, dfd, 0, varnames[0], reflevel ; ; Read the volume one slice at a time ; for z = 0, dim[2]-1 do begin vdc_bufreadslice, dfd, slice ; IDL won't let us read directly into a subscripted array - need ; to read into a 2D array and then copy to 3D :-( ; f[*,*,z] = slice endfor ; ; Close the currently opened variable/time-step. ; vdc_closevar, dfd ; ; Destroy the "buffered read" data transformation object. ; We're done with it. ; vdc_bufreaddestroy, dfd vdf_destroy, mfd end ================================================ FILE: share/examples/idl/WRFVortMagEx.pro ================================================ ; ; ; This example demonstrates the use of VAPOR with IDL ; on a WRF dataset, by importing a data ; subregion from VAPOR, calculating the magnitude of vorticity, ; and exporting the new variable (VMag) back to VAPOR. ; ; Import a region of data previously exported by vaporgui. ; In this case, the components of the velocity field ; and the ELEVATION variable ; U = impregion(STATEINFO=stateinfo, VARNAME='U') V = impregion(STATEINFO=stateinfo, VARNAME='V') W = impregion(STATEINFO=stateinfo, VARNAME='W') ELEV = impregion(STATEINFO=stateinfo, VARNAME='ELEVATION') mfd = vdf_create(stateinfo.VDFPATH) extents = VDF_GETEXTENTS(mfd) dfd = vdc_bufreadcreate(mfd) dims = vdc_getdim(dfd, -1) ; Calculate deltax, deltay based on horizontal size of full data deltax = (extents[3] - extents[0])/float(dims[0]) deltay = (extents[4] - extents[1])/float(dims[1]) ; ; Compute vorticity magnitude, results go in resx,resy,resz ; ;print, 'deltas: ', deltax, deltay print, 'input minmax ', min(U),max(U),min(V),max(V),min(W),max(W) wrf_curl_findiff,U,V,W,resx,resy,resz,deltax,deltay,ELEV ; ; Now, calculate and export vorticity magnitude ; vMag = sqrt( resx^2 + resy^2 + resz^2 ) minval = Min(vmag) maxval = Max(vmag) ;print,'min,max: ',minval, maxval tmpvdf = 'VMag.vdf' expregion, tmpvdf, stateinfo, 'VMag', vMag end ================================================ FILE: share/examples/idl/WriteTimeVaryVDF.pro ================================================ ; $Id$ ; ; This example shows how to create a time varying data set containing ; a single variable ; ; ; Dimensions of the data volumes - all volumes in a data set must be ; of the same dimension ; dim = [64,64,64] ; ; ; The number of coarsened approximations to create. A value of 0 ; indicates that the data should not be transformed, i.e. the ; data will only exist at it's native resolution. A value of 1 ; indicates that a single coarsening should be applied, and so on. ; num_levels = 1 ; ; Create a new VDF metadata object of the indicated dimension and ; transform ; level. vdf_create() returns a handle for future operations on ; the metadata object. ; mfd = vdf_create(dim,num_levels) ; ; Set the maximum number of timesteps in the data set. Note, valid data ; set may contain less than the maximum number of time steps, ; but not more ; timesteps = 10 vdf_setnumtimesteps, mfd,timesteps ; ; Set the names of the variables the data set will contain. In this case, ; only a single variable will be present, "ml" ; varnames = ['ml'] vdf_setvarnames, mfd, varnames ; ; Store the metadata object in a file for subsequent use ; vdffile = 'test.vdf' vdf_write, mfd, vdffile ; ; Destroy the metadata object. We're done with it. ; vdf_destroy, mfd ; ; At this point we've defined all of the metadata associated with ; the test data set. Now we're ready to begin populating the data ; set with actual data. Our data, in this case, will be a ; time-varying Marschner Lobb function sampled on a regular grid ; ; ; Create a "buffered write" data transformation object. The data ; transformation object will permit us to write (transform) raw ; data into the data set. The metadata for the data volumes is ; obtained from the metadata file we created previously. I.e. ; 'vdffile' must contain the path to a previously created .vdf ; file. The 'vdf_bufwritecreate' returns a handle, 'dfd', for ; subsequent ; operations. ; dfd = vdc_bufwritecreate(vdffile) ; ; Generate a time varying data, set one volume at a time, saving each ; volume into the data collection ; alpha = 0.05 for ts = 0, timesteps-1 do begin ; Create a synthetic data volume ; f = marschner_lobb(dim[0], dim[1], dim[2], ALPHA=alpha) alpha = alpha + 0.05 ; ; Prepare the data set for writing. We need to identify the time step ; and the name of the variable that we wish to store ; vdc_openvarwrite, dfd, ts, varnames[0] ; ; Write (transform) the volume to the data set one slice at a time ; for z = 0, dim[2]-1 do begin vdc_bufwriteslice, dfd, f[*,*,z] endfor ; ; Close the currently opened variable/time-step. We're done writing ; to it ; vdc_closevar, dfd endfor ; ; Destroy the "buffered write" data transformation object. ; We're done with it. ; vdc_bufwritedestroy, dfd end ================================================ FILE: share/examples/idl/WriteVDF.pro ================================================ ; $Id$ ; ; This example shows how to create a data set containing ; a single variable and at a single time step ; ; ; Dimensions of the data volumes - all volumes in a data set must be ; of the same dimension ; dim = [64,64,64] ; ; ; The number of coarsened approximations to create. A value of 0 ; indicates that the data should not be transformed, i.e. the ; data will only exist at it's native resolution. A value of 1 ; indicates that a single coarsening should be applied, and so on. ; num_levels = 1 ; ; Create a new VDF metadata object of the indicated dimension and ; transform ; level. vdf_create() returns a handle for future operations on ; the metadata object. ; mfd = vdf_create(dim,num_levels) ; ; Set the maximum number of timesteps in the data set. Note, valid data ; set may contain less than the maximum number of time steps, ; but not more ; timesteps = 1 vdf_setnumtimesteps, mfd,timesteps ; ; Set the names of the variables the data set will contain. In this case, ; only a single variable will be present, "ml" ; varnames = ['ml'] vdf_setvarnames, mfd, varnames ; ; Store the metadata object in a file for subsequent use ; vdffile = 'test.vdf' vdf_write, mfd, vdffile ; ; Destroy the metadata object. We're done with it. ; vdf_destroy, mfd ; ; At this point we've defined all of the metadata associated with ; the test data set. Now we're ready to begin populating the data ; set with actual data. Our data, in this case, will be a ; time-varying Marschner Lobb function sampled on a regular grid ; ; ; Create a "buffered write" data transformation object. The data ; transformation object will permit us to write (transform) raw ; data into the data set. The metadata for the data volumes is ; obtained from the metadata file we created previously. I.e. ; 'vdffile' must contain the path to a previously created .vdf ; file. The 'vdc_bufwritecreate' returns a handle, 'dfd', for ; subsequent ; operations. ; dfd = vdc_bufwritecreate(vdffile) ; Create a synthetic data volume ; f = marschner_lobb(dim[0], dim[1], dim[2]) ; ; Prepare the data set for writing. We need to identify the time step ; and the name of the variable that we wish to store ; vdc_openvarwrite, dfd, 0, varnames[0], -1 ; ; Write (transform) the volume to the data set one slice at a time ; for z = 0, dim[2]-1 do begin vdc_bufwriteslice, dfd, f[*,*,z] endfor ; ; Close the currently opened variable/time-step. We're done writing ; to it ; vdc_closevar, dfd ; ; Destroy the "buffered write" data transformation object. ; We're done with it. ; vdc_bufwritedestroy, dfd end ================================================ FILE: share/examples/idl/curl_findiff.pro ================================================ ; $Id$ ; ; NAME: ; CURL_FINDIFF ; ; PURPOSE: ; Computes the curl of a vector field using sixth ; order finite differences in regular Cartesian grids ; ; CALLING SEQUENCE: ; CURL_FINDIFF,INX,INY,INZ,OUTX,OUTY,OUTZ,DX,DY,DZ ; ; PARAMETERS: ; INX[in]: 3D array with the x component of the field ; INY[in]: 3D array with the y component of the field ; INZ[in]: 3D array with the z component of the field ; OUTX[out]: 3D array with the x component of the curl ; OUTY[out]: 3D array with the y component of the curl ; OUTZ[out]: 3D array with the z component of the curl ; DX[in]: spatial step of the grid in the x direction ; DY[in]: spatial step of the grid in the y direction. ; DZ[in]: spatial step of the grid in the z direction. ; ; ; COMMON BLOCKS: ; None ; ;- PRO curl_findiff,inx,iny,inz,outx,outy,outz,dx,dy,dz on_error,2 ;return to caller if an error occurs deriv_findiff,inz,aux1,2,dy ;x component of the curl deriv_findiff,iny,aux2,3,dz outx = aux1-aux2 deriv_findiff,inx,aux1,3,dz ;y component of the curl deriv_findiff,inz,aux2,1,dx outy = aux1-aux2 deriv_findiff,iny,aux1,1,dx ;z component of the curl deriv_findiff,inx,aux2,2,dy outz = aux1-aux2 end ================================================ FILE: share/examples/idl/deriv_findiff.pro ================================================ ; $Id$ ; ; NAME: ; DERIV_FINDIFF ; ; PURPOSE: ; Computes first order derivatives using sixth order finite ; differences in regular Cartesian grids ; ; CALLING SEQUENCE: ; DERIV_FINDIFF,IN,OUT,DIR,DX ; ; PARAMETERS: ; IN[in]: 3D array with the field component ; OUT[out]: 3D array with the spatial derivative ; DIR[in]: direction (1,2, or 3) of the the derivative ; DX[in]: spatial step of the grid in the direction DIR ; ; COMMON BLOCKS: ; None ; ;- PRO deriv_findiff,in,out,dir,dx on_error,2 ;return to caller if an error occurs s = size(in) ;size of the input array out = in ;output has the same size than input if dir eq 1 then begin ;derivative for dir=1 for i = 0,2 do begin out(i,*,*) = (-11*in(i,*,*)+18*in(i+1,*,*)-9*in(i+2,*,*)+2*in(i+3,*,*))$ /(6*dx) ;forward differences near the first boundary endfor for i = 3,s(dir)-4 do begin out(i,*,*) = (-in(i-3,*,*)+9*in(i-2,*,*)-45*in(i-1,*,*)+45*in(i+1,*,*) $ -9*in(i+2,*,*)+in(i+3,*,*))/(60*dx) ;centered differences endfor for i = s(dir)-3,s(dir)-1 do begin out(i,*,*) = (-2*in(i-3,*,*)+9*in(i-2,*,*)-18*in(i-1,*,*)+11*in(i,*,*))$ /(6*dx) ;backward differences near the second boundary endfor endif if dir eq 2 then begin ;derivative for dir=2 for i = 0,2 do begin out(*,i,*) = (-11*in(*,i,*)+18*in(*,i+1,*)-9*in(*,i+2,*)+2*in(*,i+3,*))$ /(6*dx) ;forward differences near the first boundary endfor for i = 3,s(dir)-4 do begin out(*,i,*) = (-in(*,i-3,*)+9*in(*,i-2,*)-45*in(*,i-1,*)+45*in(*,i+1,*) $ -9*in(*,i+2,*)+in(*,i+3,*))/(60*dx) ;centered differences endfor for i = s(dir)-3,s(dir)-1 do begin out(*,i,*) = (-2*in(*,i-3,*)+9*in(*,i-2,*)-18*in(*,i-1,*)+11*in(*,i,*))$ /(6*dx) ;backward differences near the second boundary endfor endif if dir eq 3 then begin ;derivative for dir=3 for i = 0,2 do begin out(*,*,i) = (-11*in(*,*,i)+18*in(*,*,i+1)-9*in(*,*,i+2)+2*in(*,*,i+3))$ /(6*dx) ;forward differences near the first boundary endfor for i = 3,s(dir)-4 do begin out(*,*,i) = (-in(*,*,i-3)+9*in(*,*,i-2)-45*in(*,*,i-1)+45*in(*,*,i+1)$ -9*in(*,*,i+2)+in(*,*,i+3))/(60*dx) ;centered differences endfor for i = s(dir)-3,s(dir)-1 do begin out(*,*,i) = (-2*in(*,*,i-3)+9*in(*,*,i-2)-18*in(*,*,i-1)+11*in(*,*,i))$ /(6*dx) ;backward differences near the second boundary endfor endif end ================================================ FILE: share/examples/idl/div_findiff.pro ================================================ ; $Id$ ; ; NAME: ; DIV_FINDIFF ; ; PURPOSE: ; Computes the divergence of a vector field using sixth ; order finite differences in regular Cartesian grids ; ; CALLING SEQUENCE: ; DIV_FINDIFF,INX,INY,INZ,OUT,DX,DY,DZ ; ; PARAMETERS: ; INX[in]: 3D array with the x component of the field ; INY[in]: 3D array with the y component of the field ; INZ[in]: 3D array with the z component of the field ; OUT[out]: 3D array with the divergence ; DX[in]: spatial step of the grid in the x direction ; DY[in]: spatial step of the grid in the y direction. ; DZ[in]: spatial step of the grid in the z direction. ; ; ; COMMON BLOCKS: ; None ; ;- PRO div_findiff,inx,iny,inz,out,dx,dy,dz on_error,2 ;return to caller if an error occurs deriv_findiff,inx,aux1,1,dx ;x component of the div deriv_findiff,iny,aux2,2,dy ;y component of the div deriv_findiff,inz,aux3,3,dz ;z component of the div out = aux1+aux1+aux3 end ================================================ FILE: share/examples/idl/elev_deriv.pro ================================================ ; NAME: ; ELEV_DERIV ; ; PURPOSE: ; Computes first order z-derivatives using 6 order differences ; differences in WRF grids. The z-derivative is based on ; the ratio of differences in the field variable to differences ; in the ELEVATION variable, both in the z-coordinate. ; No provision is made for a non-increasing ELEVATION variable... ; that could result in divide by zero. ; The ELEV variable must have the same dimensions as IN ; ; CALLING SEQUENCE: ; ELEV_DERIV,ELEV,IN,OUT ; ; PARAMETERS: ; IN[in]: 3D array of field variable ; OUT[out]: 3D array with the z derivative ; ELEV[in]: 3D array of elevations (z-coordinates) ; ; COMMON BLOCKS: ; None ; ;- PRO elev_deriv,in,out,elev on_error,2 ;return to caller if an error occurs s = size(in) ;size of the input array ;output has the same size than input out = fltarr(s(1),s(2),s(3)) for i = 0,2 do begin out(*,*,i) = (-11*in(*,*,i)+18*in(*,*,i+1)-9*in(*,*,i+2)+2*in(*,*,i+3))$ /(-11*elev(*,*,i)+18*elev(*,*,i+1)-9*elev(*,*,i+2)+2*elev(*,*,i+3)) ;forward differences near the first boundary endfor for i = 3,s(3)-4 do begin out(*,*,i) = (-in(*,*,i-3)+9*in(*,*,i-2)-45*in(*,*,i-1)+45*in(*,*,i+1)$ -9*in(*,*,i+2)+in(*,*,i+3))$ /(-elev(*,*,i-3)+9*elev(*,*,i-2)-45*elev(*,*,i-1)+45*elev(*,*,i+1)$ -9*elev(*,*,i+2)+elev(*,*,i+3)) ;centered differences endfor for i = s(3)-3,s(3)-1 do begin out(*,*,i) = (-2*in(*,*,i-3)+9*in(*,*,i-2)-18*in(*,*,i-1)+11*in(*,*,i))$ /(-2*elev(*,*,i-3)+9*elev(*,*,i-2)-18*elev(*,*,i-1)+11*elev(*,*,i)) ;backward differences near the second boundary endfor end ================================================ FILE: share/examples/idl/expregion.pro ================================================ ; ; NAME: ; EXPREGION ; ; PURPOSE: ; Export a volume subregion to VAPoR. This procedure is a convenience ; function for exporting a subvolume to VAPOR. In essense, it simply ; creates a mini VDC with the same basic attributes (dimension, ; user extents, num transforms, etc) as an existing "parent" VDC. ; The new, mini VDC may be merged with the parent VDC by the ; vapor gui. ; ; N.B. This procedure assumes that the region to be exported is sampled ; at the native (highest) resolution of the grid. ; ; CALLING SEQUENCE: ; EXPREGION, VDF, STATEINFO, VARNAMES, ARRAY0 [, ARRAY1 [, ARRAY2...[, ARRAY5]]] ; ; KEYWORD PARAMETERS: ; ; APPEND: A boolean indicating whether exported variables should ; be written to an existing .vdf file named by VDF. If not ; set a new .vdf file will be created ; ; COORD: A three-element array containing the starting XYZ ; coordinates (in voxels) of the region ; to be exported relative to the parent VDC. The ; default is to use the MINRANGE structure member of ; the STATEINFO paramater ; ; NUMTS: If set specifies the number of timesteps to allow ; for in the .vdf file specified by VDF. This keyword ; and the APPEND keyword are mutually exclusive. ; ; TS: If set specifies the time set offset for the ; exported variable. The default is 0 ; ; VAR2DXY: If set the variables 2D arrays in the XY plane ; ; ; INPUTS: ; ; VDF: Path name of the vdf file that will describe ; the region ; ; ; STATEINFO: A stateinfo structure returned by vaporimport() (the ; parent VDC) ; ; VARNAMES: The names of the variables that are being exported. ; The number of ARRAY arguments must agree with the ; number of names contained in VARNAMES ; ; ARRAY0: First 3D array containig the region to export ; ARRAY1: Second 3D array containig the region to export ; ARRAY2: Third 3D array containig the region to export ; ARRAY3: Fourth 3D array containig the region to export ; ARRAY4: Fifth 3D array containig the region to export ; ARRAY5: Sixth 3D array containig the region to export ; ; OUTPUTS: ; ; COMMON BLOCKS: ; None. ; ;- pro expregion, vdf, stateinfo, varnames, array0, array1, array2, array3, array4, array5, COORD=coord, APPEND=append, NUMTS=numts, TS=ts, VAR2DXY=var2dxy on_error,2 ;Return to caller if an error occurs if keyword_set(coord) eq 0 then coord = stateinfo.minrange if keyword_set(numts) eq 0 then numts = 1 if keyword_set(ts) eq 0 then ts = 0 if keyword_set(append) eq 0 then append = 0 if keyword_set(var2dxy) eq 0 then var2dxy = 0 varnamesvec = [varnames] ; Ensure varnames is an array ; ; Open the .vdf file describing the parent VDC ; mfd = vdf_create(stateinfo.vdfpath) ; ; Extract the relevant attributes from the parent VDC ; nfiltercoef = vdf_getfiltercoef(mfd) nliftingcoef = vdf_getliftingcoef(mfd) bs = vdf_getblocksize(mfd) nxforms = vdf_getnumtransforms(mfd) dim = vdf_getdimension(mfd) vdf_destroy, mfd ; ; If the append keyword is set create a new, "mini" VDC with the ; same basic attributes of the parente VDC. Otherwise the .vdf file ; referenced by 'vdf' must already exist. ; if (append eq 0) then begin mfd = vdf_create(dim, nxforms, BS=bs, NFILTERCOEF=nfiltercoef, NLIFTINGCOEF=nliftingcoef) ; ; Add the new variable to the mini VDC ; vdf_setvarnames, mfd, varnamesvec if (var2dxy eq 1) then begin vdf_setvariables2dxy, mfd, varnamesvec endif vdf_setnumtimesteps, mfd, numts vdf_write, mfd, vdf vdf_destroy, mfd endif ; ; Now write the arrays to the new VDC ; if (var2dxy eq 1) then begin dfd = vdc_regwritecreate2d(vdf) endif else begin dfd = vdc_regwritecreate(vdf) endelse ; ; Brain damaged code for handling optional number of function ; parameters ; if (n_elements(array0) ne 0) and (n_elements(varnamesvec) ge 1) then begin vdc_openvarwrite, dfd, ts, varnamesvec[0], -1 vdc_regwrite, dfd, array0, coord vdc_closevar, dfd endif if (n_elements(array1) ne 0) and (n_elements(varnamesvec) ge 2) then begin vdc_openvarwrite, dfd, ts, varnamesvec[1], -1 vdc_regwrite, dfd, array1, coord vdc_closevar, dfd endif if (n_elements(array2) ne 0) and (n_elements(varnamesvec) ge 3) then begin vdc_openvarwrite, dfd, ts, varnamesvec[2], -1 vdc_regwrite, dfd, array2, coord vdc_closevar, dfd endif if (n_elements(array3) ne 0) and (n_elements(varnamesvec) ge 4) then begin vdc_openvarwrite, dfd, ts, varnamesvec[3], -1 vdc_regwrite, dfd, array3, coord vdc_closevar, dfd endif if (n_elements(array4) ne 0) and (n_elements(varnamesvec) ge 5) then begin vdc_openvarwrite, dfd, ts, varnamesvec[4], -1 vdc_regwrite, dfd, array4, coord vdc_closevar, dfd endif if (n_elements(array5) ne 0) and (n_elements(varnamesvec) ge 6) then begin vdc_openvarwrite, dfd, ts, varnamesvec[5], -1 vdc_regwrite, dfd, array5, coord vdc_closevar, dfd endif vdc_regwritedestroy, dfd end ================================================ FILE: share/examples/idl/impexp.pro ================================================ ; $Id$ ; ; This example shows how to importion a region of data from vaporgui, ; perform an operation on that region, rename and export the region back ; to vaporgui ; ; ; Import a region of data previously exported by vaporgui ; region = impregion(STATEINFO=stateinfo) ; ; Perform an operation on the imported data - in this example we ; apply a simple algebraic operator ; region = region * region ; ; Finally, export the region to a new VDC, named 'impexp.vdf'. The new ; variable we have created will be named 'varsqr'. The new VDC maybe ; either import into a running vaporgui session from whence the original ; data came, or may simply be loaded as a new data set ; tmpvdf = 'impexp.vdf' varname = 'varsqr' expregion, tmpvdf, stateinfo, varname, region end ================================================ FILE: share/examples/idl/impregion.pro ================================================ ; $Id$ ; ; NAME: ; IMPREGION ; ; PURPOSE: ; Import a volume subregion from VAPoR. The subregion must ; first have been exported by VAPoR ; endian or big endian format. ; ; CALLING SEQUENCE: ; IMPREGION ; ; KEYWORD PARAMETERS: ; REFLEVEL[in]: The desired refinement level. If this keyword is ; not set, the subregion will be imported at full resolution ; ; VARNAME[in]: The desired variable. If this keyword is ; not set, the default exported variable returned by ; 'vaporimport()' will be obtained ; ; TIMESTEP[in]: The desired time step. If this keyword is ; not set, the default exported time step returned by ; 'vaporimport()' will be obtained ; ; STATEINFO[out]: If this keyword is present the output of ; the 'vaporimport()' function is returned by the keyword ; argument, possibly modified by the VARNAME and TIMESTEP ; keyword. ; ; OUTPUTS: ; The region is returned ; ; COMMON BLOCKS: ; None. ; ;- function impregion, REFLEVEL=reflevel, STATEINFO=stateinfo, VARNAME=varname, TIMESTEP=timestep on_error,2 ;Return to caller if an error occurs if keyword_set(reflevel) eq 0 then reflevel = -1 ; Get the state info exported from VAPoR that describes the ; region of interest. vaporimport() returns a structure with ; the following fields: ; VDFPATH : Path to the .vdf file ; TIMESTEP : Time step of the volume subregion of interest ; VARNAME : Variable name of volume subregion of interest ; MINRANGE : Minimum extents of region of interest in volume ; coordinates specified relative to the finest resolution ; MAXRANGE : Maximum extents of region of interest in volume ; coordinates specified relative to the finest resolution stateinfo = vaporimport() if keyword_set(varname) then begin stateinfo.varname = varname endif else begin varname = stateinfo.varname endelse ;if keyword_set(timestep) then begin if arg_present(timestep) then begin stateinfo.timestep = timestep endif else begin timestep = stateinfo.timestep endelse mfd = vdf_create(stateinfo.vdfpath) vars3d = vdf_getvariables3d(mfd) varIs2D = 1 for i=0, n_elements(vars3d)-1 do begin if (vars3d[i] eq varname) then varIs2D = 0 endfor ; ; Create a "Buffered Read" object to read the data, passing the ; metadata object handle created by vdf_create() as an argument ; if (varIs2D) then begin dfd = vdc_regreadcreate2d(mfd) endif else begin dfd = vdc_regreadcreate(mfd) endelse ; ; Transform coordinates from finest resolution to resolution ; of interest. Note, the coordinates returned in 'stateinfo' ; are in voxel coordinates relative to the finest resolution level. ; We first convert voxel coordinates to user coordinates, then ; convert user coordinates back to voxel coordinates, but at ; the requested refinement level. ; minu = vdc_mapvox2user(dfd, -1, timestep,stateinfo.minrange) min = vdc_mapuser2vox(dfd,reflevel,timestep,minu) maxu = vdc_mapvox2user(dfd, -1, timestep,stateinfo.maxrange) max = vdc_mapuser2vox(dfd,reflevel,timestep,maxu) ; Create an array large enough to hold the volume subregion ; if (varIs2D) then begin f = fltarr(max[0]-min[0]+1,max[1]-min[1]+1) endif else begin f = fltarr(max[0]-min[0]+1,max[1]-min[1]+1,max[2]-min[2]+1) endelse ; Select the variable and time step we want to read ; vdc_openvarread, dfd, timestep, varname, reflevel ; Read the subregion ; vdc_regread, dfd, min, max, f vdc_closevar, dfd vdc_regreaddestroy, dfd return, f end ================================================ FILE: share/examples/idl/marschner_lobb.pro ================================================ ; $Id$ ; ; Evaluate the 3D marschner lobb function over a grid at the specified ; resolution. The sampled function is returned. ; function marschner_lobb, nx, ny, nz, ALPHAFLAG = ALPHA, FMFLAG=FM if (n_elements(ALPHA) eq 0) then ALPHA = 0.25 if (n_elements(FM) eq 0) then FM = 6.0 rarr = fltarr(nx,ny,nz) zarr = fltarr(nx,ny,nz) PI = 3.14159265358979323846 for z = 0, nz-1 do begin for y = 0, ny-1 do begin yc = (y / float(ny-1)) - 0.5 for x = 0, nx-1 do begin xc = (x / float(nx-1)) - 0.5 rarr[x,y,z] = sqrt(xc*xc + yc*yc) zarr[x,y,z] = (z / float(nz-1)) - 0.5 endfor endfor endfor pr = cos(2*PI*FM*cos(PI*rarr/2.0)) f = (1.0 - sin(PI*zarr/2.0) + (ALPHA * (1.0 + pr))) / (2*(1+ALPHA)) return, f end ================================================ FILE: share/examples/idl/myderiv.pro ================================================ ; ; $Id$; ; FUNCTION myderiv,x,fx,n,nonperiod ; ; nx=n_elements(x) s=size(fx) ndim=s(0) ; ; Centered differences ; if (ndim eq 1) then begin dfx=-1.*(shift(fx,1)-shift(fx,-1))/(x(2)-x(0)) if (nonperiod ne 0) then begin lf=0 rt=s(1)-1 dfx(lf)=(-3.0d00*fx(lf)+4.0d00*fx(lf+1)-fx(lf+2))/(x(2)-x(0)) dfx(rt)=(fx(rt-2)-4.0d00*fx(rt-1)+3.0d00*fx(rt))/(x(2)-x(0)) endif endif if (ndim eq 2) then begin if(n eq 1) then begin dfx=-1.*(shift(fx,1,0)-shift(fx,-1,0))/(x(2)-x(0)) if (nonperiod ne 0) then begin lf=0 rt=s(1)-1 dfx(lf,*)=(-3.0d00*fx(lf,*)+4.0d00*fx(lf+1,*)-fx(lf+2,*))/(x(2)-x(0)) dfx(rt,*)=(fx(rt-2,*)-4.0d00*fx(rt-1,*)+3.0d00*fx(rt,*))/(x(2)-x(0)) endif endif if(n eq 2) then begin dfx=-1.*(shift(fx,0,1)-shift(fx,0,-1))/(x(2)-x(0)) if (nonperiod ne 0) then begin lf=0 rt=s(2)-1 dfx(*,lf)=(-3.0d00*fx(*,lf)+4.0d00*fx(*,lf+1)-fx(*,lf+2))/(x(2)-x(0)) dfx(*,rt)=(fx(*,rt-2)-4.0d00*fx(*,rt-1)+3.0d00*fx(*,rt))/(x(2)-x(0)) endif endif endif if (ndim eq 3) then begin if(n eq 1) then begin dfx=-1.*(shift(fx,1,0,0)-shift(fx,-1,0,0))/(x(2)-x(0)) if (nonperiod ne 0) then begin lf=0 rt=s(1)-1 dfx(lf,*,*)=(-3.0d00*fx(lf,*,*)+4.0d00*fx(lf+1,*,*)-fx(lf+2,*,*))/(x(2)-x(0)) dfx(rt,*,*)=(fx(rt-2,*,*)-4.0d00*fx(rt-1,*,*)+3.0d00*fx(rt,*,*))/(x(2)-x(0)) endif endif if(n eq 2) then begin dfx=-1.*(shift(fx,0,1,0)-shift(fx,0,-1,0))/(x(2)-x(0)) if (nonperiod ne 0) then begin lf=0 rt=s(2)-1 dfx(*,lf,*)=(-3.0d00*fx(*,lf,*)+4.0d00*fx(*,lf+1,*)-fx(*,lf+2,*))/(x(2)-x(0)) dfx(*,rt,*)=(fx(*,rt-2,*)-4.0d00*fx(*,rt-1,*)+3.0d00*fx(*,rt,*))/(x(2)-x(0)) endif endif if(n eq 3) then begin dfx=-1.*(shift(fx,0,0,1)-shift(fx,0,0,-1))/(x(2)-x(0)) if (nonperiod ne 0) then begin lf=0 rt=s(3)-1 dfx(*,*,lf)=(-3.0d00*fx(*,*,lf)+4.0d00*fx(*,*,lf+1)-fx(*,*,lf+2))/(x(2)-x(0)) dfx(*,*,rt)=(fx(*,*,rt-2)-4.0d00*fx(*,*,rt-1)+3.0d00*fx(*,*,rt))/(x(2)-x(0)) endif endif endif ; return,dfx end ================================================ FILE: share/examples/idl/pencil2vapor.pro ================================================ PRO pencil2vapor,topdir,numprocs, vdffile,timestep,varfilename ; ; Program to convert a directory of pencil files into a vapor dataset. ; Arguments are: ; topdir = absolute path to directory where pencil data is stored ; numprocs = number of procN subdirectories (N goes from 0 to numprocs -1) ; vdffile = absolute path, including filename, of vdf file for the result. ; The vdf file should be created by running vdffile before this. ; The vdf file should specify names for the variables, in the same order ; as they appear in the pencil var.dat files ; timestep = an integer timestep for the data to be converted. Must be within ; the number of time steps specified in the vdf file ; varfilename = a string used to identify the name of the var.dat files. If it ; is not specified, then the default is "var" ; ; The chunks associated with the different processors are not assumed to be ; the same size, however, all chunks at a given x-coordinate have the same x-thickness, ; and likewize for the chunks at a given y or z coordinate ; IF (N_PARAMS() LT 5 ) THEN varfilename = 'var' varfilename = varfilename + '.dat' ; ; Create tables to hold information about data: ; xsize = intarr(numprocs) ysize = intarr(numprocs) zsize = intarr(numprocs) xposition = intarr(numprocs) yposition = intarr(numprocs) zposition = intarr(numprocs) ; ; Read dim.dat files: ; ; (while finding the thickest z-size) maxzthick = 0 FOR I = 0, numprocs-1 DO BEGIN dimfile = topdir+'/proc'+STRTRIM(STRING(I),1)+'/dim.dat' OPENR, 1, dimfile ; Read the first line (contains sizes) READF,1,sizex,sizey,sizez,foo,bar xsize[I] = sizex ysize[I] = sizey zsize[I] = sizez IF (sizez GT maxzthick) THEN maxzthick = sizez ; Read second line (precision, a string) prec = ' ' READF,1,prec ; Read third line (ghost widths) READF,1,ghostx,ghosty,ghostz ; Read the last line (contains positions) READF,1,xpos,ypos,zpos xposition[I] = xpos yposition[I] = ypos zposition[I] = zpos CLOSE, 1 ENDFOR maxzthick = maxzthick - 2*ghostz ; Determine the x,y,and z-grid spacing xspacing = intarr(numprocs) yspacing = intarr(numprocs) zspacing = intarr(numprocs) xspacing[*] = 0 yspacing[*] = 0 yspacing[*] = 0 FOR I = 0, numprocs-1 DO BEGIN xspacing[xposition[I]] = xsize[I] - 2*ghostx yspacing[yposition[I]] = ysize[I] - 2*ghosty zspacing[zposition[I]] = zsize[I] - 2*ghostz ENDFOR ; Accumulate the spacings xtot = 0 ytot = 0 ztot = 0 FOR I = 0, numprocs -1 DO BEGIN IF (xspacing[I] NE 0) THEN BEGIN xtot = xtot + xspacing[I] xspacing[I] = xtot - xspacing[I] ENDIF IF (yspacing[I] NE 0) THEN BEGIN ytot = ytot + yspacing[I] yspacing[I] = ytot - yspacing[I] ENDIF IF (zspacing[I] NE 0) THEN BEGIN numslabs = I+1 ztot = ztot + zspacing[I] zspacing[I] = ztot - zspacing[I] ENDIF ENDFOR ; Sort the tables on z-coordinate: ; fileorder = SORT(zposition) ; Create the metadata from the vdffile. ; Find the dimensions of the data. ; These had better agree with the pencil data! ; mfd = vdf_create(vdffile) dim = vdf_getdimension(mfd) varnames = vdf_getvarnames(mfd) sz = size(varnames) numvariables = sz[1] ; ; Determine how many chunks of pencil data are associated with a slab: ; chunksperslab = numprocs/numslabs ; Allocate enough memory to hold the largest slab: slabdata = FLTARR(dim[0],dim[1],maxzthick) ; Loop over each variable FOR varnum = 0, numvariables -1 DO BEGIN print, 'assembling variable ',varnames[varnum] dfd = vdc_bufwritecreate(mfd) vdc_openvarwrite, dfd, timestep, varnames[varnum], -1 ; ; Loop over the slabs: FOR slab = 0, numslabs -1 DO BEGIN ; For each slab, loop over the proc directories (chunks) associated with it: FOR chunk = 0, chunksperslab-1 DO BEGIN chunknum = slab*chunksperslab + chunk dirnum = fileorder[chunknum] ; read the chunk into the dataarray ; Create an array to hold a variable chunk as it is read from the proc directory IF (prec EQ 'D') THEN BEGIN dataarray = DBLARR(xsize[dirnum],ysize[dirnum],zsize[dirnum],numvariables) ENDIF ELSE dataarray = FLTARR(xsize[dirnum],ysize[dirnum],zsize[dirnum],numvariables) varfile = topdir+'/proc'+STRTRIM(STRING(dirnum),1)+'/'+varfilename openr,1,varfile,/f77 readu,1,dataarray close,1 ; ; Then copy the data chunks into the data slab: minx = xspacing[xposition[dirnum]] maxx = FIX(minx + xsize[dirnum] - 2*ghostx-1) miny = yspacing[yposition[dirnum]] maxy = FIX(miny + ysize[dirnum] - 2*ghosty-1) minz = zspacing[zposition[dirnum]] maxz = FIX(minz + zsize[dirnum] - 2*ghostz-1) slabdata[minx:maxx,miny:maxy,0:(maxz-minz)] = FLOAT(dataarray[ghostx:xsize[dirnum]-ghostx-1,ghosty:ysize[dirnum]-ghosty-1,ghostz:zsize[dirnum]-ghostz-1,varnum]) ENDFOR ; now the full slab is populated, write it to the vdf, one ; z-slice at a time ; FOR z = 0, (maxz-minz) DO BEGIN vdc_bufwriteslice, dfd, slabdata[*,*,z] ENDFOR ENDFOR ; Now close the dfd vdc_closevar, dfd vdc_bufwritedestroy,dfd ENDFOR END ================================================ FILE: share/examples/idl/wrf_curl_findiff.pro ================================================ ; ; NAME: ; WRF_CURL_FINDIFF ; ; PURPOSE: ; Computes the curl of a vector field using sixth ; order finite differences on WRF grid ; Uses an interpolation scheme described by Mark Stoellinga ; to directly calculate the derivatives on the WRF grid. ; The 6th order difference terms are due to Pablo Mininni ; ; CALLING SEQUENCE: ; WRF_CURL_FINDIFF,INX,INY,INZ,OUTX,OUTY,OUTZ,DX,DY,ELEV ; ; PARAMETERS: ; INX[in]: 3D array with the x component of the field ; INY[in]: 3D array with the y component of the field ; INZ[in]: 3D array with the z component of the field ; OUTX[out]: 3D array with the x component of the curl ; OUTY[out]: 3D array with the y component of the curl ; OUTZ[out]: 3D array with the z component of the curl ; DX[in]: spatial step of the grid in the x direction ; DY[in]: spatial step of the grid in the y direction. ; ELEV[in]: elevation variable ; ; ; COMMON BLOCKS: ; None ; ;- PRO wrf_curl_findiff,inx,iny,inz,outx,outy,outz,dx,dy,elev on_error,2 ;return to caller if an error occurs ; x component is dW/dy - dV/dz ; dW/dy is calc by (dW/dy)_eta - (dW/dz)*(dZ/dy)_eta ; where _eta indicates the derivative calculated in the WRF grid coordinates ; as is performed by deriv_findiff.pro ; and Z is the ELEVATION. deriv_findiff, inz, aux1, 2, dy elev_deriv, inz, aux2, elev deriv_findiff, elev, aux3, 2, dy ; dV/dz: elev_deriv, iny, aux4, elev outx = aux1 - aux2*aux3 - aux4 ; y component is dU/dz - dW/dx ; dU/dz: elev_deriv, inx, aux4, elev ; dW/dx is calc by (dW/dx)_eta - (dW/dz)*(dZ/dx)_eta deriv_findiff, inz, aux1, 1, dx elev_deriv, inz, aux2, elev deriv_findiff, elev, aux3, 1, dx outy = aux4 - aux1 + aux2*aux3 ; z component of curl is dV/dx - dU/dy ; dV/dx is (dV/dx)_eta - (dV/dz)*(dZ/dx)_eta deriv_findiff, iny, aux1, 1, dx elev_deriv, iny, aux2, elev deriv_findiff, elev, aux3, 1, dx ; dU/dy is (dU/dy)_eta - (dU/dz)*(dZ/dy)_eta deriv_findiff, inx, aux4, 2, dy elev_deriv, inx, aux5, elev deriv_findiff, elev, aux6, 2, dy outz = aux1 - aux2*aux3 - aux4 + aux5*aux6 end ================================================ FILE: share/examples/idl/wrf_div_findiff.pro ================================================ ; ; NAME: ; WRF_DIV_FINDIFF ; ; PURPOSE: ; Computes the divergence of a vector field using sixth ; order finite differences on WRF grid ; Uses an interpolation scheme described by Mark Stoellinga ; to directly calculate the derivatives on the WRF grid. ; The 6th order difference terms are due to Pablo Mininni ; ; CALLING SEQUENCE: ; WRF_DIV_FINDIFF,INX,INY,INZ,OUT,DX,DY,ELEV ; ; PARAMETERS: ; INX[in]: 3D array with the x component of the field ; INY[in]: 3D array with the y component of the field ; INZ[in]: 3D array with the z component of the field ; OUT[out]: 3D array with the divergence ; DX[in]: spatial step of the grid in the x direction ; DY[in]: spatial step of the grid in the y direction. ; ELEV[in]: elevation variable ; ; ; COMMON BLOCKS: ; None ; ;- PRO wrf_div_findiff,inx,iny,inz,out,dx,dy,elev on_error,2 ;return to caller if an error occurs ; calculate dU/dx as (dU/dx)_eta - (dU/dz)*(dZ/dx)_eta ; where _eta indicates the derivative calculated in the WRF grid coordinates ; as is performed by deriv_findiff.pro deriv_findiff, inx, aux1, 1, dx elev_deriv, inx, aux2, elev deriv_findiff, elev, aux3, 1, dx out = aux1 - aux2*aux3 ; calculate dV/dy as (dV/dy)_eta - (dV/dz)*(dZ/dy)_eta ; where _eta indicates the derivative calculated in the WRF grid coordinates ; as is performed by deriv_findiff.pro deriv_findiff, iny, aux1, 2, dy elev_deriv, iny, aux2, elev deriv_findiff, elev, aux3, 2, dy out = out + aux1 - aux2*aux3 ; dW/dz: elev_deriv, inz, aux1, elev out = out + aux1 end ================================================ FILE: share/examples/listOfSeeds.txt ================================================ # # Seed injection points within your domain may be defined in this file # as comma separated values. # # A line starts with a pound sign is ignored, so is an empty line. # This is a seed at location (.5, .5, .5) .5,.5,.5 # The following line would be ill-formated because it has less than 3 values. # .5,.5 # The following line specifies a location (1.0, 1.0, 1.0) with the rest of values ignored. 1.0, 1.0, 1.0, 0.0, -1.0, -2.0 # The following line specifies a repeated location (.5, .5, .5) which will be ignored. .5,.5,.5 ================================================ FILE: share/gitHooks/pre-push ================================================ #!/bin/sh # DRYRUN='false' MAIN='false' # -d initiates a dry-run where code will be scanned, but changes will not be applied # -m initiates a comparison between the local HEAD and 'main', instead of comparing # the the local HEAD with the remote HEAD while getopts dm flag; do case ${flag} in d) DRYRUN='true' ;; m) MAIN='true' ;; esac done echo " Running dryrun? $DRYRUN" echo " Force comparison to main? $MAIN" BRANCH=`git rev-parse --abbrev-ref HEAD` # If our current branch does not exist in the remote repository yet, then compare # our local changes with main. Otherwise, compare our local changes with the remote # branch. if [ "${MAIN}" != "true" ]; then if [ `git ls-remote --heads https://github.com/NCAR/VAPOR.git $BRANCH | wc -l` = 0 ]; then COMPARE_BRANCH="main" else COMPARE_BRANCH=$BRANCH fi fi echo " Comparing current changes with branch: $COMPARE_BRANCH" # If we're on the readTheDocs branch, skip clang-format # if [ "$BRANCH" = "readTheDocs" ]; then echo "pre-push hook skipped for current branch." # Otherwise format the changed lines in all commits up to this push # else for COMMIT in $(git log --pretty=format:%h origin/$COMPARE_BRANCH...$BRANCH); do echo "Reading Commit: $COMMIT" for FILE in $(git diff --name-only $COMMIT^ $COMMIT |grep -E "\.h|\.cpp"); do NUMBERS="" for NUMBER in $(git blame --line-porcelain "$FILE" | egrep ^$COMMIT | cut -d' ' -f3); do NUMBERS="$NUMBERS --lines $NUMBER:$NUMBER " done if [ "$NUMBERS" != "" ]; then if [ "${DRYRUN}" = "true" ]; then echo "dry run activated" clang-format --dry-run -i $FILE $NUMBERS >> /tmp/clang-format.txt 2>&1 else echo " Running clang-format on $FILE, line $NUMBERS" clang-format -i $FILE $NUMBERS git add $FILE fi fi done done if [ "${DRYRUN}" = "false" ]; then git commit -m "clang-format pre-push hook" fi # git commit will return non-zero status if there's nothing to commit. Make sure # we return 0 so git 'push' will still be invoked exit 0 fi ================================================ FILE: share/gitHooks/setupHooks.sh ================================================ #!/bin/sh ROOT_DIR=$(git rev-parse --show-toplevel) HOOK_DIR=$ROOT_DIR/.git/hooks HOOK=$HOOK_DIR/pre-push ln -sf $ROOT_DIR/share/gitHooks/pre-push $HOOK if [ -e "$HOOK" ] then echo "pre-push hook installed in $HOOK_DIR" else echo "Failure: Unable to create sym-link in $HOOK_DIR" fi ================================================ FILE: share/notices/__example-notice.json ================================================ { "_comment-1": "This is an example notice. It will be ingored by Vapor", "_comment-2": "This is the date at which the notice will be displayed to users", "_comment-3": "The time format is yyyy-MM-dd by Qt's specification", "date": "2021-06-01", "_comment-4": "This is the date at which the notice will no longer be displayed to users", "until": "2021-09-27", "_comment-5": "This is the content of the notice. It uses a subset of HTML that is supported by QTextBrowser", "content": "

Notice



Vapor's homepage: Link

" } ================================================ FILE: share/palettes/Diverging/BlueWhiteGold.tf3 ================================================ 0 -1 1 1 -1 1 4 1 0.5933147668838501 0.7607843279838562 0.9137254953384399 0 0.1142061278223991 0.8627451062202454 0.6784313917160034 0.9900000095367432 Type="ParamsBase" > -1 1 1 0 0 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 ================================================ FILE: share/palettes/Diverging/CoolWarm.tf3 ================================================ 0 0 1 1 1 0 0 0 1 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 4 2 0.644444465637207 0.6949999928474426 0.7570000290870667 0 0.9666666388511658 0.9769999980926514 0.7059999704360962 1 0 1 ================================================ FILE: share/palettes/Diverging/CoolWarmBent.tf3 ================================================ 0 -1 1 1 4 0.640668511390686 0.6941176652908325 0.7568627595901489 0 -0.002785515272989869 0 0.9490196108818054 0.5208055377006531 0.9665738344192505 0.9764705896377563 0.7058823704719543 0.9900000095367432 -1 1 1 0 0 -1 1 5 0.5 1 0 1 0.33333333333333333 1 0.66666666666666666 1 1 39.47841760435743 1 0 0.1 ================================================ FILE: share/palettes/Diverging/CoolWarmSmooth.tf3 ================================================ 0 0 1 1 1 0 0 0 1 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 4 1 0.640668511390686 0.6941176652908325 0.7568627595901489 0 0.9665738344192505 0.9764705896377563 0.7058823704719543 1 0 1 ================================================ FILE: share/palettes/Diverging/GreenWhitePurple.tf3 ================================================ 0 0 1 1 1 0 0 0 1 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 4 1 0.3760445713996887 0.8392156958580017 0.5333333611488342 0 0.7325905561447144 0.5137255191802979 0.6352941393852234 1 0 1 ================================================ FILE: share/palettes/Diverging/GreenWhiteRed.tf3 ================================================ 0 0 1 1 1 0 0 0 1 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 4 1 0.3760445713996887 0.8470588326454163 0.5333333611488342 0 0.9944289922714233 0.7176470756530762 0.7607843279838562 1 0 1 ================================================ FILE: share/palettes/Diverging/PurpleWhiteOrange.tf3 ================================================ 0 0 1 1 1 0 0 0 1 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 4 1 0.7353760600090027 0.5098039507865906 0.6313725709915161 0 0.06685236841440201 0.9411764740943909 0.7607843279838562 1 0 1 ================================================ FILE: share/palettes/Diverging/balance.tf3 ================================================ 0 -939.5371704101562 1877.108642578125 1 1 0 0 -939.5371704101562 1877.108642578125 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 5 0.6488481188400105 0.6437021499566375 0.2615123885530548 0 0.5900150015421565 0.9393560590369526 0.7454889092261349 0.1666666666666667 0.5457489954299063 0.3848527451053083 0.7434335263117878 0.3333333333333333 0.02692698143186436 0.02309190124513382 0.9450241336950317 0.5 0.04242886065790093 0.4458818451186248 0.8157857974447502 0.6666666666666666 0.9959726603348144 0.7974657948930718 0.6483618361407727 0.8333333333333333 0.971657574461405 0.8504701197267419 0.236056364664614 1 -939.5371704101562 1877.108642578125 ================================================ FILE: share/palettes/Diverging/curl.tf3 ================================================ 0 -1 1 1 -1 1 0 0.8278897949606616 0.7542061978182768 0.20853720637712653 0.0 0.9250743235535671 0.6951507646615473 0.61270939731 0.16666666666666666 0.035853343170463105 0.4555012519711035 0.8593125235209843 0.3333333333333333 0.02950939488983051 0.03726602425907123 0.9929465713958281 0.5 0.3899353073524154 0.2959263644853567 0.7018019300139728 0.6666666666666666 0.5106145733580575 0.8148005363261331 0.4477088968524857 0.8333333333333333 0.6368377882653272 0.6893555377202758 0.26479016778008574 1.0 Type="ParamsBase" > -1 1 1 0 0 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 ================================================ FILE: share/palettes/Diverging/delta.tf3 ================================================ 0 -939.5371704101562 1415.363525390625 1 1 0 0 -939.5371704101562 1415.363525390625 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 0 0.6140949377805809 0.7355416095492259 0.2494811599712868 0 0.6330804295737312 0.7032664339670238 0.4936502476018932 0.07142857142857142 0.5859736252285871 0.830428699019629 0.6195251374197684 0.1428571428571428 0.5510623284995626 0.7685151994004963 0.6453485009817425 0.2142857142857143 0.5190234368385999 0.6038502597225501 0.6808595744198757 0.2857142857142857 0.4829421039692708 0.3036057396192864 0.7460500590687459 0.3571428571428571 0.4257600007162249 0.1002650673205966 0.8533263291295689 0.4285714285714285 0.1588483782677347 0.1986719170815648 0.9982730268101483 0.5 0.1368479050484376 0.4482582772952977 0.8995373837127171 0.5714285714285714 0.155234671931644 0.723048717630318 0.7426430871174343 0.6428571428571428 0.1972179231386593 0.9591742653183207 0.6180898846857883 0.7142857142857142 0.2791330843893799 0.7994216841630458 0.5211096093711738 0.7857142857142857 0.3909196980487105 0.8815572324657858 0.4047485074383744 0.8571428571428571 0.397139111935538 0.6788372476449076 0.2717262314473357 0.9285714285714285 0.288402825198751 0.4665912550886617 0.1373386075843833 1 -939.5371704101562 1415.363525390625 ================================================ FILE: share/palettes/Diverging/diff.tf3 ================================================ 0 -939.5371704101562 1877.108642578125 1 1 0 0 -939.5371704101562 1877.108642578125 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 5 0.5859776512391991 0.8767176683047709 0.249846444559915 0 0.5672289034733282 0.4310019519368037 0.4884111449080716 0.1666666666666667 0.5751576319408671 0.1101281155816629 0.7073025514622064 0.3333333333333333 0.03091203441454771 0.02270456720342846 0.962971730415212 0.5 0.1198337800190978 0.1931171328565661 0.6902175511682563 0.6666666666666666 0.1310320694992013 0.5696636144086142 0.423147463724184 0.8333333333333333 0.2033062807024827 0.7980878893216422 0.1339166670121798 1 -939.5371704101562 1877.108642578125 ================================================ FILE: share/palettes/Diverging/tarn.tf3 ================================================ 0 -939.5371704101562 1877.108642578125 1 1 0 0 -939.5371704101562 1877.108642578125 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 7 0.262152612700985 0.6149905855180422 0.1386884202488073 0 0.1442785294697875 0.7270786717586432 0.4178758479312351 0.1666666666666667 0.07458590230439183 0.5094780890838793 0.8288195980598317 0.3333333333333334 0.0380974216812194 0.02408740926575129 0.9884162623276403 0.5 0.3441111492041977 0.1524328039795236 0.6963445147045469 0.6666666666666667 0.5188190638418212 0.7374157832587309 0.4710274926158041 0.8333333333333334 0.6287394897504813 0.8021011784991612 0.3108793933905304 1 -939.5371704101562 1877.108642578125 ================================================ FILE: share/palettes/Highlighting/oxy.tf3 ================================================ 0 -939.5371704101562 1877.108642578125 1 1 0 0 -939.5371704101562 1877.108642578125 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 0 0 0.01350000035017729 0.8043488264083862 0.1803921610116959 0 0.02777777798473835 0.8333256840705872 0.4235294163227081 0.197 -1 0 0.2705882489681244 0.2 0.1666666716337204 0.008270390331745148 0.9490196108818054 0.797 0.1754444390535355 0.5960784554481506 1 0.8 0.1339722275733948 0.7939726710319519 0.7803921699523926 1 -939.5371704101562 1877.108642578125 ================================================ FILE: share/palettes/Highlighting/topo.tf3 ================================================ 0 -939.5371704101562 1877.108642578125 1 1 0 0 -939.5371704101562 1877.108642578125 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 5 0.7938268228367832 0.4059326069616122 0.1727215696232308 0 0.6190058274300871 0.568850001160404 0.5676029832475817 0.1666666666667 0.5012583114787256 0.5119882782922851 0.6340450861601971 0.3333333333333 0.1755833327770233 0.221347376704216 0.9921568632125854 0.499 0.2948611080646515 0.3939421772956848 0.1294117718935013 0.5 0.2474454176360088 0.523618576887678 0.370720292815769 0.66666666666 0.1211480166335046 0.6284944517502499 0.6664663550324849 0.8333333333333 0.1980982980158893 0.09908783848317795 0.9933519398287799 1 -939.5371704101562 1877.108642578125 ================================================ FILE: share/palettes/Sequential/BlackBody.tf3 ================================================ 0 -1 1 1 -1 1 4 -0.002785515272989869 0 0 0 0 0.8117647171020508 0.6980392336845398 0.3912840485572815 0.07520891726016998 0.9803921580314636 0.8901960849761963 0.5801073312759399 0.1448467969894409 0.9176470637321472 0.9333333373069763 0.8404544591903687 -0.002785515272989869 0 1 0.9900000095367432 Type="ParamsBase" > -1 1 1 0 0 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 ================================================ FILE: share/palettes/Sequential/BlackBodyExtended.tf3 ================================================ 0 -1 1 1 0 -0.002785515272989869 0 0 0 0.640668511390686 1 0.658823549747467 0.1373885571956635 0.7409470677375793 1 0.8941176533699036 0.2949162721633911 0.9693593382835388 0.9098039269447327 0.8627451062202454 0.5208055377006531 0.05013927444815636 0.7803921699523926 1 0.6753613352775574 0.1448467969894409 0.9176470637321472 0.9333333373069763 0.8418055176734924 -0.002785515272989869 0 1 0.9900000095367432 -1 1 1 0 0 -1 1 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 ================================================ FILE: share/palettes/Sequential/BlackWhite.tf3 ================================================ 0 -1 1 1 -1 1 0 0 0 0 0 0 0 1 0.9900000095367432 Type="ParamsBase" > -1 1 1 0 0 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 ================================================ FILE: share/palettes/Sequential/Kindlmann.tf3 ================================================ 0 -1 1 1 0 -0.002785515272989869 0 0 0 0.7660167217254639 0.9490196108818054 0.2980392277240753 0.09803897142410278 0.7353760600090027 0.9529411792755127 0.5686274766921997 0.199999988079071 0.6044568419456482 0.9529411792755127 0.6470588445663452 0.3038330078125 0.5013927817344666 0.9529411792755127 0.4156862795352936 0.4078609943389893 0.412256270647049 0.9490196108818054 0.5372549295425415 0.5019609928131104 0.3481894135475159 0.9529411792755127 0.658823549747467 0.6000000238418579 0.2646239697933197 0.95686274766922 0.7607843279838562 0.6961669921875 0.1727019548416138 0.9529411792755127 0.8078431487083435 0.800000011920929 0.06963787972927094 0.2156862765550613 0.9882352948188782 0.901249885559082 -0.002785515272989869 0 1 0.9900000095367432 -1 1 1 0 0 -1 1 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 ================================================ FILE: share/palettes/Sequential/KindlmannExtended.tf3 ================================================ 0 -1 1 1 0 -0.002785515272989869 0 0 0 0.7325905561447144 0.9529411792755127 0.4039215743541718 0.1218169927597046 0.5013927817344666 0.95686274766922 0.2627451121807098 0.250980019569397 0.3454039096832275 0.9529411792755127 0.4039215743541718 0.3803920149803162 0.1754874587059021 0.9529411792755127 0.4862745106220245 0.5019609928131104 0.02785515412688255 0.6980392336845398 0.9647058844566345 0.6196080446243286 0.8495821952819824 0.4039215743541718 0.9803921580314636 0.749472975730896 0.7493036389350891 0.1607843190431595 0.9921568632125854 0.8841270208358765 -0.002785515272989869 0 1 0.9900000095367432 -1 1 1 0 0 -1 1 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 ================================================ FILE: share/palettes/Sequential/Rainbow.tf3 ================================================ 0 -1 1 1 -1 1 0 0.835654616355896 1 1 0 0.6685236692428589 1 1 0.3312032520771027 0.3342618346214294 1 1 0.6659361124038696 0 1 1 0.9900000095367432 -1 1 1 0 0 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 ================================================ FILE: share/palettes/Sequential/algae.tf3 ================================================ 0 -1 1 1 -1 1 0 0.30431393807842216 0.1660980033034706 0.9769128443086749 0.0 0.30005392008677356 0.2989152547067349 0.8338063126244977 0.16666666666666666 0.3309718871642622 0.4515992141435242 0.7070616628058336 0.3333333333333333 0.4130561078076512 0.8801649528576773 0.5796325615836696 0.5 0.42542750956654046 0.8403187904684511 0.4316407590421983 0.6666666666666666 0.410290285400631 0.64157633829156 0.28324566551643965 0.8333333333333333 0.3564950013178268 0.515400832815782 0.14208946011590498 1.0 Type="ParamsBase" > -1 1 1 0 0 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 ================================================ FILE: share/palettes/Sequential/amp.tf3 ================================================ 0 -1 1 1 -1 1 0 0.02635813386433533 0.021761412834227965 0.9463470914425774 0.0 0.04010142603941556 0.20791215214883926 0.8735014600514631 0.16666666666666666 0.04242515583198917 0.4478198859077958 0.8153328745786678 0.3333333333333333 0.03676973779567544 0.6927978622162377 0.7514064033944252 0.5 0.9973316222226559 0.792673038422649 0.6513700233144809 0.6666666666666666 0.9584512517521356 0.8750622180279034 0.4499550509587918 0.8333333333333333 0.971657574461405 0.8504701197267419 0.23605636466461405 1.0 Type="ParamsBase" > -1 1 1 0 0 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 ================================================ FILE: share/palettes/Sequential/deep.tf3 ================================================ 0 -1 1 1 -1 1 0 0.16798488162105954 0.19533632833453615 0.9943734553013935 0.0 0.33735559873470516 0.25865604304601525 0.8740670650055499 0.16666666666666666 0.4611472243939132 0.4995300219326743 0.7276949011320993 0.3333333333333333 0.5307921490613369 0.5432212914796786 0.6185294158631611 0.5 0.5935831949277645 0.584827649057945 0.5830452587571144 0.6666666666666666 0.6867084184579647 0.4725176065265601 0.42500331672496205 0.8333333333333333 0.7938268228367832 0.40593260696161215 0.1727215696232308 1.0 Type="ParamsBase" > -1 1 1 0 0 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 ================================================ FILE: share/palettes/Sequential/dense.tf3 ================================================ 0 -1 1 1 -1 1 0 0.4985029056155954 0.044459364441300706 0.9441797977915001 0.0 0.5538618981465113 0.28459785042143 0.8875413292226666 0.16666666666666666 0.5981049031515369 0.4825601716434142 0.8962023935259622 0.3333333333333333 0.6774379035261949 0.46932251013476056 0.8354485830591045 0.5 0.7548424727275783 0.596020164491061 0.6452378997676681 0.6666666666666666 0.8332113916290097 0.7006204506630465 0.38330035466997037 0.8333333333333333 0.908421307425615 0.7375779324974272 0.21298394220008482 1.0 Type="ParamsBase" > -1 1 1 0 0 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 ================================================ FILE: share/palettes/Sequential/haline.tf3 ================================================ 0 -939.5371704101562 1877.108642578125 1 1 0 0 -939.5371704101562 1877.108642578125 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 6 0.7011534992182886 0.774675775404715 0.4225729247643044 0 0.6088781425912405 0.8740527287776149 0.6109238301118911 0.1666666666666667 0.5448574374231362 0.7694018538276051 0.5438113725374379 0.3333333333333334 0.4768648232665631 0.5931034349030235 0.577131576635999 0.5 0.3865097026016158 0.5168905297066437 0.7265676248366645 0.6666666666666667 0.2282869252736467 0.5736335355767576 0.8470513147981416 0.8333333333333334 0.1422451679013383 0.3937413041608905 0.9940805805099583 1 -939.5371704101562 1877.108642578125 ================================================ FILE: share/palettes/Sequential/ice.tf3 ================================================ 0 -939.5371704101562 1877.108642578125 1 1 0 0 -939.5371704101562 1877.108642578125 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 7 0.6457410650120362 0.7894687174364072 0.07272873735907764 0 0.6734507537530291 0.5074184930577886 0.316351221127571 0.1666666666666667 0.6422358037081647 0.5824508021175889 0.5885298594478888 0.3333333333333334 0.5862361315939045 0.6384738978095406 0.7194288695343958 0.5 0.5518749196791298 0.5112952008114653 0.7819829669338884 0.6666666666666667 0.5181582182863426 0.2844717529303322 0.8566135671784518 0.8333333333333334 0.5022720327010908 0.07531334884986909 0.9928328638314804 1 -939.5371704101562 1877.108642578125 ================================================ FILE: share/palettes/Sequential/matter.tf3 ================================================ 0 -939.5371704101562 1877.108642578125 1 1 0 0 -939.5371704101562 1877.108642578125 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 6 0.1315047750870439 0.3049367995017602 0.9942936149611202 0 0.07435862552520107 0.4982105379942617 0.9694484453171449 0.1666666666666667 0.0365168642500231 0.6239726620240689 0.9204453195710341 0.3333333333333333 0.9770167116808333 0.6738182081962212 0.8085246874446361 0.5 0.9151686322101068 0.7743545622095169 0.6229363449371849 0.6666666666666666 0.8546586694913163 0.7611032331430697 0.4003852641200215 0.8333333333333333 0.7808880998021044 0.7566950434006665 0.2430426744218359 1 -939.5371704101562 1877.108642578125 ================================================ FILE: share/palettes/Sequential/phase.tf3 ================================================ 0 -939.5371704101562 1877.108642578125 1 1 0 0 -939.5371704101562 1877.108642578125 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 6 0 0.1151063084707132 0.9249396140571944 0.6583083928922511 0 0.9827516762211339 0.6616042724377271 0.8425387334318171 0.1666666666666667 0.8327756885548686 0.7732839976462316 0.8173214043862718 0.3333333333333334 0.6809881354681986 0.5224959435452883 0.9417848067474301 0.5 0.5246391807803946 0.8208898372298726 0.6577323260140637 0.6666666666666667 0.3567894711420296 0.6566328658214546 0.6009446614046378 0.8333333333333334 0.1151063084706448 0.9249396140554326 0.6583083928921536 1 -939.5371704101562 1877.108642578125 ================================================ FILE: share/palettes/Sequential/rain.tf3 ================================================ 0 -939.5371704101562 1877.108642578125 1 1 0 0 -939.5371704101562 1877.108642578125 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 6 0.6951979254202271 0.02295059012081452 0.9527121598234155 0 0.09453797769959756 0.2114576666915019 0.833684474704683 0.1666666666666667 0.2536636757508912 0.2498954596283127 0.6552266499575032 0.3333333333333333 0.4332665894273724 0.5735234776522391 0.5574166090031631 0.5 0.5020626150570218 0.9676627588506598 0.4264935743343106 0.6666666666666666 0.5674344311981884 0.6147742237450133 0.3483613905337878 0.8333333333333333 0.7058246076905745 0.5301018061190311 0.2213363669373893 1 -939.5371704101562 1877.108642578125 ================================================ FILE: share/palettes/Sequential/solar.tf3 ================================================ 0 -939.5371704101562 1877.108642578125 1 1 0 0 -939.5371704101562 1877.108642578125 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 5 0.9783639431921791 0.6161958731217829 0.201425099783396 0 0.9967939632653428 0.6597135862458171 0.4068349561616131 0.1666666666666667 0.04240662863510477 0.8151825886459937 0.5923480147332496 0.3333333333333334 0.08309895316788585 0.894945393952475 0.7141299649529337 0.5 0.1129395338615871 0.8741471283229515 0.7979274645055595 0.6666666666666667 0.1465135077437694 0.7828284227016814 0.8556846647048814 0.8333333333333334 0.193672596476034 0.7045765444566169 0.9939881188401473 1 -939.5371704101562 1877.108642578125 ================================================ FILE: share/palettes/Sequential/speed.tf3 ================================================ 0 -1 1 1 -1 1 0 0.1596307072865247 0.1955973620128987 0.9996253193176977 0.0 0.1373421430079236 0.48977236844084415 0.8818245887426445 0.16666666666666666 0.16865647082418778 0.8113800283790015 0.6743006234739316 0.3333333333333333 0.22966149294080326 0.9165428294945905 0.5713169711328536 0.5 0.3621715121548401 0.7882711545792705 0.4491042457325262 0.6666666666666666 0.4004708869579201 0.7322728624001044 0.29398786489640066 0.8333333333333333 0.288402825198751 0.46659125508866167 0.13733860758438335 1.0 Type="ParamsBase" > -1 1 1 0 0 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 ================================================ FILE: share/palettes/Sequential/tempo.tf3 ================================================ 0 -939.5371704101562 1877.108642578125 1 1 0 0 -939.5371704101562 1877.108642578125 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 6 0.0225033366813406 0.04084497581785965 0.9985763296811462 0 0.2657248163043771 0.1122146822936219 0.8209970689783633 0.1666666666666667 0.3906836969353442 0.2983860344980878 0.7009183842407573 0.3333333333333333 0.4679695435964035 0.7121223502366618 0.5784169089899582 0.5 0.5098142117208065 0.8180924994963084 0.4492060096666722 0.6666666666666666 0.5584755476416275 0.693740141825086 0.3584370856671011 0.8333333333333333 0.6368377882653272 0.6893555377202758 0.2647901677800857 1 -939.5371704101562 1877.108642578125 ================================================ FILE: share/palettes/Sequential/thermal.tf3 ================================================ 0 -939.5371704101562 1877.108642578125 1 1 0 0 -939.5371704101562 1877.108642578125 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 6 0.5568814119463522 0.9229178682838526 0.2018108864558305 0 0.6549755477788276 0.7063194674835263 0.5859183845130114 0.1666666666666667 0.7634505310371908 0.5010011918119459 0.5741764823913097 0.3333333333333334 0.9294383782438684 0.4603631099484105 0.6922877457570544 0.5 0.0372788517634953 0.6264281833061038 0.9199740625655836 0.6666666666666667 0.1043208552539475 0.7578562555330935 0.9855936903889445 0.8333333333333334 0.1861128251649463 0.6380337773337329 0.9821574063216706 1 -939.5371704101562 1877.108642578125 ================================================ FILE: share/palettes/Sequential/turbid.tf3 ================================================ 0 -939.5371704101562 1877.108642578125 1 1 0 0 -939.5371704101562 1877.108642578125 5 0.5 1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 6 0.195866594439376 0.3024741580025216 0.9639053479101408 0 0.1435051206852861 0.4672478059499121 0.8292275089883606 0.1666666666666667 0.1113678407626282 0.6280264035922246 0.7496385821697368 0.3333333333333333 0.08644661232811861 0.6327132693687203 0.6315116605695774 0.5 0.06795198707528698 0.5377144793877353 0.4748206472212549 0.6666666666666666 0.06210044096611798 0.4098310229471856 0.3000685503066236 0.8333333333333333 0.08104897376521929 0.2074708678666135 0.1339921324751869 1 -939.5371704101562 1877.108642578125 ================================================ FILE: share/python/imagewriter.py ================================================ # outfile : string # width : image width # height : image height # rgbbuffer : buffer of R, G, B values def drawpng( outfile, width, height, rgbbuffer ): import matplotlib matplotlib.use('AGG') import matplotlib.image as mpimg import numpy as np buf = np.array( rgbbuffer, dtype=np.uint8 ) buf = buf.reshape( height, width, 3 ) mpimg.imsave( outfile, buf, format='png' ) return 0 def main(): width =64 height = 128 buf = [] for y in range( height ): for x in range( width ): buf.append(x) buf.append(y) buf.append(0) drawpng( "rgb.png", width, height, buf ) if __name__ == "__main__": main() ================================================ FILE: share/python/plot.py ================================================ # outFile : string # varNames : list of strings # sequences : list of list of floats. Has the Y values of the plot # xValues : list of floats. Has the X values of the plot # xLabel : a single string. Has the X label. # yLabel : a single string. Has the Y label. def plotSequences( outFile, varNames, sequences, xValues, xLabel, yLabel ): import matplotlib matplotlib.use('AGG') import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(8, 6)) if len(varNames) > 0: for i in range(len(varNames)): ax.plot( xValues, sequences[i], '-x', label=varNames[i] ) ax.legend(loc='best') ax.set(xlabel=xLabel, ylabel=yLabel, title="Vapor Plot Utility") #ax.set_xticks( xValues ) # give it fixed xticks fig.savefig( outFile ) plt.close( fig ) return 0 ================================================ FILE: share/python/plot1D.py ================================================ # Pass in the X dimension list as well, or just leave it blank def plot1D( D, imagePath, X=None ): import numpy as np import matplotlib matplotlib.use('AGG') import matplotlib.pyplot as plt # # Setup Plot # # N.B. This method needs to be defined inside of plot1D. Otherwise the # invocation from the python interpreter in vaporgui will fail. # # font sizes: xx-small, x-small, # small, medium, large, x-large, xx-large # linestyles: '-', '--', '-.', ':', 'None', ' ', '' # colors: 'blue', 'gree', 'red', 'cyan', 'magenta', 'yellow', 'black', 'white' # legend locations: 'best', 'upper right', 'upper left', # 'lower left', 'right', 'center left', 'center right', # 'lower center', 'upper center', 'center' # def setupPlot( title, leftLimit, rightLimit ): fig = plt.figure( figsize=(10,6), dpi=100, frameon=True ) plt.title( title, color='Black', fontsize='xx-large') plt.xlabel("X Dimension", color='Black', fontsize='large') plt.ylabel("Y Dimension", color='Black', fontsize='large') plt.xlim(leftLimit, rightLimit) plt.grid(True) plt.ioff() xRange = 0 if X is None: for v in D.itervalues(): if len(v) > xRange: xRange = len(v) X = range(xRange) setupPlot( 'Vapor Sample Plot Script', X[0], X[-1] ) globalYMin = None globalYMax = None for k, v in D.iteritems(): localYMin = min(v) localYMax = max(v) if globalYMin is None or globalYMin > localYMin: globalYMin = localYMin if globalYMax is None or globalYMax < localYMax: globalYMax = localYMax plt.plot(X, v, linewidth=1.0, linestyle='-', color=None, label=k) # use log scale on Y axis: # plt.semilogy(X, v, linewidth=1.0, linestyle='-', color=None, label=k) #plt.axis([X[0], X[-1], globalYMin, globalYMax]) plt.legend(loc='best', frameon=True, fontsize='large') plt.savefig(imagePath) plt.gcf().clear() # # Test function for invoking plot1D() from command line # def runit(): import os import numpy as np outputfile = os.path.join(os.path.expanduser('~'), 'foo.png') X = np.linspace(-np.pi, np.pi, 256,endpoint=True) C,S = np.cos(X) + 2, np.sin(X) + 2 dic = {"cosine" : C, "sine" : S } print 'Output file: ', outputfile plot1D( dic, outputfile, X ) if __name__ == '__main__': runit() ================================================ FILE: share/python/pythonSystemStartup.py ================================================ from numpy import * from vapor_utils import * ================================================ FILE: share/python/vapor_utils.py ================================================ """ The vapor_utils module contains: StaggeredToUnstaggeredGrid - resample staggered grid DerivFinDiff - calculate derivative using 6th order finite differences DerivVarFinDiff - calculate a derivative of one 3D variable with respect to another variable. CurlFinDiff - calculate curl using finite differences DivFinDiff - calculate divergence using finite differences GradFinDiff - calculate gradient using finite differences. Interp3d - interpolate a 3D variable to a vertical level surface of another variable. VectorRotate - rotate and scale vector field for lat-lon grid. """ import numpy as np def _StaggeredToUnstaggeredGrid2D(a, axis): assert isinstance(a, np.ndarray), 'A is not np.ndarray' assert a.ndim == 2 assert axis >= 0 and axis < a.ndim from scipy.interpolate import RectBivariateSpline x = np.arange(a.shape[1]) y = np.arange(a.shape[0]) if (axis == 1): xprime = np.arange(0.5, a.shape[axis] - 0.5) yprime = y else: xprime = x yprime = np.arange(0.5, a.shape[axis] - 0.5) interp_spline = RectBivariateSpline(y, x,a) return interp_spline(yprime, xprime) def StaggeredToUnstaggeredGrid(a, axis): """Resample a numpy array on a staggered grid to an unstaggered grid This function is useful for resampling data sampled on an Arakawa C-grid to an Arakawa A-grid. E.g. resampling the velocity grid to the mass grid. It simply down samples the specified axis specified by `axis` by one grid point, locating the new grid points in the returned array at the midpoints of the samples in the original array, `a` Parameters ----------- a : numpy.ndarray A two or three dimensional Numpy array axis : int An integer in the range 0..n, where n is a.ndim - 1, specifying which axis should be downsampled. Zero is the slowest varying dimension. Returns ------- aprime: numpy.ndarray: The resampled array """ assert isinstance(a, np.ndarray), 'A is not np.ndarray' assert a.ndim >= 2 and a.ndim <= 3 assert axis >= 0 and axis < a.ndim if (a.ndim == 2): return _StaggeredToUnstaggeredGrid2D(a,axis) newshape = list(a.shape) newshape[axis] -= 1; aprime = np.empty(newshape, a.dtype) if (axis == 1 or axis == 2): for k in range(0,aprime.shape[0]): aprime[k,::,::] = _StaggeredToUnstaggeredGrid2D(a[k,::,::],axis-1) else: for i in range(0,aprime.shape[2]): aprime[::,::,i] = _StaggeredToUnstaggeredGrid2D(a[::,::,i],axis) return(aprime) def Mag(*argv): """Return the magnitude of one or more vectors This method computes the vector magnitude of the Numpy arrays in *args*. Each array in *args* must have the same number of dimensions. The arrays may be a mixture of staggered and unstaggered arrays. I.e. for any axis the dimension length may differ by no more than one. Staggered arrays are downsampled along the staggered axis to have the same dimension length as the unstaggered array. Thus all arrays are resampled as necessary to have the same shape prior to computing the array magnitude. Parameters ---------- *argv : tuple of numpy.ndarray A a list of two or three-dimensional Numpy arrays Returns ------- a : numpy.ndarray The vector magnitude """ for arg in argv: assert isinstance(arg, np.ndarray), 'A is not np.ndarray' ndim = argv[0].ndim for i in range(0,len(argv)-1): assert ndim == argv[i].ndim, 'Arrays must all have same rank' shapes = np.empty(ndim*len(argv), dtype=int).reshape(len(argv), ndim) for i in range(0,len(argv)): shapes[i,::] = argv[i].shape baseshape = np.empty(ndim, dtype=int) for i in range(0,ndim): baseshape[i] = np.amin(shapes[::,i]) for i in range(0,len(argv)): if (np.sum(np.array(argv[i].shape)-baseshape) > 1): raise ValueError("array dimensions may only differ by one") magsqr = np.zeros(np.prod(baseshape), argv[0].dtype).reshape(baseshape) for i in range(0,len(argv)): myshape = np.array(argv[i].shape) if np.array_equal(myshape,baseshape): magsqr += argv[i] * argv[i] else: axis = -1 for j in range(0,myshape.size): if (myshape[j] == baseshape[j] + 1): axis = j tmp = StaggeredToUnstaggeredGrid(argv[i], axis) magsqr += tmp * tmp return(np.sqrt(magsqr)) def _deriv_findiff2(a,axis,dx): """Function that calculates first-order derivatives using 2nd order finite differences in regular Cartesian grids. """ s = np.shape(a) #size of the input array aprime = np.array(a) #output has the same size than input # # derivative for user axis=2. In python this is the slowest # varying # if axis == 2: #forward differences near the first boundary for i in range(1): aprime[:,:,i] = (-a[:,:,i]+a[:,:,i+1]) / (dx) #centered differences for i in range(1,s[2]-1): aprime[:,:,i] = (-a[:,:,i-1]+a[:,:,i+1])/(2*dx) #backward differences near the second boundary for i in range(s[2]-1,s[2]): aprime[:,:,i] = (a[:,:,i-1]-a[:,:,i]) /(dx) # # derivative for axis=1 # if axis == 1: #forward differences near the first boundary for i in range(1): aprime[:,i,:] = (-a[:,i,:]+a[:,i+1,:]) / (dx) #centered differences for i in range(1,s[1]-1): aprime[:,i,:] = (-a[:,i-1,:]+a[:,i+1,:])/(2*dx) #backward differences near the second boundary for i in range(s[1]-1,s[1]): aprime[:,i,:] = (a[:,i-1,:]-a[:,i,:]) /(dx) # # derivative for user axis=0 # if axis == 0: #forward differences near the first boundary for i in range(1): aprime[i,:,:] = (-a[i,:,:]+a[i+1,:,:]) / (dx) #centered differences for i in range(1,s[0]-1): aprime[i,:,:] = (-a[i-1,:,:]+a[i+1,:,:])/(2*dx) #backward differences near the second boundary for i in range(s[0]-1,s[0]): aprime[i,:,:] = (a[i-1,:,:]-a[i,:,:]) /(dx) return aprime def _deriv_findiff4(a,axis,dx): """Function that calculates first-order derivatives using 4th order finite differences in regular Cartesian grids. """ s = np.shape(a) #size of the input array aprime = np.array(a) #output has the same size than input if axis == 2: #forward differences near the first boundary for i in range(2): aprime[:,:,i] = (-3*a[:,:,i]+4*a[:,:,i+1]-a[:,:,i+2]) / (2*dx) #centered differences for i in range(2,s[2]-2): aprime[:,:,i] = (a[:,:,i-2]-8*a[:,:,i-1]+8*a[:,:,i+1]-a[:,:,i+2])/(12*dx) #backward differences near the second boundary for i in range(s[2]-2,s[2]): aprime[:,:,i] = (a[:,:,i-2]-4*a[:,:,i-1]+3*a[:,:,i]) /(2*dx) # # derivative for axis=2 # if axis == 1: #forward differences near the first boundary for i in range(2): aprime[:,i,:] = (-3*a[:,i,:]+4*a[:,i+1,:]-a[:,i+2,:]) / (2*dx) #centered differences for i in range(2,s[1]-2): aprime[:,i,:] = (a[:,i-2,:]-8*a[:,i-1,:]+8*a[:,i+1,:]-a[:,i+2,:])/(12*dx) #backward differences near the second boundary for i in range(s[1]-2,s[1]): aprime[:,i,:] = (a[:,i-2,:]-4*a[:,i-1,:]+3*a[:,i,:]) /(2*dx) # # derivative for user axis=3 # if axis == 0: #forward differences near the first boundary for i in range(2): aprime[i,:,:] = (-3*a[i,:,:]+4*a[i+1,:,:]-a[i+2,:,:]) / (2*dx) #centered differences for i in range(2,s[0]-2): aprime[i,:,:] = (a[i-2,:,:]-8*a[i-1,:,:]+8*a[i+1,:,:]-a[i+2,:,:])/(12*dx) #backward differences near the second boundary for i in range(s[0]-2,s[0]): aprime[i,:,:] = (a[i-2,:,:]-4*a[i-1,:,:]+3*a[i,:,:]) /(2*dx) return aprime def DerivFinDiff(a,axis,dx,order=6): """ Function that calculates first-order derivatives on Cartesian grids. This function computes the partial derivative of a multidimensional array using 2nd, 4th, or 6th order finite differences. Parameters ---------- a : numpy.ndarray A two or three-dimensional Numpy array axis : int The axis along which the derivative should be taken. The slowest varying axis is 0. The next slowest is 1. dx : float The differential step size order : int, optional The accuracy order of finite difference method. The default is 6. Valid values are 2, 4, 6. Calling sequence ---------------- >>> deriv = DerivFinDiff(a,axis,delta, order=6) Returns ------- da_dx : numpy.ndarray The derivative of `a` with respect to `dx` along `axis` """ if order == 4: return _deriv_findiff4(a,axis,dx) if order == 2: return _deriv_findiff2(a,axis,dx) s = np.shape(a) #size of the input array aprime = np.array(a) #output has the same size than input # # derivative for user axis=2, in python this is third coordinate # if axis == 2: if (s[2] < 2): return np.zeros_like(a) if (s[2] < 4): return _deriv_findiff2(a,axis,dx) if (s[2] < 6): return _deriv_findiff4(a,axis,dx) #forward differences near the first boundary for i in range(3): aprime[:,:,i] = (-11*a[:,:,i]+18*a[:,:,i+1]-9*a[:,:,i+2]+2*a[:,:,i+3]) / (6*dx) #centered differences for i in range(3,s[2]-3): aprime[:,:,i] = (-a[:,:,i-3]+9*a[:,:,i-2]-45*a[:,:,i-1]+45*a[:,:,i+1] -9*a[:,:,i+2]+a[:,:,i+3])/(60*dx) #backward differences near the second boundary for i in range(s[2]-3,s[2]): aprime[:,:,i] = (-2*a[:,:,i-3]+9*a[:,:,i-2]-18*a[:,:,i-1]+11*a[:,:,i]) /(6*dx) # # derivative for axis=1 # if axis == 1: if (s[1] < 2): return np.zeros_like(a) if (s[1] < 4): return _deriv_findiff2(a,axis,dx) if (s[1] < 6): return _deriv_findiff4(a,axis,dx) for i in range(3): aprime[:,i,:] = (-11*a[:,i,:]+18*a[:,i+1,:]-9*a[:,i+2,:]+2*a[:,i+3,:]) /(6*dx) #forward differences near the first boundary for i in range(3,s[1]-3): aprime[:,i,:] = (-a[:,i-3,:]+9*a[:,i-2,:]-45*a[:,i-1,:]+45*a[:,i+1,:] -9*a[:,i+2,:]+a[:,i+3,:])/(60*dx) #centered differences for i in range(s[1]-3,s[1]): aprime[:,i,:] = (-2*a[:,i-3,:]+9*a[:,i-2,:]-18*a[:,i-1,:]+11*a[:,i,:]) /(6*dx) #backward differences near the second boundary # # derivative for user axis=0 # if axis == 0: if (s[0] < 2): return np.zeros_like(a) if (s[0] < 4): return _deriv_findiff2(a,axis,dx) if (s[0] < 6): return _deriv_findiff4(a,axis,dx) for i in range(3): aprime[i,:,:] = (-11*a[i,:,:]+18*a[i+1,:,:]-9*a[i+2,:,:]+2*a[i+3,:,:]) /(6*dx) #forward differences near the first boundary for i in range(3,s[0]-3): aprime[i,:,:] = (-a[i-3,:,:]+9*a[i-2,:,:]-45*a[i-1,:,:]+45*a[i+1,:,:] -9*a[i+2,:,:]+a[i+3,:,:])/(60*dx) #centered differences for i in range(s[0]-3,s[0]): aprime[i,:,:] = (-2*a[i-3,:,:]+9*a[i-2,:,:]-18*a[i-1,:,:]+11*a[i,:,:]) /(6*dx) #backward differences near the second boundary return aprime def _deriv_var_findiff2(a,var,axis): s = np.shape(a) #size of the input array aprime = np.array(a) #output has the same size than input if axis == 2: #forward differences near the first boundary for i in range(1): aprime[:,:,i] = (-a[:,:,i]+a[:,:,i+1]) / (-var[:,:,i]+var[:,:,i+1]) #centered differences for i in range(1,s[2]-1): aprime[:,:,i] = (-a[:,:,i-1]+a[:,:,i+1])/(-var[:,:,i-1]+var[:,:,i+1]) #backward differences near the second boundary for i in range(s[2]-1,s[2]): aprime[:,:,i] = (a[:,:,i-1]-a[:,:,i]) / (var[:,:,i-1]-var[:,:,i]) if axis == 1: #forward differences near the first boundary for i in range(1): aprime[:,i,:] = (-a[:,i,:]+a[:,i+1,:]) / (-var[:,i,:]+var[:,i+1,:]) #centered differences for i in range(1,s[1]-1): aprime[:,i,:] = (-a[:,i-1,:]+a[:,i+1,:])/(-var[:,i-1,:]+var[:,i+1,:]) #backward differences near the second boundary for i in range(s[1]-1,s[1]): aprime[:,i,:] = (a[:,i-1,:]-a[:,i,:]) / (var[:,i-1,:]-var[:,i,:]) # # if axis == 0: #forward differences near the first boundary for i in range(1): aprime[i,:,:] = (-a[i,:,:]+a[i+1,:,:]) / (-var[i,:,:]+var[i+1,:,:]) #centered differences for i in range(1,s[0]-1): aprime[i,:,:] = (-a[i-1,:,:]+a[i+1,:,:])/ (-var[i-1,:,:]+var[i+1,:,:]) #backward differences near the second boundary for i in range(s[0]-1,s[0]): aprime[i,:,:] = (a[i-1,:,:]-a[i,:,:]) / (var[i-1,:,:]-var[i,:,:]) return aprime def _deriv_var_findiff4(a,var,axis): s = np.shape(a) #size of the input array aprime = np.array(a) #output has the same size than input # # derivative for user axis=2 # if axis == 2: #forward differences near the first boundary for i in range(2): aprime[:,:,i] = (-3*a[:,:,i]+4*a[:,:,i+1]-a[:,:,i+2]) / (-3*var[:,:,i]+4*var[:,:,i+1]-var[:,:,i+2]) #centered differences for i in range(2,s[2]-2): aprime[:,:,i] = (a[:,:,i-2]-8*a[:,:,i-1]+8*a[:,:,i+1]-a[:,:,i+2])/(var[:,:,i-2]-8*var[:,:,i-1]+8*var[:,:,i+1]-var[:,:,i+2]) #backward differences near the second boundary for i in range(s[2]-2,s[2]): aprime[:,:,i] = (a[:,:,i-2]-4*a[:,:,i-1]+3*a[:,:,i]) / (var[:,:,i-2]-4*var[:,:,i-1]+3*var[:,:,i]) # # if axis == 1: #forward differences near the first boundary for i in range(2): aprime[:,i,:] = (-3*a[:,i,:]+4*a[:,i+1,:]-a[:,i+2,:]) / (-3*var[:,i,:]+4*var[:,i+1,:]-var[:,i+2,:]) #centered differences for i in range(2,s[1]-2): aprime[:,i,:] = (a[:,i-2,:]-8*a[:,i-1,:]+8*a[:,i+1,:]-a[:,i+2,:])/ (var[:,i-2,:]-8*var[:,i-1,:]+8*var[:,i+1,:]-var[:,i+2,:]) #backward differences near the second boundary for i in range(s[1]-2,s[1]): aprime[:,i,:] = (a[:,i-2,:]-4*a[:,i-1,:]+3*a[:,i,:]) / (var[:,i-2,:]-4*var[:,i-1,:]+3*var[:,i,:]) # # if axis == 0: #forward differences near the first boundary for i in range(2): aprime[i,:,:] = (-3*a[i,:,:]+4*a[i+1,:,:]-a[i+2,:,:]) / (-3*var[i,:,:]+4*var[i+1,:,:]-var[i+2,:,:]) #centered differences for i in range(2,s[0]-2): aprime[i,:,:] = (a[i-2,:,:]-8*a[i-1,:,:]+8*a[i+1,:,:]-a[i+2,:,:])/ (var[i-2,:,:]-8*var[i-1,:,:]+8*var[i+1,:,:]-var[i+2,:,:]) #backward differences near the second boundary for i in range(s[0]-2,s[0]): aprime[i,:,:] = (a[i-2,:,:]-4*a[i-1,:,:]+3*a[i,:,:]) / (var[i-2,:,:]-4*var[i-1,:,:]+3*var[i,:,:]) return aprime def DerivVarFinDiff(a,var,axis,order=6): """ Function that calculates first-order derivatives on Cartesian grids with respect to another variable This function computes the partial derivative of a multidimensional array using 2nd, 4th, or 6th order finite differences with respect to a second multidimensional array of the same shape. Parameters ---------- a : numpy.ndarray A two or three-dimensional Numpy array var : numpy.ndarray A two or three-dimensional Numpy array of the same shape as `a` axis : int The axis along which the derivative should be taken. The slowest varying axis is 0. The next slowest is 1. order : int, optional The accuracy order of finite difference method. The default is 6. Valid values are 2, 4, 6. Calling sequence ---------------- >>> deriv = DerivFinDiff(a,var,delta, order=6) Returns ------- da_var : numpy.ndarray The derivative of `a` with respect to `var` along `axis` """ if order == 4: return deriv_var_findiff4(a,var,axis) if order == 2: return deriv_var_findiff2(a,var,axis) s = np.shape(a) #size of the input array aprime = np.array(a) #output has the same size than input # # derivative for axis=2 # if axis == 2: if (s[2] < 2): return np.zeros_like(a) if (s[2] < 4): return deriv_var_findiff2(a,var,axis) if (s[2] < 6): return deriv_var_findiff4(a,var,axis) #forward differences near the first boundary for i in range(3): aprime[:,:,i] = (-11*a[:,:,i]+18*a[:,:,i+1]-9*a[:,:,i+2]+2*a[:,:,i+3]) / (-11*var[:,:,i]+18*var[:,:,i+1]-9*var[:,:,i+2]+2*var[:,:,i+3]) #centered differences for i in range(3,s[2]-3): aprime[:,:,i] = (-a[:,:,i-3]+9*a[:,:,i-2]-45*a[:,:,i-1]+45*a[:,:,i+1] -9*a[:,:,i+2]+a[:,:,i+3])/(-var[:,:,i-3]+9*var[:,:,i-2]-45*var[:,:,i-1]+45*var[:,:,i+1] -9*var[:,:,i+2]+var[:,:,i+3]) #backward differences near the second boundary for i in range(s[2]-3,s[2]): aprime[:,:,i] = (-2*a[:,:,i-3]+9*a[:,:,i-2]-18*a[:,:,i-1]+11*a[:,:,i]) /(-2*var[:,:,i-3]+9*var[:,:,i-2]-18*var[:,:,i-1]+11*var[:,:,i]) # # derivative for axis=1 # if axis == 1: if (s[1] < 2): return np.zeros_like(a) if (s[1] < 4): return deriv_var_findiff2(a,var,axis) if (s[1] < 6): return deriv_var_findiff4(a,var,axis) for i in range(3): aprime[:,i,:] = (-11*a[:,i,:]+18*a[:,i+1,:]-9*a[:,i+2,:]+2*a[:,i+3,:]) /(-11*var[:,i,:]+18*var[:,i+1,:]-9*var[:,i+2,:]+2*var[:,i+3,:]) #forward differences near the first boundary for i in range(3,s[1]-3): aprime[:,i,:] = (-a[:,i-3,:]+9*a[:,i-2,:]-45*a[:,i-1,:]+45*a[:,i+1,:] -9*a[:,i+2,:]+a[:,i+3,:])/(-var[:,i-3,:]+9*var[:,i-2,:]-45*var[:,i-1,:]+45*var[:,i+1,:] -9*var[:,i+2,:]+var[:,i+3,:]) #centered differences for i in range(s[1]-3,s[1]): aprime[:,i,:] = (-2*a[:,i-3,:]+9*a[:,i-2,:]-18*a[:,i-1,:]+11*a[:,i,:]) /(-2*var[:,i-3,:]+9*var[:,i-2,:]-18*var[:,i-1,:]+11*var[:,i,:]) #backward differences near the second boundary # # derivative for axis=0 # if axis == 0: if (s[0] < 2): return np.zeros_like(a) if (s[0] < 4): return deriv_var_findiff2(a,var,axis) if (s[0] < 6): return deriv_var_findiff4(a,var,axis) for i in range(3): aprime[i,:,:] = (-11*a[i,:,:]+18*a[i+1,:,:]-9*a[i+2,:,:]+2*a[i+3,:,:]) /(-11*var[i,:,:]+18*var[i+1,:,:]-9*var[i+2,:,:]+2*var[i+3,:,:]) #forward differences near the first boundary for i in range(3,s[0]-3): aprime[i,:,:] = (-a[i-3,:,:]+9*a[i-2,:,:]-45*a[i-1,:,:]+45*a[i+1,:,:] -9*a[i+2,:,:]+a[i+3,:,:])/(-var[i-3,:,:]+9*var[i-2,:,:]-45*var[i-1,:,:]+45*var[i+1,:,:] -9*var[i+2,:,:]+var[i+3,:,:]) #centered differences for i in range(s[0]-3,s[0]): aprime[i,:,:] = (-2*a[i-3,:,:]+9*a[i-2,:,:]-18*a[i-1,:,:]+11*a[i,:,:]) /(-2*var[i-3,:,:]+9*var[i-2,:,:]-18*var[i-1,:,:]+11*var[i,:,:]) #backward differences near the second boundary return aprime def CurlFinDiff(M,N,P,dx,dy,dz,order=6): """ Function that calculates the Curl of a vector field on Cartesian grids This function computes the curl of a 3D vector field defined by the vector component arrays `M`, `N`, and `P` using 2nd, 4th, or 6th order finite differences. If F is defined as M(x,y,z)i + N(x,y,z)j + P(x,y,z) then curl F is given by: (dP/dy - dN/dz)i + (dM/dz - dP/dx)j + (dN/dx - dM/dy)k Parameters ---------- M : numpy.ndarray A three-dimensional Numpy array giving the x component of the vector N : numpy.ndarray A three-dimensional Numpy array giving the y component of the vector P : numpy.ndarray A three-dimensional Numpy array giving the z component of the vector dx : float The differential step size along the fastest varying axis dy : float The differential step size along the second fastest varying axis dz : float The differential step size along the third fastest varying axis order : int, optional The accuracy order of finite difference method. The default is 6. Valid values are 2, 4, 6. Calling sequence ---------------- >>> wx,wy,wz = CurlFinDiff(M,N,P,dx,dy,dz,order=6) Returns ------- wx,wy,wz : numpy.ndarray The i,j,k components of the curl, respectively """ aux1 = DerivFinDiff(P,1,dy,order) #x component of the curl aux2 = DerivFinDiff(N,0,dz,order) outx = aux1-aux2 aux1 = DerivFinDiff(M,0,dz,order) #y component of the curl aux2 = DerivFinDiff(P,2,dx,order) outy = aux1-aux2 aux1 = DerivFinDiff(N,2,dx,order) #z component of the curl aux2 = DerivFinDiff(M,1,dy,order) outz = aux1-aux2 return outx, outy, outz #return results in user coordinate order # Calculate divergence def DivFinDiff(M,N,P,dx,dy,dz,order=6): """ Function that calculates the Divergence of a vector field on Cartesian grids This function computes the divergence of a 3D vector field defined by the vector component arrays `M`, `N`, and `P` using 2nd, 4th, or 6th order finite differences. If F is defined as M(x,y,z)i + N(x,y,z)j + P(x,y,z) then div F is given by: dM/dx + dN/dy + dP/dz Parameters ---------- M : numpy.ndarray A three-dimensional Numpy array giving the x component of the vector N : numpy.ndarray A three-dimensional Numpy array giving the y component of the vector P : numpy.ndarray A three-dimensional Numpy array giving the z component of the vector dx : float The differential step size along the fastest varying axis dy : float The differential step size along the second fastest varying axis dz : float The differential step size along the third fastest varying axis order : int, optional The accuracy order of finite difference method. The default is 6. Valid values are 2, 4, 6. Calling sequence ---------------- >>> a = DivFinDiff(M,N,P,dx,dy,dz,order=6) Returns ------- wx,wy,wz : numpy.ndarray The i,j,k components of the curl, respectively """ return DerivFinDiff(P,0,dz,order) + \ DerivFinDiff(N,1,dy,order) + DerivFinDiff(M,2,dx,order) def GradFinDif(A,dx,dy,dz,order=6): """ Function that calculates the Gradient of a scalar field on Cartesian grids This function computes the gradient of a scalar field `A`: dA/dx*i + dA/dy*j + dA/dz*k Parameters ---------- A : numpy.ndarray A three-dimensional Numpy array dx : float The differential step size along the fastest varying axis dy : float The differential step size along the second fastest varying axis dz : float The differential step size along the third fastest varying axis order : int, optional The accuracy order of finite difference method. The default is 6. Valid values are 2, 4, 6. Calling sequence ---------------- >>> da_dx,da_dy,da_dz = GradFinDif(A,dx,dy,dz,order=6) Returns ------- da_dx,da_dy,da_dz: numpy.ndarray The partial derivatives of A with respect to x,y,z, respectively """ aux1 = DerivFinDiff(A,2,dx,order) #x component of the gradient aux2 = DerivFinDiff(A,1,dy,order) aux3 = DerivFinDiff(A,0,dz,order) return aux1,aux2,aux3 # return in user coordinate (x,y,z) order def Interp3d(A,PR,val): '''Method that vertically interpolates one 3D variable to a level determined by another variable. The second variable (PR) is typically pressure. The second variable must decrease as a function of z (elevation). The returned value is a 2D variable having values interpolated to the surface defined by PR = val Sweep array from bottom to top''' s = np.shape(PR) #size of the input arrays ss = [s[1],s[2]] # shape of 2d arrays interpVal = np.empty(ss,np.float32) ratio = np.zeros(ss,np.float32) # the LEVEL value is determine the lowest level where P<=val LEVEL = np.empty(ss,np.int32) LEVEL[:,:] = -1 #value where PR<=val has not been found for K in range(s[0]): #LEVNEED is true if this is first time PR= TC) T_SEA_LEVEL = numpy.where(RIDTEST, TC, TC - .005*(T_SURF -TC)**2) Z_HALF_LOWEST=ELEVATION[0,:,:] WRF_SLP = 0.01*(PR[0,:,:]*numpy.exp(2.*G*Z_HALF_LOWEST/(R*(T_SEA_LEVEL+T_SURF)))) return WRF_SLP def TD(P,PB,QVAPOR): ''' Calculation of dewpoint temperature based on WRF variables. Calling sequence: WRFTD = TD(P,PB,QVAPOR) where P,PB,QVAPOR are WRF 3D variables, and result WRFTD is a 3D variable on the same grid.''' #Let PR = 0.1*(P+PB) (pressure in hPa) #and QV = MAX(QVAPOR,0) #Where TDC = QV*PR/(0.622+QV) # TDC = MAX(TDC,0.001) #Formula is (243.5*log(TDC) - 440.8)/(19.48-log(TDC)) QV = numpy.maximum(QVAPOR,0.0) TDC = 0.01*QV*(P+PB)/(0.622+QV) TDC = numpy.maximum(TDC,0.001) WRF_TD =(243.5*numpy.log(TDC) - 440.8)/(19.48 - numpy.log(TDC)) return WRF_TD def TK(P,PB,T): ''' Calculation of temperature in degrees kelvin using WRF variables. Calling sequence: TMP = TK(P,PB,T) Where P,PB,T are WRF 3D variables, result TMP is a 3D variable indicating the temperature in degrees Kelvin.''' #Formula is (T+300)*((P+PB)*10**(-5))**c, #Where c is 287/(7*287*.5) = 2/7 c = 2.0/7.0 TH = T+300.0 WRF_TK = TH*numpy.power((P+PB)*.00001,c) return WRF_TK ================================================ FILE: share/shaders/.gitattributes ================================================ BBTraversalAlgorithms.frag -diff -merge BBTraversalAlgorithms.frag linguist-generated=true ================================================ FILE: share/shaders/2DData.frag ================================================ #version 330 core uniform sampler1D colormap; uniform float minLUTValue; uniform float maxLUTValue; uniform float constantOpacity; in vec2 vertexData; out vec4 fragColor; void main(void) { if (minLUTValue > maxLUTValue) discard; vec2 texel = vertexData; // Check for missing value if (texel.y != 0.0) discard; float s = (texel.x - minLUTValue) / (maxLUTValue - minLUTValue); if (maxLUTValue == minLUTValue) s=0.; vec4 color = texture(colormap, s); float alpha = color.a * constantOpacity; fragColor = vec4(color.rgb, alpha); if (alpha < 0.001) discard; } ================================================ FILE: share/shaders/2DData.vert ================================================ #version 330 core uniform mat4 MVP; layout (location = 0) in vec3 vertex; layout (location = 1) in vec2 vVertexData; out vec2 vertexData; uniform vec4 clippingPlanes[6]; out float gl_ClipDistance[6]; void main() { gl_Position = MVP * vec4(vertex, 1.0); vertexData = vVertexData; for (int i = 0; i < 6; i++) gl_ClipDistance[i] = dot(vec4(vertex, 1.0), clippingPlanes[i]); } ================================================ FILE: share/shaders/BBTraversalAlgorithms.frag ================================================ // --------------------------------------------- // This file is generated by GenerateBBTraversals.pl // Any changes made to this file will be lost // --------------------------------------------- int SearchSideForInitialCellWithOctree_1Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); int yEnd0 = lDims0.y; int xEnd0 = lDims0.x; int x1 = 0; int y1 = 0; for (int y0 = y1*2; y0 < yEnd0; y0++) { for (int x0 = x1*2; x0 < xEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } } } return intersections; } int SearchSideForInitialCellWithOctree_2Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); int yEnd1 = lDims1.y; int xEnd1 = lDims1.x; int x2 = 0; int y2 = 0; for (int y1 = y2*2; y1 < yEnd1; y1++) { for (int x1 = x2*2; x1 < xEnd1; x1++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) { int yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; int xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; for (int y0 = y1*2; y0 < yEnd0; y0++) { for (int x0 = x1*2; x0 < xEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } } } } } } return intersections; } int SearchSideForInitialCellWithOctree_3Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); ivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2); int yEnd2 = lDims2.y; int xEnd2 = lDims2.x; int x3 = 0; int y3 = 0; for (int y2 = y3*2; y2 < yEnd2; y2++) { for (int x2 = x3*2; x2 < xEnd2; x2++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) { int yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2; int xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2; for (int y1 = y2*2; y1 < yEnd1; y1++) { for (int x1 = x2*2; x1 < xEnd1; x1++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) { int yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; int xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; for (int y0 = y1*2; y0 < yEnd0; y0++) { for (int x0 = x1*2; x0 < xEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } } } } } } } } } return intersections; } int SearchSideForInitialCellWithOctree_4Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); ivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2); ivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3); int yEnd3 = lDims3.y; int xEnd3 = lDims3.x; int x4 = 0; int y4 = 0; for (int y3 = y4*2; y3 < yEnd3; y3++) { for (int x3 = x4*2; x3 < xEnd3; x3++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) { int yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2; int xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2; for (int y2 = y3*2; y2 < yEnd2; y2++) { for (int x2 = x3*2; x2 < xEnd2; x2++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) { int yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2; int xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2; for (int y1 = y2*2; y1 < yEnd1; y1++) { for (int x1 = x2*2; x1 < xEnd1; x1++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) { int yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; int xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; for (int y0 = y1*2; y0 < yEnd0; y0++) { for (int x0 = x1*2; x0 < xEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } } } } } } } } } } } } return intersections; } int SearchSideForInitialCellWithOctree_5Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); ivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2); ivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3); ivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4); int yEnd4 = lDims4.y; int xEnd4 = lDims4.x; int x5 = 0; int y5 = 0; for (int y4 = y5*2; y4 < yEnd4; y4++) { for (int x4 = x5*2; x4 < xEnd4; x4++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) { int yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2; int xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2; for (int y3 = y4*2; y3 < yEnd3; y3++) { for (int x3 = x4*2; x3 < xEnd3; x3++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) { int yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2; int xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2; for (int y2 = y3*2; y2 < yEnd2; y2++) { for (int x2 = x3*2; x2 < xEnd2; x2++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) { int yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2; int xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2; for (int y1 = y2*2; y1 < yEnd1; y1++) { for (int x1 = x2*2; x1 < xEnd1; x1++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) { int yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; int xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; for (int y0 = y1*2; y0 < yEnd0; y0++) { for (int x0 = x1*2; x0 < xEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } } } } } } } } } } } } } } } return intersections; } int SearchSideForInitialCellWithOctree_6Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); ivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2); ivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3); ivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4); ivec2 lDims5 = GetBBoxArrayDimensions(sideID, 5); int yEnd5 = lDims5.y; int xEnd5 = lDims5.x; int x6 = 0; int y6 = 0; for (int y5 = y6*2; y5 < yEnd5; y5++) { for (int x5 = x6*2; x5 < xEnd5; x5++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x5, y5, sideID, 5)) { int yEnd4 = y5 == lDims5.y-1 ? lDims4.y : (y5+1)*2; int xEnd4 = x5 == lDims5.x-1 ? lDims4.x : (x5+1)*2; for (int y4 = y5*2; y4 < yEnd4; y4++) { for (int x4 = x5*2; x4 < xEnd4; x4++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) { int yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2; int xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2; for (int y3 = y4*2; y3 < yEnd3; y3++) { for (int x3 = x4*2; x3 < xEnd3; x3++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) { int yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2; int xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2; for (int y2 = y3*2; y2 < yEnd2; y2++) { for (int x2 = x3*2; x2 < xEnd2; x2++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) { int yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2; int xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2; for (int y1 = y2*2; y1 < yEnd1; y1++) { for (int x1 = x2*2; x1 < xEnd1; x1++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) { int yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; int xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; for (int y0 = y1*2; y0 < yEnd0; y0++) { for (int x0 = x1*2; x0 < xEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } } } } } } } } } } } } } } } } } } return intersections; } int SearchSideForInitialCellWithOctree_7Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); ivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2); ivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3); ivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4); ivec2 lDims5 = GetBBoxArrayDimensions(sideID, 5); ivec2 lDims6 = GetBBoxArrayDimensions(sideID, 6); int yEnd6 = lDims6.y; int xEnd6 = lDims6.x; int x7 = 0; int y7 = 0; for (int y6 = y7*2; y6 < yEnd6; y6++) { for (int x6 = x7*2; x6 < xEnd6; x6++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x6, y6, sideID, 6)) { int yEnd5 = y6 == lDims6.y-1 ? lDims5.y : (y6+1)*2; int xEnd5 = x6 == lDims6.x-1 ? lDims5.x : (x6+1)*2; for (int y5 = y6*2; y5 < yEnd5; y5++) { for (int x5 = x6*2; x5 < xEnd5; x5++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x5, y5, sideID, 5)) { int yEnd4 = y5 == lDims5.y-1 ? lDims4.y : (y5+1)*2; int xEnd4 = x5 == lDims5.x-1 ? lDims4.x : (x5+1)*2; for (int y4 = y5*2; y4 < yEnd4; y4++) { for (int x4 = x5*2; x4 < xEnd4; x4++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) { int yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2; int xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2; for (int y3 = y4*2; y3 < yEnd3; y3++) { for (int x3 = x4*2; x3 < xEnd3; x3++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) { int yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2; int xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2; for (int y2 = y3*2; y2 < yEnd2; y2++) { for (int x2 = x3*2; x2 < xEnd2; x2++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) { int yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2; int xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2; for (int y1 = y2*2; y1 < yEnd1; y1++) { for (int x1 = x2*2; x1 < xEnd1; x1++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) { int yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; int xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; for (int y0 = y1*2; y0 < yEnd0; y0++) { for (int x0 = x1*2; x0 < xEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } } } } } } } } } } } } } } } } } } } } } return intersections; } int SearchSideForInitialCellWithOctree_8Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); ivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2); ivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3); ivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4); ivec2 lDims5 = GetBBoxArrayDimensions(sideID, 5); ivec2 lDims6 = GetBBoxArrayDimensions(sideID, 6); ivec2 lDims7 = GetBBoxArrayDimensions(sideID, 7); int yEnd7 = lDims7.y; int xEnd7 = lDims7.x; int x8 = 0; int y8 = 0; for (int y7 = y8*2; y7 < yEnd7; y7++) { for (int x7 = x8*2; x7 < xEnd7; x7++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x7, y7, sideID, 7)) { int yEnd6 = y7 == lDims7.y-1 ? lDims6.y : (y7+1)*2; int xEnd6 = x7 == lDims7.x-1 ? lDims6.x : (x7+1)*2; for (int y6 = y7*2; y6 < yEnd6; y6++) { for (int x6 = x7*2; x6 < xEnd6; x6++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x6, y6, sideID, 6)) { int yEnd5 = y6 == lDims6.y-1 ? lDims5.y : (y6+1)*2; int xEnd5 = x6 == lDims6.x-1 ? lDims5.x : (x6+1)*2; for (int y5 = y6*2; y5 < yEnd5; y5++) { for (int x5 = x6*2; x5 < xEnd5; x5++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x5, y5, sideID, 5)) { int yEnd4 = y5 == lDims5.y-1 ? lDims4.y : (y5+1)*2; int xEnd4 = x5 == lDims5.x-1 ? lDims4.x : (x5+1)*2; for (int y4 = y5*2; y4 < yEnd4; y4++) { for (int x4 = x5*2; x4 < xEnd4; x4++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) { int yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2; int xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2; for (int y3 = y4*2; y3 < yEnd3; y3++) { for (int x3 = x4*2; x3 < xEnd3; x3++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) { int yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2; int xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2; for (int y2 = y3*2; y2 < yEnd2; y2++) { for (int x2 = x3*2; x2 < xEnd2; x2++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) { int yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2; int xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2; for (int y1 = y2*2; y1 < yEnd1; y1++) { for (int x1 = x2*2; x1 < xEnd1; x1++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) { int yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; int xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; for (int y0 = y1*2; y0 < yEnd0; y0++) { for (int x0 = x1*2; x0 < xEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } } } } } } } } } } } } } } } } } } } } } } } } return intersections; } ================================================ FILE: share/shaders/BBTraversalAlgorithmsNV.frag ================================================ // --------------------------------------------- // This file is generated by GenerateBBTraversalsNvidia.pl // Any changes made to this file will be lost // --------------------------------------------- int SearchSideForInitialCellWithOctree_1Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); int yEnd0 = lDims0.y; int xEnd0 = lDims0.x; int x1 = 0; int y1 = 0; // for (int y0 = y1*2; y0 < yEnd0; y0++) { int y0 = y1*2; for (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } if (x0 == xEnd0-1) { x0 = x1*2-1; y0++; } } return intersections; } int SearchSideForInitialCellWithOctree_2Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); int yEnd1 = lDims1.y; int xEnd1 = lDims1.x; int x2 = 0; int y2 = 0; // for (int y1 = y2*2; y1 < yEnd1; y1++) { int y1 = y2*2; for (int x1 = x2*2; x1 < xEnd1 && y1 < yEnd1; x1++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) { int yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; int xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; // for (int y0 = y1*2; y0 < yEnd0; y0++) { int y0 = y1*2; for (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } if (x0 == xEnd0-1) { x0 = x1*2-1; y0++; } } } if (x1 == xEnd1-1) { x1 = x2*2-1; y1++; } } return intersections; } int SearchSideForInitialCellWithOctree_3Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); ivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2); int yEnd2 = lDims2.y; int xEnd2 = lDims2.x; int x3 = 0; int y3 = 0; // for (int y2 = y3*2; y2 < yEnd2; y2++) { int y2 = y3*2; for (int x2 = x3*2; x2 < xEnd2 && y2 < yEnd2; x2++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) { int yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2; int xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2; // for (int y1 = y2*2; y1 < yEnd1; y1++) { int y1 = y2*2; for (int x1 = x2*2; x1 < xEnd1 && y1 < yEnd1; x1++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) { int yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; int xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; // for (int y0 = y1*2; y0 < yEnd0; y0++) { int y0 = y1*2; for (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } if (x0 == xEnd0-1) { x0 = x1*2-1; y0++; } } } if (x1 == xEnd1-1) { x1 = x2*2-1; y1++; } } } if (x2 == xEnd2-1) { x2 = x3*2-1; y2++; } } return intersections; } int SearchSideForInitialCellWithOctree_4Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); ivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2); ivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3); int yEnd3 = lDims3.y; int xEnd3 = lDims3.x; int x4 = 0; int y4 = 0; // for (int y3 = y4*2; y3 < yEnd3; y3++) { int y3 = y4*2; for (int x3 = x4*2; x3 < xEnd3 && y3 < yEnd3; x3++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) { int yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2; int xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2; // for (int y2 = y3*2; y2 < yEnd2; y2++) { int y2 = y3*2; for (int x2 = x3*2; x2 < xEnd2 && y2 < yEnd2; x2++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) { int yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2; int xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2; // for (int y1 = y2*2; y1 < yEnd1; y1++) { int y1 = y2*2; for (int x1 = x2*2; x1 < xEnd1 && y1 < yEnd1; x1++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) { int yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; int xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; // for (int y0 = y1*2; y0 < yEnd0; y0++) { int y0 = y1*2; for (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } if (x0 == xEnd0-1) { x0 = x1*2-1; y0++; } } } if (x1 == xEnd1-1) { x1 = x2*2-1; y1++; } } } if (x2 == xEnd2-1) { x2 = x3*2-1; y2++; } } } if (x3 == xEnd3-1) { x3 = x4*2-1; y3++; } } return intersections; } int SearchSideForInitialCellWithOctree_5Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); ivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2); ivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3); ivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4); int yEnd4 = lDims4.y; int xEnd4 = lDims4.x; int x5 = 0; int y5 = 0; // for (int y4 = y5*2; y4 < yEnd4; y4++) { int y4 = y5*2; for (int x4 = x5*2; x4 < xEnd4 && y4 < yEnd4; x4++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) { int yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2; int xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2; // for (int y3 = y4*2; y3 < yEnd3; y3++) { int y3 = y4*2; for (int x3 = x4*2; x3 < xEnd3 && y3 < yEnd3; x3++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) { int yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2; int xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2; // for (int y2 = y3*2; y2 < yEnd2; y2++) { int y2 = y3*2; for (int x2 = x3*2; x2 < xEnd2 && y2 < yEnd2; x2++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) { int yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2; int xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2; // for (int y1 = y2*2; y1 < yEnd1; y1++) { int y1 = y2*2; for (int x1 = x2*2; x1 < xEnd1 && y1 < yEnd1; x1++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) { int yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; int xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; // for (int y0 = y1*2; y0 < yEnd0; y0++) { int y0 = y1*2; for (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } if (x0 == xEnd0-1) { x0 = x1*2-1; y0++; } } } if (x1 == xEnd1-1) { x1 = x2*2-1; y1++; } } } if (x2 == xEnd2-1) { x2 = x3*2-1; y2++; } } } if (x3 == xEnd3-1) { x3 = x4*2-1; y3++; } } } if (x4 == xEnd4-1) { x4 = x5*2-1; y4++; } } return intersections; } int SearchSideForInitialCellWithOctree_6Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); ivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2); ivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3); ivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4); ivec2 lDims5 = GetBBoxArrayDimensions(sideID, 5); int yEnd5 = lDims5.y; int xEnd5 = lDims5.x; int x6 = 0; int y6 = 0; // for (int y5 = y6*2; y5 < yEnd5; y5++) { int y5 = y6*2; for (int x5 = x6*2; x5 < xEnd5 && y5 < yEnd5; x5++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x5, y5, sideID, 5)) { int yEnd4 = y5 == lDims5.y-1 ? lDims4.y : (y5+1)*2; int xEnd4 = x5 == lDims5.x-1 ? lDims4.x : (x5+1)*2; // for (int y4 = y5*2; y4 < yEnd4; y4++) { int y4 = y5*2; for (int x4 = x5*2; x4 < xEnd4 && y4 < yEnd4; x4++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) { int yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2; int xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2; // for (int y3 = y4*2; y3 < yEnd3; y3++) { int y3 = y4*2; for (int x3 = x4*2; x3 < xEnd3 && y3 < yEnd3; x3++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) { int yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2; int xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2; // for (int y2 = y3*2; y2 < yEnd2; y2++) { int y2 = y3*2; for (int x2 = x3*2; x2 < xEnd2 && y2 < yEnd2; x2++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) { int yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2; int xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2; // for (int y1 = y2*2; y1 < yEnd1; y1++) { int y1 = y2*2; for (int x1 = x2*2; x1 < xEnd1 && y1 < yEnd1; x1++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) { int yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; int xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; // for (int y0 = y1*2; y0 < yEnd0; y0++) { int y0 = y1*2; for (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } if (x0 == xEnd0-1) { x0 = x1*2-1; y0++; } } } if (x1 == xEnd1-1) { x1 = x2*2-1; y1++; } } } if (x2 == xEnd2-1) { x2 = x3*2-1; y2++; } } } if (x3 == xEnd3-1) { x3 = x4*2-1; y3++; } } } if (x4 == xEnd4-1) { x4 = x5*2-1; y4++; } } } if (x5 == xEnd5-1) { x5 = x6*2-1; y5++; } } return intersections; } int SearchSideForInitialCellWithOctree_7Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); ivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2); ivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3); ivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4); ivec2 lDims5 = GetBBoxArrayDimensions(sideID, 5); ivec2 lDims6 = GetBBoxArrayDimensions(sideID, 6); int yEnd6 = lDims6.y; int xEnd6 = lDims6.x; int x7 = 0; int y7 = 0; // for (int y6 = y7*2; y6 < yEnd6; y6++) { int y6 = y7*2; for (int x6 = x7*2; x6 < xEnd6 && y6 < yEnd6; x6++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x6, y6, sideID, 6)) { int yEnd5 = y6 == lDims6.y-1 ? lDims5.y : (y6+1)*2; int xEnd5 = x6 == lDims6.x-1 ? lDims5.x : (x6+1)*2; // for (int y5 = y6*2; y5 < yEnd5; y5++) { int y5 = y6*2; for (int x5 = x6*2; x5 < xEnd5 && y5 < yEnd5; x5++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x5, y5, sideID, 5)) { int yEnd4 = y5 == lDims5.y-1 ? lDims4.y : (y5+1)*2; int xEnd4 = x5 == lDims5.x-1 ? lDims4.x : (x5+1)*2; // for (int y4 = y5*2; y4 < yEnd4; y4++) { int y4 = y5*2; for (int x4 = x5*2; x4 < xEnd4 && y4 < yEnd4; x4++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) { int yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2; int xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2; // for (int y3 = y4*2; y3 < yEnd3; y3++) { int y3 = y4*2; for (int x3 = x4*2; x3 < xEnd3 && y3 < yEnd3; x3++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) { int yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2; int xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2; // for (int y2 = y3*2; y2 < yEnd2; y2++) { int y2 = y3*2; for (int x2 = x3*2; x2 < xEnd2 && y2 < yEnd2; x2++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) { int yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2; int xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2; // for (int y1 = y2*2; y1 < yEnd1; y1++) { int y1 = y2*2; for (int x1 = x2*2; x1 < xEnd1 && y1 < yEnd1; x1++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) { int yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; int xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; // for (int y0 = y1*2; y0 < yEnd0; y0++) { int y0 = y1*2; for (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } if (x0 == xEnd0-1) { x0 = x1*2-1; y0++; } } } if (x1 == xEnd1-1) { x1 = x2*2-1; y1++; } } } if (x2 == xEnd2-1) { x2 = x3*2-1; y2++; } } } if (x3 == xEnd3-1) { x3 = x4*2-1; y3++; } } } if (x4 == xEnd4-1) { x4 = x5*2-1; y4++; } } } if (x5 == xEnd5-1) { x5 = x6*2-1; y5++; } } } if (x6 == xEnd6-1) { x6 = x7*2-1; y6++; } } return intersections; } int SearchSideForInitialCellWithOctree_8Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); ivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2); ivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3); ivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4); ivec2 lDims5 = GetBBoxArrayDimensions(sideID, 5); ivec2 lDims6 = GetBBoxArrayDimensions(sideID, 6); ivec2 lDims7 = GetBBoxArrayDimensions(sideID, 7); int yEnd7 = lDims7.y; int xEnd7 = lDims7.x; int x8 = 0; int y8 = 0; // for (int y7 = y8*2; y7 < yEnd7; y7++) { int y7 = y8*2; for (int x7 = x8*2; x7 < xEnd7 && y7 < yEnd7; x7++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x7, y7, sideID, 7)) { int yEnd6 = y7 == lDims7.y-1 ? lDims6.y : (y7+1)*2; int xEnd6 = x7 == lDims7.x-1 ? lDims6.x : (x7+1)*2; // for (int y6 = y7*2; y6 < yEnd6; y6++) { int y6 = y7*2; for (int x6 = x7*2; x6 < xEnd6 && y6 < yEnd6; x6++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x6, y6, sideID, 6)) { int yEnd5 = y6 == lDims6.y-1 ? lDims5.y : (y6+1)*2; int xEnd5 = x6 == lDims6.x-1 ? lDims5.x : (x6+1)*2; // for (int y5 = y6*2; y5 < yEnd5; y5++) { int y5 = y6*2; for (int x5 = x6*2; x5 < xEnd5 && y5 < yEnd5; x5++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x5, y5, sideID, 5)) { int yEnd4 = y5 == lDims5.y-1 ? lDims4.y : (y5+1)*2; int xEnd4 = x5 == lDims5.x-1 ? lDims4.x : (x5+1)*2; // for (int y4 = y5*2; y4 < yEnd4; y4++) { int y4 = y5*2; for (int x4 = x5*2; x4 < xEnd4 && y4 < yEnd4; x4++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) { int yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2; int xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2; // for (int y3 = y4*2; y3 < yEnd3; y3++) { int y3 = y4*2; for (int x3 = x4*2; x3 < xEnd3 && y3 < yEnd3; x3++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) { int yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2; int xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2; // for (int y2 = y3*2; y2 < yEnd2; y2++) { int y2 = y3*2; for (int x2 = x3*2; x2 < xEnd2 && y2 < yEnd2; x2++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) { int yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2; int xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2; // for (int y1 = y2*2; y1 < yEnd1; y1++) { int y1 = y2*2; for (int x1 = x2*2; x1 < xEnd1 && y1 < yEnd1; x1++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) { int yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; int xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; // for (int y0 = y1*2; y0 < yEnd0; y0++) { int y0 = y1*2; for (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) { index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; } if (x0 == xEnd0-1) { x0 = x1*2-1; y0++; } } } if (x1 == xEnd1-1) { x1 = x2*2-1; y1++; } } } if (x2 == xEnd2-1) { x2 = x3*2-1; y2++; } } } if (x3 == xEnd3-1) { x3 = x4*2-1; y3++; } } } if (x4 == xEnd4-1) { x4 = x5*2-1; y4++; } } } if (x5 == xEnd5-1) { x5 = x6*2-1; y5++; } } } if (x6 == xEnd6-1) { x6 = x7*2-1; y6++; } } } if (x7 == xEnd7-1) { x7 = x8*2-1; y7++; } } return intersections; } ================================================ FILE: share/shaders/Contour.frag ================================================ #version 330 core uniform sampler1D colormap; uniform float minLUTValue; uniform float maxLUTValue; in float fValue; out vec4 FragColor; void main() { //FragColor = fColor; float s = (fValue - minLUTValue) / (maxLUTValue - minLUTValue); vec4 color = texture(colormap, s); FragColor = color; } ================================================ FILE: share/shaders/Contour.vert ================================================ #version 330 core layout (location = 0) in vec3 vPos; layout (location = 1) in float value; out float fValue; uniform mat4 MVP; void main() { gl_Position = MVP * vec4(vPos, 1.0); fValue = value; } ================================================ FILE: share/shaders/DepthBuffer.frag ================================================ #version 330 core uniform sampler2D sampler; uniform float near; uniform float far; uniform bool linearize; in vec2 ST; out vec4 fragColor; void main(void) { float depth = texture(sampler, ST).r; if (linearize) depth = (2.0 * near) / (far + near - depth * (far - near)); fragColor = vec4(vec3(depth), 1.0); } ================================================ FILE: share/shaders/DepthBuffer.vert ================================================ #version 330 core uniform mat4 MVP; layout (location = 0) in vec2 vertex; layout (location = 1) in vec2 vTextureCoord; out vec2 ST; void main() { gl_Position = vec4(vertex, 0.0, 1.0); ST = vTextureCoord; } ================================================ FILE: share/shaders/FlowGlyphsArrow.frag ================================================ // Basic fragment shader. Maps the fValue onto a color using the LUT then applies Phong lighting. #version 330 core uniform bool constantColorEnabled = false; uniform vec3 constantColor = vec3(1.0f); uniform vec3 lightDir = vec3(0, 0, -1); uniform bool lightingEnabled = true; uniform sampler1D LUT; uniform vec2 mapRange; uniform vec3 scales; in float fValue; in vec3 fNormal; out vec4 fragment; uniform float phongAmbient; uniform float phongDiffuse; uniform float phongSpecular; uniform float phongShininess; float PhongLighting(vec3 normal, vec3 viewDir) { if (!lightingEnabled) return 1.0; vec3 lightDir = viewDir; float diffuse = abs(dot(normal, -lightDir)) * phongDiffuse; float specularStrength = phongSpecular; vec3 reflectDir = reflect(lightDir, normal); float spec = pow(abs(dot(viewDir, reflectDir)), phongShininess); float specular = specularStrength * spec; return max(phongAmbient + diffuse + specular, phongAmbient); } void main() { vec4 color; if (constantColorEnabled) color = vec4(constantColor, 1.0f); else color = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x)); if (lightingEnabled) { vec3 normal; if (gl_FrontFacing) normal = -fNormal; else normal = fNormal; vec3 ld = normalize(lightDir * scales); // float diffuse = max(dot(normal, ld), 0.0); // color.rgb *= max(diffuse, 0.2f); color.rgb *= PhongLighting(normal, ld); } fragment = color; if (color.a < 0.05) discard; } ================================================ FILE: share/shaders/FlowGlyphsArrow.geom ================================================ // This shader generates a cone at every vertex v_n pointing in the direction of // the average normal between v_n-1 to v_n and v_n to v_n+1. The cone is generated // as a triangle strip, generated from the bottom circle and top vertex. This // geometry is generated at the origin and transformed with a simple affine tranformation // using basis vectors. // // EmitWorld(vec3 v) projects v and emits it. // CylinderVert(v, ...) is a helper function that generates a point on a circle // given the parameters and passes it to EmitWorld. #version 330 core #include FlowInclude.geom #define REFINEMENT 7 layout (lines_adjacency) in; layout (triangle_strip, max_vertices = 32) out; // (7 * 2 + 2) * 2 in float gValue[]; in float clip[]; out float fValue; out vec3 fNormal; uniform mat4 P; uniform mat4 MV; uniform vec3 scales; uniform float radius = 0.05; uniform int glyphStride = 1; uniform bool showOnlyLeadingSample = false; void EmitWorld(const vec3 v); void CylinderVert(const vec3 v, const vec3 d, const float value); void main() { // Discard skipped samples if (showOnlyLeadingSample) { if (gl_PrimitiveIDIn < nVertices-4) return; } else { if (gl_PrimitiveIDIn % glyphStride != 0) return; } // Need to manually clip when using geometry shader if (clip[1] < 0.0 || clip[2] < 0.0) return; vec3 V[4]; for (int i = 0; i < 4; i++) V[i] = gl_in[i].gl_Position.xyz; vec3 VN[3]; for (int i = 0; i < 3; i++) VN[i] = normalize(V[i+1] - V[i]); vec3 N[2]; vec3 up = vec3(0, 0, 1); bool parallelToUpChanged = false; for (int i = 0; i < 2; i++) { N[i] = normalize((VN[i] + VN[i+1])/2); if (1 - dot(N[i], up) < FLT_EPSILON) parallelToUpChanged = true; } // Basis vectors are generated against an arbritray up which needs to be different from N if (parallelToUpChanged) up = vec3(1, 0, 0); // Generate basis vectors vec3 XH[2]; vec3 YH[2]; for (int i = 0; i < 2; i++) { XH[i] = normalize(cross(N[i], up)); YH[i] = normalize(cross(XH[i], N[i])); } fValue = gValue[1]; vec3 top = V[1] + N[0] * radius * 1.618 / scales; // Plot geometry sides for (int i = 0; i < REFINEMENT + 1; i++) { float t = float(i)/float(REFINEMENT) * 2.f * PI; vec3 d; d = XH[0]*cos(t) + YH[0]*sin(t); vec3 bottom = V[1] + d * radius / scales; // fNormal = normalize((d + N[0])/2.0f); fNormal = normalize(cross(top-bottom, cross(d, N[0]))); EmitWorld(bottom); EmitWorld(top); } EndPrimitive(); fNormal = -N[0]; // Plot geometry bottom for (int i = 0; i < REFINEMENT + 1; i++) { float t = float(i)/float(REFINEMENT) * 2.f * PI; vec3 d; d = XH[0]*cos(t) + YH[0]*sin(t); EmitWorld(V[1]); EmitWorld(V[1] + d * radius / scales); } EndPrimitive(); } void EmitWorld(const vec3 v) { gl_Position = P * MV * vec4(v, 1.0f); EmitVertex(); } void CylinderVert(const vec3 v, const vec3 d, const float value) { fNormal = d; EmitWorld(v + d * radius); } ================================================ FILE: share/shaders/FlowGlyphsArrow.vert ================================================ #version 330 core layout (location = 0) in vec3 vPos; layout (location = 1) in float vValue; out float gValue; uniform vec4 clippingPlanes[6]; // out float gl_ClipDistance[6]; out float clip; void main() { gValue = vValue; gl_Position = vec4(vPos, 1.0f); clip = 0; for (int i = 0; i < 6; i++) clip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0; } ================================================ FILE: share/shaders/FlowGlyphsArrow2D.frag ================================================ // Basic fragment shader. Maps the fValue onto a color using the LUT. #version 330 core uniform bool constantColorEnabled = false; uniform vec3 constantColor = vec3(1.0f); uniform float radius = 0.05f; uniform float border = 0.f; uniform vec3 borderColor = vec3(1.0f); uniform bool antiAlias = false; uniform sampler1D LUT; uniform vec2 mapRange; in float fValue; in float t; out vec4 fragment; void main() { if (constantColorEnabled) fragment = vec4(constantColor, 1.0f); else { vec4 c = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x)); if (antiAlias) { float S = 12; S *= (radius + border) / 0.1; c.rgb = mix(c.rgb, borderColor, clamp((abs(t)-radius/(radius+border))*S, 0.f, 1.f)); c.a *= min(((1-abs(t))*S), 1); } else { if (abs(t) > radius/(radius+border)) c = vec4(borderColor, 1.f); } fragment = c; if (c.a < 0.05) discard; } } ================================================ FILE: share/shaders/FlowGlyphsArrow2D.geom ================================================ // This shader generates a 2D triangle at every vertex v_n pointing in the direction of // the average normal between v_n-1 to v_n and v_n to v_n+1. // #version 330 core #include FlowInclude.geom layout (lines_adjacency) in; layout (triangle_strip, max_vertices = 3) out; in float gValue[]; in float clip[]; out float fValue; out float t; uniform float radius = 0.05f; uniform int glyphStride = 1; uniform bool showOnlyLeadingSample = false; uniform float border = 0.f; uniform float aspect; void main() { // Discard skipped samples if (showOnlyLeadingSample) { if (gl_PrimitiveIDIn < nVertices-4) return; } else { if (gl_PrimitiveIDIn % glyphStride != 0) return; } // Need to manually clip when using geometry shader if (clip[1] < 0.0 || clip[2] < 0.0) return; vec2 vS[4]; for (int i = 0; i < 4; i++) vS[i] = gl_in[i].gl_Position.xy / gl_in[i].gl_Position.w; vec2 vN[3]; for (int i = 0; i < 3; i++) vN[i] = normalize(vS[i+1] - vS[i]); // These calculations are done in screen-space so need to account for aspect ratio. vec2 n[2]; vec2 p[2]; vec4 o[2]; for (int i = 0; i < 2; i++) { n[i] = normalize((vN[i] + vN[i+1])/2); p[i] = vec2(-n[i].y, n[i].x); p[i].x /= aspect; o[i] = vec4(p[i], 0.0f, 0.0f) * (radius*2 + border); } #define v0 gl_in[1].gl_Position #define v1 gl_in[2].gl_Position vec4 top = v0 + vec4(n[0],0,0) * radius * 1.618 * 2; fValue = gValue[1]; gl_Position = v0 - o[0]; t = -1; EmitVertex(); gl_Position = top; t = -1; EmitVertex(); gl_Position = v0 + o[0]; t = 1; EmitVertex(); EndPrimitive(); } ================================================ FILE: share/shaders/FlowGlyphsArrow2D.vert ================================================ #version 330 core layout (location = 0) in vec3 vPos; layout (location = 1) in float vValue; out float gValue; uniform mat4 P; uniform mat4 MV; uniform vec4 clippingPlanes[6]; // out float gl_ClipDistance[6]; out float clip; void main() { gValue = vValue; gl_Position = P * MV * vec4(vPos, 1.0f); clip = 0; for (int i = 0; i < 6; i++) clip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0; } ================================================ FILE: share/shaders/FlowGlyphsLineDirArrow2D.frag ================================================ // Basic fragment shader. Maps the fValue onto a color using the LUT. #version 330 core uniform bool constantColorEnabled = false; uniform vec3 constantColor = vec3(1.0f); uniform float radius = 0.05f; uniform float border = 0.f; uniform vec3 borderColor = vec3(1.0f); uniform bool antiAlias = false; uniform sampler1D LUT; uniform vec2 mapRange; in float fValue; in float fFade; in float t; out vec4 fragment; void main() { vec4 color; if (constantColorEnabled) color = vec4(constantColor, 1.0f); else { vec4 c = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x)); if (antiAlias) { float S = 12; S *= (radius + border) / 0.1; c.rgb = mix(c.rgb, borderColor, clamp((abs(t)-radius/(radius+border))*S, 0.f, 1.f)); c.a *= min(((1-abs(t))*S), 1); } else { if (abs(t) > radius/(radius+border)) c = vec4(borderColor, 1.f); } color = c; } color.a *= fFade; if (fFade < 0.05) discard; fragment = color; if (color.a < 0.05) discard; } ================================================ FILE: share/shaders/FlowGlyphsLineDirArrow2D.geom ================================================ // This behaves the same as FlowGlyphsArrow2D.geom except the geometry is clipped against the line #version 330 core #include FlowInclude.geom layout (lines_adjacency) in; layout (triangle_strip, max_vertices = 6) out; in float gValue[]; in float clip[]; out float fValue; out float fFade; out float t; uniform float radius = 0.05f; uniform int glyphStride = 1; uniform float border = 0.f; uniform float aspect; void main() { if (gl_PrimitiveIDIn % glyphStride != 0) return; if (clip[1] < 0.0 || clip[2] < 0.0) return; vec2 vS[4]; for (int i = 0; i < 4; i++) vS[i] = gl_in[i].gl_Position.xy / gl_in[i].gl_Position.w; vec2 vN[3]; for (int i = 0; i < 3; i++) vN[i] = normalize(vS[i+1] - vS[i]); vec2 n[2]; vec2 p[2]; vec4 o[2]; for (int i = 0; i < 2; i++) { n[i] = normalize((vN[i] + vN[i+1])/2); p[i] = vec2(-n[i].y, n[i].x); p[i].x /= aspect; o[i] = vec4(p[i], 0.0f, 0.0f) * (radius*2 + border); } #define v0 gl_in[1].gl_Position #define v1 gl_in[2].gl_Position float s = 1.9; vec2 fade = CalculateFade(); vec4 top = v0 + vec4(n[0],0,0) * radius * 1.618 * 2; float tTop = length(top.xyz-v0.xyz)/length(v1.xyz-v0.xyz); float fTop = mix(fade[0], fade[1], tTop); float vTop = mix(gValue[1], gValue[2], tTop); gl_Position = v0 - o[0]*s; fValue = gValue[1]; fFade = fade[0]; t = -1; EmitVertex(); gl_Position = v1 - o[1]; fFade = fade[1]; fValue = gValue[2]; t = -1; EmitVertex(); gl_Position = v0 - o[0]; fValue = gValue[1]; fFade = fade[0]; t = 1; EmitVertex(); EndPrimitive(); gl_Position = v0 + o[0]*s; fValue = gValue[1]; fFade = fade[0]; t = -1; EmitVertex(); gl_Position = v0 + o[0]; fValue = gValue[1]; fFade = fade[0]; t = 1; EmitVertex(); gl_Position = v1 + o[1]; fFade = fade[1]; fValue = gValue[2]; t = -1; EmitVertex(); EndPrimitive(); } ================================================ FILE: share/shaders/FlowGlyphsLineDirArrow2D.vert ================================================ #version 330 core layout (location = 0) in vec3 vPos; layout (location = 1) in float vValue; out float gValue; uniform mat4 P; uniform mat4 MV; uniform vec4 clippingPlanes[6]; // out float gl_ClipDistance[6]; out float clip; void main() { gValue = vValue; gl_Position = P * MV * vec4(vPos, 1.0f); clip = 0; for (int i = 0; i < 6; i++) clip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0; } ================================================ FILE: share/shaders/FlowGlyphsSphere2D.frag ================================================ // Basic fragment shader. Maps the fValue onto a color using the LUT. #version 330 core uniform bool constantColorEnabled = false; uniform vec3 constantColor = vec3(1.0f); uniform float radius = 0.05f; uniform float border = 0.f; uniform vec3 borderColor = vec3(1.0f); uniform bool antiAlias = false; uniform sampler1D LUT; uniform vec2 mapRange; in float fValue; in float t; out vec4 fragment; void main() { if (constantColorEnabled) fragment = vec4(constantColor, 1.0f); else { vec4 c = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x)); if (antiAlias) { float S = 12; S *= (radius + border) / 0.1; c.rgb = mix(c.rgb, borderColor, clamp((abs(t)-radius/(radius+border))*S, 0.f, 1.f)); c.a *= min(((1-abs(t))*S), 1); } else { if (abs(t) > radius/(radius+border)) c = vec4(borderColor, 1.f); } fragment = c; if (c.a < 0.05) discard; } } ================================================ FILE: share/shaders/FlowGlyphsSphere2D.geom ================================================ // This behaves the same as FlowGlyphsArrow2D.geom except it draws a circle. #version 330 core #include FlowInclude.geom #define REFINEMENT 16 layout (lines_adjacency) in; layout (triangle_strip, max_vertices = 34) out; in float gValue[]; in float clip[]; out float fValue; out float t; uniform float radius = 0.05f; uniform int glyphStride = 1; uniform bool showOnlyLeadingSample = false; uniform float border = 0.f; uniform float aspect; void main() { if (showOnlyLeadingSample) { if (gl_PrimitiveIDIn < nVertices-4) return; } else { if (gl_PrimitiveIDIn % glyphStride != 0) return; } if (clip[1] < 0.0 || clip[2] < 0.0) return; fValue = gValue[1]; vec4 o = gl_in[1].gl_Position; for (int i = 0; i < REFINEMENT+1; i++) { float theta = float(i)/float(REFINEMENT) * 2.f * PI; vec4 d = vec4(cos(theta), sin(theta), 0.0, 0.0); d.x /= aspect; t = 0; gl_Position = o; EmitVertex(); t = 1; gl_Position = o+d*radius*2; EmitVertex(); } EndPrimitive(); } ================================================ FILE: share/shaders/FlowGlyphsSphere2D.vert ================================================ #version 330 core layout (location = 0) in vec3 vPos; layout (location = 1) in float vValue; out float gValue; uniform mat4 P; uniform mat4 MV; uniform vec4 clippingPlanes[6]; // out float gl_ClipDistance[6]; out float clip; void main() { gValue = vValue; gl_Position = P * MV * vec4(vPos, 1.0f); clip = 0; for (int i = 0; i < 6; i++) clip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0; } ================================================ FILE: share/shaders/FlowGlyphsSphereSplat.frag ================================================ // Maps the fValue onto a color using the LUT then applies Phong lighting. // Using the texture coordinates of the billboard it caclulates the bounds and normals of a sphere // which is then used for the lighting calculation. #version 330 core #define PI (3.1415926) uniform bool constantColorEnabled = false; uniform vec3 constantColor = vec3(1.0f); uniform vec3 lightDir = vec3(0, 0, -1); uniform bool lightingEnabled = true; uniform sampler1D LUT; uniform vec2 mapRange; uniform vec3 scales; in float fValue; in vec2 fC; out vec4 fragment; uniform float phongAmbient; uniform float phongDiffuse; uniform float phongSpecular; uniform float phongShininess; float PhongLighting(float theta) { if (!lightingEnabled) return 1.0; float ct = cos(theta); float diffuse = ct * phongDiffuse; float specular = phongSpecular * pow(ct, phongShininess); return max(phongAmbient + diffuse + specular, phongAmbient); } void main() { vec4 color; if (constantColorEnabled) color = vec4(constantColor, 1.0f); else color = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x)); float a = length(fC); // Length of a right angle triangle with a hypontenuse going from the origin to the sphere surface. float t = acos(a); // Angle of triangle float t2 = PI/2.0 - t; // Reflected angle if (a > 1) discard; color.rgb *= PhongLighting(t2); fragment = color; if (color.a < 0.05) discard; } ================================================ FILE: share/shaders/FlowGlyphsSphereSplat.geom ================================================ // This generates a billboard with a width and height equal to the diameter the sphere #version 330 core #include FlowInclude.geom #define REFINEMENT 10 layout (lines_adjacency) in; layout (triangle_strip, max_vertices = 4) out; in float gValue[]; in float clip[]; out float fValue; out vec2 fC; uniform mat4 P; uniform mat4 MV; uniform vec3 cameraPos; uniform vec3 scales; uniform float radius = 0.05; uniform int glyphStride = 1; uniform bool showOnlyLeadingSample = false; void EmitWorld(const vec3 v); void CylinderVert(const vec3 v, const vec3 d, const float value); void Face(const vec3 a, const vec3 b, const vec3 c); void SubDiv(const vec3 a, const vec3 b, const vec3 c); void main() { if (showOnlyLeadingSample) { if (gl_PrimitiveIDIn < nVertices-4) return; } else { if (gl_PrimitiveIDIn % glyphStride != 0) return; } // Need to manually clip if using geometry shader. if (clip[1] < 0.0 || clip[2] < 0.0) return; fValue = gValue[1]; vec3 o = gl_in[1].gl_Position.xyz; // Plane perpendicular to camera normal vec3 up = vec3(0.0, 0.0, 1.0); vec3 toCamera = normalize(cameraPos - o); vec3 xh = normalize(cross(up, toCamera)); vec3 yh = normalize(cross(toCamera, xh)); xh /= scales; yh /= scales; // Billboard fC = vec2(-1.0, -1.0); EmitWorld(o + radius * (-xh + -yh)); fC = vec2( 1.0, -1.0); EmitWorld(o + radius * ( xh + -yh)); fC = vec2(-1.0, 1.0); EmitWorld(o + radius * (-xh + yh)); fC = vec2( 1.0, 1.0); EmitWorld(o + radius * ( xh + yh)); } void EmitWorld(const vec3 v) { gl_Position = P * MV * vec4(v, 1.0f); EmitVertex(); } ================================================ FILE: share/shaders/FlowGlyphsSphereSplat.vert ================================================ #version 330 core layout (location = 0) in vec3 vPos; layout (location = 1) in float vValue; out float gValue; uniform vec4 clippingPlanes[6]; // out float gl_ClipDistance[6]; out float clip; void main() { gValue = vValue; gl_Position = vec4(vPos, 1.0f); clip = 0; for (int i = 0; i < 6; i++) clip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0; } ================================================ FILE: share/shaders/FlowGlyphsTubeDirArrow.frag ================================================ // Basic fragment shader. Maps the fValue onto a color using the LUT then applies Phong lighting. #version 330 core uniform bool constantColorEnabled = false; uniform vec3 constantColor = vec3(1.0f); uniform vec3 lightDir = vec3(0, 0, -1); uniform bool lightingEnabled = true; uniform sampler1D LUT; uniform vec2 mapRange; uniform vec3 scales; in float fValue; in float fFade; in vec3 fNormal; out vec4 fragment; uniform float phongAmbient; uniform float phongDiffuse; uniform float phongSpecular; uniform float phongShininess; float PhongLighting(vec3 normal, vec3 viewDir) { if (!lightingEnabled) return 1.0; vec3 lightDir = viewDir; float diffuse = abs(dot(normal, -lightDir)) * phongDiffuse; float specularStrength = phongSpecular; vec3 reflectDir = reflect(lightDir, normal); float spec = pow(abs(dot(viewDir, reflectDir)), phongShininess); float specular = specularStrength * spec; return max(phongAmbient + diffuse + specular, phongAmbient); } void main() { vec4 color; if (constantColorEnabled) color = vec4(constantColor, 1.0f); else color = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x)); if (lightingEnabled) { vec3 normal; if (gl_FrontFacing) normal = -fNormal; else normal = fNormal; vec3 ld = normalize(lightDir * scales); // float diffuse = max(dot(normal, ld), 0.0); // color.rgb *= max(diffuse, 0.2f); color.rgb *= PhongLighting(normal, ld); } color.a *= fFade; if (fFade < 0.05) discard; fragment = color; if (color.a < 0.05) discard; } ================================================ FILE: share/shaders/FlowGlyphsTubeDirArrow.geom ================================================ // This behaves the same as FlowGlyphsArrow.geom except it clips the geometry against the tube. #version 330 core #include FlowInclude.geom #define REFINEMENT 7 layout (lines_adjacency) in; layout (triangle_strip, max_vertices = 32) out; // (7 * 2 + 2) * 2 in float gValue[]; in float clip[]; out float fValue; out float fFade; out vec3 fNormal; uniform mat4 P; uniform mat4 MV; uniform vec3 scales; uniform float radius = 0.05; uniform int glyphStride = 1; void EmitWorld(const vec3 v); void CylinderVert(const vec3 v, const vec3 d, const float value); void main() { if (gl_PrimitiveIDIn % glyphStride != 0) return; if (clip[1] < 0.0 || clip[2] < 0.0) return; vec3 V[4]; for (int i = 0; i < 4; i++) V[i] = gl_in[i].gl_Position.xyz; vec3 VN[3]; for (int i = 0; i < 3; i++) VN[i] = normalize(V[i+1] - V[i]); vec3 N[2]; vec3 up = vec3(0, 0, 1); bool parallelToUpChanged = false; for (int i = 0; i < 2; i++) { N[i] = normalize((VN[i] + VN[i+1])/2); if (1 - dot(N[i], up) < FLT_EPSILON) parallelToUpChanged = true; } if (parallelToUpChanged) up = vec3(1, 0, 0); vec3 XH[2]; vec3 YH[2]; for (int i = 0; i < 2; i++) { XH[i] = normalize(cross(N[i], up)); YH[i] = normalize(cross(XH[i], N[i])); } fValue = gValue[1]; vec3 top = V[1] + N[0] * radius * 1.618; float s = 1.7; vec2 fade = CalculateFade(); for (int i = 0; i < REFINEMENT + 1; i++) { float t = float(i)/float(REFINEMENT) * 2.f * PI; vec3 d; d = XH[0]*cos(t) + YH[0]*sin(t); vec3 bottom = V[1] + d * radius * s / scales; vec3 top = mix(V[1], V[2], 1.0/1.218) + d * radius / scales; // fNormal = normalize((d + N[0])/2.0f); fNormal = normalize(cross(top-bottom, cross(d, N[0]))); fFade = fade[0]; EmitWorld(bottom); fFade = mix(fade[0], fade[1], 1.0/1.218); EmitWorld(top); } EndPrimitive(); fNormal = -N[0]; fFade = fade[0]; // Bottom for (int i = 0; i < REFINEMENT + 1; i++) { float t = float(i)/float(REFINEMENT) * 2.f * PI; vec3 d; d = XH[0]*cos(t) + YH[0]*sin(t); EmitWorld(V[1]); EmitWorld(V[1] + d * radius * s / scales); } EndPrimitive(); } void EmitWorld(const vec3 v) { gl_Position = P * MV * vec4(v, 1.0f); EmitVertex(); } void CylinderVert(const vec3 v, const vec3 d, const float value) { fNormal = d; EmitWorld(v + d * radius); } ================================================ FILE: share/shaders/FlowGlyphsTubeDirArrow.vert ================================================ #version 330 core layout (location = 0) in vec3 vPos; layout (location = 1) in float vValue; out float gValue; uniform vec4 clippingPlanes[6]; // out float gl_ClipDistance[6]; out float clip; void main() { gValue = vValue; gl_Position = vec4(vPos, 1.0f); clip = 0; for (int i = 0; i < 6; i++) clip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0; } ================================================ FILE: share/shaders/FlowInclude.geom ================================================ #define FLT_EPSILON 1.19e-07 #define PI float(3.1415926535897932384626433832795) uniform int nVertices = 4; uniform bool fade_tails = false; uniform int fade_start; uniform int fade_length; uniform int fade_stop; vec2 CalculateFade() { if (!fade_tails) return vec2(1.0); int i = (nVertices -4) - gl_PrimitiveIDIn; i -= fade_stop; if (i > 0) return vec2( 1.0 - clamp(((i+1) - fade_start) / float(fade_length), 0.0, 1.0), 1.0 - clamp(( i - fade_start) / float(fade_length), 0.0, 1.0) ); else return vec2(0); } ================================================ FILE: share/shaders/FlowLine.frag ================================================ #version 410 core layout(location = 0) out vec4 color; in float scalarV; in vec3 vertModel; uniform sampler1D colorMapTexture; uniform vec3 colorMapRange; uniform bool singleColor; void main(void) { if( singleColor ) { color = texelFetch( colorMapTexture, 0, 0 ); } else { float valTranslate = (scalarV - colorMapRange.x) / colorMapRange.z; color = texture( colorMapTexture, valTranslate ); if (color.a < 0.05) discard; } } ================================================ FILE: share/shaders/FlowLine.vert ================================================ #version 410 core // Input vertex position (.xyz) and colormap value (.w) layout(location = 0) in vec4 vertInfo; uniform mat4 MV; uniform mat4 Projection; uniform vec4 clippingPlanes[6]; out float gl_ClipDistance[6]; out float scalarV; out vec3 vertModel; void main(void) { gl_Position = Projection * MV * vec4( vertInfo.xyz, 1.0 ); scalarV = vertInfo.w; vertModel = vertInfo.xyz; for (int i = 0; i < 6; i++) gl_ClipDistance[i] = dot(vec4(vertModel, 1.0), clippingPlanes[i]); } ================================================ FILE: share/shaders/FlowLines.frag ================================================ // Basic fragment shader. Maps the fValue onto a color using the LUT. // This shader also supports anti-aliasing and adding a border to the lines // but these features are not currently in use. #version 330 core uniform bool constantColorEnabled = false; uniform vec3 constantColor = vec3(1.0f); uniform float radius = 0.05f; uniform float border = 0.f; uniform vec3 borderColor = vec3(1.0f); uniform bool antiAlias = false; uniform float falloff = 1.0f; uniform float tone = 1.0f; uniform bool density = false; uniform sampler1D LUT; uniform vec2 mapRange; in float fValue; in float fFade; in float t; out vec4 fragment; void main() { vec4 color; if (constantColorEnabled) color = vec4(constantColor, 1.0f); else { vec4 c = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x)); if (antiAlias) { float S = 12; S *= (radius + border) / 0.1; c.rgb = mix(c.rgb, borderColor, clamp((abs(t)-radius/(radius+border))*S, 0.f, 1.f)); c.a *= min(((1-abs(t))*S), 1); } else { if (abs(t) > radius/(radius+border)) c = vec4(borderColor, 1.f); } color = c; } if (density) { color.rgb *= vec3(pow(1-abs(t), falloff)); // Not exactly correct but will do for now color.rgb = 1-exp(-tone * color.rgb); } color.a *= fFade; if (fFade < 0.05) discard; fragment = color; if (color.a < 0.05) discard; } ================================================ FILE: share/shaders/FlowLines.geom ================================================ // Generates a line represented by quades from a set of points #version 330 core #include FlowInclude.geom layout (lines_adjacency) in; layout (triangle_strip, max_vertices = 4) out; in float gValue[]; in float clip[]; out float fValue; out float fFade; out float t; uniform float radius = 0.05f; uniform float border = 0.f; uniform float aspect; void main() { // Need to manually clip when using geometry shader. if (clip[1] < 0.0 || clip[2] < 0.0) return; vec2 vS[4]; // Screen space for (int i = 0; i < 4; i++) vS[i] = gl_in[i].gl_Position.xy / gl_in[i].gl_Position.w; vec2 vN[3]; for (int i = 0; i < 3; i++) vN[i] = normalize(vS[i+1] - vS[i]); vec2 n[2]; vec2 p[2]; vec4 o[2]; for (int i = 0; i < 2; i++) { n[i] = normalize((vN[i] + vN[i+1])/2); p[i] = vec2(-n[i].y, n[i].x); p[i].x /= aspect; o[i] = vec4(p[i], 0.0f, 0.0f) * (radius*2 + border); } vec2 fade = CalculateFade(); #define v0 gl_in[1].gl_Position #define v1 gl_in[2].gl_Position gl_Position = v0 - o[0]; fValue = gValue[1]; fFade = fade[0]; t = -1; EmitVertex(); gl_Position = v1 - o[1]; fValue = gValue[2]; fFade = fade[1]; t = -1; EmitVertex(); gl_Position = v0 + o[0]; fValue = gValue[1]; fFade = fade[0]; t = 1; EmitVertex(); gl_Position = v1 + o[1]; fValue = gValue[2]; fFade = fade[1]; t = 1; EmitVertex(); EndPrimitive(); } ================================================ FILE: share/shaders/FlowLines.vert ================================================ #version 330 core layout (location = 0) in vec3 vPos; layout (location = 1) in float vValue; out float gValue; uniform mat4 P; uniform mat4 MV; uniform vec4 clippingPlanes[6]; // out float gl_ClipDistance[6]; out float clip; void main() { gValue = vValue; gl_Position = P * MV * vec4(vPos, 1.0f); clip = 0; for (int i = 0; i < 6; i++) clip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0; } ================================================ FILE: share/shaders/FlowTubes.frag ================================================ // Basic fragment shader. Maps the fValue onto a color using the LUT then applies Phong lighting. #version 330 core uniform bool constantColorEnabled = false; uniform vec3 constantColor = vec3(1.0f); uniform vec3 lightDir = vec3(0, 0, -1); uniform bool lightingEnabled = true; uniform sampler1D LUT; uniform vec2 mapRange; uniform vec3 scales; in float fValue; in float fFade; in vec3 fNormal; out vec4 fragment; uniform float phongAmbient; uniform float phongDiffuse; uniform float phongSpecular; uniform float phongShininess; float PhongLighting(vec3 normal, vec3 viewDir) { if (!lightingEnabled) return 1.0; vec3 lightDir = viewDir; float diffuse = abs(dot(normal, -lightDir)) * phongDiffuse; float specularStrength = phongSpecular; vec3 reflectDir = reflect(lightDir, normal); float spec = pow(abs(dot(viewDir, reflectDir)), phongShininess); float specular = specularStrength * spec; return max(phongAmbient + diffuse + specular, phongAmbient); } void main() { vec4 color; if (constantColorEnabled) color = vec4(constantColor, 1.0f); else color = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x)); if (lightingEnabled) { vec3 normal; if (gl_FrontFacing) normal = -fNormal; else normal = fNormal; vec3 ld = normalize(lightDir * scales); // float diffuse = max(dot(normal, ld), 0.0); // color.rgb *= max(diffuse, 0.2f); color.rgb *= PhongLighting(normal, ld); } color.a *= fFade; if (fFade < 0.05) discard; fragment = color; if (color.a < 0.05) discard; } ================================================ FILE: share/shaders/FlowTubes.geom ================================================ // This shader generates tubes between every pair of vertices in a line. // The tube is generated as a triangle strip. This geometry is generated at the origin // and transformed with a simple affine tranformation using basis vectors. // // EmitWorld(vec3 v) projects v and emits it. // CylinderVert(v, ...) is a helper function that generates a point on a circle // given the parameters and passes it to EmitWorld. #version 330 core #include FlowInclude.geom #define REFINEMENT 7 layout (lines_adjacency) in; layout (triangle_strip, max_vertices = 16) out; // 7 * 2 + 2 in float gValue[]; in float clip[]; out float fValue; out float fFade; out vec3 fNormal; uniform mat4 P; uniform mat4 MV; uniform vec3 scales; uniform float radius = 0.05; void EmitWorld(const vec3 v); void CylinderVert(const vec3 v, const vec3 d, const float fade, const float value); void main() { if (clip[1] < 0.0 || clip[2] < 0.0) return; vec3 V[4]; for (int i = 0; i < 4; i++) V[i] = gl_in[i].gl_Position.xyz; vec3 VN[3]; for (int i = 0; i < 3; i++) VN[i] = normalize(V[i+1] - V[i]); vec3 N[2]; vec3 up = vec3(0, 0, 1); bool parallelToUpChanged = false; for (int i = 0; i < 2; i++) { N[i] = normalize((VN[i] + VN[i+1])/2); if (1 - dot(N[i], up) < FLT_EPSILON) parallelToUpChanged = true; } if (parallelToUpChanged) up = vec3(1, 0, 0); vec3 XH[2]; vec3 YH[2]; for (int i = 0; i < 2; i++) { XH[i] = normalize(cross(N[i], up)); YH[i] = normalize(cross(XH[i], N[i])); } vec2 fade = CalculateFade(); for (int i = 0; i < REFINEMENT + 1; i++) { float t = float(i)/float(REFINEMENT) * 2.f * PI; vec3 D[2]; for (int j = 0; j < 2; j++) D[j] = XH[j]*cos(t) + YH[j]*sin(t); CylinderVert(V[1], D[0], fade[0], gValue[1]); CylinderVert(V[2], D[1], fade[1], gValue[2]); } EndPrimitive(); } void EmitWorld(const vec3 v) { gl_Position = P * MV * vec4(v, 1.0f); EmitVertex(); } void CylinderVert(const vec3 v, const vec3 d, const float fade, const float value) { fNormal = d; fValue = value; fFade = fade; vec3 offset = d*radius; offset /= scales; EmitWorld(v + offset); } ================================================ FILE: share/shaders/FlowTubes.vert ================================================ #version 330 core layout (location = 0) in vec3 vPos; layout (location = 1) in float vValue; out float gValue; uniform vec4 clippingPlanes[6]; // out float gl_ClipDistance[6]; out float clip; void main() { gValue = vValue; gl_Position = vec4(vPos, 1.0f); clip = 0; for (int i = 0; i < 6; i++) clip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0; } ================================================ FILE: share/shaders/Framebuffer.frag ================================================ #version 330 core uniform sampler2D colorBuffer; uniform sampler2D depthBuffer; in vec2 ST; out vec4 fragColor; void main(void) { fragColor = texture(colorBuffer, ST); gl_FragDepth = texture(depthBuffer, ST).r; } ================================================ FILE: share/shaders/Framebuffer.vert ================================================ #version 330 core layout (location = 0) in vec2 vertex; layout (location = 1) in vec2 vTextureCoord; out vec2 ST; void main() { gl_Position = vec4(vertex, 0.0, 1.0); ST = vTextureCoord; } ================================================ FILE: share/shaders/FramebufferND.frag ================================================ #version 330 core // Draw framebuffer while translating OSPRay depth buffer to OpenGL depth buffer. uniform mat4 MVP; uniform vec3 camPos; uniform vec3 camDir; uniform sampler2D colorBuffer; uniform sampler2D depthBuffer; in vec2 ST; out vec4 fragColor; float CalculateDepth(float d) { vec4 ndc = MVP * vec4(camPos + camDir*d, 1); ndc.xyz /= ndc.w; return 0.5 * (gl_DepthRange.diff * ndc.z + (gl_DepthRange.near + gl_DepthRange.far)); } void main(void) { fragColor = texture(colorBuffer, ST); gl_FragDepth = CalculateDepth(texture(depthBuffer, ST).r); } ================================================ FILE: share/shaders/FramebufferND.vert ================================================ #version 330 core layout (location = 0) in vec2 vertex; layout (location = 1) in vec2 vTextureCoord; out vec2 ST; void main() { gl_Position = vec4(vertex, 0.0, 1.0); ST = vTextureCoord; } ================================================ FILE: share/shaders/GenerateBBTraversals.pl ================================================ ######################################################### # Notes # ######################################################### # # This code generates functions with the same signature and functionality as # SearchSideForInitialCell but using the BB traversal # The functions will be called SearchSideForInitialCellWithOctree_{1-8}Levels # # Below there is a parametric non-recursive function but it is very slow in GLSL # # ######################################################### # Example 2 Level Traversal # ######################################################### # # bool SearchSideForInitialCellWithOctree_2Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, OUT float t1) # { # ivec3 side = GetFaceFromFaceIndex(sideID); # ivec3 index = (side+1)/2 * (cellDims-1); # # ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); # ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); # # for (int y1 = 0; y1 < lDims1.y; y1++) { # for (int x1 = 0; x1 < lDims1.x; x1++) { # if (IntersectRaySideCellBBoxDirect(origin, dir, x1, y1, sideID, 1)) { # int y0End = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; # int x0End = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; # # for (int y0 = y1*2; y0 < y0End; y0++) { # for (int x0 = x1*2; x0 < lDims0.x; x0++) { # if (IntersectRaySideCellBBoxDirect(origin, dir, x0, y0, sideID, 0)) { # index[slowDim] = y0; # index[fastDim] = x0; # if (IntersectRayCellFace(origin, dir, index, side, t1)) { # if (IsRayEnteringCell(dir, index, side)) { # cellIndex = index; # entranceFace = side; # return true; # } # } # # } # } # } # } # } # } # return false; # } # ######################################################### # Non-Recursive Traversal # ######################################################### # # bool SearchSideForInitialCellWithOctreeParametric(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, OUT float t1) # { # ivec3 side = GetFaceFromFaceIndex(sideID); # ivec3 index = (side+1)/2 * (cellDims-1); # # #define MAX_LEVELS 8 # int x[MAX_LEVELS]; # int y[MAX_LEVELS]; # int xEnd[MAX_LEVELS]; # int yEnd[MAX_LEVELS]; # ivec2 dims[MAX_LEVELS]; # # for (int i = 0; i < BBLevels; i++) # dims[i] = GetBBoxArrayDimensions(sideID, i); # # # int L = min(BBLevels-1, MAX_LEVELS-1); # int dL = 0; # # xEnd[L] = dims[L].x; # yEnd[L] = dims[L].y; # # while (true) { # for (y[L] = 0; y[L] < yEnd[L] && dL==0; y[L]++) { # for (x[L] = 0; x[L] < xEnd[L] && dL==0; x[L]++) { # if (IntersectRaySideCellBBoxDirect(origin, dir, x[L], y[L], sideID, L)) { # if (L == 0) { # index[slowDim] = y[L]; # index[fastDim] = x[L]; # if (IntersectRayCellFace(origin, dir, index, side, t1)) { # if (IsRayEnteringCell(dir, index, side)) { # cellIndex = index; # entranceFace = side; # return true; # } # } # } else { # dL = -1; # xEnd[L-1] = x[L] == dims[L].x-1 ? dims[L-1].x : (x[L]+1)*2; # yEnd[L-1] = y[L] == dims[L].y-1 ? dims[L-1].y : (y[L]+1)*2; # } # } # } # } # if (dL == -1) { # L--; # dL = 0; # } else { # break; # } # } # return false; # } # # # # # # # ######################################################### # Generate Code # ######################################################### sub IncrementSpacing { my ($str, $n) = @_; my $tabs = "\t"x$n; $str =~ s/^/$tabs/mg; return $str; } sub Loop { my ($L) = @_; my $Lup = $L+1; my $ret =" for (int y$L = y$Lup*2; y$L < yEnd$L; y$L++) { for (int x$L = x$Lup*2; x$L < xEnd$L; x$L++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x$L, y$L, sideID, $L)) { "; if ($L > 0) { my $LN = $L-1; $ret .=" int yEnd$LN = y$L == lDims$L.y-1 ? lDims$LN.y : (y$L+1)*2; int xEnd$LN = x$L == lDims$L.x-1 ? lDims$LN.x : (x$L+1)*2;"; $ret .="\n"; $ret .= IncrementSpacing(Loop($LN), 1); } else { $ret .=" index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; "; } $ret .= " } } } "; return $ret; } sub Function { my ($levels) = @_; my $ret = "int SearchSideForInitialCellWithOctree_${levels}Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; "; for (my $i = 0; $i < $levels; $i++) { $ret .= " ivec2 lDims$i = GetBBoxArrayDimensions(sideID, $i);\n" } my $L = $levels-1; $ret .= " int yEnd$L = lDims$L.y; int xEnd$L = lDims$L.x; int x${levels} = 0; int y${levels} = 0; "; $ret .= IncrementSpacing(Loop($L), 1); $ret .= " return intersections; } \n"; return $ret; }; print "// ---------------------------------------------\n"; print "// This file is generated by $0\n"; print "// Any changes made to this file will be lost\n"; print "// ---------------------------------------------\n"; print "\n\n"; for (my $i = 1; $i <= 8; $i++) { print Function($i); } ================================================ FILE: share/shaders/GenerateBBTraversalsNvidia.pl ================================================ ######################################################### # Notes # ######################################################### # # This code generates functions with the same signature and functionality as # SearchSideForInitialCell but using the BB traversal # The functions will be called SearchSideForInitialCellWithOctree_{1-8}Levels # # Below there is a parametric non-recursive function but it is very slow in GLSL # # ######################################################### # Example 2 Level Traversal # ######################################################### # # bool SearchSideForInitialCellWithOctree_2Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, OUT float t1) # { # ivec3 side = GetFaceFromFaceIndex(sideID); # ivec3 index = (side+1)/2 * (cellDims-1); # # ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1); # ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0); # # for (int y1 = 0; y1 < lDims1.y; y1++) { # for (int x1 = 0; x1 < lDims1.x; x1++) { # if (IntersectRaySideCellBBoxDirect(origin, dir, x1, y1, sideID, 1)) { # int y0End = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2; # int x0End = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2; # # for (int y0 = y1*2; y0 < y0End; y0++) { # for (int x0 = x1*2; x0 < lDims0.x; x0++) { # if (IntersectRaySideCellBBoxDirect(origin, dir, x0, y0, sideID, 0)) { # index[slowDim] = y0; # index[fastDim] = x0; # if (IntersectRayCellFace(origin, dir, index, side, t1)) { # if (IsRayEnteringCell(dir, index, side)) { # cellIndex = index; # entranceFace = side; # return true; # } # } # # } # } # } # } # } # } # return false; # } # ######################################################### # Non-Recursive Traversal # ######################################################### # # bool SearchSideForInitialCellWithOctreeParametric(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, OUT float t1) # { # ivec3 side = GetFaceFromFaceIndex(sideID); # ivec3 index = (side+1)/2 * (cellDims-1); # # #define MAX_LEVELS 8 # int x[MAX_LEVELS]; # int y[MAX_LEVELS]; # int xEnd[MAX_LEVELS]; # int yEnd[MAX_LEVELS]; # ivec2 dims[MAX_LEVELS]; # # for (int i = 0; i < BBLevels; i++) # dims[i] = GetBBoxArrayDimensions(sideID, i); # # # int L = min(BBLevels-1, MAX_LEVELS-1); # int dL = 0; # # xEnd[L] = dims[L].x; # yEnd[L] = dims[L].y; # # while (true) { # for (y[L] = 0; y[L] < yEnd[L] && dL==0; y[L]++) { # for (x[L] = 0; x[L] < xEnd[L] && dL==0; x[L]++) { # if (IntersectRaySideCellBBoxDirect(origin, dir, x[L], y[L], sideID, L)) { # if (L == 0) { # index[slowDim] = y[L]; # index[fastDim] = x[L]; # if (IntersectRayCellFace(origin, dir, index, side, t1)) { # if (IsRayEnteringCell(dir, index, side)) { # cellIndex = index; # entranceFace = side; # return true; # } # } # } else { # dL = -1; # xEnd[L-1] = x[L] == dims[L].x-1 ? dims[L-1].x : (x[L]+1)*2; # yEnd[L-1] = y[L] == dims[L].y-1 ? dims[L-1].y : (y[L]+1)*2; # } # } # } # } # if (dL == -1) { # L--; # dL = 0; # } else { # break; # } # } # return false; # } # # # # # # # ######################################################### # Generate Code # ######################################################### sub IncrementSpacing { my ($str, $n) = @_; my $tabs = "\t"x$n; $str =~ s/^/$tabs/mg; return $str; } sub Loop { my ($L) = @_; my $Lup = $L+1; my $ret =" // for (int y$L = y$Lup*2; y$L < yEnd$L; y$L++) { int y$L = y$Lup*2; for (int x$L = x$Lup*2; x$L < xEnd$L && y$L < yEnd$L; x$L++) { if (IntersectRaySideCellBBoxDirect(origin, dir, t0, x$L, y$L, sideID, $L)) { "; if ($L > 0) { my $LN = $L-1; $ret .=" int yEnd$LN = y$L == lDims$L.y-1 ? lDims$LN.y : (y$L+1)*2; int xEnd$LN = x$L == lDims$L.x-1 ? lDims$LN.x : (x$L+1)*2;"; $ret .="\n"; $ret .= IncrementSpacing(Loop($LN), 1); } else { $ret .=" index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) intersections++; "; } $ret .= " } if (x$L == xEnd$L-1) { x$L = x$Lup*2-1; y$L++; } } "; return $ret; } sub Function { my ($levels) = @_; my $ret = "int SearchSideForInitialCellWithOctree_${levels}Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); int intersections = 0; "; for (my $i = 0; $i < $levels; $i++) { $ret .= " ivec2 lDims$i = GetBBoxArrayDimensions(sideID, $i);\n" } my $L = $levels-1; $ret .= " int yEnd$L = lDims$L.y; int xEnd$L = lDims$L.x; int x${levels} = 0; int y${levels} = 0; "; $ret .= IncrementSpacing(Loop($L), 1); $ret .= " return intersections; } \n"; return $ret; }; print "// ---------------------------------------------\n"; print "// This file is generated by $0\n"; print "// Any changes made to this file will be lost\n"; print "// ---------------------------------------------\n"; print "\n\n"; for (my $i = 1; $i <= 8; $i++) { print Function($i); } ================================================ FILE: share/shaders/GenerateUniversalBBTraversal.pl ================================================ ######################################################### # Notes # ######################################################### # # This code generates a single function that supports N # levels with an unrolled loop. We need to support up to # 12 levels for a 4096 grid and. It turns out, up to 9 # levels, it performs 10% slower than a function that only # supports N levels but I found that if you generate a # function that supports 12 levels, if you render a 9 level # grid, it performs 120% slower. # # This code is only here because I don't feel like deleting # it right now. # # Please refer to GenerateBBTraversals.pl # ######################################################### # Generate Code # ######################################################### sub IncrementSpacing { my ($str, $n) = @_; my $tabs = "\t"x$n; $str =~ s/^/$tabs/mg; return $str; } sub Loop { my ($L) = @_; my $Lup = $L+1; my $ret =" for (int y$L = y$Lup*2; y$L < yEnd$L; y$L++) { for (int x$L = x$Lup*2; x$L < xEnd$L; x$L++) { if (IntersectRaySideCellBBoxDirect(origin, dir, x$L, y$L, sideID, $L) || BBLevels <= $L) { "; if ($L > 0) { my $LN = $L-1; $ret .=" int yEnd$LN = y$L == lDims$L.y-1 ? lDims$LN.y : (y$L+1)*2; int xEnd$LN = x$L == lDims$L.x-1 ? lDims$LN.x : (x$L+1)*2;"; $ret .="\n"; $ret .= IncrementSpacing(Loop($LN), 1); } else { $ret .=" index[slowDim] = y0; index[fastDim] = x0; if (IsFaceThatPassedBBTheInitialCell(origin, dir, index, side, cellIndex, entranceFace, t1)) return true; "; } $ret .= " } } } "; return $ret; } sub Function { my ($levels) = @_; my $ret = "bool SearchSideForInitialCellWithOctree(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, OUT float t1) { ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); "; $ret .= " ivec2 lDims0"; for (my $i = 1; $i < $levels; $i++) { $ret .= ", lDims$i"; } $ret .= ";\n\n"; $ret .= " lDims0 = GetBBoxArrayDimensions(sideID, 0);\n"; for (my $i = 1; $i < $levels; $i++) { $ret .= " if (BBLevels > $i) lDims$i = GetBBoxArrayDimensions(sideID, $i); else lDims$i = ivec2(1);\n"; } my $L = $levels-1; $ret .= " int yEnd$L = lDims$L.y; int xEnd$L = lDims$L.x; int x${levels} = 0; int y${levels} = 0; "; $ret .= IncrementSpacing(Loop($L), 1); $ret .= " return false; } \n"; return $ret; }; print Function(12); ================================================ FILE: share/shaders/Image.frag ================================================ #version 330 core uniform sampler2D sampler; uniform float constantOpacity; in vec2 TextureCoord; out vec4 fragColor; void main(void) { vec4 color = texture(sampler, TextureCoord); // Legacy vapor behavior if (color.a <= 0.1) discard; fragColor = vec4(color.rgb, color.a * constantOpacity); } ================================================ FILE: share/shaders/Image.vert ================================================ #version 330 core uniform mat4 MVP; layout (location = 0) in vec3 vertex; layout (location = 1) in vec2 vTextureCoord; out vec2 TextureCoord; uniform vec4 clippingPlanes[6]; out float gl_ClipDistance[6]; void main() { gl_Position = MVP * vec4(vertex, 1.0); TextureCoord = vTextureCoord; for (int i = 0; i < 6; i++) gl_ClipDistance[i] = dot(vec4(vertex, 1.0), clippingPlanes[i]); } ================================================ FILE: share/shaders/Legacy.frag ================================================ #version 330 core uniform bool lightingEnabled; uniform bool textureEnabled; uniform vec3 lightDir; uniform sampler2D sampler; in vec4 fColor; in vec3 fNormal; in vec2 fTextureCoords; out vec4 fragment; void main() { vec4 color = fColor; if (textureEnabled) { color *= texture(sampler, fTextureCoords); } if (lightingEnabled) { vec3 normal; if (gl_FrontFacing) normal = fNormal; else normal = -fNormal; float diffuse = max(dot(normal, -lightDir), 0.0); color.rgb *= max(diffuse, 0.2f); } fragment = color; } ================================================ FILE: share/shaders/Legacy.vert ================================================ #version 330 core layout (location = 0) in vec3 vPos; layout (location = 1) in vec3 vNormal; layout (location = 2) in vec4 vColor; layout (location = 3) in vec2 vTextureCoords; out vec3 fNormal; out vec4 fColor; out vec2 fTextureCoords; uniform mat4 P; uniform mat4 MV; void main() { gl_Position = P * MV * vec4(vPos, 1.0f); // fNormal = mat3(transpose(inverse(MV))) * vNormal; fNormal = vNormal; fColor = vColor; fTextureCoords = vTextureCoords; } ================================================ FILE: share/shaders/ParticleDirection.frag ================================================ // Basic fragment shader. Maps the fValue onto a color using the LUT then applies Phong lighting. #version 330 core uniform bool constantColorEnabled = false; uniform vec3 constantColor = vec3(1.0f); uniform vec3 lightDir = vec3(0, 0, -1); uniform bool lightingEnabled = true; uniform sampler1D LUT; uniform vec2 mapRange; uniform vec3 scales; in float fValue; in vec3 fNormal; out vec4 fragment; uniform float phongAmbient; uniform float phongDiffuse; uniform float phongSpecular; uniform float phongShininess; float PhongLighting(vec3 normal, vec3 viewDir) { if (!lightingEnabled) return 1.0; vec3 lightDir = viewDir; float diffuse = abs(dot(normal, -lightDir)) * phongDiffuse; float specularStrength = phongSpecular; vec3 reflectDir = reflect(lightDir, normal); float spec = pow(abs(dot(viewDir, reflectDir)), phongShininess); float specular = specularStrength * spec; return max(phongAmbient + diffuse + specular, phongAmbient); } void main() { // fragment = vec4(1,0,1,1); //fragment = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x)); //return; vec4 color; if (constantColorEnabled) color = vec4(constantColor, 1.0f); else color = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x)); if (lightingEnabled) { vec3 normal; if (gl_FrontFacing) normal = -fNormal; else normal = fNormal; vec3 ld = normalize(lightDir * scales); // float diffuse = max(dot(normal, ld), 0.0); // color.rgb *= max(diffuse, 0.2f); color.rgb *= PhongLighting(normal, ld); } fragment = color; if (color.a < 0.05) discard; } ================================================ FILE: share/shaders/ParticleDirection.geom ================================================ // This shader generates tubes between every pair of vertices in a line. // The tube is generated as a triangle strip. This geometry is generated at the origin // and transformed with a simple affine transformation using basis vectors. // // EmitWorld(vec3 v) projects v and emits it. // CylinderVert(v, ...) is a helper function that generates a point on a circle // given the parameters and passes it to EmitWorld. #version 330 core #include FlowInclude.geom #define REFINEMENT 7 layout (points) in; layout (triangle_strip, max_vertices = 16) out; // 7 * 2 + 2 //layout (line_strip, max_vertices = 64) out; // 7 * 2 + 2 //layout (points, max_vertices = 64) out; // 7 * 2 + 2 in vec3 gNorm[]; in float gValue[]; out float fValue; out vec3 fNormal; #ifdef DYNAMIC_RADIUS in float gRadius[]; #endif uniform mat4 P; uniform mat4 MV; uniform vec3 scales; uniform float radius = 0.05; uniform float dirScale = 0.05; void EmitWorld(const vec3 v); void CylinderVert(const vec3 v, const vec3 d, const float value, const float radius); void main() { //fValue = gValue[0]; //EmitWorld(gl_in[0].gl_Position.xyz); //EmitWorld(gl_in[0].gl_Position.xyz + gNorm[0] * dirScale); //EndPrimitive(); //return; vec3 V[2]; V[0] = gl_in[0].gl_Position.xyz; vec3 N = gNorm[0]; V[1] = V[0] + N * dirScale; vec3 up = vec3(0, 0, 1); bool parallelToUpChanged = false; if (1 - dot(N, up) < FLT_EPSILON) parallelToUpChanged = true; if (parallelToUpChanged) up = vec3(1, 0, 0); vec3 XH; vec3 YH; XH = normalize(cross(N, up)); YH = normalize(cross(XH, N)); #ifdef DYNAMIC_RADIUS float finalRadius = radius * gRadius[0]; #else float finalRadius = radius; #endif vec2 fade = CalculateFade(); //fNormal = vec3(1,0,0); fValue = 1; EmitWorld(gl_in[0].gl_Position.xyz); EmitWorld(gl_in[1].gl_Position.xyz); EndPrimitive(); return; for (int i = 0; i < REFINEMENT + 1; i++) { float t = float(i)/float(REFINEMENT) * 2.f * PI; vec3 D; D = XH*cos(t) + YH*sin(t); CylinderVert(V[0], D, gValue[0], finalRadius); CylinderVert(V[1], D, gValue[0], finalRadius); } EndPrimitive(); } void EmitWorld(const vec3 v) { gl_Position = P * MV * vec4(v, 1.0f); EmitVertex(); } void CylinderVert(const vec3 v, const vec3 d, const float value, const float radius) { fNormal = d; fValue = value; vec3 offset = d*radius; offset /= scales; EmitWorld(v + offset); } ================================================ FILE: share/shaders/ParticleDirection.vert ================================================ #version 330 core layout (location = 0) in vec3 vPos; layout (location = 1) in vec3 vNorm; layout (location = 2) in float vValue; out vec3 gNorm; out float gValue; #ifdef DYNAMIC_RADIUS layout (location = 3) in float vRadius; out float gRadius; #endif void main() { gValue = vValue; gNorm = vNorm; gl_Position = vec4(vPos, 1.0f); #ifdef DYNAMIC_RADIUS gRadius = vRadius; #endif } ================================================ FILE: share/shaders/ParticlePoint.frag ================================================ // Maps the fValue onto a color using the LUT then applies Phong lighting. // Using the texture coordinates of the billboard it caclulates the bounds and normals of a sphere // which is then used for the lighting calculation. #version 330 core #define PI (3.1415926) uniform bool constantColorEnabled = false; uniform vec3 constantColor = vec3(1.0f); uniform vec3 lightDir = vec3(0, 0, -1); uniform bool lightingEnabled = true; uniform sampler1D LUT; uniform vec2 mapRange; uniform vec3 scales; in float fValue; in vec2 fC; out vec4 fragment; uniform float phongAmbient; uniform float phongDiffuse; uniform float phongSpecular; uniform float phongShininess; float PhongLighting(float theta) { if (!lightingEnabled) return 1.0; float ct = cos(theta); float diffuse = ct * phongDiffuse; float specular = phongSpecular * pow(ct, phongShininess); return max(phongAmbient + diffuse + specular, phongAmbient); } void main() { vec4 color; if (constantColorEnabled) color = vec4(constantColor, 1.0f); else color = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x)); float a = length(fC); // Length of a right angle triangle with a hypontenuse going from the origin to the sphere surface. float t = acos(a); // Angle of triangle float t2 = PI/2.0 - t; // Reflected angle if (a > 1) discard; color.rgb *= PhongLighting(t2); fragment = color; if (color.a < 0.05) discard; } ================================================ FILE: share/shaders/ParticlePoint.geom ================================================ // This generates a billboard with a width and height equal to the diameter the sphere #version 330 core #define REFINEMENT 10 layout (points) in; layout (triangle_strip, max_vertices = 4) out; in float gValue[]; out float fValue; out vec2 fC; #ifdef DYNAMIC_RADIUS in float gRadius[]; #endif uniform mat4 P; uniform mat4 MV; uniform vec3 cameraPos; uniform vec3 scales; uniform float radius = 0.05; void EmitWorld(const vec3 v); void main() { fValue = gValue[0]; vec3 o = gl_in[0].gl_Position.xyz; // Plane perpendicular to camera normal vec3 up = vec3(0.0, 0.0, 1.0); vec3 toCamera = normalize(cameraPos - o); vec3 xh = normalize(cross(up, toCamera)); vec3 yh = normalize(cross(toCamera, xh)); xh /= scales; yh /= scales; #ifdef DYNAMIC_RADIUS float finalRadius = radius * gRadius[0]; #else float finalRadius = radius; #endif // Billboard fC = vec2(-1.0, -1.0); EmitWorld(o + finalRadius * (-xh + -yh)); fC = vec2( 1.0, -1.0); EmitWorld(o + finalRadius * ( xh + -yh)); fC = vec2(-1.0, 1.0); EmitWorld(o + finalRadius * (-xh + yh)); fC = vec2( 1.0, 1.0); EmitWorld(o + finalRadius * ( xh + yh)); EndPrimitive(); } void EmitWorld(const vec3 v) { gl_Position = P * MV * vec4(v, 1.0f); EmitVertex(); } ================================================ FILE: share/shaders/ParticlePoint.vert ================================================ #version 330 core layout (location = 0) in vec3 vPos; layout (location = 1) in float vValue; out float gValue; #ifdef DYNAMIC_RADIUS layout (location = 2) in float vRadius; out float gRadius; #endif void main() { gValue = vValue; gl_Position = vec4(vPos, 1.0f); #ifdef DYNAMIC_RADIUS gRadius = vRadius; #endif } ================================================ FILE: share/shaders/ProgTexture.efc ================================================ ProgTexture ProgTexture ProgTexture ================================================ FILE: share/shaders/Slice.frag ================================================ #version 330 core uniform sampler1D colormap; uniform sampler2D dataValues; uniform float minLUTValue; uniform float maxLUTValue; uniform float constantOpacity; in vec2 fTexCoord; out vec4 fragColor; void main(void) { if (minLUTValue > maxLUTValue) discard; float missing = texture(dataValues, fTexCoord).g; if (missing != 0.f) discard; float value = texture(dataValues, fTexCoord).r; //if (isnan(value)) discard; float normalized = (value - minLUTValue) / (maxLUTValue - minLUTValue); if (maxLUTValue == minLUTValue) normalized=0.; vec4 color = texture(colormap, normalized); fragColor = vec4(color.rgb, color.a*constantOpacity); if (color.a < 0.001) discard; } ================================================ FILE: share/shaders/Slice.vert ================================================ #version 330 core uniform mat4 MVP; layout (location = 0) in vec3 vVertex; layout (location = 1) in vec2 vTexCoord; out vec2 fTexCoord; uniform vec4 clippingPlanes[6]; out float gl_ClipDistance[6]; void main() { fTexCoord = vTexCoord; gl_Position = MVP * vec4(vVertex, 1.0); for (int i = 0; i < 6; i++) gl_ClipDistance[i] = dot(vec4(vVertex, 1.0), clippingPlanes[i]); } ================================================ FILE: share/shaders/VolumeBase.frag ================================================ in vec2 ST; out vec4 fragColor; uniform mat4 MVP; uniform vec3 cameraPos; uniform vec3 dataBoundsMin; uniform vec3 dataBoundsMax; uniform vec3 userExtsMin; uniform vec3 userExtsMax; uniform vec3 scales; uniform float density; uniform float LUTMin; uniform float LUTMax; uniform bool mapOrthoMode; uniform bool hasMissingData; uniform bool fast; uniform float samplingRateMultiplier; uniform bool lightingEnabled; uniform float phongAmbient; uniform float phongDiffuse; uniform float phongSpecular; uniform float phongShininess; uniform sampler3D data; uniform sampler1D LUT; uniform sampler2D sceneDepth; uniform sampler3D missingMask; uniform bool useColormapData; #ifdef USE_SECOND_DATA uniform bool hasMissingData2; uniform sampler3D data2; uniform sampler3D missingMask2; uniform sampler1D LUT2; uniform float LUTMin2; uniform float LUTMax2; #endif bool readDepthBuffer = true; #define ALPHA_BREAK 0.999 #define ALPHA_DISCARD 0.01 // This is *no longer* required for the Nvidia compiler to work with cell traversal #define OUT out #include VolumeRayMath.frag vec3 ROYGBV(float v, float minV, float maxV) { vec3 colors[6]; colors[0] = vec3(1.00, 0.00, 0.00); colors[1] = vec3(1.00, 0.60, 0.00); colors[2] = vec3(1.00, 1.00, 0.00); colors[3] = vec3(0.00, 1.00, 0.00); colors[4] = vec3(0.00, 0.00, 1.00); colors[5] = vec3(0.32, 0.00, 0.32); float ratio = 5.0 * clamp((v-minV)/(maxV-minV), 0, 1); int indexMin=int(floor(ratio)); int indexMax=min(int(indexMin)+1,5); vec3 c = mix(colors[indexMin], colors[indexMax], ratio-indexMin); return c; } vec3 ROYGBVE(float v, float from, float to) { if (v < from || v > to) return vec3(1); return ROYGBV(v, from, to); } float GetSamplingNoise() { // This helps compensate for a lower sampling rate // It replaces banding artifacts with less obtrusive noise return fract(sin(gl_FragCoord.x * 12.989 + gl_FragCoord.y * 78.233) * 43758.5453) * 0.1 + 1; } bool DoesSampleHaveMissingData(vec3 dataSTR) { return texture(missingMask, dataSTR).r > 0; } #ifdef USE_SECOND_DATA bool DoesSampleHaveMissingData2(vec3 dataSTR) { return texture(missingMask2, dataSTR).r > 0; } #endif bool ShouldRenderSample(const vec3 sampleSTR) { if (hasMissingData) if (DoesSampleHaveMissingData(sampleSTR)) return false; return true; } float GetDepthBuffer() { if (readDepthBuffer) { float depth = texture(sceneDepth, ST).r; return depth; } else { return 1.0; } } float GetDepthBufferNDC() { return GetDepthBuffer() * 2 - 1; } float PhongLighting(vec3 normal, vec3 viewDir) { if (!lightingEnabled) return 1.0; vec3 lightDir = viewDir; float diffuse = abs(dot(normal, -lightDir)) * phongDiffuse; float specularStrength = phongSpecular; vec3 reflectDir = reflect(lightDir, normal); float spec = pow(abs(dot(viewDir, reflectDir)), phongShininess); float specular = specularStrength * spec; return max(phongAmbient + diffuse + specular, phongAmbient); } vec3 GetNormal(vec3 p) { vec3 dims = vec3(textureSize(data, 0)); vec3 d = 1/dims * 0.5; vec3 s0, s1; s1.x = texture(data, p + d*vec3(1,0,0)).r; s1.y = texture(data, p + d*vec3(0,1,0)).r; s1.z = texture(data, p + d*vec3(0,0,1)).r; s0.x = texture(data, p - d*vec3(1,0,0)).r; s0.y = texture(data, p - d*vec3(0,1,0)).r; s0.z = texture(data, p - d*vec3(0,0,1)).r; // glsl::normalize does not handle 0 length vectors vec3 v = s1-s0; float l = length(v); if (l == 0) return vec3(0); return v/l; } vec4 GetColorForNormalizedCoord(vec3 sampleSTR) { float value = texture(data, sampleSTR).r; float valueNorm = (value - LUTMin) / (LUTMax - LUTMin); vec4 color = texture(LUT, valueNorm); #ifdef USE_SECOND_DATA if (useColormapData) { if (hasMissingData2) if (DoesSampleHaveMissingData2(sampleSTR)) return vec4(0); float value2 = texture(data2, sampleSTR).r; float value2Norm = (value2 - LUTMin2) / (LUTMax2 - LUTMin2); color.rgb = texture(LUT2, value2Norm).rgb; } #endif return color; } float CalculateDepth(vec3 pos) { vec4 ndc = MVP * vec4(pos, 1); ndc.xyz /= ndc.w; return 0.5 * (gl_DepthRange.diff * ndc.z + (gl_DepthRange.near + gl_DepthRange.far)); } vec4 PremultiplyAlpha(vec4 color) { return vec4(color.rgb * color.a, color.a); } // GL_ONE_MINUS_DST_ALPHA, GL_ONE void BlendToBack(inout vec4 accum, vec4 color) { accum = color * (1-accum.a) + accum * (1); } void GetRayParameters(out vec3 eye, out vec3 dir, out vec3 normal, OUT float maxT) { vec2 screen = ST*2-1; vec4 world = inverse(MVP) * vec4(screen, GetDepthBufferNDC(), 1); if (mapOrthoMode) { eye = vec3(world.xy, cameraPos.z); } else { world /= world.w; eye = cameraPos; } dir = normalize(world.xyz - eye); normal = normalize((world.xyz - eye) * scales); maxT = length(world.xyz - eye); } ================================================ FILE: share/shaders/VolumeCellBase.frag ================================================ #include VolumeBase.frag // This file implements the cell traversal and provides a framework // for rendering a curvilinear grid. // It defines a Traverse function which needs to be // overridden that does the rendering uniform ivec3 coordDims; uniform float unitDistance; uniform float unitOpacityScalar; uniform int BBLevels; vec3 coordDimsF = vec3(coordDims); ivec3 cellDims = coordDims - 1; uniform sampler3D coords; uniform sampler2DArray boxMins; uniform sampler2DArray boxMaxs; uniform isampler2D levelDims; // Temporary workaround // ivec3 skipCellWhenSearchingForInit = ivec3(-1); #define DEBUG 0 #define DEBUG_SHOW_CELL_INDEX 0 #define DEBUG_SHOW_GRID 0 #define DEBUG_SHOW_NORMALS 0 #if DEBUG vec3 dbg = vec3(-1); vec3 RED = vec3(1, 0, 0); vec3 GREEN = vec3(0, 1, 0); vec3 BLUE = vec3(0, 0, 1); vec3 BLACK = vec3(0, 0, 0); vec3 WHITE = vec3(1, 1, 1); vec3 PURPLE= vec3(1, 0, 1); int dbgPriority = 0; void SD(vec3 color, int priority) { if (priority >= dbgPriority) { dbg = color; dbgPriority = priority; } } #endif void DEBUG_SHOW() { #if DEBUG if (dbg != vec3(-1)) fragColor = vec4(dbg, 1); #endif } #define FI_LEFT 0 #define FI_RIGHT 1 #define FI_UP 2 #define FI_DOWN 3 #define FI_FRONT 4 #define FI_BACK 5 #define FI_NONE 99 #define F_LEFT ivec3(-1, 0, 0) #define F_RIGHT ivec3( 1, 0, 0) #define F_UP ivec3( 0, 0, 1) #define F_DOWN ivec3( 0, 0,-1) #define F_FRONT ivec3( 0,-1, 0) #define F_BACK ivec3( 0, 1, 0) #define F_NONE ivec3(-1,-1,-1) #define CI_LEFT 0 #define CI_RIGHT 1 #define CI_UP 2 #define CI_DOWN 3 #define CI_FRONT 4 #define CI_BACK 5 #define CI_LEFT_FRONT 6 #define CI_LEFT_BACK 7 #define CI_RIGHT_FRONT 8 #define CI_RIGHT_BACK 9 #define CI_UP_FRONT 10 #define CI_UP_BACK 11 #define CI_DOWN_FRONT 12 #define CI_DOWN_BACK 13 #define CI_UP_LEFT 14 #define CI_UP_RIGHT 15 #define CI_DOWN_LEFT 16 #define CI_DOWN_RIGHT 17 #define CI_UP_LEFT_FRONT 18 #define CI_UP_LEFT_BACK 19 #define CI_UP_RIGHT_FRONT 20 #define CI_UP_RIGHT_BACK 21 #define CI_DOWN_LEFT_FRONT 22 #define CI_DOWN_LEFT_BACK 23 #define CI_DOWN_RIGHT_FRONT 24 #define CI_DOWN_RIGHT_BACK 25 #define CI_NONE 99 #define C_LEFT ivec3(-1, 0, 0) #define C_RIGHT ivec3( 1, 0, 0) #define C_UP ivec3( 0, 0, 1) #define C_DOWN ivec3( 0, 0,-1) #define C_FRONT ivec3( 0,-1, 0) #define C_BACK ivec3( 0, 1, 0) #define C_LEFT_FRONT (C_LEFT+C_FRONT) #define C_LEFT_BACK (C_LEFT+C_BACK) #define C_RIGHT_FRONT (C_RIGHT+C_FRONT) #define C_RIGHT_BACK (C_RIGHT+C_BACK) #define C_UP_FRONT (C_UP+C_FRONT) #define C_UP_BACK (C_UP+C_BACK) #define C_DOWN_FRONT (C_DOWN+C_FRONT) #define C_DOWN_BACK (C_DOWN+C_BACK) #define C_UP_LEFT (C_UP+C_LEFT) #define C_UP_RIGHT (C_UP+C_RIGHT) #define C_DOWN_LEFT (C_DOWN+C_LEFT) #define C_DOWN_RIGHT (C_DOWN+C_RIGHT) #define C_UP_LEFT_FRONT (C_UP+C_LEFT+C_FRONT) #define C_UP_LEFT_BACK (C_UP+C_LEFT+C_BACK) #define C_UP_RIGHT_FRONT (C_UP+C_RIGHT+C_FRONT) #define C_UP_RIGHT_BACK (C_UP+C_RIGHT+C_BACK) #define C_DOWN_LEFT_FRONT (C_DOWN+C_LEFT+C_FRONT) #define C_DOWN_LEFT_BACK (C_DOWN+C_LEFT+C_BACK) #define C_DOWN_RIGHT_FRONT (C_DOWN+C_RIGHT+C_FRONT) #define C_DOWN_RIGHT_BACK (C_DOWN+C_RIGHT+C_BACK) #define C_NONE ivec3(-1,-1,-1) // face fast slow // DOWN 0 1 // UP 0 1 // LEFT 1 2 // RIGHT 1 2 // FRONT 0 2 // BACK 0 2 int GetFastDimForFaceIndex(int i) { if (i == FI_LEFT || i == FI_RIGHT) return 1; return 0; } int GetSlowDimForFaceIndex(int i) { if (i == FI_DOWN || i == FI_UP) return 1; return 2; } ivec3 GetFaceFromFaceIndex(int i) { if (i == 0) return F_LEFT; if (i == 1) return F_RIGHT; if (i == 2) return F_UP; if (i == 3) return F_DOWN; if (i == 4) return F_FRONT; if (i == 5) return F_BACK; } ivec3 GetNeighborFromNeighborCellIndex(const int i) { if (i == CI_LEFT) return C_LEFT; if (i == CI_RIGHT) return C_RIGHT; if (i == CI_UP) return C_UP; if (i == CI_DOWN) return C_DOWN; if (i == CI_FRONT) return C_FRONT; if (i == CI_BACK) return C_BACK; if (i == CI_LEFT_FRONT) return C_LEFT_FRONT; if (i == CI_LEFT_BACK) return C_LEFT_BACK; if (i == CI_RIGHT_FRONT) return C_RIGHT_FRONT; if (i == CI_RIGHT_BACK) return C_RIGHT_BACK; if (i == CI_UP_FRONT) return C_UP_FRONT; if (i == CI_UP_BACK) return C_UP_BACK; if (i == CI_DOWN_FRONT) return C_DOWN_FRONT; if (i == CI_DOWN_BACK) return C_DOWN_BACK; if (i == CI_UP_LEFT) return C_UP_LEFT; if (i == CI_UP_RIGHT) return C_UP_RIGHT; if (i == CI_DOWN_LEFT) return C_DOWN_LEFT; if (i == CI_DOWN_RIGHT) return C_DOWN_RIGHT; if (i == CI_UP_LEFT_FRONT) return C_UP_LEFT_FRONT; if (i == CI_UP_LEFT_BACK) return C_UP_LEFT_BACK; if (i == CI_UP_RIGHT_FRONT) return C_UP_RIGHT_FRONT; if (i == CI_UP_RIGHT_BACK) return C_UP_RIGHT_BACK; if (i == CI_DOWN_LEFT_FRONT) return C_DOWN_LEFT_FRONT; if (i == CI_DOWN_LEFT_BACK) return C_DOWN_LEFT_BACK; if (i == CI_DOWN_RIGHT_FRONT) return C_DOWN_RIGHT_FRONT; if (i == CI_DOWN_RIGHT_BACK) return C_DOWN_RIGHT_BACK; } int GetFaceIndexFromFace(ivec3 face) { if (face == F_LEFT) return FI_LEFT; if (face == F_RIGHT) return FI_RIGHT; if (face == F_UP) return FI_UP; if (face == F_DOWN) return FI_DOWN; if (face == F_FRONT) return FI_FRONT; if (face == F_BACK) return FI_BACK; } vec4 DEBUG_GetFaceColor(ivec3 face) { if (face == F_LEFT) return vec4(0,0,1,1); // Blue if (face == F_RIGHT) return vec4(0,1,0,1); // Green if (face == F_UP) return vec4(0,1,1,1); // Cyan if (face == F_DOWN) return vec4(1,0,0,1); // Red if (face == F_FRONT) return vec4(1,0,1,1); // Purple if (face == F_BACK) return vec4(1,1,0,1); // Yellow } void GetFaceCoordinateIndices(ivec3 cell, ivec3 face, OUT ivec3 i0, OUT ivec3 i1, OUT ivec3 i2, OUT ivec3 i3) { // CCW if (face == F_DOWN) { i0 = cell + ivec3(0, 0, 0); i1 = cell + ivec3(0, 1, 0); i2 = cell + ivec3(1, 1, 0); i3 = cell + ivec3(1, 0, 0); } else if (face == F_UP) { i0 = cell + ivec3(0, 0, 1); i1 = cell + ivec3(1, 0, 1); i2 = cell + ivec3(1, 1, 1); i3 = cell + ivec3(0, 1, 1); } else if (face == F_LEFT) { i0 = cell + ivec3(0, 0, 0); i1 = cell + ivec3(0, 0, 1); i2 = cell + ivec3(0, 1, 1); i3 = cell + ivec3(0, 1, 0); } else if (face == F_RIGHT) { i0 = cell + ivec3(1, 0, 0); i1 = cell + ivec3(1, 1, 0); i2 = cell + ivec3(1, 1, 1); i3 = cell + ivec3(1, 0, 1); } else if (face == F_FRONT) { i0 = cell + ivec3(0, 0, 0); i1 = cell + ivec3(1, 0, 0); i2 = cell + ivec3(1, 0, 1); i3 = cell + ivec3(0, 0, 1); } else if (face == F_BACK) { i0 = cell + ivec3(0, 1, 0); i1 = cell + ivec3(0, 1, 1); i2 = cell + ivec3(1, 1, 1); i3 = cell + ivec3(1, 1, 0); } } void GetFaceCoordsAndVertices(ivec3 cellIndex, ivec3 face, OUT ivec3 i0, OUT ivec3 i1, OUT ivec3 i2, OUT ivec3 i3, OUT vec3 v0, OUT vec3 v1, OUT vec3 v2, OUT vec3 v3) { GetFaceCoordinateIndices(cellIndex, face, i0, i1, i2, i3); v0 = texelFetch(coords, i0, 0).xyz; v1 = texelFetch(coords, i1, 0).xyz; v2 = texelFetch(coords, i2, 0).xyz; v3 = texelFetch(coords, i3, 0).xyz; } void GetFaceVertices(ivec3 cellIndex, ivec3 face, OUT vec3 v0, OUT vec3 v1, OUT vec3 v2, OUT vec3 v3) { ivec3 i0, i1, i2, i3; GetFaceCoordsAndVertices(cellIndex, face, i0, i1, i2, i3, v0, v1, v2, v3); } float GetDataCoordinateSpace(vec3 coordinates) { return texture(data, coordinates/coordDimsF).r; } float GetDataForCoordIndex(ivec3 coordIndex) { vec3 coord = vec3(coordIndex)+vec3(0.5); return texture(data, (coord)/(coordDims-1)).r; } float NormalizeData(float data) { return (data - LUTMin) / (LUTMax - LUTMin); } vec4 GetColorForNormalizedData(float normalizedData) { return texture(LUT, normalizedData); } vec4 GetAverageColorForCoordIndex(ivec3 coordIndex) { return GetColorForNormalizedData(NormalizeData(GetDataForCoordIndex(coordIndex))); } vec4 GetColorAtCoord(vec3 coord) { // return GetColorForNormalizedData(NormalizeData(GetDataCoordinateSpace(coord))); return GetColorForNormalizedCoord(coord/coordDimsF); } vec3 GetNormalAtCoord(vec3 coord) { return GetNormal(coord/coordDimsF); } bool DoesCellHaveMissingData(ivec3 cellCoord) { vec3 coord = vec3(cellCoord)+vec3(0.5); return DoesSampleHaveMissingData((coord)/(coordDims-1)); } bool IntersectRayCellFace(vec3 o, vec3 d, float rt0, ivec3 cellIndex, ivec3 face, OUT float t, OUT vec3 dataCoordinate) { ivec3 i0, i1, i2, i3; vec3 v0, v1, v2, v3; GetFaceCoordsAndVertices(cellIndex, face, i0, i1, i2, i3, v0, v1, v2, v3); vec4 weights; if (IntersectRayQuad(o, d, rt0, v0, v1, v2, v3, t, weights)) { dataCoordinate = (weights.x*i0 + weights.y*i1 + weights.z*i2 + weights.w*i3 + vec3(0.5)); return true; } return false; } vec3 GetTriangleNormal(vec3 v0, vec3 v1, vec3 v2) { return normalize(cross(v1-v0, v2-v0)); } vec3 GetCellFaceNormal(ivec3 cellIndex, ivec3 face) { vec3 v0, v1, v2, v3; GetFaceVertices(cellIndex, face, v0, v1, v2, v3); vec3 normal = (GetTriangleNormal(v0, v1, v2) + GetTriangleNormal(v0, v2, v3)) / 2.0f; #ifdef INVERT_GRID_COORD_SYS_HAND normal = -normal; #endif return normal; } bool FindCellExit(vec3 origin, vec3 dir, float t0, ivec3 currentCell, ivec3 entranceFace, bool allowThinCells, OUT ivec3 exitFace, OUT vec3 exitCoord, OUT float t1) { exitFace = F_NONE; for (int i = 0; i < 6; i++) { ivec3 testFace = GetFaceFromFaceIndex(i); if (testFace == entranceFace) continue; if (IntersectRayCellFace(origin, dir, t0, currentCell, testFace, t1, exitCoord)) { // There are cases where very thin cells will result in the same t if (t1 - t0 > EPSILON) { exitFace = testFace; return true; } else if (allowThinCells && (t1 - t0 >= 0)) { exitFace = testFace; } } } if (exitFace != F_NONE) return true; return false; } bool FindCellExit(vec3 origin, vec3 dir, float t0, ivec3 currentCell, ivec3 entranceFace, OUT ivec3 exitFace, OUT vec3 exitCoord, OUT float t1) { return FindCellExit(origin, dir, t0, currentCell, entranceFace, true, exitFace, exitCoord, t1); } bool IsCellInBounds(ivec3 cellIndex) { return !(any(lessThan(cellIndex, ivec3(0))) || any(greaterThanEqual(cellIndex, cellDims))); } bool SearchNeighboringCells(vec3 origin, vec3 dir, float t0, ivec3 currentCell, OUT ivec3 nextCell, OUT ivec3 exitFace, OUT vec3 exitCoord, OUT float t1) { for (int sideID = 0; sideID < 26; sideID++) { ivec3 side = GetNeighborFromNeighborCellIndex(sideID); ivec3 testCell = currentCell + side; if (IsCellInBounds(testCell)) { if (FindCellExit(origin, dir, t0, testCell, -side, false, exitFace, exitCoord, t1)) { nextCell = testCell + exitFace; return true; } } } return false; } bool FindNextCell(vec3 origin, vec3 dir, float t0, ivec3 currentCell, ivec3 entranceFace, OUT ivec3 nextCell, OUT ivec3 exitFace, OUT vec3 exitCoord, OUT float t1) { if (FindCellExit(origin, dir, t0, currentCell, entranceFace, exitFace, exitCoord, t1)) { nextCell = currentCell + exitFace; if (!IsCellInBounds(nextCell)) return false; return true; } else { return SearchNeighboringCells(origin, dir, t0, currentCell, nextCell, exitFace, exitCoord, t1); } } float IntegrateConstantAlpha(float a, float distance) { return 1 - exp(-a * distance); } // Only accurate for tetrahedra // Its an approximation for cubes float IntegrateAbsorption(float a, float b, float distance) { return 1 - exp(-distance * (a+b)/2); } bool ShouldRenderCell(const ivec3 cellIndex) { if (hasMissingData) if (DoesCellHaveMissingData(cellIndex)) return false; return true; } bool IsRayEnteringCell(vec3 d, ivec3 cellIndex, ivec3 face) { vec3 n = GetCellFaceNormal(cellIndex, face); return dot(d, n) < 0; } // vec3 GetCellNonHexahedralFaceNormalAtIntersection(vec3 o, vec3 d, ivec3 cellIndex, ivec3 face) // { // float t; // vec3 v0, v1, v2, v3, uvw; // GetFaceVertices(cellIndex, face, v0, v1, v2, v3); // // if (TRI_INSTERSECT_ROUTINE(o, d, 0, v0, v1, v2, t, uvw)) // return GetTriangleNormal(v0, v1, v2); // else // return GetTriangleNormal(v0, v2, v3); // } // // bool IsRayEnteringNonHexahedralCell(vec3 o, vec3 d, ivec3 cellIndex, ivec3 face) // { // vec3 n = GetCellNonHexahedralFaceNormalAtIntersection(o, d, cellIndex, face); // return dot(d, n) < 0; // } void GetSideCellBBox(ivec3 cellIndex, int sideID, int fastDim, int slowDim, OUT vec3 bmin, OUT vec3 bmax) { ivec3 index = ivec3(cellIndex[fastDim], cellIndex[slowDim], sideID); bmin = texelFetch(boxMins, index, 0).rgb; bmax = texelFetch(boxMaxs, index, 0).rgb; } bool IntersectRaySideCellBBox(vec3 origin, vec3 dir, float rt0, ivec3 cellIndex, int sideID, int fastDim, int slowDim) { vec3 bmin, bmax; float t0, t1; GetSideCellBBox(cellIndex, sideID, fastDim, slowDim, bmin, bmax); if (IntersectRayBoundingBox(origin, dir, rt0, bmin, bmax, t0, t1)) { return true; } return false; } void GetSideCellBBoxDirect(int x, int y, int sideID, int level, OUT vec3 bmin, OUT vec3 bmax) { ivec3 index = ivec3(x, y, sideID); bmin = texelFetch(boxMins, index, level).rgb; bmax = texelFetch(boxMaxs, index, level).rgb; } bool IntersectRaySideCellBBoxDirect(vec3 origin, vec3 dir, float rt0, int x, int y, int sideID, int level) { vec3 bmin, bmax; float t0, t1; GetSideCellBBoxDirect(x, y, sideID, level, bmin, bmax); if (IntersectRayBoundingBox(origin, dir, rt0, bmin, bmax, t0, t1)) { return true; } return false; } ivec2 GetBBoxArrayDimensions(int sideID, int level) { return texelFetch(levelDims, ivec2(sideID, level), 0).rg; } #if DEBUG float DistToEdge(vec3 p, vec3 v0, vec3 v1) { vec3 m = normalize(v1-v0); float t0 = dot(m,p-v0)/dot(m,m); float de = length(p - (v0 + t0*m)); float l = length(v1-v0); de /= l; return abs(de); // return length(p - v0); } float DistToCellEdge(vec3 o, vec3 d, float t, ivec3 cell, ivec3 face) { vec3 v0, v1, v2, v3; GetFaceVertices(cell, face, v0, v1, v2, v3); vec3 p = o + d*t; float de = FLT_MAX; de = min(de, DistToEdge(p, v0, v1)); de = min(de, DistToEdge(p, v1, v2)); de = min(de, DistToEdge(p, v2, v3)); de = min(de, DistToEdge(p, v3, v0)); // de = min(de, DistToEdge(p, v0, v2)); return de; } #endif bool IsFaceThatPassedBBAnInitialCell(vec3 origin, vec3 dir, float t0, ivec3 index, ivec3 side, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { // if (index == skipCellWhenSearchingForInit) return false; float tFace; vec3 null; if (IntersectRayCellFace(origin, dir, t0, index, side, tFace, null)) { if (IsRayEnteringCell(dir, index, side)) { // Only update initial cell values if this is the closest cell // if (tFace > t0 && tFace < t1) { if (tFace < t1) { cellIndex = index; entranceFace = side; t1 = tFace; #if DEBUG #if DEBUG_SHOW_NORMALS vec3 n = GetCellNonHexahedralFaceNormalAtIntersection(origin, dir, index, side); n = normalize(n/scales); SD((n+vec3(1))/2.f, 0); #endif #if DEBUG_SHOW_CELL_INDEX SD(index/vec3(cellDims), 0); #endif #if DEBUG_SHOW_GRID float de = DistToCellEdge(origin, dir, t1, index, side); if (de < 0.03) SD(WHITE, 0); #endif #endif } return true; } } return false; } // The nvidia compiler optimizer cannot handle deep nested loops // unroll none improves compile time // inline none breaks the compiler // Side note: This is supposed to be an inline change but it is in fact a source-wide flag // #pragma optionNV(inline none) #pragma optionNV(unroll none) #ifdef NVIDIA #include BBTraversalAlgorithmsNV.frag #else #include BBTraversalAlgorithms.frag #endif int SearchSideForInitialCellBasic(vec3 origin, vec3 dir, float t0, int sideID, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { int fastDim = GetFastDimForFaceIndex(sideID); int slowDim = GetSlowDimForFaceIndex(sideID); ivec3 side = GetFaceFromFaceIndex(sideID); ivec3 index = (side+1)/2 * (cellDims-1); for (index[slowDim] = 0; index[slowDim] < cellDims[slowDim]; index[slowDim]++) { for (index[fastDim] = 0; index[fastDim] < cellDims[fastDim]; index[fastDim]++) { if (IntersectRaySideCellBBox(origin, dir, t0, index, sideID, fastDim, slowDim)) { if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1)) return 1; } } } return 0; } // Does not work on nvidia // #define SearchSideForInitialCellWithOctree_NLevels(N, origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1) SearchSideForInitialCellWithOctree_ ## N ## Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1) int SearchSideForInitialCell(vec3 origin, vec3 dir, float t0, int sideID, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1) { int fastDim = GetFastDimForFaceIndex(sideID); int slowDim = GetSlowDimForFaceIndex(sideID); #if BB_LEVELS == 1 return SearchSideForInitialCellWithOctree_1Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1); #elif BB_LEVELS == 2 return SearchSideForInitialCellWithOctree_2Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1); #elif BB_LEVELS == 3 return SearchSideForInitialCellWithOctree_3Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1); #elif BB_LEVELS == 4 return SearchSideForInitialCellWithOctree_4Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1); #elif BB_LEVELS == 5 return SearchSideForInitialCellWithOctree_5Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1); #elif BB_LEVELS == 6 return SearchSideForInitialCellWithOctree_6Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1); #elif BB_LEVELS == 7 return SearchSideForInitialCellWithOctree_7Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1); #elif BB_LEVELS == 8 return SearchSideForInitialCellWithOctree_8Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1); #elif BB_LEVELS == 9 return SearchSideForInitialCellWithOctree_9Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1); #elif BB_LEVELS == 10 return SearchSideForInitialCellWithOctree_10Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1); #elif BB_LEVELS == 11 return SearchSideForInitialCellWithOctree_11Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1); #elif BB_LEVELS == 12 return SearchSideForInitialCellWithOctree_12Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1); #endif } int FindInitialCell(vec3 origin, vec3 dir, float t0, OUT ivec3 cellIndex, OUT ivec3 entranceFace, OUT float t1) { t1 = FLT_MAX; int intersections = 0; for (int side = 0; side < 6; side++) intersections += SearchSideForInitialCell(origin, dir, t0, side, cellIndex, entranceFace, t1); return intersections; } vec4 Traverse(vec3 origin, vec3 dir, vec3 rayLightingNormal, float tMin, float tMax, float t0, ivec3 currentCell, ivec3 entranceFace, OUT float t1); void main(void) { vec3 eye, dir, rayLightingNormal; float sceneDepthT; GetRayParameters(eye, dir, rayLightingNormal, sceneDepthT); float t0, t1, tp; bool intersectBox = IntersectRayBoundingBox(eye, dir, 0, userExtsMin, userExtsMax, t0, t1); float tMin = t0, tMax = min(t1, sceneDepthT); if (intersectBox) { ivec3 initialCell; ivec3 entranceFace; float t0 = -FLT_MAX; float t1; vec4 accum = vec4(0); int intersections; int i = 0; do { intersections = FindInitialCell(eye, dir, t0, initialCell, entranceFace, t1); // skipCellWhenSearchingForInit = initialCell; if (intersections > 0) { vec4 color = Traverse(eye, dir, rayLightingNormal, tMin, tMax, t1, initialCell, entranceFace, t1); BlendToBack(accum, color); } // Failsafe to prevent infinite recursion due to float precision error // if (i++ > 8) { if (i++ > 8 || t1-t0 <= EPSILON) { break; } // if (t1-t0 <= EPSILON) { // float unitDistanceScaled = unitDistance / length(dir * scales); // float step = unitDistanceScaled/7.f/samplingRateMultiplier * GetSamplingNoise(); // t1 = t0 + step; // } if (accum.a > ALPHA_BREAK) break; t0 = t1; } while (intersections > 1); if (accum.a < ALPHA_DISCARD) { // discard; // There is a bug on in the 2015 15" AMD MBP laptops where this does not work with larger(?) datasets //fragColor = vec4(0); gl_FragDepth = GetDepthBuffer(); DEBUG_SHOW(); return; } fragColor = accum; DEBUG_SHOW(); return; } // discard; gl_FragDepth = GetDepthBuffer(); fragColor = vec4(0.f); DEBUG_SHOW(); } ================================================ FILE: share/shaders/VolumeCellDVR.frag ================================================ #pragma auto_version #include VolumeCellBase.frag vec4 RenderCellSampling(const vec3 dir, const vec3 entranceCoord, const vec3 exitCoord, const float t0, const float t1, const float step) { vec4 acc2 = vec4(0); for (float t = step * (floor(t0/step)+1); t < t1; t+= step) { vec3 hit = mix(entranceCoord, exitCoord, (t-t0)/(t1-t0)); vec4 color = GetColorAtCoord(hit); vec3 normal = GetNormalAtCoord(hit); color.rgb *= PhongLighting(normal, dir); BlendToBack(acc2, PremultiplyAlpha(color)); } return acc2; } vec4 RenderCellSmartSampling(const vec3 dir, vec3 rayLightingNormal, const vec3 entranceCoord, const vec3 exitCoord, const float tStart, const float tEnd, const float t0, const float t1, const float step, const float stepOpacityUnit) { vec4 acc2 = vec4(0); vec3 hit = mix(entranceCoord, exitCoord, (tStart-t0)/(t1-t0)); vec4 c = GetColorAtCoord(hit); vec3 normal = GetNormalAtCoord(hit); c.rgb *= PhongLighting(normal, rayLightingNormal); float l = min(step - mod(tStart, step), tEnd-tStart)/step; c.a = IntegrateConstantAlpha(c.a * density, max(l * stepOpacityUnit, 0.0f)); BlendToBack(acc2, PremultiplyAlpha(c)); for (float t = step * (floor(tStart/step)+1); t < tEnd; t+= step) { vec3 hit = mix(entranceCoord, exitCoord, (t-t0)/(t1-t0)); vec4 color = GetColorAtCoord(hit); vec3 normal = GetNormalAtCoord(hit); color.rgb *= PhongLighting(normal, rayLightingNormal); float l = min(step, t1-t)/step; color.a = IntegrateConstantAlpha(color.a * density, l * stepOpacityUnit); BlendToBack(acc2, PremultiplyAlpha(color)); } return acc2; } vec4 RenderCellConstant(const vec3 dir, const vec3 rayLightingNormal, const ivec3 currentCell, const float t0, const float t1, const float unitDistanceScaled) { float l = (t1-t0)/unitDistanceScaled; vec4 color = GetAverageColorForCoordIndex(currentCell); vec3 normal = GetNormal((vec3(currentCell)+vec3(0.5))/cellDims); color.rgb *= PhongLighting(normal, rayLightingNormal); color.a = IntegrateConstantAlpha(color.a * density, l * unitOpacityScalar); return PremultiplyAlpha(color); } vec4 Traverse(vec3 origin, vec3 dir, vec3 rayLightingNormal, float tMin, float tMax, float t0, ivec3 currentCell, ivec3 entranceFace, OUT float t1) { vec3 entranceCoord; ivec3 nextCell; ivec3 exitFace; vec3 exitCoord; bool hasNext = true; float tStart = t0; ivec3 initialCell = currentCell; float unitDistanceScaled = unitDistance / length(dir * scales); float step = unitDistanceScaled/7.f/samplingRateMultiplier * GetSamplingNoise(); float stepOpacityUnit = unitOpacityScalar/samplingRateMultiplier; if (fast) { step = unitDistanceScaled * GetSamplingNoise(); stepOpacityUnit = unitOpacityScalar * 7; } int i = 0; vec4 accum = vec4(0); float a = 0; float null; IntersectRayCellFace(origin, dir, -FLT_MAX, currentCell, entranceFace, null, entranceCoord); while (hasNext) { if (t0 > tMax) break; hasNext = FindNextCell(origin, dir, t0, currentCell, entranceFace, nextCell, exitFace, exitCoord, t1); if (t0 >= tMin || (t0 <= tMin && tMin < t1)) { float tEnd = min(t1, tMax); float tStart = max(t0, tMin); if (ShouldRenderCell(currentCell)) { #if 1 BlendToBack(accum, RenderCellSmartSampling(dir, rayLightingNormal, entranceCoord, exitCoord, tStart, tEnd, t0, t1, step, stepOpacityUnit)); #else BlendToBack(accum, RenderCellConstant (dir, rayLightingNormal, currentCell, tStart, tEnd, unitDistanceScaled)); #endif } } currentCell = nextCell; entranceFace = -exitFace; entranceCoord = exitCoord; t0 = t1; i++; if (accum.a > ALPHA_BREAK || i > 4096) break; } gl_FragDepth = CalculateDepth(origin + dir*t1); return accum; } ================================================ FILE: share/shaders/VolumeCellDVR.vert ================================================ #version 330 core layout (location = 0) in vec2 vertex; layout (location = 1) in vec2 vTextureCoord; out vec2 ST; void main() { gl_Position = vec4(vertex, 0.0, 1.0); ST = vTextureCoord; } ================================================ FILE: share/shaders/VolumeCellIso.frag ================================================ #pragma auto_version #include VolumeCellBase.frag #include VolumeIsoInclude.frag void TestIsoSegment(const vec3 origin, const vec3 dir, const vec3 rayLightingNormal, const float isoValue, const float dv, const float ld, const float t, const float lt, const float t0, const float t1, const vec3 entranceCoord, const vec3 exitCoord, inout vec4 accum) { if ((ld < isoValue && dv >= isoValue) || (ld > isoValue && dv <= isoValue)) { float ti = mix(lt, t, (isoValue-ld)/(dv-ld)); vec3 hit = mix(entranceCoord, exitCoord, (ti-t0)/(t1-t0)); vec3 isoSampleSTR = hit/coordDimsF; vec4 color = GetIsoSurfaceColor(isoSampleSTR); vec3 normal = GetNormal(isoSampleSTR); color.rgb *= PhongLighting(normal, rayLightingNormal); BlendToBack(accum, PremultiplyAlpha(color)); if (accum.a > ALPHA_BREAK) gl_FragDepth = CalculateDepth(origin + dir * ti); } } void TestAllIsoSegment(const vec3 origin, const vec3 dir, const vec3 rayLightingNormal, const float dve, const float dvs, const float te, const float ts, const float t0, const float t1, const vec3 entranceCoord, const vec3 exitCoord, inout vec4 accum) { if (isoEnabled[0]) TestIsoSegment(origin, dir, rayLightingNormal, isoValue[0], dve, dvs, te, ts, t0, t1, entranceCoord, exitCoord, accum); if (isoEnabled[1]) TestIsoSegment(origin, dir, rayLightingNormal, isoValue[1], dve, dvs, te, ts, t0, t1, entranceCoord, exitCoord, accum); if (isoEnabled[2]) TestIsoSegment(origin, dir, rayLightingNormal, isoValue[2], dve, dvs, te, ts, t0, t1, entranceCoord, exitCoord, accum); if (isoEnabled[3]) TestIsoSegment(origin, dir, rayLightingNormal, isoValue[3], dve, dvs, te, ts, t0, t1, entranceCoord, exitCoord, accum); } void SampleCell(const vec3 origin, const vec3 dir, const vec3 rayLightingNormal, const vec3 entranceCoord, const vec3 exitCoord, const float t0, const float t1, const float ts, const float te, inout vec4 accum) { if (accum.a > ALPHA_BREAK) return; vec3 hitS = mix(entranceCoord, exitCoord, (ts-t0)/(t1-t0)); float ds = GetDataCoordinateSpace(hitS); float tm = (te+ts)/2.0; vec3 hitm = mix(entranceCoord, exitCoord, (tm-t0)/(t1-t0)); float dm = GetDataCoordinateSpace(hitm); vec3 hitE = mix(entranceCoord, exitCoord, (te-t0)/(t1-t0)); float de = GetDataCoordinateSpace(hitE); TestAllIsoSegment(origin, dir, rayLightingNormal, dm, ds, tm, ts, t0, t1, entranceCoord, exitCoord, accum); TestAllIsoSegment(origin, dir, rayLightingNormal, de, dm, te, tm, t0, t1, entranceCoord, exitCoord, accum); } vec4 Traverse(vec3 origin, vec3 dir, vec3 rayLightingNormal, float tMin, float tMax, float t0, ivec3 currentCell, ivec3 entranceFace, OUT float t1) { vec3 entranceCoord; ivec3 nextCell; ivec3 exitFace; vec3 exitCoord; bool hasNext = true; ivec3 initialCell = currentCell; float unitDistanceScaled = unitDistance / length(dir * scales); float step = unitDistanceScaled/7/samplingRateMultiplier * GetSamplingNoise(); if (fast) step = unitDistanceScaled * GetSamplingNoise(); int i = 0; vec4 accum = vec4(0); float a = 0; float lt; IntersectRayCellFace(origin, dir, -FLT_MAX, currentCell, entranceFace, lt, entranceCoord); FindNextCell(origin, dir, t0, currentCell, entranceFace, nextCell, exitFace, exitCoord, t1); while (hasNext) { if (t0 > tMax) break; hasNext = FindNextCell(origin, dir, t0, currentCell, entranceFace, nextCell, exitFace, exitCoord, t1); if (t0 >= tMin || (t0 <= tMin && tMin < t1)) { float tEnd = min(t1, tMax); float tStart = max(t0, tMin); if (ShouldRenderCell(currentCell)) SampleCell(origin, dir, rayLightingNormal, entranceCoord, exitCoord, t0, t1, tStart, tEnd, accum); } currentCell = nextCell; entranceFace = -exitFace; entranceCoord = exitCoord; t0 = t1; i++; if (accum.a > ALPHA_BREAK || i > 4096) break; } return accum; } ================================================ FILE: share/shaders/VolumeCellIso.vert ================================================ #version 330 core layout (location = 0) in vec2 vertex; layout (location = 1) in vec2 vTextureCoord; out vec2 ST; void main() { gl_Position = vec4(vertex, 0.0, 1.0); ST = vTextureCoord; } ================================================ FILE: share/shaders/VolumeDVR.frag ================================================ #pragma auto_version #include VolumeBase.frag /* float Shadow(vec3 to) { float t = 0, t0, t1; IntersectRayBoundingBox(to, -lightDir, 0, vec3(0), vec3(1), t0, t1); //return t1; float acc = 0; for (; t < t1; t+= 0.05) { float dataNorm = (texture(data, to-t*lightDir).r - LUTMin) / (LUTMax - LUTMin); float opacity = texture(LUT, dataNorm).a; acc += opacity * (1-acc); } return 1-acc; } */ float IntegrateConstantAlpha(float a, float distance) { return 1 - exp(-a * distance); } void main(void) { vec3 eye, dir, rayLightingNormal; float sceneDepthT; GetRayParameters(eye, dir, rayLightingNormal, sceneDepthT); vec4 accum = vec4(0); float t0, t1; if (IntersectRayBoundingBox(eye, dir, 0, userExtsMin, userExtsMax, t0, t1)) { int STEPS; float integratePart = 1 / samplingRateMultiplier; if (fast) { STEPS = 100; integratePart = 7; } else { STEPS = int(700 * samplingRateMultiplier); } float step = GetSamplingNoise() * max(((t1-t0)/float(STEPS))*1.01, (dataBoundsMax[2]-dataBoundsMin[2])/float(STEPS)); t1 = min(t1, sceneDepthT); int i = 0; for (float t = t0; t < t1; t += step) { vec3 hit = eye + dir * t; vec3 dataSTR = (hit - dataBoundsMin) / (dataBoundsMax-dataBoundsMin); vec4 color = GetColorForNormalizedCoord(dataSTR); vec3 normal = GetNormal(dataSTR); color.rgb *= PhongLighting(normal, rayLightingNormal); color.a = IntegrateConstantAlpha(color.a * density, integratePart); if (ShouldRenderSample(dataSTR)) BlendToBack(accum, PremultiplyAlpha(color)); if (accum.a > ALPHA_BREAK) { t1 = t; break; } // Failsafe if (i++ > STEPS) break; } gl_FragDepth = CalculateDepth(eye + dir*t1); fragColor = accum; } else { fragColor = vec4(0.f); } if (accum.a < ALPHA_DISCARD) gl_FragDepth = GetDepthBuffer(); } ================================================ FILE: share/shaders/VolumeDVR.vert ================================================ #version 330 core layout (location = 0) in vec2 vertex; layout (location = 1) in vec2 vTextureCoord; out vec2 ST; void main() { gl_Position = vec4(vertex, 0.0, 1.0); ST = vTextureCoord; } ================================================ FILE: share/shaders/VolumeIso.frag ================================================ #pragma auto_version #include VolumeBase.frag #include VolumeIsoInclude.frag void TestIso(vec3 eye, vec3 dir, vec3 rayLightingNormal, float value, float dv, float ld, float step, float t, inout vec4 accum) { if ((ld < value && dv >= value) || (ld > value && dv <= value)) { float lt = t - step; float t = lt + step*(value-ld)/(dv-ld); vec3 hit = eye + dir * t; vec3 dataSTR = (hit - dataBoundsMin) / (dataBoundsMax-dataBoundsMin); vec4 color = GetIsoSurfaceColor(dataSTR); vec3 normal = GetNormal(dataSTR); color.rgb *= PhongLighting(normal, rayLightingNormal); BlendToBack(accum, PremultiplyAlpha(color)); } } void main(void) { vec3 eye, dir, rayLightingNormal; float sceneDepthT; GetRayParameters(eye, dir, rayLightingNormal, sceneDepthT); vec4 accum = vec4(0); float t0, t1; if (IntersectRayBoundingBox(eye, dir, 0, userExtsMin, userExtsMax, t0, t1)) { int STEPS; if (fast) { STEPS = 100; } else STEPS = int(700 * samplingRateMultiplier); float step = max(((t1-t0)/float(STEPS))*1.01, (dataBoundsMax[2]-dataBoundsMin[2])/float(STEPS)); vec3 initialSample = ((eye + dir * t0) - dataBoundsMin) / (dataBoundsMax-dataBoundsMin); float ld = texture(data, initialSample).r; bool lastShouldRender = ShouldRenderSample(initialSample); t1 = min(t1, sceneDepthT); int i = 0; for (float t = t0; t < t1; t += step) { vec3 hit = eye + dir * t; vec3 dataSTR = (hit - dataBoundsMin) / (dataBoundsMax-dataBoundsMin); float dv = texture(data, dataSTR).r; bool shouldRender = ShouldRenderSample(dataSTR); if (shouldRender && lastShouldRender) { // Unrolled intentionally if (isoEnabled[0]) TestIso(eye, dir, rayLightingNormal, isoValue[0], dv, ld, step, t, accum); if (isoEnabled[1]) TestIso(eye, dir, rayLightingNormal, isoValue[1], dv, ld, step, t, accum); if (isoEnabled[2]) TestIso(eye, dir, rayLightingNormal, isoValue[2], dv, ld, step, t, accum); if (isoEnabled[3]) TestIso(eye, dir, rayLightingNormal, isoValue[3], dv, ld, step, t, accum); if (accum.a > ALPHA_BREAK) gl_FragDepth = CalculateDepth(hit); } ld = dv; lastShouldRender = shouldRender; if (accum.a > ALPHA_BREAK) break; // Failsafe if (i++ > STEPS) break; } fragColor = accum; } else { fragColor = vec4(0.f); } if (accum.a < ALPHA_DISCARD) gl_FragDepth = GetDepthBuffer(); } ================================================ FILE: share/shaders/VolumeIso.vert ================================================ #version 330 core layout (location = 0) in vec2 vertex; layout (location = 1) in vec2 vTextureCoord; out vec2 ST; void main() { gl_Position = vec4(vertex, 0.0, 1.0); ST = vTextureCoord; } ================================================ FILE: share/shaders/VolumeIsoInclude.frag ================================================ uniform float isoValue[4]; uniform bool isoEnabled[4]; uniform vec4 constantColor; vec4 GetIsoSurfaceColor(vec3 sampleSTR) { float value = texture(data, sampleSTR).r; float valueNorm = (value - LUTMin) / (LUTMax - LUTMin); float opacity = texture(LUT, valueNorm).a; #ifdef USE_SECOND_DATA if (useColormapData) { if (hasMissingData2) if (DoesSampleHaveMissingData2(sampleSTR)) return vec4(0); float value2 = texture(data2, sampleSTR).r; float valueNorm2 = (value2 - LUTMin2) / (LUTMax2 - LUTMin2); return vec4(texture(LUT2, valueNorm2).rgb, opacity); } #endif return vec4(constantColor.rgb, opacity); } ================================================ FILE: share/shaders/VolumeRayMath.frag ================================================ #define FLT_MAX 3.402823466e+38 #define FLT_MIN 1.175494351e-38 #define DBL_MAX 1.7976931348623158e+308 #define DBL_MIN 2.2250738585072014e-308 #define EPSILON 1.19e-07 bool IntersectRayBoundingBox(vec3 o, vec3 d, float rt0, vec3 boxMin, vec3 boxMax, OUT float t0, OUT float t1) { vec3 tMin = (boxMin - o) / d; vec3 tMax = (boxMax - o) / d; vec3 bt1 = min(tMin, tMax); vec3 bt2 = max(tMin, tMax); t0 = max(max(max(bt1.x, bt1.y), bt1.z), rt0); t1 = min(min(bt2.x, bt2.y), bt2.z); return t0 <= t1; } bool IntersectRayPlane(vec3 o, vec3 d, float rt0, vec3 v0, vec3 n, OUT float t) { float denom = dot(n, d); if (abs(denom) > 1e-6) { t = dot(v0 - o, n) / denom; return t >= rt0; } return false; } bool IntersectRayTriangle(vec3 o, vec3 d, float rt0, vec3 v0, vec3 v1, vec3 v2, OUT float t, OUT vec3 barycentric) { vec3 n = cross(v1-v0,v2-v0); if (IntersectRayPlane(o, d, rt0, v0, n, t)) { vec3 P = o + d * t; vec3 edge0 = v1-v0; vec3 vp0 = P - v0; vec3 C0 = cross(edge0, vp0); if (dot(n, C0) < 0) return false; vec3 edge1 = v2-v1; vec3 vp1 = P - v1; vec3 C1 = cross(edge1, vp1); if (dot(n, C1) < 0) return false; vec3 edge2 = v0 - v2; vec3 vp2 = P - v2; vec3 C2 = cross(edge2, vp2); if (dot(n, C2) < 0) return false; float area = length(n); float u = length(C1) / area; float v = length(C2) / area; float w = 1-u-v; barycentric = vec3(u,v,w); return true; } return false; } int MaxDimension(vec3 v) { return (v.x > v.y) ? ((v.x > v.z) ? 0 : 2) : ((v.y > v.z) ? 1 : 2); } vec3 Permute(vec3 v, int x, int y, int z) { return vec3(v[x], v[y], v[z]); } bool IntersectRayTriangleIntel(vec3 o, vec3 dir, float rt0, vec3 v0, vec3 v1, vec3 v2, OUT float t, OUT vec3 barycentric) { // Transform triangle vertices to ray coordinate space // Translate vertices based on ray origin vec3 p0t = v0 - o; vec3 p1t = v1 - o; vec3 p2t = v2 - o; // Permute components of triangle vertices and ray direction int kz = MaxDimension(abs(dir)); int kx = kz + 1; if (kx == 3) kx = 0; int ky = kx + 1; if (ky == 3) ky = 0; vec3 d = Permute(dir, kx, ky, kz); p0t = Permute(p0t, kx, ky, kz); p1t = Permute(p1t, kx, ky, kz); p2t = Permute(p2t, kx, ky, kz); // Apply shear transformation to translated vertex positions float Sx = -d.x / d.z; float Sy = -d.y / d.z; float Sz = 1.f / d.z; p0t.x += Sx * p0t.z; p0t.y += Sy * p0t.z; p1t.x += Sx * p1t.z; p1t.y += Sy * p1t.z; p2t.x += Sx * p2t.z; p2t.y += Sy * p2t.z; // Compute edge function coefficients e0, e1, and e2 float e0 = p1t.x * p2t.y - p1t.y * p2t.x; float e1 = p2t.x * p0t.y - p2t.y * p0t.x; float e2 = p0t.x * p1t.y - p0t.y * p1t.x; #if __VERSION__ >= 400 // Fall back to double-precision test at triangle edges if (e0 == 0.0f || e1 == 0.0f || e2 == 0.0f) { double p2txp1ty = double(p2t.x) * double(p1t.y); double p2typ1tx = double(p2t.y) * double(p1t.x); e0 = float(p2typ1tx - p2txp1ty); double p0txp2ty = double(p0t.x) * double(p2t.y); double p0typ2tx = double(p0t.y) * double(p2t.x); e1 = float(p0typ2tx - p0txp2ty); double p1txp0ty = double(p1t.x) * double(p0t.y); double p1typ0tx = double(p1t.y) * double(p0t.x); e2 = float(p1typ0tx - p1txp0ty); } #endif // Perform triangle edge and determinant tests if ((e0 < 0 || e1 < 0 || e2 < 0) && (e0 > 0 || e1 > 0 || e2 > 0)) return false; float det = e0 + e1 + e2; if (det == 0) return false; // Compute scaled hit distance to triangle and test against ray t range // p0t.z *= Sz; // p1t.z *= Sz; // p2t.z *= Sz; // float tScaled = e0 * p0t.z + e1 * p1t.z + e2 * p2t.z; // if (det < 0 && (tScaled >= rt0*det || tScaled < FLT_MAX * det)) // return false; // else if (det > 0 && (tScaled <= rt0*det || tScaled > FLT_MAX * det)) // return false; // t = tScaled * invDet; // This routine provides consistent results at t = t0 // as opposed to the one above if (!IntersectRayPlane(o, dir, rt0, v0, cross(v1-v0,v2-v0), t)) return false; float invDet = 1 / det; float b0 = e0 * invDet; float b1 = e1 * invDet; float b2 = e2 * invDet; barycentric = vec3(b0, b1, b2); return true; } #ifdef USE_INTEL_TRI_ISECT #define TRI_INSTERSECT_ROUTINE IntersectRayTriangleIntel #else #define TRI_INSTERSECT_ROUTINE IntersectRayTriangle #endif bool IntersectRayQuad(vec3 o, vec3 d, float rt0, vec3 v0, vec3 v1, vec3 v2, vec3 v3, OUT float t, OUT vec4 weights) { vec3 uvw; if (TRI_INSTERSECT_ROUTINE(o, d, rt0, v0, v1, v2, t, uvw)) { weights = vec4(uvw, 0); return true; } if (TRI_INSTERSECT_ROUTINE(o, d, rt0, v0, v2, v3, t, uvw)) { weights = vec4(uvw.x, 0, uvw.y, uvw.z); return true; } return false; } ================================================ FILE: share/shaders/VolumeRectilinearDVR.frag ================================================ #pragma auto_version #include VolumeBase.frag uniform ivec3 coordDims; uniform ivec3 coordSigns; uniform sampler2D coordLUT; float IntegrateConstantAlpha(float a, float distance) { return 1 - exp(-a * distance); } vec3 ReverseCoordMapping(vec3 p) { return vec3( texture(coordLUT, vec2(p.x, 0.0)).x, texture(coordLUT, vec2(p.y, 0.5)).x, texture(coordLUT, vec2(p.z, 1.0)).x ); } vec3 GetNormalWithReverseCoordMapping(vec3 p) { vec3 dims = vec3(textureSize(data, 0)); vec3 d = 1/dims * 0.5; vec3 s0, s1; s1.x = texture(data, ReverseCoordMapping(p + d*vec3(1,0,0))).r; s1.y = texture(data, ReverseCoordMapping(p + d*vec3(0,1,0))).r; s1.z = texture(data, ReverseCoordMapping(p + d*vec3(0,0,1))).r; s0.x = texture(data, ReverseCoordMapping(p - d*vec3(1,0,0))).r; s0.y = texture(data, ReverseCoordMapping(p - d*vec3(0,1,0))).r; s0.z = texture(data, ReverseCoordMapping(p - d*vec3(0,0,1))).r; // glsl::normalize does not handle 0 length vectors vec3 v = s1-s0; float l = length(v); if (l == 0) return vec3(0); return v/l; } void main(void) { vec3 eye, dir, rayLightingNormal; float sceneDepthT; GetRayParameters(eye, dir, rayLightingNormal, sceneDepthT); vec4 accum = vec4(0); float t0, t1; if (IntersectRayBoundingBox(eye, dir, 0, userExtsMin, userExtsMax, t0, t1)) { int STEPS; float integratePart = 1 / samplingRateMultiplier; if (fast) { STEPS = 100; integratePart = 7; } else { STEPS = int(700 * samplingRateMultiplier); } float step = GetSamplingNoise() * max(((t1-t0)/float(STEPS))*1.01, (dataBoundsMax[2]-dataBoundsMin[2])/float(STEPS)); t1 = min(t1, sceneDepthT); int i = 0; for (float t = t0; t < t1; t += step) { vec3 hit = eye + dir * t; vec3 dataSTR = (hit - dataBoundsMin) / (dataBoundsMax-dataBoundsMin); vec3 dataSTRMapped = ReverseCoordMapping(dataSTR); vec4 color = GetColorForNormalizedCoord(dataSTRMapped); vec3 normal = GetNormalWithReverseCoordMapping(dataSTR); color.rgb *= PhongLighting(normal, rayLightingNormal); color.a = IntegrateConstantAlpha(color.a * density, integratePart); if (ShouldRenderSample(dataSTRMapped)) BlendToBack(accum, PremultiplyAlpha(color)); if (accum.a > ALPHA_BREAK) { t1 = t; break; } // Failsafe if (i++ > STEPS) break; } gl_FragDepth = CalculateDepth(eye + dir*t1); fragColor = accum; } else { fragColor = vec4(0.f); } if (accum.a < ALPHA_DISCARD) gl_FragDepth = GetDepthBuffer(); } ================================================ FILE: share/shaders/VolumeRectilinearDVR.vert ================================================ #version 330 core layout (location = 0) in vec2 vertex; layout (location = 1) in vec2 vTextureCoord; out vec2 ST; void main() { gl_Position = vec4(vertex, 0.0, 1.0); ST = vTextureCoord; } ================================================ FILE: share/shaders/VolumeRectilinearIso.frag ================================================ #pragma auto_version #include VolumeBase.frag #include VolumeIsoInclude.frag uniform sampler2D coordLUT; vec3 ReverseCoordMapping(vec3 p) { return vec3( texture(coordLUT, vec2(p.x, 0.0)).x, texture(coordLUT, vec2(p.y, 0.5)).x, texture(coordLUT, vec2(p.z, 1.0)).x ); } vec3 GetNormalWithReverseCoordMapping(vec3 p) { vec3 dims = vec3(textureSize(data, 0)); vec3 d = 1/dims * 0.5; vec3 s0, s1; s1.x = texture(data, ReverseCoordMapping(p + d*vec3(1,0,0))).r; s1.y = texture(data, ReverseCoordMapping(p + d*vec3(0,1,0))).r; s1.z = texture(data, ReverseCoordMapping(p + d*vec3(0,0,1))).r; s0.x = texture(data, ReverseCoordMapping(p - d*vec3(1,0,0))).r; s0.y = texture(data, ReverseCoordMapping(p - d*vec3(0,1,0))).r; s0.z = texture(data, ReverseCoordMapping(p - d*vec3(0,0,1))).r; // glsl::normalize does not handle 0 length vectors vec3 v = s1-s0; float l = length(v); if (l == 0) return vec3(0); return v/l; } void TestIso(vec3 eye, vec3 dir, vec3 rayLightingNormal, float value, float dv, float ld, float step, float t, inout vec4 accum) { if ((ld < value && dv >= value) || (ld > value && dv <= value)) { float lt = t - step; float t = lt + step*(value-ld)/(dv-ld); vec3 hit = eye + dir * t; vec3 dataSTR = (hit - dataBoundsMin) / (dataBoundsMax-dataBoundsMin); vec3 dataSTRMapped = ReverseCoordMapping(dataSTR); vec4 color = GetIsoSurfaceColor(dataSTRMapped); vec3 normal = GetNormalWithReverseCoordMapping(dataSTR); color.rgb *= PhongLighting(normal, rayLightingNormal); BlendToBack(accum, PremultiplyAlpha(color)); } } void main(void) { vec3 eye, dir, rayLightingNormal; float sceneDepthT; GetRayParameters(eye, dir, rayLightingNormal, sceneDepthT); vec4 accum = vec4(0); float t0, t1; if (IntersectRayBoundingBox(eye, dir, 0, userExtsMin, userExtsMax, t0, t1)) { int STEPS; if (fast) { STEPS = 100; } else STEPS = int(700 * samplingRateMultiplier); float step = max(((t1-t0)/float(STEPS))*1.01, (dataBoundsMax[2]-dataBoundsMin[2])/float(STEPS)); vec3 initialSample = ((eye + dir * t0) - dataBoundsMin) / (dataBoundsMax-dataBoundsMin); initialSample = ReverseCoordMapping(initialSample); float ld = texture(data, initialSample).r; bool lastShouldRender = ShouldRenderSample(initialSample); t1 = min(t1, sceneDepthT); int i = 0; for (float t = t0; t < t1; t += step) { vec3 hit = eye + dir * t; vec3 dataSTR = (hit - dataBoundsMin) / (dataBoundsMax-dataBoundsMin); vec3 dataSTRMapped = ReverseCoordMapping(dataSTR); float dv = texture(data, dataSTRMapped).r; bool shouldRender = ShouldRenderSample(dataSTRMapped); if (shouldRender && lastShouldRender) { // Unrolled intentionally if (isoEnabled[0]) TestIso(eye, dir, rayLightingNormal, isoValue[0], dv, ld, step, t, accum); if (isoEnabled[1]) TestIso(eye, dir, rayLightingNormal, isoValue[1], dv, ld, step, t, accum); if (isoEnabled[2]) TestIso(eye, dir, rayLightingNormal, isoValue[2], dv, ld, step, t, accum); if (isoEnabled[3]) TestIso(eye, dir, rayLightingNormal, isoValue[3], dv, ld, step, t, accum); if (accum.a > ALPHA_BREAK) gl_FragDepth = CalculateDepth(hit); } ld = dv; lastShouldRender = shouldRender; if (accum.a > ALPHA_BREAK) break; // Failsafe if (i++ > STEPS) break; } fragColor = accum; } else { fragColor = vec4(0.f); } if (accum.a < ALPHA_DISCARD) gl_FragDepth = GetDepthBuffer(); } ================================================ FILE: share/shaders/VolumeRectilinearIso.vert ================================================ #version 330 core layout (location = 0) in vec2 vertex; layout (location = 1) in vec2 vTextureCoord; out vec2 ST; void main() { gl_Position = vec4(vertex, 0.0, 1.0); ST = vTextureCoord; } ================================================ FILE: share/shaders/White.frag ================================================ #version 330 core out vec4 fragColor; void main(void) { fragColor = vec4(1); } ================================================ FILE: share/shaders/White.vert ================================================ #version 330 core layout (location = 0) in vec3 vertex; void main() { gl_Position = vec4(vertex, 1.0); } ================================================ FILE: share/shaders/Wireframe.frag ================================================ #version 330 core uniform sampler1D colormap; uniform float minLUTValue; uniform float maxLUTValue; in float fValue; in float fMissing; out vec4 FragColor; void main() { //FragColor = fColor; float s = (fValue - minLUTValue) / (maxLUTValue - minLUTValue); vec4 color = texture(colormap, s); FragColor = color; if (fMissing != 0.f) discard; } ================================================ FILE: share/shaders/Wireframe.vert ================================================ #version 330 core layout (location = 0) in vec3 vPos; layout (location = 1) in float value; layout (location = 2) in float missing; out float fValue; out float fMissing; uniform mat4 MVP; uniform vec4 clippingPlanes[6]; out float gl_ClipDistance[6]; void main() { gl_Position = MVP * vec4(vPos, 1.0); fValue = value; fMissing = missing; for (int i = 0; i < 6; i++) gl_ClipDistance[i] = dot(vec4(vPos, 1.0), clippingPlanes[i]); } ================================================ FILE: share/shaders/depthpeeling.efc ================================================ depthpeeling depthpeeling depthpeeling ================================================ FILE: share/shaders/font.frag ================================================ #version 330 core in vec2 TexCoords; out vec4 fragment; uniform vec4 color; uniform sampler2D text; void main() { vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r); fragment = color * sampled; } ================================================ FILE: share/shaders/font.vert ================================================ #version 330 core layout (location = 0) in vec4 vertex; // out vec2 TexCoords; uniform mat4 MVP; void main() { gl_Position = MVP * vec4(vertex.xy, 0.0, 1.0); TexCoords = vertex.zw; } ================================================ FILE: share/shaders/includes/alphagradient.hgl ================================================ //----------------------------------------------------------------------- // Compute the gradient using the alpha channel //----------------------------------------------------------------------- uniform sampler1D colormap; uniform sampler3D volumeTexture; uniform vec3 dimensions; vec3 alphaGradient() { vec3 gradient; float dx = 0.5/(dimensions.x); float dy = 0.5/(dimensions.y); float dz = 0.5/(dimensions.z); vec3 a0; vec3 a1; a0.x = texture1D(colormap, texture3D(volumeTexture, gl_TexCoord[0].xyz + vec3(dx,0,0)).x).a; a1.x = texture1D(colormap, texture3D(volumeTexture, gl_TexCoord[0].xyz + vec3(-dx,0,0)).x).a; a0.y = texture1D(colormap, texture3D(volumeTexture, gl_TexCoord[0].xyz + vec3(0,dy,0)).x).a; a1.y = texture1D(colormap, texture3D(volumeTexture, gl_TexCoord[0].xyz + vec3(0,-dy,0)).x).a; a0.z = texture1D(colormap, texture3D(volumeTexture, gl_TexCoord[0].xyz + vec3(0,0,dz)).x).a; a1.z = texture1D(colormap, texture3D(volumeTexture, gl_TexCoord[0].xyz + vec3(0,0,-dz)).x).a; gradient = (a1-a0)/2.0; return gradient; } ================================================ FILE: share/shaders/includes/cart2sph.hgl ================================================ //------------------------------------------------------------------------- // Cartesian -> Spherical transform //------------------------------------------------------------------------- vec3 cart2sph(vec3 cartesian) { const float pi = 3.14159; vec3 spherical; spherical.z = length(cartesian.xyz); spherical.x = asin(clamp(cartesian.y / length(cartesian.yz), -1.0, 1.0)); spherical.y = acos(clamp(cartesian.x / spherical.z, -1.0, 1.0)); if (cartesian.z >= 0.0) { if (spherical.x < 0.0) spherical.x += 2.0*pi; } else { spherical.x = pi - spherical.x; } // Spherical coordinates // spherical.y (0, pi) // spherical.x (0, 2pi) spherical.y = (spherical.y / (pi)); spherical.x = (spherical.x / (2.0*pi)); // Normalized spherical coordinates // spherical.z (0, 1) // spherical.y (0, 1) // spherical.x (0, 1) spherical = (spherical - dmin) * ((tmax - tmin) / (dmax - dmin)) + tmin; return spherical; } ================================================ FILE: share/shaders/includes/datagradient.hgl ================================================ uniform sampler3D volumeTexture; vec3 permute(vec3 v); uniform vec3 dimensions; vec3 dataGradient(vec3 coord) { const float pi = 3.14159; vec3 sgradient; vec3 gradient; float dx = 0.5/(dimensions.x); float dy = 0.5/(dimensions.y); float dz = 0.5/(dimensions.z); vec3 a0; vec3 a1; a0.x = texture3D(volumeTexture, coord + vec3(dx,0,0)).x; a1.x = texture3D(volumeTexture, coord + vec3(-dx,0,0)).x; a0.y = texture3D(volumeTexture, coord + vec3(0,dy,0)).x; a1.y = texture3D(volumeTexture, coord + vec3(0,-dy,0)).x; a0.z = texture3D(volumeTexture, coord + vec3(0,0,dz)).x; a1.z = texture3D(volumeTexture, coord + vec3(0,0,-dz)).x; // // Compute the spherical gradient // sgradient = permute((a1-a0)/2.0); //sgradient.x = (sgradient.x / (coord.z * sin(coord.y*pi-pi/2.0))); //sgradient.y = (sgradient.y / coord.z); // // Transform the vector into the cartesian coordinate space // float sinphi = sin(sgradient.x * 2.0*pi-pi); float cosphi = cos(sgradient.x * 2.0*pi-pi); float sintheta = sin(sgradient.y * pi - pi/2.0); float costheta = cos(sgradient.y * pi - pi/2.0); mat3 t = mat3(-sinphi, costheta*cosphi, sintheta*cosphi, cosphi, sintheta*sintheta, costheta*sinphi, 0, costheta, -sintheta); gradient = t * sgradient; return gradient; } ================================================ FILE: share/shaders/includes/depthpeeling.hgl ================================================ uniform sampler2D previousPass; uniform float width; uniform float height; void DepthPeel(in float calc_depth, in vec4 calc_color) { //sample previous depth fragment value at my x,y position in the window vec2 texCoord = vec2(gl_FragCoord.x / width, gl_FragCoord.y / height); float depth = texture2D(previousPass, texCoord).z; //use bias to avoid floating point rounding errors, can be adjusted to be more precise // by adding more 0s if z-fighting is an issue float bias = .0000000000001; //ensure that only fragments behind the previously recorded depth get tested if (depth > calc_depth || abs(depth - calc_depth) < bias ) discard; gl_FragDepth = calc_depth; gl_FragColor= calc_color; } ================================================ FILE: share/shaders/includes/gradient.hgl ================================================ uniform sampler3D volumeTexture; // sampled data to ray cast vec3 Gradient(in vec3 delta, in vec3 tc) { vec3 gradient; float dx = delta.x; float dy = delta.y; float dz = delta.z; vec3 a0; vec3 a1; a0.x = texture3D(volumeTexture, tc + vec3(dx,0,0)).x; a1.x = texture3D(volumeTexture, tc - vec3(dx,0,0)).x; a0.y = texture3D(volumeTexture, tc + vec3(0,dy,0)).x; a1.y = texture3D(volumeTexture, tc - vec3(0,dy,0)).x; a0.z = texture3D(volumeTexture, tc + vec3(0,0,dz)).x; a1.z = texture3D(volumeTexture, tc - vec3(0,0,dz)).x; gradient = (a1-a0)/2.0; return gradient; } ================================================ FILE: share/shaders/includes/gradient2.hgl ================================================ uniform sampler3D volumeTexture; vec3 Gradient(in vec3 dims, in vec3 tc) { if (dims.x<=0 || dims.y<=0 || dims.z<=0) return(vec3(0.0, 0.0, 0.0)); vec3 h0 = vec3(-0.5,-0.5,-0.5) / dims; vec3 h1 = vec3(0.5,0.5,0.5) / dims; vec3 h = vec3(1.0, 1.0, 1.0); if ((tc.x + h0.x) < 0.0) { h0.x = 0.0; h.x = 0.5; } if ((tc.x + h1.x) > 1.0) { h1.x = 0.0; h.x = 0.5; } if ((tc.y + h0.y) < 0.0) { h0.y = 0.0; h.y = 0.5; } if ((tc.y + h1.y) > 1.0) { h1.y = 0.0; h.y = 0.5; } if ((tc.z + h0.z) < 0.0) { h0.z = 0.0; h.z = 0.5; } if ((tc.z + h1.z) > 1.0) { h1.z = 0.0; h.z = 0.5; } vec3 a0, a1; a0.x = texture3D(volumeTexture, tc + vec3(h0.x,0.0,0.0)).x; a1.x = texture3D(volumeTexture, tc + vec3(h1.x,0.0,0.0)).x; a0.y = texture3D(volumeTexture, tc + vec3(0.0,h0.y,0.0)).x; a1.y = texture3D(volumeTexture, tc + vec3(0.0,h1.y,0.0)).x; a0.z = texture3D(volumeTexture, tc + vec3(0.0,0.0,h0.z)).x; a1.z = texture3D(volumeTexture, tc + vec3(0.0,0.0,h1.z)).x; return (a1-a0 / h); } ================================================ FILE: share/shaders/includes/invpermute.hgl ================================================ uniform vec3 permutation; vec3 invPermute(vec3 v) { vec3 p = v; // // Unfortunately, GLSL 2.0 doesn't seem to allow // a uniform to be used as an index. We'll do it // the long way. // if (permutation.x == 2.0) p.x = v.z; else if (permutation.x == 1.0) p.x = v.y; if (permutation.y == 2.0) p.y = v.z; else if (permutation.y == 0.0) p.y = v.x; if (permutation.z == 0.0) p.z = v.x; else if (permutation.z == 1.0) p.z = v.y; return p; } ================================================ FILE: share/shaders/includes/permute.hgl ================================================ uniform vec3 permutation; //------------------------------------------------------------------------- // Rearrange the vector into (lon, lat, radius) order //------------------------------------------------------------------------- vec3 permute(vec3 v) { vec3 p = v; // // Unfortunately, GLSL 2.0 doesn't seem to allow // a uniform to be used as an index. We'll do it // the long way. \n // if (permutation.x == 2.0) p.z = v.x; else if (permutation.x == 1.0) p.y = v.x; if (permutation.y == 2.0) p.z = v.y; else if (permutation.y == 0.0) p.x = v.y; if (permutation.z == 0.0) p.x = v.z; else if (permutation.z == 1.0) p.y = v.z; return p; } ================================================ FILE: share/shaders/includes/tex2lay.hgl ================================================ //------------------------------------------------------------------------- // texture -> layered transform // // The 3D grid represented by volumeTexture is non-regular in Z. The // Z coordinate of each grid point is given by volumeTexture[zidx]. // This function maps the Z component of texCoord (in "user" coordinates) // to a new Z (in texture coordinates) that most closely matches // the user coordinate Z. texCoord.xy is unchanged. // //------------------------------------------------------------------------- uniform sampler3D volumeTexture; uniform vec3 dimensions; // ijk dimensions of 3D texture vec3 tex2lay(vec3 texCoord, int zidx) { vec3 invalid = vec3(-1.0, -1.0, -1.0); // invalid coordinate if (dimensions.z<=0) return(invalid); float zmin = (1.0 / dimensions.z) * 0.5; float zmax = (1.0 - zmin); if (texCoord.zzmax) return(invalid); // N is the number of iterations used to find Z in the search // algorithm below. // int N = int(ceil(log2(float(dimensions.z)))); vec3 texCoord0 = texCoord; vec3 texCoord1 = texCoord; vec3 layered = texCoord; texCoord0.z = zmin; texCoord1.z = zmax; float z0 = texture3D(volumeTexture, texCoord0)[zidx]; float z1 = texture3D(volumeTexture, texCoord1)[zidx]; float z = texCoord.z; // make sure z is in initial interval if (((z-z1) * (z-z0)) > 0.0) { return (invalid); } // // Use a binary search to locate the interval containing the // desired 'z' coordinate // for (int i=0; i 0.0) { texCoord1.z = texCoord0.z; texCoord0.z = t0save; z1 = texture3D(volumeTexture, texCoord1)[zidx]; } } z0 = texture3D(volumeTexture, texCoord0)[zidx]; float weight; if ((z1-z0)<=0) { weight = 0.0; } else { weight = (z-z0) / (z1-z0); } layered.z = texCoord0.z + (weight * (texCoord1.z-texCoord0.z)); // clamp() doesn't work, and not sure why it is needed :-( // // layered.z = clamp(layered.z,zmin,zmax); if (layered.z < zmin) layered.z = zmin; if (layered.z > zmax) layered.z = zmax; return(layered); } ================================================ FILE: share/shaders/main/2DData.fgl ================================================ varying float lightIntensity; uniform sampler1D colormap; uniform float minLUTValue; uniform float maxLUTValue; #ifdef USE_VERTEX_ATTR varying vec2 vertexData; #else uniform sampler2D dataTexture; #endif //------------------------------------------------------------------ // Fragment shader main //------------------------------------------------------------------ void main(void) { if (minLUTValue >= maxLUTValue) discard; vec2 texCoord0 = gl_TexCoord[0].xy; #ifdef USE_VERTEX_ATTR vec2 texel = vertexData; #else vec2 texel = texture2D(dataTexture, texCoord0).xy; #endif // Check for missing value // if (texel.y != 0.0) discard; float s = (texel.x - minLUTValue) / (maxLUTValue - minLUTValue); vec4 color = texture1D(colormap, s); color.rgb = color.rgb * lightIntensity; gl_FragColor = vec4(color); } ================================================ FILE: share/shaders/main/2DData.vgl ================================================ // // 2D Data surface renderer // varying float lightIntensity; uniform bool lightingEnabled; uniform float kd; uniform float ka; uniform float ks; uniform float expS; uniform vec3 lightDirection; #ifdef USE_VERTEX_ATTR attribute vec2 vertexDataAttr; varying vec2 vertexData; #endif void main() { if (lightingEnabled) { vec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Vertex); vec3 tnorm = normalize(gl_NormalMatrix * gl_Normal); vec3 lightVec = normalize(lightDirection); vec3 reflectVec = reflect(-lightVec, tnorm); vec3 viewVec = normalize(-ecPosition); float spec = clamp(dot(reflectVec, viewVec), 0.0, 1.0); spec = pow(spec, expS); lightIntensity = ka + kd * max(dot(lightVec, tnorm), 0.0) + ks*spec; } else { lightIntensity = 1.0; } gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = ftransform(); gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex; #ifdef USE_VERTEX_ATTR vertexData = vertexDataAttr; #endif } ================================================ FILE: share/shaders/main/Iso.fgl ================================================ #include gradient2.hgl #include tex2lay.hgl vec3 tex2lay(vec3 texCoord, int comp); #ifdef MAPPED uniform sampler1D colormap; #endif uniform sampler1D coordmap; uniform sampler2D texcrd_buffer; // tex coords for back facing quads uniform sampler2D depth_buffer; // depth back facing quads uniform sampler3D volumeTexture; // sampled data to ray cast uniform float isovalue; uniform int zidx; // texel component containing user Z coordinate uniform int midx; // texel component containing missing data indicator uniform bool fast; // render fast uniform bool stretched; // stretched coordinates (rectilinear grid) #ifdef MAPPED uniform int vidx; // texel component containing mapped variable #else uniform vec4 isocolor; // base color for isosurface #endif uniform int nsamples; // sampling distance along ray (eye coordinates) varying vec4 position; // interpolated gl_Position #ifdef LIGHTING uniform vec2 winsize; // Window width and height // Lighting parameters uniform vec3 dimensions; // ijk dimensions of 3D texture uniform vec3 lightDirection; uniform float kd; uniform float ka; uniform float ks; uniform float expS; varying vec3 view; // normalized, negative position (view vector) #endif #ifdef DEPTHPEEL uniform int currentLayer; uniform sampler2D previousPass; uniform float width; uniform float height; #endif vec3 Gradient(in vec3, in vec3); // The GLSL discard keyword is broken under MacOS 10.6 with nVidia drivers // void mydiscard() { gl_FragColor = vec4(0.0,0.0,0.0,0.0); gl_FragDepth = gl_DepthRange.far; // discard; } //------------------------------------------------------------------ // Fragment shader main //------------------------------------------------------------------ void main(void) { // Normalized window coordinates of this frament if (position.w == 0.0) { mydiscard(); return; } vec2 texCoord2D = ((position.xy / position.w) + 1.0) / 2.0; // Starting and finishing texture coordinate of ray vec3 texStop = texture2D(texcrd_buffer, texCoord2D).xyz; vec3 texStart = gl_TexCoord[0].xyz; // Ray direction, texture coordinates vec3 texDir = texStop - texStart; if (length(texDir) == 0.0) { mydiscard(); return; } vec3 texDirUnit = normalize(texDir); float n = gl_DepthRange.near; float f = gl_DepthRange.far; if ((f-n) == 0.0) { mydiscard(); return; } // Starting and stopping Z (window, NDC and eye coordinates) // We need eye coordinates to interpolate depth (Z) because // NDC and Window space is non-linear // N.B. Inverse transform of window coords only works for perspective float zStopWin = texture2D(depth_buffer, texCoord2D).x; float zStopNDC = (2*zStopWin)/(f-n) - (n+f)/(f-n); float zStopEye = -gl_ProjectionMatrix[3].z / (zStopNDC + gl_ProjectionMatrix[2].z); float zStartWin = gl_FragCoord.z; float zStartNDC = (2*zStartWin)/(f-n) - (n+f)/(f-n); float zStartEye = -gl_ProjectionMatrix[3].z / (zStartNDC + gl_ProjectionMatrix[2].z); #ifdef LIGHTING vec3 lightColor = vec3(1.0, 1.0, 1.0); vec2 posNDC = gl_FragCoord.xy * 2.0 / winsize.xy - 1.0; #endif // Compute number of samples based on samplin distance, delta // int nsegs = int(min(float(nsamples), 256.0)); if (fast) nsegs = 16; vec3 deltaVec = texDir / float(nsegs-1.0); float deltaZ = (zStopEye-zStartEye) / float(nsegs-1.0); // texCoord{0,1} are the end points of a ray segment in texture coords // s{0,1} are the sampled values of the texture at ray segment endpoints vec3 texCoord0 = texStart; vec3 texCoord1 = texCoord0+deltaVec; float s0, s1; #ifdef DEPTHPEEL if (width <= 0.0 || height <= 0.0) { mydiscard(); return; } bool hit = false; int layerCount = 0; #endif bool missing = false; vec3 t0 = texCoord0; vec3 t1 = texCoord1; if (zidx>0 && ! fast) { // // With layered data the starting point of the ray may not reside // inside of the data volume. Keep stepping along ray until // we're inside. // bool outside = true; while (outside && (nsegs > 0)) { t0 = tex2lay(texCoord0, zidx); t1 = tex2lay(texCoord1, zidx); if (t0.x < 0.0 || t0.y < 0.0 || t0.z < 0.0 || t0.x > 1.0 || t0.y > 1.0 || t0.z > 1.0 || t1.x < 0.0 || t1.y < 0.0 || t1.z < 0.0 || t1.x > 1.0 || t1.y > 1.0 || t1.z > 1.0) { // ray starting point is outside the volume // texCoord0 = texCoord1; texCoord1 = texCoord1+deltaVec; nsegs--; } else { outside = false; } } if (outside) { mydiscard(); return; } } else if (stretched) { t0.x = texture1D(coordmap, t0.x).x; t0.y = texture1D(coordmap, t0.y).y; t0.z = texture1D(coordmap, t0.z).z; t1.x = texture1D(coordmap, t1.x).x; t1.y = texture1D(coordmap, t1.y).y; t1.z = texture1D(coordmap, t1.z).z; } s0 = texture3D(volumeTexture, t0).x; s1 = texture3D(volumeTexture, t1).x; if (midx > 0) { if ((texture3D(volumeTexture, t0)[midx] != 0.0) || (texture3D(volumeTexture, t1)[midx] != 0.0)) { missing = true; } } // Current Z value along ray and current (accumulated) color float fragDepth = zStartEye; vec4 fragColor = vec4(0.0, 0.0, 0.0, 0.0); // Make sure gl_FragDepth is set for all execution paths gl_FragDepth = zStopWin; // Composite from front to back // false after first isosurface interesected bool first = true; for (int i = 0; i0 && ! fast) { isoTexCoord = tex2lay(isoTexCoord, zidx); if (isoTexCoord.x < 0.0) { mydiscard(); return; } } else if (stretched) { isoTexCoord.x = texture1D(coordmap, isoTexCoord.x).x; isoTexCoord.y = texture1D(coordmap, isoTexCoord.y).y; isoTexCoord.z = texture1D(coordmap, isoTexCoord.z).z; } #endif #ifdef MAPPED // pseudo color isosurface with 2nd variable // float var2 = texture3D(volumeTexture,isoTexCoord)[vidx]; vec4 color = vec4(texture1D(colormap, var2)); #else vec4 color = isocolor; #endif #ifdef LIGHTING // compute surface gradient at ray's intersection with isosurface vec3 gradient = gl_NormalMatrix * Gradient(dimensions, isoTexCoord); float diffuse = 0.0; float specular = 0.0; if (length(gradient) > 0.0 && fragDepth != 0.0) { gradient = normalize(gradient); // Ugh. Need to convert ray intersection point to eye coords vec4 posClip = vec4( posNDC, -gl_ProjectionMatrix[3].z / fragDepth - gl_ProjectionMatrix[2].z, 1.0); vec4 eyePos = gl_ProjectionMatrixInverse * posClip; eyePos /= eyePos.w; //use Phong illumination if non-zero gradient vec3 lightVec = normalize(lightDirection); vec3 halfv = reflect(-lightVec, gradient); vec3 viewVec = normalize(-eyePos.xyz); diffuse = abs(dot(lightVec, gradient)); if (diffuse > 0.0) { specular = pow(abs(dot(halfv, viewVec)), expS); } } diffuse = kd * diffuse; specular = ks * specular; color.xyz = color.xyz * (ka+diffuse) + vec3(specular*lightColor); #endif #ifndef DEPTHPEEL // blend fragment color with front to back compositing operator fragColor = (vec4(1.0)- vec4(fragColor.a))*color + fragColor; #else // no manual blending, depth peeling will automatically do this fragColor = color; #endif // The depth buffer value will be the first ray-isosurface // intersection. N.B. may not be best choice #ifndef DEPTHPEEL if (first) { fragDepth = zStartEye + (float(i) * deltaZ) + (deltaZ*weight); first = false; } #else // the depth peeling algorithm has two parts with regards to output: // initial pass: get the first depth layer, and run // it through a depth test // fragDepth = zStartEye + (float(i) * deltaZ) + (deltaZ*weight); fragDepth = fragDepth == 0.0 ? -1.0 : (fragDepth * gl_ProjectionMatrix[2].z + gl_ProjectionMatrix[3].z) / -fragDepth; fragDepth = fragDepth * ((f-n)/2) + (n+f)/2; // isosurface found, check layer and depth test if not // initial rendering // if(currentLayer == 0){ //kick out colors normally for depth testing gl_FragDepth = fragDepth; gl_FragColor = vec4(fragColor.r, fragColor.g, fragColor.b, fragColor.a); hit = true; break; } else { //run the iso loop until the surface passes the depth peeling check, //i.e. the iso surface has a depth greater than the previously recorded depth //find texture coord of fragment vec2 texCoord = vec2(gl_FragCoord.x / width, gl_FragCoord.y / height); //retrieve the depth of the frag that passed the initial gl_less test, could be currentlayer ==0 //or another fragment from a different renderer float depthWin = texture2D(previousPass, texCoord).x; if (depthWin < fragDepth && abs(depthWin - fragDepth) > .00000000000000001){ gl_FragDepth = fragDepth; gl_FragColor = vec4(fragColor.r, fragColor.g, fragColor.b, fragColor.a); hit = true; break; } } layerCount++; #endif #ifndef DEPTHPEEL // // early ray termination // if (fragColor.a >= 0.95) break; #endif } texCoord0 = texCoord1; texCoord1 = texCoord1+deltaVec; t1 = texCoord1; s0 = s1; if (zidx>0 && ! fast) { t1 = tex2lay(t1, zidx); } else if (stretched) { t1.x = texture1D(coordmap, t1.x).x; t1.y = texture1D(coordmap, t1.y).y; t1.z = texture1D(coordmap, t1.z).z; } // // If outside of texture we're done // if (t1.x < 0.0 || t1.y < 0.0 || t1.z < 0.0 || t1.x > 1.0 || t1.y > 1.0 || t1.z > 1.0) { break; } #ifdef DEPTHPEEL if (hit) break; #endif // if texCoord1 is inside the volume then lookup new // value for s1. Otherwise s1 == s0 and there is no // ray-surface intersection // s1 = texture3D(volumeTexture, t1).x; if (midx > 0) { if (missing) s0 = s1; missing = (texture3D(volumeTexture, t1)[midx] != 0.0); } } #ifdef DEPTHPEEL if(!hit) discard; #endif if (fragColor.a == 0.0) { mydiscard(); return; } // Convert depth from eye coordinates back to window coords #ifndef DEPTHPEEL fragDepth = fragDepth == 0.0 ? -1.0 : (fragDepth * gl_ProjectionMatrix[2].z + gl_ProjectionMatrix[3].z) / -fragDepth; //note: update to use DepthPeel include function //DepthPeel(fragDepth * ((f-n)/2) + (n+f)/2, fragColor); gl_FragDepth = fragDepth * ((f-n)/2) + (n+f)/2; gl_FragColor = fragColor; #endif } ================================================ FILE: share/shaders/main/Iso.vgl ================================================ //----------------------------------------------------------------------- // Vertex shader main //----------------------------------------------------------------------- uniform mat4 glModelViewProjectionMatrix; varying vec4 position; #ifdef LIGHTING varying vec3 view; #endif void main(void) { gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex; position = gl_Position; #ifdef LIGHTING view = normalize(-gl_Position.xyz); #endif } ================================================ FILE: share/shaders/main/ProgTexture.fgl ================================================ uniform bool first; uniform sampler2D previousPass; uniform float width; uniform float height; uniform sampler2D image; void main(){ vec4 color = texture2D(image, gl_TexCoord[3].st).rgba; if(first){ gl_FragColor = color; gl_FragDepth = gl_FragCoord.z; } else{ vec2 texCoord = vec2(gl_FragCoord.x / width, gl_FragCoord.y / height); float depth = texture2D(previousPass, texCoord).z; if (depth > gl_FragCoord.z || abs(depth - gl_FragCoord.z) < .00000000001 || depth == 1.0 || depth == 0.0) discard; gl_FragDepth = gl_FragCoord.z; gl_FragColor= color; } } ================================================ FILE: share/shaders/main/ProgTexture.vgl ================================================ void main(){ gl_TexCoord[3] = gl_MultiTexCoord3; gl_FrontColor = gl_Color; gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; } ================================================ FILE: share/shaders/main/SphericalDVR.fgl ================================================ #include permute.hgl #include invpermute.hgl uniform sampler1D colormap; uniform sampler3D volumeTexture; uniform vec3 tmin; uniform vec3 tmax; // min and max texture coordinates in range uniform vec3 dmin; uniform vec3 dmax; // min and max spherical coordinates uniform vec3 permutation; uniform bvec2 clip; vec3 permute(vec3 v); vec3 invPermute(vec3 v); //------------------------------------------------------------------ // Fragment shader main //------------------------------------------------------------------ void main(void) { const float pi = 3.14159; vec3 cartesian = permute(gl_TexCoord[0].xyz); vec3 spherical; cartesian = dmax.z * (cartesian * 2.0 - 1.0); spherical.z = length(cartesian.xyz); if (spherical.z > dmax.z || spherical.z < dmin.z) { gl_FragColor = vec4(0,0,0,0); } else { spherical.x = asin(clamp(cartesian.y / length(cartesian.yz), -1.0, 1.0)); spherical.y = acos(clamp(cartesian.x / spherical.z, -1.0, 1.0)); if (cartesian.z >= 0.0) { if (spherical.x < 0.0) spherical.x += 2.0*pi; } else { spherical.x = pi - spherical.x; } // Spherical coordinates // spherical.y (0, pi) // spherical.x (0, 2pi) spherical.y = (spherical.y / (pi)); spherical.x = (spherical.x / (2.0*pi)); // Normalized spherical coordinates // spherical.z (0, 1) // spherical.y (0, 1) // spherical.x (0, 1) if ((clip.y && (spherical.y < dmin.y || spherical.y > dmax.y)) || (clip.x && (spherical.x < dmin.x || spherical.x > dmax.x))) { gl_FragColor = vec4(1,1,1,0); } else { // Texture coordinates (dmin, dmax) -> (tmin, tmax) spherical = (spherical - dmin) * ((tmax - tmin) / (dmax - dmin))+tmin; vec4 intensity = vec4(texture3D(volumeTexture, invPermute(spherical))); gl_FragColor = vec4 (texture1D(colormap, intensity.x)); } } } ================================================ FILE: share/shaders/main/SphericalDVR.vgl ================================================ //----------------------------------------------------------------------- // Vertex shader main //----------------------------------------------------------------------- #ifdef LIGHTING varying vec3 ecPosition; #endif void main(void) { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; gl_TexCoord[0] = gl_MultiTexCoord0; #ifdef LIGHTING ecPosition = vec3(gl_ModelViewMatrix * gl_Vertex); #endif } ================================================ FILE: share/shaders/main/depthpeeling.fgl ================================================ uniform sampler2D previousPass; uniform float width; uniform float height; void main() { if ((width == 0.0) || (height == 0.0)) discard; vec2 texCoord = vec2(gl_FragCoord.x / width, gl_FragCoord.y / height); float depth = texture2D(previousPass, texCoord).z; float bias = .00000000000000001; if (depth > gl_FragCoord.z || abs(depth - gl_FragCoord.z) < bias)// || depth == 1.0 || depth == 0.0) // -old comparisons, should not be necessary discard; gl_FragDepth = gl_FragCoord.z; gl_FragColor= vec4(gl_Color.r, gl_Color.g, gl_Color.b, gl_Color.a); } ================================================ FILE: share/shaders/main/depthpeeling.vgl ================================================ void main() { gl_FrontColor = gl_Color; gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; } ================================================ FILE: share/shaders/main/texSampler.fgl ================================================ uniform sampler2D texUnit; uniform float width; uniform float height; void main() { if (width == 0.0 || height == 0.0) discard; vec2 texCoord = vec2(gl_FragCoord.x / width, gl_FragCoord.y / height); vec4 color = texture2D(texUnit, texCoord); gl_FragColor = color; gl_FragDepth = gl_FragCoord.z; } ================================================ FILE: share/shaders/main/texSampler.vgl ================================================ void main() { gl_FrontColor = gl_Color; gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; } ================================================ FILE: share/shaders/texSampler.efc ================================================ texSampler texSampler texSampler ================================================ FILE: share/udunits/udunits2-accepted.xml ================================================ 60 s minute min 60 min hour h hr 24 h day d 3.141592653589793238462643383279 pi π (pi/180) rad arc_degree ° angular_degree degree arcdeg °/60 arc_minute ' angular_minute arcminute arcmin '/60 arc_second " angular_second arcsecond arcsec dm^3 liter L litre l 1000 kg metric_ton t tonne 1.60217733e-19 J electronvolt eV electron_volt 1.6605402e-27 kg unified_atomic_mass_unit u atomic_mass_unit atomicmassunit amu 1.495979e11 m astronomical_unit ua 1852 m nautical_mile nautical_mile/hour international_knot knot_international knot 1e-10 m angstrom ångström Å dam^2 are a 100 are hectare 100 fm^2 barn b 1000 hPa bar cm/s^2 gal 3.7e10 Bq curie Ci 2.58e-4 C/kg roentgen R cSv rem ================================================ FILE: share/udunits/udunits2-base.xml ================================================ meter m metre kilogram kg second s ampere A kelvin K mole mol candela cd ================================================ FILE: share/udunits/udunits2-common.xml ================================================ s sec A amp K °K degree_kelvin degrees_kelvin degree_K degrees_K degreeK degreesK deg_K degs_K degK degsK cd candle mole einstein Hz baud Bd bps degree_Celsius celsius degree_C degrees_C degreeC degreesC deg_C degs_C degC degsC knot kt kts 6.02214179e23/mol avogadro_constant 0.01 percent % 1e-6 ppm ppmv 1e-9 ppb ppbv 1e-12 ppt pptv 1e-15 ppq ppqv 0.9 arc_degree grade 2 pi rad circle cycle turn revolution rotation arc_degree degree_north degrees_north degree_N degrees_N degreeN degreesN degree_east degrees_east degree_E degrees_E degreeE degreesE degree_true degrees_true degree_T degrees_T degreeT degreesT -1 degree_east degree_west degrees_west degree_W degrees_W degreeW degreesW 2.916667e-2 kg assay_ton 2.834952e-2 kg avoirdupois_ounce 4.5359237e-1 kg avoirdupois_pound pound lb 2e-4 kg carat 6.479891e-5 kg grain gr 5.080235e1 kg long_hundredweight 1.555174e-3 kg pennyweight 4.535924e1 kg short_hundredweight 14.59390 kg slug 3.110348e-2 kg troy_ounce apothecary_ounce 3.732417e-1 kg troy_pound apothecary_pound 20 grain scruple 60 grain apdram 480 grain apounce 5760 grain appound 94 pound bag 2000 pound short_ton ton 2240 pound long_ton 1e-15 m fermi 9.46073e15 m light_year 1e-6 m micron 2.54e-5 m mil 3.085678e16 m parsec 3.514598e-4 m printers_point 2.011684e1 m chain 12 printers_point printers_pica pica nautical_mile nmile (1200/3937) m US_survey_foot US_survey_feet 3 US_survey_feet US_survey_yard 5280 US_survey_feet US_survey_mile US_statute_mile 16.5 US_survey_feet rod pole perch 660 US_survey_feet furlong 6 US_survey_feet fathom 2.54 cm international_inch inch in 12 international_inches international_foot international_feet foot feet ft 3 international_feet international_yard yard yd 5280 international_feet international_mile mile mi inch/72 big_point inch/3 barleycorn 191.835 foot arpentlin rotation/second rotation_per_second rotations_per_second rps cps rotation/minute rpm 1.111111e-7 kg/m denier 1e-6 kg/m tex 5.72135e-11 kg/(Pa.s.m^2) perm_0C perms_0C 5.74525e-11 kg/(Pa.s.m^2) perm_23C perms_23C 5.067075e-10 m^2 circular_mil 9.869233e-13 m^2 darcy 160 rod^2 acre 1.233489e3 m^3 acre_foot acre_feet 2.359737e-3 m^3 board_foot board_feet 3.523907e-2 m^3 bushel bu bushel/4 peck pk 4.546090e-3 m^3 Canadian_liquid_gallon 4.404884e-3 m^3 US_dry_gallon cm^3 cc 1 m^3 stere 2.831685 m^3 register_ton US_dry_gallon/4 US_dry_quart dry_quart US_dry_gallon/8 US_dry_pint dry_pint 3.785412e-3 m^3 US_liquid_gallon liquid_gallon gallon 42 US_liquid_gallon barrel bbl barrel/4 firkin US_liquid_gallon/4 US_liquid_quart liquid_quart quart US_liquid_gallon/8 US_liquid_pint liquid_pint pint pt US_liquid_gallon/16 US_liquid_cup liquid_cup cup US_liquid_gallon/32 US_liquid_gill liquid_gill gill US_liquid_gallon/128 US_fluid_ounce US_liquid_ounce fluid_ounce liquid_ounce oz floz US_fluid_ounce/2 tablespoon Tbl Tbsp tbsp Tblsp tblsp US_fluid_ounce/8 fldr US_fluid_ounce/16 dram dr tablespoon/3 teaspoon tsp 4.546090e-3 m^3 UK_liquid_gallon UK_liquid_gallon/4 UK_liquid_quart UK_liquid_gallon/8 UK_liquid_pint UK_liquid_gallon/16 UK_liquid_cup UK_liquid_gallon/32 UK_liquid_gill UK_liquid_gallon/160 UK_fluid_ounce UK_liquid_ounce lg(re (1e-6 m)^3) BZ 1e-8 s shake 8.616409e4 s sidereal_day 3.590170e3 s sidereal_hour 5.983617e1 s sidereal_minute 0.9972696 s sidereal_second 3.155815e7 s sidereal_year 3.15569259747e7 s tropical_year year yr 29.530589 day lunar_month 365 day common_year 366 day leap_year 365.25 day Julian_year 365.2425 day Gregorian_year 27.321661 day sidereal_month 27.321582 day tropical_month 14 day fortnight 7 day week 0.01 s jiffy 1e9 year eon year/12 month 1e6 m^3/s sverdrup 9.806650 m/s^2 standard_free_fall standard_free_fall gravity gravity 1000 kg/m^3 conventional_water water H2O h2o gravity 999.972 kg/m^3 water_4C waters_4C water_39F waters_39F gravity 999.001 kg/m^3 water_60F waters_60F gravity 13595.10 kg/m^3 mercury_0C mercuries_0C mercury_32F mercuries_32F conventional_mercury conventional_mercuries Hg gravity 13556.8 kg/m^3 mercury_60F mercuries_60F standard_free_fall force 1e-5 N dyne 9.806650e-3 N pond 9.806650 N force_kilogram kilogram_force kilograms_force kgf 2.780139e-1 N force_ounce ounce_force ounces_force ozf 4.4482216152605 N force_pound pound_force pounds_force lbf 1.382550e-1 N poundal gram force gram_force grams_force force_gram gf 2000 force_pound force_ton ton_force tons_force 1000 lbf kip 1.01325e5 Pa standard_atmosphere atmosphere atm 1 kg gravity/cm2 technical_atmosphere at cm H2O cm_H2O cmH2O inch water_39F inch_H2O_39F inches_H2O_39F inch water_60F inch_H2O_60F inches_H2O_60F foot water foot_water feet_water foot_H2O feet_H2O footH2O feetH2O ftH2O fth2o cm Hg cm_Hg cmHg mm mercury_0C millimeter_Hg_0C millimeters_Hg_0C inch mercury_32F inch_Hg_32F inches_Hg_32F inch mercury_60F inch_Hg_60F inches_Hg_60F mm Hg millimeter_Hg millimeters_Hg torr mm_Hg mm_hg mmHg mmhg inch Hg inch_Hg inches_Hg in_Hg inHg 1 pound gravity/in^2 psi kip/in^2 ksi 0.1 N/m^2 barie barye lg(re 20e-6 Pa) B_SPL 1e-1 Pa.s poise 1e-4 m^2/s stokes St 10/(Pa.s) rhe 1e-7 J erg 1.05505585262e3 J IT_Btu IT_Btus Btu Btus 1.05506e8 J EC_therm 4.184000 J thermochemical_calorie 4.1868 J IT_calorie calorie cal 4.184 MJ/kg TNT 4.184e9 J ton_TNT tons_TNT 1.054804e8 J US_therm therm thm watt.hour watthour 1e9 eV bev V.A voltampere VA 9.80950e3 W boiler_horsepower 7.456999e2 W shaft_horsepower horsepower hp 7.35499e2 W metric_horsepower 7.460000e2 W electric_horsepower 7.46043e2 W water_horsepower 7.4570e2 W UK_horsepower 12000 Btu/hr refrigeration_ton ton_of_refrigeration tons_of_refrigeration lg(re 1 W) BW lg(re 1 mW) Bm 1.55e-1 K.m^2/W clo 10 A abampere 7.957747e-1 A gilbert 3.335640e-10 A statampere 10 A biot 1e9 F abfarad 1e-9 H abhenry 1e9 S abmho 1e-9 ohm abohm 1e-8 V abvolt 1.602176487e-19 C e 9.64957e4 C chemical_faraday 9.65219e4 C physical_faraday 9.648531e4 C C12_faraday faraday 1e-9 T gamma 1e-4 T gauss 1e-8 Wb maxwell 7.957747e1 A/m oersted Oe 3.335640e-10 C statcoulomb 1.112650e-12 F statfarad 8.987554e11 H stathenry 1.112650e-12 S statmho 8.987554e11 ohm statohm 2.997925e2 V statvolt 1.256637e-7 Wb unit_pole lg(re 1 V) BV lg(re 0.775 V) Bv lg(re 1e-6 V) BµV K/1.8 °R degree_rankine degrees_rankine degreeR degreesR degree_R degrees_R degR degsR deg_R degs_R °R @ 459.67 °F fahrenheit degree_fahrenheit degrees_fahrenheit degreeF degreesF degree_F degrees_F degF degsF deg_F degs_F 1.076391e-1 lx footcandle 3.426259 cd/m^2 footlambert (1e4/pi) cd/m^2 lambert 1e4 cd/m^2 stilb sb 1e4 lm/m^2 phot ph 1 cd/m^2 nit nt 4.184000e4 J/m^2 langley cd/(pi m^2) blondel apostilb 100/m kayser gravity geopotential dynamic gp 2056 hours work_year work_year/12 work_month 1e-6 m^2 s^-1 K kg^-1 potential_vorticity_unit PVU 1 count 446.2 micromoles/meter^2 dobson DU ================================================ FILE: share/udunits/udunits2-derived.xml ================================================ radian rad rad^2 steradian sr 1/s hertz Hz 1e-3 kg gram g m.kg/s^2 newton N N/m^2 pascal Pa N.m joule J J/s watt W s.A coulomb C W/A volt V C/V farad F V/A ohm Ω A/V siemens S V.s weber Wb Wb/m^2 tesla T Wb/A henry H K @ 273.15 degree_Celsius degrees_Celsius °C cd.sr lumen lm lm/m^2 lux lx mol/s katal kat 1/s becquerel Bq J/kg gray Gy J/kg sievert Sv ================================================ FILE: share/udunits/udunits2-prefixes.xml ================================================ 1e24 yotta Y 1e21 zetta Z 1e18 exa E 1e15 peta P 1e12 tera T 1e9 giga G 1e6 mega M 1e3 kilo k 100 hecto h 10 deka da .1 deci d .01 centi c 1e-3 milli m 1e-6 micro µ μ u 1e-9 nano n 1e-12 pico p 1e-15 femto f 1e-18 atto a 1e-21 zepto z 1e-24 yocto y ================================================ FILE: share/udunits/udunits2.xml ================================================ udunits2-prefixes.xml udunits2-base.xml udunits2-derived.xml udunits2-accepted.xml udunits2-common.xml ================================================ FILE: site_files/site.NCAR ================================================ if (APPLE) set (THIRD_PARTY_DIR /usr/local/VAPOR-Deps/current ) #set (QTDIR /usr/local/VAPOR-Deps/current/Qt/5.15.8/clang_64 ) set (QTDIR /usr/local/VAPOR-Deps/current/Qt/lib/cmake ) list (APPEND CMAKE_PREFIX_PATH ${QTDIR}/lib/cmake ) set (OSPRAYDIR ${THIRD_PARTY_DIR}/Ospray ) elseif (UNIX AND NOT APPLE) # Try to heuristically configure our third party libraries if (NOT DEFINED THIRD_PARTY_DIR) # If we're on casper, and set third party libraries accordingly execute_process( COMMAND uname -a COMMAND grep -o "casper" RESULT_VARIABLE casperFound OUTPUT_STRIP_TRAILING_WHITESPACE ) if ("${casperFound}" EQUAL "0") set (THIRD_PARTY_DIR /glade/campaign/cisl/vast/vapor/third-party/current) message(STATUS "***") message(STATUS "***") message(STATUS " NOTICE: TO BUILD ON CASPER, NCAR'S ENVIRONMENT MUST BE UNLOADED WITH") message(STATUS " module --force unload ncarenv") message(STATUS " TO RUN VAPOR ON CASPER, LD_LIBRARY_PATH MUST BE MODIFIED TO") message(STATUS " export LD_LIBRARY_PATH=${THIRD_PARTY_DIR}") message(STATUS "***") message(STATUS "***") else() # Otherwise set the library path to our usual target set (THIRD_PARTY_DIR /usr/local/VAPOR-Deps/current ) endif() endif() if (NOT DEFINED QTDIR) #set (QTDIR ${THIRD_PARTY_DIR}/Qt/5.15.2/gcc_64) set (QTDIR ${THIRD_PARTY_DIR}) endif() set (CMAKE_PREFIX_PATH ${QTDIR}/lib/cmake ) set (Qt5Core_DIR ${QTDIR}/lib/cmake/Qt5Core ) set (QT_QMAKE_EXECUTABLE ${QTDIR}/gcc_64/bin/qmake ) set (OSPRAYDIR ${THIRD_PARTY_DIR}/Ospray ) else () set (THIRD_PARTY_DIR C:/2019-Aug) set (QTDIR ${THIRD_PARTY_DIR}/Qt/5.13.2/msvc2015_64) set (CMAKE_PREFIX_PATH ${QTDIR}/lib/cmake/Qt5) set (OSPRAYDIR ${THIRD_PARTY_DIR}/Ospray ) endif () set (THIRD_PARTY_LIB_DIR "${THIRD_PARTY_DIR}/lib") if (UNIX) if (NOT DEFINED PYTHONVERSION) set (PYTHONVERSION 3.9) endif() if (APPLE) set (PYTHONDIR ${THIRD_PARTY_DIR}/Resources) set (PYTHONPATH ${PYTHONDIR}/lib/python${PYTHONVERSION}) else () set (PYTHONDIR ${THIRD_PARTY_DIR}) set (PYTHONPATH ${THIRD_PARTY_LIB_DIR}/python${PYTHONVERSION}) endif() set (EXTRA_LIBS_SEARCH ${EXTRA_LIBS_SEARCH} dbus) elseif (WIN32) set (PYTHONVERSION 36) set (PYTHONPATH ${THIRD_PARTY_DIR}/Python${PYTHONVERSION}) endif () set (THIRD_PARTY_INC_DIR "${THIRD_PARTY_DIR}/include") if (WIN32) set (NUMPY_INCLUDE_DIR "${PYTHONPATH}/Lib/site-packages/numpy/core/include") else () set (NUMPY_INCLUDE_DIR "${PYTHONPATH}/site-packages/numpy/core/include") endif () set (MAP_IMAGES_PATH "${THIRD_PARTY_DIR}/share/images") include (../vapor-site/site.cmake OPTIONAL) ================================================ FILE: test_apps/CMakeLists.txt ================================================ if (BUILD_TEST_APPS) add_subdirectory (datamgr) add_subdirectory (grid_iter) add_subdirectory (params2) add_subdirectory (pyengine) add_subdirectory (smokeTests) add_subdirectory (quadtreerectangle) add_subdirectory (ParamsMgr) add_subdirectory (udunits) add_subdirectory (OpenMP) # add_subdirectory (controlExec) endif() ================================================ FILE: test_apps/OpenMP/CMakeLists.txt ================================================ add_executable (GetRange GetRange.cpp) target_link_libraries (GetRange vdc) set_target_properties(GetRange PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${test_output_dir}") ================================================ FILE: test_apps/OpenMP/GetRange.cpp ================================================ #include #include #include #include #include #include #include "vapor/RegularGrid.h" #include "vapor/OpenMPSupport.h" // Allocate a bunch of raw pointers. // The caller will need to delete[] them. // auto AllocateBlocks(std::array bs, std::array dims) -> std::vector { size_t block_size = 1; size_t nblocks = 1; for (size_t i = 0; i < bs.size(); i++) { block_size *= bs[i]; nblocks *= ((dims[i] - 1) / bs[i]) + 1; } auto blks = std::vector(nblocks, nullptr); for (size_t i = 0; i < nblocks; i++) blks[i] = new float[block_size]; return (blks); } // Copy of Grid::GetRange() function from VAPOR release 3.6 // void GetRange_36(VAPoR::Grid* g, float range[2]) { float missingValue = g->GetMissingValue(); auto itr = g->cbegin(); auto enditr = g->cend(); // Edge case: all values are missing values. // range[0] = range[1] = missingValue; while (*itr == missingValue && itr != enditr) { ++itr; } if (itr == enditr) return; range[0] = *itr; range[1] = range[0]; while (itr != enditr) { if (*itr < range[0] && *itr != missingValue) range[0] = *itr; else if (*itr > range[1] && *itr != missingValue) range[1] = *itr; ++itr; } } int main(int argc, char* argv[]) { if (argc != 2) { std::cout << "Help: This program measures the serial and parallel (OpenMP) execution time\n" " given a regular grid of size (Dim x Dim x Dim).\n" "Note: the environment variable OMP_NUM_THREADS controls the number of threads.\n" "Usage: ./GetRange Dim\n"; return 1; } const size_t dim = std::stol(argv[1]); const auto dims = std::array{dim, dim, dim}; size_t num_threads = 1; #pragma omp parallel { if (omp_get_thread_num() == 0) num_threads = omp_get_num_threads(); } std::printf("Testing a grid of size (%ld, %ld, %ld), using %ld threads...\n", dim, dim, dim, num_threads); // Create a grid to test const auto blk_size = std::array{128, 128, 128}; auto blks = AllocateBlocks(blk_size, dims); auto* grid = new VAPoR::RegularGrid(dims, blk_size, blks, {0.0, 0.0, 0.0}, {100.0, 100.0, 100.0}); // Fill in random values std::random_device rd; std::mt19937 gen(rd()); std::uniform_real_distribution dist(-1.0, 10.0); const auto stride_size = dim * dim * dim / num_threads; #pragma omp parallel for for (size_t i = 0; i < num_threads; i++) { auto beg = grid->begin() + i * stride_size; auto end = beg; if (i < num_threads - 1) end += stride_size; else end = grid->end(); for (auto itr = beg; itr != end; ++itr) *itr = dist(gen); } // Time a serial run float range_36[2] = {0.0, 1.1}; const auto serial_start = std::chrono::steady_clock::now(); GetRange_36(grid, range_36); const auto serial_end = std::chrono::steady_clock::now(); const auto serial_time = std::chrono::duration_cast(serial_end - serial_start).count(); std::cout << "GetRange() in serial time (milliseconds): " << serial_time << std::endl; // Time a parallel run float range_omp[2] = {2.2, 3.3}; const auto omp_start = std::chrono::steady_clock::now(); grid->GetRange(range_omp); const auto omp_end = std::chrono::steady_clock::now(); const auto omp_time = std::chrono::duration_cast(omp_end - omp_start).count(); std::cout << "GetRange() in OpenMP time (milliseconds): " << omp_time << std::endl; // Clean up delete grid; grid = nullptr; for (size_t i = 0; i < blks.size(); i++) { delete[](blks[i]); blks[i] = nullptr; } return 0; } ================================================ FILE: test_apps/ParamsMgr/CMakeLists.txt ================================================ add_executable (test_ParamsMgr test_ParamsMgr.cpp) set_target_properties(test_ParamsMgr PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${debug_output_dir}") target_link_libraries (test_ParamsMgr vdc params common wasp) ================================================ FILE: test_apps/ParamsMgr/file.xml ================================================ 0 0 1 0 0 0 0 0 0.1 2 0 0 0 0 0 0 0 1 1 1 0 4 10 1 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 100 100 0.1000000014901161 0.800000011920929 0.800000011920929 0.800000011920929 0 0 1 0 0 1 0 0 1 0 0 0 0.300000011920929 0.300000011920929 0.300000011920929 20 1 1 1 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 1 0 0 1 1 1 1 1 1 1 1 NULL P PB PH NULL U10 0 -49.3205451965332 33.28469848632812 1 1 0 0 -49.3205451965332 33.28469848632812 5 0.5 0 0 0.3333333333333333 0.3333333333333333 0.6666666666666666 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 4 0.6444444444444445 0.695 0.757 0 0.9666666666666667 0.977 0.706 0.99 2 1 0 0 0 -845627.125 1991855.625 0 412793.375 3219581.5 0 0 10 4 6 1 1 1 0.1 0.1 0.1 0.1 0 1 0 0 1 1 1 1 1 1 1 1 NULL P PB PH NULL V10 0 -41.49079132080078 43.95055770874023 1 1 0 0 -41.49079132080078 43.95055770874023 5 0.5 0 0 0.3333333333333333 0.3333333333333333 0.6666666666666666 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 4 0.6444444444444445 0.695 0.757 0 0.9666666666666667 0.977 0.706 0.99 2 1 0 0 0 -845627.125 1991855.625 0 412793.375 3219581.5 0 0 10 4 6 1 1 1 0.1 0.1 0.1 0.1 0 1 0 0 0 10 10 1 0 0 1 1 1 1 1 4 1 1 1 1 NULL P PB PH NULL P 0 -62.61578750610352 45.91978073120117 1 1 0 0 -62.61578750610352 45.91978073120117 5 0.5 0 0 0.3333333333333333 0.3333333333333333 0.6666666666666666 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 4 0.6444444444444445 0.695 0.757 0 0.9666666666666667 0.977 0.706 0.99 2 0 0 0 0 -845627.125 1991855.625 31.70084762573242 412793.375 3219581.5 20262.4765625 0 10 4 6 1 1 1 0.1 0.1 0.1 0.1 ================================================ FILE: test_apps/ParamsMgr/test_ParamsMgr.cpp ================================================ #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; struct { string ifile; OptionParser::Boolean_T help; OptionParser::Boolean_T quiet; OptionParser::Boolean_T debug; } opt; OptionParser::OptDescRec_T set_opts[] = { {"ifile", 1, "", "Construct Xml tree from a file"}, {"help", 0, "", "Print this message and exit"}, {"quiet", 0, "", "Operate quitely"}, {"debug", 0, "", "Debug mode"}, {NULL}}; OptionParser::Option_T get_options[] = {{"ifile", Wasp::CvtToCPPStr, &opt.ifile, sizeof(opt.ifile)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {NULL}}; const char *ProgName; int main(int argc, char **argv) { OptionParser op; string s; ProgName = FileUtils::LegacyBasename(argv[0]); MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << endl; op.PrintOptionHelp(stderr); exit(0); } if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); } if (argc != 2) { cerr << "Usage: " << ProgName << " VDCMaster.nc [options] " << endl; op.PrintOptionHelp(stderr); exit(1); } string vdcfile = argv[1]; DataStatus dataStatus; string dataSetName = "mydata"; int rc = dataStatus.Open(vector{vdcfile}, vector(), dataSetName, "vdc"); if (rc < 0) return (1); ParamsMgr *pm = new ParamsMgr(); pm->SetSaveStateEnabled(false); string winName = "myWindow"; pm->AddDataMgr(dataSetName, dataStatus.GetDataMgr(dataSetName)); TwoDDataParams *twoDparams0 = (TwoDDataParams *)pm->CreateRenderParamsInstance(winName, dataSetName, TwoDDataParams::GetClassType(), "twoD0"); twoDparams0->SetVariableName("U10"); TwoDDataParams *twoDparams1 = (TwoDDataParams *)pm->CreateRenderParamsInstance(winName, dataSetName, TwoDDataParams::GetClassType(), "twoD1"); twoDparams1->SetVariableName("V10"); pm->SetSaveStateEnabled(true); pm->UndoRedoClear(); pm->SaveToFile("file.xml"); twoDparams1->SetVariableName("U1"); twoDparams1->SetCompressionLevel(1); pm->RemoveVisualizer(winName); pm->Undo(); pm->Undo(); pm->Undo(); pm->Redo(); pm->Redo(); pm->Redo(); pm->Undo(); pm->Undo(); pm->Undo(); pm->SaveToFile("fileUndo.xml"); cout << "Allocated XmlNode count before delete " << XmlNode::GetAllocatedNodes().size() << endl; //#define DEBUG #ifdef DEBUG const vector &nodes = XmlNode::GetAllocatedNodes(); for (int i = 0; i < nodes.size(); i++) { cout << " " << nodes[i]->GetTag() << " " << nodes[i] << endl; } #endif delete pm; cout << "Allocated XmlNode count after delete " << XmlNode::GetAllocatedNodes().size() << endl; #ifdef DEBUG for (int i = 0; i < nodes.size(); i++) { cout << " " << nodes[i]->GetTag() << " " << nodes[i] << endl; } #endif } ================================================ FILE: test_apps/TransferFunction/test_TransferFunction.cpp ================================================ #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include using namespace Wasp; using namespace VAPoR; struct { string ifile; OptionParser::Boolean_T help; OptionParser::Boolean_T quiet; OptionParser::Boolean_T debug; } opt; OptionParser::OptDescRec_T set_opts[] = { {"ifile", 1, "", "Construct Xml tree from a file"}, {"help", 0, "", "Print this message and exit"}, {"quiet", 0, "", "Operate quitely"}, {"debug", 0, "", "Debug mode"}, {NULL}}; OptionParser::Option_T get_options[] = {{"ifile", Wasp::CvtToCPPStr, &opt.ifile, sizeof(opt.ifile)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {NULL}}; const char *ProgName; int main(int argc, char **argv) { OptionParser op; string s; ProgName = Basename(argv[0]); MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << endl; op.PrintOptionHelp(stderr); exit(0); } if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); } if (argc != 1) { cerr << "Usage: " << ProgName << endl; op.PrintOptionHelp(stderr); exit(1); } ParamsBase::StateSave save; TransferFunction *tf = new TransferFunction(&save); tf->SaveToFile("/Users/clyne/foo.xml"); tf->LoadFromFile("/Users/clyne/foo.xml"); tf->SaveToFile("/Users/clyne/doo.xml"); delete tf; cout << "Allocated note count after delete : " << XmlNode::GetAllocatedNodes().size() << endl; } ================================================ FILE: test_apps/base64/CMakeLists.txt ================================================ add_executable (test_base64 test_base64.cpp) target_link_libraries (test_base64 common) ================================================ FILE: test_apps/base64/test_base64.cpp ================================================ #include #include #include #include #include using namespace Wasp; int main(int argc, char **argv) { const int sz = 1024; string str; int buf[sz]; int outbuf[sz]; Base64 base64; for (int i = 0; i < sz; i++) { buf[i] = i; } base64.Encode((unsigned char *)buf, sz * 4, str); cout << str; size_t n; if (base64.Decode(str, (unsigned char *)outbuf, &n) < 0) { cerr << "Base64::Decode() : " << Base64::GetErrMsg() << endl; exit(1); } for (int i = 0; i < sz; i++) { if (buf[i] != outbuf[i]) { cerr << "Buf mismatch at offset " << i << endl; } } exit(0); } ================================================ FILE: test_apps/controlExec/CMakeLists.txt ================================================ find_package(Qt4 REQUIRED) set (CMAKE_AUTOUIC ON) # This needs to appear before adding sources to work properly set (CMAKE_AUTOMOC ON) set (CMAKE_INCLUDE_CURRENT_DIR ON) add_executable (test_CE test_CE.cpp test_vizwin.cpp moc_test_vizwin.cpp) target_link_libraries (test_CE common vdc wasp params render ${GLEW} Qt4::QtCore Qt4::QtGui Qt4::QtOpenGL jpeg tiff) ================================================ FILE: test_apps/controlExec/file.xml ================================================ 0 0 1 0 0 0 0 0 0.1 2 0 0 0 0 0 0 0 1 1 1 0 4 10 1 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1280 598 0.1000000014901161 0.800000011920929 0.800000011920929 0.800000011920929 0 0 1 0 0 1 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 216416.875 -2605718.5 -1502258.75 1 0.300000011920929 0.300000011920929 0.300000011920929 20 1 1 1 -216416.875 2605718.5 1502258.75 -216416.875 2605718.5625 10147.08870506287 0 1 0 -0 -0 -1 0 0 0.25 0 0 0 0 1 0 0 0 -1 0 0 0 0 1 1 1 1 1 1 1 1 P PB PH NULL U10 0 -1 0 1 4 0.6444444444444445 0.695 0.757 0 0.9666666666666667 0.977 0.706 0.99 -1 0 1 0 0 -1 0 5 0.5 0 0 0.3333333333333333 0.3333333333333333 0.6666666666666666 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 0 -49.3205451965332 33.28469848632812 1 4 0.6444444444444445 0.695 0.757 0 0.9666666666666667 0.977 0.706 0.99 -49.3205451965332 33.28469848632812 1 0 0 -49.3205451965332 33.28469848632812 5 0.5 0 0 0.3333333333333333 0.3333333333333333 0.6666666666666666 0.6666666666666666 1 1 39.47841760435743 1 0 0.1 2 1 0 0 0 -845627.125 1991855.625 31.70084762573242 412793.375 3219581.5 20262.4765625 0 10 4 6 1 1 1 0.1 0.1 0.1 0.1 ================================================ FILE: test_apps/controlExec/moc_test_vizwin.cpp ================================================ /**************************************************************************** ** Meta object code from reading C++ file 'test_vizwin.h' ** ** Created by: The Qt Meta Object Compiler version 63 (Qt 4.8.6) ** ** WARNING! All changes made in this file will be lost! *****************************************************************************/ #include "../test_vizwin.h" #if !defined(Q_MOC_OUTPUT_REVISION) #error "The header file 'test_vizwin.h' doesn't include ." #elif Q_MOC_OUTPUT_REVISION != 63 #error "This file was generated using the moc from 4.8.6. It" #error "cannot be used with the include files from this version of Qt." #error "(The moc has changed too much.)" #endif QT_BEGIN_MOC_NAMESPACE static const uint qt_meta_data_VAPoR__Test_VizWin[] = { // content: 6, // revision 0, // classname 0, 0, // classinfo 0, 0, // methods 0, 0, // properties 0, 0, // enums/sets 0, 0, // constructors 0, // flags 0, // signalCount 0 // eod }; static const char qt_meta_stringdata_VAPoR__Test_VizWin[] = {"VAPoR::Test_VizWin\0"}; void VAPoR::Test_VizWin::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) { Q_UNUSED(_o); Q_UNUSED(_id); Q_UNUSED(_c); Q_UNUSED(_a); } const QMetaObjectExtraData VAPoR::Test_VizWin::staticMetaObjectExtraData = {0, qt_static_metacall}; const QMetaObject VAPoR::Test_VizWin::staticMetaObject = {{&QGLWidget::staticMetaObject, qt_meta_stringdata_VAPoR__Test_VizWin, qt_meta_data_VAPoR__Test_VizWin, &staticMetaObjectExtraData}}; #ifdef Q_NO_DATA_RELOCATION const QMetaObject &VAPoR::Test_VizWin::getStaticMetaObject() { return staticMetaObject; } #endif // Q_NO_DATA_RELOCATION const QMetaObject *VAPoR::Test_VizWin::metaObject() const { return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; } void *VAPoR::Test_VizWin::qt_metacast(const char *_clname) { if (!_clname) return 0; if (!strcmp(_clname, qt_meta_stringdata_VAPoR__Test_VizWin)) return static_cast(const_cast(this)); return QGLWidget::qt_metacast(_clname); } int VAPoR::Test_VizWin::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { _id = QGLWidget::qt_metacall(_c, _id, _a); if (_id < 0) return _id; return _id; } QT_END_MOC_NAMESPACE ================================================ FILE: test_apps/controlExec/test_CE.cpp ================================================ #include #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include #include #include #include #include #include #include "test_vizwin.h" using namespace Wasp; using namespace VAPoR; struct { int nts; int ts0; string vdcmaster; string sessionfile; string var; OptionParser::Boolean_T arrow; OptionParser::Boolean_T twoD; OptionParser::Boolean_T hello; OptionParser::Boolean_T help; OptionParser::Boolean_T quiet; OptionParser::Boolean_T debug; } opt; OptionParser::OptDescRec_T set_opts[] = {{"nts", 1, "1", "Number of timesteps to play"}, {"ts0", 1, "0", "First time step to play"}, {"ses", 1, "", "VAPOR session file to read"}, {"var", 1, "", "Primary variable name"}, {"arrow", 0, "", "Create arrow renderer"}, {"twoD", 0, "", "Create TwoD renderer"}, {"hello", 0, "", "Create hello renderer"}, {"help", 0, "", "Print this message and exit"}, {"quiet", 0, "", "Operate quietly"}, {"debug", 0, "", "Debug mode"}, {NULL}}; OptionParser::Option_T get_options[] = {{"nts", Wasp::CvtToInt, &opt.nts, sizeof(opt.nts)}, {"ts0", Wasp::CvtToInt, &opt.ts0, sizeof(opt.ts0)}, {"ses", Wasp::CvtToCPPStr, &opt.sessionfile, sizeof(opt.sessionfile)}, {"var", Wasp::CvtToCPPStr, &opt.var, sizeof(opt.var)}, {"arrow", Wasp::CvtToBoolean, &opt.arrow, sizeof(opt.arrow)}, {"twoD", Wasp::CvtToBoolean, &opt.twoD, sizeof(opt.twoD)}, {"hello", Wasp::CvtToBoolean, &opt.hello, sizeof(opt.hello)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {NULL}}; const char *ProgName; void ErrMsgCBHandler(const char *msg, int) { cerr << ProgName << " : " << msg << endl; } RenderParams *CreateRender(ControlExec *CE, string winName, string className, string name) { RenderParams *rp = NULL; ParamsMgr * pMgr = CE->GetParamsMgr(); int rc = CE->ActivateRender(winName, className, name, false); if (rc < 0) { cerr << "Failed to activate renderer type : " << className << endl; return NULL; } // Create a new barbs params to be used in rendering rp = pMgr->GetRenderParams(winName, className, name); if (!rp) { cerr << "Failed to get params for renderer type : " << className << endl; return NULL; } return (rp); } int CreateNew(ControlExec *CE, string winName) { int rc = CE->NewVisualizer(winName); if (rc < 0) { cerr << "Failed to creat visualizer " << endl; return -1; } RenderParams *rParams = NULL; if (opt.arrow) { string name = "arrow1"; ArrowParams *myRParams = NULL; myRParams = (ArrowParams *)CreateRender(CE, winName, ArrowParams::m_classTag, name); if (!myRParams) return (-1); rParams = myRParams; } if (opt.twoD) { string name = "twoD1"; TwoDDataParams *myRParams = NULL; myRParams = (TwoDDataParams *)CreateRender(CE, winName, TwoDDataParams::m_classTag, name); if (!myRParams) return (-1); rParams = myRParams; } if (opt.hello) { string name = "hello1"; HelloParams *myRParams = NULL; myRParams = (HelloParams *)CreateRender(CE, winName, HelloParams::m_classTag, name); if (!myRParams) return (-1); myRParams->SetLineThickness(4.0); rParams = myRParams; } if (!opt.var.empty()) { rParams->SetVariableName(opt.var); } return (0); } QApplication *app; int main(int argc, char **argv) { OptionParser op; double timer = 0.0; string s; const char *ProgName = "test_CE"; MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] metafiles " << endl; op.PrintOptionHelp(stderr); exit(0); } if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); } if (argc < 2) { cerr << "Usage: " << ProgName << " [options] " << endl; op.PrintOptionHelp(stderr); exit(1); } // Set up Qt application QApplication a(argc, argv, true); app = &a; string winName = "win1"; ControlExec *CE = new ControlExec; // Create the OpenGL Window Test_VizWin vizwin(0, CE, winName); // Create and set up a visualizer (no. 0) bool useSession = false; #ifdef VAPOR3_0_0_ALPHA CE->CreateDefaultParams(0); CE->SetActiveVizIndex(0); // Restore preferences (expect .vapor3_prefs in home directory) if (getenv("HOME")) { string prefPath = string(getenv("HOME")) + "/.vapor3_prefs"; CE->RestorePreferences(prefPath); } // Load session if specified bool enabled = false; if (opt.sessionfile.length() > 0) { CE->SetToDefault(); int rc = CE->RestoreSession(opt.sessionfile); if (rc == 0) useSession = true; } #endif // Load data vector files; for (int i = 1; i < argc; i++) { files.push_back(argv[i]); } int rc = CE->LoadData(files, 1000, !useSession); if (rc < 0) return (1); // Disable command queue (not used here) #ifdef VAPOR3_0_0_ALPHA Command::blockCapture(); #endif rc = CreateNew(CE, winName); if (rc < 0) return (1); // Make the Window display itself: vizwin.show(); #ifdef VAPOR3_0_0_ALPHA if (useSession) { #ifdef VAPOR3_0_0_ALPHA int rc = CE->ActivateEnabledRenderers(0); if (rc) exit(rc); #endif } else { // Enable the barbs for rendering rParams->SetEnabled(true); // Activate the barbs renderer CE->ActivateRender(winName, HelloParams::m_classTag, "hello1", true); } #endif #ifdef VAPOR3_0_0_ALPHA // Set up animation and capture // If there is a session file, use its timestep initially, otherwise get // the first time step from the command argument. #ifdef VAPOR3_0_0_ALPHA AnimationParams *animParams = CE->GetParamsMgr()->GetAnimationParams(0); if (!useSession) animParams->setCurrentTimestep(opt.ts0); int frameStep = animParams->getFrameStepSize(); // Loop through the specified number of time steps for (int j = 0; j < opt.nts; j++) { // Prepare for capture if enabled: if (animParams->GetCaptureEnabled()) { string capturePath = animParams->GetCaptureFilepath(); if (capturePath != "") CE->EnableCapture(capturePath, 0); } // Display the scene printf("Rendering timestep %d of %d\n", j + 1, opt.nts); vizwin.updateGL(); // Advance the frame, if more to animate if (j + 1 >= opt.nts) break; int currentTS = animParams->getCurrentTimestep(); currentTS += frameStep; if (currentTS >= animParams->getMinTimestep() && currentTS <= animParams->getMaxTimestep()) animParams->setCurrentTimestep(currentTS); else break; } #endif printf("Animation sequence complete\n"); #endif int estatus = a.exec(); if (!opt.quiet) { fprintf(stdout, "total process time : %f\n", timer); } ParamsMgr *pm = CE->GetParamsMgr(); pm->SaveToFile("file.xml"); delete CE; exit(estatus); } ================================================ FILE: test_apps/controlExec/test_vizwin.cpp ================================================ //************************************************************************ // * // Copyright (C) 2016 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // File: test_vizwin.cpp // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: October 2013 // // Description: Implements the VizWin class // This is the QGLWidget that performs OpenGL rendering (using associated Visualizer) // Plus supports mouse event reporting // #include // Must be included first!!! #include "vapor/VAssert.h" #include #include #include #include #include "vapor/ControlExecutive.h" #include "test_vizwin.h" using namespace VAPoR; /* * Constructs a VizWindow as a child of 'parent', with the * name 'name' and widget flags set to 'f'. * */ Test_VizWin::Test_VizWin(QWidget *parent, ControlExec *ce, string winName) : QGLWidget(parent) { _windowName = winName; _controlExec = ce; m_initialized = false; setAutoBufferSwap(false); return; } // React to a user-change in window size/position (or possibly max/min) // Either the window is minimized, maximized, restored, or just resized. void Test_VizWin::resizeGL(int width, int height) { int rc1 = CheckGLErrorMsg("GLVizWindowResizeEvent"); int rc2 = _controlExec->ResizeViz(_windowName, width, height); if (!rc1 && !rc2) reallyUpdate(); return; } void Test_VizWin::initializeGL() { int rc1 = CheckGLErrorMsg("GLVizWindowInitializeEvent"); makeCurrent(); int rc2 = _controlExec->InitializeViz(_windowName); int rc3 = CheckGLErrorMsg("GLVizWindowInitializeEvent"); if (!(rc2 < 0)) { m_initialized = true; } } void Test_VizWin::paintGL() { if (!m_initialized) return; // only paint if necessary // Note that makeCurrent is needed when here we have multiple windows. int rc0 = CheckGLErrorMsg("VizWindowPaintGL"); int rc1 = 0, rc2 = 0; if (!rc0) { makeCurrent(); rc1 = _controlExec->Paint(_windowName, false); if (!rc1) swapBuffers(); rc2 = CheckGLErrorMsg("VizWindowPaintGL"); } return; } void Test_VizWin::reallyUpdate() { makeCurrent(); int rc = _controlExec->Paint(_windowName, true); swapBuffers(); return; } void Test_VizWin::closeEvent(QCloseEvent *e) { QGLWidget::closeEvent(e); } ================================================ FILE: test_apps/controlExec/test_vizwin.h ================================================ //************************************************************************ // * // Copyright (C) 2013 * // University Corporation for Atmospheric Research * // All Rights Reserved * // * //************************************************************************/ // // File: test_vizwin.h // // Author: Alan Norton // National Center for Atmospheric Research // PO 3000, Boulder, Colorado // // Date: January 2016 // // #ifndef TEST_VIZWIN_H #define TEST_VIZWIN_H #include #include #include class QCloseEvent; class QRect; class QMouseEvent; class QFocusEvent; namespace VAPoR { class Viewpoint; class ControlExec; //! \class Test_VizWin //! \ingroup Public_GUI //! \brief A QGLWidget that supports display based on GL methods invoked in a Visualizer //! \author Alan Norton //! \version 3.0 //! \date October 2013 //! //! The VizWin class is a QGLWidget that supports the rendering by the VAPOR Visualizer class. //! The standard rendering methods (resize, initialize, paint) are passed to the Visualizer. //! In addition this is the class that responds to mouse events, resulting in scene navigation //! or manipulator changes. //! class Test_VizWin : public QGLWidget { Q_OBJECT public: //! Force the window to update, even if nothing has changed. void reallyUpdate(); Test_VizWin(QWidget *parent, ControlExec *, std::string winName); virtual ~Test_VizWin() {} #ifndef DOXYGEN_SKIP_THIS private: bool m_initialized; void closeEvent(QCloseEvent *event); virtual QSize minimumSizeHint() const { return QSize(400, 400); } virtual void resizeGL(int width, int height); virtual void initializeGL(); void paintGL(); std::string _windowName; ControlExec *_controlExec; #endif // DOXYGEN_SKIP_THIS }; }; // namespace VAPoR #endif // TEST_VIZWIN_H ================================================ FILE: test_apps/datamgr/CMakeLists.txt ================================================ add_executable (test_datamgr test_datamgr.cpp) set_target_properties(test_datamgr PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${debug_output_dir}") target_link_libraries (test_datamgr common vdc wasp) ================================================ FILE: test_apps/datamgr/test_datamgr.cpp ================================================ #include #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; struct { int nts; int ts0; int loop; int memsize; int level; int lod; int nthreads; string varname; string savefilebase; string ftype; std::vector minu; std::vector maxu; OptionParser::Boolean_T dump; OptionParser::Boolean_T tgetvalue; OptionParser::Boolean_T nogeoxform; OptionParser::Boolean_T novertxform; OptionParser::Boolean_T verbose; OptionParser::Boolean_T help; OptionParser::Boolean_T quiet; OptionParser::Boolean_T debug; } opt; OptionParser::OptDescRec_T set_opts[] = {{"nts", 1, "1", "Number of timesteps to process"}, {"ts0", 1, "0", "First time step to process"}, {"loop", 1, "1", "Number of loops to execute"}, {"memsize", 1, "2000", "Cache size in MBs"}, {"level", 1, "0", "Multiresution refinement level. Zero implies coarsest resolution"}, {"lod", 1, "0", "Level of detail. Zero implies coarsest resolution"}, {"nthreads", 1, "0", "Specify number of execution threads " "0 => use number of cores"}, {"varname", 1, "", "Name of variable"}, {"savefilebase", 1, "", "Base path name to output file"}, {"ftype", 1, "vdc", "data set type (vdc|wrf|cf|mpas)"}, {"minu", 1, "", "Colon delimited 3-element vector " "specifying domain min extents in user coordinates (X0:Y0:Z0)"}, {"maxu", 1, "", "Colon delimited 3-element vector " "specifying domain max extents in user coordinates (X1:Y1:Z1)"}, {"verbose", 0, "", "Verobse output"}, {"tgetvalue", 0, "", "Apply Grid:;GetValue test"}, {"dump", 0, "", "Dump variable coordinates and data"}, {"nogeoxform", 0, "", "Do not apply geographic transform (projection to PCS"}, {"novertxform", 0, "", "Do not apply to convert pressure, etc. to meters"}, {"help", 0, "", "Print this message and exit"}, {"quiet", 0, "", "Operate quitely"}, {"debug", 0, "", "Debug mode"}, {NULL}}; OptionParser::Option_T get_options[] = {{"nts", Wasp::CvtToInt, &opt.nts, sizeof(opt.nts)}, {"ts0", Wasp::CvtToInt, &opt.ts0, sizeof(opt.ts0)}, {"loop", Wasp::CvtToInt, &opt.loop, sizeof(opt.loop)}, {"memsize", Wasp::CvtToInt, &opt.memsize, sizeof(opt.memsize)}, {"level", Wasp::CvtToInt, &opt.level, sizeof(opt.level)}, {"lod", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)}, {"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"varname", Wasp::CvtToCPPStr, &opt.varname, sizeof(opt.varname)}, {"savefilebase", Wasp::CvtToCPPStr, &opt.savefilebase, sizeof(opt.savefilebase)}, {"ftype", Wasp::CvtToCPPStr, &opt.ftype, sizeof(opt.ftype)}, {"minu", Wasp::CvtToDoubleVec, &opt.minu, sizeof(opt.minu)}, {"maxu", Wasp::CvtToDoubleVec, &opt.maxu, sizeof(opt.maxu)}, {"verbose", Wasp::CvtToBoolean, &opt.verbose, sizeof(opt.verbose)}, {"dump", Wasp::CvtToBoolean, &opt.dump, sizeof(opt.dump)}, {"tgetvalue", Wasp::CvtToBoolean, &opt.tgetvalue, sizeof(opt.tgetvalue)}, {"nogeoxform", Wasp::CvtToBoolean, &opt.nogeoxform, sizeof(opt.nogeoxform)}, {"novertxform", Wasp::CvtToBoolean, &opt.novertxform, sizeof(opt.novertxform)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {NULL}}; const char *ProgName; void ErrMsgCBHandler(const char *msg, int) { cerr << ProgName << " : " << msg << endl; } // Handle command line -nthreads argument so that pthreads and OpenMP threads // are treated consistently. // int get_num_ompthreads() { int nthreads = 0; #pragma omp parallel { // use all available threads // if (opt.nthreads < 1) { nthreads = omp_get_num_threads(); } else { nthreads = opt.nthreads; } } return (nthreads); } void print_info(DataMgr &datamgr, bool verbose) { vector dimnames; dimnames = datamgr.GetDimensionNames(); cout << "Dimensions:" << endl; for (int i = 0; i < dimnames.size(); i++) { DC::Dimension dimension; datamgr.GetDimension(dimnames[i], dimension, -1); cout << "\t" << dimension.GetName() << " = " << dimension.GetLength() << endl; } vector meshnames; cout << "Meshes:" << endl; meshnames = datamgr.GetMeshNames(); for (int i = 0; i < meshnames.size(); i++) { cout << "\t" << meshnames[i] << endl; if (verbose) { DC::Mesh mesh; datamgr.GetMesh(meshnames[i], mesh); cout << mesh; } } vector vars; for (int d = 1; d < 4; d++) { cout << d << "D variables: "; vars = datamgr.GetDataVarNames(d); for (int i = 0; i < vars.size(); i++) { cout << vars[i] << endl; if (verbose) { DC::DataVar datavar; datamgr.GetDataVarInfo(vars[i], datavar); cout << datavar; } } cout << endl; } cout << endl << endl; } void test_node_iterator(const Grid *g, VAPoR::CoordType minu, VAPoR::CoordType maxu) { cout << "Node Iterator Test ----->" << endl; Grid::ConstNodeIterator itr; Grid::ConstNodeIterator enditr = g->ConstNodeEnd(); float t0 = GetTime(); itr = g->ConstNodeBegin(minu, maxu); size_t count = 0; for (; itr != enditr; ++itr) { count++; } cout << "count: " << count << endl; cout << "time: " << GetTime() - t0 << endl; cout << endl; } void test_get_value(Grid *g) { cout << "Get Value Test ----->" << endl; g->SetInterpolationOrder(1); float t0 = GetTime(); auto tmp = g->GetDimensions(); auto tmp2 = std::vector{tmp[0], tmp[1], tmp[2]}; size_t n = VProduct(tmp2); size_t count = 0; size_t ecount = 0; #if defined(_OPENMP) int requested_num_threads = get_num_ompthreads(); #endif #pragma omp parallel num_threads(requested_num_threads) { size_t my_ecount = 0; size_t my_count = 0; int id = omp_get_thread_num(); int nthreads = omp_get_num_threads(); size_t istart = id * n / nthreads; size_t iend = (id + 1) * n / nthreads; if (id == nthreads - 1) iend = n; Grid::ConstIterator itr = g->cbegin() + istart; Grid::ConstCoordItr c_itr = g->ConstCoordBegin() + istart; for (size_t i = istart; i < iend; i++, ++itr, ++c_itr) { float v0 = *itr; float v1 = g->GetValue(*c_itr); if (!Wasp::NearlyEqual(v0, v1)) { my_ecount++; } my_count++; } #pragma omp critical { count += my_count; ecount += my_ecount; } } cout << "error count: " << ecount << " out of " << count << endl; cout << "time: " << GetTime() - t0 << endl; cout << endl; } void dump(const Grid *g) { auto tmp = g->GetDimensions(); auto dims = std::vector{tmp[0], tmp[1], tmp[2]}; dims.resize(g->GetNumDimensions()); vector min(dims.size(), 0); vector max; for (int i = 0; i < dims.size(); i++) { max.push_back(dims[i] - 1); } vector index = min; vector coord; while (index != max) { g->GetUserCoordinates(index, coord); float v = g->GetValueAtIndex(index); for (int i = 0; i < dims.size(); i++) { cout << coord[i] << " "; } cout << v << endl; if (index[0] == max[0]) { cout << endl; } index = IncrementCoords(min, max, index); } } void process(FILE *fp, DataMgr &datamgr, string vname, int loop, int ts) { vector timecoords; datamgr.GetTimeCoordinates(timecoords); if (!opt.savefilebase.empty()) { char buf[4 + 1]; string path(opt.savefilebase); path.append("."); sprintf(buf, "%4.4d", loop); path.append(buf); path.append("."); sprintf(buf, "%4.4d", ts); path.append(buf); fp = fopen(path.c_str(), "w"); if (!fp) { cerr << "Can't open output file " << path << endl; } } if (!datamgr.VariableExists(ts, vname, opt.level, opt.lod)) { cerr << "Variable " << vname << " does not exist" << endl; return; } VAPoR::CoordType minu = {0.0, 0.0, 0.0}; VAPoR::CoordType maxu = {0.0, 0.0, 0.0}; if (opt.minu.size()) { VAssert(opt.minu.size() == opt.maxu.size()); Grid::CopyToArr3(opt.minu, minu); Grid::CopyToArr3(opt.maxu, maxu); } else { int rc = datamgr.GetVariableExtents(ts, vname, opt.level, opt.lod, minu, maxu); if (rc < 0) exit(1); } Grid *g; g = datamgr.GetVariable(ts, vname, opt.level, opt.lod, minu, maxu, false); if (!g) { exit(1); } if (opt.dump) { dump(g); } if (fp) { Grid::Iterator itr; Grid::Iterator enditr = g->end(); float v; for (itr = g->begin(); itr != enditr;) { v = *itr; fwrite(&v, sizeof(v), 1, fp); itr += 8; } fclose(fp); } g->GetUserExtents(minu, maxu); test_node_iterator(g, minu, maxu); if (opt.tgetvalue) { test_get_value(g); } vector rvec; datamgr.GetDataRange(ts, vname, opt.level, opt.lod, rvec); cout << "Data Range: [" << rvec[0] << ", " << rvec[1] << "]" << endl; cout << "Cell face has CCW winding order : " << g->HasInvertedCoordinateSystemHandiness() << endl; auto tmp = g->GetDimensions(); auto dims = std::vector{tmp[0], tmp[1], tmp[2]}; dims.resize(g->GetNumDimensions()); cout << "Grid dimensions: [ "; for (int i = 0; i < dims.size(); i++) { cout << dims[i] << " "; } cout << "]" << endl; g->GetUserExtents(minu, maxu); cout << "Min user extents: ["; for (int i = 0; i < minu.size(); i++) cout << minu[i] << " "; cout << "]" << endl; cout << "Max user extents: ["; for (int i = 0; i < maxu.size(); i++) cout << maxu[i] << " "; cout << "]" << endl; cout << "Has missing data : " << g->HasMissingData() << endl; if (g->HasMissingData()) { cout << "Missing data value : " << g->GetMissingValue() << endl; Grid::Iterator itr; Grid::Iterator enditr = g->end(); float mv = g->GetMissingValue(); int count = 0; for (itr = g->begin(); itr != enditr; ++itr) { if (*itr == mv) count++; } cout << "Num missing values : " << count << endl; } cout << "Grid type: " << g->GetType() << endl; cout << setprecision(16) << "User time: " << timecoords[ts] << endl; cout << endl; delete g; } int main(int argc, char **argv) { OptionParser op; double timer = 0.0; string s; ProgName = FileUtils::LegacyBasename(argv[0]); MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.minu.size() && opt.minu.size() != opt.maxu.size()) { cerr << "Usage: " << ProgName << " master.nc" << endl; op.PrintOptionHelp(stderr, 80, false); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] metafiles " << endl; op.PrintOptionHelp(stderr); exit(0); } if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); } if (argc < 2) { cerr << "Usage: " << ProgName << " [options] vdcmaster " << endl; op.PrintOptionHelp(stderr); exit(1); } vector files; for (int i = 1; i < argc; i++) { files.push_back(argv[i]); } vector options; if (!opt.nogeoxform) { options.push_back("-project_to_pcs"); } if (!opt.novertxform) { options.push_back("-vertical_xform"); } DataMgr datamgr(opt.ftype, opt.memsize, opt.nthreads); int rc = datamgr.Initialize(files, options); if (rc < 0) exit(1); print_info(datamgr, opt.verbose); string vname = opt.varname; if (vname.empty()) { return (0); } FILE *fp = NULL; cout << "Variable name : " << vname << endl; int nts = datamgr.GetNumTimeSteps(vname); for (int l = 0; l < opt.loop; l++) { cout << "Processing loop " << l << endl; for (int ts = opt.ts0; ts < opt.ts0 + opt.nts && ts < nts; ts++) { cout << "Processing time step " << ts << endl; process(fp, datamgr, vname, l, ts); } } if (!opt.quiet) { fprintf(stdout, "total process time : %f\n", timer); } exit(0); } ================================================ FILE: test_apps/grid_iter/CMakeLists.txt ================================================ add_executable (test_grid_iter test_grid_iter.cpp) set_target_properties(test_grid_iter PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${debug_output_dir}") target_link_libraries (test_grid_iter common vdc wasp) ================================================ FILE: test_apps/grid_iter/test_grid_iter.cpp ================================================ #include #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; struct { std::vector bs; std::vector minu; std::vector maxu; std::vector roimin; std::vector roimax; std::vector dims; std::vector periodic; string type; OptionParser::Boolean_T debug; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"bs", 1, "64:64:64", "Colon delimited 3-element vector " "specifying block size"}, {"minu", 1, "0:0:0", "Colon delimited 3-element vector " "specifying minimum user coordinates"}, {"maxu", 1, "1.0:1.0:1.0", "Colon delimited 3-element vector " "specifying maximum user coordinates"}, {"roimin", 1, "0.0:0.0:0.0", "Colon delimited 3-element vector " "specifying min bbox coordinates for a region of interest"}, {"roimax", 1, "1.0:1.0:1.0", "Colon delimited 3-element vector " "specifying max bbox coordinates for a region of interest"}, {"dims", 1, "512:512:128", "Colon delimited 3-element vector " "specifying grid dimensions"}, {"periodic", 1, "0:0:0", "Colon delimited 3-element vector " "of booleans specifying boundary periodicity"}, {"type", 1, "regular", "Grid type. One of (regular, " "layered, curvlinear, stretched"}, {"debug", 0, "", "Print diagnostics"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"bs", Wasp::CvtToSize_tVec, &opt.bs, sizeof(opt.bs)}, {"minu", Wasp::CvtToDoubleVec, &opt.minu, sizeof(opt.minu)}, {"maxu", Wasp::CvtToDoubleVec, &opt.maxu, sizeof(opt.maxu)}, {"roimin", Wasp::CvtToDoubleVec, &opt.roimin, sizeof(opt.roimin)}, {"roimax", Wasp::CvtToDoubleVec, &opt.roimax, sizeof(opt.roimax)}, {"dims", Wasp::CvtToSize_tVec, &opt.dims, sizeof(opt.dims)}, {"periodic", Wasp::CvtToSize_tVec, &opt.periodic, sizeof(opt.periodic)}, {"type", Wasp::CvtToCPPStr, &opt.type, sizeof(opt.type)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; namespace { vector Heap; }; template void out_container(T first, T last) { for (T itr = first; itr != last; ++itr) { cout << *itr << " "; } cout << endl; } const char *ProgName; vector alloc_blocks(const vector &bs, const vector &dims) { size_t block_size = 1; size_t nblocks = 1; for (int i = 0; i < bs.size(); i++) { block_size *= bs[i]; VAssert(dims[i] > 0); size_t nb = ((dims[i] - 1) / bs[i]) + 1; nblocks *= nb; } float *buf = new float[nblocks * block_size]; Heap.push_back(buf); vector blks; for (int i = 0; i < nblocks; i++) { blks.push_back(buf + i * block_size); } return (blks); } VAPoR::RegularGrid *make_regular_grid() { VAssert(opt.bs.size() == opt.minu.size()); VAssert(opt.bs.size() == opt.maxu.size()); VAssert(opt.bs.size() == opt.dims.size()); VAssert(opt.bs.size() == opt.periodic.size()); vector blks = alloc_blocks(opt.bs, opt.dims); RegularGrid *rg = new RegularGrid(opt.dims, opt.bs, blks, opt.minu, opt.maxu); return (rg); } VAPoR::StretchedGrid *make_stretched_grid() { VAssert(opt.bs.size() == opt.minu.size()); VAssert(opt.bs.size() == opt.maxu.size()); VAssert(opt.bs.size() == opt.dims.size()); VAssert(opt.bs.size() == opt.periodic.size()); vector blks = alloc_blocks(opt.bs, opt.dims); vector xcoords, ycoords, zcoords; vector *> coords = {&xcoords, &ycoords, &zcoords}; double delta; for (int i = 0; i < opt.minu.size(); i++) { delta = opt.dims[i] == 1 ? 0.0 : (opt.maxu[i] - opt.minu[i]) / (opt.dims[i] - 1); for (int j = 0; i < opt.dims[j]; j++) { coords[i]->push_back(opt.minu[j] + j * delta); } } StretchedGrid *rg = new StretchedGrid(opt.dims, opt.bs, blks, xcoords, ycoords, zcoords); return (rg); } VAPoR::LayeredGrid *make_layered_grid() { VAssert(opt.bs.size() == 3); VAssert(opt.bs.size() == opt.minu.size()); VAssert(opt.bs.size() == opt.maxu.size()); VAssert(opt.bs.size() == opt.dims.size()); VAssert(opt.bs.size() == opt.periodic.size()); vector zblks = alloc_blocks(opt.bs, opt.dims); RegularGrid *rg = new RegularGrid(opt.dims, opt.bs, zblks, vector(3, 0.0), vector(3, 1.0)); for (size_t k = 0; k < rg->GetDimensions()[2]; k++) { for (size_t j = 0; j < rg->GetDimensions()[1]; j++) { for (size_t i = 0; i < rg->GetDimensions()[0]; i++) { double z = (opt.maxu[2] - opt.minu[2]) / (opt.dims[2] - 1) * k + opt.minu[2]; rg->SetValueIJK(i, j, k, (float)z); } } } vector blks = alloc_blocks(opt.bs, opt.dims); double deltax = opt.maxu[0] - opt.minu[0] / (opt.dims[0] - 1); vector xcoords; for (int i = 0; i < opt.dims[0]; i++) { xcoords.push_back(opt.minu[0] + (i * deltax)); } double deltay = opt.maxu[1] - opt.minu[1] / (opt.dims[1] - 1); vector ycoords; for (int i = 0; i < opt.dims[1]; i++) { ycoords.push_back(opt.minu[1] + (i * deltay)); } LayeredGrid *lg = new LayeredGrid(opt.dims, opt.bs, blks, xcoords, ycoords, *rg); return (lg); } VAPoR::CurvilinearGrid *make_curvilinear_grid() { VAssert(opt.bs.size() == 3); VAssert(opt.bs.size() == opt.minu.size()); VAssert(opt.bs.size() == opt.maxu.size()); VAssert(opt.bs.size() == opt.dims.size()); VAssert(opt.bs.size() == opt.periodic.size()); vector bs2d = {opt.bs[0], opt.bs[1]}; vector dims2d = {opt.dims[0], opt.dims[1]}; vector xblks = alloc_blocks(bs2d, dims2d); RegularGrid *xrg = new RegularGrid(dims2d, bs2d, xblks, vector(2, 0.0), vector(2, 1.0)); vector yblks = alloc_blocks(bs2d, dims2d); RegularGrid *yrg = new RegularGrid(dims2d, bs2d, yblks, vector(2, 0.0), vector(2, 1.0)); for (size_t j = 0; j < dims2d[1]; j++) { for (size_t i = 0; i < dims2d[0]; i++) { double x = (opt.maxu[0] - opt.minu[0]) / (dims2d[0] - 1) * i + opt.minu[0]; double y = (opt.maxu[1] - opt.minu[1]) / (dims2d[1] - 1) * j + opt.minu[1]; xrg->SetValueIJK(i, j, 0, x); yrg->SetValueIJK(i, j, 0, y); } } vector zcoords; for (int k = 0; k < opt.dims[2]; k++) { double z = (opt.maxu[2] - opt.minu[2]) / (opt.dims[2] - 1) * k + opt.minu[2]; zcoords.push_back(z); } vector blks = alloc_blocks(opt.bs, opt.dims); vector minu2d = {opt.minu[0], opt.minu[1]}; vector maxu2d = {opt.maxu[0], opt.maxu[1]}; CurvilinearGrid *cg = new CurvilinearGrid(opt.dims, opt.bs, blks, *xrg, *yrg, zcoords, NULL); return (cg); } VAPoR::CurvilinearGrid *make_curvilinear_terrain_grid() { VAssert(opt.bs.size() == 3); VAssert(opt.bs.size() == opt.minu.size()); VAssert(opt.bs.size() == opt.maxu.size()); VAssert(opt.bs.size() == opt.dims.size()); VAssert(opt.bs.size() == opt.periodic.size()); vector bs2d = {opt.bs[0], opt.bs[1]}; vector dims2d = {opt.dims[0], opt.dims[1]}; vector bs = {opt.bs[0], opt.bs[1], opt.bs[2]}; vector dims = {opt.dims[0], opt.dims[1], opt.dims[2]}; vector xblks = alloc_blocks(bs2d, dims2d); RegularGrid *xrg = new RegularGrid(dims2d, bs2d, xblks, vector(2, 0.0), vector(2, 1.0)); vector yblks = alloc_blocks(bs2d, dims2d); RegularGrid *yrg = new RegularGrid(dims2d, bs2d, yblks, vector(2, 0.0), vector(2, 1.0)); for (size_t j = 0; j < dims2d[1]; j++) { for (size_t i = 0; i < dims2d[0]; i++) { double x = (opt.maxu[0] - opt.minu[0]) / (dims2d[0] - 1) * i + opt.minu[0]; double y = (opt.maxu[1] - opt.minu[1]) / (dims2d[1] - 1) * j + opt.minu[1]; xrg->SetValueIJK(i, j, 0, x); yrg->SetValueIJK(i, j, 0, y); } } vector zblks = alloc_blocks(bs, dims); RegularGrid *zrg = new RegularGrid(dims, bs, zblks, vector(3, 0.0), vector(3, 1.0)); for (size_t k = 0; k < dims[2]; k++) { double z = (opt.maxu[2] - opt.minu[2]) / (dims[2] - 1) * k + opt.minu[2]; for (size_t j = 0; j < dims[1]; j++) { for (size_t i = 0; i < dims[0]; i++) { zrg->SetValueIJK(i, j, k, z); } } } vector blks = alloc_blocks(opt.bs, opt.dims); vector minu2d = {opt.minu[0], opt.minu[1]}; vector maxu2d = {opt.maxu[0], opt.maxu[1]}; CurvilinearGrid *cg = new CurvilinearGrid(opt.dims, opt.bs, blks, *xrg, *yrg, *zrg, NULL); return (cg); } void init_grid(StructuredGrid *sg) { // Initialize data to linear ramp // size_t kmax = opt.dims.size() >= 1 ? opt.dims[2] : 1; size_t jmax = opt.dims.size() >= 1 ? opt.dims[1] : 1; size_t imax = opt.dims.size() >= 1 ? opt.dims[0] : 1; size_t idx = 0; for (size_t k = 0; k < kmax; k++) { for (size_t j = 0; j < jmax; j++) { for (size_t i = 0; i < imax; i++) { sg->SetValueIJK(i, j, k, (float)idx); idx++; } } } } void test_iterator(const StructuredGrid *sg) { cout << "Value Iterator Test ----->" << endl; double t0 = Wasp::GetTime(); Grid::ConstIterator itr; Grid::ConstIterator enditr = sg->cend(); double accum = 0.0; size_t count = 0; // for (itr = sg->cbegin(opt.roimin, opt.roimax); itr!=enditr; ++itr) { for (itr = sg->cbegin(); itr != enditr; ++itr) { accum += *itr; count++; } cout << "Iteration time : " << Wasp::GetTime() - t0 << endl; cout << "Sum and count: " << accum << " " << count << endl; cout << endl; } void test_operator_pg_iterator(const StructuredGrid *sg) { cout << "Operator += Test ----->" << endl; double t0 = Wasp::GetTime(); const size_t stride = 8; Grid::ConstIterator itr1 = sg->cbegin(); Grid::ConstIterator enditr1 = sg->cend(); double accum1 = 0.0; size_t count1 = 0; size_t index = 0; for (; itr1 != enditr1; ++itr1) { if ((index % stride) == 0) { accum1 += *itr1; count1++; } index++; } double t1 = Wasp::GetTime(); cout << "Iteration time (inc by 1) : " << t1 - t0 << endl; cout << "Sum and count: " << accum1 << " " << count1 << endl; double t2 = Wasp::GetTime(); Grid::ConstIterator itr2 = sg->cbegin(); Grid::ConstIterator enditr2 = sg->cend(); double accum2 = 0.0; size_t count2 = 0; for (; itr2 != enditr2;) { accum2 += *itr2; count2++; itr2 += stride; } double t3 = Wasp::GetTime(); cout << "Iteration time (+=) : " << t3 - t2 << endl; cout << "Sum and count: " << accum2 << " " << count2 << endl; itr1 = sg->cbegin(); enditr1 = sg->cend(); itr2 = sg->cbegin(); enditr2 = sg->cend(); index = 0; bool mismatch = false; for (; itr1 != enditr1 && itr2 != enditr2; ++itr1) { if ((index % stride) == 0) { if (*itr1 != *itr2) { mismatch = true; break; } itr2 += stride; } index++; } if (!mismatch) { cout << "operator+= operator++ match" << endl; } else { cout << "FAIL : operator+= operator++ mismatch" << endl; } cout << endl; } #ifdef VAPOR3_0_0_ALPHA void test_cell_iterator(const StructuredGrid *sg) { cout << "Cell Iterator Test ----->" << endl; double t0 = Wasp::GetTime(); StructuredGrid::ConstCellIterator itr; size_t count = 0; for (itr = sg->ConstCellBegin(); itr != sg->ConstCellEnd(); ++itr) { count++; cout << "Cell : "; out_container((*itr).cbegin(), (*itr).cend()); vector> nodes; sg->GetCellNodes(*itr, nodes); cout << "\tNodes : " << endl; for (int i = 0; i < nodes.size(); i++) { cout << "\t"; out_container(nodes[i].cbegin(), nodes[i].cend()); } cout << endl; // const vector &coord = *(itr.GetCoordItr()); // cout << coord[0] << " " << coord[1] << " " << coord[2] << endl; } cout << "Iteration time : " << Wasp::GetTime() - t0 << endl; cout << "Cell count : " << count << endl; cout << endl; } #endif void test_node_iterator(const StructuredGrid *sg) { cout << "Node Iterator Test ----->" << endl; double t0 = Wasp::GetTime(); Grid::ConstNodeIterator itr; Grid::ConstNodeIterator enditr = sg->ConstNodeEnd(); if (opt.roimin == opt.minu && opt.roimax == opt.maxu) { itr = sg->ConstNodeBegin(); } else { CoordType roimin = {0.0, 0.0, 0.0}; CoordType roimax = {0.0, 0.0, 0.0}; Grid::CopyToArr3(opt.roimin, roimin); Grid::CopyToArr3(opt.roimax, roimax); itr = sg->ConstNodeBegin(roimin, roimax); } size_t count = 0; // for ( ; itr!=sg->ConstNodeEnd(); ++itr) for (; itr != enditr; ++itr) { count++; // out_container((*itr).cbegin(), (*itr).cend()); // cout << endl; } cout << "Iteration time : " << Wasp::GetTime() - t0 << endl; cout << "count: " << count << endl; cout << endl; } void test_cell_iterator(const StructuredGrid *sg) { cout << "Cell Iterator Test ----->" << endl; double t0 = Wasp::GetTime(); Grid::ConstCellIterator itr; Grid::ConstCellIterator enditr = sg->ConstCellEnd(); if (opt.roimin == opt.minu && opt.roimax == opt.maxu) { itr = sg->ConstCellBegin(); } else { CoordType roimin = {0.0, 0.0, 0.0}; CoordType roimax = {0.0, 0.0, 0.0}; Grid::CopyToArr3(opt.roimin, roimin); Grid::CopyToArr3(opt.roimax, roimax); itr = sg->ConstCellBegin(roimin, roimax); } size_t count = 0; // for (itr = sg->ConstCellBegin(); itr!=sg->ConstCellEnd(); ++itr) for (; itr != enditr; ++itr) { count++; // out_container((*itr).cbegin(), (*itr).cend()); // cout << endl; } cout << "Iteration time : " << Wasp::GetTime() - t0 << endl; cout << "count: " << count << endl; cout << endl; } void test_coord_iterator(const StructuredGrid *sg) { cout << "Coord Iterator Test ----->" << endl; double t0 = Wasp::GetTime(); Grid::ConstCoordItr itr; Grid::ConstCoordItr enditr = sg->ConstCoordEnd(); size_t count = 0; for (itr = sg->ConstCoordBegin(); itr != enditr; ++itr) { count++; } cout << "Iteration time : " << Wasp::GetTime() - t0 << endl; cout << "count: " << count << endl; cout << endl; } void test_coord_accessor(const StructuredGrid *sg) { cout << "Coord Accessor Test ----->" << endl; double t0 = Wasp::GetTime(); size_t count = 0; vector index(3); vector coord; for (size_t k = 0; k < sg->GetDimensions()[2]; k++) { for (size_t j = 0; j < sg->GetDimensions()[1]; j++) { for (size_t i = 0; i < sg->GetDimensions()[0]; i++) { index[0] = i; index[1] = j; index[2] = k; sg->GetUserCoordinates(index, coord); count++; } } } cout << "Iteration time : " << Wasp::GetTime() - t0 << endl; cout << "count: " << count << endl; cout << endl; } void test_getvalue(StructuredGrid *sg) { cout << "GetValue Test ----->" << endl; float rangev[2]; sg->GetRange(rangev); sg->SetInterpolationOrder(1); float range = rangev[1] - rangev[0]; if (range == 0.0) return; double t0 = Wasp::GetTime(); Grid::ConstIterator itr; Grid::ConstIterator enditr = sg->cend(); Grid::ConstCoordItr coord_itr = sg->ConstCoordBegin(); Grid::ConstCoordItr coord_enditr = sg->ConstCoordEnd(); float maxErr = 0.0; for (itr = sg->cbegin(); itr != enditr; ++itr, ++coord_itr) { float v1 = *itr; const CoordType & coord = *coord_itr; float v2 = sg->GetValue(coord); float err = abs(v1 - v2) / range; if (err > maxErr) { maxErr = err; } } cout << "Iteration time : " << Wasp::GetTime() - t0 << endl; cout << "Lmax error : " << maxErr << endl; cout << endl; } void test_roi_iterator() { cout << "ROI Test ----->" << endl; vector dims = {128, 128, 128}; vector bs = {64, 64, 64}; vector blks = alloc_blocks(bs, dims); vector minu = {0.0, 0.0, 0.0}; vector maxu = {(double)dims[0] - 1, (double)dims[1] - 1, (double)dims[2] - 1}; RegularGrid *rg = new RegularGrid(dims, bs, blks, minu, maxu); vector delta; CoordType roiminu = {0.0, 0.0, 0.0}; CoordType roimaxu = {0.0, 0.0, 0.0}; for (int i = 0; i < minu.size(); i++) { delta.push_back(maxu[i] - minu[i] / (dims[i] - 1)); roiminu[i] = minu[i] + (delta[i] / 0.5); roimaxu[i] = maxu[i] - (delta[i] / 0.5); } size_t idx = 0; for (size_t k = 1; k < dims[2] - 1; k++) { for (size_t j = 1; j < dims[1] - 1; j++) { for (size_t i = 1; i < dims[0] - 1; i++) { rg->SetValueIJK(i, j, k, (float)idx); idx++; } } } Grid::ConstIterator itr = rg->cbegin(roiminu, roimaxu); Grid::ConstIterator enditr = rg->cend(); idx = 0; size_t v = 0; vector index; bool pass = true; for (; itr != enditr; ++itr) { v = (size_t)*itr; if (idx != v) { pass = false; cerr << "FAIL test_roi_iterator : " << v << "not equal " << idx << endl; } } if (pass) { cout << "ROI test passed" << endl; } cout << endl; } int main(int argc, char **argv) { OptionParser op; string s; ProgName = FileUtils::LegacyBasename(argv[0]); MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] metafiles " << endl; op.PrintOptionHelp(stderr); exit(0); } if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); } double t0 = Wasp::GetTime(); StructuredGrid *sg = NULL; if (opt.type == "layered") { cout << "Layered grid" << endl; sg = make_layered_grid(); } else if (opt.type == "curvilinear") { cout << "Curvilinear grid" << endl; sg = make_curvilinear_grid(); } else if (opt.type == "curvilinear_terrain") { cout << "Curvilinear terrain grid" << endl; sg = make_curvilinear_terrain_grid(); } else if (opt.type == "stretched") { cout << "Stretched grid" << endl; sg = make_stretched_grid(); } else { cout << "Regular grid" << endl; sg = make_regular_grid(); } if (!sg) return (1); init_grid(sg); cout << "Creation time : " << Wasp::GetTime() - t0 << endl; cout << *sg; vector minu, maxu; sg->GetUserExtents(minu, maxu); cout << "Grid Extents: " << endl; for (int i = 0; i < minu.size(); i++) { cout << "\t" << minu[i] << " " << maxu[i] << endl; } cout << endl; test_roi_iterator(); test_iterator(sg); test_operator_pg_iterator(sg); test_node_iterator(sg); test_cell_iterator(sg); test_coord_iterator(sg); test_coord_accessor(sg); test_getvalue(sg); delete sg; for (int i = 0; i < Heap.size(); i++) { delete[] Heap[i]; } return (0); } ================================================ FILE: test_apps/params/file.xml ================================================ 0 1 0 0 1 1 1 1 1 1 1 1 NULL P PB PH NULL CANWAT 2 1 0 0 0 -845627.125 1991855.625 0 412793.375 3219581.5 0 0 10 4 6 1 1 1 0.1 0.1 0.1 0.1 ================================================ FILE: test_apps/params/test_params.cpp ================================================ #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include #include using namespace Wasp; using namespace VAPoR; struct { string ifile; OptionParser::Boolean_T help; OptionParser::Boolean_T quiet; OptionParser::Boolean_T debug; } opt; OptionParser::OptDescRec_T set_opts[] = { {"ifile", 1, "", "Construct Xml tree from a file"}, {"help", 0, "", "Print this message and exit"}, {"quiet", 0, "", "Operate quitely"}, {"debug", 0, "", "Debug mode"}, {NULL}}; OptionParser::Option_T get_options[] = {{"ifile", Wasp::CvtToCPPStr, &opt.ifile, sizeof(opt.ifile)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {NULL}}; const char *ProgName; void make_params(DataMgrV3_0 *dataMgr, string parent_name, string outfile) { ofstream out(outfile); if (!out) { MyBase::SetErrMsg("Failed to open file %s : %M", outfile.c_str()); exit(1); } ParamsBase::StateSave ssave; ParamsSeparator parent(&ssave, "TOP"); TwoDDataParams dataParams(dataMgr, &ssave); dataParams.SetParent(&parent); vector varnames = dataMgr->GetDataVarNames(); for (int i = 0; i < varnames.size(); i++) { dataParams.GetTransferFunc(varnames[i]); } #ifdef VAPOR3_0_0_ALPHA ParamsContainer tfs(&psm, "TransferFunctions"); tfs.GetNode()->SetParent(&parent); TransferFunction tf1(&psm); TransferFunction tf2(&psm); TransferFunction tf3(&psm); // create a second opacity map // (void)tf3.createOpacityMap(); tfs.Insert(&tf1, "X"); tfs.Insert(&tf2, "Y"); tfs.Insert(&tf3, "Z"); ParamsContainer twoDparams(&psm, &parent, "ImageParams"); TwoDImageParams imgparams1(&psm, NULL, 0); TwoDImageParams imgparams2(&psm, NULL, 0); TwoDImageParams imgparams3(imgparams2); imgparams3.SetHeightVariableName("hgt"); twoDparams.Insert(&imgparams1, "img1"); twoDparams.Insert(&imgparams2, "img2"); twoDparams.Insert(&imgparams3, "img3"); #endif out << *(parent.GetNode()); out.close(); } void import_params(DataMgrV3_0 *dataMgr, string infile) { XmlNode parent; XmlParser parser; int rc = parser.LoadFromFile(&parent, infile); if (rc < 0) exit(1); XmlNode *tfnode = parent.GetChild(0); if (!tfnode) return; ParamsBase::StateSave ssave; TwoDDataParams dataParams(dataMgr, &ssave, tfnode); cout << parent; } int main(int argc, char **argv) { OptionParser op; string s; ProgName = Basename(argv[0]); MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << endl; op.PrintOptionHelp(stderr); exit(0); } if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); } if (argc != 2) { cerr << "Usage: " << ProgName << " VDCMaster.nc [options] " << endl; op.PrintOptionHelp(stderr); exit(1); } string vdcfile = argv[1]; vector files(1, vdcfile); DataMgrV3_0 dataMgr("vdc", 1000); int rc = dataMgr.Initialize(files); if (rc < 0) return (1); make_params(&dataMgr, "parent", "file.xml"); import_params(&dataMgr, "file.xml"); cout << "Allocated note count after delete : " << XmlNode::GetAllocatedNodes().size() << endl; } ================================================ FILE: test_apps/params2/CMakeLists.txt ================================================ add_executable (test_params2 test_params2.cpp) set_target_properties(test_params2 PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${debug_output_dir}") target_link_libraries (test_params2 params common vdc wasp) ================================================ FILE: test_apps/params2/test_params2.cpp ================================================ #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include using namespace Wasp; using namespace VAPoR; struct { OptionParser::Boolean_T help; OptionParser::Boolean_T quiet; } opt; OptionParser::OptDescRec_T set_opts[] = {{"help", 0, "", "Print this message and exit"}, {"quiet", 0, "", "Operate quitely"}, {NULL}}; OptionParser::Option_T get_options[] = {{"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {NULL}}; const char *ProgName; void test() { ParamsBase::StateSave ssave; ParamsSeparator parent(&ssave, "TOP"); ViewpointParams vp1(&ssave); vp1.SetParent(&parent); ViewpointParams vp2(&ssave); // vp2.SetParent(&parent); if (vp1 == vp2) { cout << "SUCCESS: vp1 == vp2" << endl; } else { cout << "FAIL: vp1 == vp2" << endl; } vp1.SetWindowSize(1280, 1024); vp1.SetFOV(99.0); if (vp1 != vp2) { cout << "SUCCESS: vp1 != vp2" << endl; } else { cout << "FAIL: vp1 != vp2" << endl; } vp1 = vp2; if (vp1 == vp2) { cout << "SUCCESS: vp1 == vp2" << endl; } else { cout << "FAIL: vp1 == vp2" << endl; } } int main(int argc, char **argv) { OptionParser op; string s; ProgName = FileUtils::LegacyBasename(argv[0]); MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << endl; op.PrintOptionHelp(stderr); exit(0); } MyBase::SetDiagMsgFilePtr(stderr); if (argc != 1) { cerr << "Usage: " << ProgName << endl; op.PrintOptionHelp(stderr); exit(1); } test(); cout << "Allocated note count after delete : " << XmlNode::GetAllocatedNodes().size() << endl; } ================================================ FILE: test_apps/pyengine/CMakeLists.txt ================================================ add_executable (test_pyengine test_pyengine.cpp) set_target_properties(test_pyengine PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${debug_output_dir}") target_link_libraries (test_pyengine render common vdc wasp ${Python_LIBRARIES}) ================================================ FILE: test_apps/pyengine/test_pyengine.cpp ================================================ #include #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include #include #include using namespace std; using namespace Wasp; using namespace VAPoR; size_t vproduct(DimsType a) { size_t ntotal = 1; for (int i = 0; i < a.size(); i++) ntotal *= a[i]; return (ntotal); } struct { int memsize; int level; int lod; int nthreads; string ftype; OptionParser::Boolean_T help; OptionParser::Boolean_T quiet; OptionParser::Boolean_T debug; } opt; OptionParser::OptDescRec_T set_opts[] = {{"memsize", 1, "2000", "Cache size in MBs"}, {"level", 1, "0", "Multiresution refinement level. Zero implies coarsest resolution"}, {"lod", 1, "0", "Level of detail. Zero implies coarsest resolution"}, {"nthreads", 1, "0", "Specify number of execution threads " "0 => use number of cores"}, {"ftype", 1, "vdc", "data set type (vdc|wrf|cf|mpas)"}, {"help", 0, "", "Print this message and exit"}, {"quiet", 0, "", "Operate quitely"}, {"debug", 0, "", "Debug mode"}, {NULL}}; OptionParser::Option_T get_options[] = { {"memsize", Wasp::CvtToInt, &opt.memsize, sizeof(opt.memsize)}, {"level", Wasp::CvtToInt, &opt.level, sizeof(opt.level)}, {"lod", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)}, {"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"ftype", Wasp::CvtToCPPStr, &opt.ftype, sizeof(opt.ftype)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {NULL}}; const char *ProgName; void test_calculate() { int rc = PyEngine::Initialize(); if (rc < 0) return; DimsType dims = {1000, 1000, 10}; // string script = "C = sqrt(A) + B"; string script = "C = A + B"; vector inputVarNames = {"A", "B"}; vector inputVarDims = {dims, dims}; vector outputVarNames = {"C"}; vector outputVarDims = {dims}; float *A = new float[vproduct(dims)]; float *B = new float[vproduct(dims)]; float *C = new float[vproduct(dims)]; for (int i = 0; i < vproduct(dims); i++) { A[i] = 1; B[i] = 2; } vector inputVarArrays = {A, B}; vector outputVarArrays = {C}; rc = PyEngine::Calculate(script, inputVarNames, inputVarDims, inputVarArrays, outputVarNames, outputVarDims, outputVarArrays); if (rc < 0) { delete[] A; delete[] B; delete[] C; return; } string status = "SUCCESS"; for (int i = 0; i < vproduct(dims); i++) { if (C[i] != A[i] + B[i]) { status = "FAILED!!!"; break; } } delete[] A; delete[] B; delete[] C; string s = MyPython::Instance()->PyOut(); if (!s.empty()) { cout << "test_calculate : " << s << endl; } cout << "test_calculate : " << status << endl; return; } void test_datamgr(vector files) { if (files.empty()) return; DataMgr datamgr(opt.ftype, opt.memsize, opt.nthreads); int rc = datamgr.Initialize(files, vector()); if (rc < 0) exit(1); PyEngine pyEngine(&datamgr); if (pyEngine.Initialize() < 0) exit(1); vector varNames = datamgr.GetDataVarNames(); if (varNames.empty()) return; string inputVarName = varNames[0]; string outputVarName = varNames[0] + "Copy"; string script = outputVarName + " = " + inputVarName; DC::DataVar datavar; rc = datamgr.GetDataVarInfo(inputVarName, datavar); VAssert(rc >= 0); vector inputVarNames = {inputVarName}; vector outputVarNames = {outputVarName}; vector outputMeshNames = {datavar.GetMeshName()}; rc = pyEngine.AddFunction("myscript", script, inputVarNames, outputVarNames, outputMeshNames); if (rc < 0) exit(1); if (!opt.quiet) { cout << "Derived variable :\n"; datamgr.GetDataVarInfo(outputVarName, datavar); cout << datavar; } Grid *g1 = datamgr.GetVariable(0, inputVarName, opt.level, opt.lod, true); if (!g1) exit(1); Grid *g2 = datamgr.GetVariable(0, outputVarName, opt.level, opt.lod, true); if (!g2) exit(1); Grid::ConstIterator itr1 = g1->cbegin(); Grid::ConstIterator enditr1 = g1->cend(); Grid::ConstIterator itr2 = g2->cbegin(); Grid::ConstIterator enditr2 = g2->cend(); string status = "SUCCESS"; for (; itr1 != enditr1; ++itr1, ++itr2) { if (itr2 == enditr2) { status = "FAILED"; break; } if (*itr1 != *itr2) { status = "FAILED"; break; } } cout << "test_datamgr : " << status << endl; } void test_controlexec_copy(vector files) { if (files.empty()) return; ControlExec ce; const string dataSetName = "test_data"; int rc = ce.OpenData(files, dataSetName, opt.ftype); DataStatus *dataStatus = ce.GetDataStatus(); DataMgr *dataMgr = dataStatus->GetDataMgr(dataSetName); vector varNames = dataMgr->GetDataVarNames(); if (varNames.empty()) return; string inputVarName = varNames[0]; string outputVarName = varNames[0] + "Copy"; string script = outputVarName + " = " + inputVarName + "\n"; DC::DataVar datavar; rc = dataMgr->GetDataVarInfo(inputVarName, datavar); VAssert(rc >= 0); vector inputVarNames = {inputVarName}; vector outputVarNames = {outputVarName}; vector outputMeshNames = {datavar.GetMeshName()}; rc = ce.AddFunction("Python", dataSetName, "myscript_ce", script, inputVarNames, outputVarNames, outputMeshNames); if (rc < 0) exit(1); if (!opt.quiet) { cout << "Derived variable :\n"; dataMgr->GetDataVarInfo(outputVarName, datavar); cout << datavar; } Grid *g1 = dataMgr->GetVariable(0, inputVarName, opt.level, opt.lod, true); if (!g1) exit(1); Grid *g2 = dataMgr->GetVariable(0, outputVarName, opt.level, opt.lod, true); if (!g2) exit(1); Grid::ConstIterator itr1 = g1->cbegin(); Grid::ConstIterator enditr1 = g1->cend(); Grid::ConstIterator itr2 = g2->cbegin(); Grid::ConstIterator enditr2 = g2->cend(); string status = "SUCCESS"; for (; itr1 != enditr1; ++itr1, ++itr2) { if (itr2 == enditr2) { status = "FAILED"; break; } if (*itr1 != *itr2) { status = "FAILED"; break; } } ce.CloseData(dataSetName); cout << "test_controlexec_copy : " << status << endl; } void test_controlexec_coord(vector files) { if (files.empty()) return; ControlExec ce; const string dataSetName = "test_data"; int rc = ce.OpenData(files, dataSetName, opt.ftype); DataStatus *dataStatus = ce.GetDataStatus(); DataMgr *dataMgr = dataStatus->GetDataMgr(dataSetName); vector varNames = dataMgr->GetDataVarNames(); if (varNames.empty()) return; string inputVarName = varNames[0]; string outputVarName = varNames[0] + "Copy"; string script = outputVarName + " = " + inputVarName + "\n"; // string script = outputVarName + " = sqrt(" + inputVarName +")"; script += "import numpy as np\n" "for f in dir():\n" " if type(eval(f)) is np.ndarray:\n" " print f, eval(f).shape, 'min,max,mean: ', eval(f).min(), eval(f).max(), eval(f).mean()\n" "\n" "\n"; DC::DataVar datavar; rc = dataMgr->GetDataVarInfo(inputVarName, datavar); VAssert(rc >= 0); vector inputVarNames = {inputVarName}; vector outputVarNames = {outputVarName}; vector outputMeshNames = {datavar.GetMeshName()}; bool coordFlag = true; string scriptName = "test_controlexec_coord"; rc = ce.AddFunction("Python", dataSetName, scriptName, script, inputVarNames, outputVarNames, outputMeshNames, coordFlag); if (rc < 0) exit(1); if (!opt.quiet) { cout << "Derived variable :\n"; dataMgr->GetDataVarInfo(outputVarName, datavar); cout << datavar; } Grid *g1 = dataMgr->GetVariable(0, inputVarName, opt.level, opt.lod, true); if (!g1) exit(1); Grid *g2 = dataMgr->GetVariable(0, outputVarName, opt.level, opt.lod, true); if (!g2) exit(1); Grid::ConstIterator itr1 = g1->cbegin(); Grid::ConstIterator enditr1 = g1->cend(); Grid::ConstIterator itr2 = g2->cbegin(); Grid::ConstIterator enditr2 = g2->cend(); string status = "SUCCESS"; for (; itr1 != enditr1; ++itr1, ++itr2) { if (itr2 == enditr2) { status = "FAILED"; break; } if (*itr1 != *itr2) { status = "FAILED"; break; } } cout << "Script output : \n"; cout << ce.GetFunctionStdout("Python", dataSetName, scriptName) << endl; ce.CloseData(dataSetName); cout << "test_controlexec_coord : " << status << endl; } void test_controlexec_add(vector files) { if (files.empty()) return; ControlExec ce; const string dataSetName = "test_data"; int rc = ce.OpenData(files, dataSetName, opt.ftype); DataStatus *dataStatus = ce.GetDataStatus(); DataMgr *dataMgr = dataStatus->GetDataMgr(dataSetName); vector varNames = dataMgr->GetDataVarNames(); if (varNames.empty()) return; vector inputVarNames = {"U10", "V10"}; vector outputVarNames = {"U10plusV10"}; string script = "U10plusV10 = U10 + V10\n"; script += "print 'UV10plusV10 shape : ', U10plusV10.shape"; DC::DataVar datavar; rc = dataMgr->GetDataVarInfo(inputVarNames[0], datavar); VAssert(rc >= 0); vector outputMeshNames = {datavar.GetMeshName()}; rc = ce.AddFunction("Python", dataSetName, "myscript_ce", script, inputVarNames, outputVarNames, outputMeshNames); if (rc < 0) exit(1); if (!opt.quiet) { cout << "Derived variable :\n"; dataMgr->GetDataVarInfo(outputVarNames[0], datavar); cout << datavar; } Grid *g1 = dataMgr->GetVariable(0, inputVarNames[0], opt.level, opt.lod, true); if (!g1) exit(1); Grid *g2 = dataMgr->GetVariable(0, inputVarNames[1], opt.level, opt.lod, true); if (!g2) exit(1); Grid *g3 = dataMgr->GetVariable(0, outputVarNames[0], opt.level, opt.lod, true); if (!g3) exit(1); Grid::ConstIterator itr1 = g1->cbegin(); Grid::ConstIterator enditr1 = g1->cend(); Grid::ConstIterator itr2 = g2->cbegin(); Grid::ConstIterator enditr2 = g2->cend(); Grid::ConstIterator itr3 = g3->cbegin(); Grid::ConstIterator enditr3 = g3->cend(); string status = "SUCCESS"; for (; itr1 != enditr1; ++itr1, ++itr2, ++itr3) { if (itr2 == enditr2 || itr3 == enditr3) { status = "FAILED"; break; } if ((*itr1 + *itr2) != *itr3) { status = "FAILED"; break; } } ce.CloseData(dataSetName); cout << "test_controlexec_add : " << status << endl; } int main(int argc, char **argv) { OptionParser op; string s; ProgName = FileUtils::LegacyBasename(argv[0]); MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] " << endl; op.PrintOptionHelp(stderr); exit(0); } if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); } vector files; for (int i = 1; i < argc; i++) { files.push_back(argv[i]); } test_calculate(); test_datamgr(files); test_controlexec_copy(files); test_controlexec_coord(files); test_controlexec_add(files); return 0; } ================================================ FILE: test_apps/quadtreerectangle/CMakeLists.txt ================================================ add_executable (test_quadtreerectangle "") set_target_properties(test_quadtreerectangle PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${debug_output_dir}") target_sources(test_quadtreerectangle PRIVATE test_quadtreerectangle.cpp ../smokeTests/gridTools.cpp ../smokeTests/gridTools.h) target_link_libraries (test_quadtreerectangle common vdc wasp) ================================================ FILE: test_apps/quadtreerectangle/test_quadtreerectangle.cpp ================================================ #include #include "vapor/VAssert.h" #include #include #include #include #include "../smokeTests/gridTools.h" using namespace std; using namespace Wasp; using namespace VAPoR; struct { int n; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"n", 1, "1000", "Quad mesh X & Y dimensions"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"n", Wasp::CvtToInt, &opt.n, sizeof(opt.n)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; const char *ProgName; void print_histo(const QuadTreeRectangle &qtr) { vector payload_histo; vector level_histo; qtr.GetStats(payload_histo, level_histo); cout << "Payload histo" << endl; for (int i = 0; i < payload_histo.size(); i++) { cout << " " << i << " " << payload_histo[i] << endl; } cout << "Level histo" << endl; for (int i = 0; i < level_histo.size(); i++) { cout << " " << i << " " << level_histo[i] << endl; } cout << endl; } void test_mesh() { size_t n = opt.n; VAssert(n >= 2); QuadTreeRectangle qtr(0.0, 0.0, 1.0, 1.0, n * n); float delta = 1.0 / (float)(n - 1); cout << " Build" << endl; size_t index = 0; for (size_t j = 0; j < n - 1; j++) { for (size_t i = 0; i < n - 1; i++) { float left = (float)i * delta; float right = (float)i * delta + delta; float top = (float)j * delta; float bottom = (float)j * delta + delta; qtr.Insert(left, top, right, bottom, index); index++; } } cout << " Search" << endl; size_t num_missed = 0; size_t num_wrong = 0; index = 0; for (size_t j = 0; j < n - 1; j++) { for (size_t i = 0; i < n - 1; i++) { float x = (float)i * delta + (delta * 0.5); ; float y = (float)j * delta + (delta * 0.5); ; vector payloads; qtr.GetPayloadContained(x, y, payloads); if (payloads.size() < 1) { num_missed++; continue; } bool found = false; for (int ii = 0; ii < payloads.size(); ii++) { if (payloads[ii] == index) { found = true; break; } } if (!found) { num_wrong++; } index++; } } cout << " Num missed : " << num_missed << endl; cout << " Num wrong : " << num_wrong << endl; // cout << qtr; print_histo(qtr); } int main(int argc, char **argv) { OptionParser op; string s; ProgName = FileUtils::LegacyBasename(argv[0]); MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] " << endl; op.PrintOptionHelp(stderr); exit(0); } QuadTreeRectangle qtr; cout << qtr; qtr.Insert(0.0, 0.0, 1.0, 1.0, 100); qtr.Insert(0.0, 0.0, 0.2, 0.2, 101); qtr.Insert(0.9, 0.9, 1.0, 1.0, 102); cout << qtr; vector payloads; qtr.GetPayloadContained(0.1, 0.1, payloads); cout << "quads intersecting 0.1, 0.1" << endl; for (int i = 0; i < payloads.size(); i++) { cout << payloads[i] << " "; } cout << endl; qtr.GetPayloadContained(0.9, 0.9, payloads); cout << "quads intersecting 0.9, 0.9" << endl; for (int i = 0; i < payloads.size(); i++) { cout << payloads[i] << " "; } cout << endl; test_mesh(); return 0; } ================================================ FILE: test_apps/render_regression_tests/README.md ================================================ # Render Regression Tests ** **For internal use** ### Components - **run_config.py** Primary tool to run tests. It runs the entire suite of tests as configured in config.yaml. Run with `-h` for usage help. - **run_test.py** Runs a single test render. Not intended to be used directly, it is used by the `run_config.py` script. - **config.yaml** Contains the configuration for the list of tests to run. Split into 2 secions denoted by `--- # Section`. The first specifies global settings that apply to all tests. The second is a list of tests. ### Dependencies The test requires vapor's python library to be installed as well as the pyyaml library. ### Output The test will generate an output directory as specified in the config.yaml file. In the output directory, there will be one image file per test titled `-[- (if multiple)].png`. In the output directory there will be a `meta` folder containing for each test a log file with the config used to generate the test and stdout/stderr from the test, and the session file that reproduces the test named `meta/.log` and `meta/.vs3` respectively. ================================================ FILE: test_apps/render_regression_tests/config.yaml ================================================ --- # CONFIG outDir: ./out # dataRootDir: /Volumes/ExtremeSSD/data dataRootDir: /glade/p/cisl/vast/vapor/data resolution: [1000, 720] rendererSets: default: - TwoDData - Image - Volume - IsoSurface - Flow 2D: - TwoDData - Image - Flow2D 3D: - Image - Volume - IsoSurface - Flow3D --- # Tests CAM/AdamPhillips/v5_rel04_BC5_ne120_t12_pop62: files: Source/CAM/AdamPhillips/v5_rel04_BC5_ne120_t12_pop62/*.nc type: cf CAM/AMIP_0.25degree: files: Source/CAM/AMIP_0.25degree/cam5_1_amip_run2.cam2.h1.1979-01-0[1-3]-00000.nc type: cf CAM/FiniteVolume/cam_fv: # GPU out of memory for 3D files: Source/CAM/FiniteVolume/cam_fv/*.nc type: cf CAM/Gaussian: files: Source/CAM/Gaussian/*.nc type: cf renderers: - TwoDData - Image MOM4/00010101: files: Source/MOM4/00010101/*.nc type: cf MOM4/19990101: files: Source/MOM4/19990101/*.nc type: cf MOM4/iom1/ocean_month: files: Source/MOM4/iom1/ocean_month/*.nc type: cf MOM4/JinHeeYuk/ocean_eta: files: Source/MOM4/JinHeeYuk/ocean_eta/*.nc type: cf renderers: - TwoDData - Image MOM4/JinHeeYuk/ocean_salt: files: Source/MOM4/JinHeeYuk/ocean_salt/*.nc type: cf renderers: - Image - Volume - IsoSurface MOM4/om3/ocean_residency_snap: files: Source/MOM4/om3/ocean_residency_snap/*.nc type: cf renderers: - TwoDData - Image - Volume - IsoSurface MPAS/MPAS-O: files: Source/MPAS/MPAS-O/*.nc type: mpas renderers: 2D MPAS/FalkoJudt/30km: files: - Source/MPAS/FalkoJudt/30km/x1.static.nc - Source/MPAS/FalkoJudt/30km/diag.2016-08-01_10.30.00.nc type: mpas renderers: 2D MPAS/MPAS_V4.0: files: Source/MPAS/MPAS_V4.0/x1.40962.output.2012-05-25_06.00.00.nc type: mpas renderers: 2D MPAS/ThomasSchwitalla: runConcurrently: false files: - Source/MPAS/ThomasSchwitalla/x1.65536002.grid.nc - Source/MPAS/ThomasSchwitalla/ter_3km.nc type: mpas renderers: TwoDData: t2m Image: MPAS/RosimarRiosBerrios: # skip: true runConcurrently: false files: - Source/MPAS/RosimarRiosBerrios/x5.tropical_3km_10N.init.nc - Source/MPAS/RosimarRiosBerrios/diag.2000-05-31_00.00.00.nc type: mpas renderers: - TwoDData - Image POP/KISTI: files: Source/POP/KISTI/*.nc type: cf renderers: Image: TwoDData: Flow2D: XFieldVariable: HUS YFieldVariable: HUW ROMS/his: files: Source/ROMS/his/*.nc type: cf timestep: 1 renderers: default: IsoSurface: temp ROMS/jsmall: files: Source/ROMS/jsmall/*.nc type: cf ROMS/Kauffman: files: Source/ROMS/Kauffman/*.nc type: cf ROMS/KISTI/dm1: files: Source/ROMS/KISTI/dm1/*.nc type: cf renderers: default: TwoDData: zeta ROMS/KISTI/Regular2: files: Source/ROMS/KISTI/Regular2/*.nc type: cf ROMS/KISTI/Rotated: files: Source/ROMS/KISTI/Rotated/*.nc type: cf renderers: default: TwoDData: zeta WRF/2D: files: Source/WRF/2D/wrf.nc type: wrf renderers: 2D: TwoDData: variable: U10 WRF/antarctic/antarctic_01: files: Source/WRF/antarctic/antarctic_01/wrfout_d01_2009-04-01_00:00:00 type: wrf WRF/antarctic/antarctic_02: files: Source/WRF/antarctic/antarctic_02/wrfout_d02_2009-04-01_00:00:00 type: wrf WRF/antarctic/antarctic_03: files: Source/WRF/antarctic/antarctic_03/wrfout_d03_2009-04-01_00:00:00 type: wrf renderers: default: Volume: V WRF/antarctic/antarctic_04: files: Source/WRF/antarctic/antarctic_04/wrfout_d04_2009-04-01_00:00:00 type: wrf renderers: default: Volume: U TwoDData: T2 WRF/antarctic/antarctic_05: files: Source/WRF/antarctic/antarctic_05/wrfout_d05_2009-04-01_00:00:00 type: wrf WRF/antarctic/antarctic_06: files: Source/WRF/antarctic/antarctic_06/wrfout_d06_2009-04-01_00:00:00 type: wrf WRF/april: files: Source/WRF/april/wrfout_d01_2007-04-0[4-5]_00:00:00 type: wrf WRF/DUKU: files: Source/WRF/DUKU/wrfout_d02_2007-04-01_00:00:00.nc type: wrf WRF/headwaters: files: Source/WRF/headwaters/wrfout_d01_2053-03-21_00:00:00 type: wrf WRF/HurricaneBill: files: - Source/WRF/HurricaneBill/wrfout_d01_2009-08-18_12:00:00 - Source/WRF/HurricaneBill/wrfout_d01_2009-08-18_15:00:00 type: wrf renderers: default: IsoSurface: IsoValues: [60.87427] WRF/idealized/kalundquist: files: Source/WRF/idealized/kalundquist/wrfout_d01_2013-01-01_09_30_00 type: wrf renderers: default: TwoDData: variable: SWUPT WRF/idealized: files: Source/WRF/idealized/wrfout_d01_0001-01-01_00:00:40 type: wrf renderers: default: TwoDData: variable: U10 Volume: variable: V IsoSurface: variable: V WRF/Katrina: files: Source/WRF/Katrina/wrfout_d02_2005-08-29_01 type: wrf WRF/planetwrf: files: Source/WRF/planetwrf/wrfout_d01601 type: wrf WRF/rotlatlon/Alan1/d01: files: - Source/WRF/rotlatlon/Alan1/d01/wrfout_d01_2008-06-01_00 - Source/WRF/rotlatlon/Alan1/d01/wrfout_d01_2008-06-01_06 - Source/WRF/rotlatlon/Alan1/d01/wrfout_d01_2008-06-01_12 type: wrf renderers: default: TwoDData: Q2 Volume: P IsoSurface: variable: P IsoValues: [ 783 ] WRF/rotlatlon/Alan1/d02: files: - Source/WRF/rotlatlon/Alan1/d02/wrfout_d02_2008-06-01_00 - Source/WRF/rotlatlon/Alan1/d02/wrfout_d02_2008-06-01_06 - Source/WRF/rotlatlon/Alan1/d02/wrfout_d02_2008-06-01_12 type: wrf renderers: default: TwoDData: Q2 Volume: P IsoSurface: variable: P WRF/rotlatlon/Alan2/d01: files: - Source/WRF/rotlatlon/Alan2/d01/wrfout_d01_2008-06-01_00 - Source/WRF/rotlatlon/Alan2/d01/wrfout_d01_2008-06-01_06 - Source/WRF/rotlatlon/Alan2/d01/wrfout_d01_2008-06-01_12 type: wrf renderers: default: TwoDData: Q2 Volume: P IsoSurface: variable: P WRF/rotlatlon/Alan2/d02: files: - Source/WRF/rotlatlon/Alan2/d02/wrfout_d02_2008-06-01_00 - Source/WRF/rotlatlon/Alan2/d02/wrfout_d02_2008-06-01_06 - Source/WRF/rotlatlon/Alan2/d02/wrfout_d02_2008-06-01_12 type: wrf renderers: default: TwoDData: Q2 Volume: P IsoSurface: variable: P WRF/yochen: files: Source/WRF/yochen/wrfout_d05_2005-07-10_00:1[0-1]:00 type: wrf renderers: default: TwoDData: T2 Volume: V WRF/HRRR: files: Source/WRF/HRRR/wrfout_d01_2020-08-28_20_00_00 type: wrf renderers: Flow2D: TwoDData: variable: HFX Volume: IsoSurface: IsoValues: [0.01773] BOV/256i.bov: files: Source/BOV/256i.bov type: bov renderers: IsoSurface BOV/256f.bov: files: Source/BOV/256f.bov type: bov renderers: IsoSurface BOV/256d.bov: files: Source/BOV/256d.bov type: bov renderers: IsoSurface BOV/multiTimeMultiVar: files: Source/BOV/multiTimeMultiVar/*.bov type: bov renderers: IsoSurface BOV/relativePath1.bov: files: Source/BOV/relativePath1.bov type: bov renderers: IsoSurface BOV/relativePath2.bov: files: Source/BOV/relativePath2.bov type: bov renderers: IsoSurface BOV/relativePath3.bov: files: Source/BOV/relativePath3.bov type: bov renderers: IsoSurface BOV/relativePath4.bov: files: Source/BOV/relativePath4.bov type: bov renderers: IsoSurface UGRID/NOAA-geoflow/large: files: Source/UGRID/NOAA-geoflow/large/*.nc type: ugrid renderers: Image: Flow3D: XFieldVariable: v1 YFieldVariable: v2 ZFieldVariable: v3 UGRID/NOAA-geoflow/small: files: Source/UGRID/NOAA-geoflow/small/*.nc type: ugrid renderers: Image: Flow3D: XFieldVariable: v1 YFieldVariable: v2 ZFieldVariable: v3 UGRID/NOAA-geoflow/2D: files: Source/UGRID/NOAA-geoflow/2D/*.nc type: ugrid renderers: TwoDData: Image: Flow2D: XFieldVariable: v1 YFieldVariable: v2 ================================================ FILE: test_apps/render_regression_tests/run_config.py ================================================ import sys, os from glob import glob from shutil import copyfile import fnmatch import yaml, pprint import subprocess import jinja2 from itertools import * import concurrent.futures def ParseAruments() -> (dict, dict): import argparse parser = argparse.ArgumentParser() parser.add_argument('configPath') parser.add_argument('-n', '--dryRun', action='store_true') parser.add_argument('-j', '--jobs', type=int, default=1) parser.add_argument('-o', '--outDir') parser.add_argument('-t', '--testName', help="Run specific test from config.yaml. By default will run all tests.") args = parser.parse_args() with open(args.configPath, "r") as f: environment = jinja2.Environment() template = environment.from_string(f.read()) config, tests = yaml.safe_load_all(template.render(glob=glob)) config['dryRun'] = args.dryRun config['jobs'] = args.jobs if args.outDir: config['outDir'] = args.outDir config['onlyRunTestName'] = args.testName config.setdefault('resolution', [600, 480]) return config, tests def mkdir(path): os.makedirs(path, exist_ok=True) def extract(d:dict, k, default=None): v = d.get(k, default) if k in d: del d[k] return v def alwaysList(x): if x is None: return [] if isinstance(x, list): return x if isinstance(x, dict): return list(x.items()) return [x] def alwaysDict(x): if x is None: return {} if isinstance(x, dict): return x if isinstance(x, list): assert len(set(x)) == len(x) return {k:None for k in x} return {x: None} def alwaysIterable(x): if x is None: return iter(()) if isinstance(x, str): return iter((x,)) try: return iter(x) except TypeError: return iter((x,)) def locateRelPath(path, root): if os.path.isabs(path): return path return os.path.join(root, path) def GetConfigForCompletedRun(newConfig): if not os.path.exists(newConfig['outputLog']): return None with open(newConfig['outputLog'], "r") as log: lines = log.readlines() oldConfigYaml = ''.join(lines[lines.index("=========== CONFIG ===========\n")+1:lines.index("==============================\n")]) return yaml.safe_load(oldConfigYaml) import signal import psutil gotKeyboardInterrupt = False def signal_handler(sig, frame): global gotKeyboardInterrupt gotKeyboardInterrupt = True current_process = psutil.Process() children = current_process.children(recursive=True) for child in children: signal.pthread_kill(child.pid, signal.SIGKILL) print('******* Jobs cancelled *******') signal.signal(signal.SIGINT, signal_handler) def RunTest(config): if os.path.exists(config['output']) and os.path.exists(config['outputLog']): with open(config['outputLog'], "r") as log: if "=========== TEST COMPLETE ===========" in log.read(): if config == GetConfigForCompletedRun(config): # print("Skipping test", config['name'], config['renderer']) return else: print("Config changed for", config['name']) print("Run test", config['name'], config['renderer']) cmd = ['python', '-u', 'run_test.py', yaml.dump(config)] with open(config['outputLog'], "w", 1) as log: try: subprocess.run(cmd, stdout=log, stderr=subprocess.STDOUT, text=True) except Exception: pass if gotKeyboardInterrupt: print("Stopped", config['name'], config['renderer']) return print("\n=========== TEST COMPLETE ===========\n", file=log) if not os.path.exists(config['output']): copyfile("missing.png", config['output']) def TestCanBeRunConcurrently(test:dict) -> bool: return test.get('runConcurrently', True) def GenerateTests(config, tests): for name, test in tests.items(): file_globs = [locateRelPath(f, config['dataRootDir']) for f in alwaysList(extract(test, 'files'))] files = sorted(chain.from_iterable(map(glob, file_globs))) dataType = extract(test, 'type') if not files: print("WARNING: files not found:", file_globs) if extract(test, 'skip'): continue renderers:dict = alwaysDict(extract(test, 'renderers', config['rendererSets']['default'])) for k in renderers.copy(): if k in config['rendererSets']: del renderers[k] for r, v in alwaysDict(config['rendererSets'][k]).items(): renderers.setdefault(r, v) for ren, renConfig in renderers.items(): if isinstance(renConfig, str): renConfig = {'variable': renConfig} renConfig = alwaysDict(renConfig) variableKeys = [k for k in renConfig if 'variable' in k.lower()] variables = [i for i in renConfig.items() if i[0] in variableKeys] for k,_ in variables: del renConfig[k] varCombos = [*product(*[[*zip(repeat(k), alwaysList(v))] for k,v in variables])] for combo in varCombos: fullName = f"{name}-{ren}" if len(varCombos) > 1: fullName += '-'.join(['', *chain.from_iterable(combo)]) fName = fullName + ".png" fName = fName.replace('/', '-') yield { 'name': name, 'outputDir': config['outDir'], 'outputName': fName, 'output': f"{config['outDir']}/{fName}", 'outputSession': f"{config['outDir']}/meta/{fName}.vs3", 'outputLog': f"{config['outDir']}/meta/{fName}.log", 'files': files, 'type': dataType, 'renderer': ren, 'dryRun': config['dryRun'], 'resolution': config['resolution'], **dict(combo), **renConfig, **test, } if __name__ == "__main__": config, testConfigs = ParseAruments() # print("config = ", end='') # pprint.PrettyPrinter(indent=4).pprint(config) mkdir(config['outDir']) mkdir(f"{config['outDir']}/meta") tests = GenerateTests(config, testConfigs) if config['onlyRunTestName']: tests = filter(lambda t: fnmatch.fnmatch(t['name'], config['onlyRunTestName']), tests) tests = list(tests) nJobs = config.get('jobs', 1) if nJobs > 1: concurrentTests = filter(TestCanBeRunConcurrently, tests) singleTests = filter(lambda t: not TestCanBeRunConcurrently(t), tests) else: singleTests = tests concurrentTests = [] if concurrentTests: print(f"Running concurrent tests with {nJobs} jobs") with concurrent.futures.ThreadPoolExecutor(max_workers=nJobs) as executor: executor.map(RunTest, concurrentTests) if singleTests: print(f"Running single-threaded tests") for test in singleTests: RunTest(test) ================================================ FILE: test_apps/render_regression_tests/run_test.py ================================================ import os.path import sys configExample = """ output: out.png files: - /Users/stasj/Work/data/DUKU/DUKU-3.2.0.alpha.nc type: vdc renderer: TwoDData variable: ALBEDO timestep: 0 """ try: configText = sys.argv[1] except IndexError: configText = configExample print("WARNING: Missing config") dryRun = True if len(sys.argv) >= 3 and sys.argv[2] == '-n' else False print("=========== CONFIG ===========") print(configText) print("==============================") print() import yaml config:dict = yaml.safe_load(configText) # print("config =", config) dryRun = dryRun or config.get('dryRun', False) if dryRun: exit(0) sys.path.append("vapor_module_dir") import vapor.session ses = vapor.session.Session() dataset = ses.OpenDataset(config['type'], config['files']) if 'resolution' in config: ses.SetResolution(config['resolution'][0], config['resolution'][1]) print(dataset) for n in [2,3]: print(f"\t {n}D Vars: {', '.join(dataset.GetDataVarNames(n))}") if 'timestep' in config: print("Setting timestep to", config['timestep']) ses.SetTimestep(config['timestep']) def GetRendererClass(typ:str): typ = typ.removesuffix("2D") typ = typ.removesuffix("3D") for Class in vapor.renderer.Renderer.__subclasses_rec__(): if Class.VaporName == typ: return Class ren = dataset.NewRenderer(GetRendererClass(config['renderer'])) if config['renderer'].endswith("2D"): ren.SetDimensions(2) if config['renderer'].endswith("3D"): ren.SetDimensions(3) print(ren) for var in [k for k in config.keys() if 'variable' in k.lower()]: setter = f"Set{var[0].upper()+var[1:]}Name" varName = config[var] print(f"ren.{setter}({varName})") ren.__getattribute__(setter)(varName) # for c in config.get('commands', []): if 'IsoValues' in config: ren.SetIsoValues(config['IsoValues']) ses.GetCamera().ViewAll() if 'outputSession' in config: ses.Save(config['outputSession']) ses.Render(config['output']) ================================================ FILE: test_apps/smokeTests/CMakeLists.txt ================================================ add_executable ( testGrid testGrid.cpp gridTools.cpp gridTools.h ) set_target_properties(testGrid PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${test_output_dir}") add_executable ( testDataMgr testDataMgr.cpp dataMgrTools.cpp dataMgrTools.h gridTools.cpp gridTools.h ) set_target_properties(testDataMgr PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${test_output_dir}") target_link_libraries (testGrid common vdc wasp) target_link_libraries (testDataMgr common vdc wasp) ================================================ FILE: test_apps/smokeTests/dataMgrTools.cpp ================================================ #include #include "gridTools.h" #include "dataMgrTools.h" int TestDataMgr(const std::string &fileType, size_t memsize, size_t nthreads, const std::vector &files, const std::vector &options, bool silenceTime) { VAPoR::DataMgr dataMgr(fileType, memsize, nthreads); int rc = dataMgr.Initialize(files, options); if (rc < 0) { cerr << "Failed to intialize WRF DataMGR" << endl; return -1; } PrintDimensions(dataMgr); PrintMeshes(dataMgr); PrintVariables(dataMgr); TestVariables(dataMgr, silenceTime); PrintCoordVariables(dataMgr); PrintTimeCoordinates(dataMgr); return 0; } void PrintDimensions(const VAPoR::DataMgr &dataMgr) { vector dimnames; dimnames = dataMgr.GetDimensionNames(); cout << endl << "Dimensions:" << endl; for (int i = 0; i < dimnames.size(); i++) { VAPoR::DC::Dimension dimension; dataMgr.GetDimension(dimnames[i], dimension, -1); cout << " " << dimension.GetName() << " = " << dimension.GetLength() << endl; cout << " Time Varying: " << dimension.IsTimeVarying() << endl; } cout << endl; } void PrintMeshes(const VAPoR::DataMgr &dataMgr, bool verbose) { vector meshnames; cout << "Meshes:" << endl; meshnames = dataMgr.GetMeshNames(); for (int i = 0; i < meshnames.size(); i++) { cout << " " << meshnames[i] << endl; if (verbose) { VAPoR::DC::Mesh mesh; dataMgr.GetMesh(meshnames[i], mesh); cout << mesh; } } cout << endl; } void PrintCoordVariables(const VAPoR::DataMgr &dataMgr) { cout << "Projection String: " << dataMgr.GetMapProjection() << endl << endl; cout << "Coordinate Variables:" << endl; std::vector coordVars = dataMgr.GetCoordVarNames(); for (int i = 0; i < coordVars.size(); i++) { cout << " " << coordVars[i] << endl; } cout << endl; } void PrintTimeCoordinates(const VAPoR::DataMgr &dataMgr) { std::vector timeCoords = dataMgr.GetTimeCoordinates(); cout << "Time Coordinates:" << endl; auto oldPrecision = std::cout.precision(10); for (int i = 0; i < timeCoords.size(); i++) { cout << " " << timeCoords[i] << endl; } std::cout.precision(oldPrecision); cout << endl; cout << "Time coordinate variable name: "; cout << dataMgr.GetTimeCoordVarName() << endl; cout << "Number of time steps: "; cout << dataMgr.GetNumTimeSteps() << endl; } void PrintCompressionInfo(const VAPoR::DataMgr &dataMgr, const std::string &varname) { cout << "Compression Info for variable " << varname << ":" << endl; cout << " Refinement Levels: " << dataMgr.GetNumRefLevels(varname) << endl; std::stringstream ss; std::vector cRatios = dataMgr.GetCRatios(varname); for (size_t i = 0; i < cRatios.size(); i++) { if (i != 0) ss << " "; ss << cRatios[i]; } std::string s = ss.str(); cout << " Compression Ratios: " << s << endl << endl; } void PrintVariables(const VAPoR::DataMgr &dataMgr, bool verbose, bool testVars) { vector vars; for (int d = 1; d < 4; d++) { vars = dataMgr.GetDataVarNames(d); if (!vars.size()) continue; cout << d << "D variables: " << endl; ; for (int i = 0; i < vars.size(); i++) { cout << " " << vars[i] << endl; if (verbose) { VAPoR::DC::DataVar datavar; dataMgr.GetDataVarInfo(vars[i], datavar); cout << datavar; } } cout << endl; } } void TestVariables(VAPoR::DataMgr &dataMgr, bool silenceTime) { vector vars; for (int d = 1; d < 4; d++) { vars = dataMgr.GetDataVarNames(d); if (vars.size()) { std::string varName = vars[0]; PrintCompressionInfo(dataMgr, varName); VAPoR::CoordType minExt, maxExt; dataMgr.GetVariableExtents(0, varName, -1, -1, minExt, maxExt); // Reduce extents about the center of the volume to speed tests for (int i = 0; i < minExt.size(); i++) { double center = (maxExt[i] + minExt[i]) / 2.0; double width = (maxExt[i] - minExt[i]) / 32.0; minExt[i] = center - (width / 2.0); maxExt[i] = center + (width / 2.0); } VAPoR::Grid *grid = dataMgr.GetVariable(0, varName, -1, -1, minExt, maxExt); if (!grid) { cerr << "Failed to read variable " << varName << endl; exit(1); } double rms; size_t numMissingValues; size_t disagreements; CompareIndexToCoords(grid, rms, numMissingValues, disagreements); cout << "Grid test for " << d << "D variable " << varName << ":" << endl; cout << " # Dimensions: " << dataMgr.GetNumDimensions(varName) << endl; std::vector dimLens; dataMgr.GetDimLens(varName, dimLens, 0); std::stringstream ss; for (size_t i = 0; i < dimLens.size(); i++) { if (i != 0) ss << " "; ss << dimLens[i]; } std::string s = ss.str(); cout << " Dimension Lengths: " << s << endl; cout << " Topology Dimension: " << dataMgr.GetVarTopologyDim(varName) << endl; cout << endl; PrintStats(rms, numMissingValues, disagreements, 0.0, silenceTime); } } } ================================================ FILE: test_apps/smokeTests/dataMgrTools.h ================================================ #pragma once #include #include int TestDataMgr(const std::string &fileType, size_t memsize, size_t nthreads, const std::vector &files, const std::vector &options, bool silenceTime); void PrintDimensions(const VAPoR::DataMgr &dataMgr); void PrintMeshes(const VAPoR::DataMgr &dataMgr, bool verbose = false); void PrintCoordVariables(const VAPoR::DataMgr &dataMgr); void PrintTimeCoordinates(const VAPoR::DataMgr &dataMgr); void PrintVariables(const VAPoR::DataMgr &dataMgr, bool verbose = false, bool testVars = false); void PrintCompressionInfo(const VAPoR::DataMgr &dataMgr, const std::string &varname); void TestVariables(VAPoR::DataMgr &dataMgr, bool siclenceTime); ================================================ FILE: test_apps/smokeTests/gridTools.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vapor/VAssert.h" #include "gridTools.h" #include #include #include #include using namespace Wasp; using namespace VAPoR; enum interpOrder { nearestNeighbor = 0, linear = 1 }; namespace { size_t X = 0; size_t Y = 1; size_t Z = 2; std::vector Heap; } // namespace void DeleteHeap() { for (size_t i = 0; i < Heap.size(); i++) std::free(Heap[i]); } template vector AllocateBlocksType(const vector &bs, const vector &dims) { size_t block_size = 1; size_t nblocks = 1; for (size_t i = 0; i < bs.size(); i++) { block_size *= bs[i]; VAssert(dims[i] > 0); size_t nb = ((dims[i] - 1) / bs[i]) + 1; nblocks *= nb; } void *tmp = std::malloc(sizeof(T) * nblocks * block_size); T * buf = static_cast(tmp); Heap.push_back(tmp); std::vector blks; for (size_t i = 0; i < nblocks; i++) { blks.push_back(buf + i * block_size); } return (blks); } vector AllocateBlocks(const vector &bs, const vector &dims) { return (AllocateBlocksType(bs, dims)); } void MakeTriangle(Grid *grid, float minVal, float maxVal, bool addRandomMissingValues) { auto dims = grid->GetDimensions(); size_t x = dims[X]; size_t y = dims[Y]; size_t z = dims[Z]; std::mt19937 engine(0); // Fixed seed of 0 std::uniform_int_distribution<> distrib(0, 9); float value = minVal; float missingValue = grid->GetMissingValue(); for (size_t k = 0; k < z; k++) { for (size_t j = 0; j < y; j++) { for (size_t i = 0; i < x; i++) { value = value == minVal ? maxVal : minVal; if (addRandomMissingValues) { if (!distrib(engine)) grid->SetValueIJK(i, j, k, missingValue); else grid->SetValueIJK(i, j, k, value); } else grid->SetValueIJK(i, j, k, value); } } } } void MakeConstantField(Grid *grid, float value, bool addRandomMissingValues) { auto dims = grid->GetDimensions(); size_t x = dims[X]; size_t y = dims[Y]; size_t z = dims[Z]; std::mt19937 engine(0); // Fixed seed of 0 std::uniform_int_distribution<> distrib(0, 9); float missingValue = grid->GetMissingValue(); for (size_t k = 0; k < z; k++) { for (size_t j = 0; j < y; j++) { for (size_t i = 0; i < x; i++) { if (addRandomMissingValues) { if (!distrib(engine)) grid->SetValueIJK(i, j, k, missingValue); // Generate random 1 or 0 else grid->SetValueIJK(i, j, k, value); } else grid->SetValueIJK(i, j, k, value); } } } } void MakeRamp(Grid *grid, float minVal, float maxVal, bool addRandomMissingValues) { auto dims = grid->GetDimensions(); size_t x = dims[X]; size_t y = dims[Y]; size_t z = dims[Z]; float increment = (maxVal - minVal) / ((x * y * z - 1) == 0 ? 1 : (x * y * z - 1)); std::mt19937 engine(0); // Fixed seed of 0 std::uniform_int_distribution<> distrib(0, 9); float value = minVal; float missingValue = grid->GetMissingValue(); for (size_t k = 0; k < z; k++) { for (size_t j = 0; j < y; j++) { for (size_t i = 0; i < x; i++) { if (addRandomMissingValues) { if (!distrib(engine)) grid->SetValueIJK(i, j, k, missingValue); // Generate random 1 or 0 else grid->SetValueIJK(i, j, k, value); } else grid->SetValueIJK(i, j, k, value); value += increment; } } } } void MakeRampOnAxis(Grid *grid, float minVal, float maxVal, size_t axis = X, bool addRandomMissingValues) { auto dims = grid->GetDimensions(); size_t x = dims[X]; size_t y = dims[Y]; size_t z = dims[Z]; float xIncrement = axis == X ? (maxVal - minVal) / (dims[X] - 1) : 0; float yIncrement = axis == Y ? (maxVal - minVal) / (dims[Y] - 1) : 0; float zIncrement = axis == Z ? (maxVal - minVal) / (dims[Z] - 1) : 0; std::mt19937 engine(0); // Fixed seed of 0 std::uniform_int_distribution<> distrib(0, 9); float value = minVal; float missingValue = grid->GetMissingValue(); for (size_t k = 0; k < z; k++) { value = axis == Y ? minVal : value; // reset value if we're ramping on Y for (size_t j = 0; j < y; j++) { value = axis == X ? minVal : value; // reset value if we're ramping on X for (size_t i = 0; i < x; i++) { if (addRandomMissingValues) { if (!distrib(engine)) grid->SetValueIJK(i, j, k, missingValue); // Generate random 1 or 0 else grid->SetValueIJK(i, j, k, value); } else grid->SetValueIJK(i, j, k, value); value += xIncrement; } value += yIncrement; } value += zIncrement; } } // This function iterates across all nodes in a grid; making comparisons between the // data values returned by the functions GetValueAtIndex() and GetValue(). bool CompareIndexToCoords(VAPoR::Grid *grid, double & rms, // Root Mean Square error size_t & numMissingValues, // Counter for receiving MissingValue upon query size_t & disagreements // Counter for when GetValueAtIndex() and GetValue() disagree ) { bool rc = true; rms = 0.f; disagreements = 0; numMissingValues = 0; auto dims = grid->GetDimensions(); size_t x = dims[X]; size_t y = dims[Y]; size_t z = dims[Z]; double peak = 0.f; double sum = 0; for (size_t k = 0; k < z; k++) { for (size_t j = 0; j < y; j++) { for (size_t i = 0; i < x; i++) { DimsType indices = {i, j, k}; double trueValue = grid->GetValueAtIndex(indices); CoordType coords; grid->GetUserCoordinates(indices, coords); float sampleValue = grid->GetValue(coords); float mv = grid->GetMissingValue(); if (trueValue == mv || sampleValue == mv) { numMissingValues++; // If missing value is not finite we can't do // floating point operations (i.e. computer error) // if (sampleValue != trueValue) { disagreements++; } continue; } double error = abs(sampleValue - trueValue); if (!Wasp::NearlyEqual(error, 0.0)) { disagreements++; } if (error > peak) peak = error; sum += error * error; } } } rms = sqrt(sum / (x * y * z)); if ((!Wasp::NearlyEqual(rms, 0.0)) || disagreements > 0) rc = false; return rc; } bool TestIterator(Grid *g, size_t &count, size_t &expectedCount, size_t &disagreements, double &time) { bool rc = true; count = 0; expectedCount = 1; disagreements = 0; double t0 = Wasp::GetTime(); Grid::Iterator itr; Grid::Iterator enditr = g->end(); itr = g->begin(); auto dims = g->GetDimensions(); for (auto dim : dims) expectedCount *= dim; for (; itr != enditr; ++itr) { DimsType ijk; Wasp::VectorizeCoords(count, dims.data(), ijk.data(), dims.size()); if (!Wasp::NearlyEqual(*itr, g->GetValueAtIndex(ijk))) { disagreements++; } count++; } time = Wasp::GetTime() - t0; if (expectedCount != count || disagreements > 0) { rc = false; } return rc; } bool TestConstCoordItr(const Grid *g, size_t &count, size_t &expectedCount, size_t &disagreements, double &time) { bool rc = true; count = 0; expectedCount = 1; disagreements = 0; double t0 = Wasp::GetTime(); Grid::ConstCoordItr itr; Grid::ConstCoordItr enditr = g->ConstCoordEnd(); itr = g->ConstCoordBegin(); auto dims = g->GetDimensions(); for (auto dim : dims) expectedCount *= dim; for (; itr != enditr; ++itr) { DimsType ijk; Wasp::VectorizeCoords(count, dims.data(), ijk.data(), dims.size()); CoordType coords; bool disagree = false; g->GetUserCoordinates(ijk, coords); for (size_t dim = 0; dim < g->GetGeometryDim(); dim++) { if (!Wasp::NearlyEqual((*itr)[dim], coords[dim])) { disagree = true; } } if (disagree) { disagreements++; } count++; } time = Wasp::GetTime() - t0; if (expectedCount != count || disagreements > 0) { rc = false; } return rc; } void PrintStats(double rms, size_t numMissingValues, size_t disagreements, double time, bool silenceTime) { cout << " RMS error: " << rms << endl; cout << " Missing value count: " << numMissingValues << endl; cout << " GetValueAtIndex() vs GetValue() disagreement count: " << disagreements << endl; if (!silenceTime) cout << " Time: " << time << endl; cout << endl; } // Copy of Grid::GetRange() function from VAPOR release 3.6 // void GetRange_36(VAPoR::Grid* g, float range[2]) { float missingValue = g->GetMissingValue(); auto itr = g->cbegin(); auto enditr = g->cend(); // Edge case: all values are missing values. // range[0] = range[1] = missingValue; while (*itr == missingValue && itr != enditr) { ++itr; } if (itr == enditr) return; range[0] = *itr; range[1] = range[0]; while (itr != enditr) { if (*itr < range[0] && *itr != missingValue) range[0] = *itr; else if (*itr > range[1] && *itr != missingValue) range[1] = *itr; ++itr; } } bool RunTests(Grid *grid, const std::vector &tests, float minVal, float maxVal, bool silenceTime) { auto dims = grid->GetDimensions(); size_t x = dims[X]; size_t y = dims[Y]; size_t z = dims[Z]; bool rc = true; std::string type = grid->GetType(); cout << "=======================================================" << endl << endl; if (std::find(tests.begin(), tests.end(), "Constant") != tests.end()) { cout << type << " " << x << ":" << y << ":" << z << " Constant field:" << endl; MakeConstantField(grid, maxVal); grid->SetInterpolationOrder(linear); if (RunTest(grid, silenceTime) == false) { rc = false; } grid->SetInterpolationOrder(nearestNeighbor); if (RunTest(grid, silenceTime) == false) { rc = false; } } if (std::find(tests.begin(), tests.end(), "Ramp") != tests.end()) { cout << type << " " << x << ":" << y << ":" << z << " Ramp up through domain:" << endl; MakeRamp(grid, minVal, maxVal); grid->SetInterpolationOrder(linear); if (RunTest(grid, silenceTime) == false) { rc = false; } grid->SetInterpolationOrder(nearestNeighbor); if (RunTest(grid, silenceTime) == false) { rc = false; } } if (std::find(tests.begin(), tests.end(), "RampOnAxis") != tests.end()) { cout << type << " " << x << ":" << y << ":" << z << " Ramp up on Z axis:" << endl; MakeRampOnAxis(grid, minVal, maxVal, Z); grid->SetInterpolationOrder(linear); if (RunTest(grid, silenceTime) == false) { rc = false; } grid->SetInterpolationOrder(nearestNeighbor); if (RunTest(grid, silenceTime) == false) { rc = false; } } if (std::find(tests.begin(), tests.end(), "Triangle") != tests.end()) { cout << type << " " << x << ":" << y << ":" << z << " Triangle signal:" << endl; MakeTriangle(grid, minVal, maxVal); grid->SetInterpolationOrder(linear); if (RunTest(grid, silenceTime) == false) { rc = false; } RunTest(grid, silenceTime); grid->SetInterpolationOrder(nearestNeighbor); if (RunTest(grid, silenceTime) == false) { rc = false; } } if (std::find(tests.begin(), tests.end(), "AllMissingValues") != tests.end()) { cout << type << " " << x << ":" << y << ":" << z << " All missing values:" << endl; MakeConstantField(grid, grid->GetMissingValue()); grid->SetInterpolationOrder(linear); if (RunTest(grid, silenceTime) == false) { rc = false; } grid->SetInterpolationOrder(nearestNeighbor); if (RunTest(grid, silenceTime) == false) { rc = false; } } if (std::find(tests.begin(), tests.end(), "NoMissingValues") != tests.end()) { cout << type << " " << x << ":" << y << ":" << z << " No missing values:" << endl; MakeRamp(grid, minVal, maxVal, false); grid->SetInterpolationOrder(linear); if (RunTest(grid, silenceTime) == false) { rc = false; } grid->SetInterpolationOrder(nearestNeighbor); if (RunTest(grid, silenceTime) == false) { rc = false; } } // Iterator tests size_t count; size_t expectedCount; size_t disagreements; double time; if (TestIterator(grid, count, expectedCount, disagreements, time) == false) { rc = false; } PrintGridIteratorResults(type, "Iterator", count, expectedCount, disagreements, time, silenceTime); if (TestConstCoordItr(grid, count, expectedCount, disagreements, time) == false) { rc = false; } PrintGridIteratorResults(type, "ConstCoordIterator", count, expectedCount, disagreements, time, silenceTime); if (TestConstNodeIterator(grid, count, expectedCount, disagreements, time, false) == false) { rc = false; } PrintGridIteratorResults(type, "ConstNodeIterator", count, expectedCount, disagreements, time, silenceTime); if (TestConstNodeIterator(grid, count, expectedCount, disagreements, time, true) == false) { rc = false; } PrintGridIteratorResults(type, "ConstNodeIterator with bounds", count, expectedCount, disagreements, time, silenceTime); return rc; } bool TestConstNodeIterator(const Grid *g, size_t &count, size_t &expectedCount, size_t &disagreements, double &time, bool withCoordBounds) { bool rc = true; count = 0; expectedCount = 1; disagreements = 0; double t0 = Wasp::GetTime(); Grid::ConstNodeIterator itr; Grid::ConstNodeIterator enditr = g->ConstNodeEnd(); if (withCoordBounds) { CoordType minu, maxu; g->GetUserExtents(minu, maxu); itr = g->ConstNodeBegin(minu, maxu); } else { itr = g->ConstNodeBegin(); } auto dims = g->GetDimensions(); for (auto dim : dims) expectedCount *= dim; for (; itr != enditr; ++itr) { DimsType ijk3 = {0, 0, 0}; Wasp::VectorizeCoords(count, dims.data(), ijk3.data(), dims.size()); double itrData = g->GetValueAtIndex(*itr); double gridData = g->GetValueAtIndex(ijk3); if (!Wasp::NearlyEqual(itrData, gridData)) { disagreements++; } count++; } time = Wasp::GetTime() - t0; if (expectedCount != count || disagreements > 0) { rc = false; } return rc; } bool RunTest(Grid *grid, bool silenceTime) { bool rc = true; double rms; size_t numMissingValues; size_t disagreements; double t0 = Wasp::GetTime(); rc = CompareIndexToCoords(grid, rms, numMissingValues, disagreements); if (grid->GetInterpolationOrder() == 0) { cout << " Interpolation order: nearestNeighbor " << endl; } else { cout << " Interpolation order: linear " << endl; } double time = Wasp::GetTime() - t0; PrintStats(rms, numMissingValues, disagreements, time, silenceTime); // Test the correctness of OpenMP implementation of Grid::GetRange() float range_36[2] = {0.0, 1.1}; float range_omp[2] = {2.2, 3.3}; GetRange_36(grid, range_36); grid->GetRange(range_omp); bool omp_good = (range_36[0] == range_omp[0] && range_36[1] == range_omp[1]); rc = rc && omp_good; if (rc == false) { cout << " *** Error reported in " << grid->GetType() << " grid ***" << endl << endl; } else { cout << endl; } return rc; } void PrintGridIteratorResults(std::string &gridType, std::string itrType, size_t count, size_t expectedCount, size_t disagreements, double time, bool silenceTime) { std::string passFail = " --- PASS"; if (count != expectedCount || disagreements > 0) { passFail = " --- FAIL"; } cout << gridType << " Grid::" << itrType << passFail << endl; cout << " Count: " << count << endl; cout << " Expected Count: " << expectedCount << endl; cout << " Value Disagreements: " << disagreements << endl; if (!silenceTime) cout << " Time: " << time << endl; cout << endl; } VAPoR::CurvilinearGrid *MakeCurvilinearTerrainGrid(const std::vector &bs, const std::vector &minu, const std::vector &maxu, const std::vector &dims) { std::vector bs2d = {bs[X], bs[Y]}; std::vector dims2d = {dims[X], dims[Y]}; std::vector minu2d = {minu[X], minu[Y]}; std::vector maxu2d = {maxu[X], maxu[Y]}; std::vector xblks = AllocateBlocks(bs2d, dims2d); auto xrg = std::unique_ptr(new RegularGrid(dims2d, bs2d, xblks, minu2d, maxu2d)); MakeRampOnAxis(xrg.get(), minu[X], maxu[X], X, false); std::vector yblks = AllocateBlocks(bs2d, dims2d); auto yrg = std::unique_ptr(new RegularGrid(dims2d, bs2d, yblks, minu2d, maxu2d)); MakeRampOnAxis(yrg.get(), minu[Y], maxu[Y], Y, false); std::vector zblks = AllocateBlocks(bs, dims); auto zrg = std::unique_ptr(new RegularGrid(dims, bs, zblks, minu, maxu)); MakeRampOnAxis(zrg.get(), minu[Z], maxu[Z], Z, false); std::vector blks = AllocateBlocks(bs, dims); CurvilinearGrid * cg = new CurvilinearGrid(dims, bs, blks, *xrg, *yrg, *zrg, NULL); return (cg); } LayeredGrid *MakeLayeredGrid(const vector &dims, const vector &bs, const std::vector &minu, const std::vector &maxu) { std::vector zCoordBlocks = AllocateBlocks(bs, dims); RegularGrid rg(dims, bs, zCoordBlocks, minu, maxu); MakeRampOnAxis(&rg, minu[Z], maxu[Z], Z, false); double deltax = dims[X] > 1 ? maxu[X] - minu[X] / (dims[X] - 1) : 1; vector xcoords; for (int i = 0; i < dims[X]; i++) { xcoords.push_back(minu[X] + (i * deltax)); } // Get horizontal dimensions // double deltay = dims[Y] > 2 ? maxu[Y] - minu[Y] / (dims[Y] - 1) : 1; vector ycoords; for (int i = 0; i < dims[Y]; i++) { ycoords.push_back(minu[1] + (i * deltay)); } std::vector dataBlocks = AllocateBlocks(bs, dims); LayeredGrid * lg = new LayeredGrid(dims, bs, dataBlocks, xcoords, ycoords, rg); return (lg); } VAPoR::StretchedGrid *MakeStretchedGrid(const vector &dims, const vector &bs, const std::vector &minu, const std::vector &maxu) { std::vector xCoords(dims[X], 0); std::vector yCoords(dims[Y], 0); std::vector zCoords(dims[Z], 0); double xRange = maxu[X] - minu[X]; double yRange = maxu[Y] - minu[Y]; double zRange = maxu[Z] - minu[Z]; double xDenom = dims[X] > 1 ? dims[X] - 1 : 1; double yDenom = dims[Y] > 1 ? dims[Y] - 1 : 1; double zDenom = dims[Z] > 1 ? dims[Z] - 1 : 1; // Parabolically increasing coordinates for (size_t i = 0; i < dims[X]; i++) { double xIncrement = xRange * pow(float(i) / xDenom, 2.0); xCoords[i] = xIncrement + minu[X]; } for (size_t i = 0; i < dims[Y]; i++) { double yIncrement = yRange * pow(float(i) / yDenom, 2.0); yCoords[i] = yIncrement + minu[Y]; } for (size_t i = 0; i < dims[Z]; i++) { double zIncrement = zRange * pow(float(i) / zDenom, 2.0); zCoords[i] = zIncrement + minu[Z]; } vector blocks = AllocateBlocks(bs, dims); StretchedGrid * sg = new StretchedGrid(dims, bs, blocks, xCoords, yCoords, zCoords); return sg; } VAPoR::UnstructuredGrid2D *MakeUnstructuredGrid2D(const vector &dims, const vector &bs, const std::vector &minu, const std::vector &maxu) { VAssert(dims.size() >= 2); VAssert(bs.size() >= 2); vector bs1d = {bs[0] * bs[1]}; vector dims1d = {dims[0] * dims[1]}; vector vertexDims = {dims[0] * dims[1]}; vector faceDims = {(dims[0] - 1) * (dims[1] - 1) * 2}; vector edgeDims; UnstructuredGrid::Location location = UnstructuredGrid2D::Location::NODE; size_t maxVertexPerFace = 3; // each cell is a triangle size_t maxFacePerVertex = 6; // each interior vertex defines 6 triangles long vertexOffset = 0; long faceOffset = 0; const int *faceOnFace = NULL; std::vector xCoordBlocks = AllocateBlocksType(bs1d, dims1d); std::vector yCoordBlocks = AllocateBlocksType(bs1d, dims1d); std::vector vertexOnFace = AllocateBlocksType(vector{faceDims[0] * maxVertexPerFace}, vector{faceDims[0] * maxVertexPerFace}); size_t face = 0; for (size_t j = 0; j < dims[1] - 1; j++) { for (size_t i = 0; i < dims[0] - 1; i++) { vertexOnFace[0][face + 0] = j * (dims[0]) + i; vertexOnFace[0][face + 1] = j * (dims[0]) + i + 1; vertexOnFace[0][face + 2] = (j + 1) * (dims[0]) + i; face += maxVertexPerFace; vertexOnFace[0][face + 0] = j * (dims[0]) + i + 1; vertexOnFace[0][face + 1] = (j + 1) * (dims[0]) + i + 1; vertexOnFace[0][face + 2] = (j + 1) * (dims[0]) + i; face += maxVertexPerFace; } } std::vector faceOnVertex = AllocateBlocksType(vector{vertexDims[0] * maxFacePerVertex}, vector{vertexDims[0] * maxFacePerVertex}); // In the diagram below the x's are nodes and the triangle faces are numbered 0 to 7 // // The faces connected to the center node (x) are 6,5,4,1,2,3. // The faces connected to the bottom, left node (x) are 0 // The faces connected to the bottom, right node (x) are 3,2 // // x---x---x // |4\5|6\7| // x---x---x // |0\1|2\3| // x---x---x // int vertex = 0; for (long j = 0; j < dims[1]; j++) { int leftMostFaceTop = (j * (dims[0] - 1)) * 2; int rightMostFaceTop = leftMostFaceTop + 2 * (dims[0] - 1) - 1; int leftMostFaceBot = ((j - 1) * (dims[0] - 1)) * 2; int rightMostFaceBot = leftMostFaceBot + 2 * (dims[0] - 1) - 1; for (long i = 0; i < dims[0]; i++, vertex++) { // Initialize to missing faces // int face_i = 0; for (face_i = 0; face_i < maxFacePerVertex; face_i++) { faceOnVertex[0][(vertex * maxFacePerVertex) + face_i] = -1; } // No top of triangles for last row of nodes // face_i = 0; if (j < (dims[1] - 1)) { int face = ((j) * ((int)dims[0] - 1) * 2) + (2 * i); // top row of triangles - iterate in CC order // for (int ii = 0; ii < 3; ii++, face--) { if (face < leftMostFaceTop || face > rightMostFaceTop) continue; faceOnVertex[0][(vertex * maxFacePerVertex) + face_i] = face; face_i++; } } // No bottom row of triangles for first row of nodes // if (j > 0) { int face = ((j - 1) * ((int)dims[0] - 1) * 2) + (2 * i) - 1; // bottom row of triangles - iterate in CC order // for (int ii = 0; ii < 3; ii++, face++) { if (face < leftMostFaceBot || face > rightMostFaceBot) continue; faceOnVertex[0][(vertex * maxFacePerVertex) + face_i] = face; face_i++; } } } } UnstructuredGridCoordless xug(vertexDims, faceDims, edgeDims, bs1d, xCoordBlocks, 2, vertexOnFace[0], faceOnVertex[0], faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset); UnstructuredGridCoordless yug(vertexDims, faceDims, edgeDims, bs1d, yCoordBlocks, 2, vertexOnFace[0], faceOnVertex[0], faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset); float deltaX = 1.0 / (dims[0] - 1); float deltaY = 1.0 / (dims[1] - 1); for (long j = 0; j < dims[1]; j++) { for (long i = 0; i < dims[0]; i++) { DimsType indices = {j * dims[0] + i, 0, 0}; xug.SetValue(indices, i * deltaX); yug.SetValue(indices, j * deltaY); } } UnstructuredGridCoordless zug; vector blocks = AllocateBlocks(bs1d, dims1d); UnstructuredGrid2D *g = new UnstructuredGrid2D(vertexDims, faceDims, edgeDims, bs1d, blocks, vertexOnFace[0], faceOnVertex[0], faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset, xug, yug, zug, nullptr); return g; } ================================================ FILE: test_apps/smokeTests/gridTools.h ================================================ #pragma once #include #include #include #include #include void DeleteHeap(); std::vector AllocateBlocks(const std::vector &bs, const std::vector &dims); void MakeTriangle(VAPoR::Grid *grid, float minVal, float maxVal, bool addRandomMissingValues=true); void MakeConstantField(VAPoR::Grid *grid, float value, bool addRandomMissingValues=true); void MakeRamp(VAPoR::Grid *grid, float minVal, float maxVal, bool addRandomMissingValues=true); void MakeRampOnAxis(VAPoR::Grid *grid, float minVal, float maxVal, size_t axis, bool addRandomMissingValues=true); bool CompareIndexToCoords(VAPoR::Grid *grid, double & rms, // Root Mean Square error size_t & numMissingValues, // Counter for receiving MissingValue upon query size_t & disagreements // Counter for when AccessIJK() and GetValue() disagree ); // Returns the expected node count for Grid::Iterator bool TestIterator(VAPoR::Grid *g, size_t &count, size_t &expectedCount, size_t &disagreements, double &time); // Returns the expected node count for Grid::ConstCoordIterator bool TestConstCoordItr(const VAPoR::Grid *g, size_t &count, size_t &expectedCount, size_t &disagreements, double &time); // Returns the expected node count for Grid::ConstNodeIterator bool TestConstNodeIterator(const VAPoR::Grid *g, size_t &count, size_t &expectedCount, size_t &disagreements, double &time, bool withCoordBounds); void PrintStats(double rms, size_t numMissingValues, size_t disagreements, double time, bool silenceTime); bool RunTests(VAPoR::Grid *grid, const std::vector &tests, float minVal, float maxVal, bool silenceTime); bool RunTest(VAPoR::Grid *grid, bool silenceTime); void PrintGridIteratorResults(std::string &gridType, std::string itrType, size_t count, size_t expectedCount, size_t disagreements, double time, bool silenceTime); VAPoR::CurvilinearGrid *MakeCurvilinearTerrainGrid(const std::vector &bs, const std::vector &minu, const std::vector &maxu, const std::vector &dims); VAPoR::LayeredGrid *MakeLayeredGrid(const std::vector &dims, const std::vector &bs, const std::vector &minu, const std::vector &maxu); VAPoR::StretchedGrid *MakeStretchedGrid(const std::vector &dims, const std::vector &bs, const std::vector &minu, const std::vector &maxu); VAPoR::UnstructuredGrid2D *MakeUnstructuredGrid2D(const std::vector &dims, const std::vector &bs, const std::vector &minu, const std::vector &maxu); ================================================ FILE: test_apps/smokeTests/smokeTests.py ================================================ #! /usr/bin/env python3 import sys import os import subprocess import difflib import argparse # # Argument Parser # parser = argparse.ArgumentParser( "A test driver for the DataMgr and Grid classes" ) parser.add_argument( '-makeBaseline', default=False, dest='makeBaseline', action='store_true', help='This flag makes these test results the baseline on which future' + ' tests will be compared. If no baseline file exists, this will automatically ' + ' be set to true.' ) parser.add_argument( '-testDataRoot', nargs=1, type=str, default="~/Data/smokeTestData", required=False, metavar='/path/to/data', help='Directory where DataMgr test data is stored.' ) parser.add_argument( '-binaryRoot', nargs=1, type=str, default="~/VAPOR/build/test_binaries", required=False, metavar='/path/to/binaries', help='Directory where binary test programs (testGrid, testDataMgr) are stored.' ) parser.add_argument( '-resultsDir', nargs=1, type=str, default="~/VAPOR/test_apps/smokeTests/testResults", required=False, metavar='/path/to/write/results/to', help='Directory where test results are stored.' ) parser.add_argument( '-silenceTime', default=False, dest='silenceTime', action='store_true', help='This flag sliences the elapsed time from the printed results.' ) args = vars(parser.parse_args()) # # Default directories and test data # gridSizes = [ # "1:1:1", "2:2:2", "4:2:2", "8:2:2", # "1:8:8", # "8:1:8", # "8:8:1", "7:7:7", "8:8:8" ] resultsDir = os.path.expanduser("".join( args['resultsDir'] )) if (resultsDir[-1] != r'/'): resultsDir += r'/' testDataRoot = os.path.expanduser("".join( args['testDataRoot'] )) if (testDataRoot[-1] != r'/'): testDataRoot += r'/' binaryRoot = os.path.expanduser("".join( args['binaryRoot'] )) if (binaryRoot[-1] != r'/'): binaryRoot += r'/' if( args['silenceTime'] ): silenceTime = "-silenceTime" else: silenceTime = "" print("resultsDir " + resultsDir ) print("testDataRoot " + testDataRoot) print("binaryRoot " + binaryRoot ) print("silenceTime " + str(silenceTime)) dataMgrs = { #"mpas" : (testDataRoot + "hist.mpas-o.0001-01-01_00.00.00.nc") "wrf" : (testDataRoot + "wrfout_d02_2005-08-29_05"), "cf" : (testDataRoot + "24Maycontrol.04000.000000.nc"), "vdc" : (testDataRoot + "katrina_1timeStep.vdc"), } gridProgram = binaryRoot + "testGrid" dataMgrProgram = binaryRoot + "testDataMgr" gridResultsFile = resultsDir + "gridResults.txt" dataMgrResultsFile = resultsDir + "dataMgrResults.txt" # # Tests # def testGrid( grid ): rc = 0 print( "Testing " + grid + " grid" ) print(" Command: " + gridProgram + " -dims " + grid + " " + silenceTime ) programOutput = subprocess.run( [ gridProgram, "-dims", grid, silenceTime ], stdout=subprocess.PIPE, universal_newlines=True ) outputFileName = resultsDir + grid + ".txt" try: with open( outputFileName, "w" ) as outputFile: outputFile.write( programOutput.stdout ) outputFile.close() print( " " + outputFileName + " written" ) except IOError: print( "Unable to write to file " + outputFileName ) sys.exit(-1) if ( programOutput.returncode != 0 ): rc = 1 print( " Test failed with exit code " + str(programOutput.returncode) ) else: print( " Test passed\n" ) return rc def testDataMgr( dataMgrType, dataMgr, makeBaseline=False ): print( "Testing " + dataMgrType + " with " + dataMgr ) command = [] if( silenceTime != "" ): command = [ dataMgrProgram, silenceTime, "-fileType", dataMgrType, dataMgr ] else: command = [ dataMgrProgram, "-fileType", dataMgrType, dataMgr ] print( " Command: " + " ".join(command) ) programOutput = subprocess.check_output( command ) if ( makeBaseline ): outputFileName = resultsDir + dataMgrType + "_baseline.txt" else: outputFileName = resultsDir + dataMgrType + ".txt" try: with open( outputFileName, "w" ) as outputFile: outputFile = open( outputFileName, "w" ) outputFile.write( programOutput.decode("utf-8") ) outputFile.close() print( " " + outputFileName + " written\n" ) except IOError: print( "Unable to write to file " + outputFileName ) sys.exit(-1) return outputFileName def testDataMgrs( makeBaseline ): diff = open( dataMgrResultsFile, "w" ) mismatches = 0 for dataType, dataFile in dataMgrs.items(): # If we're making a baseline file, generate it, and then skip comparisons if ( makeBaseline ): resultsFile = testDataMgr( dataType, dataFile, makeBaseline ) continue resultsFile = testDataMgr( dataType, dataFile ) baselineFile = resultsDir + dataType + "_baseline.txt" baseline = open( baselineFile, "r" ) results = open( resultsFile, "r" ) # Note - we are not reading the last line of these files, since it's the # runtime for the test ( hence the [:-1] specification ) baselineLines = baseline.readlines()[:-1] resultsLines = results.readlines()[:-1] for line in difflib.unified_diff(resultsLines, baselineLines, resultsFile, baselineFile): diff.write( line ) mismatches+=1 baseline.close() results.close() diff.close() if ( makeBaseline == False ): print( dataMgrResultsFile + " written" ) print( "\n DataMgr tests resulted in " + str(mismatches) + " mismatches\n" ) else: print( "Baseline files have been generated. Re-run smokeTests.py to run comparions.\n" ) if ( mismatches > 0 ): return -1 else: return 0 def main(): makeBaseline = args['makeBaseline'] rc = 0 if ( makeBaseline == True ): print( " Warning: Some or all baseline files for running DataMgr tests were missing. " " These files are needed as comparisons for the results of the current series " " of tests, versus a known working build (the baseline).\n" " Generating baseline files in the results directory....\n" ) if ( os.path.isdir( resultsDir ) == False ): os.mkdir( resultsDir ) for grid in gridSizes: if ( testGrid(grid) != 0): print (" See artifact file " + grid + ".txt or " + resultsDir + grid + ".txt for mismatches") print (" Failed assertions, if any, are shown above.\n" ) rc = 1 for dataType, dataFile in dataMgrs.items(): baselineFile = resultsDir + dataType + "_baseline.txt" if ( os.path.isfile( baselineFile ) == False ): makeBaseline = True continue dataMgr = testDataMgrs( makeBaseline ) if ( dataMgr != 0 ): print( "DataMgr tests failed. Results are not identical to the baseline." ) rc = 1 else: print( "DataMgr tests passed" ) sys.exit(rc) if __name__ == "__main__": main() ================================================ FILE: test_apps/smokeTests/testDataMgr.cpp ================================================ // This test exercises the following DataMgr functions, and prints their // results. These results can be captured and compared to previous results // as part of an automated test for reviewing Pull Requests. // // Functions under test: // // DataMGr::DataMgr(string format, size_t mem_size, int nthreads = 0) // DataMgr::GetDimensionNames() // DataMgr::GetDimension( string dimname, DC:Dimension &dimension) // DataMgr::GetMeshNames() // DataMgr::GetMesh(string meshname, DC::Mesh &mesh) // DataMgr::GetDataVarNames(int ndim) // DataMgr::GetCoordVarNames() // DataMgr::GetTimeCoordinates() // DataMgr::GetTimeCoordVarName() // DataMgr::GetNumTimeSteps() // DataMgr::GetDataVarInfo(string varname, VAPoR::DC::DataVar &datavar) // DataMgr::GetNumRefLevels(string varname) // DataMgr::GetCRatios(string varname) // DataMgr::GetVariable( // size_t ts, string varname, int level, int lod, bool lock=false // ) // DataMgr::GetVariableExtents( // size_t ts, string varname, int level, int lod, // std::vector &min , std::vector &max // ) // DataMgr::GetDimLens(string varname, std::vector &dims) // DataMgr::GetNumDimensions( string varname ) // DataMgr::GetVarTopologyDim( sting varname ) // DataMgr::GetMapProjection() #include #include #include #include #include #include #include #include #include #include #include #include "vapor/VAssert.h" #include "gridTools.h" #include "dataMgrTools.h" using namespace Wasp; using namespace VAPoR; struct { std::string fileType; int memsize; int nthreads; OptionParser::Boolean_T silenceTime; OptionParser::Boolean_T nogeoxform; OptionParser::Boolean_T novertxform; } opt; OptionParser::OptDescRec_T set_opts[] = {{"fileType", 1, "vdc", "data set type (vdc|wrf|cf|mpas)"}, {"memsize", 1, "2000", "Cache size in MBs"}, {"nthreads", 1, "0", "Specify number of execution threads " "0 => use number of cores"}, {"silenceTime", 0, "", "Do not print elapsed time for tests"}, {"nogeoxform", 0, "", "Do not apply geographic transform (projection to PCS"}, {"novertxform", 0, "", "Do not apply to convert pressure, etc. to meters"}, {nullptr}}; OptionParser::Option_T get_options[] = {{"fileType", Wasp::CvtToCPPStr, &opt.fileType, sizeof(opt.fileType)}, {"memsize", Wasp::CvtToInt, &opt.memsize, sizeof(opt.memsize)}, {"nthreads", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {"silenceTime", Wasp::CvtToBoolean, &opt.silenceTime, sizeof(opt.silenceTime)}, {"nogeoxform", Wasp::CvtToBoolean, &opt.nogeoxform, sizeof(opt.nogeoxform)}, {"novertxform", Wasp::CvtToBoolean, &opt.novertxform, sizeof(opt.novertxform)}, {nullptr}}; void InitializeOptions(int &argc, char **argv, OptionParser &op, std::vector &files, std::vector &options) { std::string ProgName = FileUtils::LegacyBasename(argv[0]); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(EXIT_FAILURE); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(EXIT_FAILURE); } if (argc < 2) { cerr << "Usage: " << ProgName << " [options] dataFile " << endl; op.PrintOptionHelp(stderr); exit(EXIT_FAILURE); } for (int i = 1; i < argc; i++) { files.push_back(argv[i]); } if (!opt.nogeoxform) { options.push_back("-project_to_pcs"); } if (!opt.novertxform) { options.push_back("-vertical_xform"); } } int main(int argc, char **argv) { double t0 = Wasp::GetTime(); MyBase::SetErrMsgFilePtr(stderr); OptionParser op; std::vector files; std::vector options; InitializeOptions(argc, argv, op, files, options); for (int i = 0; i < files.size(); i++) { std::string fileName = files[i]; fileName = fileName.substr(fileName.find_last_of("\\/") + 1); cout << fileName << endl; } int rc = TestDataMgr(opt.fileType, opt.memsize, opt.nthreads, files, options, opt.silenceTime); if (!opt.silenceTime) cout << "Elapsed time: " << Wasp::GetTime() - t0 << endl; return rc; } ================================================ FILE: test_apps/smokeTests/testGrid.cpp ================================================ // This test exercises the RegularGrid, StretchedGrid, LayeredGrid, // and CurvilinearGrid classes. These grids are created according to // a user-changable discretization, coordinate range, value range, // and block size. // // The grids are then assigned values according to // three data patterns: a constant field, a linear ramp, and a triangle // signal. // // After values are assigned, values are gathered and compared // from the functions Grid::GetValue( {i, j, k} ) and Grid::AccessIJK(i,j,k). // RMS error is computed, along with counts for mismatches, and queries // that yield missing values. // // This process is repeated once for linear interpolation, and once for // nearest-neighbor interpolation. // // Functions under test: // LayeredGrid::LayeredGrid( // const std::vector &dims, // const std::vector &bs, // const std::vector &blks, // const std::vector &xcoords, // const std::vector &ycoords, // const RegularGrid &rg // ) // RegularGrid::RegularGrid( // const std::vector &dims, // const std::vector &bs, // const std::vector &blks, // const std::vector &minu, // const std::vector &maxu // ) // StretchedGrid::StretchedGrid( // const std::vector &dims, // const std::vector &bs, // const std::vector &blks, // const std::vector &xcoords, // const std::vector &ycoords, // const std::vector &zcoords // ) // CurvilinearGrid::CurvilinearGrid( // const std::vector &dims, // const std::vector &bs, // const std::vector &blks, // const RegularGrid &xrg, // const RegularGrid &yrg, // const RegularGrid &zrg, // std::shared_ptr > qtr // ) // Grid::GetDimensions() // Grid::SetValueIJK(size_t i, size_t j, size_t k, float v) // Grid::GetUserExtents( // std::vector &minu, std::vector &maxu // ) // Grid::GetValueAtIndex(const size_t indices[3]) // Grid::GetUserCoordinates( // const size_t indices[], // double coords[] // ) // Grid::GetValue(const std::vector &coords) // Grid::GetMissingValue() // Grid::SetInterpolationOrder(int order) #include #include #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include #include "gridTools.h" #include #include #include using namespace Wasp; using namespace VAPoR; namespace { size_t X = 0; size_t Y = 1; size_t Z = 2; std::vector Heap; } // namespace struct opt_t { std::vector grids; std::vector arrangements; std::vector dims; std::vector bs; std::vector extents; double minValue; double maxValue; OptionParser::Boolean_T silenceTime; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"grids", 1, "Regular:Stretched:Layered:Curvilinear:Unstructured2D", "Colon delimited list of grids to test"}, {"arrangements", 1, "Constant:Ramp:RampOnAxis:Triangle:AllMissingValues:NoMissingValues", "Colon delimited list of " "data arrangements to test synthetic grids with"}, {"dims", 1, "8:8:8", "Data volume dimensions expressed in " "grid points (NX:NY:NZ)"}, {"bs", 1, "64:64:64", "Internal storage blocking factor expressed in grid points (NX:NY:NZ)"}, {"extents", 1, "0:0:0:1:1:1", "Colon delimited 6-element vector " "specifying domain extents of synthetic grids in user coordinates " "(X0:Y0:Z0:X1:Y1:Z1)"}, {"minValue", 1, "0", "The minimum data value to be assigned to cells in synthetic grids"}, {"maxValue", 1, "1", "The maximum data value to be assigned to cells in synthetic grids"}, {"silenceTime", 0, "", "Do not print elapsed time for tests"}, {"help", 0, "", "Print this message and exit"}, {nullptr}}; OptionParser::Option_T get_options[] = {{"grids", Wasp::CvtToStrVec, &opt.grids, sizeof(opt.grids)}, {"arrangements", Wasp::CvtToStrVec, &opt.arrangements, sizeof(opt.arrangements)}, {"dims", Wasp::CvtToSize_tVec, &opt.dims, sizeof(opt.dims)}, {"bs", Wasp::CvtToSize_tVec, &opt.bs, sizeof(opt.bs)}, {"extents", Wasp::CvtToFloatVec, &opt.extents, sizeof(opt.extents)}, {"minValue", Wasp::CvtToDouble, &opt.minValue, sizeof(opt.minValue)}, {"maxValue", Wasp::CvtToDouble, &opt.maxValue, sizeof(opt.maxValue)}, {"silenceTime", Wasp::CvtToBoolean, &opt.silenceTime, sizeof(opt.silenceTime)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {nullptr}}; void InitializeOptions(int argc, char **argv, OptionParser &op) { std::string ProgName = FileUtils::LegacyBasename(argv[0]); MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(EXIT_FAILURE); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(EXIT_FAILURE); } if (opt.extents.size() != 6) { cerr << "The -extents flag must contain 6 elements if used" << endl; op.PrintOptionHelp(stderr, 80, false); exit(EXIT_FAILURE); } if (opt.dims.size() != 3) { cerr << "The -dims flag must contain 3 elements if used" << endl; op.PrintOptionHelp(stderr); exit(EXIT_FAILURE); } if (opt.help) { op.PrintOptionHelp(stderr); exit(EXIT_FAILURE); } } int main(int argc, char **argv) { double t0 = Wasp::GetTime(); OptionParser op; InitializeOptions(argc, argv, op); std::cout << std::fixed << std::showpoint; std::cout << std::setprecision(4); std::vector minu = {opt.extents[X], opt.extents[Y], opt.extents[Z]}; std::vector maxu = {opt.extents[X + 3], opt.extents[Y + 3], opt.extents[Z + 3]}; std::vector bs2d = {opt.bs[X], opt.bs[Y]}; std::vector minu2d = {minu[X], minu[Y]}; std::vector maxu2d = {maxu[X], maxu[Y]}; std::vector dims2d = {opt.dims[X], opt.dims[Y]}; int rc = EXIT_SUCCESS; bool regularRC = true; bool stretchedRC = true; bool layeredRC = true; bool curvilinearRC = true; bool unstructured2DRC = true; #pragma omp parallel { if (omp_get_thread_num() == 0) cout << "Num threads: " << omp_get_num_threads() << endl; } // Test Regular Grid if (std::find(opt.grids.begin(), opt.grids.end(), "Regular") != opt.grids.end()) { double t0 = Wasp::GetTime(); std::vector rgBlks = AllocateBlocks(opt.bs, opt.dims); RegularGrid * regularGrid = new RegularGrid(opt.dims, opt.bs, rgBlks, minu, maxu); double t1 = Wasp::GetTime() - t0; if (!opt.silenceTime) cout << "RegularGrid() time: " << t1 << endl; regularRC = RunTests(regularGrid, opt.arrangements, opt.minValue, opt.maxValue, opt.silenceTime); delete regularGrid; } // Test Stretched Grid if (std::find(opt.grids.begin(), opt.grids.end(), "Stretched") != opt.grids.end()) { double t0 = Wasp::GetTime(); StretchedGrid *stretchedGrid = MakeStretchedGrid(opt.dims, opt.bs, minu, maxu); double t1 = Wasp::GetTime() - t0; if (!opt.silenceTime) cout << "MakeStretchedGrid() time: " << t1 << endl; stretchedRC = RunTests(stretchedGrid, opt.arrangements, opt.minValue, opt.maxValue, opt.silenceTime); delete stretchedGrid; } // Test Layered Grid if (std::find(opt.grids.begin(), opt.grids.end(), "Layered") != opt.grids.end()) { double t0 = Wasp::GetTime(); LayeredGrid *layeredGrid = MakeLayeredGrid(opt.dims, opt.bs, minu, maxu); double t1 = Wasp::GetTime() - t0; if (!opt.silenceTime) cout << "MakeLayeredGrid() time: " << t1 << endl; layeredRC = RunTests(layeredGrid, opt.arrangements, opt.minValue, opt.maxValue, opt.silenceTime); delete layeredGrid; } // Test Curvilinear Grid if (std::find(opt.grids.begin(), opt.grids.end(), "Curvilinear") != opt.grids.end()) { double t0 = Wasp::GetTime(); CurvilinearGrid *curvilinearGrid; curvilinearGrid = MakeCurvilinearTerrainGrid(opt.bs, minu, maxu, opt.dims); double t1 = Wasp::GetTime() - t0; if (!opt.silenceTime) cout << "MakeCurvilinearTerrainGrid() time: " << t1 << endl; curvilinearRC = RunTests(curvilinearGrid, opt.arrangements, opt.minValue, opt.maxValue, opt.silenceTime); delete curvilinearGrid; } // Test Unstructured Grid 2D if (std::find(opt.grids.begin(), opt.grids.end(), "Unstructured2D") != opt.grids.end() && opt.dims[0] > 1 && opt.dims[1] > 1) { double t0 = Wasp::GetTime(); UnstructuredGrid2D *g = MakeUnstructuredGrid2D(opt.dims, opt.bs, minu, maxu); double t1 = Wasp::GetTime() - t0; if (!opt.silenceTime) cout << "MakeUnstructuredGrid2D() time: " << t1 << endl; unstructured2DRC = RunTests(g, opt.arrangements, opt.minValue, opt.maxValue, opt.silenceTime); delete g; } if (regularRC == false) { cerr << "Errors occurred while testing Grid::RegularGrid." << endl; rc = EXIT_FAILURE; } if (stretchedRC == false) { cerr << "Errors occurred while testing Grid::StretchedGrid." << endl; rc = EXIT_FAILURE; } if (layeredRC == false) { cerr << "Errors occurred while testing Grid::LayeredGrid." << endl; rc = EXIT_FAILURE; } if (curvilinearRC == false) { cerr << "Errors occurred while testing Grid::CurvilinearGrid." << endl; rc = EXIT_FAILURE; } if (unstructured2DRC == false) { cerr << "Errors occurred while testing Grid::UnstructuredGrid2D." << endl; rc = EXIT_FAILURE; } double t1 = Wasp::GetTime(); if (!opt.silenceTime) cout << "Elapsed time: " << t1 - t0 << endl; DeleteHeap(); return rc; } ================================================ FILE: test_apps/smokeTests/testResults/cf_baseline.txt ================================================ 24Maycontrol.04000.000000.nc Dimensions: time = 1 Time Varying: 0 xh = 371 Time Varying: 0 yh = 441 Time Varying: 0 zf = 201 Time Varying: 0 zh = 201 Time Varying: 0 Meshes: xhxyhxzh 3D variables: dbz hvort prespert qc qg qr streamvort thrhopert uinterp vinterp vortmag winterp xvort yvort zvort Compression Info for variable dbz: Refinement Levels: 1 Compression Ratios: 1 Grid test for 3D variable dbz: # Dimensions: 3 Dimension Lengths: 371 441 201 Topology Dimension: 3 RMS error: 0 Missing value count: 0 GetValueAtIndex() vs GetValue() disagreement count: 0 Time: 0 Projection String: Coordinate Variables: time xh yh zf zh time Time Coordinates: -31618400 Time coordinate variable name: time Number of time steps: 1 Elapsed time: 0.00193455 ================================================ FILE: test_apps/smokeTests/testResults/vdc_baseline.txt ================================================ katrina_1timeStep.vdc Dimensions: DateStrLen = 19 Time Varying: 0 Time = 1 Time Varying: 0 bottom_top = 34 Time Varying: 0 bottom_top_stag = 35 Time Varying: 0 ext_scalar = 1 Time Varying: 0 soil_layers_stag = 5 Time Varying: 0 south_north = 309 Time Varying: 0 south_north_stag = 310 Time Varying: 0 west_east = 315 Time Varying: 0 west_east_stag = 316 Time Varying: 0 Meshes: west_eastXsouth_north west_eastXsouth_northXbottom_top west_eastXsouth_northXbottom_top_stag west_eastXsouth_northXsoil_layers_stag west_eastXsouth_north_stag west_eastXsouth_north_stagXbottom_top west_east_stagXsouth_north west_east_stagXsouth_northXbottom_top 2D variables: CANWAT COSALPHA E F GLW GRDFLX HFX HGT LANDMASK LH LU_INDEX MAPFAC_M MAPFAC_U MAPFAC_V MU MUB NEST_POS PBLH PSFC Q2 QFX RAINC RAINNC RMOL SFROFF SINALPHA SNOW SNOWC SNOWH SST SWDOWN T2 TH2 TMN TSK U10 UDROFF V10 VEGFRA XICE XLAND 3D variables: P PB PH PHB QCLOUD QRAIN QVAPOR SH2O SMOIS T TSLB U V W Compression Info for variable CANWAT: Refinement Levels: 4 Compression Ratios: 62 21 4 1 Grid test for 2D variable CANWAT: # Dimensions: 2 Dimension Lengths: 315 309 Topology Dimension: 2 RMS error: 0 Missing value count: 0 GetValueAtIndex() vs GetValue() disagreement count: 0 Time: 0 Compression Info for variable P: Refinement Levels: 4 Compression Ratios: 500 100 10 1 Grid test for 3D variable P: # Dimensions: 3 Dimension Lengths: 315 309 34 Topology Dimension: 3 RMS error: 0 Missing value count: 0 GetValueAtIndex() vs GetValue() disagreement count: 0 Time: 0 Projection String: +proj=merc +lon_0=-85 +lat_ts=30 +ellps=WGS84 Coordinate Variables: Time XLAT XLAT_U XLAT_V XLONG XLONG_U XLONG_V bottom_top bottom_top_stag soil_layers_stag Elevation ElevationU ElevationV ElevationW XLATY XLAT_UY XLAT_VY XLONGX XLONG_UX XLONG_VX Time Coordinates: 147016800 Time coordinate variable name: Time Number of time steps: 1 Elapsed time: 0.017814 ================================================ FILE: test_apps/smokeTests/testResults/wrf_baseline.txt ================================================ wrfout_d02_2005-08-29_05 Dimensions: DateStrLen = 19 Time Varying: 0 Time = 1 Time Varying: 0 bottom_top = 34 Time Varying: 0 bottom_top_stag = 35 Time Varying: 0 ext_scalar = 1 Time Varying: 0 soil_layers_stag = 5 Time Varying: 0 south_north = 309 Time Varying: 0 south_north_stag = 310 Time Varying: 0 west_east = 315 Time Varying: 0 west_east_stag = 316 Time Varying: 0 Meshes: west_east_stagxsouth_north west_east_stagxsouth_northxbottom_top west_eastxsouth_north west_eastxsouth_north_stag west_eastxsouth_north_stagxbottom_top west_eastxsouth_northxbottom_top west_eastxsouth_northxbottom_top_stag west_eastxsouth_northxsoil_layers_stag 2D variables: CANWAT COSALPHA E F GLW GRDFLX HFX HGT ISLTYP IVGTYP LANDMASK LH LU_INDEX MAPFAC_M MAPFAC_U MAPFAC_V MU MUB NEST_POS PBLH PSFC Q2 QFX RAINC RAINNC RMOL SFROFF SINALPHA SNOW SNOWC SNOWH SST SWDOWN T2 TH2 TMN TSK U10 UDROFF V10 VEGFRA XICE XLAND 3D variables: P PB PH PHB QCLOUD QRAIN QVAPOR SH2O SMOIS T TSLB U V W Compression Info for variable CANWAT: Refinement Levels: 1 Compression Ratios: 1 Grid test for 2D variable CANWAT: # Dimensions: 2 Dimension Lengths: 315 309 Topology Dimension: 2 RMS error: 0 Missing value count: 0 GetValueAtIndex() vs GetValue() disagreement count: 0 Time: 0 Compression Info for variable P: Refinement Levels: 1 Compression Ratios: 1 Grid test for 3D variable P: # Dimensions: 3 Dimension Lengths: 315 309 34 Topology Dimension: 3 RMS error: 0 Missing value count: 0 GetValueAtIndex() vs GetValue() disagreement count: 0 Time: 0 Projection String: +proj=merc +lon_0=-85 +lat_ts=30 +ellps=WGS84 Coordinate Variables: Time XLAT XLAT_U XLAT_V XLONG XLONG_U XLONG_V bottom_top bottom_top_stag soil_layers_stag Elevation ElevationU ElevationV ElevationW XLATY XLAT_UY XLAT_VY XLONGX XLONG_UX XLONG_VX Time Coordinates: 146984400 Time coordinate variable name: Time Number of time steps: 1 Elapsed time: 3.46721 ================================================ FILE: test_apps/udunits/CMakeLists.txt ================================================ add_executable (test_udunits test_udunits.cpp) set_target_properties(test_udunits PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${debug_output_dir}") target_link_libraries (test_udunits common vdc wasp) ================================================ FILE: test_apps/udunits/test_udunits.cpp ================================================ #include #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include #include using namespace Wasp; using namespace VAPoR; struct { int year; int month; int day; int hour; int minute; int second; OptionParser::Boolean_T help; } opt; OptionParser::OptDescRec_T set_opts[] = {{"year", 1, "2020", "year"}, {"month", 1, "1", "month"}, {"day", 1, "1", "day"}, {"hour", 1, "1", "hour"}, {"minute", 1, "1", "minute"}, {"second", 1, "1", "second"}, {"help", 0, "", "Print this message and exit"}, {NULL}}; OptionParser::Option_T get_options[] = {{"year", Wasp::CvtToInt, &opt.year, sizeof(opt.year)}, {"month", Wasp::CvtToInt, &opt.month, sizeof(opt.month)}, {"day", Wasp::CvtToInt, &opt.day, sizeof(opt.day)}, {"hour", Wasp::CvtToInt, &opt.hour, sizeof(opt.hour)}, {"minute", Wasp::CvtToInt, &opt.minute, sizeof(opt.minute)}, {"second", Wasp::CvtToInt, &opt.second, sizeof(opt.second)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}}; const char *ProgName; int main(int argc, char **argv) { OptionParser op; string s; ProgName = FileUtils::LegacyBasename(argv[0]); MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << " [options] " << endl; op.PrintOptionHelp(stderr); exit(0); } UDUnits udunits; int rc = udunits.Initialize(); if (rc < 0) return (1); double seconds_since_epoch = 0.0; seconds_since_epoch = udunits.EncodeTime(opt.year, opt.month, opt.day, opt.hour, opt.minute, opt.second); int year, month, day, hour, minute, second; udunits.DecodeTime(seconds_since_epoch, &year, &month, &day, &hour, &minute, &second); if (year != opt.year || month != opt.month || day != opt.day || hour != opt.hour || minute != opt.minute || second != opt.second) { cerr << "Time/dates disagree" << endl; cerr << "Input " << opt.year << "-"; cerr << opt.month << "-"; cerr << opt.day << "_"; cerr << opt.hour << ":"; cerr << opt.minute << ":"; cerr << opt.second << endl; cerr << "Output " << year << "-"; cerr << month << "-"; cerr << day << "_"; cerr << hour << ":"; cerr << minute << ":"; cerr << second << endl; return (1); } return (0); } ================================================ FILE: test_apps/vdc3test/test.csh ================================================ #!/bin/csh -f set data = /glade/p/DASG/VAPOR/Data/Raw/checker128 set dataconst = /glade/p/DASG/VAPOR/Data/Raw/constant set data64 = /glade/p/DASG/VAPOR/Data/Raw/checker64 #./vdc3test.csh -dim 512x512x255 -- -- -lod -1 -level -1 $dataconst # # DIM # ./vdc3test.csh -dim 64x64x64 -- -- $data64 if ($status) exit 1 ./vdc3test.csh -dim 128x128x128 -- -- $data if ($status) exit 1 ./vdc3test.csh -dim 120x128x128 -- -- $data if ($status) exit 1 ./vdc3test.csh -dim 128x120x128 -- -- $data if ($status) exit 1 ./vdc3test.csh -dim 128x128x120 -- -- $data if ($status) exit 1 ./vdc3test.csh -dim 120x63x120 -- -- $data if ($status) exit 1 ./vdc3test.csh -dim 127x94x33 -- -- $data if ($status) exit 1 # # LOD # ./vdc3test.csh -dim 128x128x128 -- -lod 0 -- -lod 0 $data if ($status) exit 1 ./vdc3test.csh -dim 128x128x128 -- -lod 1 -- -lod 1 $data if ($status) exit 1 ./vdc3test.csh -dim 128x128x128 -- -- -lod 0 $data if ($status) exit 1 ./vdc3test.csh -dim 128x128x128 -- -- -lod 1 $data if ($status) exit 1 # # LEVEL # ./vdc3test.csh -dim 128x128x128 -- -- -level 0 $data if ($status) exit 1 ./vdc3test.csh -dim 128x128x128 -- -- -level 1 $data if ($status) exit 1 # # LEVEL+LOD # ./vdc3test.csh -dim 128x128x128 -- -- -lod 2 -level 0 $data if ($status) exit 1 ./vdc3test.csh -dim 128x128x128 -- -- -lod 2 -level 1 $data if ($status) exit 1 # # BS # ./vdc3test.csh -cratio 1:10:100:300 -dim 128x128x128 -bs 65x65x65 -- -- $data if ($status) exit 1 # # appears to be broken in raw2vdf # #./vdc3test.csh -cratio 1:10:100:300 -dim 121x119x134 -bs 65x66x67 -- -- $data #if ($status) exit 1 # # CRATIO # ./vdc3test.csh -dim 128x128x63 -cratio 1 -- -- -lod -1 -level -1 $data if ($status) exit 1 ./vdc3test.csh -dim 128x128x63 -cratio 1 -- -- -lod -1 -level -1 $data if ($status) exit 1 ./vdc3test.csh -dim 128x128x128 -cratio 10:50 -- -- -lod 1 $data if ($status) exit 1 # broken in 2.x #./vdc3test.csh -dim 128x128x128 -cratio 10:50 -- -- $data #if ($status) exit 1 # # region # ./vdc3test.csh -dim 128x128x128 -- -- -xregion 5:123 $data if ($status) exit 1 ./vdc3test.csh -dim 128x128x128 -- -- -yregion 5:123 $data if ($status) exit 1 ./vdc3test.csh -dim 128x128x128 -- -- -zregion 5:123 $data if ($status) exit 1 ./vdc3test.csh -dim 128x128x128 -- -- -xregion 90:100 -yregion 5:123 -zregion 10:63 $data if ($status) exit 1 # # TS, NUMTS # ./vdc3test.csh -dim 128x128x128 -numts 10 -- -ts 9 -- -ts 9 $data if ($status) exit 1 ## ## 2D DATA ## # # VAR2DXY # ./vdc3test.csh -dim 128x128x128 -vars2dxy var2dxy -- -var var2dxy -- -var var2dxy $data if ($status) exit 1 ./vdc3test.csh -dim 128x128x128 -vars2dxy var2dxy -- -var var2dxy -- -var var2dxy -xregion 5:123 -yregion 5:50 $data if ($status) exit 1 ================================================ FILE: test_apps/vdc3test/vdc3test.csh ================================================ #!/bin/csh -f set TmpDir = "/tmp" if ($#argv < 1) then echo "Usage $0 [xcreate options] -- [raw2x options] -- [x2raw options] rawfile" exit 1 endif set ProgName = `basename $0` set state = 0 set xcreate_options = "" set raw2x_options = "" set x2raw_options = "" while ($#argv > 1) if ("$argv[1]" == "--") then @ state += 1 else switch ("$state") case "0": set xcreate_options = ($xcreate_options $argv[1]) breaksw case "1": set raw2x_options = ($raw2x_options $argv[1]) breaksw case "2": set x2raw_options = ($x2raw_options $argv[1]) breaksw default: echo "BOGUS" exit 1 breaksw endsw endif shift end set rawfile = $argv[1] #echo xcreate_options = $xcreate_options #echo raw2x_options = $raw2x_options #echo x2raw_options = $x2raw_options #echo rawfile = $rawfile #exit 0 set vdffile = $TmpDir/${ProgName:r}_vdf.vdf /bin/rm -fr $vdffile /bin/rm -fr ${vdffile:r}_data set cmd = "vdfcreate -vdc2 $xcreate_options $vdffile" echo $cmd $cmd if ($status != 0) then echo "FAILED : $cmd" exit 1 endif set cmd = "raw2vdf $raw2x_options $vdffile $rawfile" echo $cmd $cmd if ($status != 0) then echo "FAILED : $cmd" exit 1 endif set vdfrfile = $TmpDir/${ProgName:r}_vdfr.raw set cmd = "vdf2raw $x2raw_options $vdffile $vdfrfile" echo $cmd $cmd if ($status != 0) then echo "FAILED : $cmd" exit 1 endif set master = $TmpDir/${ProgName:r}_nc.nc /bin/rm -fr $master /bin/rm -fr ${master:r}_data set cmd = "vdccreate $xcreate_options $master" echo $cmd $cmd if ($status != 0) then echo "FAILED : $cmd" exit 1 endif set cmd = "raw2vdc $raw2x_options $master $rawfile" echo $cmd $cmd if ($status != 0) then echo "FAILED : $cmd" exit 1 endif set vdcrfile = $TmpDir/${ProgName:r}_vdcr.raw set cmd = "vdc2raw $x2raw_options $master $vdcrfile" echo $cmd $cmd if ($status != 0) then echo "FAILED : $cmd" exit 1 endif set cmd = "diff $vdfrfile $vdcrfile" echo $cmd $cmd if ($status != 0) then echo "FAILED : $cmd" exit 1 endif echo "SUCCESS" /bin/rm $vdfrfile $vdcrfile exit 0 ================================================ FILE: test_apps/xmlnode/test_xmlnode.cpp ================================================ #include #include #include #include #include #include #include "vapor/VAssert.h" #include #include #include using namespace Wasp; using namespace VAPoR; struct { string ifile; OptionParser::Boolean_T help; OptionParser::Boolean_T quiet; OptionParser::Boolean_T debug; } opt; OptionParser::OptDescRec_T set_opts[] = { {"ifile", 1, "", "Construct Xml tree from a file"}, {"help", 0, "", "Print this message and exit"}, {"quiet", 0, "", "Operate quitely"}, {"debug", 0, "", "Debug mode"}, {NULL}}; OptionParser::Option_T get_options[] = {{"ifile", Wasp::CvtToCPPStr, &opt.ifile, sizeof(opt.ifile)}, {"help", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {"quiet", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {"debug", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {NULL}}; const char *ProgName; int main(int argc, char **argv) { OptionParser op; double timer = 0.0; string s; ProgName = Basename(argv[0]); MyBase::SetErrMsgFilePtr(stderr); if (op.AppendOptions(set_opts) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (op.ParseOptions(&argc, argv, get_options) < 0) { cerr << ProgName << " : " << op.GetErrMsg(); exit(1); } if (opt.help) { cerr << "Usage: " << ProgName << endl; op.PrintOptionHelp(stderr); exit(0); } if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); } if (argc != 1) { cerr << "Usage: " << ProgName << " [options] " << endl; op.PrintOptionHelp(stderr); exit(1); } XmlNode *parent = new XmlNode("parent"); parent->SetElementLong("long_data1", 1); parent->SetElementLong("long_data2", 2); parent->SetElementString("string_data", "my string"); parent->SetElementDouble("double_data1", 3.0); XmlNode *child1 = parent->NewChild("child1"); child1->SetElementLong("long_data1", 4); child1->SetElementLong("long_data2", 5); child1->SetElementString("string_data", "my string"); child1->SetElementDouble("double_data1", 6.0); VAssert(child1->GetParent() == parent); XmlNode *child2 = parent->NewChild("child2"); child2->SetElementLong("long_data1", 7); child2->SetElementLong("long_data2", 8); child2->SetElementString("string_data", "my string"); child2->SetElementDouble("double_data1", 9.0); VAssert(child2->GetParent() == parent); XmlNode *child3 = child2->NewChild("child3"); VAssert(child3 != NULL); VAssert(child3->GetParent() == child2); child3->SetElementLong("long_data1", 10); child3->SetElementLong("long_data2", 11); child3->SetElementString("string_data", "my string"); child3->SetElementDouble("double_data1", 12.0); XmlNode *parent2 = new XmlNode(*parent); if (*parent2 == *parent) { cout << "parent == parent 2" << endl; } else { cout << "parent != parent 2" << endl; } child3->SetElementDouble("double_data1", 99.0); if (*parent2 == *parent) { cout << "parent == parent 2" << endl; } else { cout << "parent != parent 2" << endl; } cout << "Allocated note count before delete : " << XmlNode::GetAllocatedNodes().size() << endl; delete parent; delete parent2; cout << "Allocated note count after delete : " << XmlNode::GetAllocatedNodes().size() << endl; // cout << "parent 1 " << endl << parent; // cout << "parent 2 " << endl << *parent2; if (!opt.ifile.empty()) { XmlNode parent3; XmlParser parser; int rc = parser.LoadFromFile(&parent3, opt.ifile); if (rc < 0) return 1; cout << "parent 3 " << endl << parent3; } }