From 9897a9fd5a73ec19cf6431b128222d2342cd7012 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Thu, 14 Dec 2023 10:10:40 +0100 Subject: [PATCH 01/30] Update GUI hash (issue #2977) --- data/assets/util/webgui.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index c7243a5f5e..19d82a7ee5 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -4,7 +4,7 @@ local guiCustomization = asset.require("customization/gui") -- Select which commit hashes to use for the frontend and backend -local frontendHash = "17af9032d000a9865a00afe88eff88a822167eea" +local frontendHash = "a2139b8cf589daf846fb3ef3f4953bc591e66dcb" local frontend = asset.resource({ Identifier = "WebGuiFrontend", From c165098cdcfc6afe97f6c71af76042ebd18c1af7 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Tue, 19 Dec 2023 13:20:07 +0100 Subject: [PATCH 02/30] Point cloud rewrite (RIP RenderableBillboardsCloud) (#2932) * Start refactoring billboardscloud renderable * Remove extra unit computation in geometry shader * More refactor and fix size parameter not working without colormap (it never did) * Remove redundant bool in shader * Divide settings into property owners * Refactor colormap * More refactoring (utilize properties for visiblity) * Remove redundant extra data structures for options * Move data logic to the colormap settings structure * Remove confusing correction size properties * Separate polygon cloud into its own renderable * Clean up some unused code * Update some property descriptions * Split some more code out into functions * Remove odd and unused "linear filtering" Should be reimplemented ina better way in a general color map overhaul * Start refactoring some more properties * Make color optional and remove redundant color assignments in assets * Refactor color-parameter input and make range mapping work correctly * Code cleanup (unused code and fix data types) * Rename ScaleFactor to ScaleExponent * Add a scale factor as well, as they're easier to use, and clarify documentation * Fix faultily renamed scale factors * Remove confusing multiplication for scale exponent * Fix problem with points not appearing when _drawElements was set to true * Move all colormapsettings into its own table in the asset files * Move scaling/sizing into its own table as well * Group sizing properties and remove min pixel size limit (was always zero) * Add some docs and rename a parameter to avoid repetition * Remove IsExact colormap and add an option to hide outliers OBS! Still need to update the actual cmap files * Add property to disable size mapping * Increase pixel size of polyon texture - reduces jagged edges * Remove unused points class * Rename files and billboard class, to make it clearer that it is a point cloud * Move size mapping into size settings * Move color map properties out into its own component * Move color map related computations into the new component * Add outlier colors, to cover some specific color mapping issues * Automatically fill parameter options if no colormap parameters were defined * Move all color-related parameters to under one property owner * Inlcude changes from matrix maintenance * Add a checkbox to disable additive blending * Remove a unused variable in shader * DO color maping on the graphics card instead of CPU, using a texture * WIP remove old "Outliers" and start introducing concept of no data colors instead * Move speck loader to core and divide into a general data loader and a speck specific loader (In preparation for adding CSV support) * More labelscomponent to core * Fix a faulty header * Handle NaN values * Rename color map component property owner It's not just the color map, but the settings for the entire mapping * Hide point with nan value is show missing data is not selected * Fix labels component documentation after move * Add option to not provide any texture, and use a sphere generated form the shader * Don't crash when loading unsupported data formats :) * Add some TODO comments that should be addressed before merge * Move renderables from DU module to base, and do some header cleanup * Move colormapping component to core ad rename it to make it clear that it is not the color map itself * Add above, below and nan color values to cmap loading * Remove missing Data value specs in asset (and use belowRange in cmap instead) * Make warning about wrong color number more verbose * Add TODO comment about colormap, and actually used color in prev version, to localdwarfs * WIP: Load CSV files * Update some property visbility * Check if chosen parameter options actually exist * Fix fault column check * Update example asset to cover more different cases * Use new asset.resource loading * Update asset versions (major update) * Add parent documentation for RenderablePolygonCloud * Add point cloud example with size scaling and add TODO comment * Add example with textured points * Don't blend textured points * Fix problem with shaders being confused about texture units * Bring back deepsky points color * Start implementing more sophisticated datamapping for point data files * Allow reading datamapping from input dictionary * Load dataset in constructor instead Solves problem with color map columns not loading for big datasets when loaded the first time * Fix crash from reading column value that is interpreted as inf * Inlcude information about data mapping when caching dataset Updating the parameters now leads to an updated caching of the data file * Adapt to tolower update * Add option to specify columns to exclude in load (for CSV files) * Start updating some docs * Add a readonly property that shows the number of data points * Rename example asset to shorter name * Add option for not using cache when loading dataset * Fix some errors in example asset * Set scaleExponent from max position if not specified That way the points are always visible, even when no exponent is given * Restructure and add explanations in example asset * Add option to not cache labels component data file * Add example file with labels and units * Compute fade distances in model coordinates instead of world space (issue #1746) * Add possiblity to invert fading and add exmaple asset * Make a separate propertyowner for fading settings * Update docs * Add example asset with custom data mapping * Address some of my own review comments * Read provided Parameter from asset * Read ValueRange from asset * Add example asset for more advanced color mapping settings * Allow using the same column for two position coordinate axes * Update src/rendering/colormappingcomponent.cpp Co-authored-by: Alexander Bock * Update src/data/datamapping.cpp * Use helper function for tolowercase * Simplify some std::optional handling, and fix broken assignment from code review fix * Update data file versions to get updated cmap files * Include a progress bar to show progress of CSV data loading * Update csv data-to-float parsing for clang * Add a description about why `openspace.absPath` is used in the file instead of `asset.resource` * Apply suggestions from code review * Apply suggestions from code review * Add some missing info in documentation * Place size-related property descriptions next to each other * Remove the explicitly set renderbin * Fix overly complicated description * Fix polygon texture not being used * Add polygon cloud example * only bind texture and activate texture unit when required * Rename alpha to opacity in shader * Fix value range not loading, and make first parameter in list the default * Rename Pixel Size property * Use base 10 for scale exponent instead of base e * Update src/data/datamapping.cpp * Update modules/base/shaders/billboardpoint_gs.glsl * Remove some redundant asset settings (Home label) * Review comments * Add TODO comment for localdwarfs asset (Speck file reading problems) * Oops, forgot part of the comment * Apply suggestions from code review Co-authored-by: Alexander Bock * More code review fixes * Fix faulty isReady check when labels are included * Apply suggestions from code review Co-authored-by: Alexander Bock * Apply suggestions from code review Co-authored-by: Alexander Bock * More code review updates --------- Co-authored-by: Alexander Bock --- .../examples/pointclouds/data/dummydata.csv | 101 ++ .../examples/pointclouds/data/dummydata.label | 100 ++ data/assets/examples/pointclouds/points.asset | 237 ++++ .../points_colormappingsettings.asset | 78 ++ .../pointclouds/points_datamapping.asset | 68 + .../examples/pointclouds/points_fading.asset | 88 ++ .../pointclouds/points_units_labels.asset | 55 + .../examples/pointclouds/polygon_cloud.asset | 45 + data/assets/examples/pointclouds/viridis.cmap | 258 ++++ data/assets/scene/digitaluniverse/2dF.asset | 27 +- data/assets/scene/digitaluniverse/2mass.asset | 30 +- data/assets/scene/digitaluniverse/6dF.asset | 28 +- data/assets/scene/digitaluniverse/abell.asset | 20 +- .../digitaluniverse/alternatestarlabels.asset | 5 +- .../scene/digitaluniverse/clusters.asset | 5 +- .../scene/digitaluniverse/deepsky.asset | 23 +- .../assets/scene/digitaluniverse/dwarfs.asset | 29 +- .../scene/digitaluniverse/exoplanets.asset | 15 +- .../exoplanets_candidates.asset | 18 +- .../digitaluniverse/globularclusters.asset | 17 +- data/assets/scene/digitaluniverse/grids.asset | 11 +- .../assets/scene/digitaluniverse/groups.asset | 6 +- .../scene/digitaluniverse/h2regions.asset | 17 +- data/assets/scene/digitaluniverse/hdf.asset | 25 +- .../scene/digitaluniverse/localdwarfs.asset | 30 +- .../digitaluniverse/milkyway_label.asset | 14 +- .../digitaluniverse/obassociations.asset | 28 +- .../scene/digitaluniverse/openclusters.asset | 17 +- .../digitaluniverse/planetarynebulae.asset | 17 +- .../scene/digitaluniverse/pulsars.asset | 17 +- .../scene/digitaluniverse/quasars.asset | 33 +- data/assets/scene/digitaluniverse/sdss.asset | 36 +- .../scene/digitaluniverse/starlabels.asset | 5 +- .../scene/digitaluniverse/superclusters.asset | 13 +- .../digitaluniverse/supernovaremnants.asset | 19 +- data/assets/scene/digitaluniverse/tully.asset | 35 +- data/assets/scene/digitaluniverse/voids.asset | 5 +- .../openspace/data/csvloader.h | 28 +- .../openspace/data/dataloader.h | 48 +- include/openspace/data/datamapping.h | 74 ++ .../openspace/data/speckloader.h | 31 +- .../rendering/colormappingcomponent.h | 117 ++ .../openspace/rendering}/labelscomponent.h | 16 +- modules/base/CMakeLists.txt | 10 + modules/base/basemodule.cpp | 6 + .../rendering/grids/renderableboxgrid.cpp | 2 +- .../base/rendering/grids/renderableboxgrid.h | 2 +- .../base/rendering/grids/renderablegrid.cpp | 2 +- modules/base/rendering/grids/renderablegrid.h | 2 +- .../rendering/grids/renderableradialgrid.cpp | 2 +- .../rendering/grids/renderableradialgrid.h | 2 +- .../grids/renderablesphericalgrid.cpp | 2 +- .../rendering/grids/renderablesphericalgrid.h | 2 +- .../pointcloud/renderablepointcloud.cpp | 1042 +++++++++++++++ .../pointcloud/renderablepointcloud.h} | 133 +- .../pointcloud/renderablepolygoncloud.cpp | 193 +++ .../pointcloud/renderablepolygoncloud.h | 70 + .../shaders/billboardpoint_fs.glsl} | 71 +- .../shaders/billboardpoint_gs.glsl} | 72 +- .../shaders/billboardpoint_vs.glsl} | 13 +- .../shaders/polygon_fs.glsl} | 0 .../shaders/polygon_gs.glsl} | 0 .../shaders/polygon_vs.glsl} | 0 modules/digitaluniverse/CMakeLists.txt | 12 - .../digitaluniverse/digitaluniversemodule.cpp | 6 - .../rendering/renderablebillboardscloud.cpp | 1142 ----------------- .../rendering/renderabledumeshes.cpp | 4 +- .../rendering/renderabledumeshes.h | 4 +- .../rendering/renderableplanescloud.cpp | 8 +- .../rendering/renderableplanescloud.h | 5 +- .../rendering/renderablepoints.cpp | 437 ------- .../rendering/renderablepoints.h | 106 -- modules/space/CMakeLists.txt | 4 - .../renderableconstellationlines.cpp | 4 +- .../renderableconstellationsbase.cpp | 4 +- .../rendering/renderableconstellationsbase.h | 2 +- modules/space/rendering/renderablestars.cpp | 6 +- modules/space/rendering/renderablestars.h | 4 +- modules/space/spacemodule.cpp | 2 - src/CMakeLists.txt | 12 + src/data/csvloader.cpp | 194 +++ src/data/dataloader.cpp | 687 ++++++++++ src/data/datamapping.cpp | 174 +++ {modules/space => src/data}/speckloader.cpp | 523 +------- src/documentation/core_registration.cpp | 7 + src/rendering/colormappingcomponent.cpp | 470 +++++++ .../rendering}/labelscomponent.cpp | 24 +- 87 files changed, 4719 insertions(+), 2637 deletions(-) create mode 100644 data/assets/examples/pointclouds/data/dummydata.csv create mode 100644 data/assets/examples/pointclouds/data/dummydata.label create mode 100644 data/assets/examples/pointclouds/points.asset create mode 100644 data/assets/examples/pointclouds/points_colormappingsettings.asset create mode 100644 data/assets/examples/pointclouds/points_datamapping.asset create mode 100644 data/assets/examples/pointclouds/points_fading.asset create mode 100644 data/assets/examples/pointclouds/points_units_labels.asset create mode 100644 data/assets/examples/pointclouds/polygon_cloud.asset create mode 100644 data/assets/examples/pointclouds/viridis.cmap rename modules/digitaluniverse/shaders/points_sprite_fs.glsl => include/openspace/data/csvloader.h (83%) rename modules/space/speckloader.h => include/openspace/data/dataloader.h (73%) create mode 100644 include/openspace/data/datamapping.h rename modules/digitaluniverse/shaders/points_vs.glsl => include/openspace/data/speckloader.h (77%) create mode 100644 include/openspace/rendering/colormappingcomponent.h rename {modules/space => include/openspace/rendering}/labelscomponent.h (91%) create mode 100644 modules/base/rendering/pointcloud/renderablepointcloud.cpp rename modules/{digitaluniverse/rendering/renderablebillboardscloud.h => base/rendering/pointcloud/renderablepointcloud.h} (58%) create mode 100644 modules/base/rendering/pointcloud/renderablepolygoncloud.cpp create mode 100644 modules/base/rendering/pointcloud/renderablepolygoncloud.h rename modules/{digitaluniverse/shaders/billboard_fs.glsl => base/shaders/billboardpoint_fs.glsl} (64%) rename modules/{digitaluniverse/shaders/billboard_gs.glsl => base/shaders/billboardpoint_gs.glsl} (73%) rename modules/{digitaluniverse/shaders/billboard_vs.glsl => base/shaders/billboardpoint_vs.glsl} (91%) rename modules/{digitaluniverse/shaders/billboardpolygon_fs.glsl => base/shaders/polygon_fs.glsl} (100%) rename modules/{digitaluniverse/shaders/billboardpolygon_gs.glsl => base/shaders/polygon_gs.glsl} (100%) rename modules/{digitaluniverse/shaders/billboardpolygon_vs.glsl => base/shaders/polygon_vs.glsl} (100%) delete mode 100644 modules/digitaluniverse/rendering/renderablebillboardscloud.cpp delete mode 100644 modules/digitaluniverse/rendering/renderablepoints.cpp delete mode 100644 modules/digitaluniverse/rendering/renderablepoints.h create mode 100644 src/data/csvloader.cpp create mode 100644 src/data/dataloader.cpp create mode 100644 src/data/datamapping.cpp rename {modules/space => src/data}/speckloader.cpp (51%) create mode 100644 src/rendering/colormappingcomponent.cpp rename {modules/space => src/rendering}/labelscomponent.cpp (92%) diff --git a/data/assets/examples/pointclouds/data/dummydata.csv b/data/assets/examples/pointclouds/data/dummydata.csv new file mode 100644 index 0000000000..e8b698833f --- /dev/null +++ b/data/assets/examples/pointclouds/data/dummydata.csv @@ -0,0 +1,101 @@ +x,y,z,a,b,normaldist_withMissing,number_withNan +13428000,26239000,45870000,-3.226548224,33.95773276,-0.357778948,29 +14727000,45282000,10832000,45.05941924,-106.0395917,,29 +24999000,28370000,19911000,-70.58906931,154.1851656,-0.167961782,Nan +26539000,36165000,39582000,-13.3663358,71.79484733,0.113536778,9 +49056000,24775000,14626000,21.42870979,-115.6088304,0.125551095,37 +43965000,21472000,18760000,65.07055022,-56.36880466,0.172981386,18 +15661000,28429000,16965000,76.15826514,125.3163407,,40 +25046000,36006000,49453000,-22.31710915,137.4486786,0.447921314,28 +13797000,34811000,18825000,-79.40300933,74.05580595,-0.02379786,12 +13879000,14824000,41472000,-30.93548431,-8.755047834,-0.041777813,50 +11481000,20480000,25925000,75.51244012,178.1377926,-0.044396255,0 +45032000,16606000,23537000,37.38766828,175.5064508,-0.449674816,13 +14395000,34940000,21968000,-31.6863061,-116.6587323,-0.09741961,30 +15945000,21478000,29536000,-53.01226701,59.18196347,0.304142338,30 +13458000,19017000,18542000,8.72692265,80.65872957,,45 +45302000,15732000,34369000,-85.57061714,124.6890481,-0.364449145,20 +15559000,36269000,18160000,-4.975784243,-156.8789425,-0.012893853,22 +16552000,14570000,39763000,-39.2579671,75.22960824,-0.281792015,Nan +11353000,13410000,38311000,8.610608538,-36.43103437,-0.196021206,9 +12383000,49302000,33539000,69.26506588,-109.0830926,-0.147483079,34 +44302000,21387000,23434000,16.14574541,78.81171702,0.115624185,5 +43107000,14206000,24728000,37.57233254,142.6103028,,Nan +49320000,43878000,24240000,-39.10527498,149.2751575,-0.086246397,29 +37519000,40514000,16409000,-24.14434437,157.2871976,-0.071946303,12 +37202000,40122000,42551000,-79.88824934,-124.089513,0.375414362,31 +12783000,11757000,25348000,-11.83866388,118.2423568,-0.243289139,Nan +39621000,30560000,15929000,75.8365484,-95.18288548,-0.399996182,37 +10937000,15183000,21413000,-32.40573,-157.8337361,-0.202310776,39 +39411000,12532000,44006000,34.67409469,-83.29512212,,Nan +47905000,25552000,28902000,36.19437814,52.25734185,,32 +28426000,45268000,27886000,-70.843469,-63.7321218,0.112287307,45 +15026000,45897000,23911000,-89.01161062,10.16376248,-0.00400866,Nan +24625000,14844000,12837000,88.91663258,169.8003753,-0.151728888,5 +46304000,21144000,24421000,-41.58069299,59.63971512,-0.371030712,48 +29558000,10724000,27312000,9.663492403,-71.18121738,0.344402457,Nan +49636000,27202000,24626000,59.46440387,-92.91431055,0.26256468,31 +38603000,23794000,41040000,70.45128929,-67.84861911,-0.184920666,48 +37336000,21742000,40982000,-15.69131418,134.6754731,0.078786176,15 +35128000,38725000,25244000,2.279345664,34.91612867,0.091098807,44 +30419000,33591000,39512000,-56.16030331,133.9105282,-0.590693487,8 +18665000,11189000,45438000,-45.68302316,-85.35524485,0.046936859,26 +15442000,36392000,16074000,81.4389588,-56.70945587,0.038804669,5 +43378000,27900000,38748000,-74.35249265,-133.1884413,0.429053963,17 +44424000,19982000,13528000,-81.19709235,49.49364675,0.115926289,47 +42733000,15383000,28933000,75.17020088,-11.11330632,0.127627239,32 +40144000,46822000,29588000,-81.25577073,-135.8002245,0.346061193,33 +16927000,38232000,43931000,-80.97022269,157.7565432,-0.096039391,39 +38910000,36030000,38003000,-37.79005665,-1.5474944,0.107402594,11 +48340000,38510000,39290000,21.94846638,-112.6129615,0.230803493,3 +17258000,45665000,27152000,80.73726495,-31.33714033,-0.079079307,10 +48363000,39701000,11905000,11.83766221,-69.99777106,-0.002514692,3 +27660000,29370000,26029000,8.179457229,147.7719143,-0.006520509,31 +47106000,30527000,17038000,73.00898959,9.988869939,0.797492967,5 +10471000,37521000,35398000,57.46145065,-29.5045034,-0.261313809,39 +27774000,44082000,40036000,78.47974779,-4.998179635,0.437739286,24 +46887000,20413000,36649000,51.11098102,-136.3276432,0.237434245,41 +10093000,46706000,19187000,-58.41750426,-157.9933447,0.275586609,45 +49093000,36514000,38499000,-55.41355694,150.177605,0.576467955,21 +48945000,49826000,23225000,-63.91174083,-177.7191007,0.475443991,Nan +26852000,28926000,32243000,-77.854481,116.9006581,,1 +34219000,34787000,30801000,-62.32990484,23.24232366,0.089523916,40 +31075000,30369000,36898000,-77.78314619,38.69526825,-0.046423443,7 +28135000,21412000,25552000,-7.411565773,-88.65122734,0.258690016,Nan +13347000,15980000,43094000,74.71054756,-37.32614369,,7 +26928000,31159000,16653000,-32.74503199,146.7695347,0.576290488,34 +12364000,14374000,43646000,28.70641859,-92.35199713,-0.059531367,16 +38991000,49388000,48534000,56.70658222,8.014973542,-0.173400177,30 +17180000,14935000,11680000,-45.39957586,102.5726701,0.16285705,1 +27666000,29337000,44778000,89.4063742,-79.68068618,0.044140443,41 +13660000,11108000,37986000,57.03349279,7.98684928,0.066242706,24 +36910000,10252000,41657000,-9.906961203,21.79114496,-0.378241692,6 +21785000,20095000,14903000,77.49612237,-84.68789002,-0.071118836,16 +33363000,42124000,39814000,-64.47776113,-30.79591997,0.371115832,35 +42758000,48892000,44762000,42.39782697,-32.55868099,-0.146011285,1 +16590000,22098000,28515000,-36.90992927,-55.27481385,-0.203981239,27 +26448000,45475000,33361000,64.22197115,146.6687002,-0.026210913,1 +41182000,23927000,25075000,-81.55929754,137.9213773,0.042229126,10 +49801000,15636000,39883000,-89.22857667,159.9681504,0.035529624,15 +32725000,13037000,49874000,-55.17873101,61.01413612,0.519438664,43 +31130000,16471000,41939000,-45.36963748,-156.5100924,0.245045969,22 +19599000,37119000,26468000,-26.58523044,174.7731562,-0.210527713,22 +30024000,23097000,14711000,44.31464407,150.7894846,-0.041347399,45 +39567000,48586000,49391000,1.721781555,156.1687027,,31 +46249000,28249000,32393000,-13.3221674,-176.0644697,-0.108879159,30 +12180000,20488000,46288000,36.02858732,30.43526779,-0.099205446,47 +29659000,40098000,45152000,72.15373455,62.01511311,,46 +41026000,19309000,15845000,-38.63636224,145.9569745,-0.083266866,32 +47146000,39852000,26666000,35.2426196,-33.97130609,-0.650089141,7 +39958000,46945000,11789000,-68.31344333,172.4154216,0.001713968,37 +25921000,13147000,22257000,-15.89505915,-150.39693,0.165178387,37 +28892000,28329000,49094000,-58.72206735,-157.3776844,-0.228068143,48 +29563000,48312000,45703000,86.78718085,179.1386066,-0.146072441,49 +46127000,46582000,13462000,39.98033674,-164.152123,-0.081830298,17 +23268000,24051000,48652000,-43.61767649,83.51428751,-0.106824408,45 +22163000,26901000,28702000,51.04347167,169.7632117,0.052782471,31 +46968000,17027000,25787000,-73.8664022,2.915300454,-0.028069047,22 +24148000,44640000,15422000,8.379412685,101.9542853,-0.049339904,14 +11566000,26486000,11735000,-36.78748293,-129.8960512,,Nan +11063000,38883000,16772000,-65.43894139,105.6607872,,7 +43081000,16718000,45813000,-2.464830259,87.07999887,-0.24057898,40 diff --git a/data/assets/examples/pointclouds/data/dummydata.label b/data/assets/examples/pointclouds/data/dummydata.label new file mode 100644 index 0000000000..fb38a1f3e0 --- /dev/null +++ b/data/assets/examples/pointclouds/data/dummydata.label @@ -0,0 +1,100 @@ +13428000 26239000 45870000 id P0 text Point 0 +14727000 45282000 10832000 id P1 text Point 1 +24999000 28370000 19911000 id P2 text Point 2 +26539000 36165000 39582000 id P3 text Point 3 +49056000 24775000 14626000 id P4 text Point 4 +43965000 21472000 18760000 id P5 text Point 5 +15661000 28429000 16965000 id P6 text Point 6 +25046000 36006000 49453000 id P7 text Point 7 +13797000 34811000 18825000 id P8 text Point 8 +13879000 14824000 41472000 id P9 text Point 9 +11481000 20480000 25925000 id P10 text Point 10 +45032000 16606000 23537000 id P11 text Point 11 +14395000 34940000 21968000 id P12 text Point 12 +15945000 21478000 29536000 id P13 text Point 13 +13458000 19017000 18542000 id P14 text Point 14 +45302000 15732000 34369000 id P15 text Point 15 +15559000 36269000 18160000 id P16 text Point 16 +16552000 14570000 39763000 id P17 text Point 17 +11353000 13410000 38311000 id P18 text Point 18 +12383000 49302000 33539000 id P19 text Point 19 +44302000 21387000 23434000 id P20 text Point 20 +43107000 14206000 24728000 id P21 text Point 21 +49320000 43878000 24240000 id P22 text Point 22 +37519000 40514000 16409000 id P23 text Point 23 +37202000 40122000 42551000 id P24 text Point 24 +12783000 11757000 25348000 id P25 text Point 25 +39621000 30560000 15929000 id P26 text Point 26 +10937000 15183000 21413000 id P27 text Point 27 +39411000 12532000 44006000 id P28 text Point 28 +47905000 25552000 28902000 id P29 text Point 29 +28426000 45268000 27886000 id P30 text Point 30 +15026000 45897000 23911000 id P31 text Point 31 +24625000 14844000 12837000 id P32 text Point 32 +46304000 21144000 24421000 id P33 text Point 33 +29558000 10724000 27312000 id P34 text Point 34 +49636000 27202000 24626000 id P35 text Point 35 +38603000 23794000 41040000 id P36 text Point 36 +37336000 21742000 40982000 id P37 text Point 37 +35128000 38725000 25244000 id P38 text Point 38 +30419000 33591000 39512000 id P39 text Point 39 +18665000 11189000 45438000 id P40 text Point 40 +15442000 36392000 16074000 id P41 text Point 41 +43378000 27900000 38748000 id P42 text Point 42 +44424000 19982000 13528000 id P43 text Point 43 +42733000 15383000 28933000 id P44 text Point 44 +40144000 46822000 29588000 id P45 text Point 45 +16927000 38232000 43931000 id P46 text Point 46 +38910000 36030000 38003000 id P47 text Point 47 +48340000 38510000 39290000 id P48 text Point 48 +17258000 45665000 27152000 id P49 text Point 49 +48363000 39701000 11905000 id P50 text Point 50 +27660000 29370000 26029000 id P51 text Point 51 +47106000 30527000 17038000 id P52 text Point 52 +10471000 37521000 35398000 id P53 text Point 53 +27774000 44082000 40036000 id P54 text Point 54 +46887000 20413000 36649000 id P55 text Point 55 +10093000 46706000 19187000 id P56 text Point 56 +49093000 36514000 38499000 id P57 text Point 57 +48945000 49826000 23225000 id P58 text Point 58 +26852000 28926000 32243000 id P59 text Point 59 +34219000 34787000 30801000 id P60 text Point 60 +31075000 30369000 36898000 id P61 text Point 61 +28135000 21412000 25552000 id P62 text Point 62 +13347000 15980000 43094000 id P63 text Point 63 +26928000 31159000 16653000 id P64 text Point 64 +12364000 14374000 43646000 id P65 text Point 65 +38991000 49388000 48534000 id P66 text Point 66 +17180000 14935000 11680000 id P67 text Point 67 +27666000 29337000 44778000 id P68 text Point 68 +13660000 11108000 37986000 id P69 text Point 69 +36910000 10252000 41657000 id P70 text Point 70 +21785000 20095000 14903000 id P71 text Point 71 +33363000 42124000 39814000 id P72 text Point 72 +42758000 48892000 44762000 id P73 text Point 73 +16590000 22098000 28515000 id P74 text Point 74 +26448000 45475000 33361000 id P75 text Point 75 +41182000 23927000 25075000 id P76 text Point 76 +49801000 15636000 39883000 id P77 text Point 77 +32725000 13037000 49874000 id P78 text Point 78 +31130000 16471000 41939000 id P79 text Point 79 +19599000 37119000 26468000 id P80 text Point 80 +30024000 23097000 14711000 id P81 text Point 81 +39567000 48586000 49391000 id P82 text Point 82 +46249000 28249000 32393000 id P83 text Point 83 +12180000 20488000 46288000 id P84 text Point 84 +29659000 40098000 45152000 id P85 text Point 85 +41026000 19309000 15845000 id P86 text Point 86 +47146000 39852000 26666000 id P87 text Point 87 +39958000 46945000 11789000 id P88 text Point 88 +25921000 13147000 22257000 id P89 text Point 89 +28892000 28329000 49094000 id P90 text Point 90 +29563000 48312000 45703000 id P91 text Point 91 +46127000 46582000 13462000 id P92 text Point 92 +23268000 24051000 48652000 id P93 text Point 93 +22163000 26901000 28702000 id P94 text Point 94 +46968000 17027000 25787000 id P95 text Point 95 +24148000 44640000 15422000 id P96 text Point 96 +11566000 26486000 11735000 id P97 text Point 97 +11063000 38883000 16772000 id P98 text Point 98 +43081000 16718000 45813000 id P99 text Point 99 diff --git a/data/assets/examples/pointclouds/points.asset b/data/assets/examples/pointclouds/points.asset new file mode 100644 index 0000000000..e298045d79 --- /dev/null +++ b/data/assets/examples/pointclouds/points.asset @@ -0,0 +1,237 @@ +local earthAsset = asset.require("scene/solarsystem/planets/earth/earth") + + + +-- Color mapped points close to Earth, with some different settings for color and +-- sizing, and a StaticRotation that makes them not overlap + +-- Point cloud with fixed color and default size (fixed) +local FixedColor_FixedSize = { + Identifier = "ExamplePoints_FixedSize", + Parent = earthAsset.Earth.Identifier, + Renderable = { + Type = "RenderablePointCloud", + File = asset.resource("data/dummydata.csv"), + Coloring = { + FixedColor = { 0.0, 0.5, 0.0 } + } + }, + GUI = { + Name = "Fixed Color / Fixed Size", + Path = "/Example/Point Clouds", + Description = "Point cloud with a fixed color and fixed sizing" + } +} + +-- Point cloud with fixed color and size scaling that is limited by a certain size, +-- in pixels +local FixedColor_MaxPixelSize = { + Identifier = "ExamplePoints_MaxPixelSize", + Parent = earthAsset.Earth.Identifier, + Transform = { + Rotation = { + Type = "StaticRotation", + Rotation = { 0, 0, 0.5 * math.pi } + } + }, + Renderable = { + Type = "RenderablePointCloud", + File = asset.resource("data/dummydata.csv"), + Coloring = { + FixedColor = { 0.0, 1.0, 1.0 } + }, + SizeSettings = { + MaxPixelSize = 4.7, + EnablePixelSizeControl = true + } + }, + GUI = { + Name = "Fixed Color / Max Pixel Size", + Path = "/Example/Point Clouds", + Description = "Point cloud with a fixed color and sizing with a given max pixel size" + } +} + +-- Point cloud with color mapping and fixed point sizing +local ColorMapped_FixedSize = { + Identifier = "ExamplePoints_ColorMapped", + Parent = earthAsset.Earth.Identifier, + Transform = { + Rotation = { + Type = "StaticRotation", + Rotation = { 0, 0, -0.5 * math.pi } + } + }, + Renderable = { + Type = "RenderablePointCloud", + File = asset.resource("data/dummydata.csv"), + Coloring = { + ColorMapping = { + File = asset.resource("viridis.cmap") + } + }, + SizeSettings = { + -- Here we set the exponent for the scale explicitly, to a value that + -- gives the points a suitable size based on their world-space coordinates + ScaleExponent = 6.5 + } + }, + GUI = { + Name = "Color Mapped", + Path = "/Example/Point Clouds", + Description = "Color mapped point cloud with fixed sizing" + } +} + +-- Point cloud with fixed color and size scaling from a selected data column +local FixedColor_ScaleBasedOnData = { + Identifier = "ExamplePoints_ScaleFromData", + Parent = earthAsset.Earth.Identifier, + Transform = { + Rotation = { + Type = "StaticRotation", + Rotation = { 0, 0.5 * math.pi, 0 } + } + }, + Renderable = { + Type = "RenderablePointCloud", + File = asset.resource("data/dummydata.csv"), + Coloring = { + FixedColor = { 0.5, 0.5, 0.0 } + }, + SizeSettings = { + -- The options for the columns that the points can be scaled by. The first + -- alternative is chosen per default + SizeMapping = { "number_withNan", "a" }, + -- Use a slightly smaller scale than above for the base size of the points + -- (will decide the size of the smallest point). That way, the points don't + -- become too big when scaled by the data parameter + ScaleExponent = 5 + } + }, + GUI = { + Name = "Fixed Color / Size From Data", + Path = "/Example/Point Clouds", + Description = [[Point cloud with a fixed color and sizing that can be set based on a + column in the dataset]] + } +} + +-- Point cloud with textures. Textured points can also be color mapped, but here it +-- is disabled per default +local Textured = { + Identifier = "ExamplePoints_Textured", + Parent = earthAsset.Earth.Identifier, + Transform = { + Rotation = { + Type = "StaticRotation", + Rotation = { 0, math.pi, 0 } + } + }, + Renderable = { + Type = "RenderablePointCloud", + File = asset.resource("data/dummydata.csv"), + -- The path to the texture file. Here we use openspace.absPath so that we can use + -- the ${DATA} token to get the path to a texture in the "OpenSpace/data" folder, + -- but for a file at a relative location it would also work to use asset.resource, + -- like for the data file above + Texture = openspace.absPath("${DATA}/test3.jpg"), + -- Disable additive blending, so that points will be rendered with their actual color + -- and overlapping points will be sorted by depth. This works best when the points + -- have an opacity of 1 + UseAdditiveBlending = false, + Coloring = { + ColorMapping = { + -- Disable color map per default. When enabled, the texture color will be + -- multiplied with the color from the color map + Enabled = false, + File = asset.resource("viridis.cmap") + } + } + }, + GUI = { + Name = "Textured", + Path = "/Example/Point Clouds", + Description = "Point cloud with a texture per point" + } +} + +-- Point cloud with more advanced color mapping and fixed point sizing. +-- Here we have predefined a couple of parameters to use for the color mapping. +-- Also, missing/NaN values are mapped to a specific color. +-- Finally, no additive blending is used for the color, meaning that the color of +-- overlapping points will not be mixed/added +local ColorMappedAdvanced_NoBlend = { + Identifier = "ExamplePoints_ColorMappedNoBlend", + Parent = earthAsset.Earth.Identifier, + Transform = { + Rotation = { + Type = "StaticRotation", + Rotation = { 0, 0, math.pi } + } + }, + Renderable = { + Type = "RenderablePointCloud", + File = asset.resource("data/dummydata.csv"), + UseAdditiveBlending = false, -- Disable additive blending + Coloring = { + ColorMapping = { + File = asset.resource("viridis.cmap"), + ParameterOptions = { + { Key = "number_withNan" }, -- no range => compute min and max + { Key = "normaldist_withMissing", Range = { -0.5, 0.5 } } + }, + ShowMissingData = true, + NoDataColor = { 0.5, 0.5, 0.5, 1.0 } + } + }, + SizeSettings = { + ScaleExponent = 6.5 + } + }, + GUI = { + Name = "Color Mapped (Advanced) - No blending", + Path = "/Example/Point Clouds", + Description = [[Color mapped point cloud without additive blending, with missing + values shown in grey, and a limited choice of parameter options to use for + the color mapping.]] + } +} + + +asset.onInitialize(function() + openspace.addSceneGraphNode(FixedColor_FixedSize) + openspace.addSceneGraphNode(FixedColor_MaxPixelSize) + openspace.addSceneGraphNode(FixedColor_ScaleBasedOnData) + openspace.addSceneGraphNode(Textured) + openspace.addSceneGraphNode(ColorMapped_FixedSize) + openspace.addSceneGraphNode(ColorMappedAdvanced_NoBlend) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(ColorMappedAdvanced_NoBlend) + openspace.removeSceneGraphNode(ColorMapped_FixedSize) + openspace.removeSceneGraphNode(Textured) + openspace.removeSceneGraphNode(FixedColor_ScaleBasedOnData) + openspace.removeSceneGraphNode(FixedColor_MaxPixelSize) + openspace.removeSceneGraphNode(FixedColor_FixedSize) +end) + +asset.export(FixedColor_FixedSize) +asset.export(FixedColor_MaxPixelSize) +asset.export(FixedColor_ScaleBasedOnData) +asset.export(Textured) +asset.export(ColorMapped_FixedSize) +asset.export(ColorMappedAdvanced_NoBlend) + + + +asset.meta = { + Name = "Example - Point Clouds", + Version = "1.0", + Description = [[Examples of point clouds with a few different settings for sizing and + coloring]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/examples/pointclouds/points_colormappingsettings.asset b/data/assets/examples/pointclouds/points_colormappingsettings.asset new file mode 100644 index 0000000000..83ca91f125 --- /dev/null +++ b/data/assets/examples/pointclouds/points_colormappingsettings.asset @@ -0,0 +1,78 @@ +local earthAsset = asset.require("scene/solarsystem/planets/earth/earth") + + + +local Example = { + Identifier = "ExamplePoints_ColorMapping", + Parent = earthAsset.Earth.Identifier, + Renderable = { + Type = "RenderablePointCloud", + File = asset.resource("data/dummydata.csv"), + Coloring = { + ColorMapping = { + File = asset.resource("viridis.cmap"), + -- Set the default choice of parameter and value range explicitly. Values + -- outside this range will be given special colors + Parameter = "normaldist_withMissing", + ValueRange = { -0.25, 0.25 }, + -- Show missing data values, so we can show these in a specific color + ShowMissingData = true, + -- Color for missing data points + NoDataColor = { 1.0, 0.0, 0.0, 1.0 }, + -- Color for point with values above the given range. If not set, or if + -- UseAboveRangeColor is false, the color will be set to the last value + -- in the color map (as per default) + AboveRangeColor = { 0.0, 1.0, 0.0, 1.0 }, + -- Color for point with values below the given range. If not set, or if + -- UseAboveRangeColor is false, the color will be set to the first value + -- in the color map (as per default) + BelowRangeColor = { 0.0, 0.0, 1.0, 1.0 }, + + -- Some other parameters that can be set are the following (these are all the + -- default values): + + -- If true, completely hide all values outside the range + HideValuesOutsideRange = false, + -- Toggle whether the above range color should be used + UseAboveRangeColor = true, + -- Toggle whether the below range color should be used + UseBelowRangeColor = true + } + }, + SizeSettings = { + -- Reduce the size of the point a little bit so that they don't overlap so much + ScaleFactor = 0.5 + } + }, + GUI = { + Name = "Advanced Color Mapping Settings", + Path = "/Example/Point Clouds", + Description = [[Example of a point cloud where the range is set explicitly and + specific colors are used for values outside the range, as well as for missing + data values.]] + } +} + + +asset.onInitialize(function() + openspace.addSceneGraphNode(Example) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(Example) +end) + +asset.export(Example) + + + +asset.meta = { + Name = "Example - Advanced Color Mapping Settings", + Version = "1.0", + Description = [[Example of a point cloud where the range is set explicitly and + specific colors are used for values outside the range, as well as for missing + data values]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/examples/pointclouds/points_datamapping.asset b/data/assets/examples/pointclouds/points_datamapping.asset new file mode 100644 index 0000000000..791e945257 --- /dev/null +++ b/data/assets/examples/pointclouds/points_datamapping.asset @@ -0,0 +1,68 @@ +local earthAsset = asset.require("scene/solarsystem/planets/earth/earth") + + + +local Example = { + Identifier = "ExamplePoints_DataMapping", + Parent = earthAsset.Earth.Identifier, + Renderable = { + Type = "RenderablePointCloud", + File = asset.resource("data/dummydata.csv"), + DataMapping = { + -- Using the DataMapping, we can specify the X, Y and Z values of the point + -- positions to be set by any value in the dataset, without changing the dataset + -- used for the rendering + X = "a", + Y = "b", + Z = "a", + -- It is also possible to specify a numeric value that corresponds to missing + -- values in the dataset. These will be interpreted as NaN values + MissingDataValue = 29, + -- And some column that we do not want to include in the loading. Here we can for + -- example skip the regular position columns + ExcludeColumns = { "x", "y", "z" } + }, + -- Interpret values as Parsec rather than meter. The values in the a and b columns + -- are much smaller than the x, y and z + Unit = "pc", + -- To show the values corresponding to missing values, use a color map and show + -- missing data values in a specific color + Coloring = { + ColorMapping = { + File = asset.resource("viridis.cmap"), + ShowMissingData = true, + NoDataColor = { 1.0, 0.0, 0.0, 1.0 } + } + }, + }, + GUI = { + Name = "Data Mapping", + Path = "/Example/Point Clouds", + Description = [[Example of a point cloud where the X, Y and Z position are mapped to + other columns in the dataset.]] + } +} + + +asset.onInitialize(function() + openspace.addSceneGraphNode(Example) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(Example) +end) + +asset.export(Example) + + + +asset.meta = { + Name = "Example - Point Cloud with Custom Data Mapping", + Version = "1.0", + Description = [[Example of a point cloud where the X, Y and Z position are mapped to + other columns in the dataset. The data mapping also includes some settings for + missing data values and columns to exclude when loading the dataset]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/examples/pointclouds/points_fading.asset b/data/assets/examples/pointclouds/points_fading.asset new file mode 100644 index 0000000000..2b9b5ea604 --- /dev/null +++ b/data/assets/examples/pointclouds/points_fading.asset @@ -0,0 +1,88 @@ +local earthAsset = asset.require("scene/solarsystem/planets/earth/earth") + + + +local EarthRadius = 6371000 + +local Example = { + Identifier = "ExamplePoints_Fading", + Parent = earthAsset.Earth.Identifier, + Renderable = { + Type = "RenderablePointCloud", + File = asset.resource("data/dummydata.csv"), + Coloring = { + FixedColor = { 0.0, 0.3, 1.0 } + }, + Fading = { + -- Control at what distance the points fade in. The points will be invisible + -- when the camera is closer than the first value, and fully visible when the + -- camera is further away then the last value. In-between they will linearly + -- fade in or out + FadeInDistances = { 15.0 * EarthRadius, 35.0 * EarthRadius } + } + }, + GUI = { + Name = "PointCloud - Fading", + Path = "/Example/Point Clouds", + Description = [[Example of a point cloud with distance-based fading (the points + are visible when the camera reaches a certain distance away from the origin)]] + } +} + +local Example_Invert = { + Identifier = "ExamplePoints_FadingInverted", + Parent = earthAsset.Earth.Identifier, + -- Rotate so that the points don't overlap with the previous ones + Transform = { + Rotation = { + Type = "StaticRotation", + Rotation = { 0, math.pi, 0 } + } + }, + Renderable = { + Type = "RenderablePointCloud", + File = asset.resource("data/dummydata.csv"), + Coloring = { + FixedColor = { 1.0, 0.3, 0.0 } + }, + Fading = { + -- Use the same fade distances, but invert the fading so that the points are + -- visible when the camera is closer to the origin that the first value, and + -- invisible when further away than the last value + FadeInDistances = { 15.0 * EarthRadius, 35.0 * EarthRadius }, + Invert = true + } + }, + GUI = { + Name = "PointCloud - Fading (Inverted)", + Path = "/Example/Point Clouds", + Description = [[Example of a point cloud with inverted distance-based fading + (the points are visible when the camera is close to the origin, and invisible + when further away)]] + } +} + + +asset.onInitialize(function() + openspace.addSceneGraphNode(Example) + openspace.addSceneGraphNode(Example_Invert) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(Example_Invert) + openspace.removeSceneGraphNode(Example) +end) + +asset.export(Example) +asset.export(Example_Invert) + + + +asset.meta = { + Name = "Example - Point Cloud with Fading", + Version = "1.0", + Description = [[Example of a point cloud with distance-based fading]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/examples/pointclouds/points_units_labels.asset b/data/assets/examples/pointclouds/points_units_labels.asset new file mode 100644 index 0000000000..a1d02c3247 --- /dev/null +++ b/data/assets/examples/pointclouds/points_units_labels.asset @@ -0,0 +1,55 @@ +local earthAsset = asset.require("scene/solarsystem/planets/earth/earth") + + + +local Example = { + Identifier = "ExamplePoints_UnitsAndLabels", + Parent = earthAsset.Earth.Identifier, + Renderable = { + Type = "RenderablePointCloud", + File = asset.resource("data/dummydata.csv"), + Coloring = { + FixedColor = { 0.0, 0.3, 1.0 } + }, + -- Add a unit to interpret the points to be in kilometers rather than meters + Unit = "Km", + -- Also load a label file with the same position information as the CSV file. + -- The unit should be the same as the renderable + Labels = { + Enabled = true, + File = asset.resource("data/dummydata.label"), + Size = 7.5, + Unit = "Km" + } + -- @TODO The labels are not correctly oriented towards the camera! + }, + GUI = { + Name = "Units & Labels", + Path = "/Example/Point Clouds", + Description = [[Example of a point cloud where a spcific unit is used when + interpreting the position values, and text labels are placed at the points]] + } +} + + +asset.onInitialize(function() + openspace.addSceneGraphNode(Example) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(Example) +end) + +asset.export(Example) + + + +asset.meta = { + Name = "Example - Point Cloud with Unit and Labels", + Version = "1.0", + Description = [[Example of a point cloud where a spcific unit is used when + interpreting the position values, and text labels are placed at the points]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/examples/pointclouds/polygon_cloud.asset b/data/assets/examples/pointclouds/polygon_cloud.asset new file mode 100644 index 0000000000..6b2ba10677 --- /dev/null +++ b/data/assets/examples/pointclouds/polygon_cloud.asset @@ -0,0 +1,45 @@ +local Example = { + Identifier = "ExamplePoints_Polygon", + Renderable = { + Type = "RenderablePolygonCloud", + File = asset.resource("data/dummydata.csv"), + Coloring = { + FixedColor = { 0.8, 0.0, 0.0 } + }, + -- Specify the number of sides for the polygon. 3 = triangle, 4 = square, + -- 5 = pentagon, 6 = hexagon, and so on + PolygonSides = 6, + -- Scale up the dataset, so that it is interpreted in Kilometers instead of meters, + -- for increased visiblity + Unit = "Km" + }, + GUI = { + Name = "Polygon Cloud", + Path = "/Example/Point Clouds", + Description = [[Example of a polygon cloud, which is a point cloud where a uniform + polygon is used for the shape of the points]] + } +} + + +asset.onInitialize(function() + openspace.addSceneGraphNode(Example) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(Example) +end) + +asset.export(Example) + + + +asset.meta = { + Name = "Example - Polygon Cloud", + Version = "1.0", + Description = [[Example of a polygon cloud, which is a point cloud where a uniform + polygon is used for the shape of the points]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/examples/pointclouds/viridis.cmap b/data/assets/examples/pointclouds/viridis.cmap new file mode 100644 index 0000000000..2c00fba35d --- /dev/null +++ b/data/assets/examples/pointclouds/viridis.cmap @@ -0,0 +1,258 @@ +# Viridis Color map +256 +0.267004 0.004874 0.329415 1.000000 +0.268510 0.009605 0.335427 1.000000 +0.269944 0.014625 0.341379 1.000000 +0.271305 0.019942 0.347269 1.000000 +0.272594 0.025563 0.353093 1.000000 +0.273809 0.031497 0.358853 1.000000 +0.274952 0.037752 0.364543 1.000000 +0.276022 0.044167 0.370164 1.000000 +0.277018 0.050344 0.375715 1.000000 +0.277941 0.056324 0.381191 1.000000 +0.278791 0.062145 0.386592 1.000000 +0.279566 0.067836 0.391917 1.000000 +0.280267 0.073417 0.397163 1.000000 +0.280894 0.078907 0.402329 1.000000 +0.281446 0.084320 0.407414 1.000000 +0.281924 0.089666 0.412415 1.000000 +0.282327 0.094955 0.417331 1.000000 +0.282656 0.100196 0.422160 1.000000 +0.282910 0.105393 0.426902 1.000000 +0.283091 0.110553 0.431554 1.000000 +0.283197 0.115680 0.436115 1.000000 +0.283229 0.120777 0.440584 1.000000 +0.283187 0.125848 0.444960 1.000000 +0.283072 0.130895 0.449241 1.000000 +0.282884 0.135920 0.453427 1.000000 +0.282623 0.140926 0.457517 1.000000 +0.282290 0.145912 0.461510 1.000000 +0.281887 0.150881 0.465405 1.000000 +0.281412 0.155834 0.469201 1.000000 +0.280868 0.160771 0.472899 1.000000 +0.280255 0.165693 0.476498 1.000000 +0.279574 0.170599 0.479997 1.000000 +0.278826 0.175490 0.483397 1.000000 +0.278012 0.180367 0.486697 1.000000 +0.277134 0.185228 0.489898 1.000000 +0.276194 0.190074 0.493001 1.000000 +0.275191 0.194905 0.496005 1.000000 +0.274128 0.199721 0.498911 1.000000 +0.273006 0.204520 0.501721 1.000000 +0.271828 0.209303 0.504434 1.000000 +0.270595 0.214069 0.507052 1.000000 +0.269308 0.218818 0.509577 1.000000 +0.267968 0.223549 0.512008 1.000000 +0.266580 0.228262 0.514349 1.000000 +0.265145 0.232956 0.516599 1.000000 +0.263663 0.237631 0.518762 1.000000 +0.262138 0.242286 0.520837 1.000000 +0.260571 0.246922 0.522828 1.000000 +0.258965 0.251537 0.524736 1.000000 +0.257322 0.256130 0.526563 1.000000 +0.255645 0.260703 0.528312 1.000000 +0.253935 0.265254 0.529983 1.000000 +0.252194 0.269783 0.531579 1.000000 +0.250425 0.274290 0.533103 1.000000 +0.248629 0.278775 0.534556 1.000000 +0.246811 0.283237 0.535941 1.000000 +0.244972 0.287675 0.537260 1.000000 +0.243113 0.292092 0.538516 1.000000 +0.241237 0.296485 0.539709 1.000000 +0.239346 0.300855 0.540844 1.000000 +0.237441 0.305202 0.541921 1.000000 +0.235526 0.309527 0.542944 1.000000 +0.233603 0.313828 0.543914 1.000000 +0.231674 0.318106 0.544834 1.000000 +0.229739 0.322361 0.545706 1.000000 +0.227802 0.326594 0.546532 1.000000 +0.225863 0.330805 0.547314 1.000000 +0.223925 0.334994 0.548053 1.000000 +0.221989 0.339161 0.548752 1.000000 +0.220057 0.343307 0.549413 1.000000 +0.218130 0.347432 0.550038 1.000000 +0.216210 0.351535 0.550627 1.000000 +0.214298 0.355619 0.551184 1.000000 +0.212395 0.359683 0.551710 1.000000 +0.210503 0.363727 0.552206 1.000000 +0.208623 0.367752 0.552675 1.000000 +0.206756 0.371758 0.553117 1.000000 +0.204903 0.375746 0.553533 1.000000 +0.203063 0.379716 0.553925 1.000000 +0.201239 0.383670 0.554294 1.000000 +0.199430 0.387607 0.554642 1.000000 +0.197636 0.391528 0.554969 1.000000 +0.195860 0.395433 0.555276 1.000000 +0.194100 0.399323 0.555565 1.000000 +0.192357 0.403199 0.555836 1.000000 +0.190631 0.407061 0.556089 1.000000 +0.188923 0.410910 0.556326 1.000000 +0.187231 0.414746 0.556547 1.000000 +0.185556 0.418570 0.556753 1.000000 +0.183898 0.422383 0.556944 1.000000 +0.182256 0.426184 0.557120 1.000000 +0.180629 0.429975 0.557282 1.000000 +0.179019 0.433756 0.557430 1.000000 +0.177423 0.437527 0.557565 1.000000 +0.175841 0.441290 0.557685 1.000000 +0.174274 0.445044 0.557792 1.000000 +0.172719 0.448791 0.557885 1.000000 +0.171176 0.452530 0.557965 1.000000 +0.169646 0.456262 0.558030 1.000000 +0.168126 0.459988 0.558082 1.000000 +0.166617 0.463708 0.558119 1.000000 +0.165117 0.467423 0.558141 1.000000 +0.163625 0.471133 0.558148 1.000000 +0.162142 0.474838 0.558140 1.000000 +0.160665 0.478540 0.558115 1.000000 +0.159194 0.482237 0.558073 1.000000 +0.157729 0.485932 0.558013 1.000000 +0.156270 0.489624 0.557936 1.000000 +0.154815 0.493313 0.557840 1.000000 +0.153364 0.497000 0.557724 1.000000 +0.151918 0.500685 0.557587 1.000000 +0.150476 0.504369 0.557430 1.000000 +0.149039 0.508051 0.557250 1.000000 +0.147607 0.511733 0.557049 1.000000 +0.146180 0.515413 0.556823 1.000000 +0.144759 0.519093 0.556572 1.000000 +0.143343 0.522773 0.556295 1.000000 +0.141935 0.526453 0.555991 1.000000 +0.140536 0.530132 0.555659 1.000000 +0.139147 0.533812 0.555298 1.000000 +0.137770 0.537492 0.554906 1.000000 +0.136408 0.541173 0.554483 1.000000 +0.135066 0.544853 0.554029 1.000000 +0.133743 0.548535 0.553541 1.000000 +0.132444 0.552216 0.553018 1.000000 +0.131172 0.555899 0.552459 1.000000 +0.129933 0.559582 0.551864 1.000000 +0.128729 0.563265 0.551229 1.000000 +0.127568 0.566949 0.550556 1.000000 +0.126453 0.570633 0.549841 1.000000 +0.125394 0.574318 0.549086 1.000000 +0.124395 0.578002 0.548287 1.000000 +0.123463 0.581687 0.547445 1.000000 +0.122606 0.585371 0.546557 1.000000 +0.121831 0.589055 0.545623 1.000000 +0.121148 0.592739 0.544641 1.000000 +0.120565 0.596422 0.543611 1.000000 +0.120092 0.600104 0.542530 1.000000 +0.119738 0.603785 0.541400 1.000000 +0.119512 0.607464 0.540218 1.000000 +0.119423 0.611141 0.538982 1.000000 +0.119483 0.614817 0.537692 1.000000 +0.119699 0.618490 0.536347 1.000000 +0.120081 0.622161 0.534946 1.000000 +0.120638 0.625828 0.533488 1.000000 +0.121380 0.629492 0.531973 1.000000 +0.122312 0.633153 0.530398 1.000000 +0.123444 0.636809 0.528763 1.000000 +0.124780 0.640461 0.527068 1.000000 +0.126326 0.644107 0.525311 1.000000 +0.128087 0.647749 0.523491 1.000000 +0.130067 0.651384 0.521608 1.000000 +0.132268 0.655014 0.519661 1.000000 +0.134692 0.658636 0.517649 1.000000 +0.137339 0.662252 0.515571 1.000000 +0.140210 0.665859 0.513427 1.000000 +0.143303 0.669459 0.511215 1.000000 +0.146616 0.673050 0.508936 1.000000 +0.150148 0.676631 0.506589 1.000000 +0.153894 0.680203 0.504172 1.000000 +0.157851 0.683765 0.501686 1.000000 +0.162016 0.687316 0.499129 1.000000 +0.166383 0.690856 0.496502 1.000000 +0.170948 0.694384 0.493803 1.000000 +0.175707 0.697900 0.491033 1.000000 +0.180653 0.701402 0.488189 1.000000 +0.185783 0.704891 0.485273 1.000000 +0.191090 0.708366 0.482284 1.000000 +0.196571 0.711827 0.479221 1.000000 +0.202219 0.715272 0.476084 1.000000 +0.208030 0.718701 0.472873 1.000000 +0.214000 0.722114 0.469588 1.000000 +0.220124 0.725509 0.466226 1.000000 +0.226397 0.728888 0.462789 1.000000 +0.232815 0.732247 0.459277 1.000000 +0.239374 0.735588 0.455688 1.000000 +0.246070 0.738910 0.452024 1.000000 +0.252899 0.742211 0.448284 1.000000 +0.259857 0.745492 0.444467 1.000000 +0.266941 0.748751 0.440573 1.000000 +0.274149 0.751988 0.436601 1.000000 +0.281477 0.755203 0.432552 1.000000 +0.288921 0.758394 0.428426 1.000000 +0.296479 0.761561 0.424223 1.000000 +0.304148 0.764704 0.419943 1.000000 +0.311925 0.767822 0.415586 1.000000 +0.319809 0.770914 0.411152 1.000000 +0.327796 0.773980 0.406640 1.000000 +0.335885 0.777018 0.402049 1.000000 +0.344074 0.780029 0.397381 1.000000 +0.352360 0.783011 0.392636 1.000000 +0.360741 0.785964 0.387814 1.000000 +0.369214 0.788888 0.382914 1.000000 +0.377779 0.791781 0.377939 1.000000 +0.386433 0.794644 0.372886 1.000000 +0.395174 0.797475 0.367757 1.000000 +0.404001 0.800275 0.362552 1.000000 +0.412913 0.803041 0.357269 1.000000 +0.421908 0.805774 0.351910 1.000000 +0.430983 0.808473 0.346476 1.000000 +0.440137 0.811138 0.340967 1.000000 +0.449368 0.813768 0.335384 1.000000 +0.458674 0.816363 0.329727 1.000000 +0.468053 0.818921 0.323998 1.000000 +0.477504 0.821444 0.318195 1.000000 +0.487026 0.823929 0.312321 1.000000 +0.496615 0.826376 0.306377 1.000000 +0.506271 0.828786 0.300362 1.000000 +0.515992 0.831158 0.294279 1.000000 +0.525776 0.833491 0.288127 1.000000 +0.535621 0.835785 0.281908 1.000000 +0.545524 0.838039 0.275626 1.000000 +0.555484 0.840254 0.269281 1.000000 +0.565498 0.842430 0.262877 1.000000 +0.575563 0.844566 0.256415 1.000000 +0.585678 0.846661 0.249897 1.000000 +0.595839 0.848717 0.243329 1.000000 +0.606045 0.850733 0.236712 1.000000 +0.616293 0.852709 0.230052 1.000000 +0.626579 0.854645 0.223353 1.000000 +0.636902 0.856542 0.216620 1.000000 +0.647257 0.858400 0.209861 1.000000 +0.657642 0.860219 0.203082 1.000000 +0.668054 0.861999 0.196293 1.000000 +0.678489 0.863742 0.189503 1.000000 +0.688944 0.865448 0.182725 1.000000 +0.699415 0.867117 0.175971 1.000000 +0.709898 0.868751 0.169257 1.000000 +0.720391 0.870350 0.162603 1.000000 +0.730889 0.871916 0.156029 1.000000 +0.741388 0.873449 0.149561 1.000000 +0.751884 0.874951 0.143228 1.000000 +0.762373 0.876424 0.137064 1.000000 +0.772852 0.877868 0.131109 1.000000 +0.783315 0.879285 0.125405 1.000000 +0.793760 0.880678 0.120005 1.000000 +0.804182 0.882046 0.114965 1.000000 +0.814576 0.883393 0.110347 1.000000 +0.824940 0.884720 0.106217 1.000000 +0.835270 0.886029 0.102646 1.000000 +0.845561 0.887322 0.099702 1.000000 +0.855810 0.888601 0.097452 1.000000 +0.866013 0.889868 0.095953 1.000000 +0.876168 0.891125 0.095250 1.000000 +0.886271 0.892374 0.095374 1.000000 +0.896320 0.893616 0.096335 1.000000 +0.906311 0.894855 0.098125 1.000000 +0.916242 0.896091 0.100717 1.000000 +0.926106 0.897330 0.104071 1.000000 +0.935904 0.898570 0.108131 1.000000 +0.945636 0.899815 0.112838 1.000000 +0.955300 0.901065 0.118128 1.000000 +0.964894 0.902323 0.123941 1.000000 +0.974417 0.903590 0.130215 1.000000 +0.983868 0.904867 0.136897 1.000000 +0.993248 0.906157 0.143936 1.000000 diff --git a/data/assets/scene/digitaluniverse/2dF.asset b/data/assets/scene/digitaluniverse/2dF.asset index fca4597e97..a86bea1544 100644 --- a/data/assets/scene/digitaluniverse/2dF.asset +++ b/data/assets/scene/digitaluniverse/2dF.asset @@ -9,26 +9,33 @@ local speck = asset.resource({ Name = "2dF Speck Files", Type = "HttpSynchronization", Identifier = "digitaluniverse_2dF_speck", - Version = 2 + Version = 3 }) local Object = { Identifier = "2dF", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, - Color = { 1.0, 1.0, 1.0 }, Opacity = 1.0, File = speck .. "2dF.speck", Unit = "Mpc", Texture = textures .. "point3A.png", - ColorMap = speck .. "2dF.cmap", - ColorOption = { "redshift", "proximity" }, - ColorRange = { { 0.0, 0.075 }, { 1.0, 25.0 } }, - ScaleFactor = 520.0, - BillboardMinMaxSize = { 0.0, 4.7 }, - EnablePixelSizeControl = true + Coloring = { + ColorMapping = { + File = speck .. "2dF.cmap", + ParameterOptions = { + { Key = "proximity", Range = { 1.0, 25.0 } }, + { Key = "redshift", Range = { 0.0, 0.075 } } + } + } + }, + SizeSettings = { + ScaleExponent = 22.6, + MaxPixelSize = 4.7, + EnablePixelSizeControl = true + } }, GUI = { Name = "2dF Galaxies", @@ -64,7 +71,7 @@ asset.export(Object) asset.meta = { Name = "2dF Galaxies", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for the The Two-degree Field (2dF) Survey", Author = "Brian Abbott (AMNH), Eric Gawiser (Rutgers U)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/2mass.asset b/data/assets/scene/digitaluniverse/2mass.asset index da92e173fc..8ed791380b 100644 --- a/data/assets/scene/digitaluniverse/2mass.asset +++ b/data/assets/scene/digitaluniverse/2mass.asset @@ -9,28 +9,34 @@ local speck = asset.resource({ Name = "2MASS Speck Files", Type = "HttpSynchronization", Identifier = "digitaluniverse_2mass_speck", - Version = 1 + Version = 2 }) local Object = { Identifier = "2MASS", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, - Color = { 1.0, 0.4, 0.2 }, Opacity = 1.0, File = speck .. "2MASS.speck", Unit = "Mpc", Texture = textures .. "point3A.png", - ColorMap = speck .. "lss.cmap", - ColorOption = { "redshift", "prox5Mpc" }, - ColorRange = { { 0.0, 0.075 }, { 1.0, 50.0 } }, - CorrectionSizeEndDistance = 20.6, - CorrectionSizeFactor = 15.0, - ScaleFactor = 510.78, - BillboardMinMaxSize = { 0.0, 11.15 }, - EnablePixelSizeControl = true + Coloring = { + FixedColor = { 1.0, 0.4, 0.2 }, + ColorMapping = { + File = speck .. "lss.cmap", + ParameterOptions = { + { Key = "prox5Mpc", Range = { 1.0, 50.0 } }, + { Key = "redshift", Range = { 0.0, 0.075 } } + } + } + }, + SizeSettings = { + ScaleExponent = 22.5, + MaxPixelSize = 11.15, + EnablePixelSizeControl = true + } }, GUI = { Name = "2MASS Galaxies", @@ -60,7 +66,7 @@ asset.export(Object) asset.meta = { Name = "2MASS Galaxies", - Version = "1.1", + Version = "2.0", Description = "Digital Universe asset for the Two Micron All-Sky Survey (2MASS) survey", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/6dF.asset b/data/assets/scene/digitaluniverse/6dF.asset index 34bdd92b3b..780aefc678 100644 --- a/data/assets/scene/digitaluniverse/6dF.asset +++ b/data/assets/scene/digitaluniverse/6dF.asset @@ -9,26 +9,34 @@ local speck = asset.resource({ Name = "6dF Speck Files", Type = "HttpSynchronization", Identifier = "digitaluniverse_6dF_speck", - Version = 2 + Version = 3 }) local Object = { Identifier = "6dF", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, - Color = { 1.0, 1.0, 0.0 }, Opacity = 1.0, File = speck .. "6dF.speck", Unit = "Mpc", Texture = textures .. "point3A.png", - ColorMap = speck .. "6dF.cmap", - ColorOption = { "redshift", "proximity" }, - ColorRange = { { 0.0, 0.075 }, { 1.0, 10.0 } }, - ScaleFactor = 534.0, - BillboardMinMaxSize = { 0.0, 9.0 }, - EnablePixelSizeControl = true + Coloring = { + FixedColor = { 1.0, 1.0, 0.0 }, + ColorMapping = { + File = speck .. "6dF.cmap", + ParameterOptions = { + { Key = "proximity", Range = { 1.0, 10.0 } }, + { Key = "redshift", Range = { 0.0, 0.075 } } + } + } + }, + SizeSettings = { + ScaleExponent = 23.2, + MaxPixelSize = 9.0, + EnablePixelSizeControl = true + } }, GUI = { Name = "6dF Galaxies", @@ -62,7 +70,7 @@ asset.export(Object) asset.meta = { Name = "6dF Galaxies", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for The Six-degree Field (6dF) Galaxy Survey", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/abell.asset b/data/assets/scene/digitaluniverse/abell.asset index b7c5de498d..2e3f6f0d02 100644 --- a/data/assets/scene/digitaluniverse/abell.asset +++ b/data/assets/scene/digitaluniverse/abell.asset @@ -9,7 +9,7 @@ local speck = asset.resource({ Name = "Abell Speck Files", Type = "HttpSynchronization", Identifier = "digitaluniverse_abell_speck", - Version = 2 + Version = 3 }) @@ -23,7 +23,7 @@ local TransformMatrix = { local Object = { Identifier = "Abell", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, Labels = { File = speck .. "abell.label", @@ -34,16 +34,20 @@ local Object = { Unit = "Mpc", TransformationMatrix = TransformMatrix }, - Color = { 1.0, 0.4, 0.2 }, Opacity = 1.0, - --ColorMap = speck .. "abell.cmap", + Coloring = { + FixedColor = { 1.0, 0.4, 0.2 }, + --ColorMap = speck .. "abell.cmap", -- TODO: Decide whether to add + }, File = speck .. "abell.speck", Texture = textures .. "point3A.png", Unit = "Mpc", TransformationMatrix = TransformMatrix, - ScaleFactor = 520.0, - BillboardMinMaxSize = { 0.0, 7.0 }, - EnablePixelSizeControl = true + SizeSettings = { + ScaleExponent = 22.6, + MaxPixelSize = 7.0, + EnablePixelSizeControl = true + } }, GUI = { Name = "Abell Galaxy Clusters", @@ -78,7 +82,7 @@ asset.export(Object) asset.meta = { Name = "Abell Galaxy Clusters", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for The Abell catalog", Author = "Stuart Levy (NCSA/UIUC), Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/alternatestarlabels.asset b/data/assets/scene/digitaluniverse/alternatestarlabels.asset index 070e50eb7d..6ae6004962 100644 --- a/data/assets/scene/digitaluniverse/alternatestarlabels.asset +++ b/data/assets/scene/digitaluniverse/alternatestarlabels.asset @@ -9,7 +9,7 @@ local speck = asset.resource({ local Object = { Identifier = "StarLabelsAlternate", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, Labels = { Enabled = true, @@ -19,7 +19,6 @@ local Object = { MinMaxSize = { 6, 20 }, Unit = "pc" }, - Color = { 1.0, 1.0, 1.0 }, Opacity = 0.65, Unit = "pc" }, @@ -51,7 +50,7 @@ asset.export(Object) asset.meta = { Name = "Stars Labels - Alternate", - Version = "1.1", + Version = "2.0", Description = "Digital Universe asset for alternate start labels", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/clusters.asset b/data/assets/scene/digitaluniverse/clusters.asset index f266d6afb9..96ff69dad6 100644 --- a/data/assets/scene/digitaluniverse/clusters.asset +++ b/data/assets/scene/digitaluniverse/clusters.asset @@ -16,7 +16,7 @@ local TransformMatrix = { local Object = { Identifier = "GalaxyClusterLabels", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, Labels = { Enabled = true, @@ -27,7 +27,6 @@ local Object = { Unit = "Mpc", TransformationMatrix = TransformMatrix }, - Color = { 1.0, 1.0, 1.0 }, Opacity = 0.65, Unit = "Mpc", TransformationMatrix = TransformMatrix @@ -58,7 +57,7 @@ asset.export(Object) asset.meta = { Name = "Galaxy Clusters Labels", - Version = "1.1", + Version = "2.0", Description = "Digital Universe asset for Galaxy Clusters", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/deepsky.asset b/data/assets/scene/digitaluniverse/deepsky.asset index 371fd66ea1..6be73ad6e4 100644 --- a/data/assets/scene/digitaluniverse/deepsky.asset +++ b/data/assets/scene/digitaluniverse/deepsky.asset @@ -16,7 +16,7 @@ local speck = asset.resource({ local DeepSkyObjects = { Identifier = "DeepSkyObjects", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, Labels = { File = speck .. "dso.label", @@ -25,22 +25,19 @@ local DeepSkyObjects = { MinMaxSize = { 16, 20 }, Unit = "pc" }, - Color = { 1.0, 1.0, 0.0 }, Opacity = 0.99, - ScaleFactor = 500.0, + Coloring = { + FixedColor = { 1.0, 1.0, 0.0 } + }, File = speck .. "dso.speck", Texture = textures .. "point3.png", - --ColorMap = speck .. "tully.cmap", - --ColorMap = speck .. "lss.cmap", - --ColorOption = { "proximity" }, - --ColorOption = { "prox5Mpc" }, - --ColorRange = { { 1.0, 30.0 } }, Unit = "pc", --FadeInDistances = { 0.05, 1.0 }, -- Fade in value in the same unit as "Unit" - BillboardMinMaxSize = { 0.0, 8.22 }, -- in pixels - --CorrectionSizeEndDistance = 22.0, - --CorrectionSizeFactor = 10.45 - EnablePixelSizeControl = true + SizeSettings = { + ScaleExponent = 21.7, + MaxPixelSize = 8.22, + EnablePixelSizeControl = true + } }, Transform = { Rotation = { @@ -112,7 +109,7 @@ asset.export(DeepSkyObjectsImages) asset.meta = { Name = "Deep Sky Objects Images", - Version = "1.1", + Version = "2.0", Description = "Digital Universe asset for Deep Sky Objects and their Images", Author = "Nate Greenstein, Matt Everhart, Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/dwarfs.asset b/data/assets/scene/digitaluniverse/dwarfs.asset index fe879a8ec6..312112931d 100644 --- a/data/assets/scene/digitaluniverse/dwarfs.asset +++ b/data/assets/scene/digitaluniverse/dwarfs.asset @@ -9,14 +9,14 @@ local speck = asset.resource({ Name = "Brown Dwarf Speck Files", Type = "HttpSynchronization", Identifier = "digitaluniverse_dwarfs_speck", - Version = 2 + Version = 3 }) local Object = { Identifier = "Dwarfs", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, Labels = { File = speck .. "dwarfs.label", @@ -25,19 +25,24 @@ local Object = { MinMaxSize = { 10, 20 }, Unit = "pc" }, - Color = { 0.4, 0.0, 0.1 }, Opacity = 1.0, File = speck .. "dwarfs.speck", Texture = textures .. "point3.png", Unit = "pc", - ColorMap = speck .. "dwarfs.cmap", - ColorOption = { "typeindex" }, - --ColorRange = { { 1.0, 4.0} }, - ScaleFactor = 372.1, - --CorrectionSizeEndDistance = 16.1, - --CorrectionSizeFactor = 7.75, - BillboardMinMaxSize = { 0.0, 20.0 }, - EnablePixelSizeControl = true + Coloring = { + FixedColor = { 0.4, 0.0, 0.1 }, + ColorMapping = { + File = speck .. "dwarfs.cmap", + ParameterOptions = { + { Key = "typeindex", Range = { 1.0, 4.0 } } + } + } + }, + SizeSettings = { + ScaleExponent = 16.2, + MaxPixelSize = 20.0, + EnablePixelSizeControl = true + } }, GUI = { Name = "Brown Dwarfs", @@ -77,7 +82,7 @@ asset.export(Object) asset.meta = { Name = "Brown Dwarfs", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for Brown Dwarfs", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/exoplanets.asset b/data/assets/scene/digitaluniverse/exoplanets.asset index c20351cb17..f7abff68f8 100644 --- a/data/assets/scene/digitaluniverse/exoplanets.asset +++ b/data/assets/scene/digitaluniverse/exoplanets.asset @@ -16,7 +16,7 @@ local speck = asset.resource({ local Object = { Identifier = "Exoplanets", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, Labels = { File = speck .. "expl.label", @@ -25,16 +25,15 @@ local Object = { MinMaxSize = { 10, 100 }, Unit = "pc" }, - Color = { 1.0, 1.0, 1.0 }, Opacity = 1.0, Texture = textures .. "target-blue.png", File = speck .. "expl.speck", Unit = "pc", - ScaleFactor = 388.67923, - CorrectionSizeEndDistance = 15.23, - CorrectionSizeFactor = 13.3, - BillboardMinMaxSize = { 0.0, 75.0 }, - EnablePixelSizeControl = true + SizeSettings = { + ScaleExponent = 16.9, + MaxPixelSize = 75.0, + EnablePixelSizeControl = true + } }, GUI = { Name = "Exoplanets", @@ -64,7 +63,7 @@ asset.export(Object) asset.meta = { Name = "Exoplanets", - Version = "1.1", + Version = "2.0", Description = "Digital Universe asset for Exoplanets", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/exoplanets_candidates.asset b/data/assets/scene/digitaluniverse/exoplanets_candidates.asset index 5fa0436b7e..d33e413484 100644 --- a/data/assets/scene/digitaluniverse/exoplanets_candidates.asset +++ b/data/assets/scene/digitaluniverse/exoplanets_candidates.asset @@ -16,18 +16,20 @@ local speck = asset.resource({ local Object = { Identifier = "PlanetaryCandidates", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, - Color = { 1.0, 1.0, 0.0 }, Opacity = 0.99, - ScaleFactor = 410.0, File = speck .. "exoplanet_candidates.speck", Unit = "pc", Texture = textures .. "halo.png", - CorrectionSizeEndDistance = 15.86, - CorrectionSizeFactor = 8.59, - BillboardMinMaxSize = { 0.0, 30.0 }, - EnablePixelSizeControl = true + Coloring = { + FixedColor = { 1.0, 1.0, 0.0 } + }, + SizeSettings = { + ScaleExponent = 17.8, + MaxPixelSize = 30.0, + EnablePixelSizeControl = true + } }, GUI = { Name = "Planetary Candidates", @@ -60,7 +62,7 @@ asset.export(Object) asset.meta = { Name = "Planetary Candidates", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for Planetary Candidates", Author = "Brian Abbott, Emily Rice, and Jason No (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/globularclusters.asset b/data/assets/scene/digitaluniverse/globularclusters.asset index 4e7095f8e4..ec6232b7af 100644 --- a/data/assets/scene/digitaluniverse/globularclusters.asset +++ b/data/assets/scene/digitaluniverse/globularclusters.asset @@ -16,7 +16,7 @@ local speck = asset.resource({ local Object = { Identifier = "GlobularClusters", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePolygonCloud", Enabled = false, Labels = { File = speck .. "gc.label", @@ -25,15 +25,18 @@ local Object = { MinMaxSize = { 4, 20 }, Unit = "pc" }, - Color = { 0.8, 0.8, 0.0 }, + Coloring = { + FixedColor = { 0.8, 0.8, 0.0 } + }, Opacity = 0.4, File = speck .. "gc.speck", - Texture = textures .. "point4.png", PolygonSides = 5, Unit = "pc", - ScaleFactor = 431.0, - BillboardMinMaxSize = { 0.0, 500.0 }, - EnablePixelSizeControl = true + SizeSettings = { + ScaleExponent = 18.7, + MaxPixelSize = 500.0, + EnablePixelSizeControl = true + } }, GUI = { Name = "Globular Clusters", @@ -69,7 +72,7 @@ asset.export(Object) asset.meta = { Name = "Globular Clusters", - Version = "2.1", + Version = "3.0", Description = [[Census: 157 globular clusters. DU Version 2.6. Globular star clusters are gravitationally bound groups of 100,000 to 1 million stars. They are compact, spherical "balls" of stars with very high stellar densities in their centers (stars diff --git a/data/assets/scene/digitaluniverse/grids.asset b/data/assets/scene/digitaluniverse/grids.asset index 65989fab4d..413694058f 100644 --- a/data/assets/scene/digitaluniverse/grids.asset +++ b/data/assets/scene/digitaluniverse/grids.asset @@ -126,7 +126,7 @@ local EclipticSphereLabels = { Identifier = "EclipticSphereLabels", Parent = transforms.SolarSystemBarycenter.Name, Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, Labels = { Enabled = true, @@ -137,7 +137,6 @@ local EclipticSphereLabels = { Unit = "pc", TransformationMatrix = EclipticTransformationMatrix }, - Color = { 1.0, 1.0, 1.0 }, Opacity = 0.65, Unit = "pc", TransformationMatrix = EclipticTransformationMatrix @@ -178,7 +177,7 @@ local EquatorialSphereLabels = { Identifier = "EquatorialSphereLabels", Parent = transforms.SolarSystemBarycenter.Name, Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, Labels = { Enabled = true, @@ -189,7 +188,6 @@ local EquatorialSphereLabels = { Unit = "pc", TransformationMatrix = EquatorialTransformationMatrix }, - Color = { 1.0, 1.0, 1.0 }, Opacity = 0.65, Unit = "pc", TransformationMatrix = EquatorialTransformationMatrix @@ -226,7 +224,7 @@ local GalacticSphereLabels = { Identifier = "GalacticSphereLabels", Parent = transforms.SolarSystemBarycenter.Name, Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, Labels = { Enabled = true, @@ -236,7 +234,6 @@ local GalacticSphereLabels = { MinMaxSize = { 1, 100 }, Unit = "pc" }, - Color = { 1.0, 1.0, 1.0 }, Opacity = 0.65, Unit = "pc" }, @@ -699,7 +696,7 @@ asset.export(Plane20Gly) asset.meta = { Name = "Grids", - Version = "2.1", + Version = "3.0", Description = [[Various grids for showing size reference. Included: 10,000 light year grid, 10 light year grid, 20 billion light year grid, 10 million light year grid, 100 light year grid, 100 million light year grid, Ecliptic Coordinate Sphere diff --git a/data/assets/scene/digitaluniverse/groups.asset b/data/assets/scene/digitaluniverse/groups.asset index 03cb117c68..a93d3608f4 100644 --- a/data/assets/scene/digitaluniverse/groups.asset +++ b/data/assets/scene/digitaluniverse/groups.asset @@ -16,7 +16,7 @@ local TransformMatrix = { local Object = { Identifier = "NearbyGalaxyGroups", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, Labels = { Enabled = true, @@ -27,9 +27,7 @@ local Object = { Unit = "Mpc", TransformationMatrix = TransformMatrix }, - Color = { 1.0, 1.0, 1.0 }, Opacity = 0.65, - --ScaleFactor = 10.0, Unit = "Mpc", TransformationMatrix = TransformMatrix }, @@ -58,7 +56,7 @@ asset.export(Object) asset.meta = { Name = "Galaxy Group Labels", - Version = "1.1", + Version = "2.0", Author = "Brian Abbott (AMNH)", Description = "Digital Universe asset for Galaxy Groups", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/h2regions.asset b/data/assets/scene/digitaluniverse/h2regions.asset index c5fb3baced..3868e22b08 100644 --- a/data/assets/scene/digitaluniverse/h2regions.asset +++ b/data/assets/scene/digitaluniverse/h2regions.asset @@ -16,7 +16,7 @@ local speck = asset.resource({ local Object = { Identifier = "HIIRegions", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePolygonCloud", Enabled = false, Labels = { File = speck .. "h2.label", @@ -25,15 +25,18 @@ local Object = { MinMaxSize = { 4, 20 }, Unit = "pc" }, - Color = { 0.0, 0.5, 1.0 }, + Coloring = { + FixedColor = { 0.0, 0.5, 1.0 } + }, Opacity = 0.70, File = speck .. "h2.speck", - Texture = textures .. "point4.png", PolygonSides = 6, Unit = "pc", - ScaleFactor = 420.0, - BillboardMinMaxSize = { 0.0, 300.0 }, - EnablePixelSizeControl = false + SizeSettings = { + ScaleExponent = 18.24, + MaxPixelSize = 300.0, + EnablePixelSizeControl = false + } }, GUI = { Name = "HII Regions", @@ -67,7 +70,7 @@ asset.export(Object) asset.meta = { Name = "HII Regions", - Version = "1.1", + Version = "2.0", Description = "Digital Universe asset for HII Regions", Author = "Carter Emmart, Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/hdf.asset b/data/assets/scene/digitaluniverse/hdf.asset index f34094b0c2..e44aeec0c0 100644 --- a/data/assets/scene/digitaluniverse/hdf.asset +++ b/data/assets/scene/digitaluniverse/hdf.asset @@ -23,19 +23,26 @@ local ColorMap = asset.resource({ local Object = { Identifier = "HubbleDeepField", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, - Color = { 1.0, 1.0, 1.0 }, Opacity = 1.0, File = HUDFSpeck .. "hudf.speck", Texture = circle .. "circle.png", - ColorMap = ColorMap .. "hudf.cmap", - ColorOption = { "redshift", "proximity" }, - ColorRange = { { 0.0, 0.075 }, { 1.0, 25.0 } }, + Coloring = { + ColorMapping = { + File = ColorMap .. "hudf.cmap", + ParameterOptions = { + { Key = "proximity", Range = { 1.0, 25.0 } }, + { Key = "redshift", Range = { 0.0, 0.075 } } + } + } + }, Unit = "Mpc", - ScaleFactor = 505.0, - BillboardMaxSize = 4.7, - EnablePixelSizeControl = true + SizeSettings = { + ScaleExponent = 21.9, + MaxPixelSize = 4.7, + EnablePixelSizeControl = true + } }, GUI = { Name = "Hubble Deep Field", @@ -62,7 +69,7 @@ asset.export(Object) asset.meta = { Name = "Hubble Ultra Deep Field", - Version = "1.2", + Version = "2.0", Description = "Hubble Ultra Deep Field galaxy survey", Author = "Frank Summers (STScI), Brian Abbott (AMNH)", URL = "http://www.haydenplanetarium.org/universe", diff --git a/data/assets/scene/digitaluniverse/localdwarfs.asset b/data/assets/scene/digitaluniverse/localdwarfs.asset index 7426659150..635b6e0edc 100644 --- a/data/assets/scene/digitaluniverse/localdwarfs.asset +++ b/data/assets/scene/digitaluniverse/localdwarfs.asset @@ -16,7 +16,7 @@ local speck = asset.resource({ local Object = { Identifier = "LocalDwarfGalaxies", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePolygonCloud", Enabled = false, Labels = { File = speck .. "localgroup.label", @@ -25,17 +25,29 @@ local Object = { MinMaxSize = { 7, 20 }, Unit = "Mpc" }, - Color = { 0.5, 1.0, 0.2 }, - ColorMap = speck .. "localgroup.cmap", - ColorOption = { "association" }, + Coloring = { + FixedColor = { 0.0, 1.0, 0.0 }, + -- @TODO: This one wasn't actually properly used before the point cloud update. + -- All points were mapped to green. Decide if we want it around. + -- @TODO: Also, the cmap is currently not applied correctly, due to speck file + -- not being read properly (it inlcudes more information than just datavar-s). + -- This should be adressed. (2023-12-13, emmbr) + ColorMapping = { + File = speck .. "localgroup.cmap", + ParameterOptions = { + { Key = "association" } + } + } + }, Opacity = 0.3, File = speck .. "localgroup.speck", - Texture = textures .. "point4.png", PolygonSides = 12, Unit = "Mpc", - ScaleFactor = 465.0, - BillboardMinMaxSize = { 0.0, 20.0 }, - EnablePixelSizeControl = true + SizeSettings = { + ScaleExponent = 20.2, + MaxPixelSize = 20.0, + EnablePixelSizeControl = true + } }, GUI = { Name = "Local Group", @@ -69,7 +81,7 @@ asset.export(Object) asset.meta = { Name = "Local Group", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for the Local Goup", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/milkyway_label.asset b/data/assets/scene/digitaluniverse/milkyway_label.asset index c2098b14ff..19088fdd44 100644 --- a/data/assets/scene/digitaluniverse/milkyway_label.asset +++ b/data/assets/scene/digitaluniverse/milkyway_label.asset @@ -16,7 +16,7 @@ local TransformMatrix = { local HomeLabel = { Identifier = "HomeLabel", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, Labels = { Enabled = true, @@ -26,15 +26,7 @@ local HomeLabel = { MinMaxSize = { 16, 20 }, Unit = "Mpc", TransformationMatrix = TransformMatrix - }, - Color = { 1.0, 0.4, 0.2 }, - Opacity = 0.99, - ScaleFactor = 500.0, - Unit = "Mpc", - TransformationMatrix = TransformMatrix, - FadeInDistances = { 0.05, 1.0 }, - BillboardMinMaxSize = { 0.0, 8.22 }, - EnablePixelSizeControl = true + } }, GUI = { Name = "Home Label", @@ -58,7 +50,7 @@ asset.export(HomeLabel) asset.meta = { Name = "Home Label", - Version = "1.1", + Version = "2.0", Description = "Label for the Milky Way titled 'Home', sided for the galactic level", Author = "OpenSpace Team", URL = "http://openspaceproject.com", diff --git a/data/assets/scene/digitaluniverse/obassociations.asset b/data/assets/scene/digitaluniverse/obassociations.asset index 73644a8c82..c1793d6717 100644 --- a/data/assets/scene/digitaluniverse/obassociations.asset +++ b/data/assets/scene/digitaluniverse/obassociations.asset @@ -9,14 +9,14 @@ local speck = asset.resource({ Name = "OB Associations Speck Files", Type = "HttpSynchronization", Identifier = "digitaluniverse_obassociations_speck", - Version = 3 + Version = 4 }) local Object = { Identifier = "OBAssociations", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePolygonCloud", Enabled = false, Labels = { File = speck .. "ob.label", @@ -25,19 +25,25 @@ local Object = { MinMaxSize = { 4, 25 }, Unit = "pc" }, - Color = { 1.0, 1.0, 1.0 }, - ColorMap = speck .. "ob.cmap", - ColorOption = { "arm" }, - SizeOption = { "diameter" }, - ExactColorMap = true, + Coloring = { + ColorMapping = { + File = speck .. "ob.cmap", + ParameterOptions = { + { Key = "arm" } + } + } + }, Opacity = 0.7, File = speck .. "ob.speck", Unit = "pc", Texture = textures .. "point4.png", PolygonSides = 7, - ScaleFactor = 390.0, - BillboardMinMaxSize = { 0.0, 450.0 }, - EnablePixelSizeControl = true + SizeSettings = { + SizeMapping = { "diameter" }, + ScaleExponent = 16.9, + MaxPixelSize = 450.0, + EnablePixelSizeControl = true + } }, GUI = { Name = "OB Associations", @@ -71,7 +77,7 @@ asset.export(Object) asset.meta = { Name = "OB Associations", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for OB Associations", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/openclusters.asset b/data/assets/scene/digitaluniverse/openclusters.asset index e16a67dcbf..dd35569693 100644 --- a/data/assets/scene/digitaluniverse/openclusters.asset +++ b/data/assets/scene/digitaluniverse/openclusters.asset @@ -16,7 +16,7 @@ local speck = asset.resource({ local Object = { Identifier = "OpenStarClusters", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePolygonCloud", Enabled = false, Labels = { File = speck .. "oc.label", @@ -25,15 +25,18 @@ local Object = { MinMaxSize = { 4, 30 }, Unit = "pc" }, - Color = { 0.1, 0.8, 0.4 }, + Coloring = { + FixedColor = { 0.1, 0.8, 0.4 } + }, Opacity = 0.5, File = speck .. "oc.speck", Unit = "pc", - Texture = textures .. "point4.png", PolygonSides = 12, - ScaleFactor = 405.75, - BillboardMinMaxSize = { 0.0, 604.0 }, - EnablePixelSizeControl = true + SizeSettings = { + ScaleExponent = 17.6, + MaxPixelSize = 604.0, + EnablePixelSizeControl = true + } }, GUI = { Name = "Open Star Clusters", @@ -68,7 +71,7 @@ asset.export(Object) asset.meta = { Name = "Open Star Clusters", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for Open Star Clusters", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/planetarynebulae.asset b/data/assets/scene/digitaluniverse/planetarynebulae.asset index 48837eac3d..303243769a 100644 --- a/data/assets/scene/digitaluniverse/planetarynebulae.asset +++ b/data/assets/scene/digitaluniverse/planetarynebulae.asset @@ -16,7 +16,7 @@ local speck = asset.resource({ local Object = { Identifier = "PlanetaryNebulae", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePolygonCloud", Enabled = false, Labels = { File = speck .. "pn.label", @@ -25,15 +25,18 @@ local Object = { MinMaxSize = { 4, 25 }, Unit = "pc" }, - Color = { 0.4, 0.4, 0.9 }, + Coloring = { + FixedColor = { 0.4, 0.4, 0.9 } + }, Opacity = 0.65, File = speck .. "pn.speck", - Texture = textures .. "point4.png", PolygonSides = 3, Unit = "pc", - ScaleFactor = 425.0, - BillboardMinMaxSize = { 0.0, 500.0 }, - EnablePixelSizeControl = true + SizeSettings = { + ScaleExponent = 18.46, + MaxPixelSize = 500.0, + EnablePixelSizeControl = true + } }, GUI = { Name = "Planetary Nebulae", @@ -64,7 +67,7 @@ asset.export(Object) asset.meta = { Name = "Planetary Nebulae", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for Planetary Nebulae", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/pulsars.asset b/data/assets/scene/digitaluniverse/pulsars.asset index 8118e80fe8..f18b4e3b5a 100644 --- a/data/assets/scene/digitaluniverse/pulsars.asset +++ b/data/assets/scene/digitaluniverse/pulsars.asset @@ -16,7 +16,7 @@ local speck = asset.resource({ local Object = { Identifier = "Pulsars", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePolygonCloud", Enabled = false, Labels = { File = speck .. "pulsar.label", @@ -25,15 +25,18 @@ local Object = { MinMaxSize = { 4, 20 }, Unit = "pc" }, - Color = { 0.7, 0.0, 0.0 }, + Coloring = { + FixedColor = { 0.7, 0.0, 0.0 } + }, Opacity = 1.0, File = speck .. "pulsar.speck", - Texture = textures .. "point4.png", PolygonSides = 4, Unit = "pc", - ScaleFactor = 424.0, - BillboardMinMaxSize = { 0.0, 500.0 }, - EnablePixelSizeControl = false + SizeSettings = { + ScaleExponent = 18.4, + MaxPixelSize = 500.0, + EnablePixelSizeControl = false + } }, GUI = { Name = "Pulsars", @@ -68,7 +71,7 @@ asset.export(Object) asset.meta = { Name = "Pulsars", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for Pulsars", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/quasars.asset b/data/assets/scene/digitaluniverse/quasars.asset index 783b1b9b1b..92c57b19e0 100644 --- a/data/assets/scene/digitaluniverse/quasars.asset +++ b/data/assets/scene/digitaluniverse/quasars.asset @@ -23,21 +23,32 @@ local colormaps = asset.resource({ local Object = { Identifier = "Quasars", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = true, - Color = { 1.0, 0.4, 0.2 }, Opacity = 0.95, File = speck .. "quasars.speck", Texture = textures .. "point3A.png", Unit = "Mpc", - ScaleFactor = 540.9, - FadeInDistances = { 1000.0, 10000.0 }, -- Fade in value in the same unit as "Unit" - BillboardMinMaxSize = { 0.0, 11.1 }, - EnablePixelSizeControl = true, - ColorMap = colormaps .. "viridis.cmap", - ColorOption = { "redshift", "Tlookback", "distMpc" }, - ColorRange = { { 0.102, 7.085 }, { 1.4, 13.0 }, { 440.5, 8852.099609 } }, - UseColorMap = false + Fading = { + FadeInDistances = { 1000.0, 10000.0 } -- Fade in value in the same unit as "Unit" + }, + Coloring = { + FixedColor = { 1.0, 0.4, 0.2 }, + ColorMapping = { + Enabled = false, + File = colormaps .. "viridis.cmap", + ParameterOptions = { + { Key = "distMpc", Range = { 440.5, 8852.099609 } }, + { Key = "redshift", Range = { 0.102, 7.085 } }, + { Key = "Tlookback", Range = { 1.4, 13.0 } } + } + } + }, + SizeSettings = { + ScaleExponent = 23.5, + MaxPixelSize = 11.1, + EnablePixelSizeControl = true + } }, GUI = { Name = "Quasars", @@ -68,7 +79,7 @@ asset.export(Object) asset.meta = { Name = "Quasars", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for Quasars", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/sdss.asset b/data/assets/scene/digitaluniverse/sdss.asset index b1159ddf92..0ed6ee3d8c 100644 --- a/data/assets/scene/digitaluniverse/sdss.asset +++ b/data/assets/scene/digitaluniverse/sdss.asset @@ -9,31 +9,37 @@ local speck = asset.resource({ Name = "Sloan Digital Sky Survey Speck Files", Type = "HttpSynchronization", Identifier = "digitaluniverse_sloandss_speck", - Version = 2 + Version = 3 }) local Object = { Identifier = "SloanDigitalSkySurvey", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = true, - Color = { 0.8, 0.8, 1.0 }, Opacity = 0.8, - ScaleFactor = 520.0, File = speck .. "SDSSgals.speck", - ColorMap = speck .. "SDSSgals.cmap", - ColorOption = { "redshift", "proximity" }, - ColorRange = { { 0.0, 0.075 }, { 1.0, 50.0 } }, + Coloring = { + FixedColor = { 0.8, 0.8, 1.0 }, + ColorMapping = { + File = speck .. "SDSSgals.cmap", + ParameterOptions = { + { Key = "proximity", Range = { 1.0, 50.0 } }, + { Key = "redshift", Range = { 0.0, 0.075 } } + } + } + }, Texture = textures .. "point3A.png", Unit = "Mpc", - FadeInDistances = { 220.0, 650.0 }, -- Fade in value in the same unit as "Unit" - BillboardMinMaxSize = { 0.0, 5.5 }, - CorrectionSizeEndDistance = 20.65, - CorrectionSizeFactor = 10.41, - TextSize = 14.8, - TextMinMaxSize = { 10, 50 }, - EnablePixelSizeControl = true + Fading = { + FadeInDistances = { 220.0, 650.0 } -- Fade in value in the same unit as "Unit" + }, + SizeSettings = { + ScaleExponent = 22.6, + MaxPixelSize = 5.5, + EnablePixelSizeControl = true + } }, GUI = { Name = "Sloan Digital Sky Survey", @@ -71,7 +77,7 @@ asset.export(Object) asset.meta = { Name = "Sloan Digital Sky Survey", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for The Sloan Digital Sky Survey (SDSS)", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/starlabels.asset b/data/assets/scene/digitaluniverse/starlabels.asset index bd33b78b85..1babd0160f 100644 --- a/data/assets/scene/digitaluniverse/starlabels.asset +++ b/data/assets/scene/digitaluniverse/starlabels.asset @@ -9,7 +9,7 @@ local speck = asset.resource({ local Object = { Identifier = "StarsLabels", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, Labels = { Enabled = true, @@ -19,7 +19,6 @@ local Object = { MinMaxSize = { 6, 50 }, Unit = "pc" }, - Color = { 1.0, 1.0, 1.0 }, Opacity = 0.65, Unit = "pc" }, @@ -45,7 +44,7 @@ asset.export(Object) asset.meta = { Name = "Star Labels", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for labels of the stars", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/superclusters.asset b/data/assets/scene/digitaluniverse/superclusters.asset index 4959dc3c47..19d8a55c41 100644 --- a/data/assets/scene/digitaluniverse/superclusters.asset +++ b/data/assets/scene/digitaluniverse/superclusters.asset @@ -16,7 +16,7 @@ local speck = asset.resource({ local Object = { Identifier = "GalaxySuperclusters", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, Labels = { Enabled = true, @@ -27,14 +27,15 @@ local Object = { Unit = "Mpc" }, DrawElements = false, - Color = { 1.0, 1.0, 1.0 }, Opacity = 0.65, File = speck .. "superclust.speck", Texture = textures .. "point3A.png", Unit = "Mpc", - ScaleFactor = 531.0, - -- BillboardMinMaxSize = { 0.0, 7.2 }, - EnablePixelSizeControl = true + SizeSettings = { + ScaleExponent = 23.1, + MaxPixelSize = 7.2, + EnablePixelSizeControl = true + } }, GUI = { Name = "Galaxy Superclusters", @@ -63,7 +64,7 @@ asset.export(Object) asset.meta = { Name = "Galaxy Superclusters", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for Galaxy Superclusters", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/supernovaremnants.asset b/data/assets/scene/digitaluniverse/supernovaremnants.asset index 5332888150..388118796a 100644 --- a/data/assets/scene/digitaluniverse/supernovaremnants.asset +++ b/data/assets/scene/digitaluniverse/supernovaremnants.asset @@ -16,7 +16,7 @@ local speck = asset.resource({ local Object = { Identifier = "SupernovaRemnants", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePolygonCloud", Enabled = false, Labels = { File = speck .. "snr.label", @@ -25,17 +25,18 @@ local Object = { MinMaxSize = { 4, 100 }, Unit = "pc" }, - Color = { 1.0, 0.5, 0.0 }, + Coloring = { + FixedColor = { 1.0, 0.5, 0.0 } + }, Opacity = 0.32, File = speck .. "snr.speck", - Texture = textures .. "point4.png", PolygonSides = 7, Unit = "pc", - ScaleFactor = 424.0, - --CorrectionSizeEndDistance = 17.5, - --CorrectionSizeFactor = 13.96, - BillboardMinMaxSize = { 0.0, 500.0 }, - EnablePixelSizeControl = true + SizeSettings = { + ScaleExponent = 18.4, + MaxPixelSize = 500.0, + EnablePixelSizeControl = true + } }, GUI = { Name = "Supernova Remnants", @@ -62,7 +63,7 @@ asset.export(Object) asset.meta = { Name = "Supernova Remnants", - Version = "2.1", + Version = "3.0", Description = "Digital Universe asset for Supernova Remnants", Author = "Brian Abbott (AMNH)", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/data/assets/scene/digitaluniverse/tully.asset b/data/assets/scene/digitaluniverse/tully.asset index b4a20b1e4b..f3a329348a 100644 --- a/data/assets/scene/digitaluniverse/tully.asset +++ b/data/assets/scene/digitaluniverse/tully.asset @@ -9,7 +9,7 @@ local speck = asset.resource({ Name = "Tully Speck Files", Type = "HttpSynchronization", Identifier = "digitaluniverse_tully_speck", - Version = 2 + Version = 3 }) @@ -23,7 +23,7 @@ local TransformMatrix = { local TullyGalaxies = { Identifier = "TullyGalaxies", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = true, Labels = { File = speck .. "tully.label", @@ -33,23 +33,28 @@ local TullyGalaxies = { Unit = "Mpc", TransformationMatrix = TransformMatrix }, - Color = { 1.0, 0.4, 0.2 }, Opacity = 0.99, - ScaleFactor = 504.0, File = speck .. "tully.speck", Texture = textures .. "point3A.png", - --ColorMap = speck .. "tully.cmap", - ColorMap = speck .. "lss.cmap", - --ColorOption = { "proximity" }, - ColorOption = { "prox5Mpc" }, - ColorRange = { { 1.0, 30.0 } }, + Coloring = { + FixedColor = { 1.0, 0.4, 0.2 }, + ColorMapping = { + File = speck .. "lss.cmap", + ParameterOptions = { + { Key = "prox5Mpc", Range = { 1.0, 30.0 } } + } + } + }, Unit = "Mpc", TransformationMatrix = TransformMatrix, - FadeInDistances = { 0.001, 1.0 }, -- Fade in value in the same unit as "Unit" - BillboardMinMaxSize = { 0.0, 7.0 }, -- in pixels - --CorrectionSizeEndDistance = 22.0, - --CorrectionSizeFactor = 10.45 - EnablePixelSizeControl = true + Fading = { + FadeInDistances = { 0.001, 1.0 } -- Fade in value in the same unit as "Unit" + }, + SizeSettings = { + ScaleExponent = 21.9, + MaxPixelSize = 7.0, + EnablePixelSizeControl = true + } }, GUI = { Name = "Tully Galaxies", @@ -125,7 +130,7 @@ asset.export(TullyGalaxiesImages) asset.meta = { Name = "Tully Galaxies", - Version = "3.1", + Version = "4.0", Description = [[Digital Universe asset for Tully Galaxies, including point cloud and images]], Author = "Stuart Levy (NCSA/UIUC), Brian Abbott (AMNH)", diff --git a/data/assets/scene/digitaluniverse/voids.asset b/data/assets/scene/digitaluniverse/voids.asset index 6f38436ee0..40db6e91b0 100644 --- a/data/assets/scene/digitaluniverse/voids.asset +++ b/data/assets/scene/digitaluniverse/voids.asset @@ -9,7 +9,7 @@ local speck = asset.resource({ local Object = { Identifier = "Voids", Renderable = { - Type = "RenderableBillboardsCloud", + Type = "RenderablePointCloud", Enabled = false, Labels = { Enabled = true, @@ -20,7 +20,6 @@ local Object = { Unit = "Mpc" }, DrawElements = false, - Color = { 1.0, 1.0, 1.0 }, Opacity = 0.65, Unit = "Mpc" }, @@ -55,7 +54,7 @@ asset.export(Object) asset.meta = { Name = "Voids", - Version = "2.1", + Version = "3.0", Author = "Brian Abbott (AMNH)", Description = "Digital Universe asset for Cosmic voids", URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", diff --git a/modules/digitaluniverse/shaders/points_sprite_fs.glsl b/include/openspace/data/csvloader.h similarity index 83% rename from modules/digitaluniverse/shaders/points_sprite_fs.glsl rename to include/openspace/data/csvloader.h index fa56e68087..dcc4163415 100644 --- a/modules/digitaluniverse/shaders/points_sprite_fs.glsl +++ b/include/openspace/data/csvloader.h @@ -22,26 +22,18 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include "fragment.glsl" +#ifndef __OPENSPACE_CORE___CSVLOADER___H__ +#define __OPENSPACE_CORE___CSVLOADER___H__ -in float vs_screenSpaceDepth; +#include +#include +#include -uniform vec3 color; -uniform float alphaValue; -uniform sampler2D spriteTexture; +namespace openspace::dataloader::csv { +Dataset loadCsvFile(std::filesystem::path path, + std::optional specs = std::nullopt); -Fragment getFragment() { - Fragment frag; +} // namespace openspace::dataloader - if (alphaValue == 0.0) { - discard; - } - - frag.color = texture(spriteTexture, gl_PointCoord) * vec4(color, alphaValue); - //frag.depth = gs_screenSpaceDepth; - frag.depth = vs_screenSpaceDepth; - frag.blend = BLEND_MODE_ADDITIVE; - - return frag; -} +#endif // __OPENSPACE_CORE___CSVLOADER___H__ diff --git a/modules/space/speckloader.h b/include/openspace/data/dataloader.h similarity index 73% rename from modules/space/speckloader.h rename to include/openspace/data/dataloader.h index 74d4150841..8e0e5920ca 100644 --- a/modules/space/speckloader.h +++ b/include/openspace/data/dataloader.h @@ -22,20 +22,28 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __OPENSPACE_MODULE_SPACE___SPECKLOADER___H__ -#define __OPENSPACE_MODULE_SPACE___SPECKLOADER___H__ +#ifndef __OPENSPACE_CORE___DATALOADER___H__ +#define __OPENSPACE_CORE___DATALOADER___H__ +#include #include #include +#include #include #include #include #include -namespace openspace::speck { - -BooleanType(SkipAllZeroLines); +namespace openspace::dataloader { +/** + * A dataset representing objects with positions and various other data columns. + * Based on the SPECK format originally used for the digital universe datasets. + * Mostly used for point-data. + * + * The read data files may also have associated texture values to be used for the + * points. + */ struct Dataset { struct Variable { int index = -1; @@ -59,8 +67,14 @@ struct Dataset { }; std::vector entries; + /// This variable can be used to get an understanding of the world scale size of + /// the dataset + float maxPositionComponent = 0.f; + int index(std::string_view variableName) const; bool normalizeVariable(std::string_view variableName); + glm::vec2 findValueRange(int variableIndex) const; + glm::vec2 findValueRange(std::string_view variableName) const; }; struct Labelset { @@ -76,49 +90,49 @@ struct Labelset { }; struct ColorMap { + std::optional belowRangeColor; + std::optional aboveRangeColor; + std::optional nanColor; std::vector entries; }; namespace data { Dataset loadFile(std::filesystem::path path, - SkipAllZeroLines skipAllZeroLines = SkipAllZeroLines::Yes); + std::optional specs = std::nullopt); std::optional loadCachedFile(std::filesystem::path path); void saveCachedFile(const Dataset& dataset, std::filesystem::path path); - Dataset loadFileWithCache(std::filesystem::path speckPath, - SkipAllZeroLines skipAllZeroLines = SkipAllZeroLines::Yes); + Dataset loadFileWithCache(std::filesystem::path path, + std::optional specs = std::nullopt); } // namespace data namespace label { Labelset loadFile(std::filesystem::path path, - SkipAllZeroLines skipAllZeroLines = SkipAllZeroLines::Yes); + std::optional specs = std::nullopt); std::optional loadCachedFile(std::filesystem::path path); void saveCachedFile(const Labelset& labelset, std::filesystem::path path); - Labelset loadFileWithCache(std::filesystem::path speckPath, - SkipAllZeroLines skipAllZeroLines = SkipAllZeroLines::Yes); + Labelset loadFileWithCache(std::filesystem::path path); } // namespace label namespace color { ColorMap loadFile(std::filesystem::path path, - SkipAllZeroLines skipAllZeroLines = SkipAllZeroLines::Yes); + std::optional specs = std::nullopt); std::optional loadCachedFile(std::filesystem::path path); void saveCachedFile(const ColorMap& colorMap, std::filesystem::path path); - ColorMap loadFileWithCache(std::filesystem::path path, - SkipAllZeroLines skipAllZeroLines = SkipAllZeroLines::Yes); + ColorMap loadFileWithCache(std::filesystem::path path); } // namespace color +} // namespace openspace::dataloader -} // namespace openspace::speck - -#endif // __OPENSPACE_MODULE_SPACE___SPECKLOADER___H__ +#endif // __OPENSPACE_CORE___DATALOADER___H__ diff --git a/include/openspace/data/datamapping.h b/include/openspace/data/datamapping.h new file mode 100644 index 0000000000..bec5890a18 --- /dev/null +++ b/include/openspace/data/datamapping.h @@ -0,0 +1,74 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2023 * + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___DATAMAPPING___H__ +#define __OPENSPACE_CORE___DATAMAPPING___H__ + +#include +#include +#include + +namespace openspace::documentation { struct Documentation; } +namespace ghoul { class Dictionary; } + +namespace openspace::dataloader { + +struct DataMapping { + static DataMapping createFromDictionary(const ghoul::Dictionary& dictionary); + static documentation::Documentation Documentation(); + + bool hasExcludeColumns() const; + bool isExcludeColumn(std::string_view column) const; + + std::optional xColumnName; + std::optional yColumnName; + std::optional zColumnName; + + std::optional missingDataValue; + + bool isCaseSensitive = false; + + std::vector excludeColumns; + + // OBS! When new parameters are added they should be included in the generateHash + // function +}; + +/** + * Generate a string based on the data mapping, that can be used to uniquely + * identify the dataset. + */ +std::string generateHashString(const DataMapping& dm); + +bool isPositionColumn(const std::string& c, const std::optional& mapping); + +bool isColumnX(const std::string& c, const std::optional& mapping); + +bool isColumnY(const std::string& c, const std::optional& mapping); + +bool isColumnZ(const std::string& c, const std::optional& mapping); + +} // namespace openspace::dataloader + +#endif // __OPENSPACE_CORE___DATAMAPPING___H__ diff --git a/modules/digitaluniverse/shaders/points_vs.glsl b/include/openspace/data/speckloader.h similarity index 77% rename from modules/digitaluniverse/shaders/points_vs.glsl rename to include/openspace/data/speckloader.h index d27c7c35a9..0ff86a8ba7 100644 --- a/modules/digitaluniverse/shaders/points_vs.glsl +++ b/include/openspace/data/speckloader.h @@ -22,29 +22,22 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#version __CONTEXT__ +#ifndef __OPENSPACE_CORE___SPECKLOADER___H__ +#define __OPENSPACE_CORE___SPECKLOADER___H__ -#include "PowerScaling/powerScaling_vs.hglsl" +#include +#include +#include -in dvec4 in_position; -in dvec4 in_colormap; +namespace openspace::dataloader::speck { -out float vs_screenSpaceDepth; -out float vs_scaleFactor; -out vec4 colorMap; +Dataset loadSpeckFile(std::filesystem::path path, + std::optional specs = std::nullopt); -uniform dmat4 modelViewProjectionTransform; -uniform float scaleFactor; +Labelset loadLabelFile(std::filesystem::path path); +ColorMap loadCmapFile(std::filesystem::path path); -void main() { - vec4 positionClipSpace = vec4(modelViewProjectionTransform * in_position); - vec4 positionScreenSpace = vec4(z_normalization(positionClipSpace)); +} // namespace openspace::dataloader::speck - vs_screenSpaceDepth = positionScreenSpace.w; - vs_scaleFactor = scaleFactor; - colorMap = vec4(in_colormap); - - gl_PointSize = scaleFactor; - gl_Position = positionScreenSpace; -} +#endif // __OPENSPACE_CORE___SPECKLOADER___H__ diff --git a/include/openspace/rendering/colormappingcomponent.h b/include/openspace/rendering/colormappingcomponent.h new file mode 100644 index 0000000000..60b9fb7868 --- /dev/null +++ b/include/openspace/rendering/colormappingcomponent.h @@ -0,0 +1,117 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2023 * + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_BASE___COLORMAPCOMPONENT___H__ +#define __OPENSPACE_MODULE_BASE___COLORMAPCOMPONENT___H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace openspace { + +namespace documentation { struct Documentation; } + +/** + * This is a component that can be used to consistently hold parameters and properties + * for controlling color mapping in different types of renderables. This includes things + * like the color map file itself (converted to a texture), colors to use for missing + * values and the available data columns and value ranges. + * + * @TODO Also provide a small shader snippet that can be included in fragment shaders + * that use this color mapping. As well as a set of uniforms? Now every + * renderable needs to handle this separately. (emmbr, 2023-10-13) + */ +class ColorMappingComponent : public properties::PropertyOwner { +public: + ColorMappingComponent(); + explicit ColorMappingComponent(const ghoul::Dictionary& dictionary); + ~ColorMappingComponent() override = default; + + ghoul::opengl::Texture* texture() const; + + /** + * Initialize the color map information (ranges, etc.) based on the input dataset. + * + * \param dataset The *loaded* input dataset + */ + void initialize(const dataloader::Dataset& dataset); + + /** + * Initialize a 1D texture based on the entries in the color map file. + */ + void initializeTexture(); + + static documentation::Documentation Documentation(); + + glm::vec4 colorFromColorMap(float value) const; + + properties::BoolProperty enabled; + properties::OptionProperty dataColumn; + properties::StringProperty colorMapFile; + properties::Vec2Property valueRange; + properties::TriggerProperty setRangeFromData; + + properties::BoolProperty hideOutsideRange; + properties::BoolProperty useNanColor; + properties::Vec4Property nanColor; + + properties::BoolProperty useAboveRangeColor; + properties::Vec4Property aboveRangeColor; + + properties::BoolProperty useBelowRangeColor; + properties::Vec4Property belowRangeColor; + +private: + /** + * Fill parameter options list and range data based on the dataset and provided + * information. + */ + void initializeParameterData(const dataloader::Dataset& dataset); + + // One item per color parameter option + std::vector _colorRangeData; + + std::unique_ptr _texture; + + dataloader::ColorMap _colorMap; + + std::optional _providedParameter; + std::optional _providedRange; + + bool _hasNanColorInAsset = false; + bool _hasBelowRangeColorInAsset = false; + bool _hasAboveRangeColorInAsset = false; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_BASE___COLORMAPCOMPONENT___H__ diff --git a/modules/space/labelscomponent.h b/include/openspace/rendering/labelscomponent.h similarity index 91% rename from modules/space/labelscomponent.h rename to include/openspace/rendering/labelscomponent.h index 9d8759fa7f..c00fbfc605 100644 --- a/modules/space/labelscomponent.h +++ b/include/openspace/rendering/labelscomponent.h @@ -22,13 +22,13 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __OPENSPACE_MODULE_SPACE___LABELSCOMPONENT___H__ -#define __OPENSPACE_MODULE_SPACE___LABELSCOMPONENT___H__ +#ifndef __OPENSPACE_CORE___LABELSCOMPONENT___H__ +#define __OPENSPACE_CORE___LABELSCOMPONENT___H__ #include #include -#include +#include #include #include #include @@ -49,8 +49,8 @@ public: explicit LabelsComponent(const ghoul::Dictionary& dictionary); ~LabelsComponent() override = default; - speck::Labelset& labelSet(); - const speck::Labelset& labelSet() const; + dataloader::Labelset& labelSet(); + const dataloader::Labelset& labelSet() const; void initialize(); @@ -68,7 +68,9 @@ public: private: std::filesystem::path _labelFile; DistanceUnit _unit = DistanceUnit::Parsec; - speck::Labelset _labelset; + dataloader::Labelset _labelset; + + bool _useCache = true; std::shared_ptr _font = nullptr; @@ -85,4 +87,4 @@ private: } // namespace openspace -#endif // __OPENSPACE_MODULE_SPACE___LABELSCOMPONENT___H__ +#endif // __OPENSPACE_CORE___LABELSCOMPONENT___H__ diff --git a/modules/base/CMakeLists.txt b/modules/base/CMakeLists.txt index 6559ad54b3..7baa93e400 100644 --- a/modules/base/CMakeLists.txt +++ b/modules/base/CMakeLists.txt @@ -44,6 +44,8 @@ set(HEADER_FILES rendering/grids/renderablegrid.h rendering/grids/renderableradialgrid.h rendering/grids/renderablesphericalgrid.h + rendering/pointcloud/renderablepointcloud.h + rendering/pointcloud/renderablepolygoncloud.h rendering/renderablecartesianaxes.h rendering/renderabledisc.h rendering/renderablelabel.h @@ -103,6 +105,8 @@ set(SOURCE_FILES rendering/grids/renderablegrid.cpp rendering/grids/renderableradialgrid.cpp rendering/grids/renderablesphericalgrid.cpp + rendering/pointcloud/renderablepointcloud.cpp + rendering/pointcloud/renderablepolygoncloud.cpp rendering/renderablecartesianaxes.cpp rendering/renderabledisc.cpp rendering/renderablelabel.cpp @@ -148,6 +152,9 @@ set(SHADER_FILES shaders/arrow_vs.glsl shaders/axes_fs.glsl shaders/axes_vs.glsl + shaders/billboardpoint_fs.glsl + shaders/billboardpoint_gs.glsl + shaders/billboardpoint_vs.glsl shaders/disc_fs.glsl shaders/disc_vs.glsl shaders/grid_vs.glsl @@ -160,6 +167,9 @@ set(SHADER_FILES shaders/model_vs.glsl shaders/plane_fs.glsl shaders/plane_vs.glsl + shaders/polygon_fs.glsl + shaders/polygon_gs.glsl + shaders/polygon_vs.glsl shaders/prism_fs.glsl shaders/prism_vs.glsl shaders/renderabletrail_fs.glsl diff --git a/modules/base/basemodule.cpp b/modules/base/basemodule.cpp index 9939cea058..2b46683efb 100644 --- a/modules/base/basemodule.cpp +++ b/modules/base/basemodule.cpp @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include #include #include @@ -144,6 +146,8 @@ void BaseModule::internalInitialize(const ghoul::Dictionary&) { fRenderable->registerClass( "RenderablePlaneTimeVaryingImage" ); + fRenderable->registerClass("RenderablePointCloud"); + fRenderable->registerClass("RenderablePolygonCloud"); fRenderable->registerClass("RenderablePrism"); fRenderable->registerClass( "RenderableTimeVaryingSphere" @@ -230,6 +234,8 @@ std::vector BaseModule::documentations() const { RenderablePlaneImageLocal::Documentation(), RenderablePlaneImageOnline::Documentation(), RenderablePlaneTimeVaryingImage::Documentation(), + RenderablePointCloud::Documentation(), + RenderablePolygonCloud::Documentation(), RenderablePrism::Documentation(), RenderableRadialGrid::Documentation(), RenderableSphere::Documentation(), diff --git a/modules/base/rendering/grids/renderableboxgrid.cpp b/modules/base/rendering/grids/renderableboxgrid.cpp index 7af3822024..c3712e9eec 100644 --- a/modules/base/rendering/grids/renderableboxgrid.cpp +++ b/modules/base/rendering/grids/renderableboxgrid.cpp @@ -76,7 +76,7 @@ namespace { // [[codegen::verbatim(LabelsInfo.description)]] std::optional labels - [[codegen::reference("space_labelscomponent")]]; + [[codegen::reference("labelscomponent")]]; }; #include "renderableboxgrid_codegen.cpp" } // namespace diff --git a/modules/base/rendering/grids/renderableboxgrid.h b/modules/base/rendering/grids/renderableboxgrid.h index e4a24c7df0..025ec3b36c 100644 --- a/modules/base/rendering/grids/renderableboxgrid.h +++ b/modules/base/rendering/grids/renderableboxgrid.h @@ -27,9 +27,9 @@ #include -#include #include #include +#include #include namespace ghoul::opengl { diff --git a/modules/base/rendering/grids/renderablegrid.cpp b/modules/base/rendering/grids/renderablegrid.cpp index ceddd1bd0f..c75afc7cdc 100644 --- a/modules/base/rendering/grids/renderablegrid.cpp +++ b/modules/base/rendering/grids/renderablegrid.cpp @@ -122,7 +122,7 @@ namespace { // [[codegen::verbatim(LabelsInfo.description)]] std::optional labels - [[codegen::reference("space_labelscomponent")]]; + [[codegen::reference("labelscomponent")]]; }; #include "renderablegrid_codegen.cpp" } // namespace diff --git a/modules/base/rendering/grids/renderablegrid.h b/modules/base/rendering/grids/renderablegrid.h index f9ddc2a1d9..14385f0847 100644 --- a/modules/base/rendering/grids/renderablegrid.h +++ b/modules/base/rendering/grids/renderablegrid.h @@ -27,12 +27,12 @@ #include -#include #include #include #include #include #include +#include #include namespace ghoul::opengl { class ProgramObject; } diff --git a/modules/base/rendering/grids/renderableradialgrid.cpp b/modules/base/rendering/grids/renderableradialgrid.cpp index 4f528fd15b..5c231a3dca 100644 --- a/modules/base/rendering/grids/renderableradialgrid.cpp +++ b/modules/base/rendering/grids/renderableradialgrid.cpp @@ -104,7 +104,7 @@ namespace { // [[codegen::verbatim(LabelsInfo.description)]] std::optional labels - [[codegen::reference("space_labelscomponent")]]; + [[codegen::reference("labelscomponent")]]; }; #include "renderableradialgrid_codegen.cpp" } // namespace diff --git a/modules/base/rendering/grids/renderableradialgrid.h b/modules/base/rendering/grids/renderableradialgrid.h index 88689832fd..cf55c07ab0 100644 --- a/modules/base/rendering/grids/renderableradialgrid.h +++ b/modules/base/rendering/grids/renderableradialgrid.h @@ -27,13 +27,13 @@ #include -#include #include #include #include #include #include #include +#include #include namespace ghoul::opengl { class ProgramObject; } diff --git a/modules/base/rendering/grids/renderablesphericalgrid.cpp b/modules/base/rendering/grids/renderablesphericalgrid.cpp index b196d5d460..a0f2a1fe61 100644 --- a/modules/base/rendering/grids/renderablesphericalgrid.cpp +++ b/modules/base/rendering/grids/renderablesphericalgrid.cpp @@ -79,7 +79,7 @@ namespace { // [[codegen::verbatim(LabelsInfo.description)]] std::optional labels - [[codegen::reference("space_labelscomponent")]]; + [[codegen::reference("labelscomponent")]]; }; #include "renderablesphericalgrid_codegen.cpp" } // namespace diff --git a/modules/base/rendering/grids/renderablesphericalgrid.h b/modules/base/rendering/grids/renderablesphericalgrid.h index 992dd7090f..5f6ac23b63 100644 --- a/modules/base/rendering/grids/renderablesphericalgrid.h +++ b/modules/base/rendering/grids/renderablesphericalgrid.h @@ -27,10 +27,10 @@ #include -#include #include #include #include +#include #include namespace ghoul::opengl { class ProgramObject; } diff --git a/modules/base/rendering/pointcloud/renderablepointcloud.cpp b/modules/base/rendering/pointcloud/renderablepointcloud.cpp new file mode 100644 index 0000000000..f43acf279a --- /dev/null +++ b/modules/base/rendering/pointcloud/renderablepointcloud.cpp @@ -0,0 +1,1042 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2023 * + * * + * 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. * + ****************************************************************************************/ + +#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 + +namespace { + constexpr std::string_view _loggerCat = "RenderablePointCloud"; + + constexpr std::array UniformNames = { + "cameraViewProjectionMatrix", "modelMatrix", "cameraPosition", "cameraLookUp", + "renderOption", "maxBillboardSize", "color", "opacity", "scaleExponent", + "scaleFactor", "up", "right", "fadeInValue", "screenSize", "hasSpriteTexture", + "spriteTexture", "useColorMap", "colorMapTexture", "cmapRangeMin", "cmapRangeMax", + "nanColor", "useNanColor", "hideOutsideRange", "enablePixelSizeControl", + "aboveRangeColor", "useAboveRangeColor", "belowRangeColor", "useBelowRangeColor", + "hasDvarScaling" + }; + + enum RenderOption { + ViewDirection = 0, + PositionNormal + }; + + constexpr openspace::properties::Property::PropertyInfo SpriteTextureInfo = { + "Texture", + "Point Sprite Texture", + "The path to the texture that should be used as the point sprite", + openspace::properties::Property::Visibility::AdvancedUser + }; + + constexpr openspace::properties::Property::PropertyInfo UseSpriteTextureInfo = { + "UseTexture", + "Use Texture", + "If true, use the provided sprite texture to render the point. If false, draw " + "the points using the default point shape", + openspace::properties::Property::Visibility::AdvancedUser + }; + + constexpr openspace::properties::Property::PropertyInfo PointColorInfo = { + "FixedColor", + "Fixed Color", + "This value is used to define the color of the points when no color map is" + "used", + openspace::properties::Property::Visibility::NoviceUser + }; + + constexpr openspace::properties::Property::PropertyInfo DrawElementsInfo = { + "DrawElements", + "Draw Elements", + "Enables/Disables the drawing of the points", + // @VISIBILITY(1.25) + openspace::properties::Property::Visibility::NoviceUser + }; + + static const openspace::properties::PropertyOwner::PropertyOwnerInfo LabelsInfo = { + "Labels", + "Labels", + "The labels for the points" + }; + + constexpr openspace::properties::Property::PropertyInfo RenderOptionInfo = { + "RenderOption", + "Render Option", + "Option wether the point billboards should face the camera or not. Used for " + "non-linear display environments such as fisheye.", + openspace::properties::Property::Visibility::AdvancedUser + }; + + constexpr openspace::properties::Property::PropertyInfo FadeInDistancesInfo = { + "FadeInDistances", + "Fade-In Start and End Distances", + "These values determine the initial and final distances from the origin of " + "the dataset at which the points will start and end fading-in. The distances " + "are specified in the same unit as the points, that is, the one provodied as the " + "Unit, or meters. With normal fading the points are fully visible once the " + "camera is outside this range and fully invisible when inside the range. With " + "inverted fading the situation is the opposite: the points are visible inside " + "hen closer than the min value of the range and invisible when further away", + // @VISIBILITY(3.25) + openspace::properties::Property::Visibility::AdvancedUser + }; + + constexpr openspace::properties::Property::PropertyInfo EnableDistanceFadeInfo = { + "Enabled", + "Enable Distance-based Fading", + "Enables/disables the Fade-in effect based on camera distance. Automatically set " + "to true if FadeInDistances are specified in the asset", + openspace::properties::Property::Visibility::User + }; + + constexpr openspace::properties::Property::PropertyInfo InvertFadeInfo = { + "Invert", + "Invert", + "This property can be used the invert the fading so that the points are " + "invisible when the camera is further away than the max fade distance " + "and fully visible when it is closer than the min distance", + openspace::properties::Property::Visibility::AdvancedUser + }; + + constexpr openspace::properties::Property::PropertyInfo UseAdditiveBlendingInfo = { + "UseAdditiveBlending", + "Use Additive Blending", + "If true (default), the color of points rendered on top of each other is " + "blended additively, resulting in a brighter color where points overlap. " + "If false, no such blending will take place and the color of the point " + "will not be modified by blending. Note that this may lead to weird behaviors " + "when the points are rendered with transparency.", + openspace::properties::Property::Visibility::AdvancedUser + }; + + constexpr openspace::properties::Property::PropertyInfo NumShownDataPointsInfo = { + "NumberOfDataPoints", + "Number of Shown Data Points", + "This read only property includes information about how many points are being " + "rendered.", + openspace::properties::Property::Visibility::User + }; + + constexpr openspace::properties::Property::PropertyInfo ScaleExponentInfo = { + "ScaleExponent", + "Scale Exponent", + "This value is used as in exponential scaling to set the absolute size of the " + "point. In general, the larger distance the dataset covers, the larger this " + "value should be. If not included, it is computed based on the maximum " + "positional component of the data points. This is useful for showing the " + "dataset at all, but you will likely want to change it to something that looks " + "good", + openspace::properties::Property::Visibility::User + }; + + constexpr openspace::properties::Property::PropertyInfo ScaleFactorInfo = { + "ScaleFactor", + "Scale Factor", + "This value is used as a multiplicative factor to adjust the size of the points, " + "after the exponential scaling and any pixel-size control effects. Simply just " + "increases or decreases the visual size of the points", + openspace::properties::Property::Visibility::User + }; + + constexpr openspace::properties::Property::PropertyInfo PixelSizeControlInfo = { + "EnablePixelSizeControl", + "Enable Pixel Size Control", + "If true, the Max Size in Pixels property will be used as an upper limit for the " + "size of the point. Reduces the size of the points when approaching them, so that " + "they stick to a maximum screen space size. Currently, the scaling is computed " + "based on rectangular displays and might look weird in other projections", + openspace::properties::Property::Visibility::AdvancedUser + }; + + constexpr openspace::properties::Property::PropertyInfo MaxPixelSizeInfo = { + "MaxPixelSize", + "Max Size in Pixels", + "The maximum size (in pixels) for the billboard representing the point.", + openspace::properties::Property::Visibility::AdvancedUser + }; + + constexpr openspace::properties::Property::PropertyInfo SizeMappingEnabledInfo = { + "Enabled", + "Size Mapping Enabled", + "If this value is set to 'true' and at least one column was loaded as an option " + "for size mapping, the chosen data column will be used to scale the size of the " + "points. The first option in the list is selected per default.", + openspace::properties::Property::Visibility::NoviceUser + }; + + constexpr openspace::properties::Property::PropertyInfo SizeMappingOptionInfo = { + "Parameter", + "Parameter Option", + "This value determines which parameter is used for scaling of the point. The " + "parameter value will be used as a miltiplicative factor to scale the size of " + "the points. Not that they may however still be scaled by pixel size adjustment " + "effects.", + openspace::properties::Property::Visibility::AdvancedUser + }; + + // A RenderablePointCloud can be used to render point-based datasets in 3D space, + // optionally including color mapping, a sprite texture and labels. There are several + // properties that affect the visuals of the points, such as settings for scaling, + // fading, sprite texture, color mapping and whether the colors of overlapping points + // should be blended additively or not. + // + // The point size depends on a few different things: + // + // - At the core, scaling is done based on an exponential value, the 'ScaleExponent'. + // A relatively small change to this value will lead to a large change in size. + // When no exponent is set, one will be created based on the coordinates in the + // dataset. The points will be visible, but may be appeared as too large or small. + // One option is to not specify the exponent when loading the dataset for the the, + // first time, to make sure the points are visual, and then adapt the value + // interactively when OpenSpace is running until you find a value that you find + // suitable. + // + // - There is also an option to limit the size of the points based on a given pixel + // size. For now, this only works for flat projection displays. + // + // - To easily change the visual size of the points, the multiplicative 'ScaleFactor' + // may be used. A value of 2 makes the points twice as large, visually, compared + // to 1. + // + // See example files in data/assets/examples/pointcloud for some concrete examples of + // point clouds with different settings. + struct [[codegen::Dictionary(RenderablePointCloud)]] Parameters { + // The path to the data file that contains information about the point to be + // rendered. Can be either a CSV or SPECK file + std::optional file; + + // If true (default), the loaded dataset will be cached so that it can be loaded + // faster at a later time. This does however mean that any updates to the values + // in the dataset will not lead to changes in the rendering without first removing + // the cached file. Set it to false to disable caching. This can be useful for + // example when working on importing a new dataset + std::optional useCaching; + + // A dictionary specifying details on how to load the dataset. Updating the data + // mapping will lead to a new cached version of the dataset + std::optional dataMapping + [[codegen::reference("dataloader_datamapping")]]; + + // [[codegen::verbatim(SpriteTextureInfo.description)]] + std::optional texture; + + // [[codegen::verbatim(UseSpriteTextureInfo.description)]] + std::optional useTexture; + + // [[codegen::verbatim(DrawElementsInfo.description)]] + std::optional drawElements; + + enum class [[codegen::map(RenderOption)]] RenderOption { + ViewDirection [[codegen::key("Camera View Direction")]], + PositionNormal [[codegen::key("Camera Position Normal")]] + }; + // [[codegen::verbatim(RenderOptionInfo.description)]] + std::optional renderOption; + + // [[codegen::verbatim(UseAdditiveBlendingInfo.description)]] + std::optional useAdditiveBlending; + + enum class [[codegen::map(openspace::DistanceUnit)]] Unit { + Meter [[codegen::key("m")]], + Kilometer [[codegen::key("Km")]], + Parsec [[codegen::key("pc")]], + Kiloparsec [[codegen::key("Kpc")]], + Megaparsec [[codegen::key("Mpc")]], + Gigaparsec [[codegen::key("Gpc")]], + Gigalightyear [[codegen::key("Gly")]] + }; + // The unit used for all distances. Should match the unit of any + // distances/positions in the data files + std::optional unit; + + // [[codegen::verbatim(LabelsInfo.description)]] + std::optional labels + [[codegen::reference("labelscomponent")]]; + + struct SizeSettings { + // A list specifying all parameters that may be used for size mapping, i.e. + // scaling the points based on the provided data columns + std::optional> sizeMapping; + + // [[codegen::verbatim(ScaleExponentInfo.description)]] + std::optional scaleExponent; + + // [[codegen::verbatim(ScaleFactorInfo.description)]] + std::optional scaleFactor; + + // [[codegen::verbatim(PixelSizeControlInfo.description)]] + std::optional enablePixelSizeControl; + + // [[codegen::verbatim(MaxPixelSizeInfo.description)]] + std::optional maxPixelSize; + }; + // Settings related to the scale of the points, whether they should limit to + // a certain pixel size, etc. + std::optional sizeSettings; + + struct ColorSettings { + // [[codegen::verbatim(PointColorInfo.description)]] + std::optional fixedColor [[codegen::color()]]; + + // Settings related to the choice of color map, parameters, etc. + std::optional colorMapping + [[codegen::reference("colormappingcomponent")]]; + }; + // Settings related to the coloring of the points, such as a fixed color, + // color map, etc. + std::optional coloring; + + struct Fading { + // [[codegen::verbatim(EnableDistanceFadeInfo.description)]] + std::optional enabled; + + // [[codegen::verbatim(FadeInDistancesInfo.description)]] + std::optional fadeInDistances; + + // [[codegen::verbatim(InvertFadeInfo.description)]] + std::optional invert; + }; + // Settings related to fading based on camera distance. Can be used to either + // fade away or fade in the points when reaching a certain distance from the + // origin of the dataset + std::optional fading; + + // Transformation matrix to be applied to each object + std::optional transformationMatrix; + }; + +#include "renderablepointcloud_codegen.cpp" +} // namespace + +namespace openspace { + +documentation::Documentation RenderablePointCloud::Documentation() { + return codegen::doc("base_renderablepointcloud"); +} + +RenderablePointCloud::SizeSettings::SizeSettings(const ghoul::Dictionary& dictionary) + : properties::PropertyOwner({ "Sizing", "Sizing", ""}) + , scaleExponent(ScaleExponentInfo, 1.f, 0.f, 25.f) + , scaleFactor(ScaleFactorInfo, 1.f, 0.f, 50.f) + , pixelSizeControl(PixelSizeControlInfo, false) + , maxPixelSize(MaxPixelSizeInfo, 400.f, 0.f, 1000.f) +{ + const Parameters p = codegen::bake(dictionary); + + if (p.sizeSettings.has_value()) { + const Parameters::SizeSettings settings = *p.sizeSettings; + + scaleFactor = settings.scaleFactor.value_or(scaleFactor); + scaleExponent = settings.scaleExponent.value_or(scaleExponent); + pixelSizeControl = settings.enablePixelSizeControl.value_or(pixelSizeControl); + maxPixelSize = settings.maxPixelSize.value_or(maxPixelSize); + + if (settings.sizeMapping.has_value()) { + std::vector opts = *settings.sizeMapping; + for (size_t i = 0; i < opts.size(); ++i) { + // Note that options are added in order + sizeMapping.parameterOption.addOption(static_cast(i), opts[i]); + } + sizeMapping.enabled = true; + + addPropertySubOwner(sizeMapping); + } + } + + addProperty(scaleFactor); + addProperty(scaleExponent); + addProperty(pixelSizeControl); + addProperty(maxPixelSize); +} + +RenderablePointCloud::SizeSettings::SizeMapping::SizeMapping() + : properties::PropertyOwner({ "SizeMapping", "Size Mapping", "" }) + , enabled(SizeMappingEnabledInfo, false) + , parameterOption( + SizeMappingOptionInfo, + properties::OptionProperty::DisplayType::Dropdown + ) +{ + addProperty(enabled); + addProperty(parameterOption); +} + +RenderablePointCloud::ColorSettings::ColorSettings(const ghoul::Dictionary& dictionary) + : properties::PropertyOwner({ "Coloring", "Coloring", "" }) + , pointColor(PointColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f)) +{ + const Parameters p = codegen::bake(dictionary); + + if (p.coloring.has_value()) { + const Parameters::ColorSettings settings = *p.coloring; + pointColor = settings.fixedColor.value_or(pointColor); + + if (settings.colorMapping.has_value()) { + colorMapping = std::make_unique( + *settings.colorMapping + ); + addPropertySubOwner(colorMapping.get()); + } + } + pointColor.setViewOption(properties::Property::ViewOptions::Color); + addProperty(pointColor); +} + +RenderablePointCloud::Fading::Fading(const ghoul::Dictionary& dictionary) + : properties::PropertyOwner({ "Fading", "Fading", "" }) + , enabled(EnableDistanceFadeInfo, false) + , fadeInDistances( + FadeInDistancesInfo, + glm::vec2(0.f), + glm::vec2(0.f), + glm::vec2(100.f) + ) + , invert(InvertFadeInfo, false) +{ + const Parameters p = codegen::bake(dictionary); + + if (p.fading.has_value()) { + const Parameters::Fading f = *p.fading; + + if (f.fadeInDistances.has_value()) { + fadeInDistances = *f.fadeInDistances; + // Set the allowed max value based of that which was entered. Just to give + // useful values for the slider + fadeInDistances.setMaxValue(10.f * glm::vec2(fadeInDistances.value().y)); + } + + enabled = f.enabled.value_or(f.fadeInDistances.has_value()); + invert = f.invert.value_or(invert); + } + + addProperty(enabled); + fadeInDistances.setViewOption(properties::Property::ViewOptions::MinMaxRange); + addProperty(fadeInDistances); + addProperty(invert); +} + +RenderablePointCloud::RenderablePointCloud(const ghoul::Dictionary& dictionary) + : Renderable(dictionary) + , _spriteTexturePath(SpriteTextureInfo) + , _useSpriteTexture(UseSpriteTextureInfo, true) + , _drawElements(DrawElementsInfo, true) + , _useAdditiveBlending(UseAdditiveBlendingInfo, true) + , _renderOption(RenderOptionInfo, properties::OptionProperty::DisplayType::Dropdown) + , _nDataPoints(NumShownDataPointsInfo, 0) + , _fading(dictionary) + , _colorSettings(dictionary) + , _sizeSettings(dictionary) +{ + const Parameters p = codegen::bake(dictionary); + + addProperty(Fadeable::_opacity); + + if (p.file.has_value()) { + _hasDataFile = true; + _dataFile = absPath(*p.file).string(); + } + + if (p.dataMapping.has_value()) { + _dataMapping = dataloader::DataMapping::createFromDictionary(*p.dataMapping); + } + + _drawElements = p.drawElements.value_or(_drawElements); + addProperty(_drawElements); + + _renderOption.addOption(RenderOption::ViewDirection, "Camera View Direction"); + _renderOption.addOption(RenderOption::PositionNormal, "Camera Position Normal"); + + if (p.renderOption.has_value()) { + _renderOption = codegen::map(*p.renderOption); + } + else { + _renderOption = RenderOption::ViewDirection; + } + addProperty(_renderOption); + + _useAdditiveBlending = p.useAdditiveBlending.value_or(_useAdditiveBlending); + addProperty(_useAdditiveBlending); + + if (p.unit.has_value()) { + _unit = codegen::map(*p.unit); + } + else { + _unit = DistanceUnit::Meter; + } + + _spriteTexturePath.onChange([this]() { _spriteTextureIsDirty = true; }); + addProperty(_spriteTexturePath); + + _useSpriteTexture = p.useTexture.value_or(_useSpriteTexture); + addProperty(_useSpriteTexture); + + if (p.texture.has_value()) { + _spriteTexturePath = absPath(*p.texture).string(); + } + + _hasSpriteTexture = p.texture.has_value(); + + if (p.labels.has_value()) { + _labels = std::make_unique(*p.labels); + _hasLabels = true; + addPropertySubOwner(_labels.get()); + // Fading of the labels should also depend on the fading of the renderable + _labels->setParentFadeable(this); + } + + _transformationMatrix = p.transformationMatrix.value_or(_transformationMatrix); + + if (p.sizeSettings.has_value() && p.sizeSettings->sizeMapping.has_value()) { + _sizeSettings.sizeMapping.parameterOption.onChange( + [this]() { _dataIsDirty = true; } + ); + _hasDatavarSize = true; + } + + addPropertySubOwner(_sizeSettings); + addPropertySubOwner(_colorSettings); + + if (p.fading.has_value()) { + addPropertySubOwner(_fading); + } + + if (p.coloring.has_value() && (*p.coloring).colorMapping.has_value()) { + _hasColorMapFile = true; + + _colorSettings.colorMapping->dataColumn.onChange( + [this]() { _dataIsDirty = true; } + ); + + _colorSettings.colorMapping->setRangeFromData.onChange([this]() { + int parameterIndex = currentColorParameterIndex(); + _colorSettings.colorMapping->valueRange = _dataset.findValueRange( + parameterIndex + ); + }); + } + + if (_hasDataFile) { + bool useCaching = p.useCaching.value_or(true); + if (useCaching) { + _dataset = dataloader::data::loadFileWithCache(_dataFile, _dataMapping); + } + else { + _dataset = dataloader::data::loadFile(_dataFile, _dataMapping); + } + _nDataPoints = static_cast(_dataset.entries.size()); + } + + // If no scale exponent was specified, compute one that will at least show the points + // based on the scale of the positions in the dataset + if (!p.sizeSettings.has_value() || !p.sizeSettings->scaleExponent.has_value()) { + double dist = _dataset.maxPositionComponent * toMeter(_unit); + float exponent = static_cast(std::log10(dist)); + // Reduce the actually used exponent a little bit, as just using the logarithm + // as is leads to very large points + _sizeSettings.scaleExponent = 0.9f * exponent; + } + + _nDataPoints.setReadOnly(true); + addProperty(_nDataPoints); +} + +bool RenderablePointCloud::isReady() const { + bool isReady = _program && !_dataset.entries.empty(); + + // If we have labels, they also need to be loaded + if (_hasLabels) { + isReady = isReady && _labels->isReady(); + } + return isReady; +} + +void RenderablePointCloud::initialize() { + ZoneScoped; + + if (_hasDataFile && _hasColorMapFile) { + _colorSettings.colorMapping->initialize(_dataset); + } + + if (_hasLabels) { + _labels->initialize(); + _labels->loadLabels(); + } +} + +void RenderablePointCloud::initializeGL() { + ZoneScoped; + + _program = BaseModule::ProgramObjectManager.request( + "RenderablePointCloud", + []() { + return global::renderEngine->buildRenderProgram( + "RenderablePointCloud", + absPath("${MODULE_BASE}/shaders/billboardpoint_vs.glsl"), + absPath("${MODULE_BASE}/shaders/billboardpoint_fs.glsl"), + absPath("${MODULE_BASE}/shaders/billboardpoint_gs.glsl") + ); + } + ); + + ghoul::opengl::updateUniformLocations(*_program, _uniformCache, UniformNames); + + if (_hasColorMapFile) { + _colorSettings.colorMapping->initializeTexture(); + } +} + +void RenderablePointCloud::deinitializeGL() { + glDeleteBuffers(1, &_vbo); + _vbo = 0; + glDeleteVertexArrays(1, &_vao); + _vao = 0; + + BaseModule::ProgramObjectManager.release( + "RenderablePointCloud", + [](ghoul::opengl::ProgramObject* p) { + global::renderEngine->removeRenderProgram(p); + } + ); + _program = nullptr; + + BaseModule::TextureManager.release(_spriteTexture); + _spriteTexture = nullptr; +} + +void RenderablePointCloud::bindTextureForRendering() const { + if (_spriteTexture) { + _spriteTexture->bind(); + } +} + +float RenderablePointCloud::computeDistanceFadeValue(const RenderData& data) const { + if (!_fading.enabled) { + return 1.f; + } + + float fadeValue = 1.f; + glm::dmat4 invModelMatrix = glm::inverse(calcModelTransform(data)); + + glm::dvec3 cameraPosModelSpace = glm::dvec3( + invModelMatrix * glm::dvec4(data.camera.positionVec3(), 1.0) + ); + + float distCamera = static_cast( + glm::length(cameraPosModelSpace) / toMeter(_unit) + ); + + const glm::vec2 fadeRange = _fading.fadeInDistances; + const float fadeRangeWidth = (fadeRange.y - fadeRange.x); + float funcValue = (distCamera - fadeRange.x) / fadeRangeWidth; + funcValue = glm::clamp(funcValue, 0.f, 1.f); + + if (_fading.invert) { + funcValue = 1.f - funcValue; + } + + return fadeValue * funcValue; +} + +void RenderablePointCloud::renderBillboards(const RenderData& data, + const glm::dmat4& modelMatrix, + const glm::dvec3& orthoRight, + const glm::dvec3& orthoUp, + float fadeInVariable) +{ + glEnablei(GL_BLEND, 0); + + if (_useAdditiveBlending) { + glDepthMask(false); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + } + else { + // Normal blending, with transparency + glDepthMask(true); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + _program->activate(); + + _program->setUniform( + "screenSize", + glm::vec2(global::renderEngine->renderingResolution()) + ); + + _program->setUniform(_uniformCache.cameraPos, data.camera.positionVec3()); + _program->setUniform( + _uniformCache.cameraLookup, + glm::vec3(data.camera.lookUpVectorWorldSpace()) + ); + _program->setUniform(_uniformCache.renderOption, _renderOption.value()); + _program->setUniform(_uniformCache.modelMatrix, modelMatrix); + _program->setUniform( + _uniformCache.cameraViewProjectionMatrix, + glm::dmat4(data.camera.projectionMatrix()) * data.camera.combinedViewMatrix() + ); + + _program->setUniform(_uniformCache.up, glm::vec3(orthoUp)); + _program->setUniform(_uniformCache.right, glm::vec3(orthoRight)); + _program->setUniform(_uniformCache.fadeInValue, fadeInVariable); + _program->setUniform(_uniformCache.opacity, opacity()); + + _program->setUniform(_uniformCache.scaleExponent, _sizeSettings.scaleExponent); + _program->setUniform(_uniformCache.scaleFactor, _sizeSettings.scaleFactor); + _program->setUniform(_uniformCache.enablePixelSizeControl, _sizeSettings.pixelSizeControl); + _program->setUniform(_uniformCache.maxBillboardSize, _sizeSettings.maxPixelSize); + _program->setUniform(_uniformCache.hasDvarScaling, _sizeSettings.sizeMapping.enabled); + + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + _program->setUniform(_uniformCache.screenSize, glm::vec2(viewport[2], viewport[3])); + + bool useTexture = _hasSpriteTexture && _useSpriteTexture; + _program->setUniform(_uniformCache.hasSpriteTexture, useTexture); + + ghoul::opengl::TextureUnit spriteTextureUnit; + _program->setUniform(_uniformCache.spriteTexture, spriteTextureUnit); + if (useTexture) { + spriteTextureUnit.activate(); + bindTextureForRendering(); + } + + _program->setUniform(_uniformCache.color, _colorSettings.pointColor); + + bool useColorMap = _hasColorMapFile && _colorSettings.colorMapping->enabled && + _colorSettings.colorMapping->texture(); + + _program->setUniform(_uniformCache.useColormap, useColorMap); + + ghoul::opengl::TextureUnit colorMapTextureUnit; + _program->setUniform(_uniformCache.colorMapTexture, colorMapTextureUnit); + + if (useColorMap) { + colorMapTextureUnit.activate(); + _colorSettings.colorMapping->texture()->bind(); + + const glm::vec2 range = _colorSettings.colorMapping->valueRange; + _program->setUniform(_uniformCache.cmapRangeMin, range.x); + _program->setUniform(_uniformCache.cmapRangeMax, range.y); + _program->setUniform( + _uniformCache.hideOutsideRange, + _colorSettings.colorMapping->hideOutsideRange + ); + + _program->setUniform( + _uniformCache.nanColor, + _colorSettings.colorMapping->nanColor + ); + _program->setUniform( + _uniformCache.useNanColor, + _colorSettings.colorMapping->useNanColor + ); + + _program->setUniform( + _uniformCache.aboveRangeColor, + _colorSettings.colorMapping->aboveRangeColor + ); + _program->setUniform( + _uniformCache.useAboveRangeColor, + _colorSettings.colorMapping->useAboveRangeColor + ); + + _program->setUniform( + _uniformCache.belowRangeColor, + _colorSettings.colorMapping->belowRangeColor + ); + _program->setUniform( + _uniformCache.useBelowRangeColor, + _colorSettings.colorMapping->useBelowRangeColor + ); + } + + glBindVertexArray(_vao); + glDrawArrays(GL_POINTS, 0, static_cast(_dataset.entries.size())); + glBindVertexArray(0); + _program->deactivate(); + + global::renderEngine->openglStateCache().resetBlendState(); + global::renderEngine->openglStateCache().resetDepthState(); +} + +void RenderablePointCloud::render(const RenderData& data, RendererTasks&) { + float fadeInVar = computeDistanceFadeValue(data); + + if (fadeInVar < 0.01f) { + return; + } + + glm::dmat4 modelMatrix = calcModelTransform(data); + glm::dmat4 modelViewProjectionMatrix = + calcModelViewProjectionTransform(data, modelMatrix); + + glm::dvec3 cameraViewDirectionWorld = -data.camera.viewDirectionWorldSpace(); + glm::dvec3 cameraUpDirectionWorld = data.camera.lookUpVectorWorldSpace(); + glm::dvec3 orthoRight = glm::normalize( + glm::cross(cameraUpDirectionWorld, cameraViewDirectionWorld) + ); + if (orthoRight == glm::dvec3(0.0)) { + glm::dvec3 otherVector = glm::vec3( + cameraUpDirectionWorld.y, + cameraUpDirectionWorld.x, + cameraUpDirectionWorld.z + ); + orthoRight = glm::normalize(glm::cross(otherVector, cameraViewDirectionWorld)); + } + glm::dvec3 orthoUp = glm::normalize(glm::cross(cameraViewDirectionWorld, orthoRight)); + + if (_hasDataFile && _drawElements) { + renderBillboards(data, modelMatrix, orthoRight, orthoUp, fadeInVar); + } + + if (_hasLabels) { + _labels->render(data, modelViewProjectionMatrix, orthoRight, orthoUp, fadeInVar); + } +} + +void RenderablePointCloud::update(const UpdateData&) { + ZoneScoped; + + if (_dataIsDirty) { + updateBufferData(); + } + + if (_spriteTextureIsDirty) { + updateSpriteTexture(); + } +} + +int RenderablePointCloud::nAttributesPerPoint() const { + int n = 4; // position + n += _hasColorMapFile ? 1 : 0; + n += _hasDatavarSize ? 1 : 0; + return n; +} + +void RenderablePointCloud::updateBufferData() { + if (!_hasDataFile) { + return; + } + + ZoneScopedN("Data dirty"); + TracyGpuZone("Data dirty"); + LDEBUG("Regenerating data"); + + std::vector slice = createDataSlice(); + + int size = static_cast(slice.size()); + + if (_vao == 0) { + glGenVertexArrays(1, &_vao); + LDEBUG(fmt::format("Generating Vertex Array id '{}'", _vao)); + } + if (_vbo == 0) { + glGenBuffers(1, &_vbo); + LDEBUG(fmt::format("Generating Vertex Buffer Object id '{}'", _vbo)); + } + + glBindVertexArray(_vao); + glBindBuffer(GL_ARRAY_BUFFER, _vbo); + glBufferData(GL_ARRAY_BUFFER, size * sizeof(float), slice.data(), GL_STATIC_DRAW); + + const int attibutesPerPoint = nAttributesPerPoint(); + int attributeOffset = 0; + + GLint positionAttrib = _program->attributeLocation("in_position"); + glEnableVertexAttribArray(positionAttrib); + glVertexAttribPointer( + positionAttrib, + 4, + GL_FLOAT, + GL_FALSE, + attibutesPerPoint * sizeof(float), + nullptr + ); + attributeOffset += 4; + + if (_hasColorMapFile) { + GLint colorParamAttrib = _program->attributeLocation("in_colorParameter"); + glEnableVertexAttribArray(colorParamAttrib); + glVertexAttribPointer( + colorParamAttrib, + 1, + GL_FLOAT, + GL_FALSE, + attibutesPerPoint * sizeof(float), + reinterpret_cast(attributeOffset * sizeof(float)) + ); + attributeOffset += 1; + } + + if (_hasDatavarSize) { + GLint scalingAttrib = _program->attributeLocation("in_scalingParameter"); + glEnableVertexAttribArray(scalingAttrib); + glVertexAttribPointer( + scalingAttrib, + 1, + GL_FLOAT, + GL_FALSE, + attibutesPerPoint * sizeof(float), + reinterpret_cast(attributeOffset * sizeof(float)) + ); + attributeOffset += 1; + } + + glBindVertexArray(0); + + _dataIsDirty = false; +} + +void RenderablePointCloud::updateSpriteTexture() { + bool shouldUpdate = _hasSpriteTexture && _spriteTextureIsDirty && + !_spriteTexturePath.value().empty(); + + if (!shouldUpdate) { + return; + } + + ZoneScopedN("Sprite texture"); + TracyGpuZone("Sprite texture"); + + ghoul::opengl::Texture* texture = _spriteTexture; + + unsigned int hash = ghoul::hashCRC32File(_spriteTexturePath); + + _spriteTexture = BaseModule::TextureManager.request( + std::to_string(hash), + [path = _spriteTexturePath]() -> std::unique_ptr { + std::filesystem::path p = absPath(path); + LINFO(fmt::format("Loaded texture from {}", p)); + std::unique_ptr t = + ghoul::io::TextureReader::ref().loadTexture(p.string(), 2); + t->uploadTexture(); + t->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + t->purgeFromRAM(); + return t; + } + ); + + BaseModule::TextureManager.release(texture); + _spriteTextureIsDirty = false; +} + +int RenderablePointCloud::currentColorParameterIndex() const { + const properties::OptionProperty& property = + _colorSettings.colorMapping->dataColumn; + + if (!_hasColorMapFile || property.options().empty()) { + return 0; + } + + return _dataset.index(property.option().description); +} + +int RenderablePointCloud::currentSizeParameterIndex() const { + const properties::OptionProperty& property = + _sizeSettings.sizeMapping.parameterOption; + + if (!_hasDatavarSize || property.options().empty()) { + return 0; + } + + return _dataset.index(property.option().description); +} + +std::vector RenderablePointCloud::createDataSlice() { + ZoneScoped; + + if (_dataset.entries.empty()) { + return std::vector(); + } + + std::vector result; + result.reserve(nAttributesPerPoint() * _dataset.entries.size()); + + // What datavar is in use for the index color + int colorParamIndex = currentColorParameterIndex(); + + // What datavar is in use for the size scaling (if present) + int sizeParamIndex = currentSizeParameterIndex(); + + double maxRadius = 0.0; + double biggestCoord = -1.0; + + for (const dataloader::Dataset::Entry& e : _dataset.entries) { + const double unitMeter = toMeter(_unit); + glm::dvec4 position = glm::dvec4(glm::dvec3(e.position) * unitMeter, 1.0); + position = _transformationMatrix * position; + + const double r = glm::length(position); + maxRadius = std::max(maxRadius, r); + + // Positions + for (int j = 0; j < 4; ++j) { + result.push_back(static_cast(position[j])); + } + + // Colors + if (_hasColorMapFile) { + biggestCoord = std::max(biggestCoord, glm::compMax(position)); + result.push_back(e.data[colorParamIndex]); + } + + // Size data + if (_hasDatavarSize) { + // @TODO: Consider more detailed control over the scaling. Currently the value + // is multiplied with the value as is. Should have similar mapping properties + // as the color mapping + result.push_back(e.data[sizeParamIndex]); + } + } + setBoundingSphere(maxRadius); + return result; +} + +} // namespace openspace diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.h b/modules/base/rendering/pointcloud/renderablepointcloud.h similarity index 58% rename from modules/digitaluniverse/rendering/renderablebillboardscloud.h rename to modules/base/rendering/pointcloud/renderablepointcloud.h index 93701b6aea..0cfcbed715 100644 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.h +++ b/modules/base/rendering/pointcloud/renderablepointcloud.h @@ -22,27 +22,27 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __OPENSPACE_MODULE_DIGITALUNIVERSE___RENDERABLEBILLBOARDSCLOUD___H__ -#define __OPENSPACE_MODULE_DIGITALUNIVERSE___RENDERABLEBILLBOARDSCLOUD___H__ +#ifndef __OPENSPACE_MODULE_BASE___RENDERABLEPOINTCLOUD___H__ +#define __OPENSPACE_MODULE_BASE___RENDERABLEPOINTCLOUD___H__ #include -#include #include #include #include #include #include +#include #include #include #include +#include +#include #include #include #include #include -#include -namespace ghoul::filesystem { class File; } namespace ghoul::opengl { class ProgramObject; class Texture; @@ -52,10 +52,15 @@ namespace openspace { namespace documentation { struct Documentation; } -class RenderableBillboardsCloud : public Renderable { +/** + * This class describes a point cloud renderable that can be used to draw billboraded + * points based on a data file with 3D positions. Alternatively the points can also + * be colored and sized based on a separate column in the data file. + */ +class RenderablePointCloud : public Renderable { public: - explicit RenderableBillboardsCloud(const ghoul::Dictionary& dictionary); - ~RenderableBillboardsCloud() override = default; + explicit RenderablePointCloud(const ghoul::Dictionary& dictionary); + ~RenderablePointCloud() override = default; void initialize() override; void initializeGL() override; @@ -68,88 +73,104 @@ public: static documentation::Documentation Documentation(); -private: +protected: + int nAttributesPerPoint() const; + void updateBufferData(); + void updateSpriteTexture(); + + /// Find the index of the currently chosen color parameter in the dataset + int currentColorParameterIndex() const; + /// Find the index of the currently chosen size parameter in the dataset + int currentSizeParameterIndex() const; + std::vector createDataSlice(); - void createPolygonTexture(); - void renderToTexture(GLuint textureToRenderTo, GLuint textureWidth, - GLuint textureHeight); - void loadPolygonGeometryForRendering(); - void renderPolygonGeometry(GLuint vao); + + virtual void bindTextureForRendering() const; + + float computeDistanceFadeValue(const RenderData& data) const; + void renderBillboards(const RenderData& data, const glm::dmat4& modelMatrix, const glm::dvec3& orthoRight, const glm::dvec3& orthoUp, float fadeInVariable); - bool _hasSpeckFile = false; bool _dataIsDirty = true; - bool _hasSpriteTexture = false; bool _spriteTextureIsDirty = true; + + bool _hasSpriteTexture = false; + bool _hasDataFile = false; bool _hasColorMapFile = false; - bool _isColorMapExact = false; bool _hasDatavarSize = false; - bool _hasPolygon = false; bool _hasLabels = false; - int _polygonSides = 0; + struct SizeSettings : properties::PropertyOwner { + explicit SizeSettings(const ghoul::Dictionary& dictionary); - GLuint _pTexture = 0; + struct SizeMapping : properties::PropertyOwner { + SizeMapping(); + properties::BoolProperty enabled; + properties::OptionProperty parameterOption; + }; + SizeMapping sizeMapping; - properties::FloatProperty _scaleFactor; - properties::BoolProperty _useColorMap; - properties::Vec3Property _pointColor; + properties::FloatProperty scaleExponent; + properties::FloatProperty scaleFactor; + + properties::BoolProperty pixelSizeControl; + properties::FloatProperty maxPixelSize; + }; + SizeSettings _sizeSettings; + + struct ColorSettings : properties::PropertyOwner { + explicit ColorSettings(const ghoul::Dictionary& dictionary); + properties::Vec3Property pointColor; + std::unique_ptr colorMapping; + }; + ColorSettings _colorSettings; + + struct Fading : properties::PropertyOwner { + explicit Fading(const ghoul::Dictionary& dictionary); + properties::Vec2Property fadeInDistances; + properties::BoolProperty enabled; + properties::BoolProperty invert; + }; + Fading _fading; + + properties::BoolProperty _useSpriteTexture; properties::StringProperty _spriteTexturePath; + + properties::BoolProperty _useAdditiveBlending; + properties::BoolProperty _drawElements; - properties::BoolProperty _pixelSizeControl; - properties::OptionProperty _colorOption; - properties::Vec2Property _optionColorRangeData; - properties::OptionProperty _datavarSizeOption; - properties::Vec2Property _fadeInDistances; - properties::BoolProperty _disableFadeInDistance; - properties::Vec2Property _billboardMinMaxSize; - properties::FloatProperty _correctionSizeEndDistance; - properties::FloatProperty _correctionSizeFactor; - properties::BoolProperty _useLinearFiltering; - properties::TriggerProperty _setRangeFromData; properties::OptionProperty _renderOption; - ghoul::opengl::Texture* _polygonTexture = nullptr; + properties::UIntProperty _nDataPoints; + ghoul::opengl::Texture* _spriteTexture = nullptr; ghoul::opengl::ProgramObject* _program = nullptr; - ghoul::opengl::ProgramObject* _renderToPolygonProgram = nullptr; UniformCache( cameraViewProjectionMatrix, modelMatrix, cameraPos, cameraLookup, renderOption, - minBillboardSize, maxBillboardSize, correctionSizeEndDistance, - correctionSizeFactor, color, alphaValue, scaleFactor, up, right, fadeInValue, - screenSize, spriteTexture, hasColormap, useColormap, enabledRectSizeControl, - hasDvarScaling + maxBillboardSize, color, opacity, scaleExponent, scaleFactor, up, right, + fadeInValue, screenSize, hasSpriteTexture, spriteTexture, useColormap, + colorMapTexture, cmapRangeMin, cmapRangeMax, nanColor, useNanColor, + hideOutsideRange, enablePixelSizeControl, aboveRangeColor, useAboveRangeColor, + belowRangeColor, useBelowRangeColor, hasDvarScaling ) _uniformCache; - std::string _speckFile; - std::string _colorMapFile; - std::string _colorOptionString; - std::string _datavarSizeOptionString; + std::string _dataFile; DistanceUnit _unit = DistanceUnit::Parsec; - speck::Dataset _dataset; - speck::ColorMap _colorMap; + dataloader::Dataset _dataset; + dataloader::DataMapping _dataMapping; - // Everything related to the labels is handled by LabelsComponent std::unique_ptr _labels; - std::vector _colorRangeData; - std::unordered_map _optionConversionMap; - std::unordered_map _optionConversionSizeMap; - glm::dmat4 _transformationMatrix = glm::dmat4(1.0); GLuint _vao = 0; GLuint _vbo = 0; - - // For polygons - GLuint _polygonVao = 0; - GLuint _polygonVbo = 0; }; } // namespace openspace -#endif // __OPENSPACE_MODULE_DIGITALUNIVERSE___RENDERABLEBILLBOARDSCLOUD___H__ +#endif // __OPENSPACE_MODULE_BASE___RENDERABLEPOINTCLOUD___H__ diff --git a/modules/base/rendering/pointcloud/renderablepolygoncloud.cpp b/modules/base/rendering/pointcloud/renderablepolygoncloud.cpp new file mode 100644 index 0000000000..672586f435 --- /dev/null +++ b/modules/base/rendering/pointcloud/renderablepolygoncloud.cpp @@ -0,0 +1,193 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2023 * + * * + * 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. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace { + constexpr std::string_view _loggerCat = "RenderablePolygonCloud"; + + // A RenderablePolygonCloud is a RenderablePointCloud where the shape of the points + // is a uniform polygon with a given number of sides instead of a texture. For + // instance, PolygonSides = 5 results in the points being rendered as pentagons. + // Note that while this renderable inherits the texture property from + // RenderablePointCloud, any added texture value will be ignored in favor of the + // polygon shape. + // + // See documentation of RenderablePointCloud for details on the other parts of the + // point cloud rendering. + struct [[codegen::Dictionary(RenderablePolygonCloud)]] Parameters { + // The number of sides for the polygon used to represent each point. Default is + // 3, i.e. to use triangles + std::optional polygonSides [[codegen::greaterequal(3)]]; + }; + +#include "renderablepolygoncloud_codegen.cpp" +} // namespace + +namespace openspace { + +documentation::Documentation RenderablePolygonCloud::Documentation() { + return codegen::doc( + "base_renderablepolygoncloud", + RenderablePointCloud::Documentation() + ); +} + +RenderablePolygonCloud::RenderablePolygonCloud(const ghoul::Dictionary& dictionary) + : RenderablePointCloud(dictionary) +{ + const Parameters p = codegen::bake(dictionary); + + _nPolygonSides = p.polygonSides.value_or(_nPolygonSides); + + // The texture to use for the rendering will be generated in initializeGl. Make sure + // we use it in the rnedering + _hasSpriteTexture = true; +} + +void RenderablePolygonCloud::initializeGL() { + ZoneScoped; + + RenderablePointCloud::initializeGL(); + createPolygonTexture(); +} + +void RenderablePolygonCloud::deinitializeGL() { + glDeleteBuffers(1, &_polygonVbo); + _polygonVbo = 0; + glDeleteVertexArrays(1, &_polygonVao); + _polygonVao = 0; + + glDeleteTextures(1, &_pTexture); + + RenderablePointCloud::deinitializeGL(); +} + +void RenderablePolygonCloud::bindTextureForRendering() const { + glBindTexture(GL_TEXTURE_2D, _pTexture); +} + +void RenderablePolygonCloud::createPolygonTexture() { + ZoneScoped; + + LDEBUG("Creating Polygon Texture"); + constexpr gl::GLsizei TexSize = 512; + + glGenTextures(1, &_pTexture); + glBindTexture(GL_TEXTURE_2D, _pTexture); + 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); + // Stopped using a buffer object for GL_PIXEL_UNPACK_BUFFER + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, TexSize, TexSize, 0, GL_RGBA, GL_BYTE, nullptr); + + renderToTexture(_pTexture, TexSize, TexSize); +} + +void RenderablePolygonCloud::renderToTexture(GLuint textureToRenderTo, + GLuint textureWidth, GLuint textureHeight) +{ + LDEBUG("Rendering to Texture"); + + // Saves initial Application's OpenGL State + GLint defaultFBO; + GLint viewport[4]; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); + glGetIntegerv(GL_VIEWPORT, viewport); + + GLuint textureFBO; + glGenFramebuffers(1, &textureFBO); + glBindFramebuffer(GL_FRAMEBUFFER, textureFBO); + GLenum drawBuffers[1] = { GL_COLOR_ATTACHMENT0 }; + glDrawBuffers(1, drawBuffers); + + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureToRenderTo, 0); + + glViewport(viewport[0], viewport[1], textureWidth, textureHeight); + + if (_polygonVao == 0) { + glGenVertexArrays(1, &_polygonVao); + } + if (_polygonVbo == 0) { + glGenBuffers(1, &_polygonVbo); + } + + glBindVertexArray(_polygonVao); + glBindBuffer(GL_ARRAY_BUFFER, _polygonVbo); + + constexpr std::array VertexData = { + // x y z w + 0.f, 0.f, 0.f, 1.f, + }; + + glBufferData(GL_ARRAY_BUFFER, sizeof(VertexData), VertexData.data(), GL_STATIC_DRAW); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), nullptr); + glEnableVertexAttribArray(0); + glBindVertexArray(0); + + renderPolygonGeometry(_polygonVao); + + // Restores Applications' OpenGL State + glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + + glDeleteBuffers(1, &_polygonVbo); + glDeleteVertexArrays(1, &_polygonVao); + glDeleteFramebuffers(1, &textureFBO); +} + +void RenderablePolygonCloud::renderPolygonGeometry(GLuint vao) { + std::unique_ptr program = + ghoul::opengl::ProgramObject::Build( + "RenderablePointCloud_Polygon", + absPath("${MODULE_BASE}/shaders/polygon_vs.glsl"), + absPath("${MODULE_BASE}/shaders/polygon_fs.glsl"), + absPath("${MODULE_BASE}/shaders/polygon_gs.glsl") + ); + + program->activate(); + constexpr glm::vec4 Black = glm::vec4(0.f, 0.f, 0.f, 0.f); + glClearBufferfv(GL_COLOR, 0, glm::value_ptr(Black)); + + program->setUniform("sides", _nPolygonSides); + program->setUniform("polygonColor", _colorSettings.pointColor); + + glBindVertexArray(vao); + glDrawArrays(GL_POINTS, 0, 1); + glBindVertexArray(0); + + program->deactivate(); +} + +} // namespace openspace diff --git a/modules/base/rendering/pointcloud/renderablepolygoncloud.h b/modules/base/rendering/pointcloud/renderablepolygoncloud.h new file mode 100644 index 0000000000..f873636779 --- /dev/null +++ b/modules/base/rendering/pointcloud/renderablepolygoncloud.h @@ -0,0 +1,70 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2023 * + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_BASE___RENDERABLEPOLYGONCLOUD___H__ +#define __OPENSPACE_MODULE_BASE___RENDERABLEPOLYGONCLOUD___H__ + +#include + +#include + +namespace ghoul::opengl { class Texture; } + +namespace openspace { + +namespace documentation { struct Documentation; } + +/** + * A billboarded point cloud, but with dynamically created uniform polygon shapes instead + * of a custom texture. Overwrites the sprite set in parent class, RenderablePointCloud + */ +class RenderablePolygonCloud : public RenderablePointCloud { +public: + explicit RenderablePolygonCloud(const ghoul::Dictionary& dictionary); + ~RenderablePolygonCloud() override = default; + + void initializeGL() override; + void deinitializeGL() override; + + static documentation::Documentation Documentation(); + +private: + void createPolygonTexture(); + void renderToTexture(GLuint textureToRenderTo, GLuint textureWidth, + GLuint textureHeight); + void renderPolygonGeometry(GLuint vao); + + void bindTextureForRendering() const override; + + int _nPolygonSides = 3; + + GLuint _pTexture = 0; + + GLuint _polygonVao = 0; + GLuint _polygonVbo = 0; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_BASE___RENDERABLEPOLYGONCLOUD___H__ diff --git a/modules/digitaluniverse/shaders/billboard_fs.glsl b/modules/base/shaders/billboardpoint_fs.glsl similarity index 64% rename from modules/digitaluniverse/shaders/billboard_fs.glsl rename to modules/base/shaders/billboardpoint_fs.glsl index f6ce480f6a..b0dfaaeb6b 100644 --- a/modules/digitaluniverse/shaders/billboard_fs.glsl +++ b/modules/base/shaders/billboardpoint_fs.glsl @@ -24,45 +24,86 @@ #include "fragment.glsl" -flat in vec4 gs_colorMap; +flat in float gs_colorParameter; flat in float vs_screenSpaceDepth; in vec2 texCoord; -in float ta; -uniform float alphaValue; +uniform float opacity; uniform vec3 color; + +uniform vec4 nanColor = vec4(0.5); +uniform bool useNanColor = true; + +uniform vec4 aboveRangeColor; +uniform bool useAboveRangeColor; + +uniform vec4 belowRangeColor; +uniform bool useBelowRangeColor; + +uniform bool hasSpriteTexture; uniform sampler2D spriteTexture; -uniform bool hasColorMap; + uniform bool useColorMap; +uniform sampler1D colorMapTexture; +uniform float cmapRangeMin; +uniform float cmapRangeMax; +uniform bool hideOutsideRange; + uniform float fadeInValue; +vec4 sampleColorMap(float dataValue) { + if (useNanColor && isnan(dataValue)) { + return nanColor; + } + + bool isOutside = dataValue < cmapRangeMin || dataValue > cmapRangeMax; + if (isnan(dataValue) || (hideOutsideRange && isOutside)) { + discard; + } + + if (useBelowRangeColor && dataValue < cmapRangeMin) { + return belowRangeColor; + } + + if (useAboveRangeColor && dataValue > cmapRangeMax) { + return aboveRangeColor; + } + + float t = (dataValue - cmapRangeMin) / (cmapRangeMax - cmapRangeMin); + t = clamp(t, 0.0, 1.0); + return texture(colorMapTexture, t); +} Fragment getFragment() { - if (gs_colorMap.a == 0.0 || ta == 0.0 || fadeInValue == 0.0 || alphaValue == 0.0) { + if (fadeInValue == 0.0 || opacity == 0.0) { discard; } - vec4 textureColor = texture(spriteTexture, texCoord); - if (textureColor.a == 0.0) { - discard; + if (!hasSpriteTexture) { + // Moving the origin to the center + vec2 st = (texCoord - vec2(0.5)) * 2.0; + if (length(st) > 1.0) { + discard; + } } - vec4 fullColor = textureColor; + vec4 fullColor = vec4(1.0); + if (hasSpriteTexture) { + fullColor = texture(spriteTexture, texCoord); + } - if (hasColorMap && useColorMap) { - fullColor *= gs_colorMap; + if (useColorMap) { + fullColor *= sampleColorMap(gs_colorParameter); } else { fullColor.rgb *= color; } - float textureOpacity = dot(fullColor.rgb, vec3(1.0)); - if (textureOpacity == 0.0) { + fullColor.a *= opacity * fadeInValue; + if (fullColor.a < 0.01) { discard; } - fullColor.a *= alphaValue * fadeInValue * ta; - Fragment frag; frag.color = fullColor; frag.depth = vs_screenSpaceDepth; diff --git a/modules/digitaluniverse/shaders/billboard_gs.glsl b/modules/base/shaders/billboardpoint_gs.glsl similarity index 73% rename from modules/digitaluniverse/shaders/billboard_gs.glsl rename to modules/base/shaders/billboardpoint_gs.glsl index 0e5cfc658d..19db521a59 100644 --- a/modules/digitaluniverse/shaders/billboard_gs.glsl +++ b/modules/base/shaders/billboardpoint_gs.glsl @@ -27,21 +27,21 @@ #include "PowerScaling/powerScalingMath.hglsl" layout(points) in; -flat in vec4 colorMap[]; -flat in float dvarScaling[]; +flat in float colorParameter[]; +flat in float scalingParameter[]; layout(triangle_strip, max_vertices = 4) out; -flat out vec4 gs_colorMap; +flat out float gs_colorParameter; out vec2 texCoord; flat out float vs_screenSpaceDepth; -out float ta; // General settings +uniform float scaleExponent; uniform float scaleFactor; uniform int renderOption; uniform dmat4 cameraViewProjectionMatrix; uniform dmat4 modelMatrix; -uniform bool enabledRectSizeControl; +uniform bool enablePixelSizeControl; uniform bool hasDvarScaling; // RenderOption: CameraViewDirection @@ -51,15 +51,10 @@ uniform vec3 right; // RenderOption: CameraPositionNormal uniform dvec3 cameraPosition; uniform vec3 cameraLookUp; -uniform float correctionSizeFactor; -uniform float correctionSizeEndDistance; // Pixel size control: true uniform vec2 screenSize; uniform float maxBillboardSize; -uniform float minBillboardSize; - -const double PARSEC = 0.308567756e17LF; const vec2 corners[4] = vec2[4]( vec2(0.0, 0.0), @@ -71,30 +66,15 @@ const vec2 corners[4] = vec2[4]( const int RenderOptionCameraViewDirection = 0; const int RenderOptionCameraPositionNormal = 1; - void main() { - ta = 1.0; vec4 pos = gl_in[0].gl_Position; - gs_colorMap = colorMap[0]; + gs_colorParameter = colorParameter[0]; - double unit = PARSEC; + dvec4 dpos = modelMatrix * dvec4(dvec3(pos.xyz), 1.0); - // Must be the same as the enum in RenderableBillboardsCloud.h - if (pos.w == 1.0) { unit = 1E3; } - else if (pos.w == 2.0) { unit = PARSEC; } - else if (pos.w == 3.0) { unit = 1E3 * PARSEC; } - else if (pos.w == 4.0) { unit = 1E6 * PARSEC; } - else if (pos.w == 5.0) { unit = 1E9 * PARSEC; } - else if (pos.w == 6.0) { - // Conversion factor from Parsecs to GigalightYears - unit = 306391534.73091 * PARSEC; - } - - dvec4 dpos = modelMatrix * dvec4(dvec3(pos.xyz) * unit, 1.0); - - float scaleMultiply = exp(scaleFactor * 0.10); + float scaleMultiply = pow(10.0, scaleExponent); if (hasDvarScaling) { - scaleMultiply *= dvarScaling[0]; + scaleMultiply *= scalingParameter[0]; } vec3 scaledRight = vec3(0.0); @@ -109,18 +89,13 @@ void main() { vec3 newRight = normalize(cross(cameraLookUp, normal)); vec3 newUp = cross(normal, newRight); - if (!enabledRectSizeControl) { - double distCamera = length(cameraPosition - dpos.xyz); - float expVar = float(-distCamera) / pow(10.0, correctionSizeEndDistance); - float factorVar = pow(10.0, correctionSizeFactor); - scaleMultiply *= 1.0 / (1.0 + factorVar * exp(expVar)); - } - scaledRight = scaleMultiply * newRight * 0.5; scaledUp = scaleMultiply * newUp * 0.5; } - if (enabledRectSizeControl) { + // @TODO: Come up with some better solution for this scaling, that + // also work with non planar projections and multiple viewport resolutions. + if (enablePixelSizeControl) { vec4 initialPosition = z_normalization(vec4(cameraViewProjectionMatrix * dvec4(dpos.xyz - dvec3(scaledRight - scaledUp), dpos.w))); @@ -137,30 +112,21 @@ void main() { // width and height vec2 sizes = abs(halfViewSize * (topRight - bottomLeft)); - if (enabledRectSizeControl && (length(sizes) > maxBillboardSize)) { + if (length(sizes) > maxBillboardSize) { float correctionScale = maxBillboardSize / length(sizes); - scaledRight *= correctionScale; scaledUp *= correctionScale; } - else { - // linear alpha decay - if (sizes.x < 2.0 * minBillboardSize) { - float maxVar = 2.0 * minBillboardSize; - float minVar = minBillboardSize; - float var = sizes.y + sizes.x; - ta = (var - minVar) / (maxVar - minVar); - if (ta == 0.0) { - return; - } - } - } + + // TODO: add checks for wether the generated plane covers too many or too few pixels } // Saving one matrix multiplication: vec4 dposClip = vec4(cameraViewProjectionMatrix * dpos); - vec4 scaledRightClip = vec4(cameraViewProjectionMatrix * dvec4(scaledRight, 0.0)); - vec4 scaledUpClip = vec4(cameraViewProjectionMatrix * dvec4(scaledUp, 0.0)); + vec4 scaledRightClip = scaleFactor * + vec4(cameraViewProjectionMatrix * dvec4(scaledRight, 0.0)); + vec4 scaledUpClip = scaleFactor * + vec4(cameraViewProjectionMatrix * dvec4(scaledUp, 0.0)); vec4 initialPosition = z_normalization(dposClip - scaledRightClip - scaledUpClip); vs_screenSpaceDepth = initialPosition.w; diff --git a/modules/digitaluniverse/shaders/billboard_vs.glsl b/modules/base/shaders/billboardpoint_vs.glsl similarity index 91% rename from modules/digitaluniverse/shaders/billboard_vs.glsl rename to modules/base/shaders/billboardpoint_vs.glsl index b1f0510a4a..35e8082b41 100644 --- a/modules/digitaluniverse/shaders/billboard_vs.glsl +++ b/modules/base/shaders/billboardpoint_vs.glsl @@ -27,15 +27,14 @@ #include "PowerScaling/powerScaling_vs.hglsl" in vec4 in_position; -in vec4 in_colormap; -in float in_dvarScaling; - -flat out vec4 colorMap; -flat out float dvarScaling; +in float in_colorParameter; +in float in_scalingParameter; +flat out float colorParameter; +flat out float scalingParameter; void main() { - colorMap = in_colormap; - dvarScaling = in_dvarScaling; + colorParameter = in_colorParameter; + scalingParameter = in_scalingParameter; gl_Position = in_position; } diff --git a/modules/digitaluniverse/shaders/billboardpolygon_fs.glsl b/modules/base/shaders/polygon_fs.glsl similarity index 100% rename from modules/digitaluniverse/shaders/billboardpolygon_fs.glsl rename to modules/base/shaders/polygon_fs.glsl diff --git a/modules/digitaluniverse/shaders/billboardpolygon_gs.glsl b/modules/base/shaders/polygon_gs.glsl similarity index 100% rename from modules/digitaluniverse/shaders/billboardpolygon_gs.glsl rename to modules/base/shaders/polygon_gs.glsl diff --git a/modules/digitaluniverse/shaders/billboardpolygon_vs.glsl b/modules/base/shaders/polygon_vs.glsl similarity index 100% rename from modules/digitaluniverse/shaders/billboardpolygon_vs.glsl rename to modules/base/shaders/polygon_vs.glsl diff --git a/modules/digitaluniverse/CMakeLists.txt b/modules/digitaluniverse/CMakeLists.txt index 252b33d460..df3b0b2eeb 100644 --- a/modules/digitaluniverse/CMakeLists.txt +++ b/modules/digitaluniverse/CMakeLists.txt @@ -25,34 +25,22 @@ include(${PROJECT_SOURCE_DIR}/support/cmake/module_definition.cmake) set(HEADER_FILES - rendering/renderablepoints.h rendering/renderabledumeshes.h - rendering/renderablebillboardscloud.h rendering/renderableplanescloud.h ) source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES - rendering/renderablepoints.cpp rendering/renderabledumeshes.cpp - rendering/renderablebillboardscloud.cpp rendering/renderableplanescloud.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) set(SHADER_FILES - shaders/billboard_fs.glsl - shaders/billboard_gs.glsl - shaders/billboard_vs.glsl - shaders/billboardpolygon_fs.glsl - shaders/billboardpolygon_gs.glsl - shaders/billboardpolygon_vs.glsl shaders/dumesh_vs.glsl shaders/dumesh_fs.glsl shaders/plane_vs.glsl shaders/plane_fs.glsl - shaders/points_sprite_fs.glsl - shaders/points_vs.glsl ) source_group("Shader Files" FILES ${SHADER_FILES}) diff --git a/modules/digitaluniverse/digitaluniversemodule.cpp b/modules/digitaluniverse/digitaluniversemodule.cpp index b77708080b..92cb71ac1e 100644 --- a/modules/digitaluniverse/digitaluniversemodule.cpp +++ b/modules/digitaluniverse/digitaluniversemodule.cpp @@ -24,10 +24,8 @@ #include -#include #include #include -#include #include #include #include @@ -48,8 +46,6 @@ void DigitalUniverseModule::internalInitialize(const ghoul::Dictionary&) { FactoryManager::ref().factory(); ghoul_assert(fRenderable, "Renderable factory was not created"); - fRenderable->registerClass("RenderablePoints"); - fRenderable->registerClass("RenderableBillboardsCloud"); fRenderable->registerClass("RenderablePlanesCloud"); fRenderable->registerClass("RenderableDUMeshes"); } @@ -61,8 +57,6 @@ void DigitalUniverseModule::internalDeinitializeGL() { std::vector DigitalUniverseModule::documentations() const { return { - RenderablePoints::Documentation(), - RenderableBillboardsCloud::Documentation(), RenderablePlanesCloud::Documentation(), RenderableDUMeshes::Documentation() }; diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp deleted file mode 100644 index 3f04668c98..0000000000 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp +++ /dev/null @@ -1,1142 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2023 * - * * - * 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. * - ****************************************************************************************/ - -#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 - -namespace { - constexpr std::string_view _loggerCat = "RenderableBillboardsCloud"; - - constexpr std::array UniformNames = { - "cameraViewProjectionMatrix", "modelMatrix", "cameraPosition", "cameraLookUp", - "renderOption", "minBillboardSize", "maxBillboardSize", - "correctionSizeEndDistance", "correctionSizeFactor", "color", "alphaValue", - "scaleFactor", "up", "right", "fadeInValue", "screenSize", "spriteTexture", - "hasColorMap", "useColorMap", "enabledRectSizeControl", "hasDvarScaling" - }; - - enum RenderOption { - ViewDirection = 0, - PositionNormal - }; - - constexpr openspace::properties::Property::PropertyInfo SpriteTextureInfo = { - "Texture", - "Point Sprite Texture", - "The path to the texture that should be used as the point sprite", - openspace::properties::Property::Visibility::AdvancedUser - }; - - constexpr openspace::properties::Property::PropertyInfo ScaleFactorInfo = { - "ScaleFactor", - "Scale Factor", - "This value is used as a multiplicative factor that is applied to the apparent " - "size of each point", - // @VISIBILITY(2.5) - openspace::properties::Property::Visibility::User - }; - - constexpr openspace::properties::Property::PropertyInfo UseColorMapInfo = { - "UseColorMap", - "Use Color Map", - "If this value is set to 'true', the provided color map is used (if one was " - "provided in the configuration). If no color map was provided, changing this " - "setting does not do anything", - // @VISIBILITY(2.75) - openspace::properties::Property::Visibility::User - }; - - constexpr openspace::properties::Property::PropertyInfo ColorInfo = { - "Color", - "Color", - "This value is used to define the color of the astronomical object", - // @VISIBILITY(1.5) - openspace::properties::Property::Visibility::NoviceUser - }; - - constexpr openspace::properties::Property::PropertyInfo ColorMapInfo = { - "ColorMap", - "Color Map File", - "The path to the color map file of the astronomical object", - openspace::properties::Property::Visibility::AdvancedUser - }; - - constexpr openspace::properties::Property::PropertyInfo DrawElementsInfo = { - "DrawElements", - "Draw Elements", - "Enables/Disables the drawing of the astronomical objects", - // @VISIBILITY(1.25) - openspace::properties::Property::Visibility::NoviceUser - }; - - static const openspace::properties::PropertyOwner::PropertyOwnerInfo LabelsInfo = { - "Labels", - "Labels", - "The labels for the astronomical objects" - }; - - constexpr openspace::properties::Property::PropertyInfo ColorOptionInfo = { - "ColorOption", - "Color Option", - "This value determines which paramenter is used for default color of the " - "astronomical objects", - openspace::properties::Property::Visibility::AdvancedUser - }; - - constexpr openspace::properties::Property::PropertyInfo OptionColorRangeInfo = { - "OptionColorRange", - "Option Color Range", - "This value changes the range of values to be mapped with the current color map", - openspace::properties::Property::Visibility::AdvancedUser - }; - - constexpr openspace::properties::Property::PropertyInfo SizeOptionInfo = { - "SizeOption", - "Size Option Variable", - "This value determines which paramenter (datavar) is used for scaling of the " - "astronomical objects", - openspace::properties::Property::Visibility::AdvancedUser - }; - - constexpr openspace::properties::Property::PropertyInfo RenderOptionInfo = { - "RenderOption", - "Render Option", - "Option wether the billboards should face the camera or not. Used for non-linear " - "display environments such as fisheye.", - openspace::properties::Property::Visibility::AdvancedUser - }; - - constexpr openspace::properties::Property::PropertyInfo FadeInDistancesInfo = { - "FadeInDistances", - "Fade-In Start and End Distances", - "These values determine the initial and final distances from the center of " - "our galaxy from which the astronomical object will start and end " - "fading-in", - // @VISIBILITY(3.25) - openspace::properties::Property::Visibility::AdvancedUser - }; - - constexpr openspace::properties::Property::PropertyInfo DisableFadeInInfo = { - "DisableFadeIn", - "Disable Fade-in Effect", - "Enables/Disables the Fade-in effect", - openspace::properties::Property::Visibility::User - }; - - constexpr openspace::properties::Property::PropertyInfo PixelSizeControlInfo = { - "EnablePixelSizeControl", - "Enable Pixel Size Control", - "Enable pixel size control for rectangular projections. If set to true, the " - "billboard size is restricted by the min/max size in pixels property", - openspace::properties::Property::Visibility::AdvancedUser - }; - - constexpr openspace::properties::Property::PropertyInfo BillboardMinMaxSizeInfo = { - "BillboardMinMaxSize", - "Billboard Min/Max Size in Pixels", - "The minimum and maximum size (in pixels) for the billboard representing the " - "astronomical object", - openspace::properties::Property::Visibility::AdvancedUser - }; - - constexpr openspace::properties::Property::PropertyInfo - CorrectionSizeEndDistanceInfo = - { - "CorrectionSizeEndDistance", - "Distance in 10^X meters where correction size stops acting", - "Distance in 10^X meters where correction size stops acting", - openspace::properties::Property::Visibility::AdvancedUser - }; - - constexpr openspace::properties::Property::PropertyInfo CorrectionSizeFactorInfo = { - "CorrectionSizeFactor", - "Control variable for distance size", - "", - openspace::properties::Property::Visibility::AdvancedUser - }; - - constexpr openspace::properties::Property::PropertyInfo UseLinearFiltering = { - "UseLinearFiltering", - "Use Linear Filtering", - "Determines whether the provided color map should be sampled nearest neighbor " - "(=off) or linearly (=on)", - // @VISIBILITY(3.25) - openspace::properties::Property::Visibility::AdvancedUser - }; - - constexpr openspace::properties::Property::PropertyInfo SetRangeFromData = { - "SetRangeFromData", - "Set Data Range from Data", - "Set the data range based on the available data", - openspace::properties::Property::Visibility::AdvancedUser - }; - - struct [[codegen::Dictionary(RenderableBillboardsCloud)]] Parameters { - // The path to the SPECK file that contains information about the astronomical - // object being rendered - std::optional file; - - // [[codegen::verbatim(ColorInfo.description)]] - glm::vec3 color [[codegen::color()]]; - - // [[codegen::verbatim(SpriteTextureInfo.description)]] - std::optional texture; - - // [[codegen::verbatim(DrawElementsInfo.description)]] - std::optional drawElements; - - enum class [[codegen::map(RenderOption)]] RenderOption { - ViewDirection [[codegen::key("Camera View Direction")]], - PositionNormal [[codegen::key("Camera Position Normal")]] - }; - // [[codegen::verbatim(RenderOptionInfo.description)]] - std::optional renderOption; - - enum class [[codegen::map(openspace::DistanceUnit)]] Unit { - Meter [[codegen::key("m")]], - Kilometer [[codegen::key("Km")]], - Parsec [[codegen::key("pc")]], - Kiloparsec [[codegen::key("Kpc")]], - Megaparsec [[codegen::key("Mpc")]], - Gigaparsec [[codegen::key("Gpc")]], - Gigalightyear [[codegen::key("Gly")]] - }; - // The unit used for all distances. Must match the unit of any - // distances/positions in the data files - std::optional unit; - - // [[codegen::verbatim(ScaleFactorInfo.description)]] - std::optional scaleFactor; - - // [[codegen::verbatim(UseColorMapInfo.description)]] - std::optional useColorMap; - - // [[codegen::verbatim(ColorMapInfo.description)]] - std::optional colorMap; - - // Set a 1 to 1 relationship between the color index variable and the colormap - // entrered value - std::optional exactColorMap; - - // The number of sides for the polygon used to represent the astronomical object - std::optional polygonSides; - - // [[codegen::verbatim(LabelsInfo.description)]] - std::optional labels - [[codegen::reference("space_labelscomponent")]]; - - // [[codegen::verbatim(ColorOptionInfo.description)]] - std::optional> colorOption; - - // [[codegen::verbatim(SizeOptionInfo.description)]] - std::optional> sizeOption; - - // This value determines the colormap ranges for the color parameters of the - // astronomical objects - std::optional> colorRange; - - // Transformation matrix to be applied to each astronomical object - std::optional transformationMatrix; - - // [[codegen::verbatim(FadeInDistancesInfo.description)]] - std::optional fadeInDistances; - - // [[codegen::verbatim(DisableFadeInInfo.description)]] - std::optional disableFadeIn; - - // [[codegen::verbatim(BillboardMinMaxSizeInfo.description)]] - std::optional billboardMinMaxSize; - - // [[codegen::verbatim(CorrectionSizeEndDistanceInfo.description)]] - std::optional correctionSizeEndDistance; - - // [[codegen::verbatim(CorrectionSizeFactorInfo.description)]] - std::optional correctionSizeFactor; - - // [[codegen::verbatim(PixelSizeControlInfo.description)]] - std::optional enablePixelSizeControl; - - // [[codegen::verbatim(UseLinearFiltering.description)]] - std::optional useLinearFiltering; - }; -#include "renderablebillboardscloud_codegen.cpp" -} // namespace - -namespace openspace { - -documentation::Documentation RenderableBillboardsCloud::Documentation() { - return codegen::doc("digitaluniverse_RenderableBillboardsCloud"); -} - -RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& dictionary) - : Renderable(dictionary) - , _scaleFactor(ScaleFactorInfo, 1.f, 0.f, 600.f) - , _useColorMap(UseColorMapInfo, true) - , _pointColor(ColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f)) - , _spriteTexturePath(SpriteTextureInfo) - , _drawElements(DrawElementsInfo, true) - , _pixelSizeControl(PixelSizeControlInfo, false) - , _colorOption(ColorOptionInfo, properties::OptionProperty::DisplayType::Dropdown) - , _optionColorRangeData(OptionColorRangeInfo, glm::vec2(0.f)) - , _datavarSizeOption( - SizeOptionInfo, - properties::OptionProperty::DisplayType::Dropdown - ) - , _fadeInDistances( - FadeInDistancesInfo, - glm::vec2(0.f), - glm::vec2(0.f), - glm::vec2(100.f) - ) - , _disableFadeInDistance(DisableFadeInInfo, true) - , _billboardMinMaxSize( - BillboardMinMaxSizeInfo, - glm::vec2(0.f, 400.f), - glm::vec2(0.f), - glm::vec2(1000.f) - ) - , _correctionSizeEndDistance(CorrectionSizeEndDistanceInfo, 17.f, 12.f, 25.f) - , _correctionSizeFactor(CorrectionSizeFactorInfo, 8.f, 0.f, 20.f) - , _useLinearFiltering(UseLinearFiltering, false) - , _setRangeFromData(SetRangeFromData) - , _renderOption(RenderOptionInfo, properties::OptionProperty::DisplayType::Dropdown) -{ - const Parameters p = codegen::bake(dictionary); - - if (p.file.has_value()) { - _speckFile = absPath(*p.file).string(); - } - _hasSpeckFile = p.file.has_value(); - - _useColorMap = p.useColorMap.value_or(_useColorMap); - - _drawElements = p.drawElements.value_or(_drawElements); - _drawElements.onChange([this]() { _hasSpeckFile = !_hasSpeckFile; }); - addProperty(_drawElements); - - _renderOption.addOption(RenderOption::ViewDirection, "Camera View Direction"); - _renderOption.addOption(RenderOption::PositionNormal, "Camera Position Normal"); - - if (p.renderOption.has_value()) { - _renderOption = codegen::map(*p.renderOption); - } - else { - _renderOption = RenderOption::ViewDirection; - } - addProperty(_renderOption); - - if (p.unit.has_value()) { - _unit = codegen::map(*p.unit); - } - else { - _unit = DistanceUnit::Meter; - } - - if (p.texture.has_value()) { - _spriteTexturePath = absPath(*p.texture).string(); - _spriteTexturePath.onChange([this]() { _spriteTextureIsDirty = true; }); - - // @TODO (abock, 2021-01-31) I don't know why we only add this property if the - // texture is given, but I think it's a bug - // @TODO (emmbr, 2021-05-24) This goes for several properties in this renderable - addProperty(_spriteTexturePath); - } - _hasSpriteTexture = p.texture.has_value(); - - if (p.colorMap.has_value()) { - _colorMapFile = absPath(*p.colorMap).string(); - _hasColorMapFile = true; - - if (p.colorOption.has_value()) { - std::vector opts = *p.colorOption; - for (size_t i = 0; i < opts.size(); ++i) { - _colorOption.addOption(static_cast(i), opts[i]); - _optionConversionMap.insert({ static_cast(i), opts[i] }); - _colorOptionString = opts[i]; - } - } - _colorOption.onChange([this]() { - _dataIsDirty = true; - const glm::vec2 colorRange = _colorRangeData[_colorOption.value()]; - _optionColorRangeData = colorRange; - _colorOptionString = _optionConversionMap[_colorOption.value()]; - }); - addProperty(_colorOption); - - _colorRangeData = p.colorRange.value_or(_colorRangeData); - if (!_colorRangeData.empty()) { - _optionColorRangeData = _colorRangeData[_colorRangeData.size() - 1]; - } - _optionColorRangeData.onChange([this]() { - const glm::vec2 colorRange = _optionColorRangeData; - _colorRangeData[_colorOption.value()] = colorRange; - _dataIsDirty = true; - }); - addProperty(_optionColorRangeData); - - _isColorMapExact = p.exactColorMap.value_or(_isColorMapExact); - } - - _pointColor = p.color; - _pointColor.setViewOption(properties::Property::ViewOptions::Color); - addProperty(_pointColor); - - addProperty(Fadeable::_opacity); - - _scaleFactor = p.scaleFactor.value_or(_scaleFactor); - addProperty(_scaleFactor); - - if (p.sizeOption.has_value()) { - std::vector opts = *p.sizeOption; - for (size_t i = 0; i < opts.size(); ++i) { - _datavarSizeOption.addOption(static_cast(i), opts[i]); - _optionConversionSizeMap.insert({ static_cast(i), opts[i] }); - _datavarSizeOptionString = opts[i]; - } - - _datavarSizeOption.onChange([this]() { - _dataIsDirty = true; - _datavarSizeOptionString = _optionConversionSizeMap[_datavarSizeOption]; - }); - addProperty(_datavarSizeOption); - - _hasDatavarSize = true; - } - - _polygonSides = p.polygonSides.value_or(_polygonSides); - _hasPolygon = p.polygonSides.has_value(); - - if (p.labels.has_value()) { - _labels = std::make_unique(*p.labels); - _hasLabels = true; - addPropertySubOwner(_labels.get()); - // Fading of the labels should also depend on the fading of the renderable - _labels->setParentFadeable(this); - } - - _transformationMatrix = p.transformationMatrix.value_or(_transformationMatrix); - - if (p.fadeInDistances.has_value()) { - _fadeInDistances = *p.fadeInDistances; - _fadeInDistances.setViewOption(properties::Property::ViewOptions::MinMaxRange); - addProperty(_fadeInDistances); - - _disableFadeInDistance = false; - addProperty(_disableFadeInDistance); - } - - _pixelSizeControl = p.enablePixelSizeControl.value_or(_pixelSizeControl); - addProperty(_pixelSizeControl); - - _billboardMinMaxSize = p.billboardMinMaxSize.value_or(_billboardMinMaxSize); - _billboardMinMaxSize.setViewOption(properties::Property::ViewOptions::MinMaxRange); - addProperty(_billboardMinMaxSize); - - _correctionSizeEndDistance = - p.correctionSizeEndDistance.value_or(_correctionSizeEndDistance); - addProperty(_correctionSizeEndDistance); - - _correctionSizeFactor = p.correctionSizeFactor.value_or(_correctionSizeFactor); - if (p.correctionSizeFactor.has_value()) { - addProperty(_correctionSizeFactor); - } - - _setRangeFromData.onChange([this]() { - const int colorMapInUse = - _hasColorMapFile ? _dataset.index(_colorOptionString) : 0; - - float minValue = std::numeric_limits::max(); - float maxValue = -std::numeric_limits::max(); - for (const speck::Dataset::Entry& e : _dataset.entries) { - float color = e.data[colorMapInUse]; - minValue = std::min(minValue, color); - maxValue = std::max(maxValue, color); - } - - _optionColorRangeData = glm::vec2(minValue, maxValue); - }); - addProperty(_setRangeFromData); - - _useColorMap.onChange([this]() { _dataIsDirty = true; }); - addProperty(_useColorMap); - - _useLinearFiltering = p.useLinearFiltering.value_or(_useLinearFiltering); - _useLinearFiltering.onChange([this]() { _dataIsDirty = true; }); - addProperty(_useLinearFiltering); -} - -bool RenderableBillboardsCloud::isReady() const { - bool isReady = _program && !_dataset.entries.empty(); - - // If we have labels, they also need to be loaded - if (_hasLabels) { - isReady = isReady || _labels->isReady(); - } - return isReady; -} - -void RenderableBillboardsCloud::initialize() { - ZoneScoped; - - if (_hasSpeckFile) { - _dataset = speck::data::loadFileWithCache(_speckFile); - } - - if (_hasColorMapFile) { - _colorMap = speck::color::loadFileWithCache(_colorMapFile); - } - - if (_hasLabels) { - _labels->initialize(); - _labels->loadLabels(); - } - - if (!_colorOptionString.empty() && (_colorRangeData.size() > 1)) { - // Following DU behavior here. The last colormap variable - // entry is the one selected by default. - _colorOption.setValue(static_cast(_colorRangeData.size() - 1)); - } - - setRenderBin(Renderable::RenderBin::PreDeferredTransparent); -} - -void RenderableBillboardsCloud::initializeGL() { - ZoneScoped; - - _program = DigitalUniverseModule::ProgramObjectManager.request( - "RenderableBillboardsCloud", - []() { - return global::renderEngine->buildRenderProgram( - "RenderableBillboardsCloud", - absPath("${MODULE_DIGITALUNIVERSE}/shaders/billboard_vs.glsl"), - absPath("${MODULE_DIGITALUNIVERSE}/shaders/billboard_fs.glsl"), - absPath("${MODULE_DIGITALUNIVERSE}/shaders/billboard_gs.glsl") - ); - } - ); - - _renderToPolygonProgram = DigitalUniverseModule::ProgramObjectManager.request( - "RenderableBillboardsCloud_Polygon", - []() { - return ghoul::opengl::ProgramObject::Build( - "RenderableBillboardsCloud_Polygon", - absPath("${MODULE_DIGITALUNIVERSE}/shaders/billboardpolygon_vs.glsl"), - absPath("${MODULE_DIGITALUNIVERSE}/shaders/billboardpolygon_fs.glsl"), - absPath("${MODULE_DIGITALUNIVERSE}/shaders/billboardpolygon_gs.glsl") - ); - } - ); - - ghoul::opengl::updateUniformLocations(*_program, _uniformCache, UniformNames); - - if (_hasPolygon) { - createPolygonTexture(); - } -} - -void RenderableBillboardsCloud::deinitializeGL() { - glDeleteBuffers(1, &_vbo); - _vbo = 0; - glDeleteVertexArrays(1, &_vao); - _vao = 0; - - DigitalUniverseModule::ProgramObjectManager.release( - "RenderableBillboardsCloud", - [](ghoul::opengl::ProgramObject* p) { - global::renderEngine->removeRenderProgram(p); - } - ); - _program = nullptr; - - DigitalUniverseModule::ProgramObjectManager.release( - "RenderableBillboardsCloud_Polygon" - ); - _renderToPolygonProgram = nullptr; - - DigitalUniverseModule::TextureManager.release(_spriteTexture); - _spriteTexture = nullptr; - - if (_hasPolygon) { - _polygonTexture = nullptr; - glDeleteTextures(1, &_pTexture); - } -} - -void RenderableBillboardsCloud::renderBillboards(const RenderData& data, - const glm::dmat4& modelMatrix, - const glm::dvec3& orthoRight, - const glm::dvec3& orthoUp, - float fadeInVariable) -{ - glDepthMask(false); - - glEnablei(GL_BLEND, 0); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - - _program->activate(); - - _program->setUniform( - "screenSize", - glm::vec2(global::renderEngine->renderingResolution()) - ); - - _program->setUniform(_uniformCache.cameraPos, data.camera.positionVec3()); - _program->setUniform( - _uniformCache.cameraLookup, - glm::vec3(data.camera.lookUpVectorWorldSpace()) - ); - _program->setUniform(_uniformCache.renderOption, _renderOption.value()); - _program->setUniform(_uniformCache.modelMatrix, modelMatrix); - _program->setUniform( - _uniformCache.cameraViewProjectionMatrix, - glm::dmat4(data.camera.projectionMatrix()) * data.camera.combinedViewMatrix() - ); - - const float minBillboardSize = _billboardMinMaxSize.value().x; // in pixels - const float maxBillboardSize = _billboardMinMaxSize.value().y; // in pixels - _program->setUniform(_uniformCache.minBillboardSize, minBillboardSize); - _program->setUniform(_uniformCache.maxBillboardSize, maxBillboardSize); - _program->setUniform(_uniformCache.color, _pointColor); - _program->setUniform(_uniformCache.alphaValue, opacity()); - _program->setUniform(_uniformCache.scaleFactor, _scaleFactor); - _program->setUniform(_uniformCache.up, glm::vec3(orthoUp)); - _program->setUniform(_uniformCache.right, glm::vec3(orthoRight)); - _program->setUniform(_uniformCache.fadeInValue, fadeInVariable); - - _program->setUniform( - _uniformCache.correctionSizeEndDistance, - _correctionSizeEndDistance - ); - _program->setUniform(_uniformCache.correctionSizeFactor, _correctionSizeFactor); - - _program->setUniform(_uniformCache.enabledRectSizeControl, _pixelSizeControl); - - _program->setUniform(_uniformCache.hasDvarScaling, _hasDatavarSize); - - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - _program->setUniform(_uniformCache.screenSize, glm::vec2(viewport[2], viewport[3])); - - ghoul::opengl::TextureUnit textureUnit; - textureUnit.activate(); - if (_hasPolygon) { - glBindTexture(GL_TEXTURE_2D, _pTexture); - } - else if (_spriteTexture) { - _spriteTexture->bind(); - } - _program->setUniform(_uniformCache.spriteTexture, textureUnit); - _program->setUniform(_uniformCache.hasColormap, _hasColorMapFile); - _program->setUniform(_uniformCache.useColormap, _useColorMap); - - glBindVertexArray(_vao); - glDrawArrays(GL_POINTS, 0, static_cast(_dataset.entries.size())); - glBindVertexArray(0); - _program->deactivate(); - - global::renderEngine->openglStateCache().resetBlendState(); - global::renderEngine->openglStateCache().resetDepthState(); -} - -void RenderableBillboardsCloud::render(const RenderData& data, RendererTasks&) { - float fadeInVar = 1.f; - if (!_disableFadeInDistance) { - float distCamera = static_cast(glm::length(data.camera.positionVec3())); - const glm::vec2 fadeRange = _fadeInDistances; - const float a = static_cast( - 1.f / ((fadeRange.y - fadeRange.x) * toMeter(_unit)) - ); - const float b = -(fadeRange.x / (fadeRange.y - fadeRange.x)); - const float funcValue = a * distCamera + b; - fadeInVar *= funcValue > 1.f ? 1.f : funcValue; - - if (funcValue < 0.01f) { - return; - } - } - - glm::dmat4 modelMatrix = calcModelTransform(data); - glm::dmat4 modelViewProjectionMatrix = - calcModelViewProjectionTransform(data, modelMatrix); - - glm::dvec3 cameraViewDirectionWorld = -data.camera.viewDirectionWorldSpace(); - glm::dvec3 cameraUpDirectionWorld = data.camera.lookUpVectorWorldSpace(); - glm::dvec3 orthoRight = glm::normalize( - glm::cross(cameraUpDirectionWorld, cameraViewDirectionWorld) - ); - if (orthoRight == glm::dvec3(0.0)) { - glm::dvec3 otherVector = glm::vec3( - cameraUpDirectionWorld.y, - cameraUpDirectionWorld.x, - cameraUpDirectionWorld.z - ); - orthoRight = glm::normalize(glm::cross(otherVector, cameraViewDirectionWorld)); - } - glm::dvec3 orthoUp = glm::normalize(glm::cross(cameraViewDirectionWorld, orthoRight)); - - if (_hasSpeckFile && _drawElements) { - renderBillboards(data, modelMatrix, orthoRight, orthoUp, fadeInVar); - } - - if (_hasLabels) { - _labels->render(data, modelViewProjectionMatrix, orthoRight, orthoUp, fadeInVar); - } -} - -void RenderableBillboardsCloud::update(const UpdateData&) { - ZoneScoped; - - if (_dataIsDirty && _hasSpeckFile) { - ZoneScopedN("Data dirty"); - TracyGpuZone("Data dirty"); - LDEBUG("Regenerating data"); - - std::vector slice = createDataSlice(); - - int size = static_cast(slice.size()); - - if (_vao == 0) { - glGenVertexArrays(1, &_vao); - LDEBUG(fmt::format("Generating Vertex Array id '{}'", _vao)); - } - if (_vbo == 0) { - glGenBuffers(1, &_vbo); - LDEBUG(fmt::format("Generating Vertex Buffer Object id '{}'", _vbo)); - } - - glBindVertexArray(_vao); - glBindBuffer(GL_ARRAY_BUFFER, _vbo); - glBufferData(GL_ARRAY_BUFFER, size * sizeof(float), slice.data(), GL_STATIC_DRAW); - GLint positionAttrib = _program->attributeLocation("in_position"); - - if (_hasColorMapFile && _hasDatavarSize) { - glEnableVertexAttribArray(positionAttrib); - glVertexAttribPointer( - positionAttrib, - 4, - GL_FLOAT, - GL_FALSE, - 9 * sizeof(float), - nullptr - ); - - GLint colorMapAttrib = _program->attributeLocation("in_colormap"); - glEnableVertexAttribArray(colorMapAttrib); - glVertexAttribPointer( - colorMapAttrib, - 4, - GL_FLOAT, - GL_FALSE, - 9 * sizeof(float), - reinterpret_cast(4 * sizeof(float)) - ); - - GLint dvarScalingAttrib = _program->attributeLocation("in_dvarScaling"); - glEnableVertexAttribArray(dvarScalingAttrib); - glVertexAttribPointer( - dvarScalingAttrib, - 1, - GL_FLOAT, - GL_FALSE, - 9 * sizeof(float), - reinterpret_cast(8 * sizeof(float)) - ); - } - else if (_hasColorMapFile) { - glEnableVertexAttribArray(positionAttrib); - glVertexAttribPointer( - positionAttrib, - 4, - GL_FLOAT, - GL_FALSE, - 8 * sizeof(float), - nullptr - ); - - GLint colorMapAttrib = _program->attributeLocation("in_colormap"); - glEnableVertexAttribArray(colorMapAttrib); - glVertexAttribPointer( - colorMapAttrib, - 4, - GL_FLOAT, - GL_FALSE, - 8 * sizeof(float), - reinterpret_cast(4 * sizeof(float)) - ); - } - else if (_hasDatavarSize) { - glEnableVertexAttribArray(positionAttrib); - glVertexAttribPointer( - positionAttrib, - 4, - GL_FLOAT, - GL_FALSE, - 8 * sizeof(float), - nullptr - ); - - GLint dvarScalingAttrib = _program->attributeLocation("in_dvarScaling"); - glEnableVertexAttribArray(dvarScalingAttrib); - glVertexAttribPointer( - dvarScalingAttrib, - 1, - GL_FLOAT, - GL_FALSE, - 5 * sizeof(float), - reinterpret_cast(4 * sizeof(float)) - ); - } - else { - glEnableVertexAttribArray(positionAttrib); - glVertexAttribPointer( - positionAttrib, - 4, - GL_FLOAT, - GL_FALSE, - 0, - nullptr - ); - } - - glBindVertexArray(0); - - _dataIsDirty = false; - } - - if (_hasSpriteTexture && _spriteTextureIsDirty && !_spriteTexturePath.value().empty()) - { - ZoneScopedN("Sprite texture"); - TracyGpuZone("Sprite texture"); - - ghoul::opengl::Texture* texture = _spriteTexture; - - unsigned int hash = ghoul::hashCRC32File(_spriteTexturePath); - - _spriteTexture = DigitalUniverseModule::TextureManager.request( - std::to_string(hash), - [path = _spriteTexturePath]() -> std::unique_ptr { - std::filesystem::path p = absPath(path); - LINFO(fmt::format("Loaded texture from {}", p)); - std::unique_ptr t = - ghoul::io::TextureReader::ref().loadTexture(p.string(), 2); - t->uploadTexture(); - t->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - t->purgeFromRAM(); - return t; - } - ); - - DigitalUniverseModule::TextureManager.release(texture); - _spriteTextureIsDirty = false; - } -} - -std::vector RenderableBillboardsCloud::createDataSlice() { - ZoneScoped; - - if (_dataset.entries.empty()) { - return std::vector(); - } - - std::vector result; - if (_hasColorMapFile) { - result.reserve(8 * _dataset.entries.size()); - } - else { - result.reserve(4 * _dataset.entries.size()); - } - - // what datavar in use for the index color - int colorMapInUse = - _hasColorMapFile ? _dataset.index(_colorOptionString) : 0; - - // what datavar in use for the size scaling (if present) - int sizeScalingInUse = - _hasDatavarSize ? _dataset.index(_datavarSizeOptionString) : -1; - - float minColorIdx = std::numeric_limits::max(); - float maxColorIdx = -std::numeric_limits::max(); - for (const speck::Dataset::Entry& e : _dataset.entries) { - if (e.data.size() > 0) { - float color = e.data[colorMapInUse]; - minColorIdx = std::min(color, minColorIdx); - maxColorIdx = std::max(color, maxColorIdx); - } else { - minColorIdx = 0; - maxColorIdx = 0; - } - } - - double maxRadius = 0.0; - - float biggestCoord = -1.f; - for (const speck::Dataset::Entry& e : _dataset.entries) { - glm::vec3 transformedPos = glm::vec3(_transformationMatrix * glm::vec4( - e.position, 1.0 - )); - - float unitValue = 0.f; - // (abock, 2022-01-02) This is vestigial from a previous rewrite. I just want to - // make it work for now and we can rewrite it properly later - switch (_unit) { - case DistanceUnit::Meter: - unitValue = 0.f; - break; - case DistanceUnit::Kilometer: - unitValue = 1.f; - break; - case DistanceUnit::Parsec: - unitValue = 2; - break; - case DistanceUnit::Kiloparsec: - unitValue = 3; - break; - case DistanceUnit::Megaparsec: - unitValue = 4; - break; - case DistanceUnit::Gigaparsec: - unitValue = 5; - break; - case DistanceUnit::Gigalightyear: - unitValue = 6; - break; - default: - throw ghoul::MissingCaseException(); - } - - glm::vec4 position(transformedPos, unitValue); - - const double unitMeter = toMeter(_unit); - glm::dvec3 p = glm::dvec3(position) * unitMeter; - const double r = glm::length(p); - maxRadius = std::max(maxRadius, r); - - if (_hasColorMapFile && _useColorMap && !_colorMap.entries.empty()) { - for (int j = 0; j < 4; ++j) { - result.push_back(position[j]); - } - biggestCoord = std::max(biggestCoord, glm::compMax(position)); - // Note: if exact colormap option is not selected, the first color and the - // last color in the colormap file are the outliers colors. - float variableColor = e.data[colorMapInUse]; - - float cmax, cmin; - if (_colorRangeData.empty()) { - cmax = maxColorIdx; // Max value of datavar used for the index color - cmin = minColorIdx; // Min value of datavar used for the index color - } - else { - glm::vec2 currentColorRange = _colorRangeData[_colorOption.value()]; - cmax = currentColorRange.y; - cmin = currentColorRange.x; - } - - if (_isColorMapExact) { - int colorIndex = static_cast(variableColor + cmin); - for (int j = 0; j < 4; ++j) { - result.push_back(_colorMap.entries[colorIndex][j]); - } - } - else { - if (_useLinearFiltering) { - float valueT = (variableColor - cmin) / (cmax - cmin); // in [0, 1) - valueT = std::clamp(valueT, 0.f, 1.f); - - const float idx = valueT * (_colorMap.entries.size() - 1); - const int floorIdx = static_cast(std::floor(idx)); - const int ceilIdx = static_cast(std::ceil(idx)); - - const glm::vec4 floorColor = _colorMap.entries[floorIdx]; - const glm::vec4 ceilColor = _colorMap.entries[ceilIdx]; - - if (floorColor != ceilColor) { - const glm::vec4 c = floorColor + idx * (ceilColor - floorColor); - result.push_back(c.r); - result.push_back(c.g); - result.push_back(c.b); - result.push_back(c.a); - } - else { - result.push_back(floorColor.r); - result.push_back(floorColor.g); - result.push_back(floorColor.b); - result.push_back(floorColor.a); - } - } - else { - float ncmap = static_cast(_colorMap.entries.size()); - float normalization = ((cmax != cmin) && (ncmap > 2.f)) ? - (ncmap - 2.f) / (cmax - cmin) : 0; - int colorIndex = static_cast( - (variableColor - cmin) * normalization + 1.f - ); - colorIndex = colorIndex < 0 ? 0 : colorIndex; - colorIndex = colorIndex >= ncmap ? - static_cast(ncmap - 1.f) : colorIndex; - - for (int j = 0; j < 4; ++j) { - result.push_back(_colorMap.entries[colorIndex][j]); - } - } - } - - if (_hasDatavarSize) { - result.push_back(e.data[sizeScalingInUse]); - } - } - else if (_hasDatavarSize) { - result.push_back(e.data[sizeScalingInUse]); - for (int j = 0; j < 4; ++j) { - result.push_back(position[j]); - } - } - else { - for (int j = 0; j < 4; ++j) { - result.push_back(position[j]); - } - } - } - setBoundingSphere(maxRadius); - _fadeInDistances.setMaxValue(glm::vec2(10.f * biggestCoord)); - return result; -} - -void RenderableBillboardsCloud::createPolygonTexture() { - ZoneScoped; - - LDEBUG("Creating Polygon Texture"); - - glGenTextures(1, &_pTexture); - glBindTexture(GL_TEXTURE_2D, _pTexture); - 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); - // Stopped using a buffer object for GL_PIXEL_UNPACK_BUFFER - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_BYTE, nullptr); - - renderToTexture(_pTexture, 256, 256); -} - -void RenderableBillboardsCloud::renderToTexture(GLuint textureToRenderTo, - GLuint textureWidth, GLuint textureHeight) -{ - LDEBUG("Rendering to Texture"); - - // Saves initial Application's OpenGL State - GLint defaultFBO; - GLint viewport[4]; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); - glGetIntegerv(GL_VIEWPORT, viewport); - - GLuint textureFBO; - glGenFramebuffers(1, &textureFBO); - glBindFramebuffer(GL_FRAMEBUFFER, textureFBO); - GLenum drawBuffers[1] = { GL_COLOR_ATTACHMENT0 }; - glDrawBuffers(1, drawBuffers); - - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureToRenderTo, 0); - - glViewport(viewport[0], viewport[1], textureWidth, textureHeight); - - loadPolygonGeometryForRendering(); - renderPolygonGeometry(_polygonVao); - - // Restores Applications' OpenGL State - glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); - glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); - - glDeleteBuffers(1, &_polygonVbo); - glDeleteVertexArrays(1, &_polygonVao); - glDeleteFramebuffers(1, &textureFBO); -} - -void RenderableBillboardsCloud::loadPolygonGeometryForRendering() { - glGenVertexArrays(1, &_polygonVao); - glGenBuffers(1, &_polygonVbo); - glBindVertexArray(_polygonVao); - glBindBuffer(GL_ARRAY_BUFFER, _polygonVbo); - - constexpr std::array VertexData = { - // x y z w - 0.f, 0.f, 0.f, 1.f, - }; - - glBufferData(GL_ARRAY_BUFFER, sizeof(VertexData), VertexData.data(), GL_STATIC_DRAW); - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), nullptr); - glEnableVertexAttribArray(0); - glBindVertexArray(0); -} - -void RenderableBillboardsCloud::renderPolygonGeometry(GLuint vao) { - std::unique_ptr program = - ghoul::opengl::ProgramObject::Build( - "RenderableBillboardsCloud_Polygon", - absPath("${MODULE_DIGITALUNIVERSE}/shaders/billboardpolygon_vs.glsl"), - absPath("${MODULE_DIGITALUNIVERSE}/shaders/billboardpolygon_fs.glsl"), - absPath("${MODULE_DIGITALUNIVERSE}/shaders/billboardpolygon_gs.glsl") - ); - - program->activate(); - constexpr glm::vec4 Black = glm::vec4(0.f, 0.f, 0.f, 0.f); - glClearBufferfv(GL_COLOR, 0, glm::value_ptr(Black)); - - program->setUniform("sides", _polygonSides); - program->setUniform("polygonColor", _pointColor); - - glBindVertexArray(vao); - glDrawArrays(GL_POINTS, 0, 1); - glBindVertexArray(0); - - program->deactivate(); -} - -} // namespace openspace diff --git a/modules/digitaluniverse/rendering/renderabledumeshes.cpp b/modules/digitaluniverse/rendering/renderabledumeshes.cpp index 96b4f4fd39..02baefd477 100644 --- a/modules/digitaluniverse/rendering/renderabledumeshes.cpp +++ b/modules/digitaluniverse/rendering/renderabledumeshes.cpp @@ -385,7 +385,7 @@ void RenderableDUMeshes::renderLabels(const RenderData& data, glm::vec4 textColor = glm::vec4(glm::vec3(_textColor), _textOpacity); - for (const speck::Labelset::Entry& e : _labelset.entries) { + for (const dataloader::Labelset::Entry& e : _labelset.entries) { glm::vec3 scaledPos(e.position); scaledPos *= scale; ghoul::fontrendering::FontRenderer::defaultProjectionRenderer().render( @@ -457,7 +457,7 @@ bool RenderableDUMeshes::loadData() { std::string labelFile = _labelFile; if (!labelFile.empty()) { - _labelset = speck::label::loadFileWithCache(_labelFile); + _labelset = dataloader::label::loadFileWithCache(_labelFile); } return success; diff --git a/modules/digitaluniverse/rendering/renderabledumeshes.h b/modules/digitaluniverse/rendering/renderabledumeshes.h index 472a413bd4..c4312fa18a 100644 --- a/modules/digitaluniverse/rendering/renderabledumeshes.h +++ b/modules/digitaluniverse/rendering/renderabledumeshes.h @@ -27,7 +27,7 @@ #include -#include +#include #include #include #include @@ -130,7 +130,7 @@ private: DistanceUnit _unit = DistanceUnit::Parsec; std::vector _fullData; - speck::Labelset _labelset; + dataloader::Labelset _labelset; std::unordered_map _meshColorMap; std::unordered_map _renderingMeshesMap; diff --git a/modules/digitaluniverse/rendering/renderableplanescloud.cpp b/modules/digitaluniverse/rendering/renderableplanescloud.cpp index fe16144353..ce8ce811d3 100644 --- a/modules/digitaluniverse/rendering/renderableplanescloud.cpp +++ b/modules/digitaluniverse/rendering/renderableplanescloud.cpp @@ -156,7 +156,7 @@ namespace { // [[codegen::verbatim(LabelsInfo.description)]] std::optional labels - [[codegen::reference("space_labelscomponent")]]; + [[codegen::reference("labelscomponent")]]; // [[codegen::verbatim(TransformationMatrixInfo.description)]] std::optional transformationMatrix; @@ -322,7 +322,7 @@ void RenderablePlanesCloud::initialize() { ZoneScoped; if (_hasSpeckFile && std::filesystem::is_regular_file(_speckFile)) { - _dataset = speck::data::loadFileWithCache(_speckFile); + _dataset = dataloader::data::loadFileWithCache(_speckFile); if (_dataset.entries.empty()) { throw ghoul::RuntimeError("Error loading data"); } @@ -488,7 +488,7 @@ void RenderablePlanesCloud::update(const UpdateData&) { } void RenderablePlanesCloud::loadTextures() { - for (const speck::Dataset::Texture& tex : _dataset.textures) { + for (const dataloader::Dataset::Texture& tex : _dataset.textures) { std::filesystem::path fullPath = absPath(_texturesPath.string() + '/' + tex.file); std::filesystem::path pngPath = fullPath; pngPath.replace_extension(".png"); @@ -535,7 +535,7 @@ void RenderablePlanesCloud::createPlanes() { LDEBUG("Creating planes..."); float maxSize = 0.f; double maxRadius = 0.0; - for (const speck::Dataset::Entry& e : _dataset.entries) { + for (const dataloader::Dataset::Entry& e : _dataset.entries) { const glm::vec4 transformedPos = glm::vec4( _transformationMatrix * glm::dvec4(e.position, 1.0) ); diff --git a/modules/digitaluniverse/rendering/renderableplanescloud.h b/modules/digitaluniverse/rendering/renderableplanescloud.h index 8c8773e70d..29edae010b 100644 --- a/modules/digitaluniverse/rendering/renderableplanescloud.h +++ b/modules/digitaluniverse/rendering/renderableplanescloud.h @@ -27,13 +27,14 @@ #include -#include +#include #include #include #include #include #include #include +#include #include #include #include @@ -111,7 +112,7 @@ private: DistanceUnit _unit = DistanceUnit::Parsec; - speck::Dataset _dataset; + dataloader::Dataset _dataset; // Everything related to the labels is handled by LabelsComponent std::unique_ptr _labels; diff --git a/modules/digitaluniverse/rendering/renderablepoints.cpp b/modules/digitaluniverse/rendering/renderablepoints.cpp deleted file mode 100644 index c104723ffb..0000000000 --- a/modules/digitaluniverse/rendering/renderablepoints.cpp +++ /dev/null @@ -1,437 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2023 * - * * - * 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. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - constexpr std::string_view _loggerCat = "RenderablePoints"; - - constexpr std::array UniformNames = { - "modelViewProjectionTransform", "color", "sides", "alphaValue", "scaleFactor", - "spriteTexture", "hasColorMap" - }; - - constexpr openspace::properties::Property::PropertyInfo SpriteTextureInfo = { - "Texture", - "Point Sprite Texture", - "The path to the texture that should be used as the point sprite", - openspace::properties::Property::Visibility::AdvancedUser - }; - - constexpr openspace::properties::Property::PropertyInfo ScaleFactorInfo = { - "ScaleFactor", - "Scale Factor", - "This value is used as a multiplicative factor that is applied to the apparent " - "size of each point", - openspace::properties::Property::Visibility::AdvancedUser - }; - - constexpr openspace::properties::Property::PropertyInfo ColorInfo = { - "Color", - "Color", - "This value is used to define the color of the astronomical object", - openspace::properties::Property::Visibility::NoviceUser - }; - - constexpr openspace::properties::Property::PropertyInfo ColorMapInfo = { - "ColorMap", - "Color Map File", - "The path to the color map file of the astronomical object", - openspace::properties::Property::Visibility::AdvancedUser - }; - - struct [[codegen::Dictionary(RenderablePoints)]] Parameters { - // The path to the SPECK file that contains information about the astronomical - // object being rendered - std::string file; - - // Astronomical Object Color (r,g,b) - glm::vec3 color [[codegen::color()]]; - - enum class [[codegen::map(openspace::DistanceUnit)]] Unit { - Meter [[codegen::key("m")]], - Kilometer [[codegen::key("Km")]], - Parsec [[codegen::key("pc")]], - Kiloparsec [[codegen::key("Kpc")]], - Megaparsec [[codegen::key("Mpc")]], - Gigaparsec [[codegen::key("Gpc")]], - Gigalightyear [[codegen::key("Gly")]] - }; - std::optional unit; - - // [[codegen::verbatim(SpriteTextureInfo.description)]] - std::optional texture; - - // [[codegen::verbatim(ScaleFactorInfo.description)]] - std::optional scaleFactor; - - // [[codegen::verbatim(ColorMapInfo.description)]] - std::optional colorMap; - }; -#include "renderablepoints_codegen.cpp" -} // namespace - -namespace openspace { - -documentation::Documentation RenderablePoints::Documentation() { - return codegen::doc("digitaluniverse_renderablepoints"); -} - -RenderablePoints::RenderablePoints(const ghoul::Dictionary& dictionary) - : Renderable(dictionary) - , _scaleFactor(ScaleFactorInfo, 1.f, 0.f, 64.f) - , _pointColor( - ColorInfo, - glm::vec3(1.f, 0.4f, 0.2f), - glm::vec3(0.f, 0.f, 0.f), - glm::vec3(1.f, 1.f, 1.f) - ) - , _spriteTexturePath(SpriteTextureInfo) -{ - const Parameters p = codegen::bake(dictionary); - - addProperty(Fadeable::_opacity); - - _speckFile = absPath(p.file); - - if (p.unit.has_value()) { - _unit = codegen::map(*p.unit); - } - else { - _unit = DistanceUnit::Meter; - } - - _pointColor = p.color; - _pointColor.setViewOption(properties::Property::ViewOptions::Color); - addProperty(_pointColor); - - if (p.texture.has_value()) { - _spriteTexturePath = absPath(*p.texture).string(); - _spriteTextureFile = std::make_unique( - _spriteTexturePath.value() - ); - - _spriteTexturePath.onChange([this]() { _spriteTextureIsDirty = true; }); - _spriteTextureFile->setCallback([this]() { _spriteTextureIsDirty = true; }); - addProperty(_spriteTexturePath); - - _hasSpriteTexture = true; - } - - if (p.colorMap.has_value()) { - _colorMapFile = absPath(*p.colorMap); - _hasColorMapFile = true; - } - - _scaleFactor = p.scaleFactor.value_or(_scaleFactor); - addProperty(_scaleFactor); -} - -bool RenderablePoints::isReady() const { - return _program && (!_dataset.entries.empty()); -} - -void RenderablePoints::initialize() { - ZoneScoped; - - _dataset = speck::data::loadFileWithCache(_speckFile); - - if (_hasColorMapFile) { - readColorMapFile(); - } -} - -void RenderablePoints::initializeGL() { - ZoneScoped; - - if (_hasSpriteTexture) { - _program = DigitalUniverseModule::ProgramObjectManager.request( - "RenderablePoints Sprite", - []() -> std::unique_ptr { - return global::renderEngine->buildRenderProgram( - "RenderablePoints Sprite", - absPath("${MODULE_DIGITALUNIVERSE}/shaders/points_vs.glsl"), - absPath("${MODULE_DIGITALUNIVERSE}/shaders/points_sprite_fs.glsl") - ); - } - ); - } - else { - _program = DigitalUniverseModule::ProgramObjectManager.request( - "RenderablePoints", - []() -> std::unique_ptr { - return global::renderEngine->buildRenderProgram( - "RenderablePoints", - absPath("${MODULE_DIGITALUNIVERSE}/shaders/points_vs.glsl"), - absPath("${MODULE_DIGITALUNIVERSE}/shaders/points_sprite_fs.glsl") - ); - } - ); - } - ghoul::opengl::updateUniformLocations(*_program, _uniformCache, UniformNames); -} - -void RenderablePoints::deinitializeGL() { - glDeleteBuffers(1, &_vbo); - _vbo = 0; - glDeleteVertexArrays(1, &_vao); - _vao = 0; - - DigitalUniverseModule::ProgramObjectManager.release( - _program->name(), - [](ghoul::opengl::ProgramObject* p) { - global::renderEngine->removeRenderProgram(p); - } - ); - - if (_hasSpriteTexture) { - _spriteTexture = nullptr; - } -} - -void RenderablePoints::render(const RenderData& data, RendererTasks&) { - glDepthMask(false); - _program->activate(); - - _program->setUniform( - _uniformCache.modelViewProjectionTransform, - calcModelViewProjectionTransform(data, glm::dmat4(1.0)) - ); - - _program->setUniform(_uniformCache.color, _pointColor); - _program->setUniform(_uniformCache.sides, 4); - _program->setUniform(_uniformCache.alphaValue, opacity()); - _program->setUniform(_uniformCache.scaleFactor, _scaleFactor); - - if (_hasSpriteTexture) { - ghoul::opengl::TextureUnit spriteTextureUnit; - spriteTextureUnit.activate(); - _spriteTexture->bind(); - _program->setUniform(_uniformCache.spriteTexture, spriteTextureUnit); - } - - _program->setUniform(_uniformCache.hasColorMap, _hasColorMapFile); - - glEnable(GL_PROGRAM_POINT_SIZE); - glBindVertexArray(_vao); - glDrawArrays(GL_POINTS, 0, static_cast(_dataset.entries.size())); - - glDisable(GL_PROGRAM_POINT_SIZE); - glBindVertexArray(0); - _program->deactivate(); - - glDepthMask(true); -} - -void RenderablePoints::update(const UpdateData&) { - if (_dataIsDirty) { - LDEBUG("Regenerating data"); - - std::vector slice = createDataSlice(); - - if (_vao == 0) { - glGenVertexArrays(1, &_vao); - } - if (_vbo == 0) { - glGenBuffers(1, &_vbo); - } - - glBindVertexArray(_vao); - glBindBuffer(GL_ARRAY_BUFFER, _vbo); - glBufferData( - GL_ARRAY_BUFFER, - slice.size() * sizeof(double), - slice.data(), - GL_STATIC_DRAW - ); - GLint positionAttrib = _program->attributeLocation("in_position"); - - if (_hasColorMapFile) { - glEnableVertexAttribArray(positionAttrib); - glVertexAttribLPointer( - positionAttrib, 4, GL_DOUBLE, sizeof(double) * 8, nullptr - ); - - GLint colorMapAttrib = _program->attributeLocation("in_colormap"); - glEnableVertexAttribArray(colorMapAttrib); - glVertexAttribLPointer( - colorMapAttrib, - 4, - GL_DOUBLE, - 8 * sizeof(double), - reinterpret_cast(4 * sizeof(double)) - ); - } - else { - glEnableVertexAttribArray(positionAttrib); - glVertexAttribLPointer(positionAttrib, 4, GL_DOUBLE, 0, nullptr); - } - - glBindVertexArray(0); - - _dataIsDirty = false; - } - - if (_hasSpriteTexture && _spriteTextureIsDirty) { - LDEBUG("Reloading Sprite Texture"); - _spriteTexture = nullptr; - if (!_spriteTexturePath.value().empty()) { - _spriteTexture = ghoul::io::TextureReader::ref().loadTexture( - absPath(_spriteTexturePath).string(), - 2 - ); - if (_spriteTexture) { - LDEBUG( - fmt::format("Loaded texture from {}", absPath(_spriteTexturePath)) - ); - _spriteTexture->uploadTexture(); - } - _spriteTexture->setFilter( - ghoul::opengl::Texture::FilterMode::AnisotropicMipMap - ); - - _spriteTextureFile = std::make_unique( - _spriteTexturePath.value() - ); - _spriteTextureFile->setCallback([this]() { _spriteTextureIsDirty = true; }); - } - _spriteTextureIsDirty = false; - } -} - -void RenderablePoints::readColorMapFile() { - std::ifstream file(_colorMapFile); - if (!file.good()) { - throw ghoul::RuntimeError(fmt::format( - "Failed to open Color Map file {}", _colorMapFile - )); - } - - std::size_t numberOfColors = 0; - - // The beginning of the speck file has a header that either contains comments - // (signaled by a preceding '#') or information about the structure of the file - // (signaled by the keywords 'datavar', 'texturevar', and 'texture') - std::string line; - while (true) { - // std::streampos position = file.tellg(); - std::getline(file, line); - - if (line.empty() || line[0] == '#') { - continue; - } - - // Initial number of colors - std::locale loc; - if (std::isdigit(line[0], loc)) { - std::string::size_type sz; - numberOfColors = std::stoi(line, &sz); - break; - } - else if (file.eof()) { - throw ghoul::RuntimeError(fmt::format( - "Failed to load colors from Color Map file {}", _colorMapFile - )); - } - } - - for (size_t i = 0; i < numberOfColors; ++i) { - std::getline(file, line); - std::stringstream str(line); - - glm::vec4 color; - str >> color.r >> color.g >> color.b >> color.a; - - _colorMapData.push_back(color); - } -} - -std::vector RenderablePoints::createDataSlice() { - std::vector slice; - if (_hasColorMapFile) { - slice.reserve(8 * _dataset.entries.size()); - } - else { - slice.reserve(4 * _dataset.entries.size()); - } - - double maxRadius = 0.0; - - int colorIndex = 0; - for (const speck::Dataset::Entry& e : _dataset.entries) { - glm::dvec3 p = e.position; - double scale = toMeter(_unit); - p *= scale; - - const double r = glm::length(p); - maxRadius = std::max(maxRadius, r); - - glm::dvec4 position(p, 1.0); - - if (_hasColorMapFile) { - for (int j = 0; j < 4; ++j) { - slice.push_back(position[j]); - } - for (int j = 0; j < 4; ++j) { - slice.push_back(_colorMapData[colorIndex][j]); - } - } - else { - for (int j = 0; j < 4; ++j) { - slice.push_back(position[j]); - } - } - - colorIndex = (colorIndex == static_cast(_colorMapData.size() - 1)) ? - 0 : - colorIndex + 1; - } - setBoundingSphere(maxRadius); - - return slice; -} - -} // namespace openspace diff --git a/modules/digitaluniverse/rendering/renderablepoints.h b/modules/digitaluniverse/rendering/renderablepoints.h deleted file mode 100644 index 1fba9ebbff..0000000000 --- a/modules/digitaluniverse/rendering/renderablepoints.h +++ /dev/null @@ -1,106 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2023 * - * * - * 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. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_DIGITALUNIVERSE___RENDERABLEPOINTS___H__ -#define __OPENSPACE_MODULE_DIGITALUNIVERSE___RENDERABLEPOINTS___H__ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ghoul::filesystem { class File; } - -namespace ghoul::opengl { - class ProgramObject; - class Texture; -} // namespace ghoul::opengl - -namespace openspace { - -namespace documentation { struct Documentation; } - -class RenderablePoints : public Renderable { -public: - explicit RenderablePoints(const ghoul::Dictionary& dictionary); - ~RenderablePoints() override = default; - - void initialize() override; - void initializeGL() override; - void deinitializeGL() override; - - bool isReady() const override; - - void render(const RenderData& data, RendererTasks& rendererTask) override; - void update(const UpdateData& data) override; - - static documentation::Documentation Documentation(); - -private: - std::vector createDataSlice(); - - void readColorMapFile(); - - bool _dataIsDirty = true; - bool _hasSpriteTexture = false; - bool _spriteTextureIsDirty = true; - bool _hasColorMapFile = false; - - properties::FloatProperty _scaleFactor; - properties::Vec3Property _pointColor; - properties::StringProperty _spriteTexturePath; - - std::unique_ptr _spriteTexture; - std::unique_ptr _spriteTextureFile; - ghoul::opengl::ProgramObject* _program = nullptr; - UniformCache( - modelViewProjectionTransform, color, sides, alphaValue, scaleFactor, - spriteTexture, hasColorMap - ) _uniformCache; - - std::filesystem::path _speckFile; - std::filesystem::path _colorMapFile; - - DistanceUnit _unit = DistanceUnit::Parsec; - - speck::Dataset _dataset; - std::vector _colorMapData; - - //int _nValuesPerAstronomicalObject = 0; - - GLuint _vao = 0; - GLuint _vbo = 0; -}; - -} // namespace openspace - -#endif // __OPENSPACE_MODULE_DIGITALUNIVERSE___RENDERABLEPOINTS___H__ diff --git a/modules/space/CMakeLists.txt b/modules/space/CMakeLists.txt index d4b308bfeb..f191570586 100644 --- a/modules/space/CMakeLists.txt +++ b/modules/space/CMakeLists.txt @@ -27,8 +27,6 @@ include(${PROJECT_SOURCE_DIR}/support/cmake/module_definition.cmake) set(HEADER_FILES horizonsfile.h kepler.h - labelscomponent.h - speckloader.h rendering/renderableconstellationsbase.h rendering/renderableconstellationbounds.h rendering/renderableconstellationlines.h @@ -51,8 +49,6 @@ set(SOURCE_FILES horizonsfile.cpp kepler.cpp spacemodule_lua.inl - labelscomponent.cpp - speckloader.cpp rendering/renderableconstellationsbase.cpp rendering/renderableconstellationbounds.cpp rendering/renderableconstellationlines.cpp diff --git a/modules/space/rendering/renderableconstellationlines.cpp b/modules/space/rendering/renderableconstellationlines.cpp index de1cc76e19..8bd0f81827 100644 --- a/modules/space/rendering/renderableconstellationlines.cpp +++ b/modules/space/rendering/renderableconstellationlines.cpp @@ -144,7 +144,7 @@ void RenderableConstellationLines::selectionPropertyHasChanged() { } if (_hasLabels) { - for (speck::Labelset::Entry& e : _labels->labelSet().entries) { + for (dataloader::Labelset::Entry& e : _labels->labelSet().entries) { e.isEnabled = true; } } @@ -156,7 +156,7 @@ void RenderableConstellationLines::selectionPropertyHasChanged() { pair.second.isEnabled = isSelected; if (_hasLabels) { - for (speck::Labelset::Entry& e : _labels->labelSet().entries) { + for (dataloader::Labelset::Entry& e : _labels->labelSet().entries) { if (constellationFullName(e.identifier) == pair.second.name) { e.isEnabled = isSelected; break; diff --git a/modules/space/rendering/renderableconstellationsbase.cpp b/modules/space/rendering/renderableconstellationsbase.cpp index fb75c8fb5a..ace7b0c53d 100644 --- a/modules/space/rendering/renderableconstellationsbase.cpp +++ b/modules/space/rendering/renderableconstellationsbase.cpp @@ -82,7 +82,7 @@ namespace { // [[codegen::verbatim(LabelsInfo.description)]] std::optional labels - [[codegen::reference("space_labelscomponent")]]; + [[codegen::reference("labelscomponent")]]; }; #include "renderableconstellationsbase_codegen.cpp" } // namespace @@ -195,7 +195,7 @@ void RenderableConstellationsBase::initialize() { _labels->initialize(); _labels->loadLabels(); - for (speck::Labelset::Entry& entry : _labels->labelSet().entries) { + for (dataloader::Labelset::Entry& entry : _labels->labelSet().entries) { if (!entry.identifier.empty()) { std::string fullName = constellationFullName(entry.identifier); if (!fullName.empty()) { diff --git a/modules/space/rendering/renderableconstellationsbase.h b/modules/space/rendering/renderableconstellationsbase.h index 7c86c12e4b..288d4cb78f 100644 --- a/modules/space/rendering/renderableconstellationsbase.h +++ b/modules/space/rendering/renderableconstellationsbase.h @@ -27,11 +27,11 @@ #include -#include #include #include #include #include +#include #include #include #include diff --git a/modules/space/rendering/renderablestars.cpp b/modules/space/rendering/renderablestars.cpp index 8207385ad8..e696d14e5b 100644 --- a/modules/space/rendering/renderablestars.cpp +++ b/modules/space/rendering/renderablestars.cpp @@ -1355,14 +1355,14 @@ void RenderableStars::loadData() { return; } - _dataset = speck::data::loadFileWithCache(file); + _dataset = dataloader::data::loadFileWithCache(file); if (_dataset.entries.empty()) { return; } std::vector variableNames; variableNames.reserve(_dataset.variables.size()); - for (const speck::Dataset::Variable& v : _dataset.variables) { + for (const dataloader::Dataset::Variable& v : _dataset.variables) { variableNames.push_back(v.name); } _otherDataOption.addOptions(variableNames); @@ -1399,7 +1399,7 @@ std::vector RenderableStars::createDataSlice(ColorOption option) { std::vector result; // 7 for the default Color option of 3 positions + bv + lum + abs + app magnitude result.reserve(_dataset.entries.size() * 7); - for (const speck::Dataset::Entry& e : _dataset.entries) { + for (const dataloader::Dataset::Entry& e : _dataset.entries) { glm::dvec3 position = glm::dvec3(e.position) * distanceconstants::Parsec; maxRadius = std::max(maxRadius, glm::length(position)); diff --git a/modules/space/rendering/renderablestars.h b/modules/space/rendering/renderablestars.h index eb7af56799..85ea0c25b4 100644 --- a/modules/space/rendering/renderablestars.h +++ b/modules/space/rendering/renderablestars.h @@ -27,7 +27,7 @@ #include -#include +#include #include #include #include @@ -143,7 +143,7 @@ private: bool _dataIsDirty = true; bool _otherDataColorMapIsDirty = true; - speck::Dataset _dataset; + dataloader::Dataset _dataset; std::string _queuedOtherData; diff --git a/modules/space/spacemodule.cpp b/modules/space/spacemodule.cpp index f5f8d792cf..67c29cf461 100644 --- a/modules/space/spacemodule.cpp +++ b/modules/space/spacemodule.cpp @@ -24,7 +24,6 @@ #include -#include #include #include #include @@ -133,7 +132,6 @@ std::vector SpaceModule::documentations() const { RenderableTravelSpeed::Documentation(), SpiceRotation::Documentation(), SpiceTranslation::Documentation(), - LabelsComponent::Documentation(), GPTranslation::Documentation() }; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a147c084dc..1d3e45b073 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,10 @@ include(${PROJECT_SOURCE_DIR}/support/cmake/set_openspace_compile_settings.cmake set(OPENSPACE_SOURCE openspace.cpp camera/camera.cpp + data/csvloader.cpp + data/dataloader.cpp + data/datamapping.cpp + data/speckloader.cpp documentation/core_registration.cpp documentation/documentation.cpp documentation/documentationengine.cpp @@ -120,6 +124,7 @@ set(OPENSPACE_SOURCE properties/vector/vec3property.cpp properties/vector/vec4property.cpp query/query.cpp + rendering/colormappingcomponent.cpp rendering/dashboard.cpp rendering/dashboard_lua.inl rendering/dashboarditem.cpp @@ -128,6 +133,7 @@ set(OPENSPACE_SOURCE rendering/deferredcastermanager.cpp rendering/fadeable.cpp rendering/helper.cpp + rendering/labelscomponent.cpp rendering/loadingscreen.cpp rendering/luaconsole.cpp rendering/raycastermanager.cpp @@ -209,6 +215,10 @@ set(OPENSPACE_HEADER ${PROJECT_SOURCE_DIR}/include/openspace/json.h ${PROJECT_SOURCE_DIR}/include/openspace/camera/camera.h ${PROJECT_SOURCE_DIR}/include/openspace/camera/camerapose.h + ${PROJECT_SOURCE_DIR}/include/openspace/data/csvloader.h + ${PROJECT_SOURCE_DIR}/include/openspace/data/dataloader.h + ${PROJECT_SOURCE_DIR}/include/openspace/data/datamapping.h + ${PROJECT_SOURCE_DIR}/include/openspace/data/speckloader.h ${PROJECT_SOURCE_DIR}/include/openspace/documentation/core_registration.h ${PROJECT_SOURCE_DIR}/include/openspace/documentation/documentation.h ${PROJECT_SOURCE_DIR}/include/openspace/documentation/documentationengine.h @@ -308,6 +318,7 @@ set(OPENSPACE_HEADER ${PROJECT_SOURCE_DIR}/include/openspace/properties/vector/vec3property.h ${PROJECT_SOURCE_DIR}/include/openspace/properties/vector/vec4property.h ${PROJECT_SOURCE_DIR}/include/openspace/query/query.h + ${PROJECT_SOURCE_DIR}/include/openspace/rendering/colormappingcomponent.h ${PROJECT_SOURCE_DIR}/include/openspace/rendering/dashboard.h ${PROJECT_SOURCE_DIR}/include/openspace/rendering/dashboarditem.h ${PROJECT_SOURCE_DIR}/include/openspace/rendering/dashboardtextitem.h @@ -319,6 +330,7 @@ set(OPENSPACE_HEADER ${PROJECT_SOURCE_DIR}/include/openspace/rendering/loadingscreen.h ${PROJECT_SOURCE_DIR}/include/openspace/rendering/luaconsole.h ${PROJECT_SOURCE_DIR}/include/openspace/rendering/helper.h + ${PROJECT_SOURCE_DIR}/include/openspace/rendering/labelscomponent.h ${PROJECT_SOURCE_DIR}/include/openspace/rendering/raycasterlistener.h ${PROJECT_SOURCE_DIR}/include/openspace/rendering/raycastermanager.h ${PROJECT_SOURCE_DIR}/include/openspace/rendering/renderable.h diff --git a/src/data/csvloader.cpp b/src/data/csvloader.cpp new file mode 100644 index 0000000000..7da87bf571 --- /dev/null +++ b/src/data/csvloader.cpp @@ -0,0 +1,194 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2023 * + * * + * 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. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + constexpr std::string_view _loggerCat = "DataLoader: CSV"; +} // namespace + +namespace openspace::dataloader::csv { + +Dataset loadCsvFile(std::filesystem::path filePath, std::optional specs) { + ghoul_assert(std::filesystem::exists(filePath), "File must exist"); + + auto readFloatData = [](const std::string& str) -> float { + float result; +#ifdef WIN32 + auto [p, ec] = std::from_chars(str.data(), str.data() + str.size(), result); + if (ec == std::errc() && std::isfinite(result)) { + return result; + } + return std::numeric_limits::quiet_NaN(); +#else + // clang is missing float support for std::from_chars + try { + result = std::stof(str.c_str(), nullptr); + if (std::isfinite(result)) { + return result; + } + } + catch (std::invalid_argument const& e) {} + return NAN; +#endif + }; + + LDEBUG("Parsing CSV file"); + + std::vector> rows = ghoul::loadCSVFile( + filePath.string(), + true + ); + + if (rows.size() < 2) { + LWARNING(fmt::format( + "Error loading data file {}. No data items read", filePath + )); + return Dataset(); + } + + Dataset res; + res.entries.reserve(rows.size() - 1); + + // First row is the column names + const std::vector& columns = rows.front(); + + int xColumn = -1; + int yColumn = -1; + int zColumn = -1; + + int nDataColumns = 0; + bool hasExcludeColumns = specs.has_value() && (*specs).hasExcludeColumns(); + std::vector skipColumns; + if (hasExcludeColumns) { + skipColumns.reserve((*specs).excludeColumns.size()); + } + + for (size_t i = 0; i < columns.size(); ++i) { + const std::string& col = columns[i]; + + if (isPositionColumn(col, specs)) { + if (isColumnX(col, specs)) { + xColumn = static_cast(i); + } + if (isColumnY(col, specs)) { + yColumn = static_cast(i); + } + if (isColumnZ(col, specs)) { + zColumn = static_cast(i); + } + } + else if (hasExcludeColumns && (*specs).isExcludeColumn(col)) { + skipColumns.push_back(i); + continue; + } + else { + res.variables.push_back({ + .index = nDataColumns, + .name = col + }); + nDataColumns++; + } + } + + if (xColumn < 0 || yColumn < 0 || zColumn < 0) { + // One or more position columns weren't read + LERROR(fmt::format( + "Error loading data file {}. Missing X, Y or Z position column", filePath + )); + } + + LINFO(fmt::format( + "Loading {} rows with {} columns", rows.size(), columns.size() + )); + ProgressBar progress(rows.size()); + + // Skip first row (column names) + for (size_t rowIdx = 1; rowIdx < rows.size(); ++rowIdx) { + const std::vector& row = rows[rowIdx]; + + Dataset::Entry entry; + entry.data.reserve(nDataColumns); + + for (size_t i = 0; i < row.size(); ++i) { + // Check if column should be exluded. Note that list of indices is sorted + // so we can do a binary search + if (hasExcludeColumns && + std::binary_search(skipColumns.begin(), skipColumns.end(), i)) + { + continue; + } + + const std::string& strValue = row[i]; + + // For now, all values are converted to float + float value = readFloatData(strValue); + + if (i == xColumn) { + entry.position.x = value; + } + else if (i == yColumn) { + entry.position.y = value; + } + else if (i == zColumn) { + entry.position.z = value; + } + else { + entry.data.push_back(value); + } + + // @TODO: comment mapping + } + + glm::vec3 positive = glm::abs(entry.position); + float max = glm::compMax(positive); + if (max > res.maxPositionComponent) { + res.maxPositionComponent = max; + } + + res.entries.push_back(entry); + + progress.print(rowIdx + 1); + } + + return res; +} + +} // namespace openspace::dataloader::csv diff --git a/src/data/dataloader.cpp b/src/data/dataloader.cpp new file mode 100644 index 0000000000..e2af74e0b0 --- /dev/null +++ b/src/data/dataloader.cpp @@ -0,0 +1,687 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2023 * + * * + * 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. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + constexpr int8_t DataCacheFileVersion = 11; + constexpr int8_t LabelCacheFileVersion = 11; + constexpr int8_t ColorCacheFileVersion = 11; + + constexpr std::string_view DefaultXColumn = "x"; + constexpr std::string_view DefaultYColumn = "y"; + constexpr std::string_view DefaultZColumn = "z"; + + template + void checkSize(U value, std::string_view message) { + if (value > std::numeric_limits::max()) { + throw ghoul::RuntimeError(fmt::format("Error saving file: {}", message)); + } + } + + template + using LoadCacheFunc = std::function(std::filesystem::path)>; + + template + using SaveCacheFunc = std::function; + + template + using LoadDataFunc = std::function specs + )>; + + template + T internalLoadFileWithCache(std::filesystem::path filePath, + std::optional specs, + LoadDataFunc loadFunction, + LoadCacheFunc loadCacheFunction, + SaveCacheFunc saveCacheFunction) + { + static_assert( + std::is_same_v || + std::is_same_v || + std::is_same_v + ); + + std::string info; + if (specs.has_value()) { + info = openspace::dataloader::generateHashString(*specs); + } + std::filesystem::path cached = FileSys.cacheManager()->cachedFilename(filePath, info); + + if (std::filesystem::exists(cached)) { + LINFOC( + "DataLoader", + fmt::format("Cached file {} used for file {}", cached, filePath) + ); + + std::optional dataset = loadCacheFunction(cached); + if (dataset.has_value()) { + // We could load the cache file and we are now done with this + return *dataset; + } + else { + FileSys.cacheManager()->removeCacheFile(cached); + } + } + LINFOC("DataLoader", fmt::format("Loading file {}", filePath)); + T dataset = loadFunction(filePath, specs); + + if (!dataset.entries.empty()) { + LINFOC("DataLoader", "Saving cache"); + saveCacheFunction(dataset, cached); + } + + return dataset; + } +} // namespace + +namespace openspace::dataloader { + +namespace data { + +Dataset loadFile(std::filesystem::path path, std::optional specs) { + ghoul_assert(std::filesystem::exists(path), "File must exist"); + + std::ifstream file(path); + if (!file.good()) { + throw ghoul::RuntimeError(fmt::format("Failed to open data file {}", path)); + } + + std::string extension = ghoul::toLowerCase(path.extension().string()); + + Dataset res; + if (extension == ".csv") { + res = csv::loadCsvFile(path, specs); + } + else if (extension == ".speck") { + res = speck::loadSpeckFile(path, specs); + } + else { + LERRORC("DataLoader", fmt::format( + "Could not read data file {}. File format {} is not supported", + path, path.extension() + )); + } + + return res; +} + +std::optional loadCachedFile(std::filesystem::path path) { + std::ifstream file(path, std::ios::binary); + if (!file.good()) { + return std::nullopt; + } + + Dataset result; + + int8_t fileVersion; + file.read(reinterpret_cast(&fileVersion), sizeof(int8_t)); + if (fileVersion != DataCacheFileVersion) { + // Incompatible version and we won't be able to read the file + return std::nullopt; + } + + // + // Read variables + uint16_t nVariables; + file.read(reinterpret_cast(&nVariables), sizeof(uint16_t)); + result.variables.resize(nVariables); + for (int i = 0; i < nVariables; i += 1) { + Dataset::Variable var; + + int16_t idx; + file.read(reinterpret_cast(&idx), sizeof(int16_t)); + var.index = idx; + + uint16_t len; + file.read(reinterpret_cast(&len), sizeof(uint16_t)); + var.name.resize(len); + file.read(var.name.data(), len); + + result.variables[i] = std::move(var); + } + + // + // Read textures + uint16_t nTextures; + file.read(reinterpret_cast(&nTextures), sizeof(uint16_t)); + result.textures.resize(nTextures); + for (int i = 0; i < nTextures; i += 1) { + Dataset::Texture tex; + + int16_t idx; + file.read(reinterpret_cast(&idx), sizeof(int16_t)); + tex.index = idx; + + uint16_t len; + file.read(reinterpret_cast(&len), sizeof(uint16_t)); + tex.file.resize(len); + file.read(tex.file.data(), len); + + result.textures[i] = std::move(tex); + } + + // + // Read indices + int16_t texDataIdx; + file.read(reinterpret_cast(&texDataIdx), sizeof(int16_t)); + result.textureDataIndex = texDataIdx; + + int16_t oriDataIdx; + file.read(reinterpret_cast(&oriDataIdx), sizeof(int16_t)); + result.orientationDataIndex = oriDataIdx; + + // + // Read entries + uint64_t nEntries; + file.read(reinterpret_cast(&nEntries), sizeof(uint64_t)); + result.entries.reserve(nEntries); + for (uint64_t i = 0; i < nEntries; i += 1) { + Dataset::Entry e; + file.read(reinterpret_cast(&e.position.x), sizeof(float)); + file.read(reinterpret_cast(&e.position.y), sizeof(float)); + file.read(reinterpret_cast(&e.position.z), sizeof(float)); + + uint16_t nValues; + file.read(reinterpret_cast(&nValues), sizeof(uint16_t)); + e.data.resize(nValues); + file.read(reinterpret_cast(e.data.data()), nValues * sizeof(float)); + + uint16_t len; + file.read(reinterpret_cast(&len), sizeof(uint16_t)); + if (len > 0) { + std::string comment; + comment.resize(len); + file.read(comment.data(), len); + e.comment = std::move(comment); + } + + result.entries.push_back(std::move(e)); + } + + // + // Read max data point variable + float max; + file.read(reinterpret_cast(&max), sizeof(float)); + result.maxPositionComponent = max; + + return result; +} + +void saveCachedFile(const Dataset& dataset, std::filesystem::path path) { + std::ofstream file(path, std::ofstream::binary); + + file.write(reinterpret_cast(&DataCacheFileVersion), sizeof(int8_t)); + + // + // Store variables + checkSize(dataset.variables.size(), "Too many variables"); + uint16_t nVariables = static_cast(dataset.variables.size()); + file.write(reinterpret_cast(&nVariables), sizeof(uint16_t)); + for (const Dataset::Variable& var : dataset.variables) { + checkSize(var.index, "Variable index too large"); + int16_t idx = static_cast(var.index); + file.write(reinterpret_cast(&idx), sizeof(int16_t)); + + checkSize(var.name.size(), "Variable name too long"); + uint16_t len = static_cast(var.name.size()); + file.write(reinterpret_cast(&len), sizeof(uint16_t)); + file.write(var.name.data(), len); + } + + // + // Store textures + checkSize(dataset.textures.size(), "Too many textures"); + uint16_t nTextures = static_cast(dataset.textures.size()); + file.write(reinterpret_cast(&nTextures), sizeof(uint16_t)); + for (const Dataset::Texture& tex : dataset.textures) { + checkSize(tex.index, "Texture index too large"); + int16_t idx = static_cast(tex.index); + file.write(reinterpret_cast(&idx), sizeof(int16_t)); + + + checkSize(tex.file.size(), "Texture file too long"); + uint16_t len = static_cast(tex.file.size()); + file.write(reinterpret_cast(&len), sizeof(uint16_t)); + file.write(tex.file.data(), len); + } + + // + // Store indices + checkSize(dataset.textureDataIndex, "Texture index too large"); + int16_t texIdx = static_cast(dataset.textureDataIndex); + file.write(reinterpret_cast(&texIdx), sizeof(int16_t)); + + checkSize(dataset.orientationDataIndex, "Orientation index too large"); + int16_t orientationIdx = static_cast(dataset.orientationDataIndex); + file.write(reinterpret_cast(&orientationIdx), sizeof(int16_t)); + + // + // Store entries + checkSize(dataset.entries.size(), "Too many entries"); + uint64_t nEntries = static_cast(dataset.entries.size()); + file.write(reinterpret_cast(&nEntries), sizeof(uint64_t)); + for (const Dataset::Entry& e : dataset.entries) { + file.write(reinterpret_cast(&e.position.x), sizeof(float)); + file.write(reinterpret_cast(&e.position.y), sizeof(float)); + file.write(reinterpret_cast(&e.position.z), sizeof(float)); + + checkSize(e.data.size(), "Too many data variables"); + uint16_t nValues = static_cast(e.data.size()); + file.write(reinterpret_cast(&nValues), sizeof(uint16_t)); + file.write( + reinterpret_cast(e.data.data()), + e.data.size() * sizeof(float) + ); + + if (e.comment.has_value()) { + checkSize(e.comment->size(), "Comment too long"); + } + uint16_t commentLen = e.comment.has_value() ? + static_cast(e.comment->size()) : + 0; + file.write(reinterpret_cast(&commentLen), sizeof(uint16_t)); + if (e.comment.has_value()) { + file.write(e.comment->data(), e.comment->size()); + } + } + + // + // Store max data point variable + file.write(reinterpret_cast(&dataset.maxPositionComponent), sizeof(float)); +} + +Dataset loadFileWithCache(std::filesystem::path filePath, std::optional specs) +{ + return internalLoadFileWithCache( + filePath, + specs, + &loadFile, + &loadCachedFile, + &saveCachedFile + ); +} + +} // namespace data + +namespace label { + +Labelset loadFile(std::filesystem::path path, std::optional) { + ghoul_assert(std::filesystem::exists(path), "File must exist"); + + std::ifstream file(path); + if (!file.good()) { + throw ghoul::RuntimeError(fmt::format("Failed to open dataset file {}", path)); + } + + std::string extension = ghoul::toLowerCase(path.extension().string()); + + Labelset res; + if (extension == ".label") { + res = speck::loadLabelFile(path); + } + else { + LERRORC("DataLoader", fmt::format( + "Could not read label data file {}. File format {} is not supported", + path, path.extension() + )); + } + + return res; +} + +std::optional loadCachedFile(std::filesystem::path path) { + std::ifstream file(path, std::ios::binary); + if (!file.good()) { + return std::nullopt; + } + + int8_t fileVersion; + file.read(reinterpret_cast(&fileVersion), sizeof(int8_t)); + if (fileVersion != LabelCacheFileVersion) { + // Incompatible version and we won't be able to read the file + return std::nullopt; + } + + Labelset result; + + int16_t textColorIdx; + file.read(reinterpret_cast(&textColorIdx), sizeof(int16_t)); + result.textColorIndex = textColorIdx; + + uint32_t nEntries; + file.read(reinterpret_cast(&nEntries), sizeof(uint32_t)); + result.entries.reserve(nEntries); + for (unsigned int i = 0; i < nEntries; i += 1) { + Labelset::Entry e; + file.read(reinterpret_cast(&e.position.x), sizeof(float)); + file.read(reinterpret_cast(&e.position.y), sizeof(float)); + file.read(reinterpret_cast(&e.position.z), sizeof(float)); + + // Identifier + uint8_t idLen; + file.read(reinterpret_cast(&idLen), sizeof(uint8_t)); + e.identifier.resize(idLen); + file.read(e.identifier.data(), idLen); + + // Text + uint16_t len; + file.read(reinterpret_cast(&len), sizeof(uint16_t)); + e.text.resize(len); + file.read(e.text.data(), len); + + result.entries.push_back(e); + } + + return result; +} + +void saveCachedFile(const Labelset& labelset, std::filesystem::path path) { + std::ofstream file(path, std::ofstream::binary); + + file.write(reinterpret_cast(&LabelCacheFileVersion), sizeof(int8_t)); + + // + // Storage text color + checkSize(labelset.textColorIndex, "Too high text color"); + int16_t textColorIdx = static_cast(labelset.textColorIndex); + file.write(reinterpret_cast(&textColorIdx), sizeof(int16_t)); + + // + // Storage text lines + checkSize(labelset.entries.size(), "Too many entries"); + uint32_t nEntries = static_cast(labelset.entries.size()); + file.write(reinterpret_cast(&nEntries), sizeof(uint32_t)); + for (const Labelset::Entry& e : labelset.entries) { + file.write(reinterpret_cast(&e.position.x), sizeof(float)); + file.write(reinterpret_cast(&e.position.y), sizeof(float)); + file.write(reinterpret_cast(&e.position.z), sizeof(float)); + + // Identifier + checkSize(e.identifier.size(), "Identifier too long"); + uint8_t idLen = static_cast(e.identifier.size()); + file.write(reinterpret_cast(&idLen), sizeof(uint8_t)); + file.write(e.identifier.data(), idLen); + + // Text + checkSize(e.text.size(), "Text too long"); + uint16_t len = static_cast(e.text.size()); + file.write(reinterpret_cast(&len), sizeof(uint16_t)); + file.write(e.text.data(), len); + } +} + +Labelset loadFileWithCache(std::filesystem::path filePath) { + return internalLoadFileWithCache( + filePath, + std::nullopt, + &loadFile, + &loadCachedFile, + &saveCachedFile + ); +} + +} // namespace label + +namespace color { + +ColorMap loadFile(std::filesystem::path path, std::optional) { + ghoul_assert(std::filesystem::exists(path), "File must exist"); + + std::ifstream file(path); + if (!file.good()) { + throw ghoul::RuntimeError(fmt::format("Failed to open colormap file {}", path)); + } + + std::string extension = ghoul::toLowerCase(path.extension().string()); + + ColorMap res; + if (extension == ".cmap") { + res = speck::loadCmapFile(path); + } + else { + LERRORC("DataLoader", fmt::format( + "Could not read color map file {}. File format {} is not supported", + path, path.extension() + )); + } + + return res; +} + +std::optional loadCachedFile(std::filesystem::path path) { + std::ifstream file(path, std::ios::binary); + if (!file.good()) { + return std::nullopt; + } + + int8_t fileVersion; + file.read(reinterpret_cast(&fileVersion), sizeof(int8_t)); + if (fileVersion != ColorCacheFileVersion) { + // Incompatible version and we won't be able to read the file + return std::nullopt; + } + + ColorMap result; + + uint32_t nColors; + file.read(reinterpret_cast(&nColors), sizeof(uint32_t)); + result.entries.reserve(nColors); + for (unsigned int i = 0; i < nColors; i += 1) { + glm::vec4 color; + file.read(reinterpret_cast(&color.x), sizeof(float)); + file.read(reinterpret_cast(&color.y), sizeof(float)); + file.read(reinterpret_cast(&color.z), sizeof(float)); + file.read(reinterpret_cast(&color.w), sizeof(float)); + result.entries.push_back(color); + } + + glm::vec4 color; + + bool hasBelowColor = false; + file.read(reinterpret_cast(&hasBelowColor), sizeof(bool)); + file.read(reinterpret_cast(&color.x), sizeof(float)); + file.read(reinterpret_cast(&color.y), sizeof(float)); + file.read(reinterpret_cast(&color.z), sizeof(float)); + file.read(reinterpret_cast(&color.w), sizeof(float)); + + if (hasBelowColor) { + result.belowRangeColor = color; + } + + bool hasAboveColor = false; + file.read(reinterpret_cast(&hasAboveColor), sizeof(bool)); + file.read(reinterpret_cast(&color.x), sizeof(float)); + file.read(reinterpret_cast(&color.y), sizeof(float)); + file.read(reinterpret_cast(&color.z), sizeof(float)); + file.read(reinterpret_cast(&color.w), sizeof(float)); + + if (hasAboveColor) { + result.aboveRangeColor = color; + } + + bool hasNanColor = false; + file.read(reinterpret_cast(&hasNanColor), sizeof(bool)); + file.read(reinterpret_cast(&color.x), sizeof(float)); + file.read(reinterpret_cast(&color.y), sizeof(float)); + file.read(reinterpret_cast(&color.z), sizeof(float)); + file.read(reinterpret_cast(&color.w), sizeof(float)); + + if (hasNanColor) { + result.nanColor = color; + } + + return result; +} + +void saveCachedFile(const ColorMap& colorMap, std::filesystem::path path) { + std::ofstream file(path, std::ofstream::binary); + + file.write(reinterpret_cast(&ColorCacheFileVersion), sizeof(int8_t)); + + uint32_t nColors = static_cast(colorMap.entries.size()); + file.write(reinterpret_cast(&nColors), sizeof(uint32_t)); + for (const glm::vec4& color : colorMap.entries) { + file.write(reinterpret_cast(&color.x), sizeof(float)); + file.write(reinterpret_cast(&color.y), sizeof(float)); + file.write(reinterpret_cast(&color.z), sizeof(float)); + file.write(reinterpret_cast(&color.w), sizeof(float)); + } + + bool hasBelowColor = colorMap.belowRangeColor.has_value(); + const glm::vec4 belowColor = colorMap.belowRangeColor.value_or(glm::vec4(0.f)); + file.write(reinterpret_cast(&hasBelowColor), sizeof(bool)); + file.write(reinterpret_cast(&belowColor.x), sizeof(float)); + file.write(reinterpret_cast(&belowColor.y), sizeof(float)); + file.write(reinterpret_cast(&belowColor.z), sizeof(float)); + file.write(reinterpret_cast(&belowColor.w), sizeof(float)); + + bool hasAboveColor = colorMap.aboveRangeColor.has_value(); + const glm::vec4 aboveColor = colorMap.aboveRangeColor.value_or(glm::vec4(0.f)); + file.write(reinterpret_cast(&hasAboveColor), sizeof(bool)); + file.write(reinterpret_cast(&aboveColor.x), sizeof(float)); + file.write(reinterpret_cast(&aboveColor.y), sizeof(float)); + file.write(reinterpret_cast(&aboveColor.z), sizeof(float)); + file.write(reinterpret_cast(&aboveColor.w), sizeof(float)); + + bool hasNanColor = colorMap.nanColor.has_value(); + const glm::vec4 nanColor = colorMap.nanColor.value_or(glm::vec4(0.f)); + file.write(reinterpret_cast(&hasNanColor), sizeof(bool)); + file.write(reinterpret_cast(&nanColor.x), sizeof(float)); + file.write(reinterpret_cast(&nanColor.y), sizeof(float)); + file.write(reinterpret_cast(&nanColor.z), sizeof(float)); + file.write(reinterpret_cast(&nanColor.w), sizeof(float)); +} + +ColorMap loadFileWithCache(std::filesystem::path path) +{ + return internalLoadFileWithCache( + path, + std::nullopt, + &loadFile, + &loadCachedFile, + &saveCachedFile + ); +} + +} // namespace color + +int Dataset::index(std::string_view variableName) const { + for (const Dataset::Variable& v : variables) { + if (v.name == variableName) { + return v.index; + } + } + return -1; +} + +bool Dataset::normalizeVariable(std::string_view variableName) { + int idx = index(variableName); + + if (idx == -1) { + // We didn't find the variable that was specified + return false; + } + + float minValue = std::numeric_limits::max(); + float maxValue = -std::numeric_limits::max(); + for (Dataset::Entry& e : entries) { + float value = e.data[idx]; + if (std::isnan(value)) { + continue; + } + minValue = std::min(minValue, value); + maxValue = std::max(maxValue, value); + } + + for (Dataset::Entry& e : entries) { + float value = e.data[idx]; + if (std::isnan(value)) { + continue; + } + e.data[idx] = (value - minValue) / (maxValue - minValue); + } + + return true; +} + +glm::vec2 Dataset::findValueRange(int variableIndex) const { + if (entries.empty()) { + // Can't find range if there are no entries + return glm::vec2(0.f); + } + + if (variableIndex >= entries[0].data.size()) { + // The index is not a valid variable index + return glm::vec2(0.f); + } + + float minValue = std::numeric_limits::max(); + float maxValue = -std::numeric_limits::max(); + for (const Dataset::Entry& e : entries) { + if (!e.data.empty()) { + float value = e.data[variableIndex]; + if (std::isnan(value)) { + continue; + } + minValue = std::min(value, minValue); + maxValue = std::max(value, maxValue); + } + else { + minValue = 0.f; + maxValue = 0.f; + } + } + + return glm::vec2(minValue, maxValue); +} + +glm::vec2 Dataset::findValueRange(std::string_view variableName) const { + int idx = index(variableName); + + if (idx == -1) { + // We didn't find the variable that was specified + return glm::vec2(0.f); + } + + return findValueRange(idx); +} + +} // namespace openspace::dataloader diff --git a/src/data/datamapping.cpp b/src/data/datamapping.cpp new file mode 100644 index 0000000000..eba72d6178 --- /dev/null +++ b/src/data/datamapping.cpp @@ -0,0 +1,174 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2023 * + * * + * 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. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +namespace { + constexpr std::string_view DefaultX = "x"; + constexpr std::string_view DefaultY = "y"; + constexpr std::string_view DefaultZ = "z"; + + enum class PositionColumn { + X, Y, Z + }; + + bool checkColumnInternal(PositionColumn columnCase, const std::string& c, + const std::optional& mapping, + const std::string_view defaultValue) + { + std::string testColumn = c; + std::string column = std::string(defaultValue); + if (mapping.has_value()) { + switch (columnCase) { + case PositionColumn::X: + column = (*mapping).xColumnName.value_or(column); + break; + case PositionColumn::Y: + column = (*mapping).yColumnName.value_or(column); + break; + case PositionColumn::Z: + column = (*mapping).zColumnName.value_or(column); + break; + } + } + + // Per default, allow both lower case and upper case versions of column names + if (!mapping.has_value() || !(*mapping).isCaseSensitive) { + column = ghoul::toLowerCase(column); + testColumn = ghoul::toLowerCase(testColumn); + } + + return testColumn == column; + } + + // This is a data mapping structure that can be used when creating point cloud + // datasets, e.g. from a CSV or Speck file. + // + // It allows specifying things like column names, whether the reading of those + // column names should be case sensitive, data value that represents missing + // values in the dataset, and more. See details for each field / class member. + // + // Note that things related to reading the point position will not be handled for + // SPECK files, as for those we always expect the first three values per row to + // specify the XYZ position + struct [[codegen::Dictionary(DataMapping)]] Parameters { + // Specifies the column name for the x coordinate + std::optional x; + + // Specifies the column name for the y coordinate + std::optional y; + + // Specifies the column name for the z coordinate + std::optional z; + + // Specifies whether to do case sensitive checks when reading column names. + // Default is not to, so that 'X' and 'x' are both valid column names for the + // x position column, for example + std::optional caseSensitive; + + // Specifies a value that, when read from the file, should be interpreted as 'no + // value', i.e. a missing data value. Note that the same value is used across all + // data columns + std::optional missingDataValue; + + // A list of column names, of columns that will not be loaded into the dataset. + // Note that not all data formats support this. E.g. SPECK files do not + std::optional> excludeColumns; + }; +#include "datamapping_codegen.cpp" +} + +namespace openspace::dataloader { + +documentation::Documentation DataMapping::Documentation() { + return codegen::doc("dataloader_datamapping"); +} + +DataMapping DataMapping::createFromDictionary(const ghoul::Dictionary& dictionary) { + const Parameters p = codegen::bake(dictionary); + + DataMapping result; + + result.xColumnName = p.x; + result.yColumnName = p.y; + result.zColumnName = p.z; + + result.missingDataValue = p.missingDataValue; + + result.isCaseSensitive = p.caseSensitive.value_or(result.isCaseSensitive); + result.excludeColumns = p.excludeColumns.value_or(result.excludeColumns); + + return result; +} + +bool DataMapping::hasExcludeColumns() const { + return !excludeColumns.empty(); +} + +bool DataMapping::isExcludeColumn(std::string_view column) const { + auto found = std::find(excludeColumns.begin(), excludeColumns.end(), column); + return (found != excludeColumns.end()); +} + +std::string generateHashString(const DataMapping& dm) { + std::string a; + for (std::string_view c : dm.excludeColumns) { + a += c; + } + unsigned int excludeColumnsHash = ghoul::hashCRC32(a); + + return fmt::format( + "DM|x{}|y{}|z{}|m{}|{}|{}", + dm.xColumnName.value_or(""), + dm.yColumnName.value_or(""), + dm.zColumnName.value_or(""), + dm.missingDataValue.has_value() ? ghoul::to_string(*dm.missingDataValue) : "", + dm.isCaseSensitive ? "1" : "0", + excludeColumnsHash + ); +} + +bool isPositionColumn(const std::string& c, const std::optional& mapping) { + return isColumnX(c, mapping) || isColumnY(c, mapping) || isColumnZ(c, mapping); +} + +bool isColumnX(const std::string& c, const std::optional& mapping) { + return checkColumnInternal(PositionColumn::X, c, mapping, DefaultX); +} + +bool isColumnY(const std::string& c, const std::optional& mapping) { + return checkColumnInternal(PositionColumn::Y, c, mapping, DefaultY); +} + +bool isColumnZ(const std::string& c, const std::optional& mapping) { + return checkColumnInternal(PositionColumn::Z, c, mapping, DefaultZ); +} + +} // namespace openspace::dataloader diff --git a/modules/space/speckloader.cpp b/src/data/speckloader.cpp similarity index 51% rename from modules/space/speckloader.cpp rename to src/data/speckloader.cpp index 72e07d19d4..ee26953f5e 100644 --- a/modules/space/speckloader.cpp +++ b/src/data/speckloader.cpp @@ -22,7 +22,7 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include #include #include @@ -30,20 +30,15 @@ #include #include #include +#include #include #include #include #include namespace { - constexpr int8_t DataCacheFileVersion = 10; - constexpr int8_t LabelCacheFileVersion = 11; - constexpr int8_t ColorCacheFileVersion = 10; - bool startsWith(std::string lhs, std::string_view rhs) noexcept { - for (size_t i = 0; i < lhs.size(); i++) { - lhs[i] = static_cast(tolower(lhs[i])); - } + lhs = ghoul::toLowerCase(lhs); return (rhs.size() <= lhs.size()) && (lhs.substr(0, rhs.size()) == rhs); } @@ -70,71 +65,11 @@ namespace { } } - template - void checkSize(U value, std::string_view message) { - if (value > std::numeric_limits::max()) { - throw ghoul::RuntimeError(fmt::format("Error saving file: {}", message)); - } - } - - template - using LoadCacheFunc = std::function(std::filesystem::path)>; - - template - using SaveCacheFunc = std::function; - - template - using LoadSpeckFunc = std::function; - - - - template - T internalLoadFileWithCache(std::filesystem::path speckPath, - openspace::speck::SkipAllZeroLines skipAllZeroLines, - LoadSpeckFunc loadSpeckFunction, - LoadCacheFunc loadCacheFunction, - SaveCacheFunc saveCacheFunction) - { - static_assert( - std::is_same_v || - std::is_same_v || - std::is_same_v - ); - - std::filesystem::path cached = FileSys.cacheManager()->cachedFilename(speckPath); - - if (std::filesystem::exists(cached)) { - LINFOC( - "SpeckLoader", - fmt::format("Cached file {} used for file {}", cached, speckPath) - ); - - std::optional dataset = loadCacheFunction(cached); - if (dataset.has_value()) { - // We could load the cache file and we are now done with this - return *dataset; - } - else { - FileSys.cacheManager()->removeCacheFile(cached); - } - } - LINFOC("SpeckLoader", fmt::format("Loading file {}", speckPath)); - T dataset = loadSpeckFunction(speckPath, skipAllZeroLines); - - if (!dataset.entries.empty()) { - LINFOC("SpeckLoader", "Saving cache"); - saveCacheFunction(dataset, cached); - } - return dataset; - } } // namespace -namespace openspace::speck { +namespace openspace::dataloader::speck { -namespace data { - -Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines) { +Dataset loadSpeckFile(std::filesystem::path path, std::optional specs) { ghoul_assert(std::filesystem::exists(path), "File must exist"); std::ifstream file(path); @@ -329,11 +264,19 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines) bool allZero = true; + // For SPECK we know that the first 3 values are the position, so no need to + // check agains data mapping std::stringstream str(line); Dataset::Entry entry; str >> entry.position.x >> entry.position.y >> entry.position.z; allZero &= (entry.position == glm::vec3(0.0)); + glm::vec3 positive = glm::abs(entry.position); + float max = glm::compMax(positive); + if (max > res.maxPositionComponent) { + res.maxPositionComponent = max; + } + if (!str.good()) { // Need to subtract one of the line number here as we increase the current // line count in the beginning of the while loop we are currently in @@ -357,6 +300,15 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines) valueStream.str(value); valueStream >> entry.data[i]; + // Check if value corresponds to a missing value + if (specs.has_value() && specs->missingDataValue.has_value()) { + float missingDataValue = specs->missingDataValue.value(); + float diff = std::abs(entry.data[i] - missingDataValue); + if (diff < std::numeric_limits::epsilon()) { + entry.data[i] = std::numeric_limits::quiet_NaN(); + } + } + allZero &= (entry.data[i] == 0.0); if (valueStream.fail()) { // Need to subtract one of the line number here as we increase the @@ -371,7 +323,7 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines) } } - if (skipAllZeroLines && allZero) { + if (allZero) { continue; } @@ -402,203 +354,12 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines) return res; } -std::optional loadCachedFile(std::filesystem::path path) { - std::ifstream file(path, std::ios::binary); - if (!file.good()) { - return std::nullopt; - } - - Dataset result; - - int8_t fileVersion; - file.read(reinterpret_cast(&fileVersion), sizeof(int8_t)); - if (fileVersion != DataCacheFileVersion) { - // Incompatible version and we won't be able to read the file - return std::nullopt; - } - - // - // Read variables - uint16_t nVariables; - file.read(reinterpret_cast(&nVariables), sizeof(uint16_t)); - result.variables.resize(nVariables); - for (int i = 0; i < nVariables; i += 1) { - Dataset::Variable var; - - int16_t idx; - file.read(reinterpret_cast(&idx), sizeof(int16_t)); - var.index = idx; - - uint16_t len; - file.read(reinterpret_cast(&len), sizeof(uint16_t)); - var.name.resize(len); - file.read(var.name.data(), len); - - result.variables[i] = std::move(var); - } - - // - // Read textures - uint16_t nTextures; - file.read(reinterpret_cast(&nTextures), sizeof(uint16_t)); - result.textures.resize(nTextures); - for (int i = 0; i < nTextures; i += 1) { - Dataset::Texture tex; - - int16_t idx; - file.read(reinterpret_cast(&idx), sizeof(int16_t)); - tex.index = idx; - - uint16_t len; - file.read(reinterpret_cast(&len), sizeof(uint16_t)); - tex.file.resize(len); - file.read(tex.file.data(), len); - - result.textures[i] = std::move(tex); - } - - // - // Read indices - int16_t texDataIdx; - file.read(reinterpret_cast(&texDataIdx), sizeof(int16_t)); - result.textureDataIndex = texDataIdx; - - int16_t oriDataIdx; - file.read(reinterpret_cast(&oriDataIdx), sizeof(int16_t)); - result.orientationDataIndex = oriDataIdx; - - // - // Read entries - uint64_t nEntries; - file.read(reinterpret_cast(&nEntries), sizeof(uint64_t)); - result.entries.reserve(nEntries); - for (uint64_t i = 0; i < nEntries; i += 1) { - Dataset::Entry e; - file.read(reinterpret_cast(&e.position.x), sizeof(float)); - file.read(reinterpret_cast(&e.position.y), sizeof(float)); - file.read(reinterpret_cast(&e.position.z), sizeof(float)); - - uint16_t nValues; - file.read(reinterpret_cast(&nValues), sizeof(uint16_t)); - e.data.resize(nValues); - file.read(reinterpret_cast(e.data.data()), nValues * sizeof(float)); - - uint16_t len; - file.read(reinterpret_cast(&len), sizeof(uint16_t)); - if (len > 0) { - std::string comment; - comment.resize(len); - file.read(comment.data(), len); - e.comment = std::move(comment); - } - - result.entries.push_back(std::move(e)); - } - - return result; -} - -void saveCachedFile(const Dataset& dataset, std::filesystem::path path) { - std::ofstream file(path, std::ofstream::binary); - - file.write(reinterpret_cast(&DataCacheFileVersion), sizeof(int8_t)); - - // - // Store variables - checkSize(dataset.variables.size(), "Too many variables"); - uint16_t nVariables = static_cast(dataset.variables.size()); - file.write(reinterpret_cast(&nVariables), sizeof(uint16_t)); - for (const Dataset::Variable& var : dataset.variables) { - checkSize(var.index, "Variable index too large"); - int16_t idx = static_cast(var.index); - file.write(reinterpret_cast(&idx), sizeof(int16_t)); - - checkSize(var.name.size(), "Variable name too long"); - uint16_t len = static_cast(var.name.size()); - file.write(reinterpret_cast(&len), sizeof(uint16_t)); - file.write(var.name.data(), len); - } - - // - // Store textures - checkSize(dataset.textures.size(), "Too many textures"); - uint16_t nTextures = static_cast(dataset.textures.size()); - file.write(reinterpret_cast(&nTextures), sizeof(uint16_t)); - for (const Dataset::Texture& tex : dataset.textures) { - checkSize(tex.index, "Texture index too large"); - int16_t idx = static_cast(tex.index); - file.write(reinterpret_cast(&idx), sizeof(int16_t)); - - - checkSize(tex.file.size(), "Texture file too long"); - uint16_t len = static_cast(tex.file.size()); - file.write(reinterpret_cast(&len), sizeof(uint16_t)); - file.write(tex.file.data(), len); - } - - // - // Store indices - checkSize(dataset.textureDataIndex, "Texture index too large"); - int16_t texIdx = static_cast(dataset.textureDataIndex); - file.write(reinterpret_cast(&texIdx), sizeof(int16_t)); - - checkSize(dataset.orientationDataIndex, "Orientation index too large"); - int16_t orientationIdx = static_cast(dataset.orientationDataIndex); - file.write(reinterpret_cast(&orientationIdx), sizeof(int16_t)); - - // - // Store entries - checkSize(dataset.entries.size(), "Too many entries"); - uint64_t nEntries = static_cast(dataset.entries.size()); - file.write(reinterpret_cast(&nEntries), sizeof(uint64_t)); - for (const Dataset::Entry& e : dataset.entries) { - file.write(reinterpret_cast(&e.position.x), sizeof(float)); - file.write(reinterpret_cast(&e.position.y), sizeof(float)); - file.write(reinterpret_cast(&e.position.z), sizeof(float)); - - checkSize(e.data.size(), "Too many data variables"); - uint16_t nValues = static_cast(e.data.size()); - file.write(reinterpret_cast(&nValues), sizeof(uint16_t)); - file.write( - reinterpret_cast(e.data.data()), - e.data.size() * sizeof(float) - ); - - if (e.comment.has_value()) { - checkSize(e.comment->size(), "Comment too long"); - } - uint16_t commentLen = e.comment.has_value() ? - static_cast(e.comment->size()) : - 0; - file.write(reinterpret_cast(&commentLen), sizeof(uint16_t)); - if (e.comment.has_value()) { - file.write(e.comment->data(), e.comment->size()); - } - } -} - -Dataset loadFileWithCache(std::filesystem::path speckPath, - SkipAllZeroLines skipAllZeroLines) -{ - return internalLoadFileWithCache( - speckPath, - skipAllZeroLines, - &loadFile, - &loadCachedFile, - &saveCachedFile - ); -} - -} // namespace data - -namespace label { - -Labelset loadFile(std::filesystem::path path, SkipAllZeroLines) { +Labelset loadLabelFile(std::filesystem::path path) { ghoul_assert(std::filesystem::exists(path), "File must exist"); std::ifstream file(path); if (!file.good()) { - throw ghoul::RuntimeError(fmt::format("Failed to open speck file {}", path)); + throw ghoul::RuntimeError(fmt::format("Failed to open dataset file {}", path)); } Labelset res; @@ -637,7 +398,6 @@ Labelset loadFile(std::filesystem::path path, SkipAllZeroLines) { )); } - std::stringstream str(line); std::string dummy; str >> dummy >> res.textColorIndex; @@ -728,117 +488,17 @@ Labelset loadFile(std::filesystem::path path, SkipAllZeroLines) { return res; } -std::optional loadCachedFile(std::filesystem::path path) { - std::ifstream file(path, std::ios::binary); - if (!file.good()) { - return std::nullopt; - } - - int8_t fileVersion; - file.read(reinterpret_cast(&fileVersion), sizeof(int8_t)); - if (fileVersion != LabelCacheFileVersion) { - // Incompatible version and we won't be able to read the file - return std::nullopt; - } - - Labelset result; - - int16_t textColorIdx; - file.read(reinterpret_cast(&textColorIdx), sizeof(int16_t)); - result.textColorIndex = textColorIdx; - - uint32_t nEntries; - file.read(reinterpret_cast(&nEntries), sizeof(uint32_t)); - result.entries.reserve(nEntries); - for (unsigned int i = 0; i < nEntries; i += 1) { - Labelset::Entry e; - file.read(reinterpret_cast(&e.position.x), sizeof(float)); - file.read(reinterpret_cast(&e.position.y), sizeof(float)); - file.read(reinterpret_cast(&e.position.z), sizeof(float)); - - // Identifier - uint8_t idLen; - file.read(reinterpret_cast(&idLen), sizeof(uint8_t)); - e.identifier.resize(idLen); - file.read(e.identifier.data(), idLen); - - // Text - uint16_t len; - file.read(reinterpret_cast(&len), sizeof(uint16_t)); - e.text.resize(len); - file.read(e.text.data(), len); - - result.entries.push_back(e); - } - - return result; -} - -void saveCachedFile(const Labelset& labelset, std::filesystem::path path) { - std::ofstream file(path, std::ofstream::binary); - - file.write(reinterpret_cast(&LabelCacheFileVersion), sizeof(int8_t)); - - // - // Storage text color - checkSize(labelset.textColorIndex, "Too high text color"); - int16_t textColorIdx = static_cast(labelset.textColorIndex); - file.write(reinterpret_cast(&textColorIdx), sizeof(int16_t)); - - // - // Storage text lines - checkSize(labelset.entries.size(), "Too many entries"); - uint32_t nEntries = static_cast(labelset.entries.size()); - file.write(reinterpret_cast(&nEntries), sizeof(uint32_t)); - for (const Labelset::Entry& e : labelset.entries) { - file.write(reinterpret_cast(&e.position.x), sizeof(float)); - file.write(reinterpret_cast(&e.position.y), sizeof(float)); - file.write(reinterpret_cast(&e.position.z), sizeof(float)); - - // Identifier - checkSize(e.identifier.size(), "Identifier too long"); - uint8_t idLen = static_cast(e.identifier.size()); - file.write(reinterpret_cast(&idLen), sizeof(uint8_t)); - file.write(e.identifier.data(), idLen); - - // Text - checkSize(e.text.size(), "Text too long"); - uint16_t len = static_cast(e.text.size()); - file.write(reinterpret_cast(&len), sizeof(uint16_t)); - file.write(e.text.data(), len); - } -} - -Labelset loadFileWithCache(std::filesystem::path speckPath, - SkipAllZeroLines skipAllZeroLines) -{ - return internalLoadFileWithCache( - speckPath, - skipAllZeroLines, - &loadFile, - &loadCachedFile, - &saveCachedFile - ); -} - -} // namespace label - -namespace color { - -ColorMap loadFile(std::filesystem::path path, SkipAllZeroLines) { +ColorMap loadCmapFile(std::filesystem::path path) { ghoul_assert(std::filesystem::exists(path), "File must exist"); std::ifstream file(path); if (!file.good()) { - throw ghoul::RuntimeError(fmt::format("Failed to open speck file {}", path)); + throw ghoul::RuntimeError(fmt::format("Failed to open color map file {}", path)); } ColorMap res; int nColorLines = -1; - // The beginning of the speck file has a header that either contains comments - // (signaled by a preceding '#') or information about the structure of the file - // (signaled by the keywords 'datavar', 'texturevar', and 'texture') std::string line; while (std::getline(file, line)) { // Ignore empty line or commented-out lines @@ -854,11 +514,11 @@ ColorMap loadFile(std::filesystem::path path, SkipAllZeroLines) { strip(line); - std::stringstream str(line); if (nColorLines == -1) { // This is the first time we get this far, it will have to be the first number // meaning that it is the number of color values + std::stringstream str(line); str >> nColorLines; res.entries.reserve(nColorLines); } @@ -867,114 +527,43 @@ ColorMap loadFile(std::filesystem::path path, SkipAllZeroLines) { // reading the individual value lines glm::vec4 color; - str >> color.x >> color.y >> color.z >> color.w; - res.entries.push_back(std::move(color)); + std::string dummy; + // Note that startwith converts the input string to all lowercase + if (startsWith(line, "belowrange")) { + std::stringstream str(line); + str >> dummy >> color.x >> color.y >> color.z >> color.w; + res.belowRangeColor = color; + } + else if (startsWith(line, "aboverange")) { + std::stringstream str(line); + str >> dummy >> color.x >> color.y >> color.z >> color.w; + res.aboveRangeColor = color; + } + else if (startsWith(line, "nan")) { + std::stringstream str(line); + str >> dummy >> color.x >> color.y >> color.z >> color.w; + res.nanColor = color; + } + else { + // TODO: Catch when this is not a color! + std::stringstream str(line); + str >> color.x >> color.y >> color.z >> color.w; + res.entries.push_back(std::move(color)); + } } } + res.entries.shrink_to_fit(); + if (nColorLines != static_cast(res.entries.size())) { LWARNINGC("SpeckLoader", fmt::format( - "While loading color map, the expected number of color values '{}' was " + "While loading color map '{}', the expected number of color values '{}' was " "different from the actual number of color values '{}'", - nColorLines, res.entries.size() + path, nColorLines, res.entries.size() )); } return res; } -std::optional loadCachedFile(std::filesystem::path path) { - std::ifstream file(path, std::ios::binary); - if (!file.good()) { - return std::nullopt; - } - - int8_t fileVersion; - file.read(reinterpret_cast(&fileVersion), sizeof(int8_t)); - if (fileVersion != ColorCacheFileVersion) { - // Incompatible version and we won't be able to read the file - return std::nullopt; - } - - ColorMap result; - - uint32_t nColors; - file.read(reinterpret_cast(&nColors), sizeof(uint32_t)); - result.entries.reserve(nColors); - for (unsigned int i = 0; i < nColors; i += 1) { - glm::vec4 color; - file.read(reinterpret_cast(&color.x), sizeof(float)); - file.read(reinterpret_cast(&color.y), sizeof(float)); - file.read(reinterpret_cast(&color.z), sizeof(float)); - file.read(reinterpret_cast(&color.w), sizeof(float)); - result.entries.push_back(color); - } - return result; -} - -void saveCachedFile(const ColorMap& colorMap, std::filesystem::path path) { - std::ofstream file(path, std::ofstream::binary); - - file.write(reinterpret_cast(&ColorCacheFileVersion), sizeof(int8_t)); - - uint32_t nColors = static_cast(colorMap.entries.size()); - file.write(reinterpret_cast(&nColors), sizeof(uint32_t)); - for (const glm::vec4& color : colorMap.entries) { - file.write(reinterpret_cast(&color.x), sizeof(float)); - file.write(reinterpret_cast(&color.y), sizeof(float)); - file.write(reinterpret_cast(&color.z), sizeof(float)); - file.write(reinterpret_cast(&color.w), sizeof(float)); - } -} - -ColorMap loadFileWithCache(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines) -{ - return internalLoadFileWithCache( - path, - skipAllZeroLines, - &loadFile, - &loadCachedFile, - &saveCachedFile - ); -} - -} // namespace color - -int Dataset::index(std::string_view variableName) const { - for (const Dataset::Variable& v : variables) { - if (v.name == variableName) { - return v.index; - } - } - return -1; -} - -bool Dataset::normalizeVariable(std::string_view variableName) { - std::optional idx; - for (const Dataset::Variable& var : variables) { - if (var.name == variableName) { - idx = var.index; - break; - } - } - - if (!idx.has_value()) { - // We didn't find the variable that was specified - return false; - } - - float minValue = std::numeric_limits::max(); - float maxValue = -std::numeric_limits::max(); - for (Dataset::Entry& e : entries) { - minValue = std::min(minValue, e.data[*idx]); - maxValue = std::max(maxValue, e.data[*idx]); - } - - for (Dataset::Entry& e : entries) { - e.data[*idx] = (e.data[*idx] - minValue) / (maxValue - minValue); - } - - return true; -} - -} // namespace openspace::speck +} // namespace openspace::dataloader::speck diff --git a/src/documentation/core_registration.cpp b/src/documentation/core_registration.cpp index 5e8b02345c..bdec3fa0a9 100644 --- a/src/documentation/core_registration.cpp +++ b/src/documentation/core_registration.cpp @@ -24,6 +24,7 @@ #include +#include #include #include #include @@ -38,7 +39,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -62,6 +65,8 @@ namespace openspace { void registerCoreClasses(documentation::DocumentationEngine& engine) { engine.addDocumentation(LogFactoryDocumentation()); + engine.addDocumentation(ColorMappingComponent::Documentation()); + engine.addDocumentation(LabelsComponent::Documentation()); engine.addDocumentation(LightSource::Documentation()); engine.addDocumentation(Mission::Documentation()); engine.addDocumentation(Renderable::Documentation()); @@ -73,6 +78,8 @@ void registerCoreClasses(documentation::DocumentationEngine& engine) { engine.addDocumentation(Translation::Documentation()); engine.addDocumentation(TimeFrame::Documentation()); + engine.addDocumentation(dataloader::DataMapping::Documentation()); + engine.addDocumentation(interaction::NavigationState::Documentation()); engine.addDocumentation(interaction::Path::Documentation()); } diff --git a/src/rendering/colormappingcomponent.cpp b/src/rendering/colormappingcomponent.cpp new file mode 100644 index 0000000000..f20038b392 --- /dev/null +++ b/src/rendering/colormappingcomponent.cpp @@ -0,0 +1,470 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2023 * + * * + * 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. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include + +namespace { + constexpr std::string_view _loggerCat = "ColorMapping"; + + constexpr openspace::properties::Property::PropertyInfo EnabledInfo = { + "Enabled", + "Color Map Enabled", + "If this value is set to 'true', the provided color map is used (if one was " + "provided in the configuration). If no color map was provided, changing this " + "setting does not do anything", + openspace::properties::Property::Visibility::NoviceUser + }; + + constexpr openspace::properties::Property::PropertyInfo FileInfo = { + "File", + "Color Map File", + "The path to the color map file to use for coloring the points", + openspace::properties::Property::Visibility::AdvancedUser + }; + + constexpr openspace::properties::Property::PropertyInfo ParameterInfo = { + "Parameter", + "Parameter", + "This value determines which paramenter is used for coloring the points based " + "on the color map. The property is set based on predefined options specified in " + "the asset file. When changing the parameter, the value range to used for the" + "mapping will also be changed. Per default, it is set to the last parameter in " + "the list of options", + openspace::properties::Property::Visibility::User + }; + + constexpr openspace::properties::Property::PropertyInfo RangeInfo = { + "ValueRange", + "Value Range", + "This value changes the range of values to be mapped with the current color map", + openspace::properties::Property::Visibility::User + }; + + constexpr openspace::properties::Property::PropertyInfo SetRangeFromDataInfo = { + "SetRangeFromData", + "Set Data Range from Data", + "Set the data range for the color mapping based on the available data for the " + "curently selected data column", + openspace::properties::Property::Visibility::User + }; + + constexpr openspace::properties::Property::PropertyInfo HideOutsideInfo = { + "HideValuesOutsideRange", + "Hide Values Outside Range", + "If true, points with values outside the provided range for the coloring will be " + "hidden, i.e. not rendered at all", + openspace::properties::Property::Visibility::AdvancedUser + }; + + constexpr openspace::properties::Property::PropertyInfo UseNoDataColorInfo = { + "ShowMissingData", + "Show Missing Data", + "If true, use a separate color (see NoDataColor) for items with values " + "corresponding to missing data values", + openspace::properties::Property::Visibility::User + }; + + constexpr openspace::properties::Property::PropertyInfo NoDataColorInfo = { + "NoDataColor", + "No Data Color", + "The color to use for items with values corresponding to missing data values, " + "if enabled. This color can also be read from the color map, but setting this " + "value overrides any value in the color map. If a color value for the below " + "range values is provided, the ShowMissingData property will automatically be " + "set to true", + openspace::properties::Property::Visibility::User + }; + + constexpr openspace::properties::Property::PropertyInfo UseAboveRangeColorInfo = { + "UseAboveRangeColor", + "Use Above Range Color", + "If true, use a separate color (see AboveRangeColor) for items with values " + "larger than the one in the provided data range. Otherwise, the values will " + "be clamped to use the color at the upper limit of the color map. If a color is " + "provided in the color map, this value will automatically be set to true", + openspace::properties::Property::Visibility::AdvancedUser + }; + + constexpr openspace::properties::Property::PropertyInfo AboveRangeColorInfo = { + "AboveRangeColor", + "Above Range Color", + "The color to use for items with values larger than the one in the provided " + "data range, if enabled. This color can also be read from the color map, but " + "setting this value overrides any value in the color map. If a color value for " + "the above range values is provided, the UseAboveRangeColor property will " + "automatically be set to true", + openspace::properties::Property::Visibility::AdvancedUser + }; + + constexpr openspace::properties::Property::PropertyInfo UseBelowRangeColorInfo = { + "UseBelowRangeColor", + "Use Below Range Color", + "If true, use a separate color (see BelowRangeColor) for items with values " + "smaller than the one in the provided data range. Otherwise, the values will " + "be clamped to use the color at the lower limit of the color map. If a color is " + "provided in the color map, this value will automatically be set to true", + openspace::properties::Property::Visibility::AdvancedUser + }; + + constexpr openspace::properties::Property::PropertyInfo BelowRangeColorInfo = { + "BelowRangeColor", + "Below Range Color", + "The color to use for items with values smaller than the one in the provided " + "data range, if enabled. This color can also be read from the color map, but " + "setting this value overrides any value in the color map. If a color value for " + "the below range values is provided, the UseBelowRangeColor property will " + "automatically be set to true", + openspace::properties::Property::Visibility::AdvancedUser + }; + + struct [[codegen::Dictionary(ColorMappingComponent)]] Parameters { + // [[codegen::verbatim(EnabledInfo.description)]] + std::optional enabled; + + // [[codegen::verbatim(FileInfo.description)]] + std::optional file; + + struct ColorMapParameter { + // The key for the data variable to use for color + std::string key; + + // An optional value range to use for coloring when this option is selected. + // If not included, the range will be set from the min and max value in the + // dataset + std::optional range; + }; + // A list of options for color parameters to use for color mapping, that will + // appear as options in the drop-down menu in the user interface. Per default, + // the first option in the list is selected. Each option is a table in the form + // { Key = \"theKey\", Range = {min, max} }, where the value range is optional. + // If added, this range will automatically be set when the option is selected + std::optional> parameterOptions; + + // [[codegen::verbatim(ParameterInfo.description)]] + std::optional parameter; + + // [[codegen::verbatim(RangeInfo.description)]] + std::optional valueRange; + + // [[codegen::verbatim(HideOutsideInfo.description)]] + std::optional hideValuesOutsideRange; + + // [[codegen::verbatim(UseNoDataColorInfo.description)]] + std::optional showMissingData; + + // [[codegen::verbatim(NoDataColorInfo.description)]] + std::optional noDataColor [[codegen::color()]]; + + // [[codegen::verbatim(UseAboveRangeColorInfo.description)]] + std::optional useAboveRangeColor; + + // [[codegen::verbatim(AboveRangeColorInfo.description)]] + std::optional aboveRangeColor [[codegen::color()]]; + + // [[codegen::verbatim(UseBelowRangeColorInfo.description)]] + std::optional useBelowRangeColor; + + // [[codegen::verbatim(BelowRangeColorInfo.description)]] + std::optional belowRangeColor [[codegen::color()]]; + }; +#include "colormappingcomponent_codegen.cpp" +} // namespace + +namespace openspace { + +documentation::Documentation ColorMappingComponent::Documentation() { + return codegen::doc("colormappingcomponent"); +} + +ColorMappingComponent::ColorMappingComponent() + : properties::PropertyOwner({ "ColorMapping", "Color Mapping", "" }) + , enabled(EnabledInfo, true) + , dataColumn(ParameterInfo, properties::OptionProperty::DisplayType::Dropdown) + , colorMapFile(FileInfo) + , valueRange(RangeInfo, glm::vec2(0.f)) + , setRangeFromData(SetRangeFromDataInfo) + , hideOutsideRange(HideOutsideInfo, false) + , useNanColor(UseNoDataColorInfo, false) + , nanColor( + NoDataColorInfo, + glm::vec4(0.5f, 0.5f, 0.5f, 1.f), + glm::vec4(0.f), + glm::vec4(1.f) + ) + , useAboveRangeColor(UseAboveRangeColorInfo, false) + , aboveRangeColor(AboveRangeColorInfo, glm::vec4(1.f), glm::vec4(0.f), glm::vec4(1.f)) + , useBelowRangeColor(UseBelowRangeColorInfo, false) + , belowRangeColor(BelowRangeColorInfo, glm::vec4(1.f), glm::vec4(0.f), glm::vec4(1.f)) +{ + addProperty(enabled); + addProperty(dataColumn); + + addProperty(valueRange); + addProperty(setRangeFromData); + + colorMapFile.setReadOnly(true); // Currently this can't be changed + addProperty(colorMapFile); + + addProperty(hideOutsideRange); + addProperty(useNanColor); + nanColor.setViewOption(properties::Property::ViewOptions::Color); + addProperty(nanColor); + + addProperty(useAboveRangeColor); + aboveRangeColor.setViewOption(properties::Property::ViewOptions::Color); + addProperty(aboveRangeColor); + + addProperty(useBelowRangeColor); + belowRangeColor.setViewOption(properties::Property::ViewOptions::Color); + addProperty(belowRangeColor); +} + +ColorMappingComponent::ColorMappingComponent(const ghoul::Dictionary& dictionary) + : ColorMappingComponent() +{ + const Parameters p = codegen::bake(dictionary); + + enabled = p.enabled.value_or(enabled); + + if (p.parameterOptions.has_value()) { + std::vector opts = *p.parameterOptions; + + _colorRangeData.reserve(opts.size()); + for (size_t i = 0; i < opts.size(); ++i) { + dataColumn.addOption(static_cast(i), opts[i].key); + // Add the provided range or an empty range. We will fill it later on, + // when the dataset is loaded, if it is empty + _colorRangeData.push_back(opts[i].range.value_or(glm::vec2(0.f))); + } + } + + dataColumn.onChange([this]() { + valueRange = _colorRangeData[dataColumn.value()]; + }); + + _providedParameter = p.parameter; + _providedRange = p.valueRange; + + hideOutsideRange = p.hideValuesOutsideRange.value_or(hideOutsideRange); + + useNanColor = p.showMissingData.value_or(useNanColor); + if (p.noDataColor.has_value()) { + useNanColor = p.showMissingData.value_or(true); + nanColor = *p.noDataColor; + _hasNanColorInAsset = true; + } + + useAboveRangeColor = p.useAboveRangeColor.value_or(useAboveRangeColor); + if (p.aboveRangeColor.has_value()) { + useAboveRangeColor = p.useAboveRangeColor.value_or(true); + aboveRangeColor = *p.aboveRangeColor; + _hasAboveRangeColorInAsset = true; + } + + useBelowRangeColor = p.useBelowRangeColor.value_or(useBelowRangeColor); + if (p.belowRangeColor.has_value()) { + useBelowRangeColor = p.useBelowRangeColor.value_or(true); + belowRangeColor = *p.belowRangeColor; + _hasBelowRangeColorInAsset = true; + } + + if (p.file.has_value()) { + colorMapFile = absPath(*p.file).string(); + } +} + +ghoul::opengl::Texture* ColorMappingComponent::texture() const { + return _texture.get(); +} + +void ColorMappingComponent::initialize(const dataloader::Dataset& dataset) { + _colorMap = dataloader::color::loadFileWithCache(colorMapFile.value()); + + initializeParameterData(dataset); + + if (_colorMap.nanColor.has_value() && !_hasNanColorInAsset) { + nanColor = *_colorMap.nanColor; + useNanColor = true; // @ TODO: Avoid overriding value set in asset? (also for useBelow and useAbove) + } + + if (_colorMap.belowRangeColor.has_value() && !_hasBelowRangeColorInAsset) { + belowRangeColor = *_colorMap.belowRangeColor; + useBelowRangeColor = true; + } + + if (_colorMap.aboveRangeColor.has_value() && !_hasAboveRangeColorInAsset) { + aboveRangeColor = *_colorMap.aboveRangeColor; + useAboveRangeColor = true; + } +} + +void ColorMappingComponent::initializeTexture() { + if (_colorMap.entries.empty()) { + return; + } + + unsigned int width = static_cast(_colorMap.entries.size()); + unsigned int height = 1; + unsigned int size = width * height; + std::vector img; + img.reserve(size * 4); + + for (const glm::vec4& c : _colorMap.entries) { + img.push_back(static_cast(255 * c.r)); + img.push_back(static_cast(255 * c.g)); + img.push_back(static_cast(255 * c.b)); + img.push_back(static_cast(255 * c.a)); + } + + _texture = std::make_unique( + glm::uvec3(width, height, 1), + GL_TEXTURE_1D, + ghoul::opengl::Texture::Format::RGBA + + ); + + // TODO: update this for linear mapping? + _texture->setFilter(ghoul::opengl::Texture::FilterMode::Nearest); + _texture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge); + _texture->setPixelData( + reinterpret_cast(img.data()), + ghoul::opengl::Texture::TakeOwnership::No + ); + + _texture->uploadTexture(); +} + +glm::vec4 ColorMappingComponent::colorFromColorMap(float valueToColorFrom) const { + glm::vec2 currentColorRange = valueRange; + float cmax = currentColorRange.y; + float cmin = currentColorRange.x; + + float nColors = static_cast(_colorMap.entries.size()); + + bool isOutsideMin = valueToColorFrom < cmin; + bool isOutsideMax = valueToColorFrom > cmax; + + if (hideOutsideRange && (isOutsideMin || isOutsideMax)) { + return glm::vec4(0.f); + } + + if (useNanColor && std::isnan(valueToColorFrom)) { + return nanColor; + } + + // Find color value using Nearest neighbor (same as texture) + float normalization = (cmax != cmin) ? (nColors) / (cmax - cmin) : 0; + int colorIndex = static_cast((valueToColorFrom - cmin) * normalization); + + // Clamp color index to valid range + colorIndex = std::max(colorIndex, 0); + colorIndex = std::min(colorIndex, static_cast(nColors) - 1); + + return _colorMap.entries[colorIndex]; +} + +void ColorMappingComponent::initializeParameterData(const dataloader::Dataset& dataset) { + // Initialize empty ranges based on values in the dataset + for (const properties::OptionProperty::Option& option : dataColumn.options()) { + int optionIndex = option.value; + int colorParameterIndex = dataset.index(option.description); + + glm::vec2& range = _colorRangeData[optionIndex]; + if (glm::length(range) < glm::epsilon()) { + range = dataset.findValueRange(colorParameterIndex); + } + } + + // Index to keep track of the potentially provided default option for the parameter + int indexOfProvidedOption = -1; + + // If no options were added, add each dataset parameter and its range as options + if (dataColumn.options().empty() && !dataset.entries.empty()) { + int i = 0; + _colorRangeData.reserve(dataset.variables.size()); + for (const dataloader::Dataset::Variable& v : dataset.variables) { + dataColumn.addOption(i, v.name); + _colorRangeData.push_back(dataset.findValueRange(v.index)); + + // While iterating over options, try to find the one provided, if any + if (_providedParameter.has_value() && *_providedParameter == v.name) { + indexOfProvidedOption = i; + } + + i++; + } + } + else { + // Otherwise, check if the selected columns exist + for (size_t i = 0; i < dataColumn.options().size(); ++i) { + std::string o = dataColumn.options()[i].description; + + bool found = false; + for (const dataloader::Dataset::Variable& v : dataset.variables) { + if (v.name == o) { + found = true; + break; + } + } + + if (!found) { + LWARNING(fmt::format( + "Dataset does not contain specified parameter '{}'", o + )); + } + // While iterating over options, try to find the one provided, if any + else if (_providedParameter.has_value() && *_providedParameter == o) { + indexOfProvidedOption = i; + } + } + } + + if (_providedParameter.has_value()) { + if (indexOfProvidedOption == -1) { + LERROR(fmt::format( + "Error when reading Parameter. Could not find provided parameter '{}' in " + "list of parameter options", *_providedParameter + )); + } + else { + dataColumn = indexOfProvidedOption; + } + } + + // Set the value range to correspond to the selected data column, or the one set by + // the user + if (_providedRange.has_value()) { + valueRange = *_providedRange; + } + else { + valueRange = _colorRangeData[dataColumn.value()]; + } +} + +} // namespace openspace diff --git a/modules/space/labelscomponent.cpp b/src/rendering/labelscomponent.cpp similarity index 92% rename from modules/space/labelscomponent.cpp rename to src/rendering/labelscomponent.cpp index 3beb097f64..983d5c8285 100644 --- a/modules/space/labelscomponent.cpp +++ b/src/rendering/labelscomponent.cpp @@ -22,7 +22,7 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include #include #include @@ -107,6 +107,12 @@ namespace { // [[codegen::verbatim(FileInfo.description)]] std::filesystem::path file; + // If true (default), the loaded labels file will be cached so that it can be + // loaded faster at a later time. Note that this also means that changes in the + // file will not be registered until the cached file is deleted. Set to false + // to disable chaching and always do a fresh load of the label file + std::optional useCaching; + // The opacity of the labels std::optional opacity [[codegen::inrange(0.0, 1.0)]]; @@ -145,7 +151,7 @@ namespace { namespace openspace { documentation::Documentation LabelsComponent::Documentation() { - return codegen::doc("space_labelscomponent"); + return codegen::doc("labelscomponent"); } LabelsComponent::LabelsComponent(const ghoul::Dictionary& dictionary) @@ -165,6 +171,7 @@ LabelsComponent::LabelsComponent(const ghoul::Dictionary& dictionary) const Parameters p = codegen::bake(dictionary); _labelFile = absPath(p.file); + _useCache = p.useCaching.value_or(true); if (p.unit.has_value()) { _unit = codegen::map(*p.unit); @@ -216,11 +223,11 @@ LabelsComponent::LabelsComponent(const ghoul::Dictionary& dictionary) _transformationMatrix = p.transformationMatrix.value_or(_transformationMatrix); } -speck::Labelset& LabelsComponent::labelSet() { +dataloader::Labelset& LabelsComponent::labelSet() { return _labelset; } -const speck::Labelset& LabelsComponent::labelSet() const { +const dataloader::Labelset& LabelsComponent::labelSet() const { return _labelset; } @@ -235,7 +242,12 @@ void LabelsComponent::initialize() { void LabelsComponent::loadLabels() { LINFO(fmt::format("Loading label file {}", _labelFile)); - _labelset = speck::label::loadFileWithCache(_labelFile); + if (_useCache) { + _labelset = dataloader::label::loadFileWithCache(_labelFile); + } + else { + _labelset = dataloader::label::loadFile(_labelFile); + } } bool LabelsComponent::isReady() const { @@ -273,7 +285,7 @@ void LabelsComponent::render(const RenderData& data, glm::vec4 textColor = glm::vec4(glm::vec3(_color), opacity() * fadeInVariable); - for (const speck::Labelset::Entry& e : _labelset.entries) { + for (const dataloader::Labelset::Entry& e : _labelset.entries) { if (!e.isEnabled) { continue; } From 9c77a1226992d22670a49768ae937fd9b11e7369 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Wed, 20 Dec 2023 08:28:07 +0100 Subject: [PATCH 03/30] Issue/2665 - Show timer for how long time left in camera path (#2980) * Add a camera path topic and compute remaining time in path * Remove unused parameter in function * Include speed scale in estimation of time the path will take * Includes cleanup and address review comments * Round instead of ceil, to make countdown reach 0 in most cases * Update GUI hash --- data/assets/util/webgui.asset | 2 +- include/openspace/navigation/path.h | 22 +++- include/openspace/navigation/pathnavigator.h | 5 +- modules/server/CMakeLists.txt | 2 + .../server/include/topics/camerapathtopic.h | 55 +++++++++ modules/server/include/topics/cameratopic.h | 2 +- .../server/include/topics/skybrowsertopic.h | 2 +- modules/server/include/topics/timetopic.h | 2 +- modules/server/src/connection.cpp | 2 + modules/server/src/topics/camerapathtopic.cpp | 113 ++++++++++++++++++ modules/server/src/topics/cameratopic.cpp | 8 +- src/navigation/path.cpp | 40 ++++--- src/navigation/pathnavigator.cpp | 12 +- 13 files changed, 237 insertions(+), 30 deletions(-) create mode 100644 modules/server/include/topics/camerapathtopic.h create mode 100644 modules/server/src/topics/camerapathtopic.cpp diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index 19d82a7ee5..566f87adff 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -4,7 +4,7 @@ local guiCustomization = asset.require("customization/gui") -- Select which commit hashes to use for the frontend and backend -local frontendHash = "a2139b8cf589daf846fb3ef3f4953bc591e66dcb" +local frontendHash = "563b65b3043f798c9efe76787454c38ccccd2aaf" local frontend = asset.resource({ Identifier = "WebGuiFrontend", diff --git a/include/openspace/navigation/path.h b/include/openspace/navigation/path.h index 5be7c88fca..6371cd0633 100644 --- a/include/openspace/navigation/path.h +++ b/include/openspace/navigation/path.h @@ -53,7 +53,7 @@ public: }; Path(Waypoint start, Waypoint end, Type type, - std::optional duration = std::nullopt); + std::optional duration = std::nullopt); Waypoint startPoint() const; Waypoint endPoint() const; @@ -63,6 +63,21 @@ public: */ double pathLength() const; + /** + * Return the remaining distance to traverse, in meters. + */ + double remainingDistance() const; + + /** + * Estimate a value for the remaining time to reach the target, based on the + * currently progressed time and the estimation for how long the path will + * take to traverse. Note that the computation is not exact. + * + * \param speedScale The speed scale factor that may affect how fast the camera moves + * \return The estimated remaining time + */ + float estimatedRemainingTime(float speedScale) const; + /** * Return a vector of positions corresponding to the control points of the path's * spline curve. @@ -170,11 +185,12 @@ private: std::unique_ptr _curve; - double _speedFactorFromDuration = 1.0; + float _speedFactorFromDuration = 1.f; + float _expectedDuration = 0.f; // Playback variables double _traveledDistance = 0.0; // Meters - double _progressedTime = 0.0; // Time since playback started (seconds) + float _progressedTime = 0.f; // Time since playback started (seconds) bool _shouldQuit = false; CameraPose _prevPose; }; diff --git a/include/openspace/navigation/pathnavigator.h b/include/openspace/navigation/pathnavigator.h index 1cd6082035..a8d1897cac 100644 --- a/include/openspace/navigation/pathnavigator.h +++ b/include/openspace/navigation/pathnavigator.h @@ -64,6 +64,9 @@ public: bool hasCurrentPath() const; bool hasFinished() const; bool isPlayingPath() const; + bool isPaused() const; + + float estimatedRemainingTimeInPath() const; void updateCamera(double deltaTime); void createPath(const ghoul::Dictionary& dictionary); @@ -102,7 +105,7 @@ private: */ void findRelevantNodes(); - void removeRollRotation(CameraPose& pose, double deltaTime); + void removeRollRotation(CameraPose& pose); std::unique_ptr _currentPath = nullptr; bool _isPlaying = false; diff --git a/modules/server/CMakeLists.txt b/modules/server/CMakeLists.txt index 2b17c10d38..3ce2d56ff8 100644 --- a/modules/server/CMakeLists.txt +++ b/modules/server/CMakeLists.txt @@ -33,6 +33,7 @@ set(HEADER_FILES include/serverinterface.h include/topics/authorizationtopic.h include/topics/bouncetopic.h + include/topics/camerapathtopic.h include/topics/cameratopic.h include/topics/documentationtopic.h include/topics/enginemodetopic.h @@ -60,6 +61,7 @@ set(SOURCE_FILES src/serverinterface.cpp src/topics/authorizationtopic.cpp src/topics/bouncetopic.cpp + src/topics/camerapathtopic.cpp src/topics/cameratopic.cpp src/topics/documentationtopic.cpp src/topics/enginemodetopic.cpp diff --git a/modules/server/include/topics/camerapathtopic.h b/modules/server/include/topics/camerapathtopic.h new file mode 100644 index 0000000000..58c4d3ba36 --- /dev/null +++ b/modules/server/include/topics/camerapathtopic.h @@ -0,0 +1,55 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2023 * + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_SERVER___CAMERAPATHTOPIC___H__ +#define __OPENSPACE_MODULE_SERVER___CAMERAPATHTOPIC___H__ + +#include +#include + +namespace openspace { + +class CameraPathTopic : public Topic { +public: + CameraPathTopic(); + ~CameraPathTopic() override; + + void handleJson(const nlohmann::json& json) override; + bool isDone() const override; + +private: + static constexpr int UnsetOnChangeHandle = -1; + + void sendCameraPathData(); + + int _dataCallbackHandle = UnsetOnChangeHandle; + bool _isDone = false; + std::chrono::system_clock::time_point _lastUpdateTime; + + std::chrono::milliseconds _cameraPathUpdateTime = std::chrono::milliseconds(100); +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_SERVER___CAMERAPATHTOPIC___H__ diff --git a/modules/server/include/topics/cameratopic.h b/modules/server/include/topics/cameratopic.h index 6aada0f62d..5cc4d60d81 100644 --- a/modules/server/include/topics/cameratopic.h +++ b/modules/server/include/topics/cameratopic.h @@ -39,7 +39,7 @@ public: bool isDone() const override; private: - const int UnsetOnChangeHandle = -1; + static constexpr int UnsetOnChangeHandle = -1; void sendCameraData(); diff --git a/modules/server/include/topics/skybrowsertopic.h b/modules/server/include/topics/skybrowsertopic.h index 312e68e70e..c9e8165277 100644 --- a/modules/server/include/topics/skybrowsertopic.h +++ b/modules/server/include/topics/skybrowsertopic.h @@ -39,7 +39,7 @@ public: bool isDone() const override; private: - const int UnsetOnChangeHandle = -1; + static constexpr int UnsetOnChangeHandle = -1; void sendBrowserData(); diff --git a/modules/server/include/topics/timetopic.h b/modules/server/include/topics/timetopic.h index af01e72ed3..d1f4e0be9d 100644 --- a/modules/server/include/topics/timetopic.h +++ b/modules/server/include/topics/timetopic.h @@ -39,7 +39,7 @@ public: bool isDone() const override; private: - const int UnsetOnChangeHandle = -1; + static constexpr int UnsetOnChangeHandle = -1; const nlohmann::json getNextPrevDeltaTimeStepJson(); diff --git a/modules/server/src/connection.cpp b/modules/server/src/connection.cpp index 5ed46e0eed..8e6dfc1c01 100644 --- a/modules/server/src/connection.cpp +++ b/modules/server/src/connection.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -99,6 +100,7 @@ Connection::Connection(std::unique_ptr s, std::string address _topicFactory.registerClass("version"); _topicFactory.registerClass("skybrowser"); _topicFactory.registerClass("camera"); + _topicFactory.registerClass("cameraPath"); } void Connection::handleMessage(const std::string& message) { diff --git a/modules/server/src/topics/camerapathtopic.cpp b/modules/server/src/topics/camerapathtopic.cpp new file mode 100644 index 0000000000..f1b98e4439 --- /dev/null +++ b/modules/server/src/topics/camerapathtopic.cpp @@ -0,0 +1,113 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2023 * + * * + * 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. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + constexpr std::string_view SubscribeEvent = "start_subscription"; +} // namespace + +using nlohmann::json; + +namespace openspace { + +CameraPathTopic::CameraPathTopic() + : _lastUpdateTime(std::chrono::system_clock::now()) +{} + +CameraPathTopic::~CameraPathTopic() { + if (_dataCallbackHandle != UnsetOnChangeHandle) { + ServerModule* module = global::moduleEngine->module(); + if (module) { + module->removePreSyncCallback(_dataCallbackHandle); + } + } +} + +bool CameraPathTopic::isDone() const { + return _isDone; +} + +void CameraPathTopic::handleJson(const nlohmann::json& json) { + std::string event = json.at("event").get(); + + if (event != SubscribeEvent) { + _isDone = true; + return; + } + + ServerModule* module = global::moduleEngine->module(); + _dataCallbackHandle = module->addPreSyncCallback( + [this]() { + bool isInPath = (global::openSpaceEngine->currentMode() + == OpenSpaceEngine::Mode::CameraPath); + + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + if (isInPath && (now - _lastUpdateTime) > _cameraPathUpdateTime) { + sendCameraPathData(); + _lastUpdateTime = std::chrono::system_clock::now(); + } + } + ); +} + +void CameraPathTopic::sendCameraPathData() { + const interaction::PathNavigator& pathNavigator = + global::navigationHandler->pathNavigator(); + + const interaction::Path* path = pathNavigator.currentPath(); + + if (!path) { + ghoul_assert(path, "Path must exist"); + return; + } + + // The time is not exact, and we only care about the number of seconds. Also, + // any negative values should be interpreted as positive + int seconds = static_cast( + std::round(pathNavigator.estimatedRemainingTimeInPath()) + ); + seconds = std::max(seconds, 0); + + nlohmann::json jsonData = { + { "target", path->endPoint().nodeIdentifier() }, + { "remainingTime", seconds }, + //{ "remainingDistance", path->remainingDistance() }, + { "isPaused", pathNavigator.isPaused() } + }; + + _connection->sendJson(wrappedPayload(jsonData)); +} + +} // namespace openspace diff --git a/modules/server/src/topics/cameratopic.cpp b/modules/server/src/topics/cameratopic.cpp index 2dc5b6a01e..8170ec2b2c 100644 --- a/modules/server/src/topics/cameratopic.cpp +++ b/modules/server/src/topics/cameratopic.cpp @@ -22,16 +22,14 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include "modules/server/include/topics/cameratopic.h" +#include +#include #include #include -#include -#include #include #include #include -#include #include #include @@ -81,8 +79,6 @@ void CameraTopic::handleJson(const nlohmann::json& json) { } void CameraTopic::sendCameraData() { - using namespace openspace; - GlobeBrowsingModule* module = global::moduleEngine->module(); glm::dvec3 position = module->geoPosition(); std::pair altSimplified = simplifyDistance(position.z); diff --git a/src/navigation/path.cpp b/src/navigation/path.cpp index a796b46595..abeb9ec85c 100644 --- a/src/navigation/path.cpp +++ b/src/navigation/path.cpp @@ -102,7 +102,7 @@ documentation::Documentation Path::Documentation() { return codegen::doc("core_path_instruction"); } -Path::Path(Waypoint start, Waypoint end, Type type, std::optional duration) +Path::Path(Waypoint start, Waypoint end, Type type, std::optional duration) : _start(start) , _end(end) , _type(type) @@ -122,25 +122,29 @@ Path::Path(Waypoint start, Waypoint end, Type type, std::optional durati _prevPose = _start.pose(); - // Compute speed factor to match any given duration, by traversing the path and - // computing how much faster/slower it should be + // Estimate how long time the camera path will take to traverse + constexpr double dt = 0.05; // 20 fps + while (!hasReachedEnd()) { + traversePath(dt); + } + float estimatedDuration = _progressedTime; + resetPlaybackVariables(); + + // We now know how long it took to traverse the path. Use that to compute the + // speed factor to match any given duration _speedFactorFromDuration = 1.0; if (duration.has_value()) { if (*duration > 0.0) { - constexpr double dt = 0.05; // 20 fps - while (!hasReachedEnd()) { - traversePath(dt); - } - - // We now know how long it took to traverse the path. Use that - _speedFactorFromDuration = _progressedTime / *duration; - resetPlaybackVariables(); + _speedFactorFromDuration = estimatedDuration / *duration; + estimatedDuration = *duration; } else { // A duration of zero means infinite speed. Handle this explicity - _speedFactorFromDuration = std::numeric_limits::infinity(); + _speedFactorFromDuration = std::numeric_limits::infinity(); + estimatedDuration = 0.f; } } + _expectedDuration = estimatedDuration; } Waypoint Path::startPoint() const { @@ -155,6 +159,14 @@ double Path::pathLength() const { return _curve->length(); } +double Path::remainingDistance() const { + return pathLength() - _traveledDistance; +} + +float Path::estimatedRemainingTime(float speedScale) const { + return _expectedDuration / speedScale - _progressedTime; +} + std::vector Path::controlPoints() const { return _curve->points(); } @@ -173,7 +185,7 @@ CameraPose Path::traversePath(double dt, float speedScale) { const double prevDistance = _traveledDistance; - _progressedTime += dt; + _progressedTime += static_cast(dt); _traveledDistance += displacement; CameraPose newPose; @@ -306,7 +318,7 @@ glm::dquat Path::easedSlerpRotation(double t) const { return glm::slerp(_start.rotation(), _end.rotation(), tScaled); } -glm::dquat Path::linearPathRotation(double t) const { +glm::dquat Path::linearPathRotation(double) const { const glm::dvec3 a = ghoul::viewDirection(_start.rotation()); const glm::dvec3 b = ghoul::viewDirection(_end.rotation()); const double angle = std::acos(glm::dot(a, b)); // assumes length 1.0 for a & b diff --git a/src/navigation/pathnavigator.cpp b/src/navigation/pathnavigator.cpp index a937ec4af5..21bed27223 100644 --- a/src/navigation/pathnavigator.cpp +++ b/src/navigation/pathnavigator.cpp @@ -208,6 +208,14 @@ bool PathNavigator::isPlayingPath() const { return hasCurrentPath() && _isPlaying; } +bool PathNavigator::isPaused() const { + return hasCurrentPath() && !_isPlaying; +} + +float PathNavigator::estimatedRemainingTimeInPath() const { + return hasCurrentPath() ? _currentPath->estimatedRemainingTime(_speedScale) : 0.f; +} + void PathNavigator::updateCamera(double deltaTime) { ghoul_assert(camera() != nullptr, "Camera must not be nullptr"); @@ -257,7 +265,7 @@ void PathNavigator::updateCamera(double deltaTime) { } if (!_includeRoll) { - removeRollRotation(newPose, deltaTime); + removeRollRotation(newPose); } camera()->setPose(newPose); @@ -537,7 +545,7 @@ SceneGraphNode* PathNavigator::findNodeNearTarget(const SceneGraphNode* node) { return nullptr; } -void PathNavigator::removeRollRotation(CameraPose& pose, double deltaTime) { +void PathNavigator::removeRollRotation(CameraPose& pose) { // The actual position for the camera does not really matter. Use the origin, // to avoid precision problems when we have large values for the position const glm::dvec3 cameraPos = glm::dvec3(0.0); From 8a1b6aceb2182437f2f95af2908a003d1ec95b72 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Wed, 20 Dec 2023 08:28:21 +0100 Subject: [PATCH 04/30] Keep track of aim from navigations state when creating a camera path (#2981) --- include/openspace/navigation/waypoint.h | 6 ++++++ src/navigation/pathnavigator.cpp | 20 ++++++++++++++++++-- src/navigation/waypoint.cpp | 14 ++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/include/openspace/navigation/waypoint.h b/include/openspace/navigation/waypoint.h index 57dca42b10..3a12dd39d2 100644 --- a/include/openspace/navigation/waypoint.h +++ b/include/openspace/navigation/waypoint.h @@ -47,6 +47,7 @@ public: glm::dquat rotation() const; SceneGraphNode* node() const; std::string nodeIdentifier() const; + std::optional aimIdentifier() const; double validBoundingSphere() const; private: @@ -54,6 +55,11 @@ private: std::string _nodeIdentifier; // To be able to handle nodes with faulty bounding spheres double _validBoundingSphere = 0.0; + + // Keep track of if there was an aim node, specified in for example the + // navigation state used to create this waypoint. It may be required in + // certain situations + std::optional _aimNodeIdentifier; }; /** diff --git a/src/navigation/pathnavigator.cpp b/src/navigation/pathnavigator.cpp index 21bed27223..f7d4eae85f 100644 --- a/src/navigation/pathnavigator.cpp +++ b/src/navigation/pathnavigator.cpp @@ -236,11 +236,19 @@ void PathNavigator::updateCamera(double deltaTime) { if (_setCameraToEndNextFrame) { LDEBUG("Skipped to end of camera path"); _currentPath->quitPath(); - camera()->setPose(_currentPath->endPoint().pose()); + + const interaction::Waypoint endPoint = _currentPath->endPoint(); + camera()->setPose(endPoint.pose()); global::navigationHandler->orbitalNavigator().setFocusNode( - _currentPath->endPoint().nodeIdentifier(), + endPoint.nodeIdentifier(), false ); + if (endPoint.aimIdentifier().has_value()) { + global::navigationHandler->orbitalNavigator().setAimNode( + *endPoint.aimIdentifier() + ); + } + handlePathEnd(); _setCameraToEndNextFrame = false; return; @@ -272,6 +280,14 @@ void PathNavigator::updateCamera(double deltaTime) { if (_currentPath->hasReachedEnd()) { LINFO("Reached target"); + + // Also set the aim once the path is finished, if one should be set + if (_currentPath->endPoint().aimIdentifier().has_value()) { + global::navigationHandler->orbitalNavigator().setAimNode( + *_currentPath->endPoint().aimIdentifier() + ); + } + handlePathEnd(); return; } diff --git a/src/navigation/waypoint.cpp b/src/navigation/waypoint.cpp index c7f1b86286..1b0f929a62 100644 --- a/src/navigation/waypoint.cpp +++ b/src/navigation/waypoint.cpp @@ -67,6 +67,16 @@ Waypoint::Waypoint(const NavigationState& ns) { } _nodeIdentifier = ns.anchor; + + if (!ns.aim.empty()) { + const SceneGraphNode* aimNode = sceneGraphNode(ns.aim); + if (!aimNode) { + LERROR(fmt::format("Could not find node '{}' to use as aim", ns.aim)); + return; + } + _aimNodeIdentifier = ns.aim; + } + const PathNavigator& navigator = global::navigationHandler->pathNavigator(); _validBoundingSphere = navigator.findValidBoundingSphere(anchorNode); _pose = ns.cameraPose(); @@ -92,6 +102,10 @@ std::string Waypoint::nodeIdentifier() const { return _nodeIdentifier; } +std::optional Waypoint::aimIdentifier() const { + return _aimNodeIdentifier; +} + double Waypoint::validBoundingSphere() const { return _validBoundingSphere; } From af5ebd77310b110db1fbebff82161229fee98c40 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Wed, 20 Dec 2023 08:28:34 +0100 Subject: [PATCH 05/30] Issue/2949 - Fix for camera transition events (#2982) * Fix variable name typo * Update transitions to not care about which sphere we were previously in * Also handle when anchor node changes * Remove log messages used for testing, and unused variable * Update src/navigation/navigationhandler.cpp Co-authored-by: Alexander Bock --------- Co-authored-by: Alexander Bock --- .../openspace/navigation/navigationhandler.h | 2 +- src/navigation/navigationhandler.cpp | 222 +++++++++++------- 2 files changed, 135 insertions(+), 89 deletions(-) diff --git a/include/openspace/navigation/navigationhandler.h b/include/openspace/navigation/navigationhandler.h index ebec211fd3..267d85507d 100644 --- a/include/openspace/navigation/navigationhandler.h +++ b/include/openspace/navigation/navigationhandler.h @@ -181,9 +181,9 @@ private: Camera* _camera = nullptr; std::function _playbackEndCallback; - static constexpr double InteractionHystersis = 0.0125; bool _inAnchorApproachSphere = false; bool _inAnchorReachSphere = false; + const SceneGraphNode* _lastAnchor = nullptr; OrbitalNavigator _orbitalNavigator; KeyframeNavigator _keyframeNavigator; diff --git a/src/navigation/navigationhandler.cpp b/src/navigation/navigationhandler.cpp index 5c0de14a84..5e53fe519f 100644 --- a/src/navigation/navigationhandler.cpp +++ b/src/navigation/navigationhandler.cpp @@ -183,6 +183,7 @@ void NavigationHandler::updateCamera(double deltaTime) { // If there is a state to set, do so immediately and then return if (_pendingState.has_value()) { applyPendingState(); + updateCameraTransitions(); return; } @@ -268,97 +269,25 @@ void NavigationHandler::updateCameraTransitions() { const double af = anchorNode()->approachFactor(); const double rf = anchorNode()->reachFactor(); - using namespace std::string_literals; - if (_inAnchorApproachSphere) { - if (currDistance > d * (af + InteractionHystersis)) { - // We left the approach sphere outwards - _inAnchorApproachSphere = false; + // Updated checks compared to last time, so we can check if we are still in the + // approach or anchor sphere + bool isInApproachSphere = currDistance < d * af; + bool isInReachSphere = currDistance < d * rf; - if (!anchorNode()->onExitAction().empty()) { - ghoul::Dictionary dict; - dict.setValue("Node", anchorNode()->identifier()); - dict.setValue("Transition", "Exiting"s); - for (const std::string& action : anchorNode()->onExitAction()) { - // No sync because events are always synced and sent to the connected - // nodes and peers - global::actionManager->triggerAction( - action, - dict, - interaction::ActionManager::ShouldBeSynchronized::No - ); - } - } + // Compare these to the values from last frame, to trigger the correct transition + // events + bool wasInApproachSphere = _inAnchorApproachSphere; + bool wasInReachSphere = _inAnchorReachSphere; + _inAnchorApproachSphere = isInApproachSphere; + _inAnchorReachSphere = isInReachSphere; - global::eventEngine->publishEvent( - _camera, - anchorNode(), - events::EventCameraFocusTransition::Transition::Exiting - ); - } - else if (currDistance < d * (rf - InteractionHystersis)) { - // We transitioned from the approach sphere into the reach sphere - _inAnchorApproachSphere = false; - _inAnchorReachSphere = true; - - if (!anchorNode()->onReachAction().empty()) { - ghoul::Dictionary dict; - dict.setValue("Node", anchorNode()->identifier()); - dict.setValue("Transition", "Reaching"s); - for (const std::string& action : anchorNode()->onReachAction()) { - // No sync because events are always synced and sent to the connected - // nodes and peers - global::actionManager->triggerAction( - action, - dict, - interaction::ActionManager::ShouldBeSynchronized::No - ); - } - } - - global::eventEngine->publishEvent( - _camera, - anchorNode(), - events::EventCameraFocusTransition::Transition::Reaching - ); - } - } - else if (_inAnchorReachSphere && currDistance > d * (rf + InteractionHystersis)) { - // We transitioned from the reach sphere to the approach sphere - _inAnchorReachSphere = false; - _inAnchorApproachSphere = true; - - if (!anchorNode()->onRecedeAction().empty()) { + auto triggerApproachEvent = [this](const SceneGraphNode* node) { + using namespace std::string_literals; + if (!node->onApproachAction().empty()) { ghoul::Dictionary dict; - dict.setValue("Node", anchorNode()->identifier()); - dict.setValue("Transition", "Receding"s); - for (const std::string& action : anchorNode()->onRecedeAction()) { - // No sync because events are always synced and sent to the connected - // nodes and peers - global::actionManager->triggerAction( - action, - dict, - interaction::ActionManager::ShouldBeSynchronized::No - ); - } - } - - global::eventEngine->publishEvent( - _camera, - anchorNode(), - events::EventCameraFocusTransition::Transition::Receding - ); - } - else if (!_inAnchorApproachSphere && !_inAnchorReachSphere && - currDistance < d * (af - InteractionHystersis)) - { - // We moved into the approach sphere - _inAnchorApproachSphere = true; - - if (!anchorNode()->onApproachAction().empty()) { - ghoul::Dictionary dict; - dict.setValue("Node", anchorNode()->identifier()); + dict.setValue("Node", node->identifier()); dict.setValue("Transition", "Approaching"s); - for (const std::string& action : anchorNode()->onApproachAction()) { + for (const std::string& action : node->onApproachAction()) { // No sync because events are always synced and sent to the connected // nodes and peers global::actionManager->triggerAction( @@ -371,10 +300,127 @@ void NavigationHandler::updateCameraTransitions() { global::eventEngine->publishEvent( _camera, - anchorNode(), + node, events::EventCameraFocusTransition::Transition::Approaching ); + }; + + auto triggerReachEvent = [this](const SceneGraphNode* node) { + using namespace std::string_literals; + if (!node->onReachAction().empty()) { + ghoul::Dictionary dict; + dict.setValue("Node", node->identifier()); + dict.setValue("Transition", "Reaching"s); + for (const std::string& action : node->onReachAction()) { + // No sync because events are always synced and sent to the connected + // nodes and peers + global::actionManager->triggerAction( + action, + dict, + interaction::ActionManager::ShouldBeSynchronized::No + ); + } + } + + global::eventEngine->publishEvent( + _camera, + node, + events::EventCameraFocusTransition::Transition::Reaching + ); + }; + + auto triggerRecedeEvent = [this](const SceneGraphNode* node) { + using namespace std::string_literals; + if (!node->onRecedeAction().empty()) { + ghoul::Dictionary dict; + dict.setValue("Node", node->identifier()); + dict.setValue("Transition", "Receding"s); + for (const std::string& action : node->onRecedeAction()) { + // No sync because events are always synced and sent to the connected + // nodes and peers + global::actionManager->triggerAction( + action, + dict, + interaction::ActionManager::ShouldBeSynchronized::No + ); + } + } + + global::eventEngine->publishEvent( + _camera, + node, + events::EventCameraFocusTransition::Transition::Receding + ); + }; + + auto triggerExitEvent = [this](const SceneGraphNode* node) { + using namespace std::string_literals; + if (!node->onExitAction().empty()) { + ghoul::Dictionary dict; + dict.setValue("Node", node->identifier()); + dict.setValue("Transition", "Exiting"s); + for (const std::string& action : node->onExitAction()) { + // No sync because events are always synced and sent to the connected + // nodes and peers + global::actionManager->triggerAction( + action, + dict, + interaction::ActionManager::ShouldBeSynchronized::No + ); + } + } + + global::eventEngine->publishEvent( + _camera, + node, + events::EventCameraFocusTransition::Transition::Exiting + ); + }; + + bool anchorWasChanged = anchorNode() != _lastAnchor; + if (anchorWasChanged) { + // The anchor was changed between frames, so the transitions we have to check + // are a bit different. Just directly trigger the relevant events for the + // respective node + if (wasInReachSphere) { + triggerRecedeEvent(_lastAnchor); + } + + if (wasInApproachSphere) { + triggerExitEvent(_lastAnchor); + } + + if (_inAnchorApproachSphere) { + triggerApproachEvent(anchorNode()); + } + + if (_inAnchorReachSphere) { + triggerReachEvent(anchorNode()); + } } + else { + if (_inAnchorApproachSphere && !wasInApproachSphere) { + // Transitioned into the approach sphere from somewhere further away => approach + triggerApproachEvent(anchorNode()); + } + + if (_inAnchorReachSphere && !wasInReachSphere) { + // Transitioned into the reach sphere from somewhere further away => reach + triggerReachEvent(anchorNode()); + } + + if (!_inAnchorReachSphere && wasInReachSphere) { + // Transitioned out of the reach sphere => recede / move away + triggerRecedeEvent(anchorNode()); + } + + if (!_inAnchorApproachSphere && wasInApproachSphere) { + // We transitioned out of the approach sphere => on exit + triggerExitEvent(anchorNode()); + } + } + + _lastAnchor = anchorNode(); } void NavigationHandler::resetNavigationUpdateVariables() { From 6281da679881aa3a47eedf2774210cf87e7f8044 Mon Sep 17 00:00:00 2001 From: Andreas Engberg Date: Wed, 20 Dec 2023 10:02:54 +0100 Subject: [PATCH 06/30] Fixed loading screen log messages taking up real estate if set to false --- openspace.cfg | 3 ++- src/rendering/loadingscreen.cpp | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openspace.cfg b/openspace.cfg index 28ef256f33..959a720475 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -217,7 +217,8 @@ VersionCheckUrl = "http://data.openspaceproject.com/latest-version" UseMultithreadedInitialization = true LoadingScreen = { ShowMessage = true, - ShowNodeNames = true + ShowNodeNames = true, + ShowLogMessages = true } CheckOpenGLState = false LogEachOpenGLCall = false diff --git a/src/rendering/loadingscreen.cpp b/src/rendering/loadingscreen.cpp index 39cb7b0cec..d256bca6f2 100644 --- a/src/rendering/loadingscreen.cpp +++ b/src/rendering/loadingscreen.cpp @@ -317,10 +317,9 @@ void LoadingScreen::render() { rectOverlaps(messageLl, messageUr, ll, ur) : false; - const bool logOverlap = rectOverlaps( - logLl, logUr, - ll, ur - ); + const bool logOverlap = _showLog ? + rectOverlaps(logLl, logUr,ll, ur) : + false; if (logoOverlap || loadingOverlap || messageOverlap || logOverlap) { // We never want to have an overlap with these, so this try didn't From 7ad27203b53189371a86a2423b135701e622be25 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Thu, 21 Dec 2023 10:01:08 +0100 Subject: [PATCH 07/30] Update GUI hash buttons hover style is now consistent --- data/assets/util/webgui.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index 566f87adff..81bd6111f6 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -4,7 +4,7 @@ local guiCustomization = asset.require("customization/gui") -- Select which commit hashes to use for the frontend and backend -local frontendHash = "563b65b3043f798c9efe76787454c38ccccd2aaf" +local frontendHash = "7c89218df5041e51f3b9d8a1ff2325f66a47e8bf" local frontend = asset.resource({ Identifier = "WebGuiFrontend", From 84b9f384cecdf97eae7220c711678f05624a3c05 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Thu, 21 Dec 2023 15:28:59 +0100 Subject: [PATCH 08/30] GUI Hash (small style updates) --- data/assets/util/webgui.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index 81bd6111f6..eb5ae44c16 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -4,7 +4,7 @@ local guiCustomization = asset.require("customization/gui") -- Select which commit hashes to use for the frontend and backend -local frontendHash = "7c89218df5041e51f3b9d8a1ff2325f66a47e8bf" +local frontendHash = "95683e59c7fa1891e7db7b83e4eeea15f9da11f1" local frontend = asset.resource({ Identifier = "WebGuiFrontend", From e64d4d66f4919f18546f939d513bf90c6299e0fc Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 22 Dec 2023 14:19:18 +0100 Subject: [PATCH 09/30] Add the optional ability to export the model matrix into an ASCII recording --- .../openspace/interaction/sessionrecording.h | 1 + src/interaction/sessionrecording.cpp | 25 ++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index 7579e9d28e..7e667c0a68 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -594,6 +594,7 @@ public: protected: properties::BoolProperty _renderPlaybackInformation; properties::BoolProperty _ignoreRecordedScale; + properties::BoolProperty _addModelMatrixinAscii; enum class RecordedType { Camera = 0, diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index f7e6c9f63c..9d27f2f7a2 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +82,15 @@ namespace { "computed values are used instead", openspace::properties::Property::Visibility::Hidden }; + + constexpr openspace::properties::Property::PropertyInfo AddModelMatrixinAsciiInfo = { + "AddModelMatrixinAscii", + "Add Model Matrix in ASCII recording", + "If this is 'true', the model matrix is written into the ASCII recording format " + "in the line before each camera keyframe. The model matrix is the full matrix " + "that converts the position into a J2000+Galactic reference frame", + openspace::properties::Property::Visibility::Developer + }; } // namespace namespace openspace::interaction { @@ -92,12 +103,11 @@ SessionRecording::SessionRecording() : properties::PropertyOwner({ "SessionRecording", "Session Recording" }) , _renderPlaybackInformation(RenderPlaybackInfo, false) , _ignoreRecordedScale(IgnoreRecordedScaleInfo, false) + , _addModelMatrixinAscii(AddModelMatrixinAsciiInfo, false) {} SessionRecording::SessionRecording(bool isGlobal) - : properties::PropertyOwner({ "SessionRecording", "Session Recording" }) - , _renderPlaybackInformation(RenderPlaybackInfo, false) - , _ignoreRecordedScale(IgnoreRecordedScaleInfo, false) + : SessionRecording() { if (isGlobal) { ghoul::TemplateFactory* fTask = FactoryManager::ref().factory(); @@ -106,6 +116,7 @@ SessionRecording::SessionRecording(bool isGlobal) fTask->registerClass("ConvertRecFileVersionTask"); addProperty(_renderPlaybackInformation); addProperty(_ignoreRecordedScale); + addProperty(_addModelMatrixinAscii); } } @@ -810,6 +821,14 @@ void SessionRecording::saveCameraKeyframeAscii(Timestamps& times, datamessagestructures::CameraKeyframe& kf, std::ofstream& file) { + if (_addModelMatrixinAscii) { + SceneGraphNode* node = sceneGraphNode(kf._focusNode); + glm::dmat4 modelTransform = node->modelTransform(); + + file << HeaderCommentAscii << ' ' << ghoul::to_string(modelTransform) << '\n'; + } + + std::stringstream keyframeLine = std::stringstream(); saveHeaderAscii(times, HeaderCameraAscii, keyframeLine); kf.write(keyframeLine); From 952b263a8ece5cca560db1cb805f3797976faf13 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 22 Dec 2023 14:40:58 +0100 Subject: [PATCH 10/30] Add Lua function to return a list of all loaded kernels --- include/openspace/util/spicemanager.h | 8 ++++++++ src/util/spicemanager.cpp | 12 +++++++++++- src/util/spicemanager_lua.inl | 7 +++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/openspace/util/spicemanager.h b/include/openspace/util/spicemanager.h index 9b045426c3..3883050ad9 100644 --- a/include/openspace/util/spicemanager.h +++ b/include/openspace/util/spicemanager.h @@ -232,6 +232,14 @@ public: */ void unloadKernel(KernelHandle kernelId); + /** + * Returns a list of all loaded kernels in the kernel pool that have been loaded + * through the SpiceManager. The kernels are reported in order of their loading. + * + * \return The list of all loaded kernels that have been loaded through this manager + */ + std::vector loadedKernels() const; + /** * Unloads a SPICE kernel identified by the \p filePath which was used in the * loading call to #loadKernel. The unloading is done by calling the `unload_c` diff --git a/src/util/spicemanager.cpp b/src/util/spicemanager.cpp index 01cd152654..d405ab829e 100644 --- a/src/util/spicemanager.cpp +++ b/src/util/spicemanager.cpp @@ -324,6 +324,15 @@ void SpiceManager::unloadKernel(std::string filePath) { } } +std::vector SpiceManager::loadedKernels() const { + std::vector res; + res.reserve(_loadedKernels.size()); + for (const KernelInformation& info : _loadedKernels) { + res.push_back(info.path); + } + return res; +} + bool SpiceManager::hasSpkCoverage(const std::string& target, double et) const { ghoul_assert(!target.empty(), "Empty target"); @@ -1530,9 +1539,10 @@ scripting::LuaLibrary SpiceManager::luaLibrary() { { codegen::lua::LoadKernel, codegen::lua::UnloadKernel, + codegen::lua::Kernels, codegen::lua::SpiceBodies, codegen::lua::RotationMatrix, - codegen::lua::Position + codegen::lua::Position, } }; } diff --git a/src/util/spicemanager_lua.inl b/src/util/spicemanager_lua.inl index e7cb1e180e..747c113d5a 100644 --- a/src/util/spicemanager_lua.inl +++ b/src/util/spicemanager_lua.inl @@ -68,6 +68,13 @@ namespace { } } +/** + * Returns a list of all loaded kernels + */ +[[codegen::luawrap]] std::vector kernels() { + return openspace::SpiceManager::ref().loadedKernels(); +} + /** * Returns a list of Spice Bodies loaded into the system. Returns SPICE built in frames if * builtInFrames. Returns User loaded frames if !builtInFrames. From cc9f235c9d8217871014c4f4b8de7631857bee45 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 22 Dec 2023 14:41:19 +0100 Subject: [PATCH 11/30] Add more debug outputs to the startup to be able to diagnose issues --- apps/OpenSpace/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index 5618fc3522..96ea13d8a2 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -1415,9 +1415,12 @@ int main(int argc, char* argv[]) { LDEBUG("Creating SGCT Engine"); std::vector arg(argv + 1, argv + argc); + LDEBUG("Parsing commandline arguments"); sgct::Configuration config = parseArguments(arg); + LDEBUG("Loading cluster information"); config::Cluster cluster = loadCluster(absPath(windowConfiguration).string()); + LDEBUG("Setting callbacks"); Engine::Callbacks callbacks; callbacks.initOpenGL = mainInitFunc; callbacks.preSync = mainPreSyncFunc; From c1ee9079f179f9eab20f486ef9ffc8a28665de97 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 23 Dec 2023 22:33:53 +0100 Subject: [PATCH 12/30] Add the ability to drag-and-drop a video file to add it as a screenspacerenderable (closes #2988) --- scripts/drag_drop_handler.lua | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/scripts/drag_drop_handler.lua b/scripts/drag_drop_handler.lua index b972971e8e..37937394b5 100644 --- a/scripts/drag_drop_handler.lua +++ b/scripts/drag_drop_handler.lua @@ -22,13 +22,31 @@ filename = filename:gsub("\\", "/") basename = basename:gsub("\\", "/") basename_without_extension = basename:sub(0, #basename - extension:len()) -is_image_file = function(extension) +local is_image_file = function(extension) return extension == ".png" or extension == ".jpg" or extension == ".jpeg" or extension == ".tif" or extension == ".tga" or extension == ".bmp" or extension == ".psd" or extension == ".gif" or extension == ".hdr" or extension == ".pic" or extension == ".pnm" end +local is_video_file = function(extension) + return extension == ".mp4" or extension == ".webm" or extension == ".mkv" or + extension == ".avi" or extension == ".mov" or extension == ".wmv" or + extension == ".mpg" or extension == ".m4v" +end + +local is_asset_file = function(extension) + return extension == ".asset" +end + +local is_recording_file = function(extension) + return extension == ".osrec" or extension == ".osrectxt" +end + +local is_geojson_file = function(extension) + return extension == ".geojson" +end + local ReloadUIScript = [[ if openspace.hasProperty('Modules.CefWebGui.Reload') then openspace.setPropertyValue('Modules.CefWebGui.Reload', nil) end ]] if is_image_file(extension) then @@ -38,14 +56,21 @@ if is_image_file(extension) then Type = "ScreenSpaceImageLocal", TexturePath = "]] .. filename .. [[" });]] .. ReloadUIScript -elseif extension == ".asset" then +elseif is_video_file(extension) then + return [[ + openspace.addScreenSpaceRenderable({ + Identifier = openspace.makeIdentifier("]] .. basename_without_extension .. [["), + Type = "ScreenSpaceVideo", + Video = "]] .. filename .. [[" + });]] .. ReloadUIScript +elseif is_asset_file(extension) then return [[ if openspace.asset.isLoaded("]] .. filename .. [[") ~= true then openspace.printInfo("Adding asset: ']] .. filename .. [[' (drag-and-drop)"); end openspace.asset.add("]] .. filename .. '");' .. ReloadUIScript -elseif extension == ".osrec" or extension == ".osrectxt" then +elseif is_recording_file(extension) then return 'openspace.sessionRecording.startPlayback("' .. filename .. '")' -elseif extension == ".geojson" then +elseif is_geojson_file(extension) then return 'openspace.globebrowsing.addGeoJsonFromFile("' .. filename .. '")' .. ReloadUIScript end From 6dd497d38c431e91a004703cbb72a2cd81f68ead Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Thu, 4 Jan 2024 13:55:21 +0100 Subject: [PATCH 13/30] Feature/add some docs (#2961) * Add docs for PathInstruction * Add docs for renderablecartesianaxes and navigationstate * Write docs for ExoplanetDataPreparationTask * Add some kind of documentation for the task base class Was already showing in the list, but the property or decription was not included * Apply suggestions from code review * Address review comments * Clarify confusing sentence * Slight rephrasing --- .../rendering/renderablecartesianaxes.cpp | 13 +++++++++- .../tasks/exoplanetsdatapreparationtask.cpp | 21 ++++++++++++++++ src/documentation/core_registration.cpp | 2 ++ src/navigation/navigationstate.cpp | 18 +++++++++++++ src/navigation/path.cpp | 25 +++++++++++++++---- src/util/task.cpp | 9 +++++++ 6 files changed, 82 insertions(+), 6 deletions(-) diff --git a/modules/base/rendering/renderablecartesianaxes.cpp b/modules/base/rendering/renderablecartesianaxes.cpp index 841a6b032e..a0f01d6c74 100644 --- a/modules/base/rendering/renderablecartesianaxes.cpp +++ b/modules/base/rendering/renderablecartesianaxes.cpp @@ -61,6 +61,18 @@ namespace { openspace::properties::Property::Visibility::NoviceUser }; + // The RenderableCartesianAxes can be used to render the local Cartesian coordinate + // system, or reference frame, of another scene graph node. The colors of the axes + // can be customized but are per default set to Red, Green and Blue, for the X-, Y- + // and Z-axis, respectively. + // + // To add the axes, create a scene graph node with the RenderableCartesianAxes + // renderable and add it as a child to the other scene graph node, i.e. specify the + // other node as the Parent of the node with this renderable. Also, the axes have to + // be scaled to match the parent object for the axes to be visible in the scene, for + // example using a StaticScale. + // + // See example asset (@TODO: link to asset file). struct [[codegen::Dictionary(RenderableCartesianAxes)]] Parameters { // [[codegen::verbatim(XColorInfo.description)]] std::optional xColor [[codegen::color()]]; @@ -70,7 +82,6 @@ namespace { // [[codegen::verbatim(ZColorInfo.description)]] std::optional zColor [[codegen::color()]]; - }; #include "renderablecartesianaxes_codegen.cpp" } // namespace diff --git a/modules/exoplanets/tasks/exoplanetsdatapreparationtask.cpp b/modules/exoplanets/tasks/exoplanetsdatapreparationtask.cpp index 98fe89286f..c160e8e473 100644 --- a/modules/exoplanets/tasks/exoplanetsdatapreparationtask.cpp +++ b/modules/exoplanets/tasks/exoplanetsdatapreparationtask.cpp @@ -40,6 +40,27 @@ namespace { constexpr std::string_view _loggerCat = "ExoplanetsDataPreparationTask"; + // This task is used for generating the binary data files that are used for the + // exoplanet system loading in OpenSpace. Using this binary file allows efficient + // data loading of an arbitrary exoplanet system during runtime, without keeping all + // data in memory. + // + // Two output files are generated, whose paths have to be specified: One binary with + // the data for the exoplanets (OutputBIN) and one look-up table that is used to + // find where in the binary file a particular system is located (OutputLUT). + // + // Additionally, the task uses three different files as input: 1) a CSV file with the + // data from the NASA Exoplanet Archive, 2) A SPECK file that contains star positions, + // and 3) a TXT file that is used for the conversion from the stars' effective + // temperature to a B-V color index. The paths for all these paths have to be + // specified. The SPECK file (2) will be used for the positions of the host stars, to + // make sure that they line up with the stars in that dataset. The cross-matching is + // done by star name, as given by the comment in the SPECK file and the host star + // column in the exoplanet dataset. + // + // Note that the CSV (1) has to include a certain set of columns for the rendering to + // be correct. Use the accompanying python script to download the datafile, or make + // sure to include all columns in your download. struct [[codegen::Dictionary(ExoplanetsDataPreparationTask)]] Parameters { // The csv file to extract data from std::string inputDataFile; diff --git a/src/documentation/core_registration.cpp b/src/documentation/core_registration.cpp index bdec3fa0a9..e1c9f03438 100644 --- a/src/documentation/core_registration.cpp +++ b/src/documentation/core_registration.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -74,6 +75,7 @@ void registerCoreClasses(documentation::DocumentationEngine& engine) { engine.addDocumentation(Scale::Documentation()); engine.addDocumentation(SceneGraphNode::Documentation()); engine.addDocumentation(ScreenSpaceRenderable::Documentation()); + engine.addDocumentation(Task::documentation()); engine.addDocumentation(TimeRange::Documentation()); engine.addDocumentation(Translation::Documentation()); engine.addDocumentation(TimeFrame::Documentation()); diff --git a/src/navigation/navigationstate.cpp b/src/navigation/navigationstate.cpp index a1f11ba337..b995b9ebf9 100644 --- a/src/navigation/navigationstate.cpp +++ b/src/navigation/navigationstate.cpp @@ -33,6 +33,24 @@ namespace { constexpr double Epsilon = 1E-7; + // A NavigationState is an object describing an exact camera position and rotation, + // in a certain reference frame (per default, the one of the specified Anchor node). + // It can be used to set the same camera position at a later point in time, or + // navigating to a specific camera position using the pathnavigation system. + // + // The camera rotation is specified using Euler angles, in radians. It is also + // possible to specify a node to be used as Aim, but note that this will not affect + // the actual camera position or view direction. + // + // To get the current navigation state of the camera, use the + // `openspace.navigation.getNavigationState()` function in the Scripting API. + // + // Note that a NavigationState does not include information about what timestamp + // within OpenSpace that the NavigationState was generated. When laoding a + // NavigationState, the visuals may be different depending on what the simulation + // timestamp is, as the relative positions of objects in the scene may have changed. + // The get the exact same visuals as when the NavigationState was saved, make sure + // to also set the time to be the same as on save. struct [[codegen::Dictionary(NavigationState)]] Parameters { // The identifier of the anchor node std::string anchor; diff --git a/src/navigation/path.cpp b/src/navigation/path.cpp index abeb9ec85c..8b827009b6 100644 --- a/src/navigation/path.cpp +++ b/src/navigation/path.cpp @@ -45,9 +45,24 @@ namespace { constexpr std::string_view _loggerCat = "Path"; constexpr float LengthEpsilon = 1e-5f; - // TODO: where should this documentation be? - // It's nice to have these to interpret the dictionary when creating the path, but - // maybe it's not really necessary + // A PathInstruction is a table describing the specification for a camera path. + // It is used as an input to the `openspace.pathnavigation.createPath` function. + // + // There are two types of paths that can be created, as specified by the required + // TargetType parameter: 'Node' or 'NavigationState'. The difference is what kind + // of target the path is created for, a scene graph node or a specific navigation + // state for the camera. + // + // Depending on the type, the parameters that can be specified are a bit different. + // A 'NavigationState' already contains all details for the camera position, so no + // other details may be specified. For a 'Node' instruction, only a 'Target' node is + // required, but a 'Height' or 'Position' may also be specified. If both a position + // and height is specified, the height value will be ignored. + // + // For 'Node' paths it is also possible to specify whether the target camera state + // at the end of the flight should take the up direction of the target node into + // account. Note that for this to give an effect on the path, rolling motions have + // to be enabled. struct [[codegen::Dictionary(PathInstruction)]] Parameters { // The type of the instruction. Decides what other parameters are // handled/available @@ -61,7 +76,7 @@ namespace { std::optional duration; // (Node): The target node of the camera path. Not optional for 'Node' - // instructions + // type instructions std::optional target; // (Node): An optional position in relation to the target node, in model @@ -76,7 +91,7 @@ namespace { std::optional useTargetUpDirection; // (NavigationState): A navigation state that will be the target - // of this path segment + // of the resulting path std::optional navigationState [[codegen::reference("core_navigation_state")]]; diff --git a/src/util/task.cpp b/src/util/task.cpp index 40e1c0fa60..2eb1ce6185 100644 --- a/src/util/task.cpp +++ b/src/util/task.cpp @@ -31,6 +31,15 @@ #include namespace { + + // The base class of all tasks. Specify the Type property to create one of the + // available task types. This property should be included in the same table object + // as the properties of the specific task. + // + // Tasks can be executed using the separate TaskRunner application. When starting the + // application, just enter the path to the file describing the task you want to run + // as input in the command line to initiate the run. All tasks should live in the task + // folder in the data folder of the OpenSpace installation. struct [[codegen::Dictionary(Task)]] Parameters { // This key specifies the type of Task that gets created. It has to be one of the // valid Tasks that are available for creation (see the FactoryDocumentation for a From 97d1dc163b252db714d64140e142dd1b43ad6c79 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 8 Jan 2024 11:30:46 +0100 Subject: [PATCH 14/30] Add the ability for the log file to rotate (closes #2995) --- ext/ghoul | 2 +- openspace.cfg | 2 +- src/engine/logfactory.cpp | 9 +++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 82f83b40fd..274d2beed3 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 82f83b40fda985e9adc25ab94f253fe127bdeee0 +Subproject commit 274d2beed38bb24ef693b2a8c9c95307bdf5204f diff --git a/openspace.cfg b/openspace.cfg index 959a720475..7c5976b387 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -202,7 +202,7 @@ Logging = { LogLevel = "Debug", ImmediateFlush = true, Logs = { - { Type = "html", File = "${LOGS}/log.html", Append = false } + { Type = "html", File = "${LOGS}/log.html", LogRotation = 3 } }, CapabilitiesVerbosity = "Full" } diff --git a/src/engine/logfactory.cpp b/src/engine/logfactory.cpp index 529241527f..d4a7332a06 100644 --- a/src/engine/logfactory.cpp +++ b/src/engine/logfactory.cpp @@ -54,6 +54,9 @@ namespace { // be appended to previous runs std::optional append; + // The number of files that should be kept around for this Log + std::optional logRotation [[codegen::greater(0)]]; + // Determines whether the log entires should be stamped with the time at which the // message was logged std::optional timeStamping; @@ -97,6 +100,7 @@ std::unique_ptr createLog(const ghoul::Dictionary& dictiona std::filesystem::path filename = absPath(p.file); bool append = p.append.value_or(true); + int nLogRotation = p.logRotation.value_or(0); bool timeStamp = p.timeStamping.value_or(true); bool dateStamp = p.dateStamping.value_or(true); bool categoryStamp = p.categoryStamping.value_or(true); @@ -116,7 +120,7 @@ std::unique_ptr createLog(const ghoul::Dictionary& dictiona return std::make_unique( filename.string(), - ghoul::logging::TextLog::Append(append), + nLogRotation, ghoul::logging::Log::TimeStamping(timeStamp), ghoul::logging::Log::DateStamping(dateStamp), ghoul::logging::Log::CategoryStamping(categoryStamp), @@ -124,11 +128,12 @@ std::unique_ptr createLog(const ghoul::Dictionary& dictiona cssFiles, jsFiles, level - ); + ); } case Parameters::Type::Text: return std::make_unique( filename.string(), + nLogRotation, ghoul::logging::TextLog::Append(append), ghoul::logging::Log::TimeStamping(timeStamp), ghoul::logging::Log::DateStamping(dateStamp), From 4bf111115e6a3c5f9f4669a3069ec23ecafcedb2 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 8 Jan 2024 17:09:59 +0100 Subject: [PATCH 15/30] Add precompiled headers to unit tests --- ext/ghoul | 2 +- support/coding/codegen | 2 +- tests/CMakeLists.txt | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 274d2beed3..d607a6d6b1 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 274d2beed38bb24ef693b2a8c9c95307bdf5204f +Subproject commit d607a6d6b11be4ad05ccd555b8b290a782e0e384 diff --git a/support/coding/codegen b/support/coding/codegen index 60b97c04cc..3bc8dc5546 160000 --- a/support/coding/codegen +++ b/support/coding/codegen @@ -1 +1 @@ -Subproject commit 60b97c04cce28a51aedc46dc74db63f7bc1cc930 +Subproject commit 3bc8dc554648d59dc7bec9a5d9c5882415ececcb diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 98bc129461..434608d6e0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -63,6 +63,10 @@ target_include_directories(OpenSpaceTest target_compile_definitions(OpenSpaceTest PUBLIC "GHL_THROW_ON_ASSERT") target_link_libraries(OpenSpaceTest PUBLIC Catch2 openspace-core sgct) +target_precompile_headers(OpenSpaceTest PRIVATE + +) + foreach (library_name ${all_enabled_modules}) get_target_property(library_type ${library_name} TYPE) if (NOT ${library_type} STREQUAL "SHARED_LIBRARY") From 902da116e782869df0262770c03a4a878eef91ba Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 9 Jan 2024 15:34:54 +0100 Subject: [PATCH 16/30] Remove interesting times (closes #2991) --- include/openspace/scene/scene.h | 19 --------------- modules/imgui/src/guispacetimecomponent.cpp | 24 ------------------- .../include/topics/flightcontrollertopic.h | 1 - .../src/topics/flightcontrollertopic.cpp | 19 --------------- src/scene/scene.cpp | 9 ------- src/scene/scene_lua.inl | 10 -------- 6 files changed, 82 deletions(-) diff --git a/include/openspace/scene/scene.h b/include/openspace/scene/scene.h index 7aed9df083..72580a8a9e 100644 --- a/include/openspace/scene/scene.h +++ b/include/openspace/scene/scene.h @@ -213,24 +213,6 @@ public: */ void updateInterpolations(); - /** - * Adds the provided \p time as an interesting time to this scene. The same time can - * be added multiple times. - * - * \param time The time that should be added - * - * \pre \p time.time must not be empty - * \pre \p time.name must not be empty - */ - void addInterestingTime(InterestingTime time); - - /** - * Returns the list of all interesting times that are defined for this scene. - * - * \return The list of all interesting times that are defined for this scene - */ - const std::vector& interestingTimes() const; - /** * Returns the Lua library that contains all Lua functions available to change the * scene graph. @@ -334,7 +316,6 @@ private: SceneGraphNode _rootDummy; std::unique_ptr _initializer; std::string _profilePropertyName; - std::vector _interestingTimes; bool _valueIsTable = false; std::mutex _programUpdateLock; diff --git a/modules/imgui/src/guispacetimecomponent.cpp b/modules/imgui/src/guispacetimecomponent.cpp index 0a7bf9dbc7..336000d2f5 100644 --- a/modules/imgui/src/guispacetimecomponent.cpp +++ b/modules/imgui/src/guispacetimecomponent.cpp @@ -192,30 +192,6 @@ void GuiSpaceTimeComponent::render() { CaptionText("Time Controls"); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.f); - const std::vector& interestingTimes = - global::renderEngine->scene()->interestingTimes(); - if (!interestingTimes.empty()) { - ImGui::Text("%s", "Interesting Times"); - - for (size_t i = 0; i < interestingTimes.size(); ++i) { - const Scene::InterestingTime& t = interestingTimes[i]; - if (ImGui::Button(t.name.c_str())) { - - // No sync or send because time settings are always synced and sent - // to the connected nodes and peers - global::scriptEngine->queueScript( - "openspace.time.setTime(\"" + t.time + "\")", - scripting::ScriptEngine::ShouldBeSynchronized::No, - scripting::ScriptEngine::ShouldSendToRemote::No - ); - } - - if (i != interestingTimes.size() - 1) { - ImGui::SameLine(); - } - } - } - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.f); ImGui::Text( diff --git a/modules/server/include/topics/flightcontrollertopic.h b/modules/server/include/topics/flightcontrollertopic.h index 4a58a30696..97afe52a41 100644 --- a/modules/server/include/topics/flightcontrollertopic.h +++ b/modules/server/include/topics/flightcontrollertopic.h @@ -63,7 +63,6 @@ private: void disconnect(); void processInputState(const nlohmann::json& json); void setFocusNodes(); - void setInterestingTimes(); void updateView(const nlohmann::json& json) const; void changeFocus(const nlohmann::json& json) const; void setRenderableEnabled(const nlohmann::json& json) const; diff --git a/modules/server/src/topics/flightcontrollertopic.cpp b/modules/server/src/topics/flightcontrollertopic.cpp index ec1b172e0e..4bba9cfa65 100644 --- a/modules/server/src/topics/flightcontrollertopic.cpp +++ b/modules/server/src/topics/flightcontrollertopic.cpp @@ -213,7 +213,6 @@ void FlightControllerTopic::connect() { std::fill(_inputState.axes.begin(), _inputState.axes.end(), 0.f); _payload[TypeKey] = Connect; setFocusNodes(); - setInterestingTimes(); _payload[Connect][FocusNodesKey] = _focusNodes; _payload[Connect][AllNodesKey] = _allNodes; _payload[Connect][InterestingTimesKey] = _interestingTimes; @@ -258,25 +257,7 @@ void FlightControllerTopic::setFocusNodes() { } } -void FlightControllerTopic::setInterestingTimes() { - std::vector times = - global::renderEngine->scene()->interestingTimes(); - - std::sort( - times.begin(), - times.end(), - [](Scene::InterestingTime lhs, Scene::InterestingTime rhs) { - return lhs.name < rhs.name; - } - ); - - for (const Scene::InterestingTime& t : times) { - _interestingTimes[t.name] = t.time; - } -} - void FlightControllerTopic::updateView(const nlohmann::json& json) const { - if (json.find(RenderableKey) != json.end()) { setRenderableEnabled(json); } diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 5b020fb8df..1134d008fd 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -572,14 +572,6 @@ void Scene::updateInterpolations() { ); } -void Scene::addInterestingTime(InterestingTime time) { - _interestingTimes.push_back(std::move(time)); -} - -const std::vector& Scene::interestingTimes() const { - return _interestingTimes; -} - void Scene::setPropertiesFromProfile(const Profile& p) { ghoul::lua::LuaState L(ghoul::lua::LuaState::IncludeStandardLibrary::Yes); @@ -873,7 +865,6 @@ scripting::LuaLibrary Scene::luaLibrary() { codegen::lua::SceneGraphNodes, codegen::lua::NodeByRenderableType, codegen::lua::ScreenSpaceRenderables, - codegen::lua::AddInterestingTime, codegen::lua::WorldPosition, codegen::lua::WorldRotation, codegen::lua::SetParent, diff --git a/src/scene/scene_lua.inl b/src/scene/scene_lua.inl index f5728f5ed5..3d7bc74554 100644 --- a/src/scene/scene_lua.inl +++ b/src/scene/scene_lua.inl @@ -924,16 +924,6 @@ namespace { return res; } -/** - * Adds an interesting time to the current scene. The first argument is the name of the - * time and the second argument is the time itself in the format YYYY-MM-DDThh:mm:ss.uuu - */ -[[codegen::luawrap]] void addInterestingTime(std::string name, std::string time) { - openspace::global::renderEngine->scene()->addInterestingTime( - { std::move(name), std::move(time) } - ); -} - /** * Returns the world position of the scene graph node with the given string as identifier. */ From cae9834ec78c098e745f770e7dd106dabd049596 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 9 Jan 2024 15:44:22 +0100 Subject: [PATCH 17/30] Add log rotation function to the Script log as well (closes #2995) --- include/openspace/engine/configuration.h | 1 + src/engine/configuration.cpp | 6 +++++ src/engine/openspaceengine.cpp | 32 ++++++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/include/openspace/engine/configuration.h b/include/openspace/engine/configuration.h index b6174030bf..20eb637564 100644 --- a/include/openspace/engine/configuration.h +++ b/include/openspace/engine/configuration.h @@ -78,6 +78,7 @@ struct Configuration { Logging logging; std::string scriptLog; + int scriptLogRotation = 3; struct DocumentationInfo { std::string path; diff --git a/src/engine/configuration.cpp b/src/engine/configuration.cpp index cdec76b78b..56470ef0e9 100644 --- a/src/engine/configuration.cpp +++ b/src/engine/configuration.cpp @@ -134,6 +134,10 @@ namespace { // from previous runs) will be silently overwritten std::optional scriptLog; + // If this value is specified, this many number of script log files are being + // retained before overwriting any + std::optional scriptLogRotation; + struct Documentation { // The path where the documentation files will be stored std::optional path; @@ -368,6 +372,7 @@ ghoul::Dictionary Configuration::createDictionary() { } res.setValue("ScriptLog", scriptLog); + res.setValue("ScriptLogRotation", scriptLogRotation); { ghoul::Dictionary documentationDict; @@ -518,6 +523,7 @@ void parseLuaState(Configuration& configuration) { c.fontSize.cameraInfo = p.fontSize.cameraInfo; c.fontSize.versionInfo = p.fontSize.versionInfo; c.scriptLog = p.scriptLog.value_or(c.scriptLog); + c.scriptLogRotation = p.scriptLogRotation.value_or(3); c.versionCheckUrl = p.versionCheckUrl.value_or(c.versionCheckUrl); c.useMultithreadedInitialization = p.useMultithreadedInitialization.value_or(c.useMultithreadedInitialization); diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 2637341fef..39885b8bb6 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -308,6 +308,38 @@ void OpenSpaceEngine::initialize() { } #endif // GHOUL_LOGGING_ENABLE_TRACE + if (!global::configuration->scriptLog.empty() && + global::configuration->scriptLogRotation > 0) + { + int rot = global::configuration->scriptLogRotation; + while (rot > 0) { + // Move all of the existing logs one position up + + std::filesystem::path file = absPath(global::configuration->scriptLog); + std::string fname = file.stem().string(); + std::string ext = file.extension().string(); + + std::filesystem::path newCandidate = file; + newCandidate.replace_filename(fmt::format("{}-{}{}", fname, rot, ext)); + + std::filesystem::path oldCandidate = file; + if (rot > 1) { + // We don't actually have a -0 version, it is just the base name + oldCandidate.replace_filename( + fmt::format("{}-{}{}", fname, rot - 1, ext) + ); + } + + if (std::filesystem::exists(newCandidate)) { + std::filesystem::remove(newCandidate); + } + if (std::filesystem::exists(oldCandidate)) { + std::filesystem::rename(oldCandidate, newCandidate); + } + + rot--; + } + } LINFOC("OpenSpace Version", std::string(OPENSPACE_VERSION_STRING_FULL)); From ab925174b55dfea9432c69a6b25d8b28ab05b457 Mon Sep 17 00:00:00 2001 From: GPayne Date: Thu, 11 Jan 2024 14:31:00 -0700 Subject: [PATCH 18/30] Fix for crash when reading meta of corrupt config file --- apps/OpenSpace/ext/launcher/src/launcherwindow.cpp | 13 ++++++++++--- apps/OpenSpace/ext/sgct | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp b/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp index 75525bdf7f..9c507e4f1d 100644 --- a/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp +++ b/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp @@ -588,10 +588,17 @@ bool handleConfigurationFile(QComboBox& box, const std::filesystem::directory_en // Add tooltip if (isJson) { - sgct::config::Meta meta = sgct::readMeta(p.path().string(), true); - if (!meta.description.empty()) { + std::string tooltipDescription; + try { + sgct::config::Meta meta = sgct::readMeta(p.path().string()); + tooltipDescription = meta.description; + } + catch (const sgct::Error&) { + tooltipDescription = "(no description available)"; + } + if (!tooltipDescription.empty()) { QString toolTip = QString::fromStdString( - fmt::format("

{}

", meta.description) + fmt::format("

{}

", tooltipDescription) ); box.setItemData(box.count() - 1, toolTip, Qt::ToolTipRole); } diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index e2e1b99a2d..9ee34038be 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit e2e1b99a2de784d1774d8b72262fc4def2f0b5ce +Subproject commit 9ee34038be3a8c0fe2410e5f511688f1ff816392 From 04a06520e59b25339b43c8ca05f92e6073d96ebc Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 12 Jan 2024 10:10:49 +0100 Subject: [PATCH 19/30] Provide a warning instead of erroring out with the localResource/syncedResource -> resource change --- src/scene/assetmanager.cpp | 61 ++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/src/scene/assetmanager.cpp b/src/scene/assetmanager.cpp index 1a9c0ec6a7..755be4a9d9 100644 --- a/src/scene/assetmanager.cpp +++ b/src/scene/assetmanager.cpp @@ -555,29 +555,78 @@ void AssetManager::setUpAssetLuaTable(Asset* asset) { ); lua_setfield(*_luaState, assetTableIndex, "resource"); + // @DEPRECATED(abock) This should be removed after 0.20.0 + ghoul::lua::push(*_luaState, this, asset); lua_pushcclosure( *_luaState, [](lua_State* L) { - return ghoul::lua::luaError( - L, + LWARNING( "'asset.localResource' has been deprecrated and should be replaced with " "'asset.resource' instead. No change to the parameters are needed" ); + + AssetManager* manager = ghoul::lua::userData(L, 1); + Asset* thisAsset = ghoul::lua::userData(L, 2); + ghoul::lua::checkArgumentsAndThrow(L, { 0, 1 }, "lua::resource"); + + auto [name] = ghoul::lua::values>(L); + std::filesystem::path path = + name.has_value() ? + thisAsset->path().parent_path() / *name : + thisAsset->path().parent_path(); + ghoul::lua::push(L, path); + + return 1; }, - 0 + 2 ); lua_setfield(*_luaState, assetTableIndex, "localResource"); + // @DEPRECATED(abock) This should be removed after 0.20.0 + ghoul::lua::push(*_luaState, this, asset); lua_pushcclosure( *_luaState, [](lua_State* L) { - return ghoul::lua::luaError( - L, + LWARNING( "'asset.syncedResource' has been deprecrated and should be replaced with " "'asset.resource' instead. No change to the parameters are needed" ); + + AssetManager* manager = ghoul::lua::userData(L, 1); + Asset* thisAsset = ghoul::lua::userData(L, 2); + ghoul::lua::checkArgumentsAndThrow(L, { 0, 1 }, "lua::resource"); + + ghoul::Dictionary d = ghoul::lua::value(L); + std::unique_ptr s = + ResourceSynchronization::createFromDictionary(d); + + std::string uid = d.value("Type") + "/" + s->generateUid(); + SyncItem* syncItem = nullptr; + auto it = manager->_synchronizations.find(uid); + if (it == manager->_synchronizations.end()) { + auto si = std::make_unique(); + si->synchronization = std::move(s); + si->assets.push_back(thisAsset); + syncItem = si.get(); + manager->_synchronizations[uid] = std::move(si); + } + else { + syncItem = it->second.get(); + syncItem->assets.push_back(thisAsset); + } + + if (!syncItem->synchronization->isResolved()) { + manager->_unfinishedSynchronizations.push_back(syncItem); + } + + thisAsset->addSynchronization(syncItem->synchronization.get()); + std::filesystem::path path = syncItem->synchronization->directory(); + path += std::filesystem::path::preferred_separator; + ghoul::lua::push(L, path); + + return 1; }, - 0 + 2 ); lua_setfield(*_luaState, assetTableIndex, "syncedResource"); From 3cf06d26a62480b2ec2fd743d414ed64450cb779 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 12 Jan 2024 15:16:40 +0100 Subject: [PATCH 20/30] Make the RenderableFOV and Missions more resilient to empty values being passed --- .../rendering/renderablefov.cpp | 36 +++++++++++-------- src/mission/mission.cpp | 2 +- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/modules/spacecraftinstruments/rendering/renderablefov.cpp b/modules/spacecraftinstruments/rendering/renderablefov.cpp index e25e156eaf..5c23b7edfd 100644 --- a/modules/spacecraftinstruments/rendering/renderablefov.cpp +++ b/modules/spacecraftinstruments/rendering/renderablefov.cpp @@ -447,20 +447,26 @@ bool RenderableFov::isReady() const { glm::dvec3 RenderableFov::orthogonalProjection(const glm::dvec3& vecFov, double time, const std::string& target) const { - const glm::dvec3 vecToTarget = SpiceManager::ref().targetPosition( - target, - _instrument.spacecraft, - _instrument.referenceFrame, - _instrument.aberrationCorrection, - time - ); - const glm::dvec3 fov = SpiceManager::ref().frameTransformationMatrix( - _instrument.name, - _instrument.referenceFrame, - time - ) * vecFov; - const glm::dvec3 p = glm::proj(vecToTarget, fov); - return p * 1000.0; // km -> m + if (target.empty()) { + glm::dvec3 vec = glm::dvec3(1.0, 0.0, 0.0); + return glm::normalize(glm::cross(vec, vecFov)); + } + else { + const glm::dvec3 vecToTarget = SpiceManager::ref().targetPosition( + target, + _instrument.spacecraft, + _instrument.referenceFrame, + _instrument.aberrationCorrection, + time + ); + const glm::dvec3 fov = SpiceManager::ref().frameTransformationMatrix( + _instrument.name, + _instrument.referenceFrame, + time + ) * vecFov; + const glm::dvec3 p = glm::proj(vecToTarget, fov); + return p * 1000.0; // km -> m + } } void RenderableFov::computeIntercepts(double time, const std::string& target, @@ -849,7 +855,7 @@ std::pair RenderableFov::determineTarget(double time) { // If none of the targets is in field of view, either use the last target or if there // hasn't been one, find the closest target - if (_previousTarget.empty()) { + if (_previousTarget.empty() && !_instrument.potentialTargets.empty()) { // If we reached this, we haven't found a target in field of view and we don't // have a previously selected target, so the next best heuristic for a target is // the closest one diff --git a/src/mission/mission.cpp b/src/mission/mission.cpp index aace145035..841a4cc667 100644 --- a/src/mission/mission.cpp +++ b/src/mission/mission.cpp @@ -92,7 +92,7 @@ MissionPhase::MissionPhase(const ghoul::Dictionary& dictionary) { _image = p.image.value_or(_image); _link = p.link.value_or(_link); - if (p.phases.has_value()) { + if (p.phases.has_value() && !p.phases->empty()) { _subphases.reserve(p.phases->size()); for (const ghoul::Dictionary& phase : *p.phases) { _subphases.emplace_back(phase); From 15aaae300782554c37191f0cf980e6dc8b476647 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 12 Jan 2024 15:20:00 +0100 Subject: [PATCH 21/30] Spice kernel handling cleanup --- .../missions/voyager/voyager2.asset | 3 ++- .../euclid/{spice.asset => kernels.asset} | 0 .../solarsystem/telescopes/euclid/model.asset | 7 +++--- .../telescopes/euclid/trails.asset | 23 ++++++++++--------- .../solarsystem/telescopes/jwst/trail.asset | 2 +- 5 files changed, 19 insertions(+), 16 deletions(-) rename data/assets/scene/solarsystem/telescopes/euclid/{spice.asset => kernels.asset} (100%) diff --git a/data/assets/scene/solarsystem/missions/voyager/voyager2.asset b/data/assets/scene/solarsystem/missions/voyager/voyager2.asset index b7c8a5b60d..169d7fbe06 100644 --- a/data/assets/scene/solarsystem/missions/voyager/voyager2.asset +++ b/data/assets/scene/solarsystem/missions/voyager/voyager2.asset @@ -1,5 +1,6 @@ local sun = asset.require("scene/solarsystem/sun/sun") local sunTransforms = asset.require("scene/solarsystem/sun/transforms") +local coreKernels = asset.require("spice/core") @@ -57,7 +58,7 @@ local Voyager2 = { Rotation = { Type = "SpiceRotation", SourceFrame = "VG2_SC_BUS", - DestinationFrame = "GALACTIC" + DestinationFrame = coreKernels.Frame.Galactic } }, GUI = { diff --git a/data/assets/scene/solarsystem/telescopes/euclid/spice.asset b/data/assets/scene/solarsystem/telescopes/euclid/kernels.asset similarity index 100% rename from data/assets/scene/solarsystem/telescopes/euclid/spice.asset rename to data/assets/scene/solarsystem/telescopes/euclid/kernels.asset diff --git a/data/assets/scene/solarsystem/telescopes/euclid/model.asset b/data/assets/scene/solarsystem/telescopes/euclid/model.asset index c837d8a779..a809d2f482 100644 --- a/data/assets/scene/solarsystem/telescopes/euclid/model.asset +++ b/data/assets/scene/solarsystem/telescopes/euclid/model.asset @@ -1,6 +1,7 @@ local transform = asset.require("scene/solarsystem/planets/earth/transforms") local sun = asset.require("scene/solarsystem/sun/sun") -local spice = asset.require("./spice") +local kernels = asset.require("./kernels") +local coreKernels = asset.require("spice/core") @@ -23,8 +24,8 @@ local Euclid = { Transform = { Translation = { Type = "SpiceTranslation", - Target = spice.ID.Euclid, - Observer = "EARTH BARYCENTER" + Target = kernels.ID.Euclid, + Observer = coreKernels.ID.EarthBarycenter }, Rotation = { Type = "FixedRotation", diff --git a/data/assets/scene/solarsystem/telescopes/euclid/trails.asset b/data/assets/scene/solarsystem/telescopes/euclid/trails.asset index b00a11b34e..9f54671974 100644 --- a/data/assets/scene/solarsystem/telescopes/euclid/trails.asset +++ b/data/assets/scene/solarsystem/telescopes/euclid/trails.asset @@ -1,7 +1,8 @@ -local spice = asset.require("./spice") +local kernels = asset.require("./kernels") local earth = asset.require("scene/solarsystem/planets/earth/transforms") local solarsystem = asset.require("scene/solarsystem/sun/transforms") local transforms = asset.require("scene/solarsystem/planets/earth/lagrange_points/l2") +local coreKernels = asset.require("spice/core") local StartTime = "2023 JUL 01 15:53:08.239" @@ -14,8 +15,8 @@ local EuclidTrailSun = { Type = "RenderableTrailTrajectory", Translation = { Type = "SpiceTranslation", - Target = spice.ID.Euclid, - Observer = "SSB" + Target = kernels.ID.Euclid, + Observer = coreKernels.ID.SolarSystemBarycenter }, Color = { 0.70, 0.50, 0.20 }, StartTime = StartTime, @@ -35,8 +36,8 @@ local EuclidTrailEarth = { Type = "RenderableTrailTrajectory", Translation = { Type = "SpiceTranslation", - Target = spice.ID.Euclid, - Observer = "EARTH BARYCENTER" + Target = kernels.ID.Euclid, + Observer = coreKernels.ID.EarthBarycenter }, Color = { 0.325, 0.65, 0.55 }, StartTime = StartTime, @@ -61,9 +62,9 @@ local EuclidTrailOrbit = { Type = "RenderableTrailOrbit", Translation = { Type = "SpiceTranslation", - Target = spice.ID.Euclid, - Observer = 392, -- L2 - Frame = "GALACTIC" + Target = kernels.ID.Euclid, + Observer = l2.ID.L2, + Frame = coreKernels.Frame.Galactic }, Color = { 0.863, 0.0, 0.902 }, Period = 182.621099, -- About 6 months @@ -88,9 +89,9 @@ local EuclidTrailCoRevOrbit = { Type = "RenderableTrailOrbit", Translation = { Type = "SpiceTranslation", - Target = spice.ID.Euclid, - Observer = 392, -- L2 - Frame = "L2_COREV" + Target = kernels.ID.Euclid, + Observer = l2.ID.L2, + Frame = l2.Frame.L2Corevolving }, Color = { 0.863, 0.0, 0.902 }, Period = 182.621099, -- About 6 months diff --git a/data/assets/scene/solarsystem/telescopes/jwst/trail.asset b/data/assets/scene/solarsystem/telescopes/jwst/trail.asset index 83f0d266eb..823714fe8d 100644 --- a/data/assets/scene/solarsystem/telescopes/jwst/trail.asset +++ b/data/assets/scene/solarsystem/telescopes/jwst/trail.asset @@ -91,7 +91,7 @@ local JWSTTrailOrbit = { Type = "SpiceTranslation", Target = kernels.ID.JWST, Observer = transforms.ID.L2, - Frame = "GALACTIC" + Frame = coreKernels.Frame.Galactic }, Color = { 0.863, 0.0, 0.902 }, Period = 182.621099, -- About 6 months From 385d23303d1483745bbe18a12bc118091c359491 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Mon, 15 Jan 2024 16:32:19 +0100 Subject: [PATCH 22/30] Prevent point cloud from never getting ready if no dataset was added Fixes issue that Voids were not begin rendered --- .../base/rendering/pointcloud/renderablepointcloud.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/base/rendering/pointcloud/renderablepointcloud.cpp b/modules/base/rendering/pointcloud/renderablepointcloud.cpp index f43acf279a..0733849ece 100644 --- a/modules/base/rendering/pointcloud/renderablepointcloud.cpp +++ b/modules/base/rendering/pointcloud/renderablepointcloud.cpp @@ -589,7 +589,7 @@ RenderablePointCloud::RenderablePointCloud(const ghoul::Dictionary& dictionary) } bool RenderablePointCloud::isReady() const { - bool isReady = _program && !_dataset.entries.empty(); + bool isReady = _program; // If we have labels, they also need to be loaded if (_hasLabels) { @@ -691,6 +691,10 @@ void RenderablePointCloud::renderBillboards(const RenderData& data, const glm::dvec3& orthoUp, float fadeInVariable) { + if (!_hasDataFile || _dataset.entries.empty()) { + return; + } + glEnablei(GL_BLEND, 0); if (_useAdditiveBlending) { @@ -861,7 +865,7 @@ int RenderablePointCloud::nAttributesPerPoint() const { } void RenderablePointCloud::updateBufferData() { - if (!_hasDataFile) { + if (!_hasDataFile || _dataset.entries.empty()) { return; } From 6fb4b89a121a2d6a7cd61d85bf2639fa10d881f6 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Mon, 15 Jan 2024 16:38:56 +0100 Subject: [PATCH 23/30] Prevent setting ScaleExponent to an invalid value May happen if no dataset was read or if the dataset only incudes (0,0,0) --- .../pointcloud/renderablepointcloud.cpp | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/modules/base/rendering/pointcloud/renderablepointcloud.cpp b/modules/base/rendering/pointcloud/renderablepointcloud.cpp index 0733849ece..f7319b3bea 100644 --- a/modules/base/rendering/pointcloud/renderablepointcloud.cpp +++ b/modules/base/rendering/pointcloud/renderablepointcloud.cpp @@ -572,16 +572,18 @@ RenderablePointCloud::RenderablePointCloud(const ghoul::Dictionary& dictionary) _dataset = dataloader::data::loadFile(_dataFile, _dataMapping); } _nDataPoints = static_cast(_dataset.entries.size()); - } - // If no scale exponent was specified, compute one that will at least show the points - // based on the scale of the positions in the dataset - if (!p.sizeSettings.has_value() || !p.sizeSettings->scaleExponent.has_value()) { - double dist = _dataset.maxPositionComponent * toMeter(_unit); - float exponent = static_cast(std::log10(dist)); - // Reduce the actually used exponent a little bit, as just using the logarithm - // as is leads to very large points - _sizeSettings.scaleExponent = 0.9f * exponent; + // If no scale exponent was specified, compute one that will at least show the + // points based on the scale of the positions in the dataset + if (!p.sizeSettings.has_value() || !p.sizeSettings->scaleExponent.has_value()) { + double dist = _dataset.maxPositionComponent * toMeter(_unit); + if (dist > 0.0) { + float exponent = static_cast(std::log10(dist)); + // Reduce the actually used exponent a little bit, as just using the + // logarithm as is leads to very large points + _sizeSettings.scaleExponent = 0.9f * exponent; + } + } } _nDataPoints.setReadOnly(true); From 640ca3ed4912dc289218c3477899f4d1b692a0e7 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Wed, 17 Jan 2024 13:46:49 +0100 Subject: [PATCH 24/30] Feature/point cloud labels from csv (#2989) * Add ability to load labels directly from CSV/SPECK for PointClouds * Provide some more docs * Update the example asset for point clouds * Make both examples visible * Some cleanup * Apply suggestions from code review Co-authored-by: Alexander Bock --------- Co-authored-by: Alexander Bock --- .../pointclouds/points_units_labels.asset | 69 +++++++++++++++---- include/openspace/data/dataloader.h | 1 + include/openspace/data/datamapping.h | 3 + include/openspace/rendering/labelscomponent.h | 17 ++++- .../rendering/grids/renderableboxgrid.cpp | 1 - .../base/rendering/grids/renderablegrid.cpp | 1 - .../rendering/grids/renderableradialgrid.cpp | 1 - .../grids/renderablesphericalgrid.cpp | 1 - .../pointcloud/renderablepointcloud.cpp | 29 +++++--- .../rendering/renderableplanescloud.cpp | 1 - .../renderableconstellationsbase.cpp | 1 - src/data/csvloader.cpp | 11 ++- src/data/dataloader.cpp | 17 +++++ src/data/datamapping.cpp | 30 ++++++-- src/rendering/labelscomponent.cpp | 27 +++++++- 15 files changed, 171 insertions(+), 39 deletions(-) diff --git a/data/assets/examples/pointclouds/points_units_labels.asset b/data/assets/examples/pointclouds/points_units_labels.asset index a1d02c3247..e124879bcb 100644 --- a/data/assets/examples/pointclouds/points_units_labels.asset +++ b/data/assets/examples/pointclouds/points_units_labels.asset @@ -1,6 +1,6 @@ local earthAsset = asset.require("scene/solarsystem/planets/earth/earth") - +-- @TODO The labels are not correctly oriented towards the camera! local Example = { Identifier = "ExamplePoints_UnitsAndLabels", @@ -9,46 +9,89 @@ local Example = { Type = "RenderablePointCloud", File = asset.resource("data/dummydata.csv"), Coloring = { - FixedColor = { 0.0, 0.3, 1.0 } + FixedColor = { 0.3, 0.8, 0.3 } + }, + DataMapping = { + -- When loading labels from a CSV file, we need to provide information about + -- which column corresponds to the name to be used for the labels (this is + -- not required for SPECK files) + Name = "number_withNan" }, -- Add a unit to interpret the points to be in kilometers rather than meters Unit = "Km", - -- Also load a label file with the same position information as the CSV file. - -- The unit should be the same as the renderable + -- Add some labels. We also need to enable them for them to be visible. + -- Since we do not specify a label file (see below), the positions and text of + -- of the labels will be set based on the information in the CSV file Labels = { Enabled = true, - File = asset.resource("data/dummydata.label"), - Size = 7.5, - Unit = "Km" + Size = 7.5 } - -- @TODO The labels are not correctly oriented towards the camera! }, GUI = { Name = "Units & Labels", Path = "/Example/Point Clouds", - Description = [[Example of a point cloud where a spcific unit is used when - interpreting the position values, and text labels are placed at the points]] + Description = [[Example of a point cloud with labels created by specifying a 'Name' + column for the dataset. The positions of the labels will exactly match that of the + points]] + } +} + +local Example_LabelFromFile = { + Identifier = "ExamplePoints_UnitsAndLabels_File", + Parent = earthAsset.Earth.Identifier, + -- Rotate to not overlap with the other dataset + Transform = { + Rotation = { + Type = "StaticRotation", + Rotation = { 0, 0, -0.5 * math.pi } + } + }, + Renderable = { + Type = "RenderablePointCloud", + File = asset.resource("data/dummydata.csv"), + Coloring = { + FixedColor = { 0.0, 0.3, 1.0 } + }, + -- Add a unit to interpret the points to be in kilometers rather than meters + Unit = "Km", + -- Also load a label file with the positions of the label (in this case they are the + -- same as in the CSV file, but that is not always the case) + Labels = { + Enabled = true, + File = asset.resource("data/dummydata.label"), + Size = 7.5, + -- When we add an explicit label file we also have to specify the unit, if it is + -- different than meters + Unit = "Km" + } + }, + GUI = { + Name = "Units & Labels (Explicit Label file)", + Path = "/Example/Point Clouds", + Description = [[Example of a point cloud with labels, created from a label file]] } } asset.onInitialize(function() openspace.addSceneGraphNode(Example) + openspace.addSceneGraphNode(Example_LabelFromFile) end) asset.onDeinitialize(function() + openspace.removeSceneGraphNode(Example_LabelFromFile) openspace.removeSceneGraphNode(Example) end) asset.export(Example) - +asset.export(Example_LabelFromFile) asset.meta = { Name = "Example - Point Cloud with Unit and Labels", Version = "1.0", - Description = [[Example of a point cloud where a spcific unit is used when - interpreting the position values, and text labels are placed at the points]], + Description = [[Example of point clouds with labels, either set from the data file + itself or from a separate .label file]], Author = "OpenSpace Team", URL = "http://openspaceproject.com", License = "MIT license" diff --git a/include/openspace/data/dataloader.h b/include/openspace/data/dataloader.h index 8e0e5920ca..4c8ef8e918 100644 --- a/include/openspace/data/dataloader.h +++ b/include/openspace/data/dataloader.h @@ -119,6 +119,7 @@ namespace label { Labelset loadFileWithCache(std::filesystem::path path); + Labelset loadFromDataset(const dataloader::Dataset& dataset); } // namespace label namespace color { diff --git a/include/openspace/data/datamapping.h b/include/openspace/data/datamapping.h index bec5890a18..791f4d4420 100644 --- a/include/openspace/data/datamapping.h +++ b/include/openspace/data/datamapping.h @@ -44,6 +44,7 @@ struct DataMapping { std::optional xColumnName; std::optional yColumnName; std::optional zColumnName; + std::optional nameColumn; std::optional missingDataValue; @@ -69,6 +70,8 @@ bool isColumnY(const std::string& c, const std::optional& mapping); bool isColumnZ(const std::string& c, const std::optional& mapping); +bool isNameColumn(const std::string& c, const std::optional& mapping); + } // namespace openspace::dataloader #endif // __OPENSPACE_CORE___DATAMAPPING___H__ diff --git a/include/openspace/rendering/labelscomponent.h b/include/openspace/rendering/labelscomponent.h index c00fbfc605..ee0c9b6bf3 100644 --- a/include/openspace/rendering/labelscomponent.h +++ b/include/openspace/rendering/labelscomponent.h @@ -47,6 +47,20 @@ namespace documentation { struct Documentation; } class LabelsComponent : public properties::PropertyOwner, public Fadeable { public: explicit LabelsComponent(const ghoul::Dictionary& dictionary); + + /** + * Create a labels component from an already loaded dataset. That dataset should have + * a comment per point to be used for the labels. + * + * \param dictionary A dictionary with the other information used for constructing + * the dataset + * \param dataset The dataset to create the labelset from, including xyz position and + * a string to be used for the text. + * \param unit The unit to use when interpreting the point information in the dataset + */ + explicit LabelsComponent(const ghoul::Dictionary& dictionary, + const dataloader::Dataset& dataset, DistanceUnit unit); + ~LabelsComponent() override = default; dataloader::Labelset& labelSet(); @@ -76,7 +90,8 @@ private: glm::dmat4 _transformationMatrix = glm::dmat4(1.0); - // Properties + bool _createdFromDataset = false; + properties::BoolProperty _enabled; properties::Vec3Property _color; properties::FloatProperty _size; diff --git a/modules/base/rendering/grids/renderableboxgrid.cpp b/modules/base/rendering/grids/renderableboxgrid.cpp index c3712e9eec..e0099c512e 100644 --- a/modules/base/rendering/grids/renderableboxgrid.cpp +++ b/modules/base/rendering/grids/renderableboxgrid.cpp @@ -124,7 +124,6 @@ bool RenderableBoxGrid::isReady() const { void RenderableBoxGrid::initialize() { if (_hasLabels) { _labels->initialize(); - _labels->loadLabels(); } } diff --git a/modules/base/rendering/grids/renderablegrid.cpp b/modules/base/rendering/grids/renderablegrid.cpp index c75afc7cdc..413885e4a4 100644 --- a/modules/base/rendering/grids/renderablegrid.cpp +++ b/modules/base/rendering/grids/renderablegrid.cpp @@ -192,7 +192,6 @@ bool RenderableGrid::isReady() const { void RenderableGrid::initialize() { if (_hasLabels) { _labels->initialize(); - _labels->loadLabels(); } } diff --git a/modules/base/rendering/grids/renderableradialgrid.cpp b/modules/base/rendering/grids/renderableradialgrid.cpp index 5c231a3dca..48ed3815e3 100644 --- a/modules/base/rendering/grids/renderableradialgrid.cpp +++ b/modules/base/rendering/grids/renderableradialgrid.cpp @@ -169,7 +169,6 @@ bool RenderableRadialGrid::isReady() const { void RenderableRadialGrid::initialize() { if (_hasLabels) { _labels->initialize(); - _labels->loadLabels(); } } diff --git a/modules/base/rendering/grids/renderablesphericalgrid.cpp b/modules/base/rendering/grids/renderablesphericalgrid.cpp index a0f2a1fe61..5a4007e82d 100644 --- a/modules/base/rendering/grids/renderablesphericalgrid.cpp +++ b/modules/base/rendering/grids/renderablesphericalgrid.cpp @@ -136,7 +136,6 @@ bool RenderableSphericalGrid::isReady() const { void RenderableSphericalGrid::initialize() { if (_hasLabels) { _labels->initialize(); - _labels->loadLabels(); } } diff --git a/modules/base/rendering/pointcloud/renderablepointcloud.cpp b/modules/base/rendering/pointcloud/renderablepointcloud.cpp index f7319b3bea..be5d3fd6e6 100644 --- a/modules/base/rendering/pointcloud/renderablepointcloud.cpp +++ b/modules/base/rendering/pointcloud/renderablepointcloud.cpp @@ -104,7 +104,10 @@ namespace { static const openspace::properties::PropertyOwner::PropertyOwnerInfo LabelsInfo = { "Labels", "Labels", - "The labels for the points" + "The labels for the points. If no label file is provided, the labels will be " + "created to match the points in the data file. For a CSV file, you should then " + "specify which column is the 'Name' column in the data mapping. For SPECK files " + "the labels are created from the comment at the end of each line" }; constexpr openspace::properties::Property::PropertyInfo RenderOptionInfo = { @@ -524,14 +527,6 @@ RenderablePointCloud::RenderablePointCloud(const ghoul::Dictionary& dictionary) _hasSpriteTexture = p.texture.has_value(); - if (p.labels.has_value()) { - _labels = std::make_unique(*p.labels); - _hasLabels = true; - addPropertySubOwner(_labels.get()); - // Fading of the labels should also depend on the fading of the renderable - _labels->setParentFadeable(this); - } - _transformationMatrix = p.transformationMatrix.value_or(_transformationMatrix); if (p.sizeSettings.has_value() && p.sizeSettings->sizeMapping.has_value()) { @@ -586,6 +581,21 @@ RenderablePointCloud::RenderablePointCloud(const ghoul::Dictionary& dictionary) } } + if (p.labels.has_value()) { + if (!p.labels->hasKey("File") && _hasDataFile) { + // Load the labelset from the dataset if no file was included + _labels = std::make_unique(*p.labels, _dataset, _unit); + } + else { + _labels = std::make_unique(*p.labels); + } + + _hasLabels = true; + addPropertySubOwner(_labels.get()); + // Fading of the labels should also depend on the fading of the renderable + _labels->setParentFadeable(this); + } + _nDataPoints.setReadOnly(true); addProperty(_nDataPoints); } @@ -609,7 +619,6 @@ void RenderablePointCloud::initialize() { if (_hasLabels) { _labels->initialize(); - _labels->loadLabels(); } } diff --git a/modules/digitaluniverse/rendering/renderableplanescloud.cpp b/modules/digitaluniverse/rendering/renderableplanescloud.cpp index ce8ce811d3..b0d635a2cb 100644 --- a/modules/digitaluniverse/rendering/renderableplanescloud.cpp +++ b/modules/digitaluniverse/rendering/renderableplanescloud.cpp @@ -330,7 +330,6 @@ void RenderablePlanesCloud::initialize() { if (_hasLabels) { _labels->initialize(); - _labels->loadLabels(); } } diff --git a/modules/space/rendering/renderableconstellationsbase.cpp b/modules/space/rendering/renderableconstellationsbase.cpp index ace7b0c53d..627ef98d0a 100644 --- a/modules/space/rendering/renderableconstellationsbase.cpp +++ b/modules/space/rendering/renderableconstellationsbase.cpp @@ -193,7 +193,6 @@ void RenderableConstellationsBase::initialize() { } _labels->initialize(); - _labels->loadLabels(); for (dataloader::Labelset::Entry& entry : _labels->labelSet().entries) { if (!entry.identifier.empty()) { diff --git a/src/data/csvloader.cpp b/src/data/csvloader.cpp index 7da87bf571..5b7febda75 100644 --- a/src/data/csvloader.cpp +++ b/src/data/csvloader.cpp @@ -93,6 +93,7 @@ Dataset loadCsvFile(std::filesystem::path filePath, std::optional s int xColumn = -1; int yColumn = -1; int zColumn = -1; + int nameColumn = -1; int nDataColumns = 0; bool hasExcludeColumns = specs.has_value() && (*specs).hasExcludeColumns(); @@ -115,6 +116,9 @@ Dataset loadCsvFile(std::filesystem::path filePath, std::optional s zColumn = static_cast(i); } } + else if (isNameColumn(col, specs)) { + nameColumn = static_cast(i); + } else if (hasExcludeColumns && (*specs).isExcludeColumn(col)) { skipColumns.push_back(i); continue; @@ -170,11 +174,14 @@ Dataset loadCsvFile(std::filesystem::path filePath, std::optional s else if (i == zColumn) { entry.position.z = value; } + else if (i == nameColumn) { + // Note that were we use the original stirng value, rather than the + // converted one + entry.comment = strValue; + } else { entry.data.push_back(value); } - - // @TODO: comment mapping } glm::vec3 positive = glm::abs(entry.position); diff --git a/src/data/dataloader.cpp b/src/data/dataloader.cpp index e2af74e0b0..1035358c8a 100644 --- a/src/data/dataloader.cpp +++ b/src/data/dataloader.cpp @@ -458,6 +458,23 @@ Labelset loadFileWithCache(std::filesystem::path filePath) { ); } +Labelset loadFromDataset(const Dataset& dataset) { + Labelset res; + res.entries.reserve(dataset.entries.size()); + + int count = 0; + for (const Dataset::Entry& entry : dataset.entries) { + Labelset::Entry label; + label.position = entry.position; + label.text = entry.comment.value_or("MISSING LABEL"); + // @TODO: make is possible to configure this identifier? + label.identifier = fmt::format("Point-{}", count); + res.entries.push_back(std::move(label)); + } + + return res; +} + } // namespace label namespace color { diff --git a/src/data/datamapping.cpp b/src/data/datamapping.cpp index eba72d6178..463be7d747 100644 --- a/src/data/datamapping.cpp +++ b/src/data/datamapping.cpp @@ -39,7 +39,7 @@ namespace { X, Y, Z }; - bool checkColumnInternal(PositionColumn columnCase, const std::string& c, + bool checkPosColumnInternal(PositionColumn columnCase, const std::string& c, const std::optional& mapping, const std::string_view defaultValue) { @@ -88,6 +88,10 @@ namespace { // Specifies the column name for the z coordinate std::optional z; + // Specifies the column name for the optional name column. Not valid for SPECK + // files, where the name is given by the comment at the end of each line + std::optional name; + // Specifies whether to do case sensitive checks when reading column names. // Default is not to, so that 'X' and 'x' are both valid column names for the // x position column, for example @@ -119,6 +123,7 @@ DataMapping DataMapping::createFromDictionary(const ghoul::Dictionary& dictionar result.xColumnName = p.x; result.yColumnName = p.y; result.zColumnName = p.z; + result.nameColumn = p.name; result.missingDataValue = p.missingDataValue; @@ -145,10 +150,11 @@ std::string generateHashString(const DataMapping& dm) { unsigned int excludeColumnsHash = ghoul::hashCRC32(a); return fmt::format( - "DM|x{}|y{}|z{}|m{}|{}|{}", + "DM|x{}|y{}|z{}|name{}|m{}|{}|{}", dm.xColumnName.value_or(""), dm.yColumnName.value_or(""), dm.zColumnName.value_or(""), + dm.nameColumn.value_or(""), dm.missingDataValue.has_value() ? ghoul::to_string(*dm.missingDataValue) : "", dm.isCaseSensitive ? "1" : "0", excludeColumnsHash @@ -160,15 +166,29 @@ bool isPositionColumn(const std::string& c, const std::optional& ma } bool isColumnX(const std::string& c, const std::optional& mapping) { - return checkColumnInternal(PositionColumn::X, c, mapping, DefaultX); + return checkPosColumnInternal(PositionColumn::X, c, mapping, DefaultX); } bool isColumnY(const std::string& c, const std::optional& mapping) { - return checkColumnInternal(PositionColumn::Y, c, mapping, DefaultY); + return checkPosColumnInternal(PositionColumn::Y, c, mapping, DefaultY); } bool isColumnZ(const std::string& c, const std::optional& mapping) { - return checkColumnInternal(PositionColumn::Z, c, mapping, DefaultZ); + return checkPosColumnInternal(PositionColumn::Z, c, mapping, DefaultZ); +} + +bool isNameColumn(const std::string& c, const std::optional& mapping) { + if (!mapping.has_value() || !mapping->nameColumn.has_value()) { + return false; + } + + std::string testColumn = c; + std::string mappedColumn = *mapping->nameColumn; + if (!mapping->isCaseSensitive) { + testColumn = ghoul::toLowerCase(testColumn); + mappedColumn = ghoul::toLowerCase(mappedColumn); + } + return testColumn == mappedColumn; } } // namespace openspace::dataloader diff --git a/src/rendering/labelscomponent.cpp b/src/rendering/labelscomponent.cpp index 983d5c8285..25ad45e7e5 100644 --- a/src/rendering/labelscomponent.cpp +++ b/src/rendering/labelscomponent.cpp @@ -105,7 +105,7 @@ namespace { std::optional enabled; // [[codegen::verbatim(FileInfo.description)]] - std::filesystem::path file; + std::optional file; // If true (default), the loaded labels file will be cached so that it can be // loaded faster at a later time. Note that this also means that changes in the @@ -170,7 +170,7 @@ LabelsComponent::LabelsComponent(const ghoul::Dictionary& dictionary) { const Parameters p = codegen::bake(dictionary); - _labelFile = absPath(p.file); + _labelFile = absPath(p.file.value_or("")); _useCache = p.useCaching.value_or(true); if (p.unit.has_value()) { @@ -223,6 +223,21 @@ LabelsComponent::LabelsComponent(const ghoul::Dictionary& dictionary) _transformationMatrix = p.transformationMatrix.value_or(_transformationMatrix); } +LabelsComponent::LabelsComponent(const ghoul::Dictionary& dictionary, + const dataloader::Dataset& dataset, + DistanceUnit unit) + : LabelsComponent(dictionary) +{ + // The unit should match the one in the dataset, not the one that was included in the + // asset (if any) + _unit = unit; + + // Load the labelset directly based on the dataset, and keep track of that it has + // already been loaded this way + _labelset = dataloader::label::loadFromDataset(dataset); + _createdFromDataset = true; +} + dataloader::Labelset& LabelsComponent::labelSet() { return _labelset; } @@ -238,10 +253,18 @@ void LabelsComponent::initialize() { ghoul::fontrendering::FontManager::Outline::Yes, ghoul::fontrendering::FontManager::LoadGlyphs::No ); + + loadLabels(); } void LabelsComponent::loadLabels() { LINFO(fmt::format("Loading label file {}", _labelFile)); + + if (_createdFromDataset) { + // The labelset should already have been loaded + return; + } + if (_useCache) { _labelset = dataloader::label::loadFileWithCache(_labelFile); } From 9959c2b94c216d9631720ca8513eb144d2e62408 Mon Sep 17 00:00:00 2001 From: timol085 Date: Wed, 17 Jan 2024 16:45:33 +0100 Subject: [PATCH 25/30] Add missing include file for mac --- src/data/speckloader.cpp | 2 ++ src/engine/settings.cpp | 1 + src/rendering/loadingscreen.cpp | 2 ++ tests/test_sgctedit.cpp | 1 + 4 files changed, 6 insertions(+) diff --git a/src/data/speckloader.cpp b/src/data/speckloader.cpp index ee26953f5e..d71a349ee1 100644 --- a/src/data/speckloader.cpp +++ b/src/data/speckloader.cpp @@ -34,8 +34,10 @@ #include #include #include +#include #include + namespace { bool startsWith(std::string lhs, std::string_view rhs) noexcept { lhs = ghoul::toLowerCase(lhs); diff --git a/src/engine/settings.cpp b/src/engine/settings.cpp index e1df61f429..3eb054b262 100644 --- a/src/engine/settings.cpp +++ b/src/engine/settings.cpp @@ -25,6 +25,7 @@ #include #include +#include namespace openspace { diff --git a/src/rendering/loadingscreen.cpp b/src/rendering/loadingscreen.cpp index d256bca6f2..9c20088155 100644 --- a/src/rendering/loadingscreen.cpp +++ b/src/rendering/loadingscreen.cpp @@ -41,8 +41,10 @@ #include #include #include +#include #include + namespace { constexpr float LoadingFontSize = 25.f; constexpr float MessageFontSize = 22.f; diff --git a/tests/test_sgctedit.cpp b/tests/test_sgctedit.cpp index bca8b65e8d..ed78cbeb75 100644 --- a/tests/test_sgctedit.cpp +++ b/tests/test_sgctedit.cpp @@ -33,6 +33,7 @@ #include #include #include +#include using namespace openspace; From 27608634b2fb169b64a0eeea74f95c84a5253800 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jan 2024 09:58:20 +0100 Subject: [PATCH 26/30] Remove warnings (#2999) * Remove warnings for MSVC, GCC, and Clang 17 --- .../ext/launcher/include/settingsdialog.h | 2 +- .../ext/launcher/src/launcherwindow.cpp | 4 +- .../ext/launcher/src/sgctedit/sgctedit.cpp | 4 +- apps/OpenSpace/ext/sgct | 2 +- ext/ghoul | 2 +- include/openspace/util/distanceconversion.h | 4 - include/openspace/util/timeconversion.h | 4 - modules/base/rendering/renderablemodel.cpp | 2 +- modules/gaia/tasks/readfilejob.cpp | 4 - .../src/geojson/geojsoncomponent.cpp | 2 +- .../src/geojson/geojsonproperties.cpp | 2 +- modules/globebrowsing/src/layer.cpp | 5 +- modules/globebrowsing/src/layer.h | 2 +- .../globebrowsing/src/rawtiledatareader.cpp | 126 ------------------ modules/globebrowsing/src/renderableglobe.cpp | 3 +- modules/skybrowser/src/wwtcommunicator.cpp | 9 -- .../rendering/renderableorbitalkepler.cpp | 6 +- modules/sync/syncs/urlsynchronization.cpp | 2 - src/data/csvloader.cpp | 10 +- src/data/dataloader.cpp | 4 - src/interaction/actionmanager.cpp | 20 +-- src/navigation/orbitalnavigator.cpp | 5 - src/rendering/colormappingcomponent.cpp | 2 +- src/scene/assetmanager.cpp | 5 +- src/util/resourcesynchronization.cpp | 2 +- .../set_openspace_compile_settings.cmake | 2 + 26 files changed, 39 insertions(+), 196 deletions(-) diff --git a/apps/OpenSpace/ext/launcher/include/settingsdialog.h b/apps/OpenSpace/ext/launcher/include/settingsdialog.h index 54ba955ec0..dcd2aa89c0 100644 --- a/apps/OpenSpace/ext/launcher/include/settingsdialog.h +++ b/apps/OpenSpace/ext/launcher/include/settingsdialog.h @@ -50,7 +50,7 @@ private: void updateSaveButton(); void save(); - void reject(); + void reject() override; QLineEdit* _configuration = nullptr; QCheckBox* _rememberLastConfiguration = nullptr; diff --git a/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp b/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp index 9c507e4f1d..98d222cdaa 100644 --- a/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp +++ b/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp @@ -401,8 +401,8 @@ QWidget* LauncherWindow::createCentralWidget() { connect( &dialog, &SettingsDialog::saveSettings, - [](Settings settings) { - saveSettings(settings, findSettings()); + [](Settings s) { + saveSettings(s, findSettings()); } ); diff --git a/apps/OpenSpace/ext/launcher/src/sgctedit/sgctedit.cpp b/apps/OpenSpace/ext/launcher/src/sgctedit/sgctedit.cpp index 2a98f99b78..08d72eaa49 100644 --- a/apps/OpenSpace/ext/launcher/src/sgctedit/sgctedit.cpp +++ b/apps/OpenSpace/ext/launcher/src/sgctedit/sgctedit.cpp @@ -142,7 +142,7 @@ void SgctEdit::setupStateOfUiOnFirstWindow(size_t nWindows) { bool firstWindowGuiIsEnabled = (nWindows > 1); int graphicsSelectionForFirstWindow = 0; int nGuiRenderTagsFound = 0; - _settingsWidget->nWindowsDisplayedChanged(nWindows); + _settingsWidget->nWindowsDisplayedChanged(static_cast(nWindows)); for (size_t i = 0; i < nWindows; ++i) { sgct::config::Window& w = _cluster.nodes.front().windows[i]; @@ -185,7 +185,7 @@ void SgctEdit::setupStateOfUiOnFirstWindow(size_t nWindows) { // Call these again in order to ensure that GUI is configured correctly based on // the values read from the config file _settingsWidget->setEnableShowUiOnFirstWindowCheckbox(true); - _settingsWidget->nWindowsDisplayedChanged(nWindows); + _settingsWidget->nWindowsDisplayedChanged(static_cast(nWindows)); } _settingsWidget->setGraphicsSelectionForShowUiOnFirstWindow( graphicsSelectionForFirstWindow diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index 9ee34038be..cd588a8090 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit 9ee34038be3a8c0fe2410e5f511688f1ff816392 +Subproject commit cd588a809006263554950a51aeb0cb9cf4848417 diff --git a/ext/ghoul b/ext/ghoul index d607a6d6b1..ba6aece1de 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit d607a6d6b11be4ad05ccd555b8b290a782e0e384 +Subproject commit ba6aece1deb12599fcaa61be133658534ed84425 diff --git a/include/openspace/util/distanceconversion.h b/include/openspace/util/distanceconversion.h index 989951b229..52e568e63c 100644 --- a/include/openspace/util/distanceconversion.h +++ b/include/openspace/util/distanceconversion.h @@ -157,20 +157,16 @@ DistanceUnitNamesPlural = { }; constexpr bool isValidDistanceUnitName(std::string_view name) { - int i = 0; for (std::string_view val : DistanceUnitNamesSingular) { if (val == name) { return true; } - ++i; } - i = 0; for (std::string_view val : DistanceUnitNamesPlural) { if (val == name) { return true; } - ++i; } return false; } diff --git a/include/openspace/util/timeconversion.h b/include/openspace/util/timeconversion.h index e4aaa8846e..753d84c7da 100644 --- a/include/openspace/util/timeconversion.h +++ b/include/openspace/util/timeconversion.h @@ -100,20 +100,16 @@ TimeUnitNamesPlural = { }; constexpr bool isValidTimeUnitName(std::string_view name) { - int i = 0; for (std::string_view val : TimeUnitNamesSingular) { if (val == name) { return true; } - ++i; } - i = 0; for (std::string_view val : TimeUnitNamesPlural) { if (val == name) { return true; } - ++i; } return false; } diff --git a/modules/base/rendering/renderablemodel.cpp b/modules/base/rendering/renderablemodel.cpp index 1264099bd2..d6a9aa5569 100644 --- a/modules/base/rendering/renderablemodel.cpp +++ b/modules/base/rendering/renderablemodel.cpp @@ -593,7 +593,7 @@ void RenderableModel::initializeGL() { } // Set animation settings - _geometry->setTimeScale(_animationTimeScale); + _geometry->setTimeScale(static_cast(_animationTimeScale)); } // Initialize shaders diff --git a/modules/gaia/tasks/readfilejob.cpp b/modules/gaia/tasks/readfilejob.cpp index 005f94523d..8377062677 100644 --- a/modules/gaia/tasks/readfilejob.cpp +++ b/modules/gaia/tasks/readfilejob.cpp @@ -65,7 +65,6 @@ void ReadFileJob::execute() { int nStars = table->readRows - _firstRow + 1; - int nNullArr = 0; size_t nColumnsRead = _allColumns.size(); if (nColumnsRead != _nDefaultCols) { LINFO( @@ -117,7 +116,6 @@ void ReadFileJob::execute() { // Return early if star doesn't have a measured position. if (std::isnan(ra[i]) || std::isnan(dec[i])) { - nNullArr++; continue; } @@ -260,8 +258,6 @@ void ReadFileJob::execute() { _octants[index].insert(_octants[index].end(), values.begin(), values.end()); } - - // LINFO(fmt::format("{} out of {} read stars were nullArrays", nNullArr, nStars)); } std::vector> ReadFileJob::product() { diff --git a/modules/globebrowsing/src/geojson/geojsoncomponent.cpp b/modules/globebrowsing/src/geojson/geojsoncomponent.cpp index e87bf58e67..287fae4d5c 100644 --- a/modules/globebrowsing/src/geojson/geojsoncomponent.cpp +++ b/modules/globebrowsing/src/geojson/geojsoncomponent.cpp @@ -313,8 +313,8 @@ GeoJsonComponent::GeoJsonComponent(const ghoul::Dictionary& dictionary, glm::vec2(90.f, 180.f) ) , _flyToFeature(FlyToFeatureInfo) - , _deleteThisComponent(DeleteInfo) , _deletePropertyOwner({ "Deletion", "Deletion" }) + , _deleteThisComponent(DeleteInfo) , _lightSourcePropertyOwner({ "LightSources", "Light Sources" }) , _featuresPropertyOwner({ "Features", "Features" }) { diff --git a/modules/globebrowsing/src/geojson/geojsonproperties.cpp b/modules/globebrowsing/src/geojson/geojsonproperties.cpp index 2b96742276..35e0aca85e 100644 --- a/modules/globebrowsing/src/geojson/geojsonproperties.cpp +++ b/modules/globebrowsing/src/geojson/geojsonproperties.cpp @@ -151,7 +151,7 @@ namespace { } } return color; - }; + } constexpr openspace::properties::Property::PropertyInfo OpacityInfo = { "Opacity", diff --git a/modules/globebrowsing/src/layer.cpp b/modules/globebrowsing/src/layer.cpp index f82930fe5d..9863383105 100644 --- a/modules/globebrowsing/src/layer.cpp +++ b/modules/globebrowsing/src/layer.cpp @@ -223,8 +223,6 @@ Layer::Layer(layers::Group::ID id, const ghoul::Dictionary& layerDict, LayerGrou addProperty(_guiDescription); } - TileTextureInitData initData = tileTextureInitData(_layerGroupId); - _opacity = p.opacity.value_or(_opacity); addProperty(Fadeable::_opacity); addProperty(Fadeable::_fade); @@ -457,8 +455,7 @@ void Layer::update() { } glm::vec2 Layer::tileUvToTextureSamplePosition(const TileUvTransform& uvTransform, - const glm::vec2& tileUV, - const glm::uvec2& resolution) + const glm::vec2& tileUV) { glm::vec2 uv = uvTransform.uvOffset + uvTransform.uvScale * tileUV; return uv; diff --git a/modules/globebrowsing/src/layer.h b/modules/globebrowsing/src/layer.h index e0679deda0..e6d272dcd9 100644 --- a/modules/globebrowsing/src/layer.h +++ b/modules/globebrowsing/src/layer.h @@ -69,7 +69,7 @@ public: void update(); glm::vec2 tileUvToTextureSamplePosition(const TileUvTransform& uvTransform, - const glm::vec2& tileUV, const glm::uvec2& resolution); + const glm::vec2& tileUV); static documentation::Documentation Documentation(); diff --git a/modules/globebrowsing/src/rawtiledatareader.cpp b/modules/globebrowsing/src/rawtiledatareader.cpp index 14fe3a01a8..1a7d8dd0cf 100644 --- a/modules/globebrowsing/src/rawtiledatareader.cpp +++ b/modules/globebrowsing/src/rawtiledatareader.cpp @@ -140,110 +140,6 @@ int calculateTileLevelDifference(GDALDataset* dataset, int minimumPixelSize) { return static_cast(intdiff); } -/** - * Aligns one the sides of the pixel regino to the specified position. This does - * not change the number of pixels within the region. - * - * Example: Side = left and pos = 16: - * start.x = 16 and keep the size the same - */ -void alignPixelRegion(PixelRegion& pixelRegion, Side side, int pos) { - switch (side) { - case Side::Left: - pixelRegion.start.x = pos; - break; - case Side::Top: - pixelRegion.start.y = pos; - break; - case Side::Right: - pixelRegion.start.x = pos - pixelRegion.numPixels.x; - break; - case Side::Bottom: - pixelRegion.start.y = pos - pixelRegion.numPixels.y; - break; - } -} - -PixelRegion globalCut(PixelRegion& pixelRegion, Side side, int p) { - const bool lineIntersect = [pr = pixelRegion, side, p]() { - switch (side) { - case Side::Left: - case Side::Right: - return pr.start.x <= p && p <= (pr.start.x + pr.numPixels.x); - case Side::Top: - case Side::Bottom: - return pr.start.y <= p && p <= (pr.start.y + pr.numPixels.y); - default: - throw ghoul::MissingCaseException(); - } - }(); - - if (!lineIntersect) { - return PixelRegion(); - } - - auto setSide = [](PixelRegion& pr, Side s, int pos) { - switch (s) { - case Side::Left: - pr.numPixels.x += (pr.start.x - pos); - pr.start.x = pos; - break; - case Side::Top: - pr.numPixels.y += (pr.start.y - pos); - pr.start.y = pos; - break; - case Side::Right: - pr.numPixels.x = pos - pr.start.x; - break; - case Side::Bottom: - pr.numPixels.y = pos - pr.start.y; - break; - } - }; - - PixelRegion cutOff(pixelRegion); - int cutSize = 0; - switch (side) { - case Side::Left: - setSide(pixelRegion, Side::Left, p); - setSide(cutOff, Side::Right, p - cutSize); - break; - case Side::Top: - setSide(pixelRegion, Side::Top, p); - setSide(cutOff, Side::Bottom, p - cutSize); - break; - case Side::Right: - setSide(pixelRegion, Side::Right, p); - setSide(cutOff, Side::Left, p + cutSize); - break; - case Side::Bottom: - setSide(pixelRegion, Side::Bottom, p); - setSide(cutOff, Side::Top, p + cutSize); - break; - } - return cutOff; -} - -int edge(const PixelRegion& pixelRegion, Side side) { - switch (side) { - case Side::Left: return pixelRegion.start.x; - case Side::Top: return pixelRegion.start.y; - case Side::Right: return pixelRegion.start.x + pixelRegion.numPixels.x; - case Side::Bottom: return pixelRegion.start.y + pixelRegion.numPixels.y; - default: throw ghoul::MissingCaseException(); - } -} - -PixelRegion localCut(PixelRegion& pr, Side side, int localPos) { - if (localPos < 1) { - return PixelRegion(); - } - else { - const int edgeDirectionSign = (side < Side::Right) ? -1 : 1; - return globalCut(pr, side, edge(pr, side) - edgeDirectionSign * localPos); - } -} - bool isInside(const PixelRegion& lhs, const PixelRegion& rhs) { glm::ivec2 e = lhs.start + lhs.numPixels; glm::ivec2 re = rhs.start + rhs.numPixels; @@ -251,28 +147,6 @@ bool isInside(const PixelRegion& lhs, const PixelRegion& rhs) { rhs.start.y <= lhs.start.y && e.y <= re.y; } -IODescription cutIODescription(IODescription& io, Side side, int pos) { - glm::dvec2 ratio = glm::dvec2( - io.write.region.numPixels.x / static_cast(io.read.region.numPixels.x), - io.write.region.numPixels.y / static_cast(io.read.region.numPixels.y) - ); - - IODescription whatCameOff = io; - whatCameOff.read.region = globalCut(io.read.region, side, pos); - - glm::ivec2 cutSize = whatCameOff.read.region.numPixels; - glm::ivec2 localWriteCutSize = ratio * glm::dvec2(cutSize); - - int localWriteCutPos = - (side == Side::Left || side == Side::Right) ? - localWriteCutSize.x : - localWriteCutSize.y; - - whatCameOff.write.region = localCut(io.write.region, side, localWriteCutPos); - - return whatCameOff; -} - /** * Returns the geo transform from raster space to projection coordinates as defined * by GDAL. diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index 475679d262..44898268fa 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -1987,8 +1987,7 @@ float RenderableGlobe::getHeight(const glm::dvec3& position) const { glm::vec2 transformedUv = layer->tileUvToTextureSamplePosition( uvTransform, - patchUV, - glm::uvec2(tileTexture->dimensions()) + patchUV ); // Sample and do linear interpolation diff --git a/modules/skybrowser/src/wwtcommunicator.cpp b/modules/skybrowser/src/wwtcommunicator.cpp index 67c7224f98..93b9a27524 100644 --- a/modules/skybrowser/src/wwtcommunicator.cpp +++ b/modules/skybrowser/src/wwtcommunicator.cpp @@ -58,15 +58,6 @@ namespace { return msg; } - ghoul::Dictionary setForegroundMessage(const std::string& name) { - using namespace std::string_literals; - - ghoul::Dictionary msg; - msg.setValue("event", "set_foreground_by_name"s); - msg.setValue("name", name); - return msg; - } - ghoul::Dictionary addImageMessage(const std::string& url) { using namespace std::string_literals; diff --git a/modules/space/rendering/renderableorbitalkepler.cpp b/modules/space/rendering/renderableorbitalkepler.cpp index 06510b1379..438c0fbad3 100644 --- a/modules/space/rendering/renderableorbitalkepler.cpp +++ b/modules/space/rendering/renderableorbitalkepler.cpp @@ -354,11 +354,11 @@ void RenderableOrbitalKepler::updateBuffers() { _segmentSize.clear(); _startIndex.clear(); _startIndex.push_back(0); - for (int i = 0; i < parameters.size(); ++i) { + for (size_t i = 0; i < parameters.size(); ++i) { const double scale = static_cast(_segmentQuality) * 10.0; const kepler::Parameters& p = parameters[i]; _segmentSize.push_back( - static_cast(scale + (scale / pow(1 - p.eccentricity, 1.2))) + static_cast(scale + (scale / pow(1.0 - p.eccentricity, 1.2))) ); _startIndex.push_back(_startIndex[i] + static_cast(_segmentSize[i])); } @@ -388,7 +388,7 @@ void RenderableOrbitalKepler::updateBuffers() { orbit.epoch ); - for (size_t j = 0 ; j < (_segmentSize[orbitIdx]); ++j) { + for (GLint j = 0 ; j < (_segmentSize[orbitIdx]); ++j) { double timeOffset = orbit.period * static_cast(j) / static_cast(_segmentSize[orbitIdx] - 1); diff --git a/modules/sync/syncs/urlsynchronization.cpp b/modules/sync/syncs/urlsynchronization.cpp index df3b67acd4..8e4ac2cc2a 100644 --- a/modules/sync/syncs/urlsynchronization.cpp +++ b/modules/sync/syncs/urlsynchronization.cpp @@ -293,7 +293,6 @@ bool UrlSynchronization::trySyncUrls() { std::unordered_map sizeData; std::mutex fileSizeMutex; - size_t nDownloads = 0; std::atomic_bool startedAllDownloads = false; std::vector> downloads; @@ -327,7 +326,6 @@ bool UrlSynchronization::trySyncUrls() { downloads.push_back(std::move(download)); - ++nDownloads; sizeData[url] = SizeData(); dl->onProgress( diff --git a/src/data/csvloader.cpp b/src/data/csvloader.cpp index 5b7febda75..e498c5d246 100644 --- a/src/data/csvloader.cpp +++ b/src/data/csvloader.cpp @@ -57,7 +57,7 @@ Dataset loadCsvFile(std::filesystem::path filePath, std::optional s return result; } return std::numeric_limits::quiet_NaN(); -#else +#else // ^^^^ WIN32 // !WIN32 vvvv // clang is missing float support for std::from_chars try { result = std::stof(str.c_str(), nullptr); @@ -65,9 +65,9 @@ Dataset loadCsvFile(std::filesystem::path filePath, std::optional s return result; } } - catch (std::invalid_argument const& e) {} + catch (const std::invalid_argument&) {} return NAN; -#endif +#endif // WIN32 }; LDEBUG("Parsing CSV file"); @@ -142,7 +142,7 @@ Dataset loadCsvFile(std::filesystem::path filePath, std::optional s LINFO(fmt::format( "Loading {} rows with {} columns", rows.size(), columns.size() )); - ProgressBar progress(rows.size()); + ProgressBar progress = ProgressBar(static_cast(rows.size())); // Skip first row (column names) for (size_t rowIdx = 1; rowIdx < rows.size(); ++rowIdx) { @@ -192,7 +192,7 @@ Dataset loadCsvFile(std::filesystem::path filePath, std::optional s res.entries.push_back(entry); - progress.print(rowIdx + 1); + progress.print(static_cast(rowIdx + 1)); } return res; diff --git a/src/data/dataloader.cpp b/src/data/dataloader.cpp index 1035358c8a..7c2aa4a8d6 100644 --- a/src/data/dataloader.cpp +++ b/src/data/dataloader.cpp @@ -44,10 +44,6 @@ namespace { constexpr int8_t LabelCacheFileVersion = 11; constexpr int8_t ColorCacheFileVersion = 11; - constexpr std::string_view DefaultXColumn = "x"; - constexpr std::string_view DefaultYColumn = "y"; - constexpr std::string_view DefaultZColumn = "z"; - template void checkSize(U value, std::string_view message) { if (value > std::numeric_limits::max()) { diff --git a/src/interaction/actionmanager.cpp b/src/interaction/actionmanager.cpp index c52f00f42f..3a20f481f9 100644 --- a/src/interaction/actionmanager.cpp +++ b/src/interaction/actionmanager.cpp @@ -99,16 +99,20 @@ void ActionManager::triggerAction(const std::string& identifier, a.command : fmt::format("args = {}\n{}", ghoul::formatLua(arguments), a.command); - using ShouldBeSynchronized = scripting::ScriptEngine::ShouldBeSynchronized; - using ShouldSendToRemote = scripting::ScriptEngine::ShouldSendToRemote; - ShouldBeSynchronized sync = ShouldBeSynchronized::Yes; - ShouldSendToRemote send = ShouldSendToRemote::Yes; if (!shouldBeSynchronized || a.isLocal) { - sync = ShouldBeSynchronized::No; - send = ShouldSendToRemote::No; + global::scriptEngine->queueScript( + script, + scripting::ScriptEngine::ShouldBeSynchronized::No, + scripting::ScriptEngine::ShouldSendToRemote::No + ); + } + else { + global::scriptEngine->queueScript( + script, + scripting::ScriptEngine::ShouldBeSynchronized::Yes, + scripting::ScriptEngine::ShouldSendToRemote::Yes + ); } - - global::scriptEngine->queueScript(script, sync, send); } scripting::LuaLibrary ActionManager::luaLibrary() { diff --git a/src/navigation/orbitalnavigator.cpp b/src/navigation/orbitalnavigator.cpp index dd1659a763..b2f4b72c2a 100644 --- a/src/navigation/orbitalnavigator.cpp +++ b/src/navigation/orbitalnavigator.cpp @@ -2060,11 +2060,6 @@ double OrbitalNavigator::rotationSpeedScaleFromCameraHeight( const glm::dmat4 modelTransform = _anchorNode->modelTransform(); const glm::dvec3 anchorPos = _anchorNode->worldPosition(); - const glm::dvec3 outDirection = glm::normalize( - glm::dmat3(modelTransform) * - positionHandle.referenceSurfaceOutDirection - ); - const glm::dvec3 posDiff = cameraPosition - anchorPos; const glm::dvec3 centerToActualSurfaceModelSpace = positionHandle.centerToReferenceSurface + diff --git a/src/rendering/colormappingcomponent.cpp b/src/rendering/colormappingcomponent.cpp index f20038b392..e24c491ae4 100644 --- a/src/rendering/colormappingcomponent.cpp +++ b/src/rendering/colormappingcomponent.cpp @@ -440,7 +440,7 @@ void ColorMappingComponent::initializeParameterData(const dataloader::Dataset& d } // While iterating over options, try to find the one provided, if any else if (_providedParameter.has_value() && *_providedParameter == o) { - indexOfProvidedOption = i; + indexOfProvidedOption = static_cast(i); } } } diff --git a/src/scene/assetmanager.cpp b/src/scene/assetmanager.cpp index 755be4a9d9..aa0ae9d741 100644 --- a/src/scene/assetmanager.cpp +++ b/src/scene/assetmanager.cpp @@ -556,7 +556,7 @@ void AssetManager::setUpAssetLuaTable(Asset* asset) { lua_setfield(*_luaState, assetTableIndex, "resource"); // @DEPRECATED(abock) This should be removed after 0.20.0 - ghoul::lua::push(*_luaState, this, asset); + ghoul::lua::push(*_luaState, asset); lua_pushcclosure( *_luaState, [](lua_State* L) { @@ -565,8 +565,7 @@ void AssetManager::setUpAssetLuaTable(Asset* asset) { "'asset.resource' instead. No change to the parameters are needed" ); - AssetManager* manager = ghoul::lua::userData(L, 1); - Asset* thisAsset = ghoul::lua::userData(L, 2); + Asset* thisAsset = ghoul::lua::userData(L, 1); ghoul::lua::checkArgumentsAndThrow(L, { 0, 1 }, "lua::resource"); auto [name] = ghoul::lua::values>(L); diff --git a/src/util/resourcesynchronization.cpp b/src/util/resourcesynchronization.cpp index 411719457b..818946aa4f 100644 --- a/src/util/resourcesynchronization.cpp +++ b/src/util/resourcesynchronization.cpp @@ -105,7 +105,7 @@ const std::string& ResourceSynchronization::name() const { return _name; } -void ResourceSynchronization::createSyncFile(bool isFullySynchronized) const { +void ResourceSynchronization::createSyncFile(bool) const { std::filesystem::path dir = directory(); std::filesystem::create_directories(dir); diff --git a/support/cmake/set_openspace_compile_settings.cmake b/support/cmake/set_openspace_compile_settings.cmake index ed62bc3fdf..8d44f0b44e 100644 --- a/support/cmake/set_openspace_compile_settings.cmake +++ b/support/cmake/set_openspace_compile_settings.cmake @@ -145,6 +145,7 @@ function (set_openspace_compile_settings target) "-Wno-attributes" "-Wno-deprecated-enum-enum-conversion" "-Wno-missing-braces" + "-Wno-sign-compare" "-Wno-unknown-attributes" ) @@ -182,6 +183,7 @@ function (set_openspace_compile_settings target) "-Wno-float-equal" "-Wno-long-long" "-Wno-missing-field-initializers" + "-Wno-sign-compare" "-Wno-unknown-attributes" "-Wno-write-strings" ) From 54cf26755cfdaad1893c92c726cd36962b10fea4 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Thu, 18 Jan 2024 13:23:22 +0100 Subject: [PATCH 27/30] Feature/point cloud scaling (#2994) * Try using angular max size rather than max pixel size * Update property name and use for shader * Add docs and remove mention of angle from user's perspective * People will wonder, so add some details as to what the value represents * Fix inconsistent punctuation in property texts with multiple sentences * Slight clarification of transformation matrix usage * Add values to asset files * Increase max size of example points a bit * Remove/Update comment * Add TODO comment about potential optimization * Reduce max size of SDSS and quasars a bit * Address review comment * Decrease 6df and increase globular clusters size as per review comment * Remove any mention of pixel size in the example asset * Remove some more mentions of pixel size * Write view space position to G-buffer to prevent atm. from shining through points --- data/assets/examples/pointclouds/points.asset | 21 ++-- data/assets/scene/digitaluniverse/2dF.asset | 4 +- data/assets/scene/digitaluniverse/2mass.asset | 6 +- data/assets/scene/digitaluniverse/6dF.asset | 6 +- data/assets/scene/digitaluniverse/abell.asset | 4 +- .../scene/digitaluniverse/deepsky.asset | 4 +- .../assets/scene/digitaluniverse/dwarfs.asset | 4 +- .../scene/digitaluniverse/exoplanets.asset | 4 +- .../exoplanets_candidates.asset | 4 +- .../digitaluniverse/globularclusters.asset | 6 +- .../scene/digitaluniverse/h2regions.asset | 4 +- data/assets/scene/digitaluniverse/hdf.asset | 4 +- .../scene/digitaluniverse/localdwarfs.asset | 4 +- .../digitaluniverse/obassociations.asset | 4 +- .../scene/digitaluniverse/openclusters.asset | 4 +- .../digitaluniverse/planetarynebulae.asset | 4 +- .../scene/digitaluniverse/pulsars.asset | 4 +- .../scene/digitaluniverse/quasars.asset | 4 +- data/assets/scene/digitaluniverse/sdss.asset | 4 +- .../scene/digitaluniverse/superclusters.asset | 4 +- .../digitaluniverse/supernovaremnants.asset | 4 +- data/assets/scene/digitaluniverse/tully.asset | 4 +- .../pointcloud/renderablepointcloud.cpp | 107 +++++++++--------- .../pointcloud/renderablepointcloud.h | 16 +-- modules/base/shaders/billboardpoint_fs.glsl | 4 +- modules/base/shaders/billboardpoint_gs.glsl | 54 ++++----- 26 files changed, 143 insertions(+), 149 deletions(-) diff --git a/data/assets/examples/pointclouds/points.asset b/data/assets/examples/pointclouds/points.asset index e298045d79..8007829406 100644 --- a/data/assets/examples/pointclouds/points.asset +++ b/data/assets/examples/pointclouds/points.asset @@ -23,10 +23,9 @@ local FixedColor_FixedSize = { } } --- Point cloud with fixed color and size scaling that is limited by a certain size, --- in pixels -local FixedColor_MaxPixelSize = { - Identifier = "ExamplePoints_MaxPixelSize", +-- Point cloud with fixed color and size scaling that is limited by a certain size +local FixedColor_MaxSize = { + Identifier = "ExamplePoints_MaxSize", Parent = earthAsset.Earth.Identifier, Transform = { Rotation = { @@ -41,14 +40,14 @@ local FixedColor_MaxPixelSize = { FixedColor = { 0.0, 1.0, 1.0 } }, SizeSettings = { - MaxPixelSize = 4.7, - EnablePixelSizeControl = true + MaxSize = 0.7, + EnableMaxSizeControl = true } }, GUI = { - Name = "Fixed Color / Max Pixel Size", + Name = "Fixed Color / Max Size", Path = "/Example/Point Clouds", - Description = "Point cloud with a fixed color and sizing with a given max pixel size" + Description = "Point cloud with a fixed color and sizing with a given max size" } } @@ -201,7 +200,7 @@ local ColorMappedAdvanced_NoBlend = { asset.onInitialize(function() openspace.addSceneGraphNode(FixedColor_FixedSize) - openspace.addSceneGraphNode(FixedColor_MaxPixelSize) + openspace.addSceneGraphNode(FixedColor_MaxSize) openspace.addSceneGraphNode(FixedColor_ScaleBasedOnData) openspace.addSceneGraphNode(Textured) openspace.addSceneGraphNode(ColorMapped_FixedSize) @@ -213,12 +212,12 @@ asset.onDeinitialize(function() openspace.removeSceneGraphNode(ColorMapped_FixedSize) openspace.removeSceneGraphNode(Textured) openspace.removeSceneGraphNode(FixedColor_ScaleBasedOnData) - openspace.removeSceneGraphNode(FixedColor_MaxPixelSize) + openspace.removeSceneGraphNode(FixedColor_MaxSize) openspace.removeSceneGraphNode(FixedColor_FixedSize) end) asset.export(FixedColor_FixedSize) -asset.export(FixedColor_MaxPixelSize) +asset.export(FixedColor_MaxSize) asset.export(FixedColor_ScaleBasedOnData) asset.export(Textured) asset.export(ColorMapped_FixedSize) diff --git a/data/assets/scene/digitaluniverse/2dF.asset b/data/assets/scene/digitaluniverse/2dF.asset index a86bea1544..48441443d8 100644 --- a/data/assets/scene/digitaluniverse/2dF.asset +++ b/data/assets/scene/digitaluniverse/2dF.asset @@ -33,8 +33,8 @@ local Object = { }, SizeSettings = { ScaleExponent = 22.6, - MaxPixelSize = 4.7, - EnablePixelSizeControl = true + MaxSize = 0.2, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/2mass.asset b/data/assets/scene/digitaluniverse/2mass.asset index 8ed791380b..daf8dfe6d9 100644 --- a/data/assets/scene/digitaluniverse/2mass.asset +++ b/data/assets/scene/digitaluniverse/2mass.asset @@ -33,9 +33,9 @@ local Object = { } }, SizeSettings = { - ScaleExponent = 22.5, - MaxPixelSize = 11.15, - EnablePixelSizeControl = true + ScaleExponent = 22.2, + MaxSize = 0.44, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/6dF.asset b/data/assets/scene/digitaluniverse/6dF.asset index 780aefc678..f3d5528369 100644 --- a/data/assets/scene/digitaluniverse/6dF.asset +++ b/data/assets/scene/digitaluniverse/6dF.asset @@ -33,9 +33,9 @@ local Object = { } }, SizeSettings = { - ScaleExponent = 23.2, - MaxPixelSize = 9.0, - EnablePixelSizeControl = true + ScaleExponent = 22.5, + MaxSize = 0.2, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/abell.asset b/data/assets/scene/digitaluniverse/abell.asset index 2e3f6f0d02..43ef6c6796 100644 --- a/data/assets/scene/digitaluniverse/abell.asset +++ b/data/assets/scene/digitaluniverse/abell.asset @@ -45,8 +45,8 @@ local Object = { TransformationMatrix = TransformMatrix, SizeSettings = { ScaleExponent = 22.6, - MaxPixelSize = 7.0, - EnablePixelSizeControl = true + MaxSize = 0.27, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/deepsky.asset b/data/assets/scene/digitaluniverse/deepsky.asset index 6be73ad6e4..5aa89ea88b 100644 --- a/data/assets/scene/digitaluniverse/deepsky.asset +++ b/data/assets/scene/digitaluniverse/deepsky.asset @@ -35,8 +35,8 @@ local DeepSkyObjects = { --FadeInDistances = { 0.05, 1.0 }, -- Fade in value in the same unit as "Unit" SizeSettings = { ScaleExponent = 21.7, - MaxPixelSize = 8.22, - EnablePixelSizeControl = true + MaxSize = 0.32, + EnableMaxSizeControl = true } }, Transform = { diff --git a/data/assets/scene/digitaluniverse/dwarfs.asset b/data/assets/scene/digitaluniverse/dwarfs.asset index 312112931d..fd13e0e4ec 100644 --- a/data/assets/scene/digitaluniverse/dwarfs.asset +++ b/data/assets/scene/digitaluniverse/dwarfs.asset @@ -40,8 +40,8 @@ local Object = { }, SizeSettings = { ScaleExponent = 16.2, - MaxPixelSize = 20.0, - EnablePixelSizeControl = true + MaxSize = 0.7, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/exoplanets.asset b/data/assets/scene/digitaluniverse/exoplanets.asset index f7abff68f8..c53f3ae27d 100644 --- a/data/assets/scene/digitaluniverse/exoplanets.asset +++ b/data/assets/scene/digitaluniverse/exoplanets.asset @@ -31,8 +31,8 @@ local Object = { Unit = "pc", SizeSettings = { ScaleExponent = 16.9, - MaxPixelSize = 75.0, - EnablePixelSizeControl = true + MaxSize = 2.8, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/exoplanets_candidates.asset b/data/assets/scene/digitaluniverse/exoplanets_candidates.asset index d33e413484..e0bb934486 100644 --- a/data/assets/scene/digitaluniverse/exoplanets_candidates.asset +++ b/data/assets/scene/digitaluniverse/exoplanets_candidates.asset @@ -27,8 +27,8 @@ local Object = { }, SizeSettings = { ScaleExponent = 17.8, - MaxPixelSize = 30.0, - EnablePixelSizeControl = true + MaxSize = 1.0, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/globularclusters.asset b/data/assets/scene/digitaluniverse/globularclusters.asset index ec6232b7af..2ce9c05cd5 100644 --- a/data/assets/scene/digitaluniverse/globularclusters.asset +++ b/data/assets/scene/digitaluniverse/globularclusters.asset @@ -33,9 +33,9 @@ local Object = { PolygonSides = 5, Unit = "pc", SizeSettings = { - ScaleExponent = 18.7, - MaxPixelSize = 500.0, - EnablePixelSizeControl = true + ScaleExponent = 18.9, + MaxSize = 13.0, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/h2regions.asset b/data/assets/scene/digitaluniverse/h2regions.asset index 3868e22b08..f704d48757 100644 --- a/data/assets/scene/digitaluniverse/h2regions.asset +++ b/data/assets/scene/digitaluniverse/h2regions.asset @@ -34,8 +34,8 @@ local Object = { Unit = "pc", SizeSettings = { ScaleExponent = 18.24, - MaxPixelSize = 300.0, - EnablePixelSizeControl = false + MaxSize = 8.0, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/hdf.asset b/data/assets/scene/digitaluniverse/hdf.asset index e44aeec0c0..964144e69c 100644 --- a/data/assets/scene/digitaluniverse/hdf.asset +++ b/data/assets/scene/digitaluniverse/hdf.asset @@ -39,9 +39,7 @@ local Object = { }, Unit = "Mpc", SizeSettings = { - ScaleExponent = 21.9, - MaxPixelSize = 4.7, - EnablePixelSizeControl = true + ScaleExponent = 21.9 } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/localdwarfs.asset b/data/assets/scene/digitaluniverse/localdwarfs.asset index 635b6e0edc..b09da57150 100644 --- a/data/assets/scene/digitaluniverse/localdwarfs.asset +++ b/data/assets/scene/digitaluniverse/localdwarfs.asset @@ -45,8 +45,8 @@ local Object = { Unit = "Mpc", SizeSettings = { ScaleExponent = 20.2, - MaxPixelSize = 20.0, - EnablePixelSizeControl = true + MaxSize = 0.7, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/obassociations.asset b/data/assets/scene/digitaluniverse/obassociations.asset index c1793d6717..fd0610c6f1 100644 --- a/data/assets/scene/digitaluniverse/obassociations.asset +++ b/data/assets/scene/digitaluniverse/obassociations.asset @@ -41,8 +41,8 @@ local Object = { SizeSettings = { SizeMapping = { "diameter" }, ScaleExponent = 16.9, - MaxPixelSize = 450.0, - EnablePixelSizeControl = true + MaxSize = 17, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/openclusters.asset b/data/assets/scene/digitaluniverse/openclusters.asset index dd35569693..d7a4e2a551 100644 --- a/data/assets/scene/digitaluniverse/openclusters.asset +++ b/data/assets/scene/digitaluniverse/openclusters.asset @@ -34,8 +34,8 @@ local Object = { PolygonSides = 12, SizeSettings = { ScaleExponent = 17.6, - MaxPixelSize = 604.0, - EnablePixelSizeControl = true + MaxSize = 23.0, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/planetarynebulae.asset b/data/assets/scene/digitaluniverse/planetarynebulae.asset index 303243769a..f9638d1392 100644 --- a/data/assets/scene/digitaluniverse/planetarynebulae.asset +++ b/data/assets/scene/digitaluniverse/planetarynebulae.asset @@ -34,8 +34,8 @@ local Object = { Unit = "pc", SizeSettings = { ScaleExponent = 18.46, - MaxPixelSize = 500.0, - EnablePixelSizeControl = true + MaxSize = 19.0, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/pulsars.asset b/data/assets/scene/digitaluniverse/pulsars.asset index f18b4e3b5a..fd8a4edee1 100644 --- a/data/assets/scene/digitaluniverse/pulsars.asset +++ b/data/assets/scene/digitaluniverse/pulsars.asset @@ -34,8 +34,8 @@ local Object = { Unit = "pc", SizeSettings = { ScaleExponent = 18.4, - MaxPixelSize = 500.0, - EnablePixelSizeControl = false + MaxSize = 19.0, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/quasars.asset b/data/assets/scene/digitaluniverse/quasars.asset index 92c57b19e0..93efec3236 100644 --- a/data/assets/scene/digitaluniverse/quasars.asset +++ b/data/assets/scene/digitaluniverse/quasars.asset @@ -46,8 +46,8 @@ local Object = { }, SizeSettings = { ScaleExponent = 23.5, - MaxPixelSize = 11.1, - EnablePixelSizeControl = true + MaxSize = 0.3, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/sdss.asset b/data/assets/scene/digitaluniverse/sdss.asset index 0ed6ee3d8c..0ffa195d31 100644 --- a/data/assets/scene/digitaluniverse/sdss.asset +++ b/data/assets/scene/digitaluniverse/sdss.asset @@ -37,8 +37,8 @@ local Object = { }, SizeSettings = { ScaleExponent = 22.6, - MaxPixelSize = 5.5, - EnablePixelSizeControl = true + MaxSize = 0.15, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/superclusters.asset b/data/assets/scene/digitaluniverse/superclusters.asset index 19d8a55c41..77260619f7 100644 --- a/data/assets/scene/digitaluniverse/superclusters.asset +++ b/data/assets/scene/digitaluniverse/superclusters.asset @@ -33,8 +33,8 @@ local Object = { Unit = "Mpc", SizeSettings = { ScaleExponent = 23.1, - MaxPixelSize = 7.2, - EnablePixelSizeControl = true + MaxSize = 0.2, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/supernovaremnants.asset b/data/assets/scene/digitaluniverse/supernovaremnants.asset index 388118796a..6a6c8816a8 100644 --- a/data/assets/scene/digitaluniverse/supernovaremnants.asset +++ b/data/assets/scene/digitaluniverse/supernovaremnants.asset @@ -34,8 +34,8 @@ local Object = { Unit = "pc", SizeSettings = { ScaleExponent = 18.4, - MaxPixelSize = 500.0, - EnablePixelSizeControl = true + MaxSize = 19.0, + EnableMaxSizeControl = true } }, GUI = { diff --git a/data/assets/scene/digitaluniverse/tully.asset b/data/assets/scene/digitaluniverse/tully.asset index f3a329348a..b7739c503d 100644 --- a/data/assets/scene/digitaluniverse/tully.asset +++ b/data/assets/scene/digitaluniverse/tully.asset @@ -52,8 +52,8 @@ local TullyGalaxies = { }, SizeSettings = { ScaleExponent = 21.9, - MaxPixelSize = 7.0, - EnablePixelSizeControl = true + MaxSize = 0.3, + EnableMaxSizeControl = true } }, GUI = { diff --git a/modules/base/rendering/pointcloud/renderablepointcloud.cpp b/modules/base/rendering/pointcloud/renderablepointcloud.cpp index be5d3fd6e6..6c8e08031f 100644 --- a/modules/base/rendering/pointcloud/renderablepointcloud.cpp +++ b/modules/base/rendering/pointcloud/renderablepointcloud.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -56,11 +55,11 @@ namespace { constexpr std::string_view _loggerCat = "RenderablePointCloud"; constexpr std::array UniformNames = { - "cameraViewProjectionMatrix", "modelMatrix", "cameraPosition", "cameraLookUp", - "renderOption", "maxBillboardSize", "color", "opacity", "scaleExponent", - "scaleFactor", "up", "right", "fadeInValue", "screenSize", "hasSpriteTexture", + "cameraViewMatrix", "projectionMatrix", "modelMatrix", "cameraPosition", + "cameraLookUp", "renderOption", "maxAngularSize", "color", "opacity", + "scaleExponent", "scaleFactor", "up", "right", "fadeInValue", "hasSpriteTexture", "spriteTexture", "useColorMap", "colorMapTexture", "cmapRangeMin", "cmapRangeMax", - "nanColor", "useNanColor", "hideOutsideRange", "enablePixelSizeControl", + "nanColor", "useNanColor", "hideOutsideRange", "enableMaxSizeControl", "aboveRangeColor", "useAboveRangeColor", "belowRangeColor", "useBelowRangeColor", "hasDvarScaling" }; @@ -81,7 +80,7 @@ namespace { "UseTexture", "Use Texture", "If true, use the provided sprite texture to render the point. If false, draw " - "the points using the default point shape", + "the points using the default point shape.", openspace::properties::Property::Visibility::AdvancedUser }; @@ -127,7 +126,7 @@ namespace { "Unit, or meters. With normal fading the points are fully visible once the " "camera is outside this range and fully invisible when inside the range. With " "inverted fading the situation is the opposite: the points are visible inside " - "hen closer than the min value of the range and invisible when further away", + "hen closer than the min value of the range and invisible when further away.", // @VISIBILITY(3.25) openspace::properties::Property::Visibility::AdvancedUser }; @@ -136,7 +135,7 @@ namespace { "Enabled", "Enable Distance-based Fading", "Enables/disables the Fade-in effect based on camera distance. Automatically set " - "to true if FadeInDistances are specified in the asset", + "to true if FadeInDistances are specified in the asset.", openspace::properties::Property::Visibility::User }; @@ -145,7 +144,7 @@ namespace { "Invert", "This property can be used the invert the fading so that the points are " "invisible when the camera is further away than the max fade distance " - "and fully visible when it is closer than the min distance", + "and fully visible when it is closer than the min distance.", openspace::properties::Property::Visibility::AdvancedUser }; @@ -176,7 +175,7 @@ namespace { "value should be. If not included, it is computed based on the maximum " "positional component of the data points. This is useful for showing the " "dataset at all, but you will likely want to change it to something that looks " - "good", + "good.", openspace::properties::Property::Visibility::User }; @@ -184,25 +183,29 @@ namespace { "ScaleFactor", "Scale Factor", "This value is used as a multiplicative factor to adjust the size of the points, " - "after the exponential scaling and any pixel-size control effects. Simply just " - "increases or decreases the visual size of the points", + "after the exponential scaling and any max size control effects. Simply just " + "increases or decreases the visual size of the points.", openspace::properties::Property::Visibility::User }; - constexpr openspace::properties::Property::PropertyInfo PixelSizeControlInfo = { - "EnablePixelSizeControl", - "Enable Pixel Size Control", - "If true, the Max Size in Pixels property will be used as an upper limit for the " - "size of the point. Reduces the size of the points when approaching them, so that " - "they stick to a maximum screen space size. Currently, the scaling is computed " - "based on rectangular displays and might look weird in other projections", + constexpr openspace::properties::Property::PropertyInfo UseMaxSizeControlInfo = { + "EnableMaxSizeControl", + "Enable Max Size Control", + "If true, the Max Size property will be used as an upper limit for the size of " + "the point. This reduces the size of the points when approaching them, so that " + "they stick to a maximum visual size depending on the Max Size value.", openspace::properties::Property::Visibility::AdvancedUser }; - constexpr openspace::properties::Property::PropertyInfo MaxPixelSizeInfo = { - "MaxPixelSize", - "Max Size in Pixels", - "The maximum size (in pixels) for the billboard representing the point.", + constexpr openspace::properties::Property::PropertyInfo MaxSizeInfo = { + "MaxSize", + "Max Size", + "This value controls the maximum allowed size for the points, when the max size " + "control feature is enabled. This limits the visual size of the points based on " + "the distance to the camera. The larger the value, the larger the points are " + "allowed to become. In the background, the computations are made by limiting the " + "size to a certain angle based on the field of view of the camera. So a value of " + "1 limits the point size to take up a maximum of one degree of the view space.", openspace::properties::Property::Visibility::AdvancedUser }; @@ -220,7 +223,7 @@ namespace { "Parameter Option", "This value determines which parameter is used for scaling of the point. The " "parameter value will be used as a miltiplicative factor to scale the size of " - "the points. Not that they may however still be scaled by pixel size adjustment " + "the points. Note that they may however still be scaled by max size adjustment " "effects.", openspace::properties::Property::Visibility::AdvancedUser }; @@ -242,8 +245,8 @@ namespace { // interactively when OpenSpace is running until you find a value that you find // suitable. // - // - There is also an option to limit the size of the points based on a given pixel - // size. For now, this only works for flat projection displays. + // - There is also an option to limit the size of the points based on a given max + // size value. // // - To easily change the visual size of the points, the multiplicative 'ScaleFactor' // may be used. A value of 2 makes the points twice as large, visually, compared @@ -315,14 +318,14 @@ namespace { // [[codegen::verbatim(ScaleFactorInfo.description)]] std::optional scaleFactor; - // [[codegen::verbatim(PixelSizeControlInfo.description)]] - std::optional enablePixelSizeControl; + // [[codegen::verbatim(UseMaxSizeControlInfo.description)]] + std::optional enableMaxSizeControl; - // [[codegen::verbatim(MaxPixelSizeInfo.description)]] - std::optional maxPixelSize; + // [[codegen::verbatim(MaxSizeInfo.description)]] + std::optional maxSize; }; // Settings related to the scale of the points, whether they should limit to - // a certain pixel size, etc. + // a certain max size, etc. std::optional sizeSettings; struct ColorSettings { @@ -352,7 +355,7 @@ namespace { // origin of the dataset std::optional fading; - // Transformation matrix to be applied to each object + // Transformation matrix to be applied to the position of each object std::optional transformationMatrix; }; @@ -369,8 +372,8 @@ RenderablePointCloud::SizeSettings::SizeSettings(const ghoul::Dictionary& dictio : properties::PropertyOwner({ "Sizing", "Sizing", ""}) , scaleExponent(ScaleExponentInfo, 1.f, 0.f, 25.f) , scaleFactor(ScaleFactorInfo, 1.f, 0.f, 50.f) - , pixelSizeControl(PixelSizeControlInfo, false) - , maxPixelSize(MaxPixelSizeInfo, 400.f, 0.f, 1000.f) + , useMaxSizeControl(UseMaxSizeControlInfo, false) + , maxAngularSize(MaxSizeInfo, 1.f, 0.f, 45.f) { const Parameters p = codegen::bake(dictionary); @@ -379,8 +382,8 @@ RenderablePointCloud::SizeSettings::SizeSettings(const ghoul::Dictionary& dictio scaleFactor = settings.scaleFactor.value_or(scaleFactor); scaleExponent = settings.scaleExponent.value_or(scaleExponent); - pixelSizeControl = settings.enablePixelSizeControl.value_or(pixelSizeControl); - maxPixelSize = settings.maxPixelSize.value_or(maxPixelSize); + useMaxSizeControl = settings.enableMaxSizeControl.value_or(useMaxSizeControl); + maxAngularSize = settings.maxSize.value_or(maxAngularSize); if (settings.sizeMapping.has_value()) { std::vector opts = *settings.sizeMapping; @@ -396,8 +399,8 @@ RenderablePointCloud::SizeSettings::SizeSettings(const ghoul::Dictionary& dictio addProperty(scaleFactor); addProperty(scaleExponent); - addProperty(pixelSizeControl); - addProperty(maxPixelSize); + addProperty(useMaxSizeControl); + addProperty(maxAngularSize); } RenderablePointCloud::SizeSettings::SizeMapping::SizeMapping() @@ -720,11 +723,6 @@ void RenderablePointCloud::renderBillboards(const RenderData& data, _program->activate(); - _program->setUniform( - "screenSize", - glm::vec2(global::renderEngine->renderingResolution()) - ); - _program->setUniform(_uniformCache.cameraPos, data.camera.positionVec3()); _program->setUniform( _uniformCache.cameraLookup, @@ -732,9 +730,15 @@ void RenderablePointCloud::renderBillboards(const RenderData& data, ); _program->setUniform(_uniformCache.renderOption, _renderOption.value()); _program->setUniform(_uniformCache.modelMatrix, modelMatrix); + _program->setUniform( - _uniformCache.cameraViewProjectionMatrix, - glm::dmat4(data.camera.projectionMatrix()) * data.camera.combinedViewMatrix() + _uniformCache.cameraViewMatrix, + data.camera.combinedViewMatrix() + ); + + _program->setUniform( + _uniformCache.projectionMatrix, + glm::dmat4(data.camera.projectionMatrix()) ); _program->setUniform(_uniformCache.up, glm::vec3(orthoUp)); @@ -744,14 +748,10 @@ void RenderablePointCloud::renderBillboards(const RenderData& data, _program->setUniform(_uniformCache.scaleExponent, _sizeSettings.scaleExponent); _program->setUniform(_uniformCache.scaleFactor, _sizeSettings.scaleFactor); - _program->setUniform(_uniformCache.enablePixelSizeControl, _sizeSettings.pixelSizeControl); - _program->setUniform(_uniformCache.maxBillboardSize, _sizeSettings.maxPixelSize); + _program->setUniform(_uniformCache.enableMaxSizeControl, _sizeSettings.useMaxSizeControl); + _program->setUniform(_uniformCache.maxAngularSize, _sizeSettings.maxAngularSize); _program->setUniform(_uniformCache.hasDvarScaling, _sizeSettings.sizeMapping.enabled); - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - _program->setUniform(_uniformCache.screenSize, glm::vec2(viewport[2], viewport[3])); - bool useTexture = _hasSpriteTexture && _useSpriteTexture; _program->setUniform(_uniformCache.hasSpriteTexture, useTexture); @@ -829,8 +829,6 @@ void RenderablePointCloud::render(const RenderData& data, RendererTasks&) { } glm::dmat4 modelMatrix = calcModelTransform(data); - glm::dmat4 modelViewProjectionMatrix = - calcModelViewProjectionTransform(data, modelMatrix); glm::dvec3 cameraViewDirectionWorld = -data.camera.viewDirectionWorldSpace(); glm::dvec3 cameraUpDirectionWorld = data.camera.lookUpVectorWorldSpace(); @@ -852,6 +850,9 @@ void RenderablePointCloud::render(const RenderData& data, RendererTasks&) { } if (_hasLabels) { + glm::dmat4 modelViewProjectionMatrix = + calcModelViewProjectionTransform(data, modelMatrix); + _labels->render(data, modelViewProjectionMatrix, orthoRight, orthoUp, fadeInVar); } } diff --git a/modules/base/rendering/pointcloud/renderablepointcloud.h b/modules/base/rendering/pointcloud/renderablepointcloud.h index 0cfcbed715..ab51cfe2d9 100644 --- a/modules/base/rendering/pointcloud/renderablepointcloud.h +++ b/modules/base/rendering/pointcloud/renderablepointcloud.h @@ -114,8 +114,8 @@ protected: properties::FloatProperty scaleExponent; properties::FloatProperty scaleFactor; - properties::BoolProperty pixelSizeControl; - properties::FloatProperty maxPixelSize; + properties::BoolProperty useMaxSizeControl; + properties::FloatProperty maxAngularSize; }; SizeSettings _sizeSettings; @@ -148,12 +148,12 @@ protected: ghoul::opengl::ProgramObject* _program = nullptr; UniformCache( - cameraViewProjectionMatrix, modelMatrix, cameraPos, cameraLookup, renderOption, - maxBillboardSize, color, opacity, scaleExponent, scaleFactor, up, right, - fadeInValue, screenSize, hasSpriteTexture, spriteTexture, useColormap, - colorMapTexture, cmapRangeMin, cmapRangeMax, nanColor, useNanColor, - hideOutsideRange, enablePixelSizeControl, aboveRangeColor, useAboveRangeColor, - belowRangeColor, useBelowRangeColor, hasDvarScaling + cameraViewMatrix, projectionMatrix, modelMatrix, cameraPos, cameraLookup, + renderOption, maxAngularSize, color, opacity, scaleExponent, scaleFactor, up, + right, fadeInValue, hasSpriteTexture, spriteTexture, useColormap, colorMapTexture, + cmapRangeMin, cmapRangeMax, nanColor, useNanColor, hideOutsideRange, + enableMaxSizeControl, aboveRangeColor, useAboveRangeColor, belowRangeColor, + useBelowRangeColor, hasDvarScaling ) _uniformCache; std::string _dataFile; diff --git a/modules/base/shaders/billboardpoint_fs.glsl b/modules/base/shaders/billboardpoint_fs.glsl index b0dfaaeb6b..7b6b51c8e4 100644 --- a/modules/base/shaders/billboardpoint_fs.glsl +++ b/modules/base/shaders/billboardpoint_fs.glsl @@ -26,6 +26,7 @@ flat in float gs_colorParameter; flat in float vs_screenSpaceDepth; +flat in vec4 vs_positionViewSpace; in vec2 texCoord; uniform float opacity; @@ -107,8 +108,7 @@ Fragment getFragment() { Fragment frag; frag.color = fullColor; frag.depth = vs_screenSpaceDepth; - // Setting the position of the billboards to not interact with the ATM - frag.gPosition = vec4(-1e32, -1e32, -1e32, 1.0); + frag.gPosition = vs_positionViewSpace; frag.gNormal = vec4(0.0, 0.0, 0.0, 1.0); return frag; diff --git a/modules/base/shaders/billboardpoint_gs.glsl b/modules/base/shaders/billboardpoint_gs.glsl index 19db521a59..51e58c3774 100644 --- a/modules/base/shaders/billboardpoint_gs.glsl +++ b/modules/base/shaders/billboardpoint_gs.glsl @@ -34,14 +34,16 @@ layout(triangle_strip, max_vertices = 4) out; flat out float gs_colorParameter; out vec2 texCoord; flat out float vs_screenSpaceDepth; +flat out vec4 vs_positionViewSpace; // General settings uniform float scaleExponent; uniform float scaleFactor; uniform int renderOption; -uniform dmat4 cameraViewProjectionMatrix; +uniform dmat4 cameraViewMatrix; +uniform dmat4 projectionMatrix; uniform dmat4 modelMatrix; -uniform bool enablePixelSizeControl; +uniform bool enableMaxSizeControl; uniform bool hasDvarScaling; // RenderOption: CameraViewDirection @@ -52,9 +54,9 @@ uniform vec3 right; uniform dvec3 cameraPosition; uniform vec3 cameraLookUp; -// Pixel size control: true -uniform vec2 screenSize; -uniform float maxBillboardSize; +// Max size control: true +// The max size is an angle, in degrees, for the diameter +uniform float maxAngularSize; const vec2 corners[4] = vec2[4]( vec2(0.0, 0.0), @@ -93,41 +95,35 @@ void main() { scaledUp = scaleMultiply * newUp * 0.5; } - // @TODO: Come up with some better solution for this scaling, that - // also work with non planar projections and multiple viewport resolutions. - if (enablePixelSizeControl) { - vec4 initialPosition = z_normalization(vec4(cameraViewProjectionMatrix * - dvec4(dpos.xyz - dvec3(scaledRight - scaledUp), dpos.w))); + if (enableMaxSizeControl) { + // Limit the max size of the points, as the angle in "FOV" that the point is allowed + // to take up. Note that the max size is for the diameter, and we need the radius + float desiredAngleRadians = radians(maxAngularSize * 0.5); - vs_screenSpaceDepth = initialPosition.w; + double distanceToCamera = length(dpos.xyz - cameraPosition); + double pointSize = length(dvec3(scaledRight)); + // @TODO (2023-01-05, emmbr) Consider if this atan computation can be optimized using + // approximation + float angle = atan(float(pointSize / distanceToCamera)); - vec4 crossCorner = z_normalization(vec4(cameraViewProjectionMatrix * - dvec4(dpos.xyz + dvec3(scaledRight + scaledUp), dpos.w))); - - // Testing size for rectangular viewport: - vec2 halfViewSize = screenSize * 0.5; - vec2 topRight = crossCorner.xy / crossCorner.w; - vec2 bottomLeft = initialPosition.xy / initialPosition.w; - - // width and height - vec2 sizes = abs(halfViewSize * (topRight - bottomLeft)); - - if (length(sizes) > maxBillboardSize) { - float correctionScale = maxBillboardSize / length(sizes); - scaledRight *= correctionScale; - scaledUp *= correctionScale; + if ((angle > desiredAngleRadians) && (distanceToCamera > 0.0)) { + float correctionScaleFactor = float(distanceToCamera) * tan(desiredAngleRadians) / float(pointSize); + scaledRight *= correctionScaleFactor; + scaledUp *= correctionScaleFactor; } - - // TODO: add checks for wether the generated plane covers too many or too few pixels } - // Saving one matrix multiplication: + dmat4 cameraViewProjectionMatrix = projectionMatrix * cameraViewMatrix; + vec4 dposClip = vec4(cameraViewProjectionMatrix * dpos); vec4 scaledRightClip = scaleFactor * vec4(cameraViewProjectionMatrix * dvec4(scaledRight, 0.0)); vec4 scaledUpClip = scaleFactor * vec4(cameraViewProjectionMatrix * dvec4(scaledUp, 0.0)); + vec4 dposViewSpace= vec4(cameraViewMatrix * dpos); + vs_positionViewSpace = dposViewSpace; + vec4 initialPosition = z_normalization(dposClip - scaledRightClip - scaledUpClip); vs_screenSpaceDepth = initialPosition.w; vec4 secondPosition = z_normalization(dposClip + scaledRightClip - scaledUpClip); From 232a0e016d50dda18d732ef99369a67469737516 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jan 2024 14:02:55 +0100 Subject: [PATCH 28/30] Add ESA's Bepicolombo mission (#3000) --- .../missions/bepicolombo/bepicolombo.asset | 16 + .../missions/bepicolombo/fov.asset | 10 + .../missions/bepicolombo/fov/bela.asset | 108 +++ .../missions/bepicolombo/fov/hga.asset | 48 + .../missions/bepicolombo/fov/mertis.asset | 104 +++ .../missions/bepicolombo/fov/mgns.asset | 57 ++ .../missions/bepicolombo/fov/mixs.asset | 81 ++ .../missions/bepicolombo/fov/phebus.asset | 137 +++ .../missions/bepicolombo/fov/serena.asset | 56 ++ .../bepicolombo/fov/serena_anodes.asset | 832 ++++++++++++++++++ .../missions/bepicolombo/fov/sibbiosys.asset | 378 ++++++++ .../missions/bepicolombo/fov/sixs.asset | 104 +++ .../bepicolombo/fov/startracker.asset | 107 +++ .../missions/bepicolombo/kernels.asset | 303 +++++++ .../missions/bepicolombo/mission.asset | 88 ++ .../missions/bepicolombo/model.asset | 84 ++ .../missions/bepicolombo/trails.asset | 73 ++ data/profiles/bepicolombo.profile | 183 ++++ 18 files changed, 2769 insertions(+) create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/bepicolombo.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/fov.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/fov/bela.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/fov/hga.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/fov/mertis.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/fov/mgns.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/fov/mixs.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/fov/phebus.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/fov/serena.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/fov/serena_anodes.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/fov/sibbiosys.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/fov/sixs.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/fov/startracker.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/kernels.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/mission.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/model.asset create mode 100644 data/assets/scene/solarsystem/missions/bepicolombo/trails.asset create mode 100644 data/profiles/bepicolombo.profile diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/bepicolombo.asset b/data/assets/scene/solarsystem/missions/bepicolombo/bepicolombo.asset new file mode 100644 index 0000000000..616728c08b --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/bepicolombo.asset @@ -0,0 +1,16 @@ +asset.require("./model") +asset.require("./trails") +asset.require("./mission") +asset.require("./fov") + + + +asset.meta = { + Name = "BepiColombo", + Version = "1.0", + Description = + "This asset includes all of the other assets for the BepiColombo mission.", + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/fov.asset b/data/assets/scene/solarsystem/missions/bepicolombo/fov.asset new file mode 100644 index 0000000000..6dfe003e15 --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/fov.asset @@ -0,0 +1,10 @@ +asset.require("./fov/bela") +asset.require("./fov/hga") +asset.require("./fov/mertis") +asset.require("./fov/mgns") +asset.require("./fov/mixs") +asset.require("./fov/phebus") +asset.require("./fov/serena") +asset.require("./fov/sibbiosys") +asset.require("./fov/sixs") +asset.require("./fov/startracker") diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/fov/bela.asset b/data/assets/scene/solarsystem/missions/bepicolombo/fov/bela.asset new file mode 100644 index 0000000000..e99a422999 --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/fov/bela.asset @@ -0,0 +1,108 @@ +local transforms = asset.require("../model") +local kernels = asset.require("../kernels") + + + +local BelaReceiver = { + Identifier = "BepiColomboMPO_BelaReceiver", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.BelaReceiver, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_BELA_RX", + Method = "CIRCLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO BELA Receiver", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local BelaTransmitterMain = { + Identifier = "BepiColomboMPO_BelaTransmitterMain", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.BelaTransmitterMain, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_BELA_TX_MAIN", + Method = "CIRCLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO BELA Transmitter Main", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local BelaTransmitterRed = { + Identifier = "BepiColomboMPO_BelaTransmitterRed", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.BelaTransmitterRed, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_BELA_TX_RED", + Method = "CIRCLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO BELA Transmitter Main", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +asset.onInitialize(function() + -- Circle shapes are currently not supported + -- openspace.addSceneGraphNode(BelaReceiver) + -- openspace.addSceneGraphNode(BelaTransmitterMain) + -- openspace.addSceneGraphNode(BelaTransmitterRed) +end) + +asset.onDeinitialize(function() + -- openspace.removeSceneGraphNode(BelaTransmitterRed) + -- openspace.removeSceneGraphNode(BelaTransmitterMain) + -- openspace.removeSceneGraphNode(BelaReceiver) +end) + + + +asset.meta = { + Name = "BELA", + Version = "1.0", + Description = [[ + BELA for the first time will return a digitized laser reflection signal (only in a + dedicated instrument mode in order to keep the overall data volume moderate). This + will allow characterizing the surface roughness with unprecedented detail and + accuracy. BELA's albedo measurement capability will be particularly important for + permanently shaded craters where ice is suspected to be found. Here, BELA can observe + with its laser where most other remote sensing instruments will fail to obtain a + signal. In its normal operational mode, BELA employs a modified digital filter + matching algorithms for return pulse detection, while other similar instruments + (MOLA, MLA) use analog filter matching. The digital filters can be exchanged at any + time by telecommand and/or parameter upload. + ]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/fov/hga.asset b/data/assets/scene/solarsystem/missions/bepicolombo/fov/hga.asset new file mode 100644 index 0000000000..e4e5e6c7e6 --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/fov/hga.asset @@ -0,0 +1,48 @@ +local transforms = asset.require("../model") +local kernels = asset.require("../kernels") + + + +local HGA = { + Identifier = "BepiColomboMPO_HGA", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.HGA, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_HGA", + Method = "CIRCLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO HGA", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + + +asset.onInitialize(function() + -- Circle shapes are currently not supported + -- openspace.addSceneGraphNode(HGA) +end) + +asset.onDeinitialize(function() + -- openspace.removeSceneGraphNode(HGA) +end) + + + +asset.meta = { + Name = "HGA", + Version = "1.0", + Description = "Shows the field-view for the High Gain Antenna of the MPO spacecraft.", + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/fov/mertis.asset b/data/assets/scene/solarsystem/missions/bepicolombo/fov/mertis.asset new file mode 100644 index 0000000000..2746bc7a0b --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/fov/mertis.asset @@ -0,0 +1,104 @@ +local transforms = asset.require("../model") +local kernels = asset.require("../kernels") + + + +local MertisTis = { + Identifier = "BepiColomboMPO_MertisTis", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.MertisTis, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_MERTIS_TIS", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO MERTIS TIS", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local MertisTisPlanet = { + Identifier = "BepiColomboMPO_MertisTisPlanet", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.MertisTisPlanet, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_MERTIS_TIS_PLANET", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO MERTIS TIS Planet", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local MertisTisSpace = { + Identifier = "BepiColomboMPO_MertisTisSpace", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.MertisTisSpace, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_MERTIS_TIS_SPACE", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO MERTIS TIS Space", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + + +asset.onInitialize(function() + openspace.addSceneGraphNode(MertisTis) + openspace.addSceneGraphNode(MertisTisPlanet) + openspace.addSceneGraphNode(MertisTisSpace) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(MertisTisSpace) + openspace.removeSceneGraphNode(MertisTisPlanet) + openspace.removeSceneGraphNode(MertisTis) +end) + + + +asset.meta = { + Name = "MERTIS", + Version = "1.0", + Description = [[ + The Mercury Radiometer and Thermal Infrared Spectrometer (MERTIS) is an innovative + instrument for studying the surface composition and mineralogy of planet Mercury. + MERTIS combines an uncooled grating push broom IR-spectrometer (TIS) with a radiometer + (TIR), which will operate in the wavelength region of 7-14 and 7-40 um, respectively. + The spatial resolution of the MERTIS observations will be about 500 m globally and + better than 500 m for approximately 5-10 percent of the surface. + ]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/fov/mgns.asset b/data/assets/scene/solarsystem/missions/bepicolombo/fov/mgns.asset new file mode 100644 index 0000000000..d54ce926c3 --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/fov/mgns.asset @@ -0,0 +1,57 @@ +local transforms = asset.require("../model") +local kernels = asset.require("../kernels") + + + +local MGNS = { + Identifier = "BepiColomboMPO_MGNS", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.MGNS, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_MGNS", + Method = "CIRCLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO MGNS", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + + +asset.onInitialize(function() + -- Circle shapes are currently not supported + -- openspace.addSceneGraphNode(MGNS) +end) + +asset.onDeinitialize(function() + -- openspace.removeSceneGraphNode(MGNS) +end) + + + +asset.meta = { + Name = "MGNS", + Version = "1.0", + Description = [[ + The Mercury Gamma-ray and Neutron Spectrometer (MGNS) on board BepiColombo Mercury + Planet Orbiter is designed to observe and study the gamma-ray and neutron emissions of + Mercury. The MGNS is a multifunctional scientific instrument, comprising one gamma-ray + spectrometer and four neutron detectors. The sensor unit of the gamma-ray spectrometer + consists of one 3 by 3 inches high energy resolution inorganic scintillator crystal, + i.e. CeBr3, whereas the sensor unit of the neutron detectors consists of three 3He + gas-filled tubes and one stilbene organic scintillator crystal with plastic + scintillator as its anticoincidence shield. + ]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/fov/mixs.asset b/data/assets/scene/solarsystem/missions/bepicolombo/fov/mixs.asset new file mode 100644 index 0000000000..5696e1fed2 --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/fov/mixs.asset @@ -0,0 +1,81 @@ +local transforms = asset.require("../model") +local kernels = asset.require("../kernels") + + + +local MIXS_C = { + Identifier = "BepiColomboMPO_MIXS-C", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.MIXS_C, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_MIXS-C", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO MIXS-C", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local MIXS_T = { + Identifier = "BepiColomboMPO_MIXS-T", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.MIXS_T, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_MIXS-T", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO MIXS-T", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + + +asset.onInitialize(function() + openspace.addSceneGraphNode(MIXS_C) + openspace.addSceneGraphNode(MIXS_T) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(MIXS_T) + openspace.removeSceneGraphNode(MIXS_C) +end) + + + +asset.meta = { + Name = "MIXS", + Version = "1.0", + Description = [[ + The MIXS instrument contains two parallel telescopes, designed to map the X-ray + emission from Mercury at two angular resolutions. The narrow-field telescope (MIXS-T) + uses a grazing incidence optic with a 1 degree field-of-view (FOV) and an imaging + detector with 64 x 64 pixels. The wide-field telescope (MIXS-C) uses a collimator to + define a FOV of ~10 degrees Full Width at Zero Maximum (FWZM). Its detector is + identical to MIXS-T, but as the collimator has no imaging capability, the pixels are + aggregated into a single output. The optical axes are aligned with the nadir-pointing + axis of the spacecraft. + ]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/fov/phebus.asset b/data/assets/scene/solarsystem/missions/bepicolombo/fov/phebus.asset new file mode 100644 index 0000000000..86d52904ec --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/fov/phebus.asset @@ -0,0 +1,137 @@ +local transforms = asset.require("../model") +local kernels = asset.require("../kernels") + + + +local PhebusSlit75 = { + Identifier = "BepiColomboMPO_PhebusSlit75", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.PhebusSlit75, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_PHEBUS_SLIT_75", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Phebus Slit 75", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local PhebusSlit100 = { + Identifier = "BepiColomboMPO_PhebusSlit100", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.PhebusSlit100, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_PHEBUS_SLIT_100", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Phebus Slit 100", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local Phebus75 = { + Identifier = "BepiColomboMPO_Phebus75", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.Phebus75, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_PHEBUS_75", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Phebus 75", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local Phebus100 = { + Identifier = "BepiColomboMPO_Phebus100", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.Phebus100, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_PHEBUS_100", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Phebus 100", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + + +asset.onInitialize(function() + openspace.addSceneGraphNode(PhebusSlit75) + openspace.addSceneGraphNode(PhebusSlit100) + openspace.addSceneGraphNode(Phebus75) + openspace.addSceneGraphNode(Phebus100) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(Phebus100) + openspace.removeSceneGraphNode(Phebus75) + openspace.removeSceneGraphNode(PhebusSlit100) + openspace.removeSceneGraphNode(PhebusSlit75) +end) + + + +asset.meta = { + Name = "Phebus", + Version = "1.0", + Description = [[ + The PHEBUS instrument is a UV spectrometer covering the spectral range going from + 50 nm to 315 nm with two additional narrow bands in the visible around 404 nm (K line) + and 422 nm (Ca line). Photons from the source (exosphere of Mercury) are collected by + a SiC primary mirror installed inside a one-degree of freedom rotating mechanism + (360 degrees). The primary mirror focuses the photons on a slit. Spectrometric + information is obtained by the use of two gratings sharing the same pupil. Photons + going through the slit are scattered according to their wavelength onto two separate + intensified cross-delay anode detectors. One detector (labelled EUV) covers the + 55-155 nm wavelength range. The second one (labelled FUV) covers the 145-315nm + wavelength range. The two intensifiers based on Micro-Channel Plates use high voltages + at values around 3600-5000 V. The two visible narrow spectral bands are obtained by + two prisms on the side of the FUV detector that feed two identical Photo-Multiplier + Tubes. The high voltage level that is necessary for these PMT is around 1000 V. They + are called NUV Ca and NUV K detectors. + ]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/fov/serena.asset b/data/assets/scene/solarsystem/missions/bepicolombo/fov/serena.asset new file mode 100644 index 0000000000..ce050aa3ec --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/fov/serena.asset @@ -0,0 +1,56 @@ +local transforms = asset.require("../model") +local kernels = asset.require("../kernels") + + + +local SerenaElena = { + Identifier = "BepiColomboMPO_SerenaElena", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElena, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA", + Method = "POLYGON", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + + +asset.onInitialize(function() + openspace.addSceneGraphNode(SerenaElena) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(SerenaElena) +end) + + + +asset.meta = { + Name = "Serena", + Version = "1.0", + Description = [[ + The Search for Exospheric Refilling and Emitted Natural Abundances (SERENA) is a + single instrument composed by 4 units devoted to the detection of neutral and ionized + particles in the Hermean environment. It addresses some of the main scientific + objectives of the BepiColombo mission: composition, origin and dynamics of Mercury's + exosphere and polar deposits; and structure and dynamics of Mercury's magnetosphere. + Each unit is able to operate individually and to achieve its specific scientific + objectives. In addition, the opportunity to operate sensors simultaneously greatly + improves the success of scientific objectives and allows for additional objectives. + ]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/fov/serena_anodes.asset b/data/assets/scene/solarsystem/missions/bepicolombo/fov/serena_anodes.asset new file mode 100644 index 0000000000..9476efd37f --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/fov/serena_anodes.asset @@ -0,0 +1,832 @@ +local transforms = asset.require("../model") +local kernels = asset.require("../kernels") + + + +local SerenaElenaAN01 = { + Identifier = "BepiColomboMPO_SerenaElena_AN01", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN01, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_01", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN01", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN02 = { + Identifier = "BepiColomboMPO_SerenaElena_AN02", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN02, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_02", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN02", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN03 = { + Identifier = "BepiColomboMPO_SerenaElena_AN03", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN03, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_03", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN03", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN04 = { + Identifier = "BepiColomboMPO_SerenaElena_AN04", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN04, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_04", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN04", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN05 = { + Identifier = "BepiColomboMPO_SerenaElena_AN05", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN05, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_05", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN05", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN06 = { + Identifier = "BepiColomboMPO_SerenaElena_AN06", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN06, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_06", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN06", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN07 = { + Identifier = "BepiColomboMPO_SerenaElena_AN07", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN07, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_07", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN07", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN08 = { + Identifier = "BepiColomboMPO_SerenaElena_AN08", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN08, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_08", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN08", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN09 = { + Identifier = "BepiColomboMPO_SerenaElena_AN09", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN09, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_09", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN09", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN10 = { + Identifier = "BepiColomboMPO_SerenaElena_AN10", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN10, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_10", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN10", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN11 = { + Identifier = "BepiColomboMPO_SerenaElena_AN11", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN11, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_11", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN11", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN12 = { + Identifier = "BepiColomboMPO_SerenaElena_AN12", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN12, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_12", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN12", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN13 = { + Identifier = "BepiColomboMPO_SerenaElena_AN13", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN13, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_13", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN13", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN14 = { + Identifier = "BepiColomboMPO_SerenaElena_AN14", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN14, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_14", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN14", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN15 = { + Identifier = "BepiColomboMPO_SerenaElena_AN15", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN15, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_15", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN15", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN16 = { + Identifier = "BepiColomboMPO_SerenaElena_AN16", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN16, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_16", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN16", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN17 = { + Identifier = "BepiColomboMPO_SerenaElena_AN17", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN17, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_17", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN17", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN18 = { + Identifier = "BepiColomboMPO_SerenaElena_AN18", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN18, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_18", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN18", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN19 = { + Identifier = "BepiColomboMPO_SerenaElena_AN19", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN19, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_19", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN19", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN20 = { + Identifier = "BepiColomboMPO_SerenaElena_AN20", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN20, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_20", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN20", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN21 = { + Identifier = "BepiColomboMPO_SerenaElena_AN21", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN21, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_21", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN21", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN22 = { + Identifier = "BepiColomboMPO_SerenaElena_AN22", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN22, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_22", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN22", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN23 = { + Identifier = "BepiColomboMPO_SerenaElena_AN23", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN23, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_23", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN23", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN24 = { + Identifier = "BepiColomboMPO_SerenaElena_AN24", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN24, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_24", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN24", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN25 = { + Identifier = "BepiColomboMPO_SerenaElena_AN25", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN25, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_25", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN25", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN26 = { + Identifier = "BepiColomboMPO_SerenaElena_AN26", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN26, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_26", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN26", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN27 = { + Identifier = "BepiColomboMPO_SerenaElena_AN27", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN27, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_27", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN27", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN28 = { + Identifier = "BepiColomboMPO_SerenaElena_AN28", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN28, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_28", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN28", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN29 = { + Identifier = "BepiColomboMPO_SerenaElena_AN29", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN29, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_29", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN29", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN30 = { + Identifier = "BepiColomboMPO_SerenaElena_AN30", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN30, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_30", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN30", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN31 = { + Identifier = "BepiColomboMPO_SerenaElena_AN31", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN31, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_31", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN31", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SerenaElenaAN32 = { + Identifier = "BepiColomboMPO_SerenaElena_AN32", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SerenaElenaAN32, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SERENA_ELENA_AN_32", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Serena Elena AN32", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + + + +asset.onInitialize(function() + openspace.addSceneGraphNode(SerenaElenaAN01) + openspace.addSceneGraphNode(SerenaElenaAN02) + openspace.addSceneGraphNode(SerenaElenaAN03) + openspace.addSceneGraphNode(SerenaElenaAN04) + openspace.addSceneGraphNode(SerenaElenaAN05) + openspace.addSceneGraphNode(SerenaElenaAN06) + openspace.addSceneGraphNode(SerenaElenaAN07) + openspace.addSceneGraphNode(SerenaElenaAN08) + openspace.addSceneGraphNode(SerenaElenaAN09) + openspace.addSceneGraphNode(SerenaElenaAN10) + openspace.addSceneGraphNode(SerenaElenaAN11) + openspace.addSceneGraphNode(SerenaElenaAN12) + openspace.addSceneGraphNode(SerenaElenaAN13) + openspace.addSceneGraphNode(SerenaElenaAN14) + openspace.addSceneGraphNode(SerenaElenaAN15) + openspace.addSceneGraphNode(SerenaElenaAN16) + openspace.addSceneGraphNode(SerenaElenaAN17) + openspace.addSceneGraphNode(SerenaElenaAN18) + openspace.addSceneGraphNode(SerenaElenaAN19) + openspace.addSceneGraphNode(SerenaElenaAN20) + openspace.addSceneGraphNode(SerenaElenaAN21) + openspace.addSceneGraphNode(SerenaElenaAN22) + openspace.addSceneGraphNode(SerenaElenaAN23) + openspace.addSceneGraphNode(SerenaElenaAN24) + openspace.addSceneGraphNode(SerenaElenaAN25) + openspace.addSceneGraphNode(SerenaElenaAN26) + openspace.addSceneGraphNode(SerenaElenaAN27) + openspace.addSceneGraphNode(SerenaElenaAN28) + openspace.addSceneGraphNode(SerenaElenaAN29) + openspace.addSceneGraphNode(SerenaElenaAN30) + openspace.addSceneGraphNode(SerenaElenaAN31) + openspace.addSceneGraphNode(SerenaElenaAN32) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(SerenaElenaAN32) + openspace.removeSceneGraphNode(SerenaElenaAN31) + openspace.removeSceneGraphNode(SerenaElenaAN30) + openspace.removeSceneGraphNode(SerenaElenaAN29) + openspace.removeSceneGraphNode(SerenaElenaAN28) + openspace.removeSceneGraphNode(SerenaElenaAN27) + openspace.removeSceneGraphNode(SerenaElenaAN26) + openspace.removeSceneGraphNode(SerenaElenaAN25) + openspace.removeSceneGraphNode(SerenaElenaAN24) + openspace.removeSceneGraphNode(SerenaElenaAN23) + openspace.removeSceneGraphNode(SerenaElenaAN22) + openspace.removeSceneGraphNode(SerenaElenaAN21) + openspace.removeSceneGraphNode(SerenaElenaAN20) + openspace.removeSceneGraphNode(SerenaElenaAN19) + openspace.removeSceneGraphNode(SerenaElenaAN18) + openspace.removeSceneGraphNode(SerenaElenaAN17) + openspace.removeSceneGraphNode(SerenaElenaAN16) + openspace.removeSceneGraphNode(SerenaElenaAN15) + openspace.removeSceneGraphNode(SerenaElenaAN14) + openspace.removeSceneGraphNode(SerenaElenaAN13) + openspace.removeSceneGraphNode(SerenaElenaAN12) + openspace.removeSceneGraphNode(SerenaElenaAN11) + openspace.removeSceneGraphNode(SerenaElenaAN10) + openspace.removeSceneGraphNode(SerenaElenaAN09) + openspace.removeSceneGraphNode(SerenaElenaAN08) + openspace.removeSceneGraphNode(SerenaElenaAN07) + openspace.removeSceneGraphNode(SerenaElenaAN06) + openspace.removeSceneGraphNode(SerenaElenaAN05) + openspace.removeSceneGraphNode(SerenaElenaAN04) + openspace.removeSceneGraphNode(SerenaElenaAN03) + openspace.removeSceneGraphNode(SerenaElenaAN02) + openspace.removeSceneGraphNode(SerenaElenaAN01) +end) + + + +asset.meta = { + Name = "Serena Anodes", + Version = "1.0", + Description = [[ + The Search for Exospheric Refilling and Emitted Natural Abundances (SERENA) is a + single instrument composed by 4 units devoted to the detection of neutral and ionized + particles in the Hermean environment. It addresses some of the main scientific + objectives of the BepiColombo mission: composition, origin and dynamics of Mercury's + exosphere and polar deposits; and structure and dynamics of Mercury's magnetosphere. + Each unit is able to operate individually and to achieve its specific scientific + objectives. In addition, the opportunity to operate sensors simultaneously greatly + improves the success of scientific objectives and allows for additional objectives. + ]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/fov/sibbiosys.asset b/data/assets/scene/solarsystem/missions/bepicolombo/fov/sibbiosys.asset new file mode 100644 index 0000000000..b5199d9b94 --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/fov/sibbiosys.asset @@ -0,0 +1,378 @@ +local transforms = asset.require("../model") +local kernels = asset.require("../kernels") + + + +local SimbioSys_HRIC_FPA = { + Identifier = "BepiColomboMPO_SIMBIOSYS_HRIC_FPA", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SymbioSysHricFpa, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIMBIO-SYS_HRIC_FPA", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Simbio-Sys HRIC FPA", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SimbioSys_HRIC_F550 = { + Identifier = "BepiColomboMPO_SIMBIOSYS_HRIC_F550", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SymbioSysHricF550, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIMBIO-SYS_HRIC_F550", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Simbio-Sys HRIC F550", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SimbioSys_HRIC_FPAN = { + Identifier = "BepiColomboMPO_SIMBIOSYS_HRIC_FPAN", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SymbioSysHricFpan, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIMBIO-SYS_HRIC_FPAN", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Simbio-Sys HRIC FPAN", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SimbioSys_HRIC_F750 = { + Identifier = "BepiColomboMPO_SIMBIOSYS_HRIC_F750", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SymbioSysHricF750, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIMBIO-SYS_HRIC_F750", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Simbio-Sys HRIC F750", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SimbioSys_HRIC_F880 = { + Identifier = "BepiColomboMPO_SIMBIOSYS_HRIC_F880", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SymbioSysHricF880, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIMBIO-SYS_HRIC_F880", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Simbio-Sys HRIC F880", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SimbioSys_STC_L = { + Identifier = "BepiColomboMPO_SIMBIOSYS_STC_L", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SymbioSysSTCL, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIMBIO-SYS_STC-L", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Simbio-Sys STC L", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SimbioSys_STC_H = { + Identifier = "BepiColomboMPO_SIMBIOSYS_STC_H", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SymbioSysSTCH, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIMBIO-SYS_STC-H", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Simbio-Sys STC H", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SimbioSys_STC_L_F920 = { + Identifier = "BepiColomboMPO_SIMBIOSYS_STC_L_F920", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SymbioSysSTCLF920, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIMBIO-SYS_STC-L_F920", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Simbio-Sys STC L F920", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SimbioSys_STC_L_F550 = { + Identifier = "BepiColomboMPO_SIMBIOSYS_STC_L_F550", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SymbioSysSTCLF550, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIMBIO-SYS_STC-L_F550", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Simbio-Sys STC L F550", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SimbioSys_STC_L_P700 = { + Identifier = "BepiColomboMPO_SIMBIOSYS_STC_L_P700", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SymbioSysSTCLP700, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIMBIO-SYS_STC-L_P700", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Simbio-Sys STC L P700", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SimbioSys_STC_H_P700 = { + Identifier = "BepiColomboMPO_SIMBIOSYS_STC_H_P700", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SymbioSysSTCHP700, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIMBIO-SYS_STC-H_P700", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Simbio-Sys STC H P700", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SimbioSys_STC_H_F420 = { + Identifier = "BepiColomboMPO_SIMBIOSYS_STC_H_F420", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SymbioSysSTCHF420, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIMBIO-SYS_STC-H_F420", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Simbio-Sys STC H F420", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SimbioSys_STC_H_F750 = { + Identifier = "BepiColomboMPO_SIMBIOSYS_STC_H_F750", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SymbioSysSTCHF750, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIMBIO-SYS_STC-H_F750", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Simbio-Sys STC H F750", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SimbioSys_VIHI = { + Identifier = "BepiColomboMPO_SIMBIOSYS_VIHI", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.SymbioSysVIHI, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIMBIO-SYS_VIHI", + Method = "RECTANGLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Simbio-Sys VIHI", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + + +asset.onInitialize(function() + openspace.addSceneGraphNode(SimbioSys_HRIC_FPA) + openspace.addSceneGraphNode(SimbioSys_HRIC_F550) + openspace.addSceneGraphNode(SimbioSys_HRIC_FPAN) + openspace.addSceneGraphNode(SimbioSys_HRIC_F750) + openspace.addSceneGraphNode(SimbioSys_HRIC_F880) + openspace.addSceneGraphNode(SimbioSys_STC_L) + openspace.addSceneGraphNode(SimbioSys_STC_H) + openspace.addSceneGraphNode(SimbioSys_STC_L_F920) + openspace.addSceneGraphNode(SimbioSys_STC_L_F550) + openspace.addSceneGraphNode(SimbioSys_STC_L_P700) + openspace.addSceneGraphNode(SimbioSys_STC_H_P700) + openspace.addSceneGraphNode(SimbioSys_STC_H_F420) + openspace.addSceneGraphNode(SimbioSys_STC_H_F750) + openspace.addSceneGraphNode(SimbioSys_VIHI) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(SimbioSys_VIHI) + openspace.removeSceneGraphNode(SimbioSys_STC_H_F750) + openspace.removeSceneGraphNode(SimbioSys_STC_H_F420) + openspace.removeSceneGraphNode(SimbioSys_STC_H_P700) + openspace.removeSceneGraphNode(SimbioSys_STC_L_P700) + openspace.removeSceneGraphNode(SimbioSys_STC_L_F550) + openspace.removeSceneGraphNode(SimbioSys_STC_L_F920) + openspace.removeSceneGraphNode(SimbioSys_STC_H) + openspace.removeSceneGraphNode(SimbioSys_STC_L) + openspace.removeSceneGraphNode(SimbioSys_HRIC_F880) + openspace.removeSceneGraphNode(SimbioSys_HRIC_F750) + openspace.removeSceneGraphNode(SimbioSys_HRIC_FPAN) + openspace.removeSceneGraphNode(SimbioSys_HRIC_F550) + openspace.removeSceneGraphNode(SimbioSys_HRIC_FPA) +end) + + + +asset.meta = { + Name = "SYMBIO-SYS", + Version = "1.0", + Description = [[ + SIMBIO-SYS has been conceived to be integrated on the BepiColombo MPO pointing in the + nadir direction in order to perform the remote sensing of the Mercury surface during + the satellite orbits. The SIMBIO-SYS instrument architecture is based on 3 different + channels composing the instrument front-end with a common main electronics and power + supply. + ]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/fov/sixs.asset b/data/assets/scene/solarsystem/missions/bepicolombo/fov/sixs.asset new file mode 100644 index 0000000000..a523a5c653 --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/fov/sixs.asset @@ -0,0 +1,104 @@ +local transforms = asset.require("../model") +local kernels = asset.require("../kernels") + + + +local SixsX1 = { + Identifier = "BepiColomboMPO_SixsX1", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.Sixs_X1, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIXS-X-1", + Method = "ELLIPSE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Sixs X1", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SixsX2 = { + Identifier = "BepiColomboMPO_SixsX2", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.Sixs_X2, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIXS-X-2", + Method = "ELLIPSE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Sixs X2", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local SixsX3 = { + Identifier = "BepiColomboMPO_SixsX3", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.Sixs_X3, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_SIXS-X-3", + Method = "ELLIPSE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Sixs X3", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + + +asset.onInitialize(function() + -- Circle shapes are currently not supported + -- openspace.addSceneGraphNode(SixsX1) + -- openspace.addSceneGraphNode(SixsX2) + -- openspace.addSceneGraphNode(SixsX3) +end) + +asset.onDeinitialize(function() + -- openspace.removeSceneGraphNode(SixsX3) + -- openspace.removeSceneGraphNode(SixsX2) + -- openspace.removeSceneGraphNode(SixsX1) +end) + + + +asset.meta = { + Name = "Sixs", + Version = "1.0", + Description = [[ + The scientific investigation performed by the Solar Intensity X-ray and particle + Spectrometer (SIXS) is the determination of solar impact on the Hermean surface in the + form of direct X-rays and energetic particles, which induce observable X-ray emission + via interaction with the surface of the planet. Particles of concern here are highly + energetic solar protons and electrons. + ]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/fov/startracker.asset b/data/assets/scene/solarsystem/missions/bepicolombo/fov/startracker.asset new file mode 100644 index 0000000000..924aa134a2 --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/fov/startracker.asset @@ -0,0 +1,107 @@ +local transforms = asset.require("../model") +local kernels = asset.require("../kernels") + + + +local StarTracker1 = { + Identifier = "BepiColomboMPO_StarTracker1", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.StarTracker1, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_STR-1", + Method = "CIRCLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Star Tracker 1", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local StarTracker2 = { + Identifier = "BepiColomboMPO_StarTracker2", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.StarTracker2, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_STR-2", + Method = "CIRCLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Star Tracker 2", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + +local StarTracker3 = { + Identifier = "BepiColomboMPO_StarTracker3", + Parent = transforms.BepiColombo.Identifier, + Renderable = { + Type = "RenderableFov", + Body = kernels.ID.MPO, + Frame = kernels.Frame.StarTracker3, + RGB = { 0.8, 0.7, 0.7 }, + Instrument = { + Name = "MPO_STR-3", + Method = "CIRCLE", + Aberration = "NONE" + }, + AlwaysDrawFov = true, + PotentialTargets = { "MERCURY", "EARTH", "VENUS" }, + FrameConversions = {} + }, + GUI = { + Name = "MPO Star Tracker 3", + Path = "/Solar System/Missions/BepiColombo/Instruments", + } +} + + +asset.onInitialize(function() + -- Circle shapes are currently not supported + -- openspace.addSceneGraphNode(StarTracker1) + -- openspace.addSceneGraphNode(StarTracker2) + -- openspace.addSceneGraphNode(StarTracker3) +end) + +asset.onDeinitialize(function() + -- openspace.removeSceneGraphNode(StarTracker1) + -- openspace.removeSceneGraphNode(StarTracker2) + -- openspace.removeSceneGraphNode(StarTracker3) +end) + + + +asset.meta = { + Name = "Star Tracker", + Version = "1.0", + Description = [[ + From a functional point of view, the Autonomous Star Trackers can be seen as a video + camera plus an image processing unit that, starting from an image of the sky, extracts + the attitude information for the AOCS, measured with respect to the J2000 inertial + reference system. + + The STR can track up to 15 stars simultaneously and consists of a Single box that + contains the optical head, the main electronics and a baffle which is thermally + decoupled from the box. + ]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/kernels.asset b/data/assets/scene/solarsystem/missions/bepicolombo/kernels.asset new file mode 100644 index 0000000000..7503619b7a --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/kernels.asset @@ -0,0 +1,303 @@ +local kernels = asset.resource({ + Name = "BepiColombo Kernels", + Type = "HttpSynchronization", + Identifier = "bepicolombo_kernels", + Version = 1 +}) + + +local BepiColomboKernels = { + -- Kernel list based on bc_ops_v413_20240112_001.tm + kernels .. "bc_mpo_magboom_default_s20191107_v01.bc", + kernels .. "bc_mpo_hga_scm_20181020_20190101_s20201020_v02.bc", + kernels .. "bc_mpo_hga_scm_20190101_20200101_s20230309_v01.bc", + kernels .. "bc_mpo_hga_scm_20200101_20210101_s20230309_v01.bc", + kernels .. "bc_mpo_hga_scm_20210101_20220101_s20230309_v01.bc", + kernels .. "bc_mpo_hga_scm_20220101_20230101_s20221229_v01.bc", + kernels .. "bc_mpo_hga_scm_20230101_20240101_s20240104_v01.bc", + kernels .. "bc_mpo_hga_scm_20240101_20240111_s20240110_v01.bc", + kernels .. "bc_mpo_mga_scm_20181020_20190101_s20200109_v02.bc", + kernels .. "bc_mpo_mga_scm_20190101_20200101_s20230309_v01.bc", + kernels .. "bc_mpo_mga_scm_20200101_20210101_s20230309_v01.bc", + kernels .. "bc_mpo_mga_scm_20210101_20220101_s20230309_v01.bc", + kernels .. "bc_mpo_mga_scm_20220101_20230101_s20221229_v01.bc", + kernels .. "bc_mpo_mga_scm_20230101_20240101_s20240104_v01.bc", + kernels .. "bc_mpo_mga_scm_20240101_20240111_s20240110_v01.bc", + kernels .. "bc_mpo_sa_scm_20181020_20190101_s20211202_v01.bc", + kernels .. "bc_mpo_sa_scm_20190101_20200101_s20230309_v01.bc", + kernels .. "bc_mpo_sa_scm_20200101_20210101_s20230309_v01.bc", + kernels .. "bc_mpo_sa_scm_20210101_20220101_s20230309_v01.bc", + kernels .. "bc_mpo_sa_scm_20220101_20230101_s20221229_v01.bc", + kernels .. "bc_mpo_sa_scm_20230101_20240101_s20240104_v01.bc", + kernels .. "bc_mpo_sa_scm_20240101_20240111_s20240110_v01.bc", + kernels .. "bc_mtm_sa_scm_20181020_20190101_s20200109_v02.bc", + kernels .. "bc_mtm_sa_scm_20190101_20200101_s20230309_v01.bc", + kernels .. "bc_mtm_sa_scm_20200101_20210101_s20230309_v01.bc", + kernels .. "bc_mtm_sa_scm_20210101_20220101_s20230309_v01.bc", + kernels .. "bc_mtm_sa_scm_20220101_20230101_s20221229_v01.bc", + kernels .. "bc_mtm_sa_scm_20230101_20240101_s20240104_v01.bc", + kernels .. "bc_mtm_sa_scm_20240101_20240111_s20240110_v01.bc", + kernels .. "bc_mmo_sc_scp_20180317_20251220_f20170228_v02.bc", + kernels .. "bc_mmo_sc_slt_50038_20251220_20280305_f20170228_v02.bc", + kernels .. "bc_mtm_sc_scp_20180317_20251219_f20181121_v02.bc", + kernels .. "bc_mtm_sep_scp_20181019_20251205_f20181127_v02.bc", + kernels .. "bc_mpo_sc_prelaunch_f20181121_v01.bc", + kernels .. "bc_mpo_sc_fcp_00160_20181020_20240216_f20181127_v01.bc", + kernels .. "bc_mpo_sc_scc_20181019_20190101_s20230309_v01.bc", + kernels .. "bc_mpo_sc_scc_20190101_20200101_s20230309_v01.bc", + kernels .. "bc_mpo_sc_scc_20200101_20210101_s20230309_v01.bc", + kernels .. "bc_mpo_sc_scc_20210101_20220101_s20230309_v01.bc", + kernels .. "bc_mpo_sc_scc_20220101_20230101_s20221229_v01.bc", + kernels .. "bc_mpo_sc_scc_20230101_20240101_s20240104_v01.bc", + kernels .. "bc_mpo_sc_scc_20240101_20240111_s20240110_v01.bc", + kernels .. "bc_mpo_sc_scm_20181020_20190101_s20230309_v01.bc", + kernels .. "bc_mpo_sc_scm_20190101_20200101_s20230309_v01.bc", + kernels .. "bc_mpo_sc_scm_20200101_20210101_s20210618_v01.bc", + kernels .. "bc_mpo_sc_scm_20210101_20220101_s20230309_v01.bc", + kernels .. "bc_mpo_sc_scm_20220101_20230101_s20230309_v01.bc", + kernels .. "bc_mpo_sc_scm_20230101_20240101_s20240104_v01.bc", + kernels .. "bc_mpo_sc_scm_20240101_20240111_s20240110_v01.bc", + kernels .. "bc_mpo_v34.tf", + kernels .. "bc_mtm_v12.tf", + kernels .. "bc_mmo_v13.tf", + kernels .. "bc_ops_v01.tf", + kernels .. "bc_sci_v12.tf", + kernels .. "bc_dsk_surfaces_v03.tf", + kernels .. "rssd0004.tf", + kernels .. "earth_topo_201023.tf", + kernels .. "earthstns_jaxa_20230905.tf", + kernels .. "earthfixeditrf93.tf", + kernels .. "estrack_v04.tf", + kernels .. "bc_mmo_sc_bus_v02.bds", + kernels .. "bc_mpo_sc_bus_v02.bds", + kernels .. "bc_mpo_sc_hga_v02.bds", + kernels .. "bc_mpo_sc_mga_v02.bds", + kernels .. "bc_mpo_sc_mosif_v02.bds", + kernels .. "bc_mpo_sc_sa_v02.bds", + kernels .. "bc_mtm_sc_bus_v02.bds", + kernels .. "bc_mtm_sc_samx_v02.bds", + kernels .. "bc_mtm_sc_sapx_v02.bds", + kernels .. "mercury_m002_mes_v02.bds", + + kernels .. "bc_mpo_bela_v09.ti", + kernels .. "bc_mpo_mertis_v08.ti", + kernels .. "bc_mpo_mgns_v02.ti", + kernels .. "bc_mpo_mixs_v06.ti", + kernels .. "bc_mpo_phebus_v06.ti", + kernels .. "bc_mpo_serena_v08.ti", + kernels .. "bc_mpo_simbio-sys_v10.ti", + kernels .. "bc_mpo_sixs_v08.ti", + kernels .. "bc_mpo_str_v02.ti", + kernels .. "bc_mpo_aux_v01.ti", + kernels .. "bc_mtm_mcam_v05.ti", + kernels .. "bc_mmo_mppe_v04.ti", + kernels .. "bc_mmo_msasi_v03.ti", + kernels .. "bc_mmo_ssas_v01.ti", + + kernels .. "de403_masses.tpc", + kernels .. "gm_de431.tpc", + kernels .. "pck00011_bc_v00.tpc", + + kernels .. "earth_070425_370426_predict.bpc", + kernels .. "earth_000101_240403_240109.bpc", + + kernels .. "bc_mpo_step_20240110.tsc", + kernels .. "bc_mpo_fict_20181127.tsc", + kernels .. "bc_mmo_fict_20170228.tsc", + + kernels .. "de432s.bsp", + kernels .. "earthstns_itrf93_201023.bsp", + kernels .. "earthstns_jaxa_20230905.bsp", + kernels .. "estrack_v04.bsp", + kernels .. "bc_sci_v02.bsp", + kernels .. "bc_mmo_struct_v01.bsp", + kernels .. "bc_mmo_scp_20181019_20251220_v02.bsp", + kernels .. "bc_mtm_struct_v06.bsp", + kernels .. "bc_mtm_scp_20181019_20251219_v03.bsp", + kernels .. "bc_mpo_cog_v03.bsp", + kernels .. "bc_mpo_cog_00160_20181118_20240201_v01.bsp", + kernels .. "bc_mpo_struct_v09.bsp", + kernels .. "bc_mpo_schulte_vector_v01.bsp", + kernels .. "bc_mpo_prelaunch_v01.bsp", + kernels .. "bc_mpo_fcp_00160_20181020_20260328_v01.bsp" + + +-- kernels .. "bc_mpo_step_20240110.tsc", +-- +-- kernels .. "de432s.bsp", +-- kernels .. "bc_mpo_fcp_00160_20181020_20260328_v01.bsp", +-- kernels .. "bc_mmo_struct_v01.bsp", +-- kernels .. "bc_mtm_struct_v06.bsp", +-- kernels .. "bc_mpo_struct_v09.bsp", +-- +-- kernels .. "bc_mmo_mppe_v04.ti", +-- kernels .. "bc_mmo_msasi_v03.ti", +-- kernels .. "bc_mmo_ssas_v01.ti", +-- kernels .. "bc_mpo_aux_v01.ti", +-- kernels .. "bc_mpo_bela_v09.ti", +-- kernels .. "bc_mpo_mertis_v08.ti", +-- kernels .. "bc_mpo_mgns_v02.ti", +-- kernels .. "bc_mpo_mixs_v06.ti", +-- kernels .. "bc_mpo_phebus_v06.ti", +-- kernels .. "bc_mpo_serena_v08.ti", +-- kernels .. "bc_mpo_simbio-sys_v10.ti", +-- kernels .. "bc_mpo_sixs_v08.ti", +-- kernels .. "bc_mpo_str_v02.ti", +-- kernels .. "bc_mtm_mcam_v05.ti", +-- +-- kernels .. "bc_sci_v12.tf", +-- kernels .. "bc_mmo_v13.tf", +-- kernels .. "bc_mpo_v34.tf", +-- kernels .. "bc_mtm_v12.tf", +-- kernels .. "bc_ops_v01.tf", +-- +-- kernels .. "bc_mpo_sc_fcp_00160_20181020_20240216_f20181127_v01.bc", +-- -- kernels .. "bc_mpo_sc_scm_20240101_20240111_s20240110_v01.bc", +-- -- kernels .. "bc_mpo_sc_scm_20230101_20240101_s20240104_v01.bc", +-- -- kernels .. "bc_mpo_sc_scm_20220101_20230101_s20230309_v01.bc", +-- -- kernels .. "bc_mpo_sc_scm_20210101_20220101_s20230309_v01.bc", +-- -- kernels .. "bc_mpo_sc_scm_20200101_20210101_s20210618_v01.bc", +-- -- kernels .. "bc_mpo_sc_scm_20190101_20200101_s20230309_v01.bc", +-- -- kernels .. "bc_mpo_sc_scm_20181020_20190101_s20230309_v01.bc", +-- +-- kernels .. "bc_mpo_sc_scc_20240101_20240111_s20240110_v01.bc", +-- kernels .. "bc_mpo_sc_scc_20230101_20240101_s20240104_v01.bc", +-- kernels .. "bc_mpo_sc_scc_20220101_20230101_s20221229_v01.bc", +-- kernels .. "bc_mpo_sc_scc_20210101_20220101_s20230309_v01.bc", +-- kernels .. "bc_mpo_sc_scc_20200101_20210101_s20230309_v01.bc", +-- kernels .. "bc_mpo_sc_scc_20190101_20200101_s20230309_v01.bc", +-- kernels .. "bc_mpo_sc_scc_20181019_20190101_s20230309_v01.bc", +-- +-- kernels .. "bc_mpo_hga_scm_20240101_20240111_s20240110_v01.bc", +-- kernels .. "bc_mpo_hga_scm_20181020_20190101_s20201020_v02.bc", +-- kernels .. "bc_mpo_hga_scm_20190101_20200101_s20230309_v01.bc", +-- kernels .. "bc_mpo_hga_scm_20200101_20210101_s20230309_v01.bc", +-- kernels .. "bc_mpo_hga_scm_20210101_20220101_s20230309_v01.bc", +-- kernels .. "bc_mpo_hga_scm_20220101_20230101_s20221229_v01.bc", +-- kernels .. "bc_mpo_hga_scm_20230101_20240101_s20240104_v01.bc", +-- kernels .. "bc_mpo_magboom_default_s20191107_v01.bc", +-- kernels .. "bc_mpo_mertis_zero_s20191107_v02.bc", +-- kernels .. "bc_mpo_mga_scm_20181020_20190101_s20200109_v02.bc", +-- kernels .. "bc_mpo_mga_scm_20190101_20200101_s20230309_v01.bc", +-- kernels .. "bc_mpo_mga_scm_20200101_20210101_s20230309_v01.bc", +-- kernels .. "bc_mpo_mga_scm_20210101_20220101_s20230309_v01.bc", +-- kernels .. "bc_mpo_mga_scm_20220101_20230101_s20221229_v01.bc", +-- kernels .. "bc_mpo_mga_scm_20230101_20240101_s20240104_v01.bc", +-- kernels .. "bc_mpo_mga_scm_20240101_20240111_s20240110_v01.bc", +-- kernels .. "bc_mpo_mga_zero_s20191107_v02.bc", +-- kernels .. "bc_mpo_phebus_zero_s20210408_v02.bc", +-- kernels .. "bc_mpo_sa_scm_20181020_20190101_s20211202_v01.bc", +-- kernels .. "bc_mpo_sa_scm_20190101_20200101_s20230309_v01.bc", +-- kernels .. "bc_mpo_sa_scm_20200101_20210101_s20230309_v01.bc", +-- kernels .. "bc_mpo_sa_scm_20210101_20220101_s20230309_v01.bc", +-- kernels .. "bc_mpo_sa_scm_20220101_20230101_s20221229_v01.bc", +-- kernels .. "bc_mpo_sa_scm_20230101_20240101_s20240104_v01.bc", +-- kernels .. "bc_mpo_sa_scm_20240101_20240111_s20240110_v01.bc", +-- kernels .. "bc_mpo_sa_zero_s20191107_v02.bc", +-- kernels .. "bc_mpo_sa_zero_s20191107_v02.bc", +-- kernels .. "bc_mpo_serena_zero_s20191207_v02.bc" +} + +local ID = { + MPO = "-121" +} + +local Frame = { + MPO = "MPO_SPACECRAFT", + + HGA = "MPO_HGA", + BelaReceiver = "MPO_BELA_RX", + BelaTransmitterMain = "MPO_BELA_TX_MAIN", + BelaTransmitterRed = "MPO_BELA_TX_RED", + MertisTis = "MPO_MERTIS_TIS", + MertisTisPlanet = "MPO_MERTIS_TIS_PLANET", + MertisTisSpace = "MPO_MERTIS_TIS_SPACE", + MGNS = "MPO_MGNS", + MIXS_C = "MPO_MIXS-C", + MIXS_T = "MPO_MIXS-T", + PhebusSlit75 = "MPO_PHEBUS_SLIT_75", + PhebusSlit100 = "MPO_PHEBUS_SLIT_100", + Phebus75 = "MPO_PHEBUS_75", + Phebus100 = "MPO_PHEBUS_100", + SerenaElena = "MPO_SERENA_ELENA", + SerenaElenaAN01 = "MPO_SERENA_ELENA_AN_01", + SerenaElenaAN02 = "MPO_SERENA_ELENA_AN_02", + SerenaElenaAN03 = "MPO_SERENA_ELENA_AN_03", + SerenaElenaAN04 = "MPO_SERENA_ELENA_AN_04", + SerenaElenaAN05 = "MPO_SERENA_ELENA_AN_05", + SerenaElenaAN06 = "MPO_SERENA_ELENA_AN_06", + SerenaElenaAN07 = "MPO_SERENA_ELENA_AN_07", + SerenaElenaAN08 = "MPO_SERENA_ELENA_AN_08", + SerenaElenaAN09 = "MPO_SERENA_ELENA_AN_09", + SerenaElenaAN10 = "MPO_SERENA_ELENA_AN_10", + SerenaElenaAN11 = "MPO_SERENA_ELENA_AN_11", + SerenaElenaAN12 = "MPO_SERENA_ELENA_AN_12", + SerenaElenaAN13 = "MPO_SERENA_ELENA_AN_13", + SerenaElenaAN14 = "MPO_SERENA_ELENA_AN_14", + SerenaElenaAN15 = "MPO_SERENA_ELENA_AN_15", + SerenaElenaAN16 = "MPO_SERENA_ELENA_AN_16", + SerenaElenaAN17 = "MPO_SERENA_ELENA_AN_17", + SerenaElenaAN18 = "MPO_SERENA_ELENA_AN_18", + SerenaElenaAN19 = "MPO_SERENA_ELENA_AN_19", + SerenaElenaAN20 = "MPO_SERENA_ELENA_AN_20", + SerenaElenaAN21 = "MPO_SERENA_ELENA_AN_21", + SerenaElenaAN22 = "MPO_SERENA_ELENA_AN_22", + SerenaElenaAN23 = "MPO_SERENA_ELENA_AN_23", + SerenaElenaAN24 = "MPO_SERENA_ELENA_AN_24", + SerenaElenaAN25 = "MPO_SERENA_ELENA_AN_25", + SerenaElenaAN26 = "MPO_SERENA_ELENA_AN_26", + SerenaElenaAN27 = "MPO_SERENA_ELENA_AN_27", + SerenaElenaAN28 = "MPO_SERENA_ELENA_AN_28", + SerenaElenaAN29 = "MPO_SERENA_ELENA_AN_29", + SerenaElenaAN30 = "MPO_SERENA_ELENA_AN_30", + SerenaElenaAN31 = "MPO_SERENA_ELENA_AN_31", + SerenaElenaAN32 = "MPO_SERENA_ELENA_AN_32", + SymbioSysHricFpa = "MPO_SIMBIO-SYS_HRIC_FPA", + SymbioSysHricF550 = "MPO_SIMBIO-SYS_HRIC_F550", + SymbioSysHricFpan = "MPO_SIMBIO-SYS_HRIC_FPAN", + SymbioSysHricF750 = "MPO_SIMBIO-SYS_HRIC_F750", + SymbioSysHricF880 = "MPO_SIMBIO-SYS_HRIC_F880", + SymbioSysSTCL = "MPO_SIMBIO-SYS_STC-L", + SymbioSysSTCH = "MPO_SIMBIO-SYS_STC-H", + SymbioSysSTCLF920 = "MPO_SIMBIO-SYS_STC-L_F920", + SymbioSysSTCLF550 = "MPO_SIMBIO-SYS_STC-L_F550", + SymbioSysSTCLP700 = "MPO_SIMBIO-SYS_STC-L_P700", + SymbioSysSTCHP700 = "MPO_SIMBIO-SYS_STC-H_P700", + SymbioSysSTCHF420 = "MPO_SIMBIO-SYS_STC-H_F420", + SymbioSysSTCHF750 = "MPO_SIMBIO-SYS_STC-H_F750", + SymbioSysVIHI = "MPO_SIMBIO-SYS_VIHI", + Sixs_X1 = "MPO_SIXS-X-1", + Sixs_X2 = "MPO_SIXS-X-2", + Sixs_X3 = "MPO_SIXS-X-3", + StarTracker1 = "MPO_STR-1", + StarTracker2 = "MPO_STR-2", + StarTracker3 = "MPO_STR-3", + + + + + +} + + +asset.onInitialize(function() + openspace.spice.loadKernel(BepiColomboKernels) +end) + +asset.onDeinitialize(function() + openspace.spice.unloadKernel(BepiColomboKernels) +end) + +asset.export("ID", ID) +asset.export("Frame", Frame) + + + +asset.meta = { + Name = "BepiColombo Kernels", + Version = "1.0", + Description = "This asset contains the SPICE kernels for the BepiColombo mission.", + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/mission.asset b/data/assets/scene/solarsystem/missions/bepicolombo/mission.asset new file mode 100644 index 0000000000..717e23b6c2 --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/mission.asset @@ -0,0 +1,88 @@ +local Mission = { + Name = "BepiColombo", + Image = "https://scifleet.esa.int/downloads/bepi_mcs/bepicolombo.png", + Description = [[BepiColombo is Europe's first mission to Mercury. It will launch in October 2018 on a journey to the smallest and least explored terrestrial planet in our Solar System. Arriving at Mercury in December 2025, it will endure temperatures in excess of 350°C and gather data during a 1 year nominal mission. The mission comprises two spacecraft: 1. Mercury Planetary Orbiter (MPO), 2. Mercury Magnetospheric Orbiter (MMO). BepiColombo is a joint mission between ESA and the Japan Aerospace Exploration Agency (JAXA), executed under ESA leadership.]], + TimeRange = { + Start = "2018 OCT 20 01:45:00", + End = "2028 MAY 01 12:00:00" -- Preliminary time + }, + Milestones = { + { + Name = "Launch", + Date = "2018 OCT 20 01:45:00" + }, + { + Name = "Earth flyby", + Date = "2020 APR 10 04:25" + }, + { + Name = "First Venus flyby", + Date = "2020 OCT 15 03:58:00" + }, + { + Name = "Second Venus flyby", + Date = "2021 AUG 10 13:51:00" + }, + { + Name = "First Mercury flyby", + Date = "2021 OCT 01 23:34:41" + }, + { + Name = "Second Mercury flyby", + Date = "2022 JUN 23 09:44:00" + }, + { + Name = "Third Mercury flyby", + Date = "2023 JUN 19 19:34:00" + }, + { + Name = "Fourth Mercury flyby", + Date = "2024 SEP 05 12:00:00" -- Preliminary time + }, + { + Name = "Fifth Mercury flyby", + Date = "2024 DEC 02 12:00:00" -- Preliminary time + }, + { + Name = "Sixth Mercury flyby", + Date = "2025 JAN 09 12:00:00" -- Preliminary time + }, + { + Name = "Mercury orbit insertion", + Date = "2025 DEC 05 12:00:00" -- Preliminary time + }, + { + Name = "MPO in final science orbit", + Date = "2026 MAR 14 12:00:00" -- Preliminary time + }, + { + Name = "End of nominal mission", + Date = "2027 MAY 01 12:00:00" -- Preliminary time + }, + { + Name = "End of extended mission", + Date = "2028 MAY 01 12:00:00" -- Preliminary time + } + }, + Phases = {} +} + + +asset.onInitialize(function() + openspace.loadMission(Mission) +end) + +asset.onDeinitialize(function() + openspace.unloadMission(Mission.Name) +end) + + + +asset.meta = { + Name = "BepiColombo Mission", + Version = "1.0", + Description = "This asset contains the mission profile information for the BepiColombo mission. The data in this file has been taken from https://www.esa.int/Science_Exploration/Space_Science/BepiColombo/BepiColombo_factsheet", + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/model.asset b/data/assets/scene/solarsystem/missions/bepicolombo/model.asset new file mode 100644 index 0000000000..05aec4d10e --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/model.asset @@ -0,0 +1,84 @@ +local transform = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") +local kernels = asset.require("./kernels") +local coreKernels = asset.require("spice/core") + + + +local modelFolder = asset.resource({ + Name = "BepiColombo Model", + Type = "HttpSynchronization", + Identifier = "bepicolombo_models", + Version = 1 +}) + + +local BepiColombo = { + Identifier = "BepiColombo", + Parent = transform.SolarSystemBarycenter.Identifier, + Transform = { + Translation = { + Type = "SpiceTranslation", + Target = kernels.ID.MPO, + Observer = coreKernels.ID.SolarSystemBarycenter + }, + Rotation = { + Type = "SpiceRotation", + SourceFrame = kernels.Frame.MPO, + DestinationFrame = coreKernels.Frame.Galactic + } + }, + GUI = { + Name = "BepiColombo", + Path = "/Solar System/Missions/BepiColombo" + } +} + +local Model = { + Identifier = "BepiColomboModel", + Parent = BepiColombo.Identifier, + Transform = { + Translation = { + Type = "StaticTranslation", + Position = { 0.0, -0.275, 0.0 } + } + }, + Renderable = { + Type = "RenderableModel", + GeometryFile = modelFolder .. "bepi_mcs.fbx", + ModelScale = 0.00075, -- The number has been determined by eyeballing it + LightSources = { + sun.LightSource + }, + PerformShading = true, + AmbientIntensity = 0.075 + }, + GUI = { + Name = "BepiColombo Model", + Path = "/Solar System/Missions/BepiColombo" + } +} + + +asset.onInitialize(function() + openspace.addSceneGraphNode(BepiColombo) + openspace.addSceneGraphNode(Model) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(Model) + openspace.removeSceneGraphNode(BepiColombo) +end) + +asset.export(BepiColombo) + + + +asset.meta = { + Name = "BepiColombo Model", + Version = "1.0", + Description = "This asset contains the model of the BepiColombo spacecraft. The model is retrieved from https://s2e2.cosmos.esa.int/bitbucket/projects/SPICE_KERNELS/repos/bepicolombo", + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/assets/scene/solarsystem/missions/bepicolombo/trails.asset b/data/assets/scene/solarsystem/missions/bepicolombo/trails.asset new file mode 100644 index 0000000000..b2220287c2 --- /dev/null +++ b/data/assets/scene/solarsystem/missions/bepicolombo/trails.asset @@ -0,0 +1,73 @@ +local kernels = asset.require("./kernels") +local mercury = asset.require("scene/solarsystem/planets/mercury/transforms") +local solarsystem = asset.require("scene/solarsystem/sun/transforms") +local coreKernels = asset.require("spice/core") + + + +local BepiColomboTrailSun = { + Identifier = "BepiColomboTrailSun", + Parent = solarsystem.SolarSystemBarycenter.Identifier, + Renderable = { + Type = "RenderableTrailTrajectory", + Translation = { + Type = "SpiceTranslation", + Target = kernels.ID.MPO, + Observer = coreKernels.ID.SolarSystemBarycenter + }, + Color = { 0.70, 0.50, 0.20 }, + StartTime = "2018 OCT 20 01:45:00", + EndTime = "2028 MAY 01 12:00:00", + SampleInterval = 60000 + }, + GUI = { + Name = "BepiColombo Trail (Sun)", + Path = "/Solar System/Missions/BepiColombo" + } +} + +local BepiColomboTrailMercury = { + Identifier = "BepiColomboTrailMercury", + Parent = mercury.MercuryBarycenter.Identifier, + Renderable = { + Type = "RenderableTrailTrajectory", + Translation = { + Type = "SpiceTranslation", + Target = kernels.ID.MPO, + Observer = coreKernels.ID.Mercury + }, + Color = { 0.625, 0.255, 0.45 }, + StartTime = "2025 DEC 05 12:00:00", + EndTime = "2028 MAY 01 12:00:00", + SampleInterval = 600 + }, + GUI = { + Name = "BepiColombo Trail (Mercury)", + Path = "/Solar System/Missions/BepiColombo" + } +} + + +asset.onInitialize(function() + openspace.addSceneGraphNode(BepiColomboTrailSun) + openspace.addSceneGraphNode(BepiColomboTrailMercury) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(BepiColomboTrailMercury) + openspace.removeSceneGraphNode(BepiColomboTrailSun) +end) + +asset.export(BepiColomboTrailSun) +asset.export(BepiColomboTrailMercury) + + + +asset.meta = { + Name = "BepiColombo Trails", + Version = "1.0", + Description = "This asset contains the trails for the BepiColombo spacecraft relative to the Sun and Mercury.", + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license" +} diff --git a/data/profiles/bepicolombo.profile b/data/profiles/bepicolombo.profile new file mode 100644 index 0000000000..6cef837a3c --- /dev/null +++ b/data/profiles/bepicolombo.profile @@ -0,0 +1,183 @@ +{ + "assets": [ + "base", + "base_keybindings", + "scene/solarsystem/missions/bepicolombo/bepicolombo", + "scene/solarsystem/planets/earth/earth" + ], + "camera": { + "altitude": 17000000.0, + "anchor": "Earth", + "latitude": 58.5877, + "longitude": 16.1924, + "type": "goToGeo" + }, + "delta_times": [ + 1.0, + 5.0, + 30.0, + 60.0, + 300.0, + 1800.0, + 3600.0, + 43200.0, + 86400.0, + 604800.0, + 1209600.0, + 2592000.0, + 5184000.0, + 7776000.0, + 15552000.0, + 31536000.0, + 63072000.0, + 157680000.0, + 315360000.0, + 630720000.0 + ], + "mark_nodes": [ + "BepiColombo", + "Mercury", + "Earth", + "Venus", + "Sun" + ], + "meta": { + "author": "OpenSpace Team", + "description": "Default OpenSpace Profile. Adds Earth satellites not contained in other profiles", + "license": "MIT License", + "name": "Default", + "url": "https://www.openspaceproject.com", + "version": "1.0" + }, + "properties": [ + { + "name": "Scene.BepiColomboMPO_MertisTis.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_MertisTisPlanet.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_MertisTisSpace.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_Phebus100.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_Phebus75.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_PhebusSlit100.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_PhebusSlit75.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SerenaElena.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SIMBIOSYS_HRIC_F550.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SIMBIOSYS_HRIC_F750.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SIMBIOSYS_HRIC_F880.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SIMBIOSYS_HRIC_FPA.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SIMBIOSYS_HRIC_FPAN.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SIMBIOSYS_STC_H.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SIMBIOSYS_STC_H_F420.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SIMBIOSYS_STC_H_F750.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SIMBIOSYS_STC_H_P700.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SIMBIOSYS_STC_L.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SIMBIOSYS_STC_L_F550.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SIMBIOSYS_STC_L_F920.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SIMBIOSYS_STC_L_P700.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_SIMBIOSYS_VIHI.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_MIXS-C.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + }, + { + "name": "Scene.BepiColomboMPO_MIXS-T.Renderable.Enabled", + "type": "setPropertyValueSingle", + "value": "false" + } + ], + "time": { + "is_paused": false, + "type": "relative", + "value": "-1d" + }, + "version": { + "major": 1, + "minor": 3 + } +} From 0e78e651753233e1d3a1af019ec9ca0a4f21da67 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jan 2024 14:11:04 +0100 Subject: [PATCH 29/30] Fix crash when registering replacement resource functions --- src/scene/assetmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scene/assetmanager.cpp b/src/scene/assetmanager.cpp index aa0ae9d741..ef666ebe85 100644 --- a/src/scene/assetmanager.cpp +++ b/src/scene/assetmanager.cpp @@ -577,7 +577,7 @@ void AssetManager::setUpAssetLuaTable(Asset* asset) { return 1; }, - 2 + 1 ); lua_setfield(*_luaState, assetTableIndex, "localResource"); From ef52155e83e087592f3eb9b23117030bf3b55c97 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jan 2024 16:14:23 +0100 Subject: [PATCH 30/30] Update the VideoPlayer correctly when writing out frames in SessionRecording --- modules/video/src/videoplayer.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/modules/video/src/videoplayer.cpp b/modules/video/src/videoplayer.cpp index 32e9a81b06..bb4cded563 100644 --- a/modules/video/src/videoplayer.cpp +++ b/modules/video/src/videoplayer.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,7 @@ #include #include + namespace { constexpr std::string_view _loggerCat = "VideoPlayer"; @@ -497,6 +499,28 @@ void VideoPlayer::update() { if (_isDestroying) { return; } + + if (global::sessionRecording->isSavingFramesDuringPlayback()) { + double dt = global::sessionRecording->fixedDeltaTimeDuringFrameOutput(); + if (_playbackMode == PlaybackMode::MapToSimulationTime) { + _currentVideoTime = correctVideoPlaybackTime(); + } + else { + _currentVideoTime = _currentVideoTime + dt; + } + + MpvKey key = MpvKey::Time; + mpv_set_property(_mpvHandle, keys[key], formats[key], &_currentVideoTime); + + uint64_t result = mpv_render_context_update(_mpvRenderContext); + while ((result & MPV_RENDER_UPDATE_FRAME) == 0) { + renderFrame(); + + result = mpv_render_context_update(_mpvRenderContext); + } + return; + } + if (_playbackMode == PlaybackMode::MapToSimulationTime) { seekToTime(correctVideoPlaybackTime()); }