diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3298efa
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,34 @@
+################################################################################
+# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
+################################################################################
+
+/.vs/SVFEngine/v16
+/bin/cache
+/bin/street_points_svf.txt
+*.tlog
+*.obj
+*.log
+*.pdb
+*.txt
+/lib/SVFEngine.lib
+/Release
+/ReleaseD
+*.dll
+*.ipdb
+*.iobj
+*.exe
+*.lib
+/bin/Solar3D.exp
+/.vs/Solar3D/v16
+*.csv
+/bin/depth1.jpg
+/bin/depth1 - Copy.jpg
+/bin/depth.jpg
+/bin/POS_Z.png
+/bin/POS_Y.png
+/bin/POS_X.png
+/bin/NEG_Z.png
+/bin/NEG_Y.png
+/bin/NEG_X.png
+/bin/fisheye2.png
+/bin/fisheye.png
diff --git a/Example1/Example1.vcxproj b/Example1/Example1.vcxproj
deleted file mode 100644
index 18ce118..0000000
--- a/Example1/Example1.vcxproj
+++ /dev/null
@@ -1,167 +0,0 @@
-
-
-
-
- Debug
- Win32
-
-
- Release
- Win32
-
-
- Debug
- x64
-
-
- Release
- x64
-
-
-
- {D1FFF330-FBDF-46FE-9F0B-649709F29896}
- Win32Proj
- Registration
- 8.1
- Example1
-
-
-
- Application
- true
- v140
- Unicode
-
-
- Application
- false
- v140
- true
- Unicode
-
-
- Application
- true
- v140
- Unicode
-
-
- Application
- false
- v140
- true
- Unicode
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
- false
- $(SolutionDir)\bin\
-
-
- false
-
-
- false
- $(SolutionDir)\bin\
-
-
-
-
-
- Level3
- Disabled
- WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
-
-
- Console
- true
-
-
-
-
-
-
- Level3
- Disabled
- _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
- $(SolutionDir)\include;..\SVFEngine
-
-
- Console
- true
- osgEarthd.lib;osgEarthFeaturesd.lib;osgEarthUtild.lib;osgEarthQtd.lib;osgEarthSymbologyd.lib;osgEarthAnnotationd.lib;OpenThreadsd.lib;osgd.lib;osgDBd.lib;osgUtild.lib;osgViewerd.lib;osgWidgetd.lib;osgSimd.lib;osgTextd.lib;osgGAd.lib;osgShadowd.lib;osgManipulatord.lib;gdal_i.lib
- $(SolutionDir)\lib\$(Platform)\
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
-
-
- Console
- true
- true
- true
-
-
-
-
- TurnOffAllWarnings
-
-
- MaxSpeed
- true
- true
- NDEBUG;_CONSOLE;OSG_NOTIFY_DISABLED;%(PreprocessorDefinitions)
- $(SolutionDir)\include;..\SVFEngine
-
-
- Console
- true
- true
- true
- $(SolutionDir)\lib\$(Platform)\
- osgEarth.lib;osgEarthFeatures.lib;osgEarthUtil.lib;osgEarthSymbology.lib;osgEarthAnnotation.lib;osgEarthQt.lib;osg.lib;osgDB.lib;osgUtil.lib;osgViewer.lib;OpenThreads.lib;osgSim.lib;osgTerrain.lib;osgFX.lib;osgShadow.lib;osgManipulator.lib;osgText.lib;osgGA.lib;gdal_i.lib;%(AdditionalDependencies)
-
-
-
-
-
-
-
- {f8df3492-a941-4a6d-860e-19c63fa93da5}
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Example1/Example1.vcxproj.filters b/Example1/Example1.vcxproj.filters
deleted file mode 100644
index 40d218e..0000000
--- a/Example1/Example1.vcxproj.filters
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
- {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
- cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
-
-
- {93995380-89BD-4b04-88EB-625FBE52EBFB}
- h;hh;hpp;hxx;hm;inl;inc;xsd
-
-
- {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
- rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
-
-
-
-
-
-
-
- Source Files
-
-
-
\ No newline at end of file
diff --git a/Example1/Example1.vcxproj.user b/Example1/Example1.vcxproj.user
deleted file mode 100644
index ba7105e..0000000
--- a/Example1/Example1.vcxproj.user
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
- E:\VGE4SVF\data\models\OAP3D\OAP3D.osgb
- WindowsLocalDebugger
- $(SolutionDir)\bin
-
-
- E:\VGE4SVF\data\models\OAP3D\OAP3D.osgb
- WindowsLocalDebugger
- $(SolutionDir)\bin
-
-
\ No newline at end of file
diff --git a/Example1/Main.cpp b/Example1/Main.cpp
deleted file mode 100644
index ad61d67..0000000
--- a/Example1/Main.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-
-#ifdef _WIN32 || WIN32
-#include
-#endif
-#include "SVFDatabasePager.h"
-#include "SVFComputeTools.h"
-#include "osg/ShapeDrawable"
-
-int main(int argc, char **argv)
-{
-
- SVFComputeTools computeTools;
- // construct the viewer.
- osgViewer::Viewer* viewer = new osgViewer::Viewer;
- viewer->setUpViewAcrossAllScreens();
- osg::ref_ptr root = new osg::Group;
- //load a 3D city model from file
- //osg::ref_ptr city = osgDB::readNodeFile(argv[1]); //create a model from argument
- //osg::ref_ptr city = osgDB::readNodeFile("./data/models/CAD/CAD.osg"); //use CAD model
- osg::ref_ptr city = osgDB::readNodeFile("./data/models/OAP3D/OAP3D.osgb"); //use OAP3D
- root->addChild(city.get());
-
- osg::ref_ptr manip = new osgGA::TrackballManipulator;
- viewer->setCameraManipulator(manip.get());
- root->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
- viewer->setSceneData(root);
- viewer->setThreadingModel(osgViewer::ViewerBase::ThreadingModel::ThreadPerContext);
- viewer->addEventHandler(new osgViewer::ThreadingHandler);
-
- // add the window size toggle handler
- viewer->addEventHandler(new osgViewer::WindowSizeHandler);
-
- // add the stats handler
- viewer->addEventHandler(new osgViewer::StatsHandler);
-
- // add the LOD Scale handler
- viewer->addEventHandler(new osgViewer::LODScaleHandler);
-
- viewer->addEventHandler(new SkyViewFactorEventHandler(city, root, manip, viewer));
- VGEDatabasePager* databasePager = new VGEDatabasePager;
- databasePager->resume();
- viewer->getScene()->setDatabasePager(databasePager);
-
- return viewer->run();
-}
-
-
-
diff --git a/Example1/ReadMe.txt b/Example1/ReadMe.txt
deleted file mode 100644
index 18aabdb..0000000
--- a/Example1/ReadMe.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-(1) Toggle Full Screen: F key
-(2) Reset camera: Control key
-(3) Rotate: Mouse left button + drag
-(4) Zoom: Mouse right button + drag or Mouse scroll
-(5) Exit: Esc key
-(6) Calculate SVF at a position: Ctrl + mouse click
\ No newline at end of file
diff --git a/Example2/Example2.vcxproj b/Example2/Example2.vcxproj
deleted file mode 100644
index a43ffb8..0000000
--- a/Example2/Example2.vcxproj
+++ /dev/null
@@ -1,167 +0,0 @@
-
-
-
-
- Debug
- Win32
-
-
- Release
- Win32
-
-
- Debug
- x64
-
-
- Release
- x64
-
-
-
- {9266A440-9187-41F7-85C7-82DF0E110143}
- Win32Proj
- Registration
- 8.1
- Example2
-
-
-
- Application
- true
- v140
- Unicode
-
-
- Application
- false
- v140
- true
- Unicode
-
-
- Application
- true
- v140
- Unicode
-
-
- Application
- false
- v140
- true
- Unicode
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
- true
- $(SolutionDir)\bin\
-
-
- false
-
-
- false
- $(SolutionDir)\bin\
-
-
-
-
-
- Level3
- Disabled
- WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
-
-
- Console
- true
-
-
-
-
-
-
- Level3
- Disabled
- _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
- $(SolutionDir)\include;..\SVFEngine
-
-
- Console
- true
- osgEarthd.lib;osgEarthFeaturesd.lib;osgEarthUtild.lib;osgEarthQtd.lib;osgEarthSymbologyd.lib;osgEarthAnnotationd.lib;OpenThreadsd.lib;osgd.lib;osgDBd.lib;osgUtild.lib;osgViewerd.lib;osgWidgetd.lib;osgSimd.lib;osgTextd.lib;osgGAd.lib;osgShadowd.lib;osgManipulatord.lib;gdal_i.lib
- $(SolutionDir)\lib\$(Platform)\
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
-
-
- Console
- true
- true
- true
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
- $(SolutionDir)\include;..\SVFEngine
-
-
- Console
- true
- true
- true
- $(SolutionDir)\lib\$(Platform)\
- osgEarth.lib;osgEarthFeatures.lib;osgEarthUtil.lib;osgEarthSymbology.lib;osgEarthAnnotation.lib;osgEarthQt.lib;osg.lib;osgDB.lib;osgUtil.lib;osgViewer.lib;OpenThreads.lib;osgSim.lib;osgTerrain.lib;osgFX.lib;osgShadow.lib;osgManipulator.lib;osgText.lib;osgGA.lib;gdal_i.lib;%(AdditionalDependencies)
-
-
-
-
-
-
-
- {f8df3492-a941-4a6d-860e-19c63fa93da5}
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Example2/Example2.vcxproj.filters b/Example2/Example2.vcxproj.filters
deleted file mode 100644
index ac2817d..0000000
--- a/Example2/Example2.vcxproj.filters
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
- {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
- cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
-
-
- {93995380-89BD-4b04-88EB-625FBE52EBFB}
- h;hh;hpp;hxx;hm;inl;inc;xsd
-
-
- {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
- rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
-
-
-
-
- Source Files
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Example2/Example2.vcxproj.user b/Example2/Example2.vcxproj.user
deleted file mode 100644
index d7d1f96..0000000
--- a/Example2/Example2.vcxproj.user
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- $(SolutionDir)\bin
- WindowsLocalDebugger
-
-
- $(SolutionDir)\bin
- WindowsLocalDebugger
-
-
\ No newline at end of file
diff --git a/Example2/Main.cpp b/Example2/Main.cpp
deleted file mode 100644
index 289a21d..0000000
--- a/Example2/Main.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-
-
-#ifdef _WIN32 || WIN32
-#include
-#endif
-#include "SVFDatabasePager.h"
-#include "SVFComputeTools.h"
-#include "ShapeFile.h"
-#include
-#ifdef WIN32
-#define ifstream osgDB::ifstream
-#define ofstream osgDB::ofstream
-
-#else
-
-#include
-#define ifstream std::ifstream
-#define ofstream std::ofstream
-
-#endif
-
-//--------------------------------------------------------------------------
-int main(int argc, char **argv)
-{
- // parse arguments
- osg::ArgumentParser arguments(&argc,argv);
- // construct the viewer.
- osgViewer::Viewer* viewer = new osgViewer::Viewer(arguments);
- //viewer->setUpViewInWindow(100, 100, 1024, 1024);
- viewer->setUpViewAcrossAllScreens();
-
- osg::ref_ptr root = new osg::Group;
- osg::ref_ptr city = osgDB::readNodeFile("./data/models/OAP3D/OAP3D.osgb");
- root->addChild(city.get());
- //create a node to render a cubemap from a 3D position
- osg::Group* cubemapCameras = SVFComputeTools::createSVFCameras(city);
- cubemapCameras->setNodeMask(false);
- root->addChild(cubemapCameras);
-
- //create a node to transform a cubemap into a fisheye view and then render onto the screen
- root->addChild(SVFComputeTools::cubemap2hemispherical(cubemapCameras));
-
- //create a node to transform a cubemap into a fisheye view and then render onto an off-screen image for svf calculation
- std::vector contexts;
- viewer->getContexts(contexts);
- osg::ref_ptr cubemap2fisheyeCamera = CameraBuffer::createSlave(512, 512,contexts[0]);
- viewer->addSlave(cubemap2fisheyeCamera.get(), false);
- cubemap2fisheyeCamera->setCullingActive(false);
- cubemap2fisheyeCamera->addChild(SVFComputeTools::cubemap2hemispherical(cubemapCameras));
-
- //create text label for displaying svf value
- osgText::Text* text;
- osg::ref_ptr hudCamera = SVFComputeTools::createHUDText(text, osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
- root->addChild(hudCamera.get());
-
- //create an image buffer for screen capture
- osg::ref_ptr screenshotImg = new osg::Image;
- screenshotImg->allocateImage(1024, 1024, 1, GL_RGB, GL_UNSIGNED_BYTE);
- viewer->getCamera()->attach(osg::Camera::COLOR_BUFFER, screenshotImg.get());
-
-
- osg::ref_ptr manip = new osgGA::TrackballManipulator;
- viewer->setCameraManipulator(manip.get());
- root->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
- viewer->setSceneData(root.get());
- viewer->setThreadingModel(osgViewer::ViewerBase::ThreadingModel::ThreadPerContext);
-
- // add the thread model handler
- viewer->addEventHandler(new osgViewer::ThreadingHandler);
-
- // add the window size toggle handler
- viewer->addEventHandler(new osgViewer::WindowSizeHandler);
-
- // add the stats handler
- viewer->addEventHandler(new osgViewer::StatsHandler);
-
- // add the LOD Scale handler
- viewer->addEventHandler(new osgViewer::LODScaleHandler);
-
- VGEDatabasePager* databasePager = new VGEDatabasePager;
- databasePager->resume();
- viewer->getScene()->setDatabasePager(databasePager);
- std::vector normals;
- std::vector points;
-
- GDALAllRegister();
- //read in a point set from a shapefile. These points were interactively collected in the 3D city model using the PointPicker tool.
- ShapeFile shp("./data/street_points.shp");
- OGRFeature *poFeature;
- shp.poLayer->ResetReading();
- int pointid = 0;
- //write out SVF results
- ofstream ofssvf;
- ofssvf.open("./street_points_svf.txt");
-
- while ((poFeature = shp.poLayer->GetNextFeature()) != NULL)
- {
-
- OGRPoint* ogrp = (OGRPoint*)poFeature->GetGeometryRef();
- double x = poFeature->GetFieldAsDouble("x");
- double y = poFeature->GetFieldAsDouble("y");
- double z = poFeature->GetFieldAsDouble("z");
- double nx = poFeature->GetFieldAsDouble("nx");
- double ny = poFeature->GetFieldAsDouble("ny");
- double nz = poFeature->GetFieldAsDouble("nz");
-
- osg::Vec3d pos(x, y, z);
- osg::Vec3d normal(nx, ny, nz);
- normals.push_back(normal);
- points.push_back(pos);
- OGRFeature::DestroyFeature(poFeature);
- viewer->setCameraManipulator(NULL, false);
- VGEDatabasePager* databasePager = (VGEDatabasePager*)viewer->getDatabasePager();
- databasePager->pause();
-
- osg::Vec3d observer = pos;
- osg::Vec3d observerNormal = normal;
- observer = observer + observerNormal * 2.5;//distance of camera from the surface
- for (size_t i = 0; i < cubemapCameras->getNumChildren(); i++)
- {
- CameraBuffer* cameraBuffer = (CameraBuffer*)cubemapCameras->getChild(i);
- cameraBuffer->_pos = observer;
- }
- cubemapCameras->setNodeMask(true);
- viewer->frame();
- databasePager->frame();
- while (databasePager->getFileRequestListSize() > 0)
- {
- viewer->frame();
- databasePager->frame();
- }
- viewer->frame();
-
- cubemapCameras->setNodeMask(false);
- databasePager->resume();
- viewer->setCameraManipulator(manip.get(), false);
-
- double svf = SVFComputeTools::calSVF(cubemap2fisheyeCamera->_image, false);
- printf("%f\n", svf);
- ofssvf << svf << std::endl;
-
- //std::stringstream ssFile;
- //ssFile << "svf_" << pointid << ".png";
- //write out fisheye image
- //osgDB::writeImageFile(*cubemap2fisheyeCamera->image, ssFile.str());
-
- printf("SVF=%f\n", svf);
- std::stringstream ss;
- ss << std::setprecision(3) << "SVF = " << svf;
- text->setText(ss.str());
-
- pointid++;
- }
- ofssvf.close();
-
- return 0;
-}
-
-
-
diff --git a/Example2/ReadMe.txt b/Example2/ReadMe.txt
deleted file mode 100644
index 1766c03..0000000
--- a/Example2/ReadMe.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-(1) Toggle Full Screen: F key
-(2) Reset camera: Control key
-(3) Rotate: Mouse left button + drag
-(4) Zoom: Mouse right button + drag or Mouse scroll
-(5) Exit: Esc key
-(6) "./data/street_points.shp" was created using the PointPicker tool.
\ No newline at end of file
diff --git a/Example3/Example3.vcxproj b/Example3/Example3.vcxproj
deleted file mode 100644
index d5ee5ca..0000000
--- a/Example3/Example3.vcxproj
+++ /dev/null
@@ -1,167 +0,0 @@
-
-
-
-
- Debug
- Win32
-
-
- Release
- Win32
-
-
- Debug
- x64
-
-
- Release
- x64
-
-
-
- {0AE29B44-19FD-4A3E-AC27-93AB06AE12AB}
- Win32Proj
- Registration
- 8.1
- Example3
-
-
-
- Application
- true
- v140
- Unicode
-
-
- Application
- false
- v140
- true
- Unicode
-
-
- Application
- true
- v140
- Unicode
-
-
- Application
- false
- v140
- true
- Unicode
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
- true
- $(SolutionDir)\bin\
-
-
- false
-
-
- false
- $(SolutionDir)\bin\
-
-
-
-
-
- Level3
- Disabled
- WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
-
-
- Console
- true
-
-
-
-
-
-
- Level3
- Disabled
- _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
- $(SolutionDir)\include;..\SVFEngine
-
-
- Console
- true
- osgEarthd.lib;osgEarthFeaturesd.lib;osgEarthUtild.lib;osgEarthQtd.lib;osgEarthSymbologyd.lib;osgEarthAnnotationd.lib;OpenThreadsd.lib;osgd.lib;osgDBd.lib;osgUtild.lib;osgViewerd.lib;osgWidgetd.lib;osgSimd.lib;osgTextd.lib;osgGAd.lib;osgShadowd.lib;osgManipulatord.lib;gdal_i.lib
- $(SolutionDir)\lib\$(Platform)\
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
-
-
- Console
- true
- true
- true
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
- $(SolutionDir)\include;..\SVFEngine
-
-
- Console
- true
- true
- true
- $(SolutionDir)\lib\$(Platform)\
- osgEarth.lib;osgEarthFeatures.lib;osgEarthUtil.lib;osgEarthSymbology.lib;osgEarthAnnotation.lib;osgEarthQt.lib;osg.lib;osgDB.lib;osgUtil.lib;osgViewer.lib;OpenThreads.lib;osgSim.lib;osgTerrain.lib;osgFX.lib;osgShadow.lib;osgManipulator.lib;osgText.lib;osgGA.lib;gdal_i.lib;%(AdditionalDependencies)
-
-
-
-
-
-
-
-
-
-
- {f8df3492-a941-4a6d-860e-19c63fa93da5}
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Example3/Example3.vcxproj.filters b/Example3/Example3.vcxproj.filters
deleted file mode 100644
index 31e103f..0000000
--- a/Example3/Example3.vcxproj.filters
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
- {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
- cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
-
-
- {93995380-89BD-4b04-88EB-625FBE52EBFB}
- h;hh;hpp;hxx;hm;inl;inc;xsd
-
-
- {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
- rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
-
-
-
-
-
-
-
- Source Files
-
-
-
\ No newline at end of file
diff --git a/Example3/Example3.vcxproj.user b/Example3/Example3.vcxproj.user
deleted file mode 100644
index d7d1f96..0000000
--- a/Example3/Example3.vcxproj.user
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- $(SolutionDir)\bin
- WindowsLocalDebugger
-
-
- $(SolutionDir)\bin
- WindowsLocalDebugger
-
-
\ No newline at end of file
diff --git a/Example3/Main.cpp b/Example3/Main.cpp
deleted file mode 100644
index bedc913..0000000
--- a/Example3/Main.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-
-#ifdef _WIN32 || WIN32
-#include
-#endif
-#include "SVFDatabasePager.h"
-#include "SVFComputeTools.h"
-#include "ShapeFile.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-using namespace osgEarth;
-using namespace osgEarth::Drivers;
-using namespace osgEarth::Features;
-using namespace osgEarth::Symbology;
-using namespace osgEarth::Util;
-
-#define ELEVATION_URL "http://readymap.org/readymap/tiles/1.0.0/9/"
-#define BUILDINGS_URL "./data/boston_buildings_utm19.shp"
-#define RESOURCE_LIB_URL "./data/resources/textures_us/catalog.xml"
-#define STREETS_URL "./data/boston-scl-utm19n-meters.shp"
-#define PARKS_URL "./data/boston-parks.shp"
-#define TREE_MODEL_URL "./data/loopix/tree4.osgb"
-
-// forward declarations.
-void addImagery(Map* map);
-void addElevation(Map* map);
-void addBuildings(Map* map);
-void addStreets(Map* map);
-void addParks(Map* map);
-
-osgEarth::ProfileOptions ProfileOptionsFromFile(std::string filename)
-{
- osgEarth::ProfileOptions opt;
- if (filename.substr(filename.length() - 4, 4) == ".shp")
- {
- char srs[512];
- memset(srs, 0, 512);
- char* psrs = (char*)srs;
- ShapeFile shp(filename);
- shp.poLayer->GetSpatialRef()->exportToWkt(&psrs);
- opt.srsString() = psrs;
- OGREnvelope env;
- shp.poLayer->GetExtent(&env);
- opt.bounds() = osgEarth::Bounds(env.MinX, env.MinY, env.MaxX, env.MaxY);
- }
- else
- {
- double adfGeoTransform[6];
- GDALDataset* pDataset = (GDALDataset*)GDALOpen(filename.data(), GA_ReadOnly);
- pDataset->GetGeoTransform(adfGeoTransform);
- int ncols = pDataset->GetRasterXSize();
- int nrows = pDataset->GetRasterYSize();
- opt.bounds() = osgEarth::Bounds(adfGeoTransform[0], adfGeoTransform[3] + adfGeoTransform[5] * nrows, adfGeoTransform[3], adfGeoTransform[0] + adfGeoTransform[1] * ncols);
- opt.srsString() = pDataset->GetProjectionRef();
- }
- return opt;
-}
-
-
-void addImagery(Map* map)
-{
- //use readymap imagery
- //TMSOptions imagery;
- //imagery.url() = "http://readymap.org/readymap/tiles/1.0.0/9/";
- //map->addImageLayer(new ImageLayer("TMS imagery", imagery));
-
- //use ArcGIS imagery
- ArcGISOptions arcGISLayer;
- arcGISLayer.url() = "http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer";
- map->addImageLayer( new ImageLayer("ArcGIS", arcGISLayer) );
-}
-
-
-void addElevation(Map* map)
-{
- // add a TMS elevation layer:
- TMSOptions elevation;
- elevation.url() = ELEVATION_URL;
- map->addElevationLayer(new ElevationLayer("ReadyMap elevation", elevation));
-}
-
-//extrude building footprint polygons into 3D models
-void addBuildings(Map* map)
-{
- // create a feature source to load the building footprint shapefile.
- OGRFeatureOptions feature_opt;
- feature_opt.name() = "buildings";
- feature_opt.url() = BUILDINGS_URL;
- feature_opt.buildSpatialIndex() = true;
-
- // a style for the building data:
- Style buildingStyle;
- buildingStyle.setName("buildings");
-
- // Extrude the shapes into 3D buildings.
- ExtrusionSymbol* extrusion = buildingStyle.getOrCreate();
- extrusion->heightExpression() = NumericExpression("3.5 * max( [story_ht_], 1 )");
- extrusion->flatten() = true;
- extrusion->wallStyleName() = "building-wall";
- extrusion->roofStyleName() = "building-roof";
-
- PolygonSymbol* poly = buildingStyle.getOrCreate();
- poly->fill()->color() = Color::White;
-
- // Clamp the buildings to the terrain.
- AltitudeSymbol* alt = buildingStyle.getOrCreate();
- alt->clamping() = alt->CLAMP_TO_TERRAIN;
- alt->binding() = alt->BINDING_VERTEX;
-
- // a style for the wall textures:
- Style wallStyle;
- wallStyle.setName("building-wall");
- SkinSymbol* wallSkin = wallStyle.getOrCreate();
- wallSkin->library() = "us_resources";
- wallSkin->addTag("building");
- wallSkin->randomSeed() = 1;
-
- // a style for the rooftop textures:
- Style roofStyle;
- roofStyle.setName("building-roof");
- SkinSymbol* roofSkin = roofStyle.getOrCreate();
- roofSkin->library() = "us_resources";
- roofSkin->addTag("rooftop");
- roofSkin->randomSeed() = 1;
- roofSkin->isTiled() = true;
-
- // assemble a stylesheet and add our styles to it:
- StyleSheet* styleSheet = new StyleSheet();
- styleSheet->addStyle(buildingStyle);
- styleSheet->addStyle(wallStyle);
- styleSheet->addStyle(roofStyle);
-
- // load a resource library that contains the building textures.
- ResourceLibrary* reslib = new ResourceLibrary("us_resources", RESOURCE_LIB_URL);
- styleSheet->addResourceLibrary(reslib);
-
- // set up a paging layout for incremental loading. The tile size factor and
- // the visibility range combine to determine the tile size, such that
- // tile radius = max range / tile size factor.
- FeatureDisplayLayout layout;
- layout.tileSizeFactor() = 52.0;
- layout.addLevel(FeatureLevel(0.0f, 20000.0f, "buildings"));
-
- // create a model layer that will render the buildings according to our style sheet.
- FeatureGeomModelOptions fgm_opt;
- fgm_opt.featureOptions() = feature_opt;
- fgm_opt.styles() = styleSheet;
- fgm_opt.layout() = layout;
-
- map->addModelLayer(new ModelLayer("buildings", fgm_opt));
-}
-
-
-void addStreets(Map* map)
-{
- // create a feature source to load the street shapefile.
- OGRFeatureOptions feature_opt;
- feature_opt.name() = "streets";
- feature_opt.url() = STREETS_URL;
- feature_opt.buildSpatialIndex() = true;
-
- // a resampling filter will ensure that the length of each segment falls
- // within the specified range. That can be helpful to avoid cropping
- // very long lines segments.
- feature_opt.filters().push_back(new ResampleFilter(0.0, 25.0));
-
- // a style:
- Style style;
- style.setName("streets");
-
- // Render the data as translucent yellow lines that are 7.5m wide.
- LineSymbol* line = style.getOrCreate();
- line->stroke()->color() = Color(Color::Yellow, 0.5f);
- line->stroke()->width() = 7.5f;
- line->stroke()->widthUnits() = Units::METERS;
-
- // Clamp the lines to the terrain.
- AltitudeSymbol* alt = style.getOrCreate();
- alt->clamping() = alt->CLAMP_TO_TERRAIN;
-
- // Apply a depth offset to avoid z-fighting. The "min bias" is the minimum
- // apparent offset (towards the camera) of the geometry from its actual position.
- // The value here was chosen empirically by tweaking the "oe_doff_min_bias" uniform.
- RenderSymbol* render = style.getOrCreate();
- render->depthOffset()->minBias() = 6.6f;
-
- // Set up a paging layout. The tile size factor and the visibility range combine
- // to determine the tile size, such that tile radius = max range / tile size factor.
- FeatureDisplayLayout layout;
- layout.tileSizeFactor() = 7.5f;
- layout.maxRange() = 5000.0f;
-
- // create a model layer that will render the buildings according to our style sheet.
- FeatureGeomModelOptions fgm_opt;
- fgm_opt.featureOptions() = feature_opt;
- fgm_opt.layout() = layout;
- fgm_opt.styles() = new StyleSheet();
- fgm_opt.styles()->addStyle(style);
-
- map->addModelLayer(new ModelLayer("streets", fgm_opt));
-}
-
-
-void addParks(Map* map)
-{
- // create a feature source to load the shapefile.
- OGRFeatureOptions feature_opt;
- feature_opt.name() = "parks";
- feature_opt.url() = PARKS_URL;
- feature_opt.buildSpatialIndex() = true;
-
- // a style:
- Style style;
- style.setName("parks");
-
- // Render the data using point-model substitution, which replaces each point
- // in the feature geometry with an instance of a 3D model. Since the input
- // data are polygons, the PLACEMENT_RANDOM directive below will scatter
- // points within the polygon boundary at the specified density.
- ModelSymbol* model = style.getOrCreate();
- model->url()->setLiteral(TREE_MODEL_URL);
- model->scale()->setLiteral(0.2);
- model->placement() = model->PLACEMENT_RANDOM;
- model->density() = 3000.0f; // instances per sqkm
-
- // Clamp to the terrain:
- AltitudeSymbol* alt = style.getOrCreate();
- alt->clamping() = alt->CLAMP_TO_TERRAIN;
-
- // Since the tree model contains alpha components, we will discard any data
- // that's sufficiently transparent; this will prevent depth-sorting anomolies
- // common when rendering lots of semi-transparent objects.
- RenderSymbol* render = style.getOrCreate();
- render->minAlpha() = 0.15f;
-
- // Set up a paging layout. The tile size factor and the visibility range combine
- // to determine the tile size, such that tile radius = max range / tile size factor.
- FeatureDisplayLayout layout;
- layout.tileSizeFactor() = 3.0f;
- layout.maxRange() = 10000.0f;
-
- // create a model layer that will render the buildings according to our style sheet.
- FeatureGeomModelOptions fgm_opt;
- fgm_opt.featureOptions() = feature_opt;
- fgm_opt.layout() = layout;
- fgm_opt.styles() = new StyleSheet();
- fgm_opt.styles()->addStyle(style);
- fgm_opt.compilerOptions().instancing() = true;
-
- map->addModelLayer(new ModelLayer("parks", fgm_opt));
-}
-
-int main(int argc, char** argv)
-{
- osg::ArgumentParser arguments(&argc, argv);
- osgViewer::Viewer* viewer = new osgViewer::Viewer(arguments);
- viewer->setUpViewAcrossAllScreens();
- GDALAllRegister();
-
- ProfileOptions profileOpt = ProfileOptionsFromFile(PARKS_URL);
- MapOptions mapOpt;
- mapOpt.coordSysType() = MapOptions::CSTYPE_PROJECTED;
- mapOpt.profile() = profileOpt;
-
- //cache map tiles
- FileSystemCacheOptions cacheOpt;
- cacheOpt.rootPath() = "./cache";
- mapOpt.cache() = cacheOpt;
- mapOpt.cachePolicy() = osgEarth::CachePolicy::USAGE_READ_WRITE;
- Map* map = new Map(mapOpt);
-
- addImagery(map);
- addElevation(map);
- addStreets(map);
- addBuildings(map);
- addParks(map);
-
- osg::ref_ptr manip = new EarthManipulator;
- viewer->setCameraManipulator(manip.get());
-
- osg::ref_ptr root = new osg::Group();
- viewer->setSceneData(root.get());
- // make the map scene graph:
- MapNode* mapNode = new MapNode(map);
- root->addChild(mapNode);
-
- // zoom to a good startup position
- manip->setViewpoint(Viewpoint(
- "Home",
- -71.0763, 42.34425, 0, // longitude, latitude, altitude
- 24.261, -21.6, 3450.0), // heading, pitch, range
- 5.0); // duration
-
- viewer->addEventHandler(new SkyViewFactorEventHandler(mapNode, root, manip, viewer));
-
- viewer->addEventHandler(new osgViewer::ThreadingHandler);
-
- // add the window size toggle handler
- viewer->addEventHandler(new osgViewer::WindowSizeHandler);
-
- // add the stats handler
- viewer->addEventHandler(new osgViewer::StatsHandler);
-
- // add the LOD Scale handler
- viewer->addEventHandler(new osgViewer::LODScaleHandler);
- return viewer->run();
-}
diff --git a/Example3/ReadMe.txt b/Example3/ReadMe.txt
deleted file mode 100644
index 18aabdb..0000000
--- a/Example3/ReadMe.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-(1) Toggle Full Screen: F key
-(2) Reset camera: Control key
-(3) Rotate: Mouse left button + drag
-(4) Zoom: Mouse right button + drag or Mouse scroll
-(5) Exit: Esc key
-(6) Calculate SVF at a position: Ctrl + mouse click
\ No newline at end of file
diff --git a/PointPicker/PointPicker.cpp b/PointPicker/PointPicker.cpp
deleted file mode 100644
index bb6d565..0000000
--- a/PointPicker/PointPicker.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-#include "PointPicker.h"
-#include "osgUtil/Tessellator"
-#include "osgDB/WriteFile"
-#include "osg/LineWidth"
-#include
-#include
-#include
-#include
-#include
-#include
-#include "ogrsf_frmts.h"
-#include "ShapeFile.h"
-PointPicker::PointPicker()
-{
- OGRRegisterAll();
- osg::ref_ptr program = new osg::Program;
-
- char vertexShaderSource[] =
- "void main(void)\n"
- "{\n"
- " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
- "}\n";
- char fragmentShaderSource[] =
- "void main(void) \n"
- "{\n"
- " gl_FragColor = vec4(1,0,0,1);\n"
- "}\n";
-
- program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
- program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
- g_pPointGeode = new osg::Geode;
- osg::StateSet* ss = g_pPointGeode->getOrCreateStateSet();
-
- ss->setAttribute(program.get(),osg::StateAttribute::ON |osg::StateAttribute::OVERRIDE);
-
- g_pPointGeode->setCullingActive(false);
- osg::ref_ptr point = new osg::Point(5.0);
- //point->setDistanceAttenuation(osg::Vec3(0.0, 0.0000, 0.05f));
- ss->setAttribute(point.get());
-
-}
-PointPicker::~PointPicker(void)
-{
-
-}
-bool PointPicker::loadFromShapeFile(std::string filename)
-{
- OGRRegisterAll();
- g_mNormals.clear();
- g_mPoints.clear();
- ShapeFile shp(filename);
- if (!shp.poDS)
- return false;
- OGRFeature *poFeature;
- shp.poLayer->ResetReading();
- int pointid = 0;
- while ((poFeature = shp.poLayer->GetNextFeature()) != NULL)
- {
-
- OGRPoint* ogrp = (OGRPoint*)poFeature->GetGeometryRef();
- double x = poFeature->GetFieldAsDouble("x");
- double y = poFeature->GetFieldAsDouble("y");
- double z = poFeature->GetFieldAsDouble("z");
- double nx = poFeature->GetFieldAsDouble("nx");
- double ny = poFeature->GetFieldAsDouble("ny");
- double nz = poFeature->GetFieldAsDouble("nz");
-
- osg::Vec3d pos(x, y, z);
- osg::Vec3d normal(nx, ny, nz);
- g_mNormals.push_back(normal);
- g_mPoints.push_back(pos);
- OGRFeature::DestroyFeature(poFeature);
-
- }
- updateGeometry();
- return true;
-
-}
-bool PointPicker::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
-{
-
- if(ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton() == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON)
- {
- osgViewer::View* view = dynamic_cast(&aa);
- if( !view)
- return false;
- osgUtil::LineSegmentIntersector::Intersections intersections;
-
- if(view->computeIntersections(ea,intersections))
- {
- osg::Vec3d pos = intersections.begin()->getWorldIntersectPoint();
- osg::Vec3d normal = intersections.begin()->getWorldIntersectNormal();
- normal.normalize();
- pos = pos + normal * 0.01;
-
- printf("%f,%f,%f\n", pos.x(), pos.y(), pos.z());
- //pos.z() = g_mBound.zMin();
- g_mNormals.push_back(normal);
- g_mPoints.push_back(pos);
- updateGeometry();
-
- }
- }
- else if(ea.getKey() == osgGA::GUIEventAdapter::KEY_Delete && ea.getEventType() == osgGA::GUIEventAdapter::KEYUP)
- {
- if(g_mPoints.size()>0)
- {
- g_mPoints.erase(--g_mPoints.end());
- g_mNormals.erase(--g_mNormals.end());
- updateGeometry();
- }
- }
- else if(ea.getKey() == osgGA::GUIEventAdapter::KEY_B && ea.getEventType() == osgGA::GUIEventAdapter::KEYUP)
- {
- ShapeFile shp;
- shp.create(m_filename.data());
-
- OGRFeatureDefn *poFDefn = shp.poLayer->GetLayerDefn();
-
-
- OGRFieldDefn defx("x", OGRFieldType::OFTReal);
- shp.poLayer->CreateField(&defx);
- int x = shp.poLayer->GetLayerDefn()->GetFieldIndex("x");
-
- OGRFieldDefn defy("y", OGRFieldType::OFTReal);
- shp.poLayer->CreateField(&defy);
- int y = shp.poLayer->GetLayerDefn()->GetFieldIndex("y");
-
- OGRFieldDefn defz("z", OGRFieldType::OFTReal);
- shp.poLayer->CreateField(&defz);
- int z = shp.poLayer->GetLayerDefn()->GetFieldIndex("z");
-
-
- OGRFieldDefn defnx("nx", OGRFieldType::OFTReal);
- shp.poLayer->CreateField(&defnx);
- int nx = shp.poLayer->GetLayerDefn()->GetFieldIndex("nx");
-
- OGRFieldDefn defny("ny", OGRFieldType::OFTReal);
- shp.poLayer->CreateField(&defny);
- int ny = shp.poLayer->GetLayerDefn()->GetFieldIndex("ny");
-
- OGRFieldDefn defnz("nz", OGRFieldType::OFTReal);
- shp.poLayer->CreateField(&defnz);
- int nz = shp.poLayer->GetLayerDefn()->GetFieldIndex("nz");
-
-
- for (size_t i = 0; i < g_mPoints.size(); i++)
- {
-
- osg::Vec3d p = g_mPoints[i];
- osg::Vec3d n = g_mNormals[i];
- OGRPoint po;
- po.setX(p.x());
- po.setY(p.y());
- OGRFeature* poFeaPoint = OGRFeature::CreateFeature(shp.poLayer->GetLayerDefn());
- poFeaPoint->SetGeometry(&po);
- poFeaPoint->SetField(x, p.x());
- poFeaPoint->SetField(y, p.y());
- poFeaPoint->SetField(z, p.z());
-
- poFeaPoint->SetField(nx, n.x());
- poFeaPoint->SetField(ny, n.y());
- poFeaPoint->SetField(nz, n.z());
-
- shp.poLayer->CreateFeature(poFeaPoint);
- OGRFeature::DestroyFeature(poFeaPoint);
- }
-
- }
-
- return false;
-}
-void PointPicker::updateGeometry()
-{
- g_pPointGeode->removeDrawables(0,g_pPointGeode->getNumDrawables());
-
- osg::ref_ptr vertices = new osg::Vec3Array;
- osg::ref_ptr polyGeom = new osg::Geometry();
- for(std::vector::iterator iter = g_mPoints.begin(); iter != g_mPoints.end(); ++iter)
- {
- vertices->push_back(*iter);
- }
- polyGeom->setVertexArray(vertices.get());
- polyGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS,0,vertices->size()));
- g_pPointGeode->addDrawable(polyGeom.get());
-
-}
-
diff --git a/PointPicker/PointPicker.h b/PointPicker/PointPicker.h
deleted file mode 100644
index 304dd91..0000000
--- a/PointPicker/PointPicker.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-#include
-#include
-#include
-#include "osg/Texture2D"
-#include "osg/Image"
-
-class PointPicker : public osgGA::GUIEventHandler
-{
-public:
- PointPicker(void);
- ~PointPicker(void);
- osg::ref_ptr PointGeode() { return g_pPointGeode; }
- std::string m_filename;
- bool loadFromShapeFile(std::string filename);
-protected:
- bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa);
- void updateGeometry();
-protected:
- std::vector g_mPoints;
- std::vector g_mNormals;
- osg::ref_ptr g_pPointGeode;
-
-};
-
diff --git a/PointPicker/PointPicker.vcxproj b/PointPicker/PointPicker.vcxproj
deleted file mode 100644
index 4c09ad4..0000000
--- a/PointPicker/PointPicker.vcxproj
+++ /dev/null
@@ -1,176 +0,0 @@
-
-
-
-
- Debug
- Win32
-
-
- Release
- Win32
-
-
- Debug
- x64
-
-
- Release
- x64
-
-
-
- {D6E2F799-0F77-4E8E-8B62-E8B51E1EAA0C}
- Win32Proj
- GridPolygonIntersection
- 8.1
- PointPicker
-
-
-
- Application
- true
- v140
- Unicode
-
-
- Application
- false
- v140
- true
- Unicode
-
-
- Application
- true
- v140
- Unicode
-
-
- Application
- false
- v140
- true
- Unicode
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
- true
- $(SolutionDir)\bin\
-
-
- false
-
-
- false
- $(SolutionDir)\bin\
-
-
-
-
-
- Level3
- Disabled
- WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
-
-
- Console
- true
-
-
-
-
-
-
- Level3
- Disabled
- _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
- $(SolutionDir)\include;..\SVFEngine
-
-
- Console
- true
- SVFEngine.lib;osgEarthd.lib;osgEarthFeaturesd.lib;osgEarthUtild.lib;osgEarthQtd.lib;osgEarthSymbologyd.lib;osgEarthAnnotationd.lib;OpenThreadsd.lib;osgd.lib;osgDBd.lib;osgUtild.lib;osgViewerd.lib;osgWidgetd.lib;osgSimd.lib;osgTextd.lib;osgGAd.lib;osgShadowd.lib;osgManipulatord.lib;gdal_i.lib
- $(SolutionDir)\lib\$(Platform)\
- $(SolutionDir)\bin\$(TargetName)$(TargetExt)
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
-
-
- Console
- true
- true
- true
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
- $(SolutionDir)\include;..\SVFEngine
-
-
- Console
- true
- true
- true
- $(SolutionDir)\lib\$(Platform)\
- osgEarth.lib;osgEarthFeatures.lib;osgEarthUtil.lib;osgEarthSymbology.lib;osgEarthAnnotation.lib;osgEarthQt.lib;osg.lib;osgDB.lib;osgUtil.lib;osgViewer.lib;OpenThreads.lib;osgSim.lib;osgTerrain.lib;osgFX.lib;osgShadow.lib;osgManipulator.lib;osgText.lib;osgGA.lib;gdal_i.lib;%(AdditionalDependencies)
- $(SolutionDir)\bin\$(TargetName)$(TargetExt)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {f8df3492-a941-4a6d-860e-19c63fa93da5}
-
-
-
-
-
-
\ No newline at end of file
diff --git a/PointPicker/PointPicker.vcxproj.filters b/PointPicker/PointPicker.vcxproj.filters
deleted file mode 100644
index 2c84276..0000000
--- a/PointPicker/PointPicker.vcxproj.filters
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
- {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
- cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
-
-
- {93995380-89BD-4b04-88EB-625FBE52EBFB}
- h;hh;hpp;hxx;hm;inl;inc;xsd
-
-
- {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
- rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
-
-
-
-
-
-
-
- Header Files
-
-
- Header Files
-
-
- Header Files
-
-
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
-
\ No newline at end of file
diff --git a/PointPicker/PointPicker.vcxproj.user b/PointPicker/PointPicker.vcxproj.user
deleted file mode 100644
index d0a2bac..0000000
--- a/PointPicker/PointPicker.vcxproj.user
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
- WindowsLocalDebugger
- $(SolutionDir)\bin
-
-
- $(SolutionDir)\bin
- WindowsLocalDebugger
-
-
-
-
\ No newline at end of file
diff --git a/PointPicker/ReadMe.txt b/PointPicker/ReadMe.txt
deleted file mode 100644
index 54ccb88..0000000
--- a/PointPicker/ReadMe.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-#This tool was designed for collecting points from a 3D city model (for example data/models/OAP3D/OAP3D.osgb or data/models/CAD/CAD.osg)
-
-#arguments:
-(1) path of a 3D model file
-(2) path of a Shapefile to create or update
-(3) base height of groud plane to create (optional)
-
-#how to use the tool:
-(1) mouse right click to add a point
-(2) press key DELETE to delete the last point
-(3) press key B to update the Shapefile (remember to do this regularly, since results will not be saved in case of abnormal termination)
-
-#how to view the results:
-(1) change the variables (3D model file and Shapefile) in Example2 and recomplie
\ No newline at end of file
diff --git a/PointPicker/main.cpp b/PointPicker/main.cpp
deleted file mode 100644
index 320981a..0000000
--- a/PointPicker/main.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-
-#ifdef _WIN32 || WIN32
-#include
-#endif
-#include "osgDB/WriteFile"
-#include "osgDB/WriteFile"
-#include "osg/ComputeBoundsVisitor"
-#include "osgGA/StateSetManipulator"
-#include "osgViewer/ViewerEventHandlers"
-#include "osgUtil/Optimizer"
-#include "osg/MatrixTransform"
-#include "osgGA/TrackballManipulator"
-#include "osg/Texture2D"
-#include "osg/Image"
-#include "osgDB/writeFile"
-#include "osgDB/readFile"
-#include "osg/ClampColor"
-#include "osg/Depth"
-#include "osgUtil/SmoothingVisitor"
-#include "PointPicker.h"
-#include
-#include "ShapeFile.h"
-using namespace OpenThreads;
-
-//create a ground plane in case a 3D city scene does not come with one
-osg::Node* createRect(osg::BoundingBox bb, double baseHeight)
-{
- osg::ref_ptr geode = new osg::Geode;
- osg::ref_ptr program = new osg::Program;
-
- char vertexShaderSource[] =
- "void main(void)\n"
- "{\n"
- " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
- "}\n";
- char fragmentShaderSource[] =
- "void main(void) \n"
- "{\n"
- " gl_FragColor = vec4(0.5,0.5,0.5,1);\n"
- "}\n";
-
- program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
- program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
- osg::StateSet* ss = geode->getOrCreateStateSet();
-
- ss->setAttribute(program.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
-
- geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0, 0, 0), 1)));
-
- osg::MatrixTransform* mat = new osg::MatrixTransform;
- mat->setMatrix(
- osg::Matrix::scale(bb.xMax() - bb.xMin(), bb.yMax() - bb.yMin(), 0.00001)
- * osg::Matrix::translate(bb.center()));
- mat->addChild(geode.get());
- return mat;
-}
-
-int main(int argc, char** argv)
-{
-
- osg::ArgumentParser arguments(&argc, argv);
- osgViewer::Viewer viewer;
- //viewer.getScene()->setDatabasePager()
- // add the state manipulator
- viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
-
- // add the thread model handler
- viewer.addEventHandler(new osgViewer::ThreadingHandler);
-
- // add the window size toggle handler
- viewer.addEventHandler(new osgViewer::WindowSizeHandler);
-
- // add the stats handler
- viewer.addEventHandler(new osgViewer::StatsHandler);
- PointPicker* pointPicker = new PointPicker;
- viewer.addEventHandler(pointPicker);
- osg::ref_ptr root = new osg::Group;
-
- std::string infile = argv[1];
- std::string inshpfile = argv[2];
-
- if (pointPicker->loadFromShapeFile(inshpfile.data())) {
- printf("file exists: %s\n", inshpfile.data());
- }
- pointPicker->m_filename = inshpfile;
- printf("%s\n", inshpfile.data());
- osg::ref_ptr node;
- if (argc > 3)
- {
- double baseHeight = atof(argv[3]);
- osg::BoundingBox bb;
- std::string bbfile = infile + ".bb";
-
- node = osgDB::readNodeFile(infile);
- osg::ComputeBoundsVisitor cbv;
- node->accept(cbv);
- bb = cbv.getBoundingBox();
-
- bb.zMin() = bb.zMax() = baseHeight;
- osg::ref_ptr ground = createRect(bb, baseHeight);
- root->addChild(ground.get());
- }
- if(!node.valid())
- node = osgDB::readNodeFile(infile);
-
- if (!node || !node.valid())
- {
- return 1;
- }
-
-
- root->addChild(node.get());
-
-
- root->addChild(pointPicker->PointGeode().get());
- viewer.setSceneData(root.get());
-
- viewer.run();
- exit(0);
- return 0;
-}
diff --git a/PointPicker/stdafx.cpp b/PointPicker/stdafx.cpp
deleted file mode 100644
index a08c42a..0000000
--- a/PointPicker/stdafx.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-// stdafx.cpp : source file that includes just the standard includes
-// GridPolygonIntersection.pch will be the pre-compiled header
-// stdafx.obj will contain the pre-compiled type information
-
-#include "stdafx.h"
-
-// TODO: reference any additional headers you need in STDAFX.H
-// and not in this file
diff --git a/PointPicker/stdafx.h b/PointPicker/stdafx.h
deleted file mode 100644
index b005a83..0000000
--- a/PointPicker/stdafx.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// stdafx.h : include file for standard system include files,
-// or project specific include files that are used frequently, but
-// are changed infrequently
-//
-
-#pragma once
-
-#include "targetver.h"
-
-#include
-#include
-
-
-
-// TODO: reference additional headers your program requires here
diff --git a/PointPicker/targetver.h b/PointPicker/targetver.h
deleted file mode 100644
index 87c0086..0000000
--- a/PointPicker/targetver.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#pragma once
-
-// Including SDKDDKVer.h defines the highest available Windows platform.
-
-// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
-// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
-
-#include
diff --git a/README.md b/README.md
index ee3497d..5b3eaac 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,11 @@
-# SVFEngine
+# SolarEngine
## 1.Publication
- https://doi.org/10.1016/j.enbuild.2017.05.024
- http://www.sciencedirect.com/science/article/pii/S0378778816317030
- Liang, J., Gong, J., Sun, J., & Liu, J. (2017). A customizable framework for computing sky view factor from large-scale 3D city models. Energy and Buildings, 149, 38-44.
- Abstract
-A common approach to derive the sky view factor (SVF) in an urban environment is to combine urban morphological modeling and computational geometry techniques. Computational methods and tools have been developed to derive SVF from digital surface models (DSMs) and small-scale three dimensional (3D) city models, but they are not well suited for accommodating large-scale 3D city models. In this paper, we present a computational framework (SVFEngine) for deriving SVF from a wide variety of 3D city models, including the recently developed oblique airborne photogrammetry-based 3D city model (OAP3D), which is a highly detailed representation of an urban environment. We compared the SVF estimates computed from a large-scale high-resolution OAP3D with those from a set of street view panoramas at 30 locations. The comparison shows that the SVF estimates obtained using both methods closely match each other with a correlation coefficient of 0.99. The result suggests that high-resolution 3D city models have the potential for deriving accurate SVF estimates. Several examples are presented to show how SVFEngine can be applied in urban environmental modeling and analysis. The source code of SVFEngine is freely available (https://github.com/ljm355/SVFEngine) so it can be fully integrated into a user-defined workflow.
+A common approach to derive the sky view factor (SVF) in an urban environment is to combine urban morphological modeling and computational geometry techniques. Computational methods and tools have been developed to derive SVF from digital surface models (DSMs) and small-scale three dimensional (3D) city models, but they are not well suited for accommodating large-scale 3D city models. In this paper, we present a computational framework (SolarEngine) for deriving SVF from a wide variety of 3D city models, including the recently developed oblique airborne photogrammetry-based 3D city model (OAP3D), which is a highly detailed representation of an urban environment. We compared the SVF estimates computed from a large-scale high-resolution OAP3D with those from a set of street view panoramas at 30 locations. The comparison shows that the SVF estimates obtained using both methods closely match each other with a correlation coefficient of 0.99. The result suggests that high-resolution 3D city models have the potential for deriving accurate SVF estimates. Several examples are presented to show how SolarEngine can be applied in urban environmental modeling and analysis. The source code of SolarEngine is freely available (https://github.com/ljm355/SolarEngine) so it can be fully integrated into a user-defined workflow.
## 2.Environment
* (1) Operating System: deveoped and tested under Windows 7 64-bit
diff --git a/SVFEngine.sln b/SVFEngine.sln
deleted file mode 100644
index 5f57a3f..0000000
--- a/SVFEngine.sln
+++ /dev/null
@@ -1,83 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.23107.0
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SVFEngine", "SVFEngine\SVFEngine.vcxproj", "{F8DF3492-A941-4A6D-860E-19C63FA93DA5}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PointPicker", "PointPicker\PointPicker.vcxproj", "{D6E2F799-0F77-4E8E-8B62-E8B51E1EAA0C}"
- ProjectSection(ProjectDependencies) = postProject
- {F8DF3492-A941-4A6D-860E-19C63FA93DA5} = {F8DF3492-A941-4A6D-860E-19C63FA93DA5}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example1", "Example1\Example1.vcxproj", "{D1FFF330-FBDF-46FE-9F0B-649709F29896}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example3", "Example3\Example3.vcxproj", "{0AE29B44-19FD-4A3E-AC27-93AB06AE12AB}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Example2", "Example2\Example2.vcxproj", "{9266A440-9187-41F7-85C7-82DF0E110143}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
- Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
- Release|x86 = Release|x86
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {F8DF3492-A941-4A6D-860E-19C63FA93DA5}.Debug|Any CPU.ActiveCfg = Debug|Win32
- {F8DF3492-A941-4A6D-860E-19C63FA93DA5}.Debug|x64.ActiveCfg = Debug|x64
- {F8DF3492-A941-4A6D-860E-19C63FA93DA5}.Debug|x64.Build.0 = Debug|x64
- {F8DF3492-A941-4A6D-860E-19C63FA93DA5}.Debug|x86.ActiveCfg = Debug|Win32
- {F8DF3492-A941-4A6D-860E-19C63FA93DA5}.Debug|x86.Build.0 = Debug|Win32
- {F8DF3492-A941-4A6D-860E-19C63FA93DA5}.Release|Any CPU.ActiveCfg = Release|Win32
- {F8DF3492-A941-4A6D-860E-19C63FA93DA5}.Release|x64.ActiveCfg = Release|x64
- {F8DF3492-A941-4A6D-860E-19C63FA93DA5}.Release|x64.Build.0 = Release|x64
- {F8DF3492-A941-4A6D-860E-19C63FA93DA5}.Release|x86.ActiveCfg = Release|Win32
- {F8DF3492-A941-4A6D-860E-19C63FA93DA5}.Release|x86.Build.0 = Release|Win32
- {D6E2F799-0F77-4E8E-8B62-E8B51E1EAA0C}.Debug|Any CPU.ActiveCfg = Debug|Win32
- {D6E2F799-0F77-4E8E-8B62-E8B51E1EAA0C}.Debug|x64.ActiveCfg = Debug|x64
- {D6E2F799-0F77-4E8E-8B62-E8B51E1EAA0C}.Debug|x64.Build.0 = Debug|x64
- {D6E2F799-0F77-4E8E-8B62-E8B51E1EAA0C}.Debug|x86.ActiveCfg = Debug|Win32
- {D6E2F799-0F77-4E8E-8B62-E8B51E1EAA0C}.Debug|x86.Build.0 = Debug|Win32
- {D6E2F799-0F77-4E8E-8B62-E8B51E1EAA0C}.Release|Any CPU.ActiveCfg = Release|Win32
- {D6E2F799-0F77-4E8E-8B62-E8B51E1EAA0C}.Release|x64.ActiveCfg = Release|x64
- {D6E2F799-0F77-4E8E-8B62-E8B51E1EAA0C}.Release|x64.Build.0 = Release|x64
- {D6E2F799-0F77-4E8E-8B62-E8B51E1EAA0C}.Release|x86.ActiveCfg = Release|Win32
- {D6E2F799-0F77-4E8E-8B62-E8B51E1EAA0C}.Release|x86.Build.0 = Release|Win32
- {D1FFF330-FBDF-46FE-9F0B-649709F29896}.Debug|Any CPU.ActiveCfg = Debug|Win32
- {D1FFF330-FBDF-46FE-9F0B-649709F29896}.Debug|x64.ActiveCfg = Debug|x64
- {D1FFF330-FBDF-46FE-9F0B-649709F29896}.Debug|x64.Build.0 = Debug|x64
- {D1FFF330-FBDF-46FE-9F0B-649709F29896}.Debug|x86.ActiveCfg = Debug|Win32
- {D1FFF330-FBDF-46FE-9F0B-649709F29896}.Debug|x86.Build.0 = Debug|Win32
- {D1FFF330-FBDF-46FE-9F0B-649709F29896}.Release|Any CPU.ActiveCfg = Release|Win32
- {D1FFF330-FBDF-46FE-9F0B-649709F29896}.Release|x64.ActiveCfg = Release|x64
- {D1FFF330-FBDF-46FE-9F0B-649709F29896}.Release|x64.Build.0 = Release|x64
- {D1FFF330-FBDF-46FE-9F0B-649709F29896}.Release|x86.ActiveCfg = Release|Win32
- {D1FFF330-FBDF-46FE-9F0B-649709F29896}.Release|x86.Build.0 = Release|Win32
- {0AE29B44-19FD-4A3E-AC27-93AB06AE12AB}.Debug|Any CPU.ActiveCfg = Debug|Win32
- {0AE29B44-19FD-4A3E-AC27-93AB06AE12AB}.Debug|x64.ActiveCfg = Debug|x64
- {0AE29B44-19FD-4A3E-AC27-93AB06AE12AB}.Debug|x64.Build.0 = Debug|x64
- {0AE29B44-19FD-4A3E-AC27-93AB06AE12AB}.Debug|x86.ActiveCfg = Debug|Win32
- {0AE29B44-19FD-4A3E-AC27-93AB06AE12AB}.Debug|x86.Build.0 = Debug|Win32
- {0AE29B44-19FD-4A3E-AC27-93AB06AE12AB}.Release|Any CPU.ActiveCfg = Release|Win32
- {0AE29B44-19FD-4A3E-AC27-93AB06AE12AB}.Release|x64.ActiveCfg = Release|x64
- {0AE29B44-19FD-4A3E-AC27-93AB06AE12AB}.Release|x64.Build.0 = Release|x64
- {0AE29B44-19FD-4A3E-AC27-93AB06AE12AB}.Release|x86.ActiveCfg = Release|Win32
- {0AE29B44-19FD-4A3E-AC27-93AB06AE12AB}.Release|x86.Build.0 = Release|Win32
- {9266A440-9187-41F7-85C7-82DF0E110143}.Debug|Any CPU.ActiveCfg = Debug|Win32
- {9266A440-9187-41F7-85C7-82DF0E110143}.Debug|x64.ActiveCfg = Debug|x64
- {9266A440-9187-41F7-85C7-82DF0E110143}.Debug|x64.Build.0 = Debug|x64
- {9266A440-9187-41F7-85C7-82DF0E110143}.Debug|x86.ActiveCfg = Debug|Win32
- {9266A440-9187-41F7-85C7-82DF0E110143}.Debug|x86.Build.0 = Debug|Win32
- {9266A440-9187-41F7-85C7-82DF0E110143}.Release|Any CPU.ActiveCfg = Release|Win32
- {9266A440-9187-41F7-85C7-82DF0E110143}.Release|x64.ActiveCfg = Release|x64
- {9266A440-9187-41F7-85C7-82DF0E110143}.Release|x64.Build.0 = Release|x64
- {9266A440-9187-41F7-85C7-82DF0E110143}.Release|x86.ActiveCfg = Release|Win32
- {9266A440-9187-41F7-85C7-82DF0E110143}.Release|x86.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/SVFEngine/PointRenderer.cpp b/SVFEngine/PointRenderer.cpp
deleted file mode 100644
index cdb3e96..0000000
--- a/SVFEngine/PointRenderer.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifdef _WIN32 || WIN32
-#include
-#endif
-
-#include "PointRenderer.h"
-#include
-#include
-#include
-#include
-#include
-#include
-
-PointRenderer::PointRenderer()
-{
-
-}
-
-
-PointRenderer::~PointRenderer()
-{
-
-}
-void PointRenderer::create()
-{
- osg::ref_ptr program = new osg::Program;
-
- char vertexShaderSource[] =
- "void main(void)\n"
- "{\n"
- " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
- "}\n";
- char fragmentShaderSource[] =
- "void main(void) \n"
- "{\n"
- " gl_FragColor = vec4(1,0,0,1);\n"
- "}\n";
-
- program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
- program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
- osg::StateSet* ss = this->getOrCreateStateSet();
- ss->setAttribute(program.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
- this->setCullingActive(false);
- osg::ref_ptr point = new osg::Point(5.0);
- point->setDistanceAttenuation(osg::Vec3(0.0, 0.0000, 0.05f));
- ss->setAttribute(point.get());
- ss->setRenderBinDetails(6000, "RenderBin");
- //ss->setMode(GL_BLEND, osg::StateAttribute::ON);
- //geode->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
- ss->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
-}
-
-void PointRenderer::setPoint(osg::Vec3d point)
-{
- removeDrawables(0, getNumDrawables());
- osg::ref_ptr vertices = new osg::Vec3Array;
- osg::ref_ptr polyGeom = new osg::Geometry();
- vertices->push_back(point);
- polyGeom->setVertexArray(vertices.get());
- polyGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, vertices->size()));
- addDrawable(polyGeom.get());
-}
diff --git a/SVFEngine/PointRenderer.h b/SVFEngine/PointRenderer.h
deleted file mode 100644
index e894c5f..0000000
--- a/SVFEngine/PointRenderer.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-#include "osg/Geode"
-#include "osg/Vec3d"
-//Render a point at a 3D position picked by mouse double-click
-class PointRenderer : public osg::Geode
-{
-public:
- PointRenderer();
- ~PointRenderer();
- void create();
- //set the position of the point lable
- void setPoint(osg::Vec3d point);
-};
-
diff --git a/SVFEngine/SVFComputeTools.cpp b/SVFEngine/SVFComputeTools.cpp
deleted file mode 100644
index ffe76ba..0000000
--- a/SVFEngine/SVFComputeTools.cpp
+++ /dev/null
@@ -1,747 +0,0 @@
-#include "SVFComputeTools.h"
-#include
-#include
-CameraBuffer::CameraBuffer()
- :osg::Camera()
-{
-
-}
-
-void CameraBuffer::setupBuffer(int w, int h, osg::Vec3d dir, osg::Vec3d up, std::string name)
-{
- _texture = new osg::Texture2D;
- _texture->setTextureSize(w, h);
- _texture->setResizeNonPowerOfTwoHint(false);
- _texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR);
- _texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);
- _texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
- _texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
- //rtTexture->setDataVariance(osg::Object::DYNAMIC);
- _texture->setInternalFormat(GL_RGBA);
- _texture->setSourceFormat(GL_RGBA);
- _texture->setSourceType(GL_UNSIGNED_BYTE);
- _image = new osg::Image;
- _image->allocateImage(w, h, 1, GL_RGBA, GL_UNSIGNED_BYTE);
- _texture->setImage(_image.get());
-
- //camera = new osg::Camera;
-
- setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- setClearColor(osg::Vec4(0, 0, 0, 0));
- //camera->setClearDepth(0);
- //camera->setClearColor(osg::Vec4(0.53f, 0.85f, 1.0f, 0.9f)); // Background
- setReferenceFrame(osg::Transform::ABSOLUTE_RF_INHERIT_VIEWPOINT);
- setViewport(0, 0, w, h);
- setRenderOrder(osg::Camera::PRE_RENDER);
- setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
-
- attach(osg::Camera::COLOR_BUFFER0, _texture.get());
- attach(osg::Camera::COLOR_BUFFER0, _image.get());
-
- _dir = dir;
- _up = up;
- _name = name;
-}
-
-void CameraBuffer::update()
-{
- osg::Matrix localOffset;
- localOffset.makeLookAt(_pos, _pos + _dir * 100, _up);
- osg::Matrix viewMatrix = localOffset;
- setReferenceFrame(osg::Camera::ABSOLUTE_RF);
- float nearDist = 0.1;
- setProjectionMatrixAsFrustum(-nearDist, nearDist, -nearDist, nearDist, nearDist, 10000.0);
- setViewMatrix(viewMatrix);
- setClearColor(osg::Vec4(0, 0, 0, 0));
-}
-
-CameraBuffer * CameraBuffer::create(int w, int h, osg::Vec3d dir, osg::Vec3d up, std::string name)
-{
- CameraBuffer* camera = new CameraBuffer;
- camera->setupBuffer(w, h, dir, up, name);
- return camera;
-}
-
-CameraBuffer * CameraBuffer::createSlave(int w, int h, osg::GraphicsContext * context)
-{
- CameraBuffer* camera = new CameraBuffer;
- if (!context)
- {
- osg::ref_ptr traits = new osg::GraphicsContext::Traits;
- traits->x = 0;
- traits->y = 0;
- traits->width = w;
- traits->height = h;
- traits->windowDecoration = true; // window border etc.
- traits->doubleBuffer = true;
- traits->sharedContext = 0;
- traits->vsync = false;
- context = osg::GraphicsContext::createGraphicsContext(traits.get());
- }
-
- camera->setViewport(0, 0, w, h);
- camera->setGraphicsContext(context);
- camera->setupBuffer(w, h, osg::Vec3d(1, 0, 0), osg::Vec3d(1, 0, 0), "");
-
- return camera;
-}
-
-CameraCB::CameraCB(osg::Group* svfCameraBuffers)
-{
- _cubemapCameras = svfCameraBuffers;
-}
-void CameraCB::operator()(osg::Node* node, osg::NodeVisitor* nv)
-{
-
- if (nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
- {
- osgUtil::CullVisitor* cv = static_cast(nv);
- for (size_t i = 0; i < _cubemapCameras->getNumChildren(); i++)
- {
- CameraBuffer* cameraBuffer = (CameraBuffer*)_cubemapCameras->getChild(i);
- cameraBuffer->update();
- }
-
- }
- traverse(node, nv);
-}
-SVFComputeTools::SVFComputeTools()
-{
-}
-
-SVFComputeTools::~SVFComputeTools()
-{
-}
-
-osg::Group * SVFComputeTools::createSVFCameras(osg::Node * city)
-{
- osg::Group* cameras = new osg::Group;
- int w = 512;
- int h = 512;
- cameras->addChild(CameraBuffer::create(w, h, osg::Vec3(1, 0, 0), osg::Vec3(0, 0, 1), "POS_X"));
- cameras->addChild(CameraBuffer::create(w, h, osg::Vec3(-1, 0, 0), osg::Vec3(0, 0, 1), "NEG_X"));
- cameras->addChild(CameraBuffer::create(w, h, osg::Vec3(0, 1, 0), osg::Vec3(0, 0, 1), "POS_Y"));
- cameras->addChild(CameraBuffer::create(w, h, osg::Vec3(0, -1, 0), osg::Vec3(0, 0, 1), "NEG_Y"));
- cameras->addChild(CameraBuffer::create(w, h, osg::Vec3(0, 0, 1), osg::Vec3(0, -1, 0), "POS_Z"));
- cameras->addChild(CameraBuffer::create(w, h, osg::Vec3(0, 0, -1), osg::Vec3(0, 1, 0), "NEG_Z"));
-
- for (size_t i = 0; i < cameras->getNumChildren(); i++)
- {
- CameraBuffer* cameraBuffer = (CameraBuffer*)cameras->getChild(i);
- cameraBuffer->addChild(city);
- }
-
- osg::StateSet* ss = cameras->getOrCreateStateSet();
- CameraCB* cameraCB = new CameraCB(cameras);
- cameras->addCullCallback(cameraCB);
-
- return cameras;
-}
-
-osg::Node * SVFComputeTools::cubemap2hemispherical(osg::Group * svfCameraBuffers)
-{
- //osg::TextureCubeMap* cubemap = SkyDome::loadCubeMapTextures("E:/OpenSceneGraphSVF/OpenSceneGraphSVF/images_WEIHAI", ".png");
- enum { POS_X, NEG_X, POS_Y, NEG_Y, POS_Z, NEG_Z };
-
-
- osg::Geode* geode = new osg::Geode;
- osg::ref_ptr geom = new osg::Geometry();
- osg::Vec3Array* vertices = new osg::Vec3Array();
- osg::Vec3Array* normals = new osg::Vec3Array();
- vertices->push_back(osg::Vec3(-1, -1, -1));
- vertices->push_back(osg::Vec3(-1, 1, -1));
- vertices->push_back(osg::Vec3(1, -1, -1));
- vertices->push_back(osg::Vec3(1, -1, -1));
- vertices->push_back(osg::Vec3(-1, 1, -1));
- vertices->push_back(osg::Vec3(1, 1, -1));
- normals->push_back(osg::Vec3(0, 0, 1));
- geom->setVertexArray(vertices);
- geom->setNormalArray(normals);
- geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
- geode->getOrCreateStateSet()->setMode(GL_CULL_FACE,
- osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
- //geom->setInitialBound(osg::BoundingBox(-1000000, -1000000, -1000000, 1000000, 1000000, 1000000));
- //geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
- geom->setCullingActive(false);
- geode->setCullingActive(false);
- geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, 6));
- geode->addDrawable(geom.get());
- geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
-
- osg::TextureCubeMap* cubeMap = new osg::TextureCubeMap;
- cubeMap->setInternalFormat(GL_RGBA);
-
- cubeMap->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
- cubeMap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- cubeMap->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
- cubeMap->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
-
- cubeMap->setImage(osg::TextureCubeMap::NEGATIVE_X, ((CameraBuffer*)svfCameraBuffers->getChild(NEG_X))->_image.get());
- cubeMap->setImage(osg::TextureCubeMap::POSITIVE_X, ((CameraBuffer*)svfCameraBuffers->getChild(POS_X))->_image.get());
- cubeMap->setImage(osg::TextureCubeMap::NEGATIVE_Y, ((CameraBuffer*)svfCameraBuffers->getChild(POS_Z))->_image.get());
- cubeMap->setImage(osg::TextureCubeMap::POSITIVE_Y, ((CameraBuffer*)svfCameraBuffers->getChild(NEG_Z))->_image.get());
- cubeMap->setImage(osg::TextureCubeMap::NEGATIVE_Z, ((CameraBuffer*)svfCameraBuffers->getChild(NEG_Y))->_image.get());
- cubeMap->setImage(osg::TextureCubeMap::POSITIVE_Z, ((CameraBuffer*)svfCameraBuffers->getChild(POS_Y))->_image.get());
- geode->getOrCreateStateSet()->setTextureAttributeAndModes(0, cubeMap, osg::StateAttribute::ON);
-
- osg::Program* program = new osg::Program;
-
- char vertexSource[] =
- "void main(void)\n"
- "{\n"
- " gl_TexCoord[0] = vec4(gl_Vertex.x,gl_Vertex.y,0,1.0);\n"
- " gl_Position = vec4(gl_Vertex.x,gl_Vertex.y,0,1);\n"
- "}\n";
- char fragmentSource[] =
- "uniform vec4 color;\n"
- "uniform float alpha;\n"
- "uniform samplerCube uEnvironmentMap;\n"
- "uniform float rotateAngle;\n"
- "\n"
- "vec3 spherical2Cartisian(float lon, float lat)\n"
- "{\n"
- "float theta = lon * 0.0174533;\n"
- "float phi = lat* 0.0174533;\n"
- "return vec3(cos(phi)*cos(theta), cos(phi)*sin(theta), sin(phi));\n"
- "}\n"
-
- "vec2 rotate(vec2 uv,float angle)\n"
- "{\n"
- " angle = angle * 0.0174533;\n"
- " float sin_factor = sin(angle);\n"
- " float cos_factor = cos(angle);\n"
- " uv = (uv - 0.5) * mat2(cos_factor, sin_factor, -sin_factor, cos_factor);\n"
- " uv += 0.5;\n"
- " return uv;\n"
- "}\n"
- "void main(void) \n"
- "{\n"
- " float radius = length(gl_TexCoord[0].xy);\n"
- " vec3 tex = vec3(-gl_TexCoord[0].x, gl_TexCoord[0].y, -(1-radius));\n"
- " vec2 uv = gl_TexCoord[0].xy; \n"
- " uv = uv * 0.5 + 0.5;\n"
- " uv = rotate(uv,rotateAngle);\n"
- " gl_FragColor = textureCube( uEnvironmentMap, tex.xzy );\n"
- " if(radius > 1)\n"
- " {\n"
- " gl_FragColor = vec4(0,0,0,0);\n"
- " }\n"
- " else if(gl_FragColor.a < 0.5 )\n"
- " {\n"
- " gl_FragColor = vec4(1,1,1,0.5);\n"
- " }\n"
- "}\n";
-
- //geode->setCullCallback(new GeomCB);
- program->setName("sky_dome_shader");
- program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexSource));
- program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentSource));
- geode->getOrCreateStateSet()->setAttributeAndModes(program, osg::StateAttribute::ON);
- geode->getOrCreateStateSet()->addUniform(new osg::Uniform("uEnvironmentMap", 0));
- geode->getOrCreateStateSet()->addUniform(new osg::Uniform("rotateAngle", 0.0f));
- geode->getOrCreateStateSet()->addUniform(new osg::Uniform("alpha", 0.0f));
-
- return geode;
-}
-
-osg::Node * SVFComputeTools::cubemap2hemisphericalHUD(osg::Group * svfCameraBuffers)
-{
- //osg::TextureCubeMap* cubemap = SkyDome::loadCubeMapTextures("E:/OpenSceneGraphSVF/OpenSceneGraphSVF/images_WEIHAI", ".png");
- enum { POS_X, NEG_X, POS_Y, NEG_Y, POS_Z, NEG_Z };
-
- osg::TextureCubeMap* cubeMap = new osg::TextureCubeMap;
- cubeMap->setInternalFormat(GL_RGBA);
-
- cubeMap->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
- cubeMap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- cubeMap->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
- cubeMap->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
-
- cubeMap->setImage(osg::TextureCubeMap::NEGATIVE_X, ((CameraBuffer*)svfCameraBuffers->getChild(NEG_X))->_image.get());
- cubeMap->setImage(osg::TextureCubeMap::POSITIVE_X, ((CameraBuffer*)svfCameraBuffers->getChild(POS_X))->_image.get());
- cubeMap->setImage(osg::TextureCubeMap::NEGATIVE_Y, ((CameraBuffer*)svfCameraBuffers->getChild(POS_Z))->_image.get());
- cubeMap->setImage(osg::TextureCubeMap::POSITIVE_Y, ((CameraBuffer*)svfCameraBuffers->getChild(NEG_Z))->_image.get());
- cubeMap->setImage(osg::TextureCubeMap::NEGATIVE_Z, ((CameraBuffer*)svfCameraBuffers->getChild(NEG_Y))->_image.get());
- cubeMap->setImage(osg::TextureCubeMap::POSITIVE_Z, ((CameraBuffer*)svfCameraBuffers->getChild(POS_Y))->_image.get());
- osg::Geode* geode = new osg::Geode;
- //createGeometry( );
- //SetupStateSet(cubemap);
- osg::ref_ptr geom = new osg::Geometry();
- osg::Vec3Array* vertices = new osg::Vec3Array();
- osg::Vec3Array* normals = new osg::Vec3Array();
- vertices->push_back(osg::Vec3(-1, -1, -1));
- vertices->push_back(osg::Vec3(-1, 1, -1));
- vertices->push_back(osg::Vec3(1, -1, -1));
- vertices->push_back(osg::Vec3(1, -1, -1));
- vertices->push_back(osg::Vec3(-1, 1, -1));
- vertices->push_back(osg::Vec3(1, 1, -1));
- normals->push_back(osg::Vec3(0, 0, -1));
- geom->setVertexArray(vertices);
- geom->setNormalArray(normals);
- geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
- geode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
- //geom->setInitialBound(osg::BoundingBox(-1000000, -1000000, -1000000, 1000000, 1000000, 1000000));
- //geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
- geom->setCullingActive(false);
- geode->setCullingActive(false);
- geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, 6));
- geode->addDrawable(geom.get());
- geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- geode->getOrCreateStateSet()->setTextureAttributeAndModes(0, cubeMap, osg::StateAttribute::ON);
- //geode->getOrCreateStateSet()->setTextureAttributeAndModes(1, g_pPanoTexture, osg::StateAttribute::ON);
- osg::Program* program = new osg::Program;
-
- char vertexSource[] =
- "void main(void)\n"
- "{\n"
- " gl_TexCoord[0] = vec4(gl_Vertex.x,gl_Vertex.y,0,1.0);\n"
- " //gl_Position = vec4(gl_Vertex.x,gl_Vertex.y,0,1);\n"
- " gl_Position = vec4(gl_Vertex.x*0.5+0.5,gl_Vertex.y*0.5+0.5,0,1);\n"
- "}\n";
- char fragmentSource[] =
- "uniform vec4 color;\n"
- "uniform float alpha;\n"
- "uniform samplerCube uEnvironmentMap;\n"
- "uniform float rotateAngle;\n"
- "\n"
- "vec3 spherical2Cartisian(float lon, float lat)\n"
- "{\n"
- "float theta = lon * 0.0174533;\n"
- "float phi = lat* 0.0174533;\n"
- "return vec3(cos(phi)*cos(theta), cos(phi)*sin(theta), sin(phi));\n"
- "}\n"
-
- "vec2 rotate(vec2 uv,float angle)\n"
- "{\n"
- " angle = angle * 0.0174533;\n"
- " float sin_factor = sin(angle);\n"
- " float cos_factor = cos(angle);\n"
- " uv = (uv - 0.5) * mat2(cos_factor, sin_factor, -sin_factor, cos_factor);\n"
- " uv += 0.5;\n"
- " return uv;\n"
- "}\n"
- "void main(void) \n"
- "{\n"
- " float radius = length(gl_TexCoord[0].xy);\n"
- " vec3 tex = vec3(-gl_TexCoord[0].x, gl_TexCoord[0].y, -(1-radius));\n"
- " vec4 fisheye1 = textureCube( uEnvironmentMap, tex.xzy );\n"
- " vec2 uv = gl_TexCoord[0].xy; \n"
- " uv = uv * 0.5 + 0.5;\n"
- " uv = rotate(uv,rotateAngle);\n"
- " gl_FragColor = vec4(fisheye1.rgb,1);\n"
- " if(radius > 1)\n"
- " {\n"
- " gl_FragColor = vec4(0,0,0,0.5);\n"
- " }\n"
- " else if(fisheye1.a < 0.5 )\n"
- " {\n"
- " gl_FragColor = vec4(0.529411765,0.807843137,0.921568627,0.5);\n"
- " }\n"
- "}\n";
-
- //geode->setCullCallback(new GeomCB);
- program->setName("sky_dome_shader");
- program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexSource));
- program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentSource));
- geode->getOrCreateStateSet()->setAttributeAndModes(program, osg::StateAttribute::ON);
- geode->getOrCreateStateSet()->addUniform(new osg::Uniform("uEnvironmentMap", 0));
- geode->getOrCreateStateSet()->addUniform(new osg::Uniform("rotateAngle", 0.0f));
- geode->getOrCreateStateSet()->addUniform(new osg::Uniform("alpha", 0.0f));
-
- geode->getOrCreateStateSet()->setRenderBinDetails(5000, "RenderBin");
- geode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
- //geode->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
- geode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
- //g_pPanoState = geode->getOrCreateStateSet();
-
- osg::Projection * HUDProjectionMatrix = new osg::Projection;
-
- HUDProjectionMatrix->setMatrix(osg::Matrix::ortho2D(0, 512, 0, 512));
- osg::MatrixTransform* HUDModelViewMatrix = new osg::MatrixTransform;
- HUDModelViewMatrix->setMatrix(osg::Matrix::translate(512, 512, 0));
- // above it in the scene graph:
- HUDModelViewMatrix->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
-
- HUDProjectionMatrix->addChild(HUDModelViewMatrix);
- HUDModelViewMatrix->addChild(geode);
-
- return HUDProjectionMatrix;
- //return geode;
-}
-
-osg::Node * SVFComputeTools::createTextureRect(std::string texfile)
-{
- osg::ref_ptr tex = new osg::Texture2D;
- tex->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP_TO_BORDER);
- tex->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP_TO_BORDER);
- tex->setImage(osgDB::readImageFile(texfile));
-
- osg::Geode* geode = new osg::Geode;
- //createGeometry( );
- //SetupStateSet(cubemap);
- osg::ref_ptr geom = new osg::Geometry();
- osg::Vec3Array* vertices = new osg::Vec3Array();
- osg::Vec3Array* normals = new osg::Vec3Array();
- vertices->push_back(osg::Vec3(-1, -1, 1));
- vertices->push_back(osg::Vec3(-1, 1, 1));
- vertices->push_back(osg::Vec3(1, -1, 1));
- vertices->push_back(osg::Vec3(1, -1, 1));
- vertices->push_back(osg::Vec3(-1, 1, 1));
- vertices->push_back(osg::Vec3(1, 1, 1));
- normals->push_back(osg::Vec3(0, 0, 1));
- geom->setVertexArray(vertices);
- geom->setNormalArray(normals);
- geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
- geom->setCullingActive(false);
- geode->setCullingActive(false);
- geode->getOrCreateStateSet()->setMode(GL_CULL_FACE,
- osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
- geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, 6));
- geode->addDrawable(geom.get());
- geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- geode->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex.get(), osg::StateAttribute::ON);
-
- osg::Program* program = new osg::Program;
-
- char vertexSource[] =
- "void main(void)\n"
- "{\n"
- " gl_TexCoord[0] = vec4(gl_Vertex.x,gl_Vertex.y,0,1.0);\n"
- " //gl_Position = vec4(gl_Vertex.x*0.5-0.5,gl_Vertex.y*0.5+0.5,0,1);\n"
- " gl_Position = vec4(gl_Vertex.x*0.5+0.5,gl_Vertex.y*0.5+0.5,0,1);\n"
- "}\n";
- char fragmentSource[] =
- "uniform sampler2D texture0;\n"
- "uniform float rotateAngle;\n"
- "vec2 rotate(vec2 uv,float angle)\n"
- "{\n"
- " angle = angle * 0.0174533;\n"
- " float sin_factor = sin(angle);\n"
- " float cos_factor = cos(angle);\n"
- " uv = (uv - 0.5) * mat2(cos_factor, sin_factor, -sin_factor, cos_factor);\n"
- " uv += 0.5;\n"
- " return uv;\n"
- "}\n"
- "void main(void) \n"
- "{\n"
- " vec2 uv = gl_TexCoord[0].xy; \n"
- " uv = uv * 0.5 + 0.5;\n"
- " uv = rotate(uv,rotateAngle);\n"
- " vec4 color = texture2D( texture0, uv );\n"
- " gl_FragColor = vec4(color.rgb,0.5);\n"
- "}\n";
- program->setName("sky_dome_shader");
- program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexSource));
- program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentSource));
- geode->getOrCreateStateSet()->setAttributeAndModes(program, osg::StateAttribute::ON);
- geode->getOrCreateStateSet()->addUniform(new osg::Uniform("texture0", 0));
- geode->getOrCreateStateSet()->addUniform(new osg::Uniform("rotateAngle", 0.0f));
-
- //geode->getOrCreateStateSet()->setRenderBinDetails(100000, "RenderBin");
- geode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::OFF);
- geode->getOrCreateStateSet()->setRenderingHint(osg::StateSet::OPAQUE_BIN);
- //g_pPanoState = geode->getOrCreateStateSet();
- return geode;
-}
-
-double SVFComputeTools::calSVF(osg::Image * img, bool applyLambert)
-{
- unsigned int skypixels = 0;
- unsigned int nonskypixels = 0;
- unsigned char* data = img->data();
- unsigned int numpixels = img->s() * img->t();
- unsigned int ncols = img->s();
- unsigned int nrows = img->t();
- if (ncols != nrows)
- return 0;
- double resol = 1.0 / nrows;
- double totalarea = 0;
- double skyarea = 0;
- double y = resol * 0.5 - 0.5;
- for (unsigned int row = 0; row < nrows; row++)
- {
- y += resol;
- double x = resol * 0.5 - 0.5;
- for (unsigned int col = 0; col < ncols; col++)
- {
- unsigned char a = data[3];
- if (a == 0) {
- x += resol;
- data += 4;
- continue;//outside
- }
- double zenithD = sqrt(x*x + y*y) * 90.0;//in degrees
- if (zenithD <= 0.000000001)
- zenithD = 0.000000001;
- double zenithR = zenithD * 3.1415926 / 180.0;
- double wproj = sin(zenithR) / (zenithD / 90);//weight for equal-areal projection
- if (applyLambert)
- {
- wproj = wproj * cos(zenithR);
- }
- totalarea += wproj;
- if (a < 250)
- {
- skypixels++;
- skyarea += wproj;
- }
- else
- {
- nonskypixels++;
- }
- x += resol;
- data += 4;
- }
-
- }
- double svf = skyarea / totalarea;
- return svf;
-}
-osg::Camera* SVFComputeTools::createHUDText(osgText::Text*& _text, osg::Vec4 color)
-{
- // create a camera to set _up the projection and model view matrices, and the subgraph to draw in the HUD
- osg::Camera* camera = new osg::Camera;
-
- // set the projection matrix
- camera->setProjectionMatrix(osg::Matrix::ortho2D(0, 1024, 0, 1024));
-
- // set the view matrix
- camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
- camera->setViewMatrix(osg::Matrix::identity());
-
- // only clear the depth buffer
- camera->setClearMask(GL_DEPTH_BUFFER_BIT);
-
- // draw subgraph after main camera view.
- camera->setRenderOrder(osg::Camera::POST_RENDER);
-
- // we don't want the camera to grab event focus from the viewers main camera(s).
- camera->setAllowEventFocus(false);
-
-
-
- // add to this camera a subgraph to render
- {
-
- osg::Geode* geode = new osg::Geode();
-
- //std::string timesFont("fonts/arial.ttf");
-
- // turn lighting off for the _text and disable depth test to ensure it's always ontop.
- osg::StateSet* stateset = geode->getOrCreateStateSet();
- stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
-
- osg::Vec3 position(650.0f, 768.0f, 0.0f);
- _text = new osgText::Text;
- geode->addDrawable(_text);
- _text->setColor(color);
- //_text->setFont(timesFont);
- _text->setFont("times.ttf");
- _text->setPosition(position);
- _text->setText("");
-
- {
- osg::BoundingBox bb;
- for (unsigned int i = 0; igetNumDrawables(); ++i)
- {
- bb.expandBy(geode->getDrawable(i)->getBoundingBox());
- }
-
- osg::Geometry* geom = new osg::Geometry;
-
- osg::Vec3Array* vertices = new osg::Vec3Array;
- float depth = bb.zMin() - 0.1;
- vertices->push_back(osg::Vec3(bb.xMin(), bb.yMax(), depth));
- vertices->push_back(osg::Vec3(bb.xMin(), bb.yMin(), depth));
- vertices->push_back(osg::Vec3(bb.xMax(), bb.yMin(), depth));
- vertices->push_back(osg::Vec3(bb.xMax(), bb.yMax(), depth));
- geom->setVertexArray(vertices);
-
- osg::Vec3Array* normals = new osg::Vec3Array;
- normals->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));
- geom->setNormalArray(normals, osg::Array::BIND_OVERALL);
-
- osg::Vec4Array* colors = new osg::Vec4Array;
- colors->push_back(osg::Vec4(0.0f, 0.0, 0.0f, 0.5f));
- geom->setColorArray(colors, osg::Array::BIND_OVERALL);
-
- geom->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));
-
- osg::StateSet* stateset = geom->getOrCreateStateSet();
- stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
- //stateset->setAttribute(new osg::PolygonOffset(1.0f,1.0f),osg::StateAttribute::ON);
- stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
-
- geode->addDrawable(geom);
- }
-
- camera->addChild(geode);
- }
-
- return camera;
-}
-
-SkyViewFactorEventHandler::SkyViewFactorEventHandler(osg::Node* threeDModel, osg::Group * root, osg::ref_ptr manip, osgViewer::Viewer * viewer)
-{
- _viewer = viewer;
- _manip = manip;
- _root = root;
-
-
- _renderGroup = new osg::Group;
- _root->addChild(_renderGroup.get());
-
- //create point label for highlighting intersection point
- _pointRenderer = new PointRenderer;
- _pointRenderer->create();
- _renderGroup->addChild(_pointRenderer.get());
-
- std::vector contexts;
- _viewer->getContexts(contexts);
- //create a node to render a cubemap from a 3D position picked by mouse double-click
- _cubemapCameras = SVFComputeTools::createSVFCameras(threeDModel);
- _cubemapCameras->setNodeMask(false);
- root->addChild(_cubemapCameras.get());
-
- //create a HUD node to transform a cubemap into a fisheye view and then render onto the screen
- osg::ref_ptr cubemap2fisheyeHUD = SVFComputeTools::cubemap2hemisphericalHUD(_cubemapCameras);
- root->addChild(cubemap2fisheyeHUD.get());
-
- //create a node to transform a cubemap into a fisheye view and then render onto an off-screen image for svf calculation
- _cubemap2fisheyeCamera = CameraBuffer::createSlave(512, 512, contexts[0]);
- osg::ref_ptr cubemap2fisheye = SVFComputeTools::cubemap2hemispherical(_cubemapCameras);
- _cubemap2fisheyeCamera->addChild(cubemap2fisheye.get());
- _viewer->addSlave(_cubemap2fisheyeCamera.get(), false);
- _cubemap2fisheyeCamera->setCullingActive(false);
-
- //create text label for displaying svf value
- osg::ref_ptr hudCamera = SVFComputeTools::createHUDText(_text);
- _renderGroup->addChild(hudCamera.get());
-}
-SkyViewFactorEventHandler::~SkyViewFactorEventHandler()
-{
- _root->removeChild(_renderGroup);
-}
-void SkyViewFactorEventHandler::printfVec3d(osg::Vec3d v)
-{
- printf("%f,%f,%f\n", v.x(), v.y(), v.z());
-}
-
-void SkyViewFactorEventHandler::printfVec3(osg::Vec3 v)
-{
- printf("%f,%f,%f\n", v.x(), v.y(), v.z());
-}
-
-void SkyViewFactorEventHandler::computeMouseIntersection(osgUtil::LineSegmentIntersector * ray)
-{
-
- osg::Vec3d orieye, oricenter, oriup;
- _viewer->getCamera()->getViewMatrixAsLookAt(orieye, oricenter, oriup);
- if (ray->getIntersections().size() == 0)
- return;
- osg::Vec3d _dir = orieye - oricenter;
- _dir.normalize();
- osg::Vec3d curcenter = ray->getFirstIntersection().getWorldIntersectPoint();
-
- osg::Vec3d cureye = ray->getFirstIntersection().getWorldIntersectPoint() + _dir * 50;
-
- _viewer->setCameraManipulator(NULL, false);
- _viewer->frame();
- VGEDatabasePager* databasePager = dynamic_cast(_viewer->getDatabasePager());
- if (databasePager)
- {
- databasePager->pause();
- databasePager->frame();
- while (databasePager->getFileRequestListSize() > 0)
- {
- _viewer->frame();
- databasePager->frame();
- }
- }
-
- osgUtil::IntersectionVisitor visitor(ray);
- _viewer->getCamera()->accept(visitor);
- printfVec3(ray->getFirstIntersection().getWorldIntersectPoint());
- osg::Vec3d observer = ray->getFirstIntersection().getWorldIntersectPoint();
- osg::Vec3d observerNormal = ray->getFirstIntersection().getWorldIntersectNormal();
- observer = observer + observerNormal * 2.5; //distance of camera from the surface
- osg::Vec3d observerup = osg::Vec3(0, 0, 1);
- _pointRenderer->setPoint(observer);
-
- for (size_t i = 0; i < _cubemapCameras->getNumChildren(); i++)
- {
- CameraBuffer* cameraBuffer = (CameraBuffer*)_cubemapCameras->getChild(i);
- cameraBuffer->_pos = observer;
- }
- _cubemapCameras->setNodeMask(true);
- _viewer->frame();
- if (databasePager)
- {
- databasePager->frame();
- while (databasePager->getFileRequestListSize() > 0)
- {
- _viewer->frame();
- if (databasePager)
- {
- databasePager->frame();
- }
- }
- _viewer->frame();
- }
- else
- {
- for (size_t i = 0; i < 5; i++)
- {
- _viewer->frame();
- }
- }
-
- _cubemapCameras->setNodeMask(false);
- _viewer->getCamera()->setViewMatrixAsLookAt(orieye, oricenter, oriup);
- if (databasePager)
- {
- databasePager->resume();
- }
- osg::Matrix viewmat;
- viewmat.makeLookAt(orieye, oricenter, oriup);
- _viewer->setCameraManipulator(_manip.get(), false);
- _manip->setByInverseMatrix(viewmat);
- _viewer->getCamera()->getViewMatrixAsLookAt(orieye, oricenter, oriup);
- if (_cubemap2fisheyeCamera && _cubemap2fisheyeCamera.valid())
- {
- double svf = SVFComputeTools::calSVF(_cubemap2fisheyeCamera->_image, false);
- printf("SVF=%f\n", svf);
- std::stringstream ss;
- ss << std::setprecision(3) << "SVF = " << svf;
- _text->setText(ss.str());
- }
-}
-
-bool SkyViewFactorEventHandler::handle(const osgGA::GUIEventAdapter & ea, osgGA::GUIActionAdapter & aa)
-{
- osgViewer::Viewer* viewer = dynamic_cast(&aa);
- if (!viewer)
- return false;
- osg::Vec3d orieye, oricenter, oriup;
- viewer->getCamera()->getViewMatrixAsLookAt(orieye, oricenter, oriup);
- osgViewer::Renderer *render = dynamic_cast(aa.asView()->getCamera()->getRenderer());
- osgUtil::SceneView *sceneView = render->getSceneView(0);
-
- sceneView->getRenderInfo().getState()->setCheckForGLErrors(osg::State::NEVER_CHECK_GL_ERRORS);
- if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN) {
- }
- if (ea.getEventType() == osgGA::GUIEventAdapter::KEYUP) {
- }
- if (ea.getEventType() == osgGA::GUIEventAdapter::DOUBLECLICK) {
- }
-
- if ((ea.getModKeyMask() & ea.MODKEY_CTRL) != 0 && ea.getEventType() == osgGA::GUIEventAdapter::PUSH)
- {
- osg::ref_ptr ray = new osgUtil::LineSegmentIntersector(osgUtil::Intersector::PROJECTION, ea.getXnormalized(), ea.getYnormalized());
- osgUtil::IntersectionVisitor visitor(ray);
- viewer->getCamera()->accept(visitor);
- computeMouseIntersection(ray.get());
- }
-
- return false;
-}
diff --git a/SVFEngine/SVFComputeTools.h b/SVFEngine/SVFComputeTools.h
deleted file mode 100644
index 39b14a6..0000000
--- a/SVFEngine/SVFComputeTools.h
+++ /dev/null
@@ -1,105 +0,0 @@
-#pragma once
-#ifdef _WIN32 || WIN32
-#include
-#endif
-#include "osg/Camera"
-#include "osg/Texture2D"
-#include "osg/Geode"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "osg/LineWidth"
-#include
-#include "SVFDatabasePager.h"
-#include "PointRenderer.h"
-#include
-#include
-#include
-
-//a cubemap camera
-class CameraBuffer : public osg::Camera
-{
-public:
- osg::ref_ptr _texture;
- osg::ref_ptr _image;
- std::string _name;
- osg::Vec3d _pos;//position of camera
- osg::Vec3d _dir;//viewing direction of camera
- osg::Vec3d _up;//the _up vector for use in building a view matrix
- CameraBuffer();
- void setupBuffer(int w, int h, osg::Vec3d _dir, osg::Vec3d _up, std::string _name);
- void update();
- //w: width of camera buffer
- //h: height of camera buffer
- static CameraBuffer* create(int w, int h, osg::Vec3d dir, osg::Vec3d up, std::string name);
- static CameraBuffer* createSlave(int w, int h, osg::GraphicsContext* context = NULL);
-};
-
-//callback for updating cubemap camera matrix before rendering
-class CameraCB : public osg::NodeCallback
-{
-public:
- osg::Group* _cubemapCameras;
- //_cubemapCameras is a group of cubemap cameras created from SVFComputeTools
- CameraCB(osg::Group* svfCameraBuffers);
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
-};
-
-class SVFComputeTools
-{
-public:
- SVFComputeTools();
- ~SVFComputeTools();
- //create a group of cameras to render a cubemap set from a 3D position
- //it contains six cameras looking respectively in the six cubemap directions
- static osg::Group* createSVFCameras(osg::Node* city);
- //create node to convert a cubemap set into a fisheye view and then render onto an off-screen _image
- static osg::Node* cubemap2hemispherical(osg::Group* _cubemapCameras);
- //create node to convert a cubemap set into a fisheye view and then render onto the screen
- static osg::Node* cubemap2hemisphericalHUD(osg::Group* _cubemapCameras);
- static osg::Node* createTextureRect(std::string texfile);
- //calculate SVF from a fisheye _image
- //Lambert's cosine law will be applied when applyLambert = true
- static double calSVF(osg::Image* img, bool applyLambert = false);
- //create a _text node to display SVF value
- static osg::Camera* createHUDText(osgText::Text*& _text,osg::Vec4 color = osg::Vec4(0,0,0,1));
-};
-//class for handling interactive 3D picking, SVF calculation and result displaying
-class SkyViewFactorEventHandler : public osgGA::GUIEventHandler
-{
-public:
- //_cubemapCameras: a group of cubemap cameras created from SVFComputeTools
- //_root: child nodes for showing the point lable and the fisheye HUD are inserted into this parent node
- SkyViewFactorEventHandler(osg::Node* threeDModel, osg::Group* root, osg::ref_ptr manip, osgViewer::Viewer* viewer);
- ~SkyViewFactorEventHandler();
- bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);
-private:
- //compute the mouse-model intersection point; compute SVF at this point; update the fisheye HUD and _text labels
- void computeMouseIntersection(osgUtil::LineSegmentIntersector* ray);
- osg::ref_ptr _cubemapCameras;
- osg::ref_ptr _manip;
- osg::Group* _root;
- osg::ref_ptr _pointRenderer;
- osg::ref_ptr _cubemap2fisheyeCamera;
- osg::ref_ptr _screenshotTextImg;
- osgViewer::Viewer* _viewer;
- osgText::Text* _text;
- void printfVec3d(osg::Vec3d v);
- void printfVec3(osg::Vec3 v);
- osg::ref_ptr _renderGroup;
-};
-
diff --git a/SVFEngine/SVFDatabasePager.h b/SVFEngine/SVFDatabasePager.h
deleted file mode 100644
index 0e3a5cd..0000000
--- a/SVFEngine/SVFDatabasePager.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#pragma once
-#ifdef _WIN32 || WIN32
-#include
-#endif
-#include
-#include
-#include
-#include
-using namespace osgDB;
-using namespace OpenThreads;
-
-class VGEDatabasePager : public osgDB::DatabasePager
-{
-public:
- VGEDatabasePager()
- :osgDB::DatabasePager(){}
- void frame();
- void pause();
- void resume();
-};
diff --git a/SVFEngine/SVFEDatabasePager.cpp b/SVFEngine/SVFEDatabasePager.cpp
deleted file mode 100644
index a56d151..0000000
--- a/SVFEngine/SVFEDatabasePager.cpp
+++ /dev/null
@@ -1,308 +0,0 @@
-#include "SVFDatabasePager.h"
-struct DatabasePager::DatabasePagerCompileCompletedCallback : public osgUtil::IncrementalCompileOperation::CompileCompletedCallback
-{
- DatabasePagerCompileCompletedCallback(osgDB::DatabasePager* pager, osgDB::DatabasePager::DatabaseRequest* databaseRequest) :
- _pager(pager),
- _databaseRequest(databaseRequest) {}
-
- virtual bool compileCompleted(osgUtil::IncrementalCompileOperation::CompileSet* /*compileSet*/)
- {
- _pager->compileCompleted(_databaseRequest.get());
- return true;
- }
-
- osgDB::DatabasePager* _pager;
- osg::ref_ptr _databaseRequest;
-};
-
-class DatabasePager::FindCompileableGLObjectsVisitor : public osgUtil::StateToCompile
-{
-public:
- FindCompileableGLObjectsVisitor(const DatabasePager* pager) :
- osgUtil::StateToCompile(osgUtil::GLObjectsVisitor::COMPILE_DISPLAY_LISTS | osgUtil::GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES),
- _pager(pager),
- _changeAutoUnRef(false), _valueAutoUnRef(false),
- _changeAnisotropy(false), _valueAnisotropy(1.0)
- {
- _assignPBOToImages = _pager->_assignPBOToImages;
-
- _changeAutoUnRef = _pager->_changeAutoUnRef;
- _valueAutoUnRef = _pager->_valueAutoUnRef;
- _changeAnisotropy = _pager->_changeAnisotropy;
- _valueAnisotropy = _pager->_valueAnisotropy;
-
- switch (_pager->_drawablePolicy)
- {
- case DatabasePager::DO_NOT_MODIFY_DRAWABLE_SETTINGS:
- // do nothing, leave settings as they came in from loaded database.
- // OSG_NOTICE<<"DO_NOT_MODIFY_DRAWABLE_SETTINGS"<getBuildKdTreesHint() == osgDB::Options::BUILD_KDTREES &&
- osgDB::Registry::instance()->getKdTreeBuilder())
- {
- _kdTreeBuilder = osgDB::Registry::instance()->getKdTreeBuilder()->clone();
- }
- }
-
- META_NodeVisitor("osgDB", "FindCompileableGLObjectsVisitor")
-
- bool requiresCompilation() const { return !empty(); }
-
- virtual void apply(osg::Geode& geode)
- {
- StateToCompile::apply(geode);
-
- if (_kdTreeBuilder.valid())
- {
- geode.accept(*_kdTreeBuilder);
- }
- }
-
- void apply(osg::Texture& _texture)
- {
- StateToCompile::apply(_texture);
-
- if (_changeAutoUnRef)
- {
- _texture.setUnRefImageDataAfterApply(_valueAutoUnRef);
- }
-
- if ((_changeAnisotropy && _texture.getMaxAnisotropy() != _valueAnisotropy))
- {
- _texture.setMaxAnisotropy(_valueAnisotropy);
- }
- }
-
- const DatabasePager* _pager;
- bool _changeAutoUnRef;
- bool _valueAutoUnRef;
- bool _changeAnisotropy;
- float _valueAnisotropy;
- osg::ref_ptr _kdTreeBuilder;
-
-protected:
-
- FindCompileableGLObjectsVisitor& operator = (const FindCompileableGLObjectsVisitor&) { return *this; }
-};
-
-void VGEDatabasePager::frame()
-{
-
-
- //bool firstTime = true;
-
- osg::ref_ptr read_queue;
- osg::ref_ptr out_queue;
-
-
- read_queue = _fileRequestQueue;
-
-
-
- //read_queue->block();
-
-
- //
- // delete any children if required.
- //
- if (_deleteRemovedSubgraphsInDatabaseThread/* && !(read_queue->_childrenToDeleteList.empty())*/)
- {
- ObjectList deleteList;
- {
- // Don't hold lock during destruction of deleteList
- OpenThreads::ScopedLock lock(read_queue->_requestMutex);
- if (!read_queue->_childrenToDeleteList.empty())
- {
- deleteList.swap(read_queue->_childrenToDeleteList);
- read_queue->updateBlock();
- }
- }
- }
-
- //
- // load any subgraphs that are required.
- //
- osg::ref_ptr databaseRequest;
- read_queue->takeFirst(databaseRequest);
-
- bool readFromFileCache = false;
-
- osg::ref_ptr fileCache = osgDB::Registry::instance()->getFileCache();
- osg::ref_ptr fileLocationCallback = osgDB::Registry::instance()->getFileLocationCallback();
- osg::ref_ptr dr_loadOptions;
- std::string fileName;
- int frameNumberLastRequest = 0;
- if (databaseRequest.valid())
- {
- {
- OpenThreads::ScopedLock drLock(_dr_mutex);
- dr_loadOptions = databaseRequest->_loadOptions;
- fileName = databaseRequest->_fileName;
- frameNumberLastRequest = databaseRequest->_frameNumberLastRequest;
- }
- if (dr_loadOptions.valid())
- {
- if (dr_loadOptions->getFileCache()) fileCache = dr_loadOptions->getFileCache();
- if (dr_loadOptions->getFileLocationCallback()) fileLocationCallback = dr_loadOptions->getFileLocationCallback();
-
- dr_loadOptions = dr_loadOptions->cloneOptions();
- }
- else
- {
- dr_loadOptions = new osgDB::Options;
- }
-
- dr_loadOptions->setTerrain(databaseRequest->_terrain);
-
- // disable the FileCache if the fileLocationCallback tells us that it isn't required for this request.
- if (fileLocationCallback.valid() && !fileLocationCallback->useFileCache()) fileCache = 0;
-
-
- // check if databaseRequest is still relevant
- if ((_frameNumber - frameNumberLastRequest) <= 1)
- {
-
-
- // do nothing as this thread can handle the load
- if (fileCache.valid() && fileCache->isFileAppropriateForFileCache(fileName))
- {
- if (fileCache->existsInCache(fileName))
- {
- readFromFileCache = true;
- }
- }
-
-
- }
-
- }
- if (databaseRequest.valid())
- {
-
- // load the data, note safe to write to the databaseRequest since once
- // it is created this thread is the only one to write to the _loadedModel pointer.
- //OSG_NOTICE<<"In DatabasePager thread readNodeFile("<_fileName<<")"<tick();
-
-
- // assume that readNode is thread safe...
- ReaderWriter::ReadResult rr = readFromFileCache ?
- fileCache->readNode(fileName, dr_loadOptions.get(), false) :
- Registry::instance()->readNode(fileName, dr_loadOptions.get(), false);
-
- osg::ref_ptr loadedModel;
- if (rr.validNode()) loadedModel = rr.getNode();
- if (rr.error()) OSG_WARN << "Error in reading file " << fileName << " : " << rr.message() << std::endl;
- if (rr.notEnoughMemory()) OSG_INFO << "Not enought memory to load file " << fileName << std::endl;
-
- if (loadedModel.valid() &&
- fileCache.valid() &&
- fileCache->isFileAppropriateForFileCache(fileName) &&
- !readFromFileCache)
- {
- fileCache->writeNode(*(loadedModel), fileName, dr_loadOptions.get());
- }
-
- {
- OpenThreads::ScopedLock drLock(_dr_mutex);
- if ((_frameNumber - databaseRequest->_frameNumberLastRequest)>1)
- {
-
- loadedModel = 0;
- }
- }
-
- //OSG_NOTICE<<" node read in "<delta_m(before,osg::Timer::instance()->tick())<<" ms"<getBound();
-
- // find all the compileable rendering objects
- DatabasePager::FindCompileableGLObjectsVisitor stateToCompile(this);
- loadedModel->accept(stateToCompile);
-
- bool loadedObjectsNeedToBeCompiled = _doPreCompile &&
- _incrementalCompileOperation.valid() &&
- _incrementalCompileOperation->requiresCompile(stateToCompile);
-
- // move the databaseRequest from the front of the fileRequest to the end of
- // dataToCompile or dataToMerge lists.
- osg::ref_ptr compileSet = 0;
- if (loadedObjectsNeedToBeCompiled)
- {
- // OSG_NOTICE<<"Using IncrementalCompileOperation"<buildCompileMap(_incrementalCompileOperation->getContextSet(), stateToCompile);
- compileSet->_compileCompletedCallback = new DatabasePagerCompileCompletedCallback(this, databaseRequest.get());
- _incrementalCompileOperation->add(compileSet.get(), false);
- }
- {
- OpenThreads::ScopedLock drLock(_dr_mutex);
- databaseRequest->_loadedModel = loadedModel;
- databaseRequest->_compileSet = compileSet;
- }
- // Dereference the databaseRequest while the queue is
- // locked. This prevents the request from being
- // deleted at an unpredictable time within
- // addLoadedDataToSceneGraph.
- if (loadedObjectsNeedToBeCompiled)
- {
- OpenThreads::ScopedLock listLock(
- _dataToCompileList->_requestMutex);
- _dataToCompileList->addNoLock(databaseRequest.get());
- databaseRequest = 0;
- }
- else
- {
- OpenThreads::ScopedLock listLock(
- _dataToMergeList->_requestMutex);
- _dataToMergeList->addNoLock(databaseRequest.get());
- databaseRequest = 0;
- }
-
- }
-
- // _pager->_dataToCompileList->pruneOldRequestsAndCheckIfEmpty();
- }
-
-
-}
-void VGEDatabasePager::pause()
-{
-
- for (DatabaseThreadList::iterator dt_itr = _databaseThreads.begin();
- dt_itr != _databaseThreads.end();
- ++dt_itr)
- {
- (*dt_itr)->setActive(true);
- }
-
-}
-void VGEDatabasePager::resume()
-{
-
- for (DatabaseThreadList::iterator dt_itr = _databaseThreads.begin();
- dt_itr != _databaseThreads.end();
- ++dt_itr)
- {
- (*dt_itr)->setActive(false);
- }
-}
\ No newline at end of file
diff --git a/SVFEngine/SVFEngine.vcxproj b/SVFEngine/SVFEngine.vcxproj
deleted file mode 100644
index 62f81a1..0000000
--- a/SVFEngine/SVFEngine.vcxproj
+++ /dev/null
@@ -1,171 +0,0 @@
-
-
-
-
- Debug
- Win32
-
-
- Release
- Win32
-
-
- Debug
- x64
-
-
- Release
- x64
-
-
-
- {F8DF3492-A941-4A6D-860E-19C63FA93DA5}
- Win32Proj
- Registration
- 8.1
- SVFEngine
-
-
-
- Application
- true
- v140
- Unicode
-
-
- Application
- false
- v140
- true
- Unicode
-
-
- StaticLibrary
- true
- v140
- Unicode
-
-
- StaticLibrary
- false
- v140
- true
- Unicode
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
- true
- $(SolutionDir)\lib\$(Platform)\
-
-
- false
-
-
- false
- $(SolutionDir)\lib\$(Platform)\
-
-
-
-
-
- Level3
- Disabled
- WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
-
-
- Console
- true
-
-
-
-
-
-
- Level3
- Disabled
- _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
- $(SolutionDir)\include
-
-
- Console
- true
- qtmaind.lib;QtCored4.lib;QtGuid4.lib;QtSqld4.lib;QtMultimediad4.lib;QtXmld4.lib;QtOpenGLd4.lib;opengl32.lib;glu32.lib;QtNetworkd4.lib;QtScriptd4.lib;Qt3Supportd4.lib;comdlg32.lib;QAxServerd.lib;QtSvgd4.lib;QtHelpd4.lib;QtWebKitd4.lib;QtXmlPatternsd4.lib;QtTestd4.lib;QtDeclaratived4.lib;phonond4.lib;osgEarthd.lib;osgEarthFeaturesd.lib;osgEarthUtild.lib;osgEarthQtd.lib;osgEarthSymbologyd.lib;osgEarthAnnotationd.lib;OpenThreadsd.lib;osgd.lib;osgDBd.lib;osgUtild.lib;osgViewerd.lib;osgWidgetd.lib;osgSimd.lib;osgTextd.lib;osgGAd.lib;osgShadowd.lib;osgQtd.lib;osgManipulatord.lib;gdal_i.lib
- $(OSGEO4W)\lib
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
-
-
- Console
- true
- true
- true
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
- $(SolutionDir)\include
-
-
- Console
- true
- true
- true
- $(OSGEO4W)\lib
- qtmain.lib;QtCore4.lib;QtGui4.lib;QtMultimedia4.lib;QtXml4.lib;QtSql4.lib;QtOpenGL4.lib;opengl32.lib;glu32.lib;QtNetwork4.lib;QtScript4.lib;Qt3Support4.lib;comdlg32.lib;QAxServer.lib;QtSvg4.lib;QtHelp4.lib;QtWebKit4.lib;QtXmlPatterns4.lib;QtTest4.lib;QtDeclarative4.lib;phonon4.lib;osgEarth.lib;osgEarthFeatures.lib;osgEarthUtil.lib;osgEarthSymbology.lib;osgEarthAnnotation.lib;osgEarthQt.lib;osg.lib;osgDB.lib;osgUtil.lib;osgViewer.lib;OpenThreads.lib;osgSim.lib;osgTerrain.lib;osgFX.lib;osgShadow.lib;osgManipulator.lib;osgText.lib;osgGA.lib;osgQt.lib;gdal_i.lib;%(AdditionalDependencies);gdal_i.lib
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/SVFEngine/SVFEngine.vcxproj.filters b/SVFEngine/SVFEngine.vcxproj.filters
deleted file mode 100644
index c88521e..0000000
--- a/SVFEngine/SVFEngine.vcxproj.filters
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
- {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
- cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
-
-
- {93995380-89BD-4b04-88EB-625FBE52EBFB}
- h;hh;hpp;hxx;hm;inl;inc;xsd
-
-
- {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
- rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
-
-
-
-
-
-
-
- Header Files
-
-
- Header Files
-
-
- Header Files
-
-
- Header Files
-
-
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
-
\ No newline at end of file
diff --git a/SVFEngine/SVFEngine.vcxproj.user b/SVFEngine/SVFEngine.vcxproj.user
deleted file mode 100644
index abe8dd8..0000000
--- a/SVFEngine/SVFEngine.vcxproj.user
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/SVFEngine/ShapeFile.cpp b/SVFEngine/ShapeFile.cpp
deleted file mode 100644
index b34ee90..0000000
--- a/SVFEngine/ShapeFile.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-#include "ShapeFile.h"
-#include
-void ShapeFile::close()
-{
- if (poDS)
- GDALClose(poDS);
- poDS = NULL;
-}
-void ShapeFile::splitFilepath(std::string filepath, std::string& _dir, std::string& _name, std::string& ext)
-{
- int lastdot = -1;
- int lastslash = -1;
- int secondslash = -1;
- for (int i = filepath.size() - 1; i >= 0; i--)
- {
- if (lastslash == -1 && (filepath[i] == '/' || filepath[i] == '\\'))
- {
- lastslash = i;
- //break;
- }
- if (lastslash != -1 && secondslash == -1 && (filepath[i] == '/' || filepath[i] == '\\'))
- {
- secondslash = i;
- //break;
- }
- if (lastdot == -1 && filepath[i] == '.')
- {
- lastdot = i;
- }
- }
- ext = filepath.substr(lastdot, filepath.size() - lastdot);
- _name = filepath.substr(lastslash + 1, filepath.size() - (lastslash + 1) - ext.size());
- _dir = filepath.substr(0, secondslash + 1);
-
-}
-void ShapeFile::create(std::string filename, OGRSpatialReference* spatialRef, OGRFeatureDefn *poFDefn, OGRwkbGeometryType geotype)
-{
-
-
- g_mFileName = filename;
- if (poDS)
- GDALClose(poDS);
- const char *pszDriverName = "ESRI Shapefile";
- GDALDriver *poDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(
- pszDriverName);
- std::ifstream ifs;
- ifs.open(filename.data());
- if (ifs){
- poDriver->Delete(filename.data());
- }
- ifs.close();
-
- poDS = poDriver->Create(filename.data(), 0, 0, 0, GDT_Unknown, NULL);
- std::string _dir, _name, ext;
- splitFilepath(filename, _dir, _name, ext);
- if (spatialRef)
- {
- poLayer = poDS->CreateLayer(_name.data(), spatialRef, geotype, NULL);
- }
-
- if (poFDefn)
- {
- for (int iField = 0; iField < poFDefn->GetFieldCount(); iField++)
- {
- OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn(iField);
- poLayer->CreateField(poFieldDefn);
- }
- }
-
-}
-int ShapeFile::getOrCreateField(const char* _name, OGRFieldType tp) {
- int idx = poLayer->GetLayerDefn()->GetFieldIndex(_name);
- if (idx > -1)
- return idx;
- OGRFieldDefn field(_name, tp);
- poLayer->CreateField(&field);
- return poLayer->GetLayerDefn()->GetFieldIndex(_name);
-}
-
-ShapeFile::ShapeFile()
-{
- poDS = NULL;
-}
-
-ShapeFile::ShapeFile(std::string filename, int update) {
- g_mFileName = filename;
- poDS = (GDALDataset*)GDALOpenEx(filename.data(), GDAL_OF_VECTOR | update, NULL, NULL, NULL);
- if(poDS)
- poLayer = poDS->GetLayer(0);
-}
-
-ShapeFile::~ShapeFile()
-{
- close();
-}
diff --git a/SVFEngine/ShapeFile.h b/SVFEngine/ShapeFile.h
deleted file mode 100644
index e40dadc..0000000
--- a/SVFEngine/ShapeFile.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#pragma once
-#include "ogrsf_frmts.h"
-//read and write ESRI ShapeFile
-//http://support.esri.com/en/white-paper/279
-class ShapeFile
-{
-public:
- ShapeFile();
- ShapeFile(std::string filename, int update = 0);
- ~ShapeFile();
- void close();
- int getOrCreateField(const char* _name, OGRFieldType tp);
- void create(std::string filename, OGRSpatialReference* spatialRef = NULL, OGRFeatureDefn *poFDefn = NULL, OGRwkbGeometryType geotype = wkbPolygon);
-public:
- OGRLayer *poLayer;
- GDALDataset *poDS;
-private:
- std::string g_mFileName;
- void splitFilepath(std::string filepath, std::string& _dir, std::string& _name, std::string& ext);
-};
-
diff --git a/Solar3D.sln b/Solar3D.sln
new file mode 100644
index 0000000..84421fd
--- /dev/null
+++ b/Solar3D.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30104.148
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SolarEngine", "SolarEngine\SolarEngine.vcxproj", "{62D74672-958E-43AB-8326-EDD104916D15}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Solar3D", "Solar3D\Solar3D.vcxproj", "{6A000ED9-C66F-48CB-8547-34A2AB0F5A76}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Release|x64 = Release|x64
+ ReleaseD|x64 = ReleaseD|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {62D74672-958E-43AB-8326-EDD104916D15}.Release|x64.ActiveCfg = Release|x64
+ {62D74672-958E-43AB-8326-EDD104916D15}.Release|x64.Build.0 = Release|x64
+ {62D74672-958E-43AB-8326-EDD104916D15}.ReleaseD|x64.ActiveCfg = ReleaseD|x64
+ {62D74672-958E-43AB-8326-EDD104916D15}.ReleaseD|x64.Build.0 = ReleaseD|x64
+ {6A000ED9-C66F-48CB-8547-34A2AB0F5A76}.Release|x64.ActiveCfg = Release|x64
+ {6A000ED9-C66F-48CB-8547-34A2AB0F5A76}.Release|x64.Build.0 = Release|x64
+ {6A000ED9-C66F-48CB-8547-34A2AB0F5A76}.ReleaseD|x64.ActiveCfg = ReleaseD|x64
+ {6A000ED9-C66F-48CB-8547-34A2AB0F5A76}.ReleaseD|x64.Build.0 = ReleaseD|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {CE4EC8B0-FDD8-47DF-82E2-198FD0ED9FD5}
+ EndGlobalSection
+EndGlobal
diff --git a/Solar3D/Main.cpp b/Solar3D/Main.cpp
new file mode 100644
index 0000000..b767283
--- /dev/null
+++ b/Solar3D/Main.cpp
@@ -0,0 +1,814 @@
+
+#ifdef _WIN32 || WIN32
+#include
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "CustomControls.h"
+#include "GrassSolar.h"
+#include "SolarInteractiveHandler.h"
+#include "ModelLoader.h"
+
+using namespace osgEarth;
+using namespace osgEarth::Util;
+//using namespace osgEarth::Drivers;
+//using namespace osgEarth::Features;
+//using namespace osgEarth::Symbology;
+
+const int UI_FONT_SIZE = 18;
+SolarParam m_solarParam;
+size_t m_frameCount = 1;
+
+osg::ref_ptr m_solarInteractiveHandler;
+CustomControls::VBox* m_mainUIControl;
+CustomControls::HBox* m_popupControl;
+std::map m_controls;
+CustomControls::VBox* m_parametersControl;
+CustomControls::VBox* m_fisheyeControl;
+CustomControls::VBox* m_resultLabelsControl = new CustomControls::VBox();
+CustomControls::LabelControl* m_svfLabel;
+CustomControls::LabelControl* m_globalRadLabel;
+CustomControls::LabelControl* m_beamRadLabel;
+CustomControls::LabelControl* m_diffuseRadLabel;
+CustomControls::LabelControl* m_statusBar;
+MapNode* m_mapNode;
+CustomControls::CustomImageControl* m_compass;
+
+CustomControls::CustomImageControl* createCompass(CustomControls::ControlCanvas* cs, int viewWidth, int viewHeight)
+{
+ char fragmentSource[] =
+ "uniform sampler2D texture0;\n"
+ "uniform float rotateAngle;\n"
+ "vec2 rotateXY(vec2 xy, float rotation)\n"
+ "{\n"
+ " float mid = 0.5;\n"
+ " float x = cos(rotation) * (xy.x - mid) + sin(rotation) * (xy.y - mid) + mid;\n"
+ " float y = cos(rotation) * (xy.y - mid) - sin(rotation) * (xy.x - mid) + mid;\n"
+ " return vec2(x,y);\n"
+ "}\n"
+ "void main(void) \n"
+ "{\n"
+ " vec4 color = texture2D(texture0, rotateXY(gl_TexCoord[0].xy, rotateAngle * 0.0174533));\n"
+ " if(color.a < 0.5)\n"
+ " color = vec4(0.1,0.1,0.1,0.4);\n"
+ " else\n"
+ " color = color + vec4(0,0.3,0,0);\n"
+ " gl_FragColor = color;\n"
+ "}\n";
+ osg::ref_ptr img = osgDB::readImageFile("./data/compass.png");
+ osg::ref_ptr tex = new osg::Texture2D;
+ tex->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
+ tex->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
+ tex->setImage(img.get());
+
+ CustomControls::CustomImageControl* imageCtrl = new CustomControls::CustomImageControl;
+ imageCtrl->setSize(128, 128);
+ imageCtrl->setPosition(viewWidth - 128 - 10, 10);
+ imageCtrl->setImage(img.get());
+ imageCtrl->getOrCreateStateSet()->addUniform(new osg::Uniform("rotateAngle", 0.0f));
+
+ ProgramBinder binder;
+ binder.initialize("NorthArrowProgram", imageCtrl->getOrCreateStateSet());
+ binder.setFragmentShader(fragmentSource);
+ imageCtrl->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex.get(), osg::StateAttribute::ON);
+ cs->addChild(imageCtrl);
+ return imageCtrl;
+}
+
+SolarParam createSolarParam()
+{
+ SolarParam param;
+ param.m_aspect = 270;
+ param.m_slope = 0;
+ param.m_lon = -9999;
+ param.m_lat = 37.5131;
+ param.m_day = 183;
+ param.m_time_step = 1;
+ param.m_linke = 3.0;
+ param.m_startDay = param.m_day;
+ param.m_endDay = param.m_day;
+ param.m_isSingleDay = true;
+ param.m_isInstantaneous;
+ param.m_elev = 0;
+ return param;
+}
+
+class ParamControlBase : public CustomControls::HBox
+{
+public:
+ ParamControlBase(std::string name)
+ :CustomControls::HBox()
+ {
+ m_name = name;
+ setName(name);
+ m_controls[m_name] = (CustomControls::Control*)this;
+ }
+ CustomControls::HSliderControl* m_slider;
+ CustomControls::CheckBoxControl* m_check;
+ CustomControls::LabelControl* m_nameLabel;
+ std::string m_name;
+
+ virtual void onValueChanged(CustomControls::Control* control, float value) {}
+
+ virtual void onValueChanged(CustomControls::Control* control, bool value) {}
+};
+
+void onResultsUpdated(float svf, SolarRadiation rad)
+{
+ m_svfLabel->setText("SVF: " + Utils::value2String(svf, 3));
+ rad = rad / 1000;
+ m_globalRadLabel->setText("Global radiation [kWh/m2]: " + Utils::value2String(rad.m_global, 3));
+ m_beamRadLabel->setText("Beam radiation [kWh/m2]: " + Utils::value2String(rad.m_beam, 3));
+ m_diffuseRadLabel->setText("Diffuse radiation [kWh/m2]: " + Utils::value2String(rad.m_diffuse, 3));
+ //printf("Global: %f\n", rad.global);
+}
+
+class ParamControlEventHandler : public CustomControls::ControlEventHandler
+{
+public:
+ ParamControlBase* _paramControl;
+ ParamControlEventHandler(ParamControlBase* paramControl) :
+ _paramControl(paramControl)
+ {
+
+ }
+ virtual void onValueChanged(CustomControls::Control* control, float value)
+ {
+ if (_paramControl)
+ _paramControl->onValueChanged(control, value);
+ }
+
+ virtual void onValueChanged(CustomControls::Control* control, bool value)
+ {
+ if (_paramControl)
+ _paramControl->onValueChanged(control, value);
+ }
+};
+
+class ParamControl : public ParamControlBase, public CustomControls::ControlEventHandler
+{
+public:
+
+ void Init(std::string name, std::string label, bool isInteger)
+ {
+ m_isInteger = isInteger;
+ setChildSpacing(0);
+ setChildVertAlign(CustomControls::Control::ALIGN_CENTER);
+ setHorizFill(true);
+ m_nameLabel = new CustomControls::LabelControl(label);
+ m_nameLabel->setHorizAlign(CustomControls::Control::ALIGN_LEFT);
+ m_nameLabel->setVertAlign(CustomControls::Control::ALIGN_CENTER);
+ m_nameLabel->setTextBackdropOffset(3);
+ m_nameLabel->setFontSize(UI_FONT_SIZE);
+ addControl(m_nameLabel);
+
+ }
+ ParamControl(std::string name, std::string label, float min, float max, float value, bool isInteger)
+ :ParamControlBase(name), CustomControls::ControlEventHandler()
+ {
+ Init(name, label, isInteger);
+
+ m_slider = new CustomControls::HSliderControl(min, max, value);
+ //m_slider->setBackColor(.6, 0, 0, 1);
+ m_slider->setHeight(UI_FONT_SIZE);
+ m_slider->setWidth(200);
+ m_slider->setName(name);
+ m_slider->addEventHandler(new ParamControlEventHandler(this));
+ m_slider->setHorizAlign(CustomControls::Control::ALIGN_LEFT);
+ m_valueLabel = new CustomControls::LabelControl(name);
+ m_valueLabel->setText(toString(value));
+ addControl(m_slider);
+ addControl(m_valueLabel);
+ }
+
+ ParamControl(std::string name, std::string label, bool isChecked)
+ :ParamControlBase(name), CustomControls::ControlEventHandler()
+ {
+ Init(name, label, false);
+
+ m_check = new CustomControls::CheckBoxControl(isChecked);
+ //slider->setBackColor(.6, 0, 0, 1);
+ m_check->setHeight(10);
+ m_check->setName(name);
+ m_check->addEventHandler(new ParamControlEventHandler(this));
+ addControl(m_check);
+ }
+
+ ParamControl(std::string name, std::string label, float min, float max, float value, bool isInteger, bool isChecked)
+ :ParamControlBase(name), CustomControls::ControlEventHandler()
+ {
+ Init(name, label, isInteger);
+
+ m_slider = new CustomControls::HSliderControl(min, max, value);
+ m_slider->setHorizAlign(CustomControls::Control::ALIGN_LEFT);
+ //m_slider->setBackColor(.6, 0, 0, 1);
+ m_slider->setHeight(10);
+ m_slider->setWidth(200);
+ m_slider->setName(name);
+ m_slider->addEventHandler(new ParamControlEventHandler(this));
+ m_valueLabel = new CustomControls::LabelControl(name);
+ m_valueLabel->setText(toString(value));
+ m_valueLabel->setFontSize(UI_FONT_SIZE);
+ m_check = new CustomControls::CheckBoxControl(isChecked);
+ //slider->setBackColor(.6, 0, 0, 1);
+ m_check->setHeight(10);
+ m_check->setName(name);
+ m_check->addEventHandler(new ParamControlEventHandler(this));
+ addControl(m_slider);
+ addControl(m_valueLabel);
+ addControl(m_check);
+ }
+
+
+ static bool getSingleDayMode()
+ {
+ auto iter = m_controls.find("SingleDayMode");
+ return ((ParamControlBase*)iter->second)->m_check->getValue();
+ }
+
+ static float getStartDay()
+ {
+ auto iter = m_controls.find("StartDay");
+ return ((ParamControlBase*)iter->second)->m_slider->getValue();
+ }
+
+ static float getEndDay()
+ {
+ auto iter = m_controls.find("EndDay");
+ return ((ParamControlBase*)iter->second)->m_slider->getValue();
+ }
+
+private:
+ CustomControls::LabelControl* m_valueLabel;
+ bool m_isInteger;
+ std::string toString(float value)
+ {
+ //bool isInt = (floor(value) == value);
+ std::stringstream buf;
+ std::string str = "";
+ if (m_isInteger)
+ {
+ buf << (int)value;
+ str = buf.str();
+ }
+ else
+ {
+ buf.precision(2);
+ buf << std::fixed << value;
+ str = buf.str();
+ str = Utils::padRight(str, 7, '0');
+ }
+ return str;
+ }
+
+ void onValueChanged(CustomControls::Control* control, float value)
+ {
+ int intValue = (int)value;
+ bool isSingleMode = m_solarParam.m_isSingleDay;
+ if (m_name == "StartDay")
+ {
+ m_solarParam.m_startDay = intValue;
+ if (isSingleMode || m_solarParam.m_endDay < intValue)
+ {
+ auto iter = m_controls.find("EndDay");
+ ParamControl* endSlider = (ParamControl*)iter->second;
+ endSlider->m_slider->setValue(value);
+ m_solarParam.m_endDay = intValue;
+ }
+ }
+ else if (m_name == "EndDay")
+ {
+ m_solarParam.m_endDay = intValue;
+ if (isSingleMode || m_solarParam.m_startDay > intValue)
+ {
+ auto iter = m_controls.find("StartDay");
+ ParamControl* endSlider = (ParamControl*)iter->second;
+ endSlider->m_slider->setValue(value);
+ m_solarParam.m_startDay = intValue;
+ }
+ }
+ else if (m_name == "Latitude")
+ {
+ auto iter = m_controls.find("Latitude");
+ ParamControl* slider = (ParamControl*)iter->second;
+ slider->m_slider->setValue(value);
+ m_solarParam.m_lat = value;
+ }
+ else if (m_name == "Elevation")
+ {
+ auto iter = m_controls.find("Elevation");
+ ParamControl* slider = (ParamControl*)iter->second;
+ slider->m_slider->setValue(value);
+ m_solarParam.m_elev = value;
+ }
+ else if (m_name == "TimeStep")
+ {
+ m_solarParam.m_time_step = value;
+ }
+
+ if (m_isInteger)
+ value = intValue;
+ m_valueLabel->setText(toString(value));
+ }
+
+ void onValueChanged(CustomControls::Control* control, bool value)
+ {
+ m_solarParam.m_isSingleDay = value;
+ if (m_name == "SingleDayMode")
+ {
+ auto iter = m_controls.find("StartDay");
+ ParamControl* starSlider = (ParamControl*)iter->second;
+ iter = m_controls.find("EndDay");
+ ParamControl* endSlider = (ParamControl*)iter->second;
+ if (value)
+ {
+ endSlider->m_slider->setValue(starSlider->m_slider->getValue());
+ }
+ m_solarParam.m_isSingleDay = value;
+ }
+ else if (m_name == "Latitude")
+ {
+ m_solarParam.m_useLatitudeOverride = value;
+ }
+ else if (m_name == "Elevation")
+ {
+ m_solarParam.m_useElevationOverride = value;
+ }
+ else if (m_name == "ToggleParameters")
+ {
+ m_parametersControl->setVisible(value);
+ }
+ else if (m_name == "ToggleResults")
+ {
+ m_resultLabelsControl->setVisible(value);
+ }
+ else if (m_name == "ToggleFisheye")
+ {
+ m_fisheyeControl->setVisible(value);
+ }
+ }
+};
+
+class PopupControl : public CustomControls::HBox
+{
+public:
+ PopupControl() :CustomControls::HBox()
+ {
+ m_point.m_id = -1;
+ setChildSpacing(0);
+ setChildVertAlign(CustomControls::Control::ALIGN_CENTER);
+ setHorizFill(true);
+ osg::Vec4 borderColor(0.8, 0.8, 0.8, 1);
+ int borderWidth = 2;
+ m_namesLabel = new CustomControls::LabelControl("");
+ m_namesLabel->setHorizAlign(CustomControls::Control::ALIGN_LEFT);
+ m_namesLabel->setVertAlign(CustomControls::Control::ALIGN_CENTER);
+ m_namesLabel->setTextBackdropOffset(3);
+ m_namesLabel->setFontSize(UI_FONT_SIZE);
+ m_namesLabel->setBorderColor(borderColor);
+ m_namesLabel->setBorderWidth(borderWidth);
+
+ m_valuesLabel = new CustomControls::LabelControl("");
+ m_valuesLabel->setHorizAlign(CustomControls::Control::ALIGN_LEFT);
+ m_valuesLabel->setVertAlign(CustomControls::Control::ALIGN_CENTER);
+ m_valuesLabel->setTextBackdropOffset(3);
+ m_valuesLabel->setFontSize(UI_FONT_SIZE);
+ m_valuesLabel->setBorderColor(borderColor);
+ m_valuesLabel->setBorderWidth(borderWidth);
+
+ m_fisheyeImagel = new CustomControls::ImageControl;
+ m_fisheyeImagel->setSize(256, 256);
+ m_fisheyeImagel->setBorderColor(borderColor);
+ m_fisheyeImagel->setBorderWidth(borderWidth);
+
+ addControl(m_namesLabel);
+ addControl(m_valuesLabel);
+ addControl(m_fisheyeImagel);
+ }
+
+ void SetPoint(SolarRadiationPoint& point)
+ {
+ m_point = point;
+ std::string names;
+ std::string values;
+ m_point.toString(names, values);
+ m_namesLabel->setText(names);
+ m_valuesLabel->setText(values);
+ osg::Image* fisheye = m_solarInteractiveHandler->getFisheyeForPoint(m_point.m_id);
+ if (fisheye)
+ m_fisheyeImagel->setImage(fisheye);
+ }
+
+ void setPositionSmart(int x, int y, int viewWidth, int viewHeight)
+ {
+ if (m_point.m_id < 0)
+ {
+ setPosition(x, y);
+ return;
+ }
+ float width = renderSize().x();
+ float height = renderSize().y();
+ int xdiff = (x + width) - viewWidth;
+ int ydiff = (y + height) - viewHeight;
+ if (xdiff < 0 && ydiff < 0)
+ {
+ setPosition(x, y);
+ return;
+ }
+
+ int xoffset = 0;
+ if (xdiff > 0 && (x - width) > 0)
+ {
+ xoffset = -width;
+ }
+
+ int yoffset = 0;
+ if (ydiff > 0 && (y - height) > 0)
+ {
+ yoffset = -height;
+ }
+
+ setPosition(x + xoffset, y + yoffset);
+ }
+
+ SolarRadiationPoint m_point;
+ CustomControls::LabelControl* m_namesLabel;
+ CustomControls::LabelControl* m_valuesLabel;
+ CustomControls::ImageControl* m_fisheyeImagel;
+};
+
+void createMainUIControls(CustomControls::ControlCanvas* cs, int viewWidth, int viewHeight)
+{
+ m_mainUIControl = new CustomControls::VBox();
+ m_mainUIControl->setPosition(0, 0);
+ m_mainUIControl->setPadding(5);
+ int maxLabelLen = 20;
+ osg::Vec4 backgroundColor(0.0, 0.0, 0.0, 0.6);
+ osg::Vec4 borderColor(0.0, 0.0, 0.0, 1.0);
+ osg::Vec4 fontColor(1, 1, 1, 1);
+
+ CustomControls::VBox* togglesControl = new CustomControls::VBox();
+ CustomControls::HBox* toggleParameters = new ParamControl("ToggleParameters", "Toggle Hide/Show Parameters", true);
+ CustomControls::HBox* toggleResults = new ParamControl("ToggleResults", "Toggle Hide/Show Results", true);
+ CustomControls::HBox* toggleFisheye = new ParamControl("ToggleFisheye", "Toggle Hide/Show Fisheye", true);
+ togglesControl->addControl(toggleParameters);
+ togglesControl->addControl(toggleResults);
+ togglesControl->addControl(toggleFisheye);
+ togglesControl->setBackColor(backgroundColor);
+ togglesControl->setBorderColor(borderColor);
+
+ m_parametersControl = new CustomControls::VBox();
+ m_parametersControl->setBackColor(backgroundColor);
+ m_parametersControl->setBorderColor(borderColor);
+ CustomControls::LabelControl* titleLabel = new CustomControls::LabelControl("GRASS GIS r.sun parameters", fontColor);
+ titleLabel->setFontSize(UI_FONT_SIZE);
+ CustomControls::HBox* linkieSlider = new ParamControl("Linkie", Utils::padRight("Linkie", maxLabelLen), 3, 8, m_solarParam.m_linke, true);
+ CustomControls::HBox* startDaySlider = new ParamControl("StartDay", Utils::padRight("Start Day", maxLabelLen), 1, 365, m_solarParam.m_startDay, true);
+ CustomControls::HBox* endDaySlider = new ParamControl("EndDay", Utils::padRight("End Day", maxLabelLen), 1, 365, m_solarParam.m_endDay, true);
+ CustomControls::HBox* isSingleDayCheck = new ParamControl("SingleDayMode", Utils::padRight("Single Day Mode", maxLabelLen), m_solarParam.m_isSingleDay);
+ CustomControls::HBox* timeStepSlider = new ParamControl("TimeStep", Utils::padRight("Time Step (hours)", maxLabelLen), 0.1, 1, m_solarParam.m_time_step, false);
+ CustomControls::HBox* latSlider = new ParamControl("Latitude", Utils::padRight("Default Latitude", maxLabelLen), -90, 90, m_solarParam.m_lat, false, true);
+ CustomControls::HBox* elevSlider = new ParamControl("Elevation", Utils::padRight("Base Elevation", maxLabelLen), 0, 9999, m_solarParam.m_elev, false, true);
+ m_parametersControl->addControl(titleLabel);
+ m_parametersControl->addControl(isSingleDayCheck);
+ m_parametersControl->addControl(startDaySlider);
+ m_parametersControl->addControl(endDaySlider);
+ m_parametersControl->addControl(latSlider);
+ m_parametersControl->addControl(elevSlider);
+ m_parametersControl->addControl(timeStepSlider);
+ m_parametersControl->addControl(linkieSlider);
+
+ m_resultLabelsControl = new CustomControls::VBox();
+ m_resultLabelsControl->setBackColor(backgroundColor);
+ m_resultLabelsControl->setBorderColor(borderColor);
+ m_resultLabelsControl->setWidth(320);
+
+ m_svfLabel = new CustomControls::LabelControl("SVF:", fontColor, UI_FONT_SIZE);
+ m_globalRadLabel = new CustomControls::LabelControl("Global radiation:", fontColor, UI_FONT_SIZE);
+ m_beamRadLabel = new CustomControls::LabelControl("Beam radiation:", fontColor, UI_FONT_SIZE);
+ m_diffuseRadLabel = new CustomControls::LabelControl("Diffuse radiation:", fontColor, UI_FONT_SIZE);
+
+ m_resultLabelsControl->addControl(m_svfLabel);
+ m_resultLabelsControl->addControl(m_globalRadLabel);
+ m_resultLabelsControl->addControl(m_beamRadLabel);
+ m_resultLabelsControl->addControl(m_diffuseRadLabel);
+
+ m_fisheyeControl = new CustomControls::VBox();
+ m_fisheyeControl->setBackColor(backgroundColor);
+ m_fisheyeControl->setBorderColor(borderColor);
+ CustomControls::ImageControl* fishEyeImg = new CustomControls::ImageControl(m_solarInteractiveHandler->fisheyeSurface()->Texture());
+ fishEyeImg->setSize(320, 320);
+ m_fisheyeControl->addControl(fishEyeImg);
+ m_mainUIControl->addControl(togglesControl);
+ m_mainUIControl->addControl(m_parametersControl);
+ m_mainUIControl->addControl(m_resultLabelsControl);
+ m_mainUIControl->addControl(m_fisheyeControl);
+
+ cs->addControl(m_mainUIControl);
+
+ m_compass = createCompass(cs, viewWidth, viewHeight);
+ cs->addControl(m_compass);
+
+ m_statusBar = new CustomControls::LabelControl("", fontColor);
+ m_statusBar->setFontSize(UI_FONT_SIZE);
+ m_statusBar->setBackColor(backgroundColor);
+ m_statusBar->setPosition(viewWidth * 0.5 - 50, viewHeight - 50);
+ //m_statusBar->setBorderColor(borderColor);
+ m_statusBar->setPadding(15);
+ cs->addControl(m_statusBar);
+}
+
+void createPopup(CustomControls::ControlCanvas* cs)
+{
+ PopupControl* popup = new PopupControl();
+ popup->setPosition(200, 200);
+ popup->setPadding(5);
+ int maxLabelLen = 20;
+ osg::Vec4 backgroundColor(0.0, 0.0, 0.0, 0.6);
+ osg::Vec4 borderColor(1.0, 1.0, 1.0, 1.0);
+ osg::Vec4 fontColor(1, 1, 1, 1);
+ popup->setBorderColor(borderColor);
+ popup->setBackColor(backgroundColor);
+ popup->setBorderWidth(5);
+ popup->m_namesLabel->setFontSize(UI_FONT_SIZE);
+ popup->m_namesLabel->setForeColor(fontColor);
+ popup->setVisible(false);
+ m_popupControl = popup;
+ cs->addControl(popup);
+}
+
+class MainUIEventHandler : public osgGA::GUIEventHandler
+{
+private:
+ float calAngle(float x, float y)
+ {
+ float x2 = 0.0;
+ float y2 = 1.0;
+ float dot = x * x2 + y * y2; //# dot product\n"
+ float det = x * y2 - y * x2; //# determinant\n"
+ float angle = atan2(det, dot) * 57.2958; //# atan2(y, x) or atan2(sin, cos)\n"
+ if (angle < 0)
+ angle += 360;
+ return angle;
+ }
+public:
+ bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
+ {
+ osgViewer::Viewer* viewer = dynamic_cast(&aa);
+ if (!viewer)
+ return false;
+
+ if (ea.getEventType() == osgGA::GUIEventAdapter::FRAME)
+ {
+ if (m_frameCount % 2 == 0)
+ {
+ float rotateAngle = 0;
+ if (m_mapNode)
+ {
+ osg::Vec3d eye, center, up;
+ viewer->getCamera()->getViewMatrixAsLookAt(eye, center, up);
+ osg::Vec3d look = (center - eye);
+ look.normalize();
+ osg::Vec3d north(0, 0, 1);
+ double projectedX = look * north;
+ double projectedY = look * osg::Vec3d(1,0,0);
+ osg::Vec2d xy(projectedY, projectedX);
+ xy.normalize();
+ rotateAngle = calAngle(xy.x(), xy.y());
+ }
+ else
+ {
+ osg::Vec3d eye, center, up;
+ viewer->getCamera()->getViewMatrixAsLookAt(eye, center, up);
+ osg::Vec3d look = (center - eye);
+ look.normalize();
+ osg::Vec2d xy(look.x(), look.y());
+ xy.normalize();
+ rotateAngle = calAngle(xy.x(), xy.y());
+ }
+ m_compass->getOrCreateStateSet()->getUniform("rotateAngle")->set(rotateAngle);
+ }
+ return false;
+ }
+
+ if (ea.getEventType() == osgGA::GUIEventAdapter::MOVE)
+ {
+ osg::Vec3d worldPos, geoPos;
+ std::tie(worldPos, geoPos) = m_solarInteractiveHandler->queryCoordinatesAtMouse(ea.getXnormalized(), ea.getYnormalized());
+ std::stringstream ss;
+ ss.precision(4);
+
+ if (m_mapNode)
+ {
+ std::string lonFix = geoPos.x() > 0 ? "E" : "W";
+ std::string latFix = geoPos.y() > 0 ? "N" : "S";
+ std::string eleFix = "m";
+ ss << std::fixed << abs(geoPos.x()) << lonFix << " " << abs(geoPos.y()) << latFix << " " << geoPos.z() << eleFix;
+ }
+ else
+ {
+ ss << std::fixed << worldPos.x() << "X" << " " << worldPos.y() << "Y" << " " << worldPos.z() << "Z";
+ }
+ m_statusBar->setText(ss.str());
+ }
+
+ if (ea.getEventType() == osgGA::GUIEventAdapter::RESIZE)
+ {
+ int viewWidth = viewer->getCamera()->getViewport()->width();
+ int viewHeight = viewer->getCamera()->getViewport()->height();
+ m_compass->setPosition(viewWidth - 128 - 10, 10);
+ m_statusBar->setPosition(viewWidth * 0.5 - 100, viewHeight - 50);
+ return false;
+ }
+
+ if (ea.getEventType() == osgGA::GUIEventAdapter::DOUBLECLICK)
+ return false;
+ if (ea.getEventType() == osgGA::GUIEventAdapter::DRAG)
+ return false;
+
+ int key = ea.getUnmodifiedKey();
+
+ if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN && key == osgGA::GUIEventAdapter::KEY_H)
+ {
+ m_mainUIControl->setVisible(!m_mainUIControl->visible());
+ return true;
+ }
+
+ PopupControl* popup = (PopupControl*)m_popupControl;
+
+
+ bool handlePointQuery = false;
+ if (
+ (ea.getEventType() == osgGA::GUIEventAdapter::KEYUP ||
+ ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN)
+ && (ea.getUnmodifiedKey() == osgGA::GUIEventAdapter::KEY_Control_L ||
+ ea.getUnmodifiedKey() == osgGA::GUIEventAdapter::KEY_Control_R)
+ )
+ {
+ handlePointQuery = true;
+ }
+ else if (ea.getEventType() == osgGA::GUIEventAdapter::MOVE
+ && (ea.getModKeyMask() & ea.MODKEY_CTRL))
+ {
+ handlePointQuery = true;
+ }
+ else if (ea.getEventType() == osgGA::GUIEventAdapter::MOVE)
+ {
+ popup->setVisible(false);
+ }
+
+ if (!handlePointQuery)
+ {
+ return false;
+ }
+
+ SolarRadiationPoint point;
+ if (m_solarInteractiveHandler->queryPoint(ea.getXnormalized(), ea.getYnormalized(), point))
+ {
+ float viewWidth = viewer->getCamera()->getViewport()->width();
+ float viewHeight = viewer->getCamera()->getViewport()->height();
+ int x = (int)((ea.getXnormalized() * 0.5 + 0.5) * viewWidth) + 10;
+ int y = (int)((1.0 - (ea.getYnormalized() * 0.5 + 0.5)) * viewHeight) + 10;
+ bool isInitialized = popup->m_point.m_id > -1;
+ if (popup->m_point.m_id != point.m_id)
+ {
+ popup->setPositionSmart(x, y, viewWidth, viewHeight);
+ popup->SetPoint(point);
+ }
+ popup->setVisible(true);
+ }
+ else
+ {
+ popup->setVisible(false);
+ }
+
+ return false;
+ }
+};
+
+int main(int argc, char** argv)
+{
+ m_solarParam = createSolarParam();
+
+ osg::ArgumentParser arguments(&argc, argv);
+
+ if (argc < 2)
+ return 0;
+
+ // create a viewer:
+ osgViewer::Viewer viewer(arguments);
+
+ // Tell the database pager to not modify the unref settings
+ viewer.getDatabasePager()->setUnrefImageDataAfterApplyPolicy(true, false);
+
+ // thread-safe initialization of the OSG wrapper manager. Calling this here
+ // prevents the "unsupported wrapper" messages from OSG
+ osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper("osg::Image");
+
+ osg::ref_ptr scene = MapNodeHelper().load(arguments, &viewer);
+ if (!scene)
+ {
+ scene = osgDB::readNodeFiles(arguments);
+ }
+
+ if (!scene)
+ {
+ scene = ModelLoader::Load3DTiles(arguments[1]);
+ }
+
+ if (!scene)
+ return 0;
+
+ osg::ref_ptr root = new osg::Group;
+ root->addChild(scene.get());
+
+ viewer.setSceneData(root.get());
+
+ m_mapNode = MapNode::findMapNode(scene);
+
+ osg::ref_ptr manip;
+ if (m_mapNode)
+ {
+ // install our default manipulator (do this before calling load)
+ manip = new EarthManipulator(arguments);
+ // disable the small-feature culling
+ viewer.getCamera()->setSmallFeatureCullingPixelSize(-1.0f);
+ // set a near/far ratio that is smaller than the default. This allows us to get
+ // closer to the ground without near clipping. If you need more, use --logdepth
+ viewer.getCamera()->setNearFarRatio(0.0001);
+ }
+ else
+ {
+ manip = new osgGA::TrackballManipulator();
+ if (!Utils::nodeHasNormals(scene))
+ {
+ viewer.getCamera()->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
+ }
+ }
+
+ viewer.setCameraManipulator(manip.get());
+
+ m_solarInteractiveHandler = new SolarInteractiveHandler(scene, root, m_mapNode, manip, &viewer, &m_solarParam, onResultsUpdated);
+
+
+ unsigned int width, height;
+ osg::GraphicsContext::ScreenIdentifier main_screen_id;
+ osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
+ main_screen_id.readDISPLAY();
+ main_screen_id.setUndefinedScreenDetailsToDefaultScreen();
+ wsi->getScreenResolution(main_screen_id, width, height);
+
+ // create a surface to house the controls
+ CustomControls::ControlCanvas* canvas = CustomControls::ControlCanvas::getOrCreate(&viewer);
+ // create some controls.
+ createMainUIControls(canvas, width, height);
+ createPopup(canvas);
+
+ //osg::Group* group = (osg::Group*)viewer.getCamera()->getChild(0);
+ // group->addChild(m_northArrow);
+ // zoom to a good startup position
+
+ viewer.addEventHandler(m_solarInteractiveHandler);
+ viewer.addEventHandler(new MainUIEventHandler);
+ viewer.addEventHandler(new osgViewer::ThreadingHandler);
+
+ // add the window size toggle handler
+ viewer.addEventHandler(new osgViewer::WindowSizeHandler);
+
+ // add the stats handler
+ viewer.addEventHandler(new osgViewer::StatsHandler);
+
+ // add the LOD Scale handler
+ viewer.addEventHandler(new osgViewer::LODScaleHandler);
+
+ // add the state manipulator
+ viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
+
+
+ //viewer.setUpViewInWindow(50, 50, 1024, 768);
+ viewer.realize();
+ while (!viewer.done())
+ {
+ viewer.frame();
+ if (m_frameCount % 10 == 0)
+ {
+ m_solarInteractiveHandler->postDrawUpdate();
+ }
+ m_frameCount++;
+ if (m_frameCount > 1000000)
+ m_frameCount = 1;
+ }
+ return 0;
+}
diff --git a/Solar3D/Solar3D.vcxproj b/Solar3D/Solar3D.vcxproj
new file mode 100644
index 0000000..7c8b201
--- /dev/null
+++ b/Solar3D/Solar3D.vcxproj
@@ -0,0 +1,123 @@
+
+
+
+
+ ReleaseD
+ x64
+
+
+ Release
+ x64
+
+
+
+ {6A000ED9-C66F-48CB-8547-34A2AB0F5A76}
+ Win32Proj
+ Registration
+ 10.0
+ Solar3D
+
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ $(SolutionDir)\bin
+ $(SolutionDir)\$(Configuration)\$(ProjectName)
+
+
+ false
+ $(SolutionDir)\bin
+ $(SolutionDir)\$(Configuration)\$(ProjectName)
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ $(vcpkg_x64)\include;$(vcpkg_x64)\include\QtCore;$(SolutionDir)\SolarEngine
+
+
+ Console
+ false
+ true
+ true
+ $(vcpkg_x64)\lib;$(SolutionDir)\lib
+ osgEarth.lib;osgEarthFeatures.lib;osgEarthUtil.lib;osgEarthSymbology.lib;osgEarthAnnotation.lib;osg.lib;osgDB.lib;osgUtil.lib;osgViewer.lib;OpenThreads.lib;osgSim.lib;osgTerrain.lib;osgFX.lib;osgShadow.lib;osgManipulator.lib;osgText.lib;osgGA.lib;Qt5Core.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+
+
+ Disabled
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ $(vcpkg_x64)\include;$(vcpkg_x64)\include\QtCore;$(SolutionDir)\SolarEngine
+
+
+ Console
+ true
+ true
+ true
+ $(vcpkg_x64)\lib;$(SolutionDir)\lib
+ osgEarth.lib;osgEarthFeatures.lib;osgEarthUtil.lib;osgEarthSymbology.lib;osgEarthAnnotation.lib;osg.lib;osgDB.lib;osgUtil.lib;osgViewer.lib;OpenThreads.lib;osgSim.lib;osgTerrain.lib;osgFX.lib;osgShadow.lib;osgManipulator.lib;osgText.lib;osgGA.lib;Qt5Core.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Solar3D/Solar3D.vcxproj.filters b/Solar3D/Solar3D.vcxproj.filters
new file mode 100644
index 0000000..cd84446
--- /dev/null
+++ b/Solar3D/Solar3D.vcxproj.filters
@@ -0,0 +1,81 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {7e94fff8-f364-4c89-9261-1196015e46ad}
+
+
+
+
+ Source Files
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+ SolarEngine
+
+
+
\ No newline at end of file
diff --git a/Solar3D/Solar3D.vcxproj.user b/Solar3D/Solar3D.vcxproj.user
new file mode 100644
index 0000000..5c2b14c
--- /dev/null
+++ b/Solar3D/Solar3D.vcxproj.user
@@ -0,0 +1,13 @@
+
+
+
+ $(OutDir)
+ WindowsLocalDebugger
+ ./tests/boston_buildings.earth
+
+
+ $(OutDir)
+ WindowsLocalDebugger
+ ./data/models/OAP3D/OAP3D.osgb
+
+
\ No newline at end of file
diff --git a/SolarEngine/Cubemap.cpp b/SolarEngine/Cubemap.cpp
new file mode 100644
index 0000000..af54b55
--- /dev/null
+++ b/SolarEngine/Cubemap.cpp
@@ -0,0 +1,218 @@
+#include "Cubemap.h"
+#include "GrassSolar.h"
+
+CubemapSurface::CubemapSurface(int width, int height, GLenum internalFormat, GLenum sourceFormat, GLenum sourceType, bool allocateImage,
+ osg::Vec3d dir, osg::Vec3d up, std::string name) :
+ RenderSurface(width, height, internalFormat, sourceFormat, sourceType, allocateImage),
+ m_dir(dir), m_up(up)
+{
+ m_local2World = osg::Matrixd::identity();
+ osg::Camera::setName(name);
+ setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+ setReferenceFrame(osg::Camera::ABSOLUTE_RF);
+ setClearColor(osg::Vec4(0, 0, 0, 0));
+}
+
+void CubemapSurface::update()
+{
+ osg::Vec3d dir = m_dir * m_local2World;
+ dir.normalize();
+ osg::Vec3d up = m_up * m_local2World;
+ _viewMatrix.makeLookAt(m_pos, m_pos + dir * 100, up);
+ _projectionMatrix.makePerspective(90, 1.0, 0.01, 1000000);
+ m_viewProjMatrix = _viewMatrix * _projectionMatrix;
+ dirtyBound();
+}
+
+Cubemap* Cubemap::create(int imageSize, osg::Node* scene)
+{
+ Cubemap* cubemap = new Cubemap;
+ int w = imageSize;
+ int h = imageSize;
+ cubemap->addChild(new CubemapSurface(w, h, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true, osg::Vec3d(1, 0, 0), osg::Vec3d(0, 0, 1), "POS_X"));
+ cubemap->addChild(new CubemapSurface(w, h, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true, osg::Vec3(-1, 0, 0), osg::Vec3(0, 0, 1), "NEG_X"));
+ cubemap->addChild(new CubemapSurface(w, h, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true, osg::Vec3(0, 1, 0), osg::Vec3(0, 0, 1), "POS_Y"));
+ cubemap->addChild(new CubemapSurface(w, h, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true, osg::Vec3(0, -1, 0), osg::Vec3(0, 0, 1), "NEG_Y"));
+ cubemap->addChild(new CubemapSurface(w, h, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true, osg::Vec3(0, 0, 1), osg::Vec3(0, -1, 0), "POS_Z"));
+ cubemap->addChild(new CubemapSurface(w, h, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true, osg::Vec3(0, 0, -1), osg::Vec3(0, 1, 0), "NEG_Z"));
+ if (scene)
+ {
+ for (int i = 0; i < 6; i++)
+ {
+ cubemap->getFace((osg::TextureCubeMap::Face)i)->addChild(scene);
+ }
+ }
+ return cubemap;
+}
+
+CubemapSurface* Cubemap::getFace(int face)
+{
+ if (face > getNumChildren())
+ return nullptr;
+ return dynamic_cast(getChild(face));
+}
+
+CubemapSurface* Cubemap::getFace(osg::TextureCubeMap::Face face)
+{
+ return getFace((int)face);
+}
+
+RenderSurface* Cubemap::toHemisphericalSurface()
+{
+ osg::ref_ptr cubeMap = new osg::TextureCubeMap;
+ cubeMap->setInternalFormat(GL_RGBA);
+ cubeMap->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
+ cubeMap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
+ cubeMap->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
+ cubeMap->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
+
+ cubeMap->setImage(osg::TextureCubeMap::NEGATIVE_X, getFace(osg::TextureCubeMap::NEGATIVE_X)->Image());
+ cubeMap->setImage(osg::TextureCubeMap::POSITIVE_X, getFace(osg::TextureCubeMap::POSITIVE_X)->Image());
+ cubeMap->setImage(osg::TextureCubeMap::NEGATIVE_Y, getFace(osg::TextureCubeMap::POSITIVE_Z)->Image());
+ cubeMap->setImage(osg::TextureCubeMap::POSITIVE_Y, getFace(osg::TextureCubeMap::NEGATIVE_Z)->Image());
+ cubeMap->setImage(osg::TextureCubeMap::NEGATIVE_Z, getFace(osg::TextureCubeMap::NEGATIVE_Y)->Image());
+ cubeMap->setImage(osg::TextureCubeMap::POSITIVE_Z, getFace(osg::TextureCubeMap::POSITIVE_Y)->Image());
+ char vertexSource[] =
+ "void main(void)\n"
+ "{\n"
+ " gl_TexCoord[0] = vec4(-gl_Vertex.x,gl_Vertex.y,0,1.0);\n"
+ " gl_Position = vec4(-gl_Vertex.x,gl_Vertex.y,0,1);\n"
+ "}\n";
+
+ char fragmentSource[] =
+ "uniform samplerCube uEnvironmentMap;\n"
+ "const float PI = 3.1415926535897932384626433832795;\n"
+ "const float PI_2 = 1.57079632679489661923;\n"
+ "const float degree2radian = 0.0174533;\n"
+ "const float radian2degree = 57.2958;\n"
+
+ "float calAzimuth(float x, float y)\n"
+ "{\n"
+ " float x2 = 0.0;\n"
+ " float y2 = 1.0;\n"
+ " float dot = x * x2 + y * y2; //# dot product\n"
+ " float det = x * y2 - y * x2; //# determinant\n"
+ " float angle = atan(det, dot) * radian2degree; //# atan2(y, x) or atan2(sin, cos)\n"
+ " if (angle < 0)\n"
+ " angle += 360;\n"
+ " return angle;\n"
+ "}\n"
+ "vec3 cartesian2hemispherical(vec2 xy)\n"
+ "{\n"
+ " float rho = length(xy);\n"
+ " float x = xy.x;\n"
+ " float y = xy.y;\n"
+ " float azimuth = calAzimuth(x, y);\n"
+ " float alt = (1.0 - rho) * 90.0;\n"
+ " float z = cos((90.0 - alt)*degree2radian);\n"
+ " float projectedLenghOnXY = cos(alt*degree2radian);\n"
+ " y = projectedLenghOnXY * cos(azimuth*degree2radian);\n"
+ " x = projectedLenghOnXY * cos((90 - azimuth)*degree2radian);\n"
+ " return normalize(vec3(x, y, z));\n"
+ "}\n"
+ "void main(void) \n"
+ "{\n"
+ " float radius = length(gl_TexCoord[0].xy);\n"
+ " //vec3 dir = normalize(vec3(gl_TexCoord[0].x, -(1-radius), gl_TexCoord[0].y));//a close approximation of the solar vector\n"
+ " //vec4 rgba = textureCube(uEnvironmentMap, dir);\n"
+ " vec3 dir = cartesian2hemispherical(gl_TexCoord[0].xy);\n"
+ " vec4 rgba = textureCube( uEnvironmentMap, vec3(dir.x, -dir.z, dir.y));\n"
+ " if(radius > 1)\n"
+ " {\n"
+ " rgba = vec4(0.0,0.0,0.0,0.0);\n"
+ " gl_FragColor = rgba;\n"
+ " return;\n"
+ " }\n"
+ " else if(rgba.a < 0.5)\n"
+ " {\n"
+ " rgba = vec4(0, 0.5, 1, 0.65);\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " rgba = vec4(rgba.rgb,1);\n"
+ " }\n"
+ " //rgba = vec4(dir*0.5+vec3(0.5),1);//check the solar vectors\n"
+ " gl_FragColor = rgba;\n"
+ "}\n";
+
+ OverlayRenderSurface* fisheye = new OverlayRenderSurface(512, 512, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true);
+ fisheye->overlay()->setProgramName("fisheye");
+ fisheye->overlay()->setTextureLayer(cubeMap.get(), 0);
+ fisheye->overlay()->SetVertexShader(vertexSource);
+ fisheye->overlay()->SetFragmentShader(fragmentSource);
+ fisheye->getOrCreateStateSet()->addUniform(new osg::Uniform("uEnvironmentMap", 0));
+ return fisheye;
+}
+
+osg::Image* Cubemap::toHemisphericalImage(int width, int height)
+{
+ osg::Image* fisheye = new osg::Image;
+ fisheye->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE);
+ double yresol = 1.0 / height;
+ double xresol = 1.0 / width;
+ ColorUB4* data = (ColorUB4*)fisheye->data();
+ for (int row = 0; row < height; row++)
+ {
+ double y = (row / (height - 1.0) - 0.5) * 2.0;
+ for (int col = 0; col < width; col++)
+ {
+ double x = (col / (width - 1.0) - 0.5) * 2.0;
+ double radius = sqrt(x * x + y * y);
+ if (radius > 1.0)
+ {
+ *data++ = ColorUB4(osg::Vec4(0, 0, 1, 0.3));
+ continue;
+ }
+ double azimuth = Utils::calAzimuthAngle(x, y);
+ double alt = (1.0 - radius) * 90.0;
+ osg::Vec3 dir = Utils::solarAngle2Vector(alt, azimuth);
+ CubemapSurface* face = getFace(alt, azimuth);
+ osg::Image* faceImage = face->Image();
+ osg::Vec3d sundir = Utils::solarAngle2Vector(alt, azimuth);
+ osg::Vec3d targetPos = face->m_pos + sundir * 10000;
+ osg::Vec3d screenPos = targetPos * face->m_viewProjMatrix;
+ double u = (screenPos.x() + 1.0) * 0.5;
+ double v = (screenPos.y() + 1.0) * 0.5;
+ osg::Vec4 color = faceImage->getColor(osg::Vec2(u, v));
+ *data++ = ColorUB4(color);
+ }
+ }
+ return fisheye;
+}
+
+osg::TextureCubeMap::Face Cubemap::getFaceNum(float alt, float azimuth)
+{
+ if (alt > 45)
+ return osg::TextureCubeMap::POSITIVE_Z;
+ else if (alt < -45)
+ return osg::TextureCubeMap::NEGATIVE_Z;
+ if (azimuth < 45)
+ return osg::TextureCubeMap::POSITIVE_Y;
+ if (azimuth < 135)
+ return osg::TextureCubeMap::POSITIVE_X;
+ if (azimuth < 225)
+ return osg::TextureCubeMap::NEGATIVE_Y;
+ if (azimuth < 315)
+ return osg::TextureCubeMap::NEGATIVE_X;
+ return osg::TextureCubeMap::POSITIVE_Y;
+}
+
+CubemapSurface* Cubemap::getFace(float alt, float azimuth)
+{
+ osg::TextureCubeMap::Face face = getFaceNum(alt, azimuth);
+ return getFace(face);
+}
+
+bool Cubemap::isShadowed(double alt, double azimuth)
+{
+ CubemapSurface* face = getFace(alt, azimuth);
+ osg::Image* faceImage = face->Image();
+ osg::Vec3d sundir = Utils::solarAngle2Vector(alt, azimuth);
+ osg::Vec3d targetPos = face->m_pos + sundir * 10000;
+ osg::Vec3d screenPos = targetPos * face->m_viewProjMatrix;
+ double u = (screenPos.x() + 1.0) * 0.5;
+ double v = (screenPos.y() + 1.0) * 0.5;
+ osg::Vec4 color = faceImage->getColor(osg::Vec2(u, v));
+ return color.a() > 0.95;
+}
+
diff --git a/SolarEngine/Cubemap.h b/SolarEngine/Cubemap.h
new file mode 100644
index 0000000..fb0877c
--- /dev/null
+++ b/SolarEngine/Cubemap.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#ifdef _WIN32 || WIN32
+#include
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "RenderSurface.h"
+
+class CubemapSurface : public RenderSurface
+{
+public:
+ osg::Vec3d m_pos;//position of camera
+ osg::Vec3d m_dir;//viewing direction of camera
+ osg::Vec3d m_up;//the up vector
+ osg::Matrixd m_local2World;
+ osg::Matrixd m_viewProjMatrix;
+
+ CubemapSurface(int width, int height, GLenum internalFormat, GLenum sourceFormat, GLenum sourceType, bool allocateImage,
+ osg::Vec3d dir, osg::Vec3d up, std::string name);
+
+ void update();
+};
+
+class Cubemap : public osg::Group
+{
+private:
+ Cubemap() : osg::Group() { }
+public:
+ static Cubemap* create(int imageSize, osg::Node* scene = nullptr);
+ CubemapSurface* getFace(int face);
+ CubemapSurface* getFace(osg::TextureCubeMap::Face face);
+ osg::TextureCubeMap::Face getFaceNum(float alt, float azimuth);
+ CubemapSurface* getFace(float alt, float azimuth);
+ RenderSurface* toHemisphericalSurface();
+ osg::Image* toHemisphericalImage(int width, int height);
+ bool isShadowed(double alt, double azimuth);
+};
\ No newline at end of file
diff --git a/SolarEngine/CustomControls.cpp b/SolarEngine/CustomControls.cpp
new file mode 100644
index 0000000..1c52caa
--- /dev/null
+++ b/SolarEngine/CustomControls.cpp
@@ -0,0 +1,3043 @@
+/* -*-c++-*- */
+/* osgEarth - Geospatial SDK for OpenSceneGraph
+ * Copyright 2019 Pelican Mapping
+ * http://osgearth.org
+ *
+ * osgEarth is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see
+ */
+#include "CustomControls.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace osgEarth;
+using namespace osgEarth::Features;
+using namespace osgEarth::Symbology;
+using namespace osgEarth::Util;
+using namespace CustomControls;
+#define LC "[Controls] "
+
+// ---------------------------------------------------------------------------
+
+namespace
+{
+ void calculateRotatedSize( float w, float h, float angle_rad, float& out_w, float& out_h )
+ {
+ float x1 = -w/2, x2 = w/2, x3 = w/2, x4 = -w/2;
+ float y1 = h/2, y2 = h/2, y3 = -h/2, y4 = -h/2;
+
+ float cosa = cos(angle_rad);
+ float sina = sin(angle_rad);
+
+ float
+ x11 = x1*cosa + y1*sina,
+ y11 = -x1*sina + y1*cosa,
+ x21 = x2*cosa + y2*sina,
+ y21 = -x2*sina + y2*cosa,
+ x31 = x3*cosa + y3*sina,
+ y31 = -x3*sina + y3*cosa,
+ x41 = x4*cosa + y4*sina,
+ y41 = -x4*sina + y3*cosa;
+
+ float xmin = osg::minimum(x11, osg::minimum(x21, osg::minimum(x31, x41)));
+ float ymin = osg::minimum(y11, osg::minimum(y21, osg::minimum(y31, y41)));
+
+ float xmax = osg::maximum(x11, osg::maximum(x21, osg::maximum(x31, x41)));
+ float ymax = osg::maximum(y11, osg::maximum(y21, osg::maximum(y31, y41)));
+
+ out_w = xmax-xmin;
+ out_h = ymax-ymin;
+ }
+
+ void rot( float x, float y, const osg::Vec2f& c, float angle_rad, osg::Vec3f& out )
+ {
+ float cosa = cos(angle_rad);
+ float sina = sin(angle_rad);
+ out.x() = (c.x()-x)*cosa - (c.y()-y)*sina + c.x();
+ out.y() = (c.y()-y)*cosa + (c.x()-x)*sina + c.y();
+ out.z() = 0.0f;
+ }
+
+ // Convenience method to create safe Control geometry.
+ // Since Control geometry can change, we need to always set it
+ // to DYNAMIC data variance.
+ osg::Geometry* newGeometry()
+ {
+ osg::Geometry* geom = new osg::Geometry();
+ geom->setUseVertexBufferObjects( true );
+ geom->setUseDisplayList( false );
+ geom->setDataVariance( osg::Object::DYNAMIC );
+ return geom;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+float
+UVec2f::x( const osg::Vec2f& size ) const
+{
+ if ( _xunits == UNITS_PIXELS )
+ return _v[0];
+ else if ( _xunits == UNITS_FRACTION )
+ return _v[0] * size.x();
+ else // UNITS_INSET_PIXELS
+ return size.x() - _v[0] - 1.0f;
+}
+
+float
+UVec2f::x( const ControlContext& cx ) const
+{
+ return cx._vp ? x( osg::Vec2f(cx._vp->width(), cx._vp->height()) ) : _v[0];
+}
+
+float
+UVec2f::y( const osg::Vec2f& size ) const
+{
+ if ( _yunits == UNITS_PIXELS )
+ return _v[1];
+ else if ( _yunits == UNITS_FRACTION )
+ return _v[1] * size.y();
+ else // UNITS_INSET_PIXELS
+ return size.y() - _v[1] - 1.0f;
+}
+
+float
+UVec2f::y( const ControlContext& cx ) const
+{
+ return cx._vp ? y( osg::Vec2f(cx._vp->width(), cx._vp->height()) ) : _v[1];
+}
+
+UVec2f
+UVec2f::asPixels( const osg::Vec2f& size ) const
+{
+ return UVec2f( x(size), y(size), UNITS_PIXELS, UNITS_PIXELS );
+}
+
+UVec2f
+UVec2f::asPixels( const ControlContext& cx ) const
+{
+ return UVec2f( x(cx), y(cx), UNITS_PIXELS, UNITS_PIXELS );
+}
+
+
+// ---------------------------------------------------------------------------
+
+Control::Control()
+{
+ init();
+}
+
+Control::Control( const Alignment& halign, const Alignment& valign, const Gutter& padding )
+{
+ init();
+
+ setHorizAlign( halign );
+ setVertAlign( valign );
+ setPadding( padding );
+}
+
+void
+Control::init()
+{
+ setStateSet(getGeomStateSet());
+
+ _x.init(0);
+ _y.init(0);
+ _width.init(1);
+ _height.init(1);
+ _valign.init( ALIGN_NONE );
+ _halign.init( ALIGN_NONE );
+ _backColor.init( osg::Vec4(0,0,0,0) );
+ _foreColor.init( osg::Vec4(1,1,1,1) );
+ _activeColor.init( osg::Vec4(.4,.4,.4,1) );
+
+ _margin = Gutter(0);
+ _padding = Gutter(2);
+ _hfill = false;
+ _vfill = false;
+ _visible = true;
+ _active = false;
+ _absorbEvents = true;
+ _dirty = true;
+ _borderWidth = 1.0f;
+
+ _geode = new osg::Geode();
+ this->addChild( _geode );
+}
+
+// shared state set for control geometry
+osg::observer_ptr Control::s_geomStateSet;
+
+osg::ref_ptr
+Control::getGeomStateSet()
+{
+ osg::ref_ptr stateSet;
+ if (s_geomStateSet.lock(stateSet) == false)
+ {
+ static Threading::Mutex m;
+ Threading::ScopedMutexLock lock(m);
+ if (s_geomStateSet.lock(stateSet) == false)
+ {
+ s_geomStateSet = stateSet = new osg::StateSet();
+ VirtualProgram* vp = VirtualProgram::getOrCreate(stateSet.get());
+ vp->setName("Control::geomStateSet");
+ vp->setInheritShaders(false);
+ }
+ }
+ return stateSet;
+}
+
+void
+Control::setVisible( bool value ) {
+ if ( value != _visible ) {
+ _visible = value;
+ dirty();
+ }
+}
+
+void
+Control::setX( float value ) {
+ if ( value != _x.value() ) {
+ _x = value;
+ dirty();
+ }
+}
+
+void
+Control::setY( float value ) {
+ if ( value != _y.value() ) {
+ _y = value;
+ dirty();
+ }
+}
+
+void
+Control::setPosition( float x, float y ) {
+ setX( x );
+ setY( y );
+}
+
+void
+Control::setWidth( float value ) {
+ if ( value != _width.value() ) {
+ _width = value;
+ dirty();
+ }
+}
+
+void
+Control::setHeight( float value ) {
+ if ( value != _height.value() ) {
+ _height = value;
+ dirty();
+ }
+}
+
+void
+Control::setSize( float w, float h ) {
+ setWidth( w );
+ setHeight( h );
+}
+
+void
+Control::setMargin( const Gutter& value ) {
+ if ( value != _margin ) {
+ _margin = value;
+ dirty();
+ }
+}
+
+void
+Control::setMargin( Side side, float value ) {
+ switch(side) {
+ case SIDE_TOP:
+ if ( _margin.top() != value ) {
+ _margin.top() = value;
+ dirty();
+ }
+ break;
+ case SIDE_BOTTOM:
+ if ( _margin.bottom() != value ) {
+ _margin.bottom() = value;
+ dirty();
+ }
+ break;
+ case SIDE_LEFT:
+ if ( _margin.left() != value ) {
+ _margin.left() = value;
+ dirty();
+ }
+ break;
+ case SIDE_RIGHT:
+ if ( _margin.right() != value ) {
+ _margin.right() = value;
+ dirty();
+ }
+ break;
+ }
+}
+
+void
+Control::setPadding( const Gutter& value )
+{
+ if ( value != _padding ) {
+ _padding = value;
+ dirty();
+ }
+}
+
+void
+Control::setPadding( float value ) {
+ Gutter g(value);
+ if ( g != _padding ) {
+ _padding = g;
+ dirty();
+ }
+}
+
+void
+Control::setPadding( Side side, float value ) {
+ switch(side) {
+ case SIDE_TOP:
+ if ( _padding.top() != value ) {
+ _padding.top() = value;
+ dirty();
+ }
+ break;
+ case SIDE_BOTTOM:
+ if ( _padding.bottom() != value ) {
+ _padding.bottom() = value;
+ dirty();
+ }
+ break;
+ case SIDE_LEFT:
+ if ( _padding.left() != value ) {
+ _padding.left() = value;
+ dirty();
+ }
+ break;
+ case SIDE_RIGHT:
+ if ( _padding.right() != value ) {
+ _padding.right() = value;
+ dirty();
+ }
+ break;
+ }
+}
+
+void
+Control::setHorizAlign( const Alignment& value ) {
+ if ( !_halign.isSetTo( value ) ) {
+ _halign = value;
+ _x.unset(); // horiz align is mutex with abs positioning
+ dirty();
+ }
+}
+
+void
+Control::setVertAlign( const Alignment& value ) {
+ if ( !_valign.isSetTo( value ) ) {
+ _valign = value;
+ _y.unset(); // vert align is mutex with abs positioning
+ dirty();
+ }
+}
+
+void
+Control::setAlign(const Alignment& h, const Alignment& v) {
+ setHorizAlign( h );
+ setVertAlign ( v );
+}
+
+void
+Control::setHorizFill( bool hfill, float minWidth ) {
+ if ( hfill != _hfill || !_width.isSetTo(minWidth) ) { //minWidth != _width.value() ) {
+ _hfill = hfill;
+ if ( hfill )
+ setWidth( minWidth );
+ else
+ _width.unset();
+ dirty();
+ }
+}
+
+void
+Control::setVertFill( bool vfill, float minHeight ) {
+ if ( vfill != _hfill || minHeight != _height.value() ) {
+ _vfill = vfill;
+ if ( vfill )
+ setHeight( minHeight );
+ else
+ _height.unset();
+ dirty();
+ }
+}
+
+bool
+Control::parentIsVisible() const
+{
+ bool visible = true;
+
+ // ------------------------------------------------------------------------
+ // -- If visible through any parent, consider it visible and return true --
+ // -- Also visible if the parent is not a control (is a top-level) --
+ // ------------------------------------------------------------------------
+ for( unsigned i=0; i( getParent(i) );
+
+ // ----------------------------------------
+ // -- Parent not a control, keep looking --
+ // ----------------------------------------
+ if( c == NULL )
+ continue;
+
+ // -----------------------------------------
+ // -- If this path is visible, we're done --
+ // -----------------------------------------
+ if( c->visible() && c->parentIsVisible() )
+ {
+ return true;
+ }
+ else
+ {
+ // ---------------------------------------------
+ // -- If their is a parent control, but it's --
+ // -- not visible, change our assumption but --
+ // -- keep looking at other parent controls --
+ // ---------------------------------------------
+ visible = false;
+ }
+ }
+
+ return visible;
+}
+
+void
+Control::setOpacity(float a) {
+ osg::Vec4f c = _foreColor.get();
+ c.a() = a;
+ setForeColor(c);
+}
+
+void
+Control::setForeColor( const osg::Vec4f& value ) {
+ if ( value != _foreColor.value() ) {
+ _foreColor = value;
+ dirty();
+ }
+}
+
+void
+Control::setBackColor( const osg::Vec4f& value ) {
+ if ( value != _backColor.value() ) {
+ _backColor = value;
+ dirty();
+ }
+}
+
+void
+Control::setActiveColor( const osg::Vec4f& value ) {
+ if ( value != _activeColor.value() ) {
+ _activeColor = value;
+ if ( _active )
+ dirty();
+ }
+}
+
+void
+Control::setBorderColor( const osg::Vec4f& value ) {
+ if ( value != _borderColor.value() ) {
+ _borderColor = value;
+ dirty();
+ }
+}
+
+void
+Control::addEventHandler( ControlEventHandler* handler, bool fire )
+{
+ _eventHandlers.push_back( handler );
+ if ( fire )
+ fireValueChanged( handler );
+}
+
+void
+Control::setActive( bool value ) {
+ if ( value != _active ) {
+ _active = value;
+ if ( _activeColor.isSet() )
+ dirty();
+ }
+}
+
+void
+Control::setBorderWidth( float value ) {
+ if ( value != _borderWidth ) {
+ _borderWidth = value;
+ dirty();
+ }
+}
+
+namespace
+{
+ void dirtyParent(osg::Group* p)
+ {
+ if ( p )
+ {
+ Control* c = dynamic_cast( p );
+ if ( c )
+ {
+ c->dirty();
+ }
+ else if ( dynamic_cast( p ) )
+ {
+ return;
+ }
+ else
+ {
+ for( unsigned i=0; igetNumParents(); ++i )
+ {
+ dirtyParent( p->getParent(i) );
+ }
+ }
+ }
+ }
+}
+
+void
+Control::dirty()
+{
+ _dirty = true;
+ for(unsigned i=0; i= _renderPos.x() - padding().left() && x <= _renderPos.x() - padding().left() + _renderSize.x() &&
+ y >= _renderPos.y() - padding().top() && y <= _renderPos.y() - padding().top() + _renderSize.y();
+}
+
+void
+Control::draw(const ControlContext& cx)
+{
+ clearGeode();
+
+ // by default, rendering a Control directly results in a colored quad. Usually however
+ // you will not render a Control directly, but rather one of its subclasses.
+ if ( visible() && parentIsVisible() )
+ {
+ if (_renderSize.x() > 0 && _renderSize.y() > 0)
+ {
+ float vph = cx._vp->height();
+
+ // draw the background poly:
+ if ((_backColor.isSet() && _backColor->a() > 0.0f) ||
+ (_activeColor.isSet() && _activeColor->a() > 0.0f && _active))
+ {
+ _geom = newGeometry();
+
+ float rx = _renderPos.x() - padding().left();
+ float ry = _renderPos.y() - padding().top();
+
+ osg::Vec3Array* verts = new osg::Vec3Array(6);
+ _geom->setVertexArray( verts );
+ (*verts)[0].set( rx, vph - ry, 0 );
+ (*verts)[1].set( rx, vph - ry - _renderSize.y(), 0 );
+ (*verts)[2].set( rx + _renderSize.x(), vph - ry - _renderSize.y(), 0 );
+ (*verts)[3].set( (*verts)[2] );
+ (*verts)[4].set( rx + _renderSize.x(), vph - ry, 0 );
+ (*verts)[5].set( (*verts)[0] );
+
+ _geom->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLES, 0, 6 ) );
+
+ osg::Vec4Array* colors = new osg::Vec4Array(osg::Array::BIND_OVERALL, 1);
+ (*colors)[0] = _active && _activeColor.isSet() ? _activeColor.value() : _backColor.value();
+ _geom->setColorArray( colors );
+
+ getGeode()->addDrawable( _geom.get() );
+ }
+
+ // draw the border:
+ if ( _borderColor.isSet() && _borderColor->a() > 0.0f && _borderWidth > 0.0f )
+ {
+ float rx = _renderPos.x() - padding().left();
+ float ry = _renderPos.y() - padding().top();
+
+ osg::ref_ptr verts = new osg::Vec3Array(5);
+ (*verts)[0].set( rx, vph - ry, 0 );
+ (*verts)[1].set( rx, vph - ry - _renderSize.y(), 0 );
+ (*verts)[2].set( rx + _renderSize.x(), vph - ry - _renderSize.y(), 0 );
+ (*verts)[3].set( rx + _renderSize.x(), vph - ry, 0 );
+ (*verts)[4].set( rx, vph - ry, 0 );
+
+ Stroke stroke;
+ stroke.color() = *_borderColor;
+ stroke.width() = _borderWidth;
+ stroke.lineCap() = Stroke::LINECAP_SQUARE;
+ stroke.lineJoin() = Stroke::LINEJOIN_MITRE;
+
+ PolygonizeLinesOperator makeBorder(stroke);
+ osg::Geometry* geom = makeBorder( verts.get(), 0L );
+
+ getGeode()->addDrawable( geom );
+ }
+ }
+
+ _dirty = false;
+ }
+}
+
+bool
+Control::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, ControlContext& cx )
+{
+ bool handled = false;
+
+ if( !visible() || !parentIsVisible() )
+ return false;
+
+ if ( _eventHandlers.size() > 0 )
+ {
+ handled = true;
+
+ if ( !_active )
+ {
+ if ( ea.getEventType() == osgGA::GUIEventAdapter::MOVE )
+ {
+ cx._active.push( this );
+ }
+ }
+ else
+ {
+ if ( ea.getEventType() == osgGA::GUIEventAdapter::RELEASE )
+ {
+ float canvasY = cx._vp->height() - (ea.getY() - cx._view->getCamera()->getViewport()->y());
+ float canvasX = ea.getX() - cx._view->getCamera()->getViewport()->x();
+
+ for( ControlEventHandlerList::const_iterator i = _eventHandlers.begin(); i != _eventHandlers.end(); ++i )
+ {
+ osg::Vec2f relXY( canvasX - _renderPos.x(), canvasY - _renderPos.y() );
+ i->get()->onClick( this, relXY, ea.getButtonMask() );
+ aa.requestRedraw();
+ }
+ }
+ }
+ }
+
+ return handled || _absorbEvents;
+}
+
+// ---------------------------------------------------------------------------
+
+namespace
+{
+ // override osg Text to get at some of the internal properties
+ struct LabelText : public osgEarth::Text
+ {
+ LabelText() : osgEarth::Text()
+ {
+ setDataVariance(osg::Object::DYNAMIC);
+ }
+ const osg::BoundingBox& getTextBB() const { return _textBB; }
+ const osg::Matrix& getATMatrix(int contextID) const {
+ #if OSG_MIN_VERSION_REQUIRED(3,5,6)
+ return _matrix;
+ #else
+ return _autoTransformCache[contextID]._matrix;
+ #endif
+ }
+ };
+
+ // writes a value to a label
+ struct ValueLabelHandler : public ControlEventHandler
+ {
+ osg::observer_ptr _label;
+ ValueLabelHandler( LabelControl* label ) : _label(label) { }
+ void onValueChanged( class Control* control, bool value ) {
+ if ( _label.valid() ) _label->setText( Stringify() << value ); }
+ void onValueChanged( class Control* control, double value ) {
+ if ( _label.valid() ) _label->setText( Stringify() << std::setprecision(16) << value ); }
+ void onValueChanged( class Control* control, float value ) {
+ if ( _label.valid() ) _label->setText( Stringify() << value ); }
+ void onValueChanged( class Control* control, int value ) {
+ if ( _label.valid() ) _label->setText( Stringify() << value ); }
+ void onValueChanged( class Control* control, const osg::Vec3f& value ) {
+ if ( _label.valid() ) _label->setText( Stringify() << std::setprecision(8) << value.x() << ", " << value.y() << ", " << value.z() ); }
+ void onValueChanged( class Control* control, const osg::Vec2f& value ) {
+ if ( _label.valid() ) _label->setText( Stringify() << std::setprecision(8) << value.x() << ", " << value.y() ); }
+ void onValueChanged( class Control* control, const osg::Vec3d& value ) {
+ if ( _label.valid() ) _label->setText( Stringify() << std::setprecision(16) << value.x() << ", " << value.y() << ", " << value.z() ); }
+ void onValueChanged( class Control* control, const osg::Vec2d& value ) {
+ if ( _label.valid() ) _label->setText( Stringify() << std::setprecision(16) << value.x() << ", " << value.y() ); }
+ void onValueChanged( class Control* control, const std::string& value ) {
+ if ( _label.valid() ) _label->setText( value ); }
+ };
+}
+
+LabelControl::LabelControl(const std::string& text,
+ float fontSize,
+ const osg::Vec4f& foreColor):
+_text ( text ),
+_fontSize( fontSize ),
+_encoding( osgText::String::ENCODING_UNDEFINED ),
+_backdropType( osgText::Text::OUTLINE ),
+_backdropImpl( osgText::Text::NO_DEPTH_BUFFER ),
+_backdropOffset( 0.03f )
+{
+ //setStateSet(textStateSet());
+ setFont( Registry::instance()->getDefaultFont() );
+ setForeColor( foreColor );
+ setBackColor( osg::Vec4f(0,0,0,0) );
+}
+
+LabelControl::LabelControl(const std::string& text,
+ const osg::Vec4f& foreColor,
+ float fontSize ):
+_text ( text ),
+_fontSize( fontSize ),
+_encoding( osgText::String::ENCODING_UNDEFINED ),
+_backdropType( osgText::Text::OUTLINE ),
+_backdropImpl( osgText::Text::NO_DEPTH_BUFFER ),
+_backdropOffset( 0.03f )
+{
+ setFont( Registry::instance()->getDefaultFont() );
+ setForeColor( foreColor );
+ setBackColor( osg::Vec4f(0,0,0,0) );
+}
+
+LabelControl::LabelControl(Control* valueControl,
+ float fontSize,
+ const osg::Vec4f& foreColor):
+_fontSize( fontSize ),
+_encoding( osgText::String::ENCODING_UNDEFINED ),
+_backdropType( osgText::Text::OUTLINE ),
+_backdropImpl( osgText::Text::NO_DEPTH_BUFFER ),
+_backdropOffset( 0.03f )
+{
+ setFont( Registry::instance()->getDefaultFont() );
+ setForeColor( foreColor );
+ setBackColor( osg::Vec4f(0,0,0,0) );
+
+ if ( valueControl )
+ valueControl->addEventHandler( new ValueLabelHandler(this), true );
+}
+
+LabelControl::LabelControl(Control* valueControl,
+ const osg::Vec4f& foreColor,
+ float fontSize ):
+_fontSize( fontSize ),
+_encoding( osgText::String::ENCODING_UNDEFINED ),
+_backdropType( osgText::Text::OUTLINE ),
+_backdropImpl( osgText::Text::NO_DEPTH_BUFFER ),
+_backdropOffset( 0.03f )
+{
+ setFont( Registry::instance()->getDefaultFont() );
+ setForeColor( foreColor );
+ setBackColor( osg::Vec4f(0,0,0,0) );
+
+ if ( valueControl )
+ valueControl->addEventHandler( new ValueLabelHandler(this), true );
+}
+
+
+void
+LabelControl::setText( const std::string& value )
+{
+ if ( value != _text ) {
+ _text = value;
+ dirty();
+ }
+}
+
+void
+LabelControl::setEncoding( osgText::String::Encoding value )
+{
+ if ( value != _encoding ) {
+ _encoding = value;
+ dirty();
+ }
+}
+
+void
+LabelControl::setFont( osgText::Font* value )
+{
+ if ( value != _font.get() ) {
+ _font = value;
+ dirty();
+ }
+}
+
+void
+LabelControl::setFontSize( float value )
+{
+ if ( value != _fontSize ) {
+ _fontSize = value;
+ dirty();
+ }
+}
+
+void
+LabelControl::setHaloColor( const osg::Vec4f& value )
+{
+ if ( !_haloColor.isSet() || *_haloColor != value ) {
+ _haloColor = value;
+ dirty();
+ }
+}
+
+void
+LabelControl::setTextBackdropImplementation(osgText::Text::BackdropImplementation value)
+{
+ if( _backdropImpl != value ) {
+ _backdropImpl = value;
+ dirty();
+ }
+}
+
+void
+LabelControl::setTextBackdropType(osgText::Text::BackdropType value)
+{
+ if( _backdropType != value ) {
+ _backdropType = value;
+ dirty();
+ }
+}
+
+void
+LabelControl::setTextBackdropOffset(float offsetValue)
+{
+ if ( offsetValue != _backdropOffset ) {
+ _backdropOffset = offsetValue;
+ dirty();
+ }
+}
+
+void
+LabelControl::calcSize(const ControlContext& cx, osg::Vec2f& out_size)
+{
+ if ( visible() == true )
+ {
+ // we have to create the drawable during the layout pass so we can calculate its size.
+ LabelText* t = new LabelText();
+
+ t->setText( _text, _encoding );
+ // yes, object coords. screen coords won't work because the bounding box will be wrong.
+ t->setCharacterSizeMode( osgText::Text::OBJECT_COORDS );
+ t->setCharacterSize( _fontSize );
+
+ // always align to top. layout alignment gets calculated layer in Control::calcPos().
+ t->setAlignment( osgText::Text::LEFT_TOP );
+ t->setColor( foreColor().value() );
+
+ // set up the font.
+ if ( _font.valid() )
+ t->setFont( _font.get() );
+
+ // set up the backdrop halo:
+ if ( haloColor().isSet() )
+ {
+ t->setBackdropType( _backdropType );
+ t->setBackdropImplementation( _backdropImpl );
+ t->setBackdropOffset( _backdropOffset );
+ t->setBackdropColor( haloColor().value() );
+ }
+
+ osg::BoundingBox bbox = t->getBoundingBox(); //t->getTextBB();
+ if ( cx._viewContextID != ~0u )
+ {
+ //the Text's autoTransformCache matrix puts some mojo on the bounding box
+ osg::Matrix m = t->getATMatrix( cx._viewContextID );
+ _bmin = osg::Vec3( bbox.xMin(), bbox.yMin(), bbox.zMin() ) * m;
+ _bmax = osg::Vec3( bbox.xMax(), bbox.yMax(), bbox.zMax() ) * m;
+ }
+ else
+ {
+ _bmin = osg::Vec3( bbox.xMin(), bbox.yMin(), bbox.zMin() );
+ _bmax = osg::Vec3( bbox.xMax(), bbox.yMax(), bbox.zMax() );
+ }
+
+ _renderSize.set(
+ (_bmax.x() - _bmin.x()) + padding().x(),
+ (_bmax.y() - _bmin.y()) + padding().y() );
+
+ // If width explicitly set and > measured width of label text - use it.
+ if (width().isSet() && width().get() > _renderSize.x()) _renderSize.x() = width().get();
+
+ _drawable = t;
+
+ out_size.set(
+ margin().x() + _renderSize.x(),
+ margin().y() + _renderSize.y() );
+ }
+ else
+ {
+ out_size.set(0,0);
+ }
+}
+
+void
+LabelControl::draw( const ControlContext& cx )
+{
+ Control::draw( cx );
+
+ if ( _drawable.valid() && visible() && parentIsVisible() )
+ {
+ float vph = cx._vp->height();
+
+ LabelText* t = static_cast( _drawable.get() );
+ osg::BoundingBox bbox = t->getTextBB();
+ t->setPosition( osg::Vec3( _renderPos.x(), vph - _renderPos.y(), 0 ) );
+ getGeode()->addDrawable( _drawable.get() );
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+ButtonControl::ButtonControl(const std::string& text,
+ float fontSize,
+ const osg::Vec4f& foreColor,
+ const osg::Vec4f& backColor,
+ const osg::Vec4f& activeColor,
+ ControlEventHandler* handler) :
+LabelControl(text, fontSize, foreColor)
+{
+ setBackColor( backColor );
+ setActiveColor( activeColor );
+ setPadding( 6.0f );
+ if ( handler )
+ this->addEventHandler( handler );
+}
+
+ButtonControl::ButtonControl(const std::string& text,
+ const osg::Vec4f& foreColor,
+ const osg::Vec4f& backColor,
+ const osg::Vec4f& activeColor,
+ float fontSize,
+ ControlEventHandler* handler) :
+LabelControl(text, foreColor, fontSize)
+{
+ setBackColor( backColor );
+ setActiveColor( activeColor );
+ setPadding( 6.0f );
+ if ( handler )
+ this->addEventHandler( handler );
+}
+
+ButtonControl::ButtonControl(const std::string& text,
+ ControlEventHandler* handler) :
+LabelControl(text)
+{
+ setForeColor( Color::White );
+ setBackColor( Color::DarkGray );
+ setActiveColor( Color::Blue );
+ setPadding( 6.0f );
+ if ( handler )
+ this->addEventHandler( handler );
+}
+
+// ---------------------------------------------------------------------------
+
+ImageControl::ImageControl( osg::Image* image ) :
+_rotation ( 0.0, Units::RADIANS ),
+_fixSizeForRot( false ),
+_opacity ( 1.0f )
+{
+ setStateSet(getImageStateSet());
+ setImage( image );
+}
+
+ImageControl::ImageControl( osg::Texture* texture ) :
+_rotation ( 0.0, Units::RADIANS ),
+_fixSizeForRot( false ),
+_opacity ( 1.0f )
+{
+ setStateSet(getImageStateSet());
+ setTexture( texture );
+}
+
+// shared state set for image geometry
+osg::observer_ptr ImageControl::s_imageStateSet;
+
+osg::ref_ptr
+ImageControl::getImageStateSet()
+{
+ osg::ref_ptr stateSet;
+ if (s_imageStateSet.lock(stateSet) == false)
+ {
+ static Threading::Mutex m;
+ Threading::ScopedMutexLock lock(m);
+ if (s_imageStateSet.lock(stateSet) == false)
+ {
+ s_imageStateSet = stateSet = new osg::StateSet();
+
+ const char* vert =
+ "#version " GLSL_VERSION_STR "\n"
+ "out vec2 oe_Controls_texCoord; \n"
+ "void oe_Controls_renderImageVert(inout vec4 vert) { \n"
+ " oe_Controls_texCoord = gl_MultiTexCoord0.xy; \n"
+ "}\n";
+
+ const char* frag =
+ "#version " GLSL_VERSION_STR "\n"
+ "in vec2 oe_Controls_texCoord; \n"
+ "uniform sampler2D oe_Controls_tex; \n"
+ "void oe_Controls_renderImageFrag(inout vec4 color) { \n"
+ " vec4 texel = texture(oe_Controls_tex, oe_Controls_texCoord); \n"
+ " color = color * texel; \n"
+ "}\n";
+
+ VirtualProgram* vp = VirtualProgram::getOrCreate(stateSet.get());
+ vp->setName("Control::imageStateSet");
+ vp->setInheritShaders(false);
+ vp->setFunction("oe_Controls_renderImageVert", vert, ShaderComp::LOCATION_VERTEX_MODEL);
+ vp->setFunction("oe_Controls_renderImageFrag", frag, ShaderComp::LOCATION_FRAGMENT_COLORING);
+ }
+ }
+
+ return stateSet;
+}
+
+void
+ImageControl::setImage( osg::Image* image )
+{
+ if ( image != _image.get() ) {
+ _image = image;
+ _texture = 0L;
+ dirty();
+ }
+}
+
+void
+ImageControl::setTexture(osg::Texture* texture)
+{
+ if ( texture != _texture.get() ) {
+ _texture = texture;
+ _image = 0L;
+ dirty();
+ }
+}
+
+void
+ImageControl::setRotation( const Angular& angle )
+{
+ if ( angle != _rotation ) {
+ _rotation = angle;
+ dirty();
+ }
+}
+
+void
+ImageControl::setFixSizeForRotation( bool value )
+{
+ if ( _fixSizeForRot != value ) {
+ _fixSizeForRot = value;
+ dirty();
+ }
+}
+
+void
+ImageControl::calcSize(const ControlContext& cx, osg::Vec2f& out_size)
+{
+ if ( visible() == true )
+ {
+ const osg::Vec2i imageSize = calculateImageSize();
+ _renderSize.set( imageSize.x(), imageSize.y() );
+
+ //if there's a rotation angle, rotate
+ float rot = _fixSizeForRot ? osg::PI_4 : _rotation.as(Units::RADIANS);
+ if ( rot != 0.0f )
+ {
+ calculateRotatedSize(
+ _renderSize.x(), _renderSize.y(),
+ rot,
+ _renderSize.x(), _renderSize.y() );
+ }
+
+ out_size.set(
+ margin().left() + margin().right() + _renderSize.x(),
+ margin().top() + margin().bottom() + _renderSize.y() );
+
+ //_dirty = false;
+ }
+ else
+ {
+ out_size.set(0,0);
+ }
+}
+
+osg::Vec2i
+ImageControl::calculateImageSize() const
+{
+ //First try the explicit settings
+ if (width().isSet() && height().isSet())
+ {
+ return osg::Vec2i(width().value(), height().value());
+ }
+ //Second try the size of the image
+ else if (_image.valid())
+ {
+ return osg::Vec2i(_image->s(), _image->t());
+ }
+ //Next try the size of the texture itself
+ else if (_texture.valid() && _texture->getTextureWidth() > 0)
+ {
+ return osg::Vec2i(_texture->getTextureWidth(), _texture->getTextureHeight());
+ }
+ //Try the size of the texture's image
+ else if (_texture.valid() && _texture->getImage(0))
+ {
+ const osg::Image* image = _texture->getImage(0);
+ return osg::Vec2i(image->s(), image->t());
+ }
+ //Lastly just use the default values for width and height
+ return osg::Vec2i(width().value(), height().value());
+}
+
+void
+ImageControl::draw( const ControlContext& cx )
+{
+ Control::draw( cx );
+
+ if ( !visible() || !parentIsVisible() )
+ return;
+
+ if ( !_texture.valid() )
+ {
+ if ( !_image.valid() )
+ return;
+
+ _texture = new osg::Texture2D( _image.get() );
+ _texture->setResizeNonPowerOfTwoHint( false );
+ _texture->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR );
+ _texture->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR );
+ }
+ const osg::Vec2i imageSize = calculateImageSize();
+
+ //TODO: this is not precisely correct..images get deformed slightly..
+ osg::Geometry* g = newGeometry();
+
+ float rx = osg::round( _renderPos.x() );
+ float ry = osg::round( _renderPos.y() );
+ float vph = cx._vp->height();
+
+ osg::Vec3Array* verts = new osg::Vec3Array(6);
+ g->setVertexArray( verts );
+
+ if ( _rotation.as(Units::RADIANS) != 0.0f || _fixSizeForRot == true )
+ {
+ osg::Vec2f rc( rx+_renderSize.x()/2, (vph-ry)-_renderSize.y()/2 );
+ float ra = osg::PI - _rotation.as(Units::RADIANS);
+
+ rx += 0.5*_renderSize.x() - 0.5*(float)imageSize.x();
+ ry += 0.5*_renderSize.y() - 0.5*(float)imageSize.y();
+
+ rot( rx, vph-ry, rc, ra, (*verts)[0] );
+ rot( rx, vph-ry-imageSize.y(), rc, ra, (*verts)[1] );
+ rot( rx+imageSize.x(), vph-ry-imageSize.y(), rc, ra, (*verts)[2] );
+ (*verts)[3].set( (*verts)[2] );
+ rot( rx+imageSize.x(), vph-ry, rc, ra, (*verts)[4] );
+ (*verts)[5].set( (*verts)[0] );
+ }
+ else
+ {
+ (*verts)[0].set( rx, vph - ry, 0 );
+ (*verts)[1].set( rx, vph - ry - _renderSize.y(), 0 );
+ (*verts)[2].set( rx + _renderSize.x(), vph - ry - _renderSize.y(), 0 );
+ (*verts)[3].set( (*verts)[2] );
+ (*verts)[4].set( rx + _renderSize.x(), vph - ry, 0 );
+ (*verts)[5].set( (*verts)[0] );
+ }
+
+ g->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLES, 0, 6 ) );
+
+ osg::Vec4Array* c = new osg::Vec4Array(osg::Array::BIND_OVERALL, 1);
+ (*c)[0] = osg::Vec4f(1,1,1,1);
+ g->setColorArray( c );
+
+ bool flip = false;
+ if ( _image.valid() )
+ flip = (_image->getOrigin()==osg::Image::TOP_LEFT);
+ else if ( _texture->getImage(0) )
+ flip = (_texture->getImage(0)->getOrigin() == osg::Image::TOP_LEFT);
+
+ osg::Vec2Array* t = new osg::Vec2Array(6);
+
+ (*t)[0].set( 0, flip? 0 : 1 );
+ (*t)[1].set( 0, flip? 1 : 0 );
+ (*t)[2].set( 1, flip? 1 : 0 );
+ (*t)[3].set( (*t)[2]);
+ (*t)[4].set( 1, flip? 0 : 1 );
+ (*t)[5].set( (*t)[0] );
+
+ g->setTexCoordArray( 0, t );
+
+ osg::StateSet* ss = g->getOrCreateStateSet();
+
+ ss->setTextureAttributeAndModes( 0, _texture.get(), osg::StateAttribute::ON );
+ ss->addUniform(new osg::Uniform("oe_Controls_tex", (int)0));
+
+ getGeode()->addDrawable( g );
+
+ _dirty = false;
+}
+
+CustomImageControl::CustomImageControl(osg::Image* image)
+{
+ setStateSet(new osg::StateSet);
+ _rotation = Angular(0.0, Units::RADIANS);
+ _fixSizeForRot = false;
+ _opacity = 1.0f;
+ setImage(image);
+}
+
+CustomImageControl::CustomImageControl(osg::Texture* texture)
+{
+ setStateSet(new osg::StateSet);
+ _rotation = Angular(0.0, Units::RADIANS);
+ _fixSizeForRot = false;
+ _opacity = 1.0f;
+ setTexture(texture);
+}
+
+// ---------------------------------------------------------------------------
+static HSliderControl* _dragObject = nullptr;
+
+HSliderControl::HSliderControl( float min, float max, float value, ControlEventHandler* handler) :
+_min(min),
+_max(max),
+_value(value)
+{
+ setHorizFill( true );
+ setVertAlign( ALIGN_CENTER );
+ setHeight( 20.0f );
+
+ if ( handler )
+ addEventHandler( handler );
+}
+
+void
+HSliderControl::fireValueChanged( ControlEventHandler* oneHandler )
+{
+ if ( oneHandler )
+ {
+ oneHandler->onValueChanged( this, _value );
+ }
+ else
+ {
+ for( ControlEventHandlerList::const_iterator i = _eventHandlers.begin(); i != _eventHandlers.end(); ++i )
+ {
+ i->get()->onValueChanged( this, _value );
+ }
+ }
+}
+
+void
+HSliderControl::setValue( float value, bool notify )
+{
+ if ( value != _value )
+ {
+ _value = value;
+ if ( notify )
+ fireValueChanged();
+ dirty();
+ }
+}
+
+void
+HSliderControl::setMin( float min, bool notify )
+{
+ if ( min != _min )
+ {
+ _min = min;
+ if ( _min >= _max )
+ _max = _min+1.0f;
+
+ if ( _value < _min || _value > _max )
+ {
+ _value = _min;
+ if ( notify )
+ fireValueChanged();
+ }
+ dirty();
+ }
+}
+
+void
+HSliderControl::setMax( float max, bool notify )
+{
+ if ( max != _max )
+ {
+ _max = max;
+ if ( _max <= _min )
+ _max = _min+1.0f;
+
+ if ( _value < _min || _value > _max )
+ {
+ _value = _max;
+ if ( notify )
+ fireValueChanged();
+ }
+ dirty();
+ }
+}
+
+void
+HSliderControl::draw( const ControlContext& cx )
+{
+ Control::draw( cx );
+
+ if ( visible() && parentIsVisible())
+ {
+ osg::ref_ptr g = newGeometry();
+
+ float rx = osg::round( _renderPos.x() );
+ float ry = osg::round( _renderPos.y() );
+ float rw = osg::round( _renderSize.x() - padding().x() );
+ float rh = osg::round( _renderSize.y() - padding().y() );
+
+ if ( rw > 0.0f && rh > 0.0f )
+ {
+ float vph = cx._vp->height();
+
+ osg::Vec3Array* verts = new osg::Vec3Array(10);
+ g->setVertexArray( verts );
+
+ (*verts)[0].set( rx, vph - ry, 0 );
+ (*verts)[1].set( rx, vph - (ry + rh), 0 );
+ (*verts)[2].set( rx + rw, vph - (ry + rh), 0 );
+ (*verts)[3].set( rx + rw, vph - ry, 0 );
+ g->addPrimitiveSet( new osg::DrawArrays( GL_LINE_LOOP, 0, 4 ) );
+
+ float hx = rx + rw * ( (_value-_min)/(_max-_min) );
+
+ (*verts)[4].set( hx-4, vph - ry + 3, 0 );
+ (*verts)[5].set( hx-4, vph - (ry + rh + 3), 0 );
+ (*verts)[6].set( hx+4, vph - (ry + rh + 3), 0 );
+ (*verts)[7].set( (*verts)[6] );
+ (*verts)[8].set( hx+4, vph - ry + 3, 0 );
+ (*verts)[9].set( (*verts)[4] );
+
+ g->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLES, 4, 6) );
+
+ osg::Vec4Array* c = new osg::Vec4Array(osg::Array::BIND_OVERALL, 1);
+ (*c)[0] = *foreColor();
+ g->setColorArray( c );
+
+ getGeode()->addDrawable( g.get() );
+ }
+ }
+}
+
+bool
+HSliderControl::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, ControlContext& cx )
+{
+ if( !visible() || !parentIsVisible())
+ return false;
+ if (ea.getEventType() == osgGA::GUIEventAdapter::PUSH && ea.getButtonMask() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
+ {
+ _dragObject = this;
+ }
+ else if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButtonMask() == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON)
+ {
+ _dragObject = nullptr;
+ }
+ else if (ea.getEventType() == osgGA::GUIEventAdapter::DRAG && _dragObject == this)
+ {
+ float canvasX = ea.getX() - cx._view->getCamera()->getViewport()->x();
+ float relX = canvasX - _renderPos.x();
+
+ if ( _min < _max )
+ setValue( osg::clampBetween(_min + (_max-_min) * ( relX / width().value()), _min, _max) );
+ else
+ setValue( osg::clampBetween(_min - (_min-_max) * ( relX / width().value()), _max, _min) );
+
+ aa.requestRedraw();
+
+ return true;
+ }
+ return Control::handle( ea, aa, cx );
+}
+
+// ---------------------------------------------------------------------------
+
+CheckBoxControl::CheckBoxControl( bool value ) :
+_value( value )
+{
+ setWidth( 16 );
+ setHeight( 16 );
+}
+
+CheckBoxControl::CheckBoxControl( bool value, ControlEventHandler* handler ) :
+_value( value )
+{
+ this->addEventHandler( handler );
+ setWidth( 16 );
+ setHeight( 16 );
+}
+
+void
+CheckBoxControl::fireValueChanged( ControlEventHandler* oneHandler )
+{
+ if ( oneHandler )
+ {
+ oneHandler->onValueChanged( this, _value );
+ }
+ else
+ {
+ for( ControlEventHandlerList::const_iterator i = _eventHandlers.begin(); i != _eventHandlers.end(); ++i )
+ {
+ i->get()->onValueChanged( this, _value );
+ }
+ }
+}
+
+void
+CheckBoxControl::setValue( bool value, bool notify )
+{
+ if ( value != _value )
+ {
+ _value = value;
+ if (notify)
+ fireValueChanged();
+ dirty();
+ }
+}
+
+void
+CheckBoxControl::draw( const ControlContext& cx )
+{
+ Control::draw( cx );
+
+ if ( visible() && parentIsVisible() )
+ {
+ osg::Geometry* g = newGeometry();
+
+ float rx = osg::round( _renderPos.x() );
+ float ry = osg::round( _renderPos.y() );
+ float rw = _renderSize.x() - padding().x();
+ float rh = _renderSize.y() - padding().y();
+ float vph = cx._vp->height(); // - padding().bottom();
+
+ osg::Vec3Array* verts = new osg::Vec3Array(4);
+ g->setVertexArray( verts );
+
+ (*verts)[0].set( rx, vph - ry, 0 );
+ (*verts)[1].set( rx + rw, vph - ry, 0 );
+ (*verts)[2].set( rx + rw, vph - (ry + rh), 0 );
+ (*verts)[3].set( rx, vph - (ry + rh), 0 );
+
+ g->addPrimitiveSet( new osg::DrawArrays( GL_LINE_LOOP, 0, 4 ) );
+
+ if ( _value )
+ {
+ osg::DrawElementsUByte* e = new osg::DrawElementsUByte( GL_LINES );
+ e->push_back( 0 );
+ e->push_back( 2 );
+ e->push_back( 1 );
+ e->push_back( 3 );
+ g->addPrimitiveSet( e );
+ }
+
+ osg::Vec4Array* c = new osg::Vec4Array(osg::Array::BIND_OVERALL, 1);
+ (*c)[0] = *foreColor();
+ g->setColorArray( c );
+
+ getGeode()->addDrawable( g );
+ }
+}
+
+bool
+CheckBoxControl::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, ControlContext& cx )
+{
+ if( !visible() || !parentIsVisible() )
+ return false;
+
+ if ( ea.getEventType() == osgGA::GUIEventAdapter::PUSH )
+ {
+ setValue( !_value );
+ aa.requestRedraw();
+ return true;
+ }
+ return Control::handle( ea, aa, cx );
+}
+
+// ---------------------------------------------------------------------------
+
+Frame::Frame()
+{
+ setPadding( 0 );
+}
+
+void
+Frame::calcPos(const ControlContext& context, const osg::Vec2f& cursor, const osg::Vec2f& parentSize)
+{
+ _renderPos = cursor;
+}
+
+void
+Frame::draw( const ControlContext& cx )
+{
+ if ( !getImage() || getImage()->s() != _renderSize.x() || getImage()->t() != _renderSize.y() )
+ {
+ // a simple colored border frame
+ osg::ref_ptr geom = new Ring();
+ geom->push_back( osg::Vec3d( 0, 0, 0 ) );
+ geom->push_back( osg::Vec3d( _renderSize.x()-1, 0, 0 ) );
+ geom->push_back( osg::Vec3d( _renderSize.x()-1, _renderSize.y()-1, 0 ) );
+ geom->push_back( osg::Vec3d( 0, _renderSize.y()-1, 0 ) );
+
+ Style style;
+ LineSymbol* line = style.getOrCreate();
+ line->stroke()->color() = Color::White;
+ line->stroke()->width() = 2.5f;
+ GeometryRasterizer ras( (int)_renderSize.x(), (int)_renderSize.y(), style );
+ ras.draw( geom.get() );
+
+ osg::Image* image = ras.finalize();
+ const_cast(this)->setImage( image );
+ }
+
+ Control::draw( cx ); // draws the background
+ ImageControl::draw( cx ); // draws the border
+}
+
+// ---------------------------------------------------------------------------
+
+RoundedFrame::RoundedFrame()
+{
+ //nop
+}
+
+void
+RoundedFrame::draw( const ControlContext& cx )
+{
+ if ( Geometry::hasBufferOperation() )
+ {
+ if ( !getImage() || getImage()->s() != _renderSize.x() || getImage()->t() != _renderSize.y() )
+ {
+ // create a rounded rectangle by buffering a rectangle. "buffer" value affects how rounded
+ // the corners are.
+ float buffer = Geometry::hasBufferOperation() ? 10.0f : 0.0f;
+
+ osg::ref_ptr geom = new osgEarth::Symbology::Polygon();
+ geom->push_back( osg::Vec3d( buffer, buffer, 0 ) );
+ geom->push_back( osg::Vec3d( _renderSize.x()-1-buffer, buffer, 0 ) );
+ geom->push_back( osg::Vec3d( _renderSize.x()-1-buffer, _renderSize.y()-1-buffer, 0 ) );
+ geom->push_back( osg::Vec3d( buffer, _renderSize.y()-1-buffer, 0 ) );
+
+ BufferParameters bp;
+ bp._capStyle = BufferParameters::CAP_ROUND;
+ geom->buffer( buffer-1.0f, geom, bp );
+
+ GeometryRasterizer ras( (int)_renderSize.x(), (int)_renderSize.y() );
+ ras.draw( geom.get(), backColor().value() );
+
+ osg::Image* image = ras.finalize();
+ const_cast(this)->setImage( image );
+ }
+
+ ImageControl::draw( cx );
+ }
+ else
+ {
+ // fallback: draw a non-rounded frame.
+ Frame::draw( cx );
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+Container::Container() :
+_spacing( 5.0f )
+{
+ //nop
+}
+
+Container::Container( const Alignment& halign, const Alignment& valign, const Gutter& padding, float spacing )
+: Control( halign, valign, padding )
+{
+ this->setChildSpacing( spacing );
+}
+
+void
+Container::getChildren(std::vector& out)
+{
+ for(unsigned i=1; i( getChild(i) );
+ if ( c ) out.push_back( c );
+ }
+}
+
+void
+Container::setChildSpacing( float value )
+{
+ if ( value != _spacing ) {
+ _spacing = value;
+ dirty();
+ }
+}
+
+void
+Container::setChildHorizAlign( Alignment value )
+{
+ if ( !_childhalign.isSet() || _childhalign != value )
+ {
+ _childhalign = value;
+ applyChildAligns();
+ }
+}
+
+void
+Container::setChildVertAlign( Alignment value )
+{
+ if ( !_childvalign.isSet() || _childvalign != value )
+ {
+ _childvalign = value;
+ applyChildAligns();
+ }
+}
+
+void
+Container::applyChildAligns()
+{
+ if ( _childhalign.isSet() || _childvalign.isSet() )
+ {
+ std::vector children;
+ getChildren( children );
+ for( std::vector::iterator i = children.begin(); i != children.end(); ++i )
+ {
+ Control* child = (*i);
+
+ if ( _childvalign.isSet() && !child->vertAlign().isSet() )
+ child->setVertAlign( *_childvalign );
+
+ if ( _childhalign.isSet() && !child->horizAlign().isSet() )
+ child->setHorizAlign( *_childhalign );
+ }
+ dirty();
+ }
+}
+
+void
+Container::calcSize(const ControlContext& cx, osg::Vec2f& out_size)
+{
+ if ( visible() == true )
+ {
+ float w = width().isSet() ? osg::maximum( width().value(), _renderSize.x() ) : _renderSize.x();
+ float h = height().isSet() ? osg::maximum( height().value(), _renderSize.y() ) : _renderSize.y();
+
+ _renderSize.set(
+ w + padding().x(),
+ h + padding().y() );
+
+ out_size.set(
+ _renderSize.x() + margin().x(),
+ _renderSize.y() + margin().y() );
+ }
+}
+
+void
+Container::calcFill(const ControlContext& cx)
+{
+ for( unsigned i=1; i( getChild(i) );
+ if ( child )
+ {
+ child->calcFill( cx );
+ }
+ }
+}
+
+void
+Container::calcPos(const ControlContext& context, const osg::Vec2f& cursor, const osg::Vec2f& parentSize)
+{
+ Control::calcPos( context, cursor, parentSize );
+}
+
+void
+Container::draw( const ControlContext& cx )
+{
+ Control::draw( cx );
+}
+
+bool
+Container::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, ControlContext& cx )
+{
+ if( !visible() || !parentIsVisible() )
+ return false;
+
+ bool handled = false;
+
+ float canvasY = cx._vp->height() - (ea.getY() - cx._view->getCamera()->getViewport()->y());
+ float canvasX = ea.getX() - cx._view->getCamera()->getViewport()->x();
+
+ std::vector children;
+ getChildren( children );
+ //OE_NOTICE << "handling " << children.size() << std::endl;
+ for( std::vector::reverse_iterator i = children.rbegin(); i != children.rend(); ++i )
+ {
+ Control* child = *i;
+ //Control* child = dynamic_cast( getChild(i) );
+ if ( child )
+ {
+ if (ea.getEventType() == osgGA::GUIEventAdapter::FRAME || child->intersects( canvasX, canvasY ) )
+ handled = child->handle( ea, aa, cx );
+ if ( handled )
+ break;
+ }
+ }
+
+ return handled ? handled : Control::handle( ea, aa, cx );
+}
+
+void
+Container::addControls( const ControlVector& controls )
+{
+ for( ControlVector::const_iterator i = controls.begin(); i != controls.end(); ++i )
+ {
+ addControl( i->get() );
+ }
+}
+
+
+
+
+
+
+void Container::setVisible(bool visibility)
+{
+ Control::setVisible(visibility);
+ std::vector out;
+ getChildren(out);
+ for (int i = 0; i < (int) out.size(); i++)
+ {
+ Container* container = dynamic_cast( out[i] );
+ if (container) {
+ container->setVisible(visibility);
+ } else {
+ out[i]->setVisible(visibility);
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+VBox::VBox()
+{
+ //nop
+}
+
+VBox::VBox( const Alignment& halign, const Alignment& valign, const Gutter& padding, float spacing ) :
+Container( halign, valign, padding, spacing )
+{
+ //nop
+}
+
+Control*
+VBox::addControlImpl( Control* control, int index )
+{
+ insertChild( index, control );
+ applyChildAligns();
+ dirty();
+ return control;
+}
+
+void
+VBox::clearControls()
+{
+ removeChildren( 1, getNumChildren()-1 );
+ dirty();
+}
+
+void
+VBox::calcSize(const ControlContext& cx, osg::Vec2f& out_size)
+{
+ if ( visible() )
+ {
+ _renderSize.set( 0, 0 );
+
+ // collect all the members, growing the container size vertically
+ for( unsigned i=1; i( getChild(i) );
+ if ( child )
+ {
+ osg::Vec2f childSize;
+ bool first = i == 1; //_controls.begin();
+
+ child->calcSize( cx, childSize );
+
+ _renderSize.x() = osg::maximum( _renderSize.x(), childSize.x() );
+ _renderSize.y() += first ? childSize.y() : childSpacing() + childSize.y();
+ }
+ }
+
+ Container::calcSize( cx, out_size );
+ }
+ else
+ {
+ out_size.set(0,0);
+ }
+}
+
+void
+VBox::calcFill(const ControlContext& cx)
+{
+ float used_x = padding().x();
+ float used_y = padding().y() - childSpacing();
+
+ Control* hc = 0L;
+ Control* vc = 0L;
+
+ for( unsigned i=1; i( getChild(i) );
+ if ( child )
+ {
+ used_y += child->margin().y() + childSpacing();
+ if ( !hc && child->horizFill() )
+ {
+ hc = child;
+ used_x += child->margin().x();
+ }
+
+ if ( !vc && child->vertFill() )
+ vc = child;
+ else
+ used_y += child->renderSize().y();
+ }
+ }
+
+ if ( hc && renderWidth(hc) < (_renderSize.x() - used_x) )
+ renderWidth(hc) = _renderSize.x() - used_x;
+
+ if ( vc && renderHeight(vc) < (_renderSize.y() - used_y) )
+ renderHeight(vc) = _renderSize.y() - used_y;
+
+ Container::calcFill( cx );
+}
+
+void
+VBox::calcPos(const ControlContext& cx, const osg::Vec2f& cursor, const osg::Vec2f& parentSize)
+{
+ Container::calcPos( cx, cursor, parentSize );
+
+ osg::Vec2f childCursor = _renderPos;
+
+ osg::Vec2f renderArea = _renderSize - padding().size();
+
+ for( unsigned i=1; i( getChild(i) );
+ if ( child )
+ {
+ child->calcPos( cx, childCursor, renderArea ); // GW1
+ float deltaY = child->margin().top() + child->renderSize().y() + child->margin().bottom() + childSpacing();
+ childCursor.y() += deltaY;
+ renderArea.y() -= deltaY;
+ }
+ }
+}
+
+void
+VBox::draw( const ControlContext& cx )
+{
+
+ Container::draw( cx );
+
+ for( unsigned i=1; i(getChild(i));
+ if ( c )
+ c->draw( cx );
+ }
+
+}
+
+// ---------------------------------------------------------------------------
+
+HBox::HBox()
+{
+ //nop
+}
+
+HBox::HBox( const Alignment& halign, const Alignment& valign, const Gutter& padding, float spacing ) :
+Container( halign, valign, padding, spacing )
+{
+ //nop
+}
+
+Control*
+HBox::addControlImpl( Control* control, int index )
+{
+ insertChild(index, control);
+ applyChildAligns();
+ dirty();
+ return control;
+}
+
+void
+HBox::clearControls()
+{
+ removeChildren(1, getNumChildren()-1);
+ dirty();
+}
+
+void
+HBox::calcSize(const ControlContext& cx, osg::Vec2f& out_size)
+{
+ if ( visible() )
+ {
+ _renderSize.set( 0, 0 );
+
+ // collect all the members, growing the container is its orientation.
+ for( unsigned i=1; i( getChild(i) );
+ if ( child )
+ {
+ osg::Vec2f childSize;
+ bool first = i == 1;
+
+ child->calcSize( cx, childSize );
+
+ _renderSize.x() += first ? childSize.x() : childSpacing() + childSize.x();
+ _renderSize.y() = osg::maximum( _renderSize.y(), childSize.y() );
+ }
+ }
+
+ // If width explicitly set and > total width of children - use it
+ if (width().isSet() && width().get() > _renderSize.x()) _renderSize.x() = width().get();
+
+ Container::calcSize( cx, out_size );
+ }
+ else
+ {
+ out_size.set(0,0);
+ }
+}
+
+void
+HBox::calcFill(const ControlContext& cx)
+{
+ float used_x = padding().x() - childSpacing();
+ float used_y = padding().y();
+
+ Control* hc = 0L;
+ Control* vc = 0L;
+
+ for( unsigned i=1; i( getChild(i) );
+ if ( child )
+ {
+ used_x += child->margin().x() + childSpacing();
+ if ( !hc && child->horizFill() )
+ hc = child;
+ else
+ used_x += child->renderSize().x();
+
+ if ( !vc && child->vertFill() )
+ {
+ vc = child;
+ used_y += child->margin().y();
+ }
+ }
+ }
+
+ if ( hc && renderWidth(hc) < (_renderSize.x() - used_x) )
+ renderWidth(hc) = _renderSize.x() - used_x;
+
+ if ( vc && renderHeight(vc) < (_renderSize.y() - used_y) )
+ renderHeight(vc) = _renderSize.y() - used_y;
+
+ Container::calcFill( cx );
+}
+
+void
+HBox::calcPos(const ControlContext& cx, const osg::Vec2f& cursor, const osg::Vec2f& parentSize)
+{
+ Container::calcPos( cx, cursor, parentSize );
+
+ osg::Vec2f childCursor = _renderPos;
+
+ osg::Vec2f renderArea = _renderSize - padding().size();
+
+ for( unsigned i=1; i( getChild(i) );
+ if ( child )
+ {
+ child->calcPos( cx, childCursor, renderArea );
+ float deltaX = child->margin().left() + child->renderSize().x() + child->margin().right() + childSpacing();
+ childCursor.x() += deltaX;
+ renderArea.x() -= deltaX;
+ }
+ }
+}
+
+void
+HBox::draw( const ControlContext& cx )
+{
+
+ Container::draw( cx );
+
+ for( unsigned i=1; i(getChild(i));
+ if ( c )
+ c->draw( cx );
+ }
+
+}
+
+// ---------------------------------------------------------------------------
+
+Grid::Grid() :
+Container(),
+_maxCols(0)
+{
+ setChildHorizAlign( ALIGN_LEFT );
+ setChildVertAlign( ALIGN_CENTER );
+}
+
+Grid::Grid( const Alignment& halign, const Alignment& valign, const Gutter& padding, float spacing ) :
+Container( halign, valign, padding, spacing ),
+_maxCols(0)
+{
+ //nop
+}
+
+void
+Grid::getChildren(std::vector& out)
+{
+ for(unsigned i=1; iasGroup();
+ if ( row )
+ {
+ for( unsigned j=0; jgetNumChildren(); ++j )
+ {
+ Control* c = dynamic_cast( row->getChild(j) );
+ if ( c ) out.push_back( c );
+ }
+ }
+ }
+}
+
+unsigned
+Grid::getNumRows() const
+{
+ return getNumChildren()-1;
+}
+
+unsigned
+Grid::getNumColumns() const
+{
+ if ( getNumRows() == 0 )
+ return 0;
+ else
+ return const_cast(this)->getRow(0)->getNumChildren();
+}
+
+osg::Group*
+Grid::getRow(unsigned index)
+{
+ return getNumChildren() >= 2+index ? getChild(1+index)->asGroup() : 0L;
+}
+
+Control*
+Grid::setControlImpl( int col, int row, Control* child )
+{
+ if ( child )
+ {
+ expandToInclude( col, row );
+ osg::Group* rowGroup = getRow(row);
+ rowGroup->setChild( col, child );
+ applyChildAligns();
+
+ dirty();
+ }
+
+ return child;
+}
+
+Control*
+Grid::getControl(int col, int row)
+{
+ if ( row < (int)getNumChildren()+1 )
+ {
+ osg::Group* rowGroup = getRow(row);
+ if ( col < (int)rowGroup->getNumChildren() )
+ {
+ return dynamic_cast( rowGroup->getChild(col) );
+ }
+ }
+ return 0L;
+}
+
+void
+Grid::expandToInclude( int col, int row )
+{
+ // ensure all rows have sufficient columns:
+ if ( col+1 > (int)_maxCols )
+ {
+ _maxCols = col+1;
+ }
+
+ // and that we have sufficient rows:
+ unsigned maxRows = osg::maximum( (unsigned)getNumRows(), (unsigned)(row+1) );
+
+ // expand everything and use empty groups as placeholders
+ for( unsigned r=0; rgetNumChildren() < _maxCols )
+ {
+ rowGroup->addChild( new osg::Group() );
+ }
+ }
+}
+
+Control*
+Grid::addControlImpl( Control* control, int index )
+{
+ // creates a new row and puts the control in its first column (index is ignored)
+ return setControlImpl( 0, getNumRows(), control );
+}
+
+void
+Grid::addControls( const ControlVector& controls )
+{
+ unsigned row = getNumRows();
+ unsigned col = 0;
+ for( ControlVector::const_iterator i = controls.begin(); i != controls.end(); ++i, ++col )
+ {
+ if ( i->valid() )
+ {
+ setControlImpl( col, row, i->get() );
+ }
+ }
+}
+
+void
+Grid::clearControls()
+{
+ removeChildren(1, getNumChildren()-1);
+ dirty();
+}
+
+void
+Grid::calcSize( const ControlContext& cx, osg::Vec2f& out_size )
+{
+
+ _renderSize.set( 0, 0 );
+
+ int nRows = (int)getNumRows();
+ int nCols = (int)getNumColumns();
+
+ _rowHeights.assign( nRows, 0.0f );
+ _colWidths.assign ( nCols, 0.0f );
+
+ if ( nRows > 0 && nCols > 0 )
+ {
+ for( int r=0; rcalcSize( cx, childSize );
+
+ if ( childSize.x() > _colWidths[c] )
+ _colWidths[c] = childSize.x();
+ if ( childSize.y() > _rowHeights[r] )
+ _rowHeights[r] = childSize.y();
+ }
+ }
+ }
+
+ for( int c=0; chorizFill() )
+ renderWidth(child) = _colWidths[c] - child->margin().x();
+ if ( child->vertFill() )
+ renderHeight(child) = _rowHeights[r] - child->margin().y();
+ }
+ }
+ }
+}
+
+void
+Grid::calcPos( const ControlContext& cx, const osg::Vec2f& cursor, const osg::Vec2f& parentSize )
+{
+ Container::calcPos( cx, cursor, parentSize );
+
+ int nRows = (int)getNumRows();
+ int nCols = (int)getNumColumns();
+
+ osg::Vec2f childCursor = _renderPos;
+
+ for( int r=0; rcalcPos( cx, childCursor, cellSize );
+ }
+ childCursor.x() += _colWidths[c] + childSpacing();
+ }
+ childCursor.x() = _renderPos.x();
+ childCursor.y() += _rowHeights[r] + childSpacing();
+ }
+}
+
+
+
+
+
+void
+Grid::draw( const ControlContext& cx )
+{
+
+ Container::draw( cx );
+
+ for( unsigned i=1; iasGroup();
+ if ( rowGroup )
+ {
+ for( unsigned j=0; jgetNumChildren(); ++j )
+ {
+ Control* c = dynamic_cast( rowGroup->getChild(j) );
+ if ( c )
+ {
+ c->draw( cx );
+ }
+ }
+ }
+ }
+
+}
+
+// ---------------------------------------------------------------------------
+
+ControlCanvas::EventCallback::EventCallback(ControlCanvas* canvas) :
+_canvas ( canvas ),
+_firstTime( true ),
+_width ( 0 ),
+_height ( 0 )
+{
+ //nop
+}
+
+#define AS_ADAPTER(e) e->asGUIEventAdapter()
+
+void
+ControlCanvas::EventCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
+{
+ osgGA::EventVisitor* ev = static_cast