WS30: Initial coastlines
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
include (SimGearComponent)
|
||||
|
||||
set(HEADERS
|
||||
GroundLightManager.hxx
|
||||
AreaFeatureBin.hxx
|
||||
CoastlineBin.hxx
|
||||
GroundLightManager.hxx
|
||||
LineFeatureBin.hxx
|
||||
ReaderWriterSPT.hxx
|
||||
ReaderWriterSTG.hxx
|
||||
@@ -22,6 +23,7 @@ set(HEADERS
|
||||
ShaderGeometry.hxx
|
||||
TreeBin.hxx
|
||||
VPBElevationSlice.hxx
|
||||
VPBTileBounds.hxx
|
||||
VPBTechnique.hxx
|
||||
apt_signs.hxx
|
||||
obj.hxx
|
||||
@@ -30,8 +32,9 @@ set(HEADERS
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
GroundLightManager.cxx
|
||||
AreaFeatureBin.cxx
|
||||
CoastlineBin.cxx
|
||||
GroundLightManager.cxx
|
||||
LineFeatureBin.cxx
|
||||
ReaderWriterSPT.cxx
|
||||
ReaderWriterSTG.cxx
|
||||
@@ -42,6 +45,7 @@ set(SOURCES
|
||||
ShaderGeometry.cxx
|
||||
TreeBin.cxx
|
||||
VPBElevationSlice.cxx
|
||||
VPBTileBounds.cxx
|
||||
VPBTechnique.cxx
|
||||
apt_signs.cxx
|
||||
obj.cxx
|
||||
|
||||
99
simgear/scene/tgdb/CoastlineBin.cxx
Normal file
99
simgear/scene/tgdb/CoastlineBin.cxx
Normal file
@@ -0,0 +1,99 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2008 Stuart Buchanan
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <osgDB/ReadFile>
|
||||
#include <osgDB/FileUtils>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/io/iostreams/sgstream.hxx>
|
||||
#include <simgear/math/SGGeod.hxx>
|
||||
#include <simgear/scene/util/OsgMath.hxx>
|
||||
|
||||
#include "CoastlineBin.hxx"
|
||||
|
||||
using namespace osg;
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
CoastlineBin::CoastlineBin(const SGPath& absoluteFileName)
|
||||
{
|
||||
if (!absoluteFileName.exists()) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Coastline list file " << absoluteFileName << " does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
sg_gzifstream stream(absoluteFileName);
|
||||
if (!stream.is_open()) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Unable to open " << absoluteFileName);
|
||||
return;
|
||||
}
|
||||
|
||||
while (!stream.eof()) {
|
||||
// read a line. Each line defines a coast line feature, consisting of a series of lon/lat positions.
|
||||
// Or a comment, starting with #
|
||||
std::string line;
|
||||
std::getline(stream, line);
|
||||
|
||||
// strip comments
|
||||
std::string::size_type hash_pos = line.find('#');
|
||||
if (hash_pos != std::string::npos)
|
||||
line.resize(hash_pos);
|
||||
|
||||
// and process further
|
||||
std::stringstream in(line);
|
||||
|
||||
if (in.bad() || in.fail()) {
|
||||
SG_LOG(SG_TERRAIN, SG_WARN, "Error parsing area entry in: " << absoluteFileName << " line: \"" << line << "\"");
|
||||
continue;
|
||||
}
|
||||
|
||||
std::list<osg::Vec3d> nodes;
|
||||
|
||||
while (true) {
|
||||
double lon = 0.0f, lat=0.0f;
|
||||
in >> lon >> lat;
|
||||
|
||||
if (in.bad() || in.fail()) {
|
||||
break;
|
||||
}
|
||||
|
||||
SGVec3d tmp;
|
||||
SGGeodesy::SGGeodToCart(SGGeod::fromDeg(lon, lat), tmp);
|
||||
nodes.push_back(toOsg(tmp));
|
||||
}
|
||||
|
||||
if (nodes.size() > 1) {
|
||||
insert(Coastline(nodes));
|
||||
} else {
|
||||
SG_LOG(SG_TERRAIN, SG_WARN, "Coastline definition with fewer than two lon/lat nodes : " << absoluteFileName << " line: \"" << line << "\"");
|
||||
}
|
||||
}
|
||||
|
||||
stream.close();
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
69
simgear/scene/tgdb/CoastlineBin.hxx
Normal file
69
simgear/scene/tgdb/CoastlineBin.hxx
Normal file
@@ -0,0 +1,69 @@
|
||||
/* -*-c++-*-
|
||||
*
|
||||
* Copyright (C) 2021 Stuart Buchanan
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef COAST_BIN_HXX
|
||||
#define COAST_BIN_HXX
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Group>
|
||||
#include <osg/Matrix>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
class CoastlineBin {
|
||||
public:
|
||||
CoastlineBin() = default;
|
||||
CoastlineBin(const SGPath& absoluteFileName);
|
||||
|
||||
~CoastlineBin() = default;
|
||||
|
||||
struct Coastline {
|
||||
const std::list<osg::Vec3d> _nodes;
|
||||
Coastline(const std::list<osg::Vec3d> nodes) :
|
||||
_nodes(nodes)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::list<Coastline> CoastlineList;
|
||||
|
||||
void insert(const Coastline& t) {
|
||||
_coastFeatureList.push_back(t);
|
||||
}
|
||||
|
||||
const CoastlineList getCoastlines() const {
|
||||
return _coastFeatureList;
|
||||
}
|
||||
|
||||
private:
|
||||
CoastlineList _coastFeatureList;
|
||||
};
|
||||
|
||||
typedef std::list<CoastlineBin> CoastlineBinList;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
const float _b;
|
||||
const float _c;
|
||||
const float _d;
|
||||
LineFeature(const std::list<osg::Vec3d> nodes, const float w, const int attributes, const float a, const float b, const float c, const float d) :
|
||||
LineFeature(const std::list<osg::Vec3d> nodes, const float w, const int attributes=0, const float a=0.0, const float b=0.0, const float c=0.0, const float d=0.0) :
|
||||
_nodes(nodes), _width(w), _attributes(attributes), _a(a), _b(b), _c(c), _d(d)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
#define TREE_LIST "TREE_LIST"
|
||||
#define LINE_FEATURE_LIST "LINE_FEATURE_LIST"
|
||||
#define AREA_FEATURE_LIST "AREA_FEATURE_LIST"
|
||||
#define COASTLINE_LIST "COASTLINE_LIST"
|
||||
|
||||
namespace simgear {
|
||||
|
||||
@@ -167,6 +168,12 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
SGBucket _bucket;
|
||||
};
|
||||
|
||||
struct _CoastlineList {
|
||||
_CoastlineList() { }
|
||||
std::string _filename;
|
||||
SGBucket _bucket;
|
||||
};
|
||||
|
||||
class DelayLoadReadFileCallback : public OptionsReadFileCallback {
|
||||
|
||||
private:
|
||||
@@ -353,6 +360,20 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
VPBTechnique::addAreaFeatureList(_bucket, areaFeatures, _terrainNode);
|
||||
}
|
||||
|
||||
if (!_coastFeatureList.empty()) {
|
||||
|
||||
CoastlineBinList coastFeatures;
|
||||
|
||||
for (const auto& b : _coastFeatureList) {
|
||||
// add the lineFeatures to the list
|
||||
const auto path = SGPath(b._filename);
|
||||
coastFeatures.push_back(CoastlineBin(path));
|
||||
}
|
||||
|
||||
VPBTechnique::addCoastlineList(_bucket, coastFeatures, _terrainNode);
|
||||
}
|
||||
|
||||
|
||||
return group.release();
|
||||
}
|
||||
|
||||
@@ -363,6 +384,7 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
std::list<_TreeList> _treeList;
|
||||
std::list<_LineFeatureList> _lineFeatureList;
|
||||
std::list<_AreaFeatureList> _areaFeatureList;
|
||||
std::list<_CoastlineList> _coastFeatureList;
|
||||
osg::ref_ptr<osg::Node> _terrainNode;
|
||||
|
||||
/// The original options to use for this bunch of models
|
||||
@@ -672,6 +694,11 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
in >> areaFeaturelist._material;
|
||||
areaFeaturelist._bucket = bucketIndexFromFileName(absoluteFileName.file_base().c_str());
|
||||
_areaFeatureListList.push_back(areaFeaturelist);
|
||||
} else if (token == COASTLINE_LIST) {
|
||||
_CoastlineList coastFeaturelist;
|
||||
coastFeaturelist._filename = path.utf8Str();
|
||||
coastFeaturelist._bucket = bucketIndexFromFileName(absoluteFileName.file_base().c_str());
|
||||
_coastFeatureListList.push_back(coastFeaturelist);
|
||||
} else {
|
||||
// Check registered callback for token. Keep lock until callback completed to make sure it will not be
|
||||
// executed after a thread successfully executed removeSTGObjectHandler()
|
||||
@@ -790,50 +817,58 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
i->_elev += elevation(*terrainGroup, SGGeod::fromDeg(i->_lon, i->_lat));
|
||||
}
|
||||
|
||||
if (_objectStaticList.empty() && _signList.empty() && _buildingListList.empty() && _treeListList.empty() && _lineFeatureListList.empty() && _areaFeatureListList.empty()) {
|
||||
if (_objectStaticList.empty() &&
|
||||
_signList.empty() &&
|
||||
_buildingListList.empty() &&
|
||||
_treeListList.empty() &&
|
||||
_lineFeatureListList.empty() &&
|
||||
_areaFeatureListList.empty() &&
|
||||
_coastFeatureListList.empty())
|
||||
{
|
||||
// The simple case, just return the terrain group
|
||||
return terrainGroup.release();
|
||||
} else {
|
||||
osg::PagedLOD* pagedLOD = new osg::PagedLOD;
|
||||
pagedLOD->setCenterMode(osg::PagedLOD::USE_BOUNDING_SPHERE_CENTER);
|
||||
std::string name = string("pagedObjectLOD ").append(bucket.gen_index_str());
|
||||
pagedLOD->setName(name);
|
||||
|
||||
// This should be visible in any case.
|
||||
// If this is replaced by some lower level of detail, the parent LOD node handles this.
|
||||
pagedLOD->addChild(terrainGroup, 0, std::numeric_limits<float>::max());
|
||||
pagedLOD->setMinimumExpiryTime(0, pagedLODExpiry);
|
||||
|
||||
// we just need to know about the read file callback that itself holds the data
|
||||
osg::ref_ptr<DelayLoadReadFileCallback> readFileCallback = new DelayLoadReadFileCallback;
|
||||
readFileCallback->_objectStaticList = _objectStaticList;
|
||||
readFileCallback->_buildingList = _buildingListList;
|
||||
readFileCallback->_treeList = _treeListList;
|
||||
readFileCallback->_signList = _signList;
|
||||
readFileCallback->_options = options;
|
||||
readFileCallback->_bucket = bucket;
|
||||
|
||||
if (vpb_active && vpb_node) {
|
||||
readFileCallback->_lineFeatureList = _lineFeatureListList;
|
||||
readFileCallback->_areaFeatureList = _areaFeatureListList;
|
||||
readFileCallback->_terrainNode = vpb_node;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osgDB::Options> callbackOptions = new osgDB::Options;
|
||||
callbackOptions->setReadFileCallback(readFileCallback.get());
|
||||
pagedLOD->setDatabaseOptions(callbackOptions.get());
|
||||
|
||||
pagedLOD->setFileName(pagedLOD->getNumChildren(), "Dummy name - use the stored data in the read file callback");
|
||||
|
||||
// Objects may end up displayed up to 2x the object range.
|
||||
pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 2.0 * _object_range_rough);
|
||||
pagedLOD->setMinimumExpiryTime(pagedLOD->getNumChildren(), pagedLODExpiry);
|
||||
pagedLOD->setRadius(SG_TILE_RADIUS);
|
||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Center: " << pagedLOD->getCenter().x() << "," << pagedLOD->getCenter().y() << "," << pagedLOD->getCenter().z() );
|
||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Range: " << (2.0 * _object_range_rough));
|
||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Radius: " << SG_TILE_RADIUS);
|
||||
return pagedLOD;
|
||||
}
|
||||
|
||||
osg::PagedLOD* pagedLOD = new osg::PagedLOD;
|
||||
pagedLOD->setCenterMode(osg::PagedLOD::USE_BOUNDING_SPHERE_CENTER);
|
||||
std::string name = string("pagedObjectLOD ").append(bucket.gen_index_str());
|
||||
pagedLOD->setName(name);
|
||||
|
||||
// This should be visible in any case.
|
||||
// If this is replaced by some lower level of detail, the parent LOD node handles this.
|
||||
pagedLOD->addChild(terrainGroup, 0, std::numeric_limits<float>::max());
|
||||
pagedLOD->setMinimumExpiryTime(0, pagedLODExpiry);
|
||||
|
||||
// we just need to know about the read file callback that itself holds the data
|
||||
osg::ref_ptr<DelayLoadReadFileCallback> readFileCallback = new DelayLoadReadFileCallback;
|
||||
readFileCallback->_objectStaticList = _objectStaticList;
|
||||
readFileCallback->_buildingList = _buildingListList;
|
||||
readFileCallback->_treeList = _treeListList;
|
||||
readFileCallback->_signList = _signList;
|
||||
readFileCallback->_options = options;
|
||||
readFileCallback->_bucket = bucket;
|
||||
|
||||
if (vpb_active && vpb_node) {
|
||||
readFileCallback->_lineFeatureList = _lineFeatureListList;
|
||||
readFileCallback->_areaFeatureList = _areaFeatureListList;
|
||||
readFileCallback->_coastFeatureList = _coastFeatureListList;
|
||||
readFileCallback->_terrainNode = vpb_node;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osgDB::Options> callbackOptions = new osgDB::Options;
|
||||
callbackOptions->setReadFileCallback(readFileCallback.get());
|
||||
pagedLOD->setDatabaseOptions(callbackOptions.get());
|
||||
|
||||
pagedLOD->setFileName(pagedLOD->getNumChildren(), "Dummy name - use the stored data in the read file callback");
|
||||
|
||||
// Objects may end up displayed up to 2x the object range.
|
||||
pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 2.0 * _object_range_rough);
|
||||
pagedLOD->setMinimumExpiryTime(pagedLOD->getNumChildren(), pagedLODExpiry);
|
||||
pagedLOD->setRadius(SG_TILE_RADIUS);
|
||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Center: " << pagedLOD->getCenter().x() << "," << pagedLOD->getCenter().y() << "," << pagedLOD->getCenter().z() );
|
||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Range: " << (2.0 * _object_range_rough));
|
||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Radius: " << SG_TILE_RADIUS);
|
||||
return pagedLOD;
|
||||
}
|
||||
|
||||
double _object_range_bare;
|
||||
@@ -847,6 +882,7 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
std::list<_TreeList> _treeListList;
|
||||
std::list<_LineFeatureList> _lineFeatureListList;
|
||||
std::list<_AreaFeatureList> _areaFeatureListList;
|
||||
std::list<_CoastlineList> _coastFeatureListList;
|
||||
};
|
||||
|
||||
ReaderWriterSTG::ReaderWriterSTG()
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <simgear/scene/material/EffectGeode.hxx>
|
||||
#include <simgear/scene/model/model.hxx>
|
||||
#include <simgear/scene/tgdb/VPBElevationSlice.hxx>
|
||||
#include <simgear/scene/tgdb/VPBTileBounds.hxx>
|
||||
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
|
||||
#include <simgear/scene/util/SGSceneFeatures.hxx>
|
||||
#include <simgear/scene/util/RenderConstants.hxx>
|
||||
@@ -169,6 +170,7 @@ void VPBTechnique::init(int dirtyMask, bool assumeMultiThreaded)
|
||||
applyTrees(*buffer, masterLocator);
|
||||
applyLineFeatures(*buffer, masterLocator);
|
||||
applyAreaFeatures(*buffer, masterLocator);
|
||||
applyCoastline(*buffer, masterLocator);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -177,7 +179,7 @@ void VPBTechnique::init(int dirtyMask, bool assumeMultiThreaded)
|
||||
applyColorLayers(*buffer, masterLocator);
|
||||
applyTrees(*buffer, masterLocator);
|
||||
applyLineFeatures(*buffer, masterLocator);
|
||||
applyAreaFeatures(*buffer, masterLocator);
|
||||
applyCoastline(*buffer, masterLocator);
|
||||
}
|
||||
|
||||
if (buffer->_transform.valid()) buffer->_transform->setThreadSafeRefUnref(true);
|
||||
@@ -1298,6 +1300,8 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator)
|
||||
}
|
||||
}
|
||||
|
||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "VPB Image level:" << _terrainTile->getTileID().level << " " << image->s() << "x" << image->t() << " mipmaps:" << image->getNumMipmapLevels() << " format:" << image->getInternalTextureFormat());
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> texture2D = new osg::Texture2D;
|
||||
texture2D->setImage(image);
|
||||
texture2D->setMaxAnisotropy(16.0f);
|
||||
@@ -1309,16 +1313,6 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator)
|
||||
texture2D->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE);
|
||||
texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE);
|
||||
|
||||
bool mipMapping = !(texture2D->getFilter(osg::Texture::MIN_FILTER)==osg::Texture::LINEAR || texture2D->getFilter(osg::Texture::MIN_FILTER)==osg::Texture::NEAREST);
|
||||
bool s_NotPowerOfTwo = image->s()==0 || (image->s() & (image->s() - 1));
|
||||
bool t_NotPowerOfTwo = image->t()==0 || (image->t() & (image->t() - 1));
|
||||
|
||||
if (mipMapping && (s_NotPowerOfTwo || t_NotPowerOfTwo))
|
||||
{
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Disabling mipmapping for non power of two tile size("<<image->s()<<", "<<image->t()<<")");
|
||||
texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
|
||||
}
|
||||
|
||||
osg::StateSet* stateset = buffer._landGeode->getOrCreateStateSet();
|
||||
stateset->setTextureAttributeAndModes(0, texture2D, osg::StateAttribute::ON);
|
||||
stateset->setTextureAttributeAndModes(1, atlas.image, osg::StateAttribute::ON);
|
||||
@@ -1680,23 +1674,24 @@ void VPBTechnique::applyLineFeatures(BufferData& buffer, Locator* masterLocator)
|
||||
|
||||
void VPBTechnique::generateLineFeature(BufferData& buffer, Locator* masterLocator, LineFeatureBin::LineFeature road, osg::Vec3d modelCenter, osg::Vec3Array* v, osg::Vec2Array* t, osg::Vec3Array* n, unsigned int xsize, unsigned int ysize)
|
||||
{
|
||||
if (road._nodes.size() < 2) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Coding error - LineFeatureBin::LineFeature with fewer than two nodes");
|
||||
return;
|
||||
}
|
||||
|
||||
osg::Vec3d ma, mb;
|
||||
std::list<osg::Vec3d> roadPoints;
|
||||
auto road_iter = road._nodes.begin();
|
||||
|
||||
// We're in Earth-centered coordinates, so "up" is simply directly away from (0,0,0)
|
||||
osg::Vec3d up = modelCenter;
|
||||
up.normalize();
|
||||
TileBounds tileBounds(masterLocator, up);
|
||||
|
||||
std::list<osg::Vec3d> nodes = tileBounds.clipToTile(road._nodes);
|
||||
|
||||
// We need at least two node to make a road.
|
||||
if (nodes.size() < 2) return;
|
||||
|
||||
osg::Vec3d ma, mb;
|
||||
std::list<osg::Vec3d> roadPoints;
|
||||
auto road_iter = nodes.begin();
|
||||
|
||||
ma = getMeshIntersection(buffer, masterLocator, *road_iter - modelCenter, up);
|
||||
road_iter++;
|
||||
|
||||
for (; road_iter != road._nodes.end(); road_iter++) {
|
||||
for (; road_iter != nodes.end(); road_iter++) {
|
||||
mb = getMeshIntersection(buffer, masterLocator, *road_iter - modelCenter, up);
|
||||
auto esl = VPBElevationSlice::computeVPBElevationSlice(buffer._landGeometry, ma, mb, up);
|
||||
|
||||
@@ -1929,6 +1924,203 @@ void VPBTechnique::generateAreaFeature(BufferData& buffer, Locator* masterLocato
|
||||
}
|
||||
}
|
||||
|
||||
void VPBTechnique::applyCoastline(BufferData& buffer, Locator* masterLocator)
|
||||
{
|
||||
unsigned int coast_features_lod_range = 4;
|
||||
float coastWidth = 40.0;
|
||||
|
||||
const unsigned int tileLevel = _terrainTile->getTileID().level;
|
||||
const SGPropertyNode* propertyNode = _options->getPropertyNode().get();
|
||||
|
||||
if (propertyNode) {
|
||||
const SGPropertyNode* static_lod = propertyNode->getNode("/sim/rendering/static-lod");
|
||||
coast_features_lod_range = static_lod->getIntValue("coastline-lod-level", coast_features_lod_range);
|
||||
coastWidth = static_lod->getIntValue("coastline-width", coastWidth);
|
||||
}
|
||||
|
||||
if (tileLevel < coast_features_lod_range) {
|
||||
// Do not generate coasts for tiles too far away
|
||||
return;
|
||||
}
|
||||
|
||||
const SGMaterialLibPtr matlib = _options->getMaterialLib();
|
||||
if (! matlib) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Unable to get materials library to generate areas");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all appropriate coasts. We assume that the VPB terrain tile is smaller than a Bucket size.
|
||||
const osg::Vec3d world = buffer._transform->getMatrix().getTrans();
|
||||
const SGGeod loc = SGGeod::fromCart(toSG(world));
|
||||
const SGBucket bucket = SGBucket(loc);
|
||||
auto coasts = std::find_if(_coastFeatureLists.begin(), _coastFeatureLists.end(), [bucket](BucketCoastlineBinList b){return (b.first == bucket);});
|
||||
|
||||
if (coasts == _coastFeatureLists.end()) return;
|
||||
|
||||
// We're in Earth-centered coordinates, so "up" is simply directly away from (0,0,0)
|
||||
osg::Vec3d up = world;
|
||||
up.normalize();
|
||||
|
||||
TileBounds tileBounds(masterLocator, up);
|
||||
|
||||
SGMaterialCache* matcache = matlib->generateMatCache(loc, _options);
|
||||
SGMaterial* mat = matcache->find("ws30coastline");
|
||||
|
||||
if (!mat) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Unable to find material ws30coastline at " << loc << " " << bucket);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int xsize = mat->get_xsize();
|
||||
unsigned int ysize = mat->get_ysize();
|
||||
|
||||
// Generate a geometry for this set of coasts.
|
||||
osg::Vec3Array* v = new osg::Vec3Array;
|
||||
osg::Vec2Array* t = new osg::Vec2Array;
|
||||
osg::Vec3Array* n = new osg::Vec3Array;
|
||||
osg::Vec4Array* c = new osg::Vec4Array;
|
||||
|
||||
for (; coasts != _coastFeatureLists.end(); ++coasts) {
|
||||
const CoastlineBinList coastBins = coasts->second;
|
||||
|
||||
for (auto rb = coastBins.begin(); rb != coastBins.end(); ++rb)
|
||||
{
|
||||
auto coastFeatures = rb->getCoastlines();
|
||||
|
||||
for (auto r = coastFeatures.begin(); r != coastFeatures.end(); ++r) {
|
||||
auto clipped = tileBounds.clipToTile(r->_nodes);
|
||||
if (clipped.size() > 1) {
|
||||
// We need at least two points to render a line.
|
||||
LineFeatureBin::LineFeature line = LineFeatureBin::LineFeature(clipped, coastWidth);
|
||||
generateCoastlineFeature(buffer, masterLocator, line, world, v, t, n, xsize, ysize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (v->size() == 0) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "No vertices for coastline! " << loc << " " << bucket);
|
||||
return;
|
||||
}
|
||||
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Generating coastline of " << v->size() << " vertices.");
|
||||
|
||||
c->push_back(osg::Vec4(1.0,1.0,1.0,1.0));
|
||||
|
||||
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
|
||||
geometry->setVertexArray(v);
|
||||
geometry->setTexCoordArray(0, t, osg::Array::BIND_PER_VERTEX);
|
||||
geometry->setTexCoordArray(1, t, osg::Array::BIND_PER_VERTEX);
|
||||
geometry->setNormalArray(n, osg::Array::BIND_PER_VERTEX);
|
||||
geometry->setColorArray(c, osg::Array::BIND_OVERALL);
|
||||
geometry->setUseDisplayList( false );
|
||||
geometry->setUseVertexBufferObjects( true );
|
||||
geometry->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLES, 0, v->size()) );
|
||||
|
||||
EffectGeode* geode = new EffectGeode;
|
||||
geode->addDrawable(geometry);
|
||||
|
||||
geode->setMaterial(mat);
|
||||
geode->setEffect(mat->get_one_effect(0));
|
||||
geode->setNodeMask( ~(simgear::CASTSHADOW_BIT | simgear::MODELLIGHT_BIT) );
|
||||
buffer._transform->addChild(geode);
|
||||
}
|
||||
|
||||
void VPBTechnique::generateCoastlineFeature(BufferData& buffer, Locator* masterLocator, LineFeatureBin::LineFeature coastline, osg::Vec3d modelCenter, osg::Vec3Array* v, osg::Vec2Array* t, osg::Vec3Array* n, unsigned int xsize, unsigned int ysize)
|
||||
{
|
||||
if (coastline._nodes.size() < 2) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Coding error - LineFeatureBin::LineFeature with fewer than two nodes");
|
||||
return;
|
||||
}
|
||||
|
||||
osg::Vec3d ma, mb;
|
||||
std::list<osg::Vec3d> coastlinePoints;
|
||||
auto coastline_iter = coastline._nodes.begin();
|
||||
|
||||
// We're in Earth-centered coordinates, so "up" is simply directly away from (0,0,0)
|
||||
osg::Vec3d up = modelCenter;
|
||||
up.normalize();
|
||||
|
||||
ma = getMeshIntersection(buffer, masterLocator, *coastline_iter - modelCenter, up);
|
||||
coastline_iter++;
|
||||
|
||||
for (; coastline_iter != coastline._nodes.end(); coastline_iter++) {
|
||||
mb = getMeshIntersection(buffer, masterLocator, *coastline_iter - modelCenter, up);
|
||||
auto esl = VPBElevationSlice::computeVPBElevationSlice(buffer._landGeometry, ma, mb, up);
|
||||
|
||||
for(auto eslitr = esl.begin(); eslitr != esl.end(); ++eslitr) {
|
||||
coastlinePoints.push_back(*eslitr);
|
||||
}
|
||||
|
||||
// Now traverse the next segment
|
||||
ma = mb;
|
||||
}
|
||||
|
||||
if (coastlinePoints.size() == 0) return;
|
||||
|
||||
// We now have a series of points following the topography of the elevation mesh.
|
||||
|
||||
auto iter = coastlinePoints.begin();
|
||||
osg::Vec3d start = *iter;
|
||||
iter++;
|
||||
|
||||
osg::Vec3d last_spanwise = (*iter - start)^ up;
|
||||
last_spanwise.normalize();
|
||||
|
||||
float yTexBaseA = 0.0f;
|
||||
float yTexBaseB = 0.0f;
|
||||
|
||||
for (; iter != coastlinePoints.end(); iter++) {
|
||||
|
||||
osg::Vec3d end = *iter;
|
||||
|
||||
// Ignore tiny segments - likely artifacts of the elevation slicer
|
||||
if ((end - start).length2() < 5.0) continue;
|
||||
|
||||
// Find a spanwise vector
|
||||
osg::Vec3d spanwise = ((end-start) ^ up);
|
||||
spanwise.normalize();
|
||||
|
||||
// Define the coastline extents. Angle it in slightly on the seaward side
|
||||
const osg::Vec3d a = start + up;
|
||||
const osg::Vec3d b = start + last_spanwise * coastline._width;
|
||||
const osg::Vec3d c = end + up;
|
||||
const osg::Vec3d d = end + spanwise * coastline._width;
|
||||
|
||||
// Determine the x and y texture coordinates for the edges
|
||||
const float xTex = 0.5 * coastline._width / xsize;
|
||||
const float yTexA = yTexBaseA + (c-a).length() / ysize;
|
||||
const float yTexB = yTexBaseB + (d-b).length() / ysize;
|
||||
|
||||
// Now generate two triangles, .
|
||||
v->push_back(a);
|
||||
v->push_back(b);
|
||||
v->push_back(c);
|
||||
|
||||
t->push_back(osg::Vec2d(0, yTexBaseA));
|
||||
t->push_back(osg::Vec2d(xTex, yTexBaseB));
|
||||
t->push_back(osg::Vec2d(0, yTexA));
|
||||
|
||||
v->push_back(b);
|
||||
v->push_back(d);
|
||||
v->push_back(c);
|
||||
|
||||
t->push_back(osg::Vec2d(xTex, yTexBaseB));
|
||||
t->push_back(osg::Vec2d(xTex, yTexB));
|
||||
t->push_back(osg::Vec2d(0, yTexBaseA));
|
||||
|
||||
// Normal is straight from the quad
|
||||
osg::Vec3d normal = (end-start)^spanwise;
|
||||
normal.normalize();
|
||||
for (unsigned int i = 0; i < 6; i++) n->push_back(normal);
|
||||
|
||||
start = end;
|
||||
yTexBaseA = yTexA;
|
||||
yTexBaseB = yTexB;
|
||||
last_spanwise = spanwise;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the intersection of a given SGGeod with the terrain mesh
|
||||
osg::Vec3d VPBTechnique::getMeshIntersection(BufferData& buffer, Locator* masterLocator, osg::Vec3d pt, osg::Vec3d up)
|
||||
{
|
||||
@@ -2145,6 +2337,35 @@ void VPBTechnique::addAreaFeatureList(SGBucket bucket, AreaFeatureBinList areaLi
|
||||
terrainNode->accept(ftv);
|
||||
}
|
||||
|
||||
void VPBTechnique::addCoastlineList(SGBucket bucket, CoastlineBinList coastline, osg::ref_ptr<osg::Node> terrainNode)
|
||||
{
|
||||
if (coastline.empty()) return;
|
||||
|
||||
// Block to mutex the List alone
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(VPBTechnique::_coastFeatureLists_mutex); // Lock the _lineFeatureLists for this scope
|
||||
_coastFeatureLists.push_back(std::pair(bucket, coastline));
|
||||
}
|
||||
|
||||
// We need to trigger a re-build of the appropriate Terrain tile, so create a pretend node and run the TerrainVisitor to
|
||||
// "dirty" the TerrainTile that it intersects with.
|
||||
osg::ref_ptr<osg::Node> n = new osg::Node();
|
||||
|
||||
//SGVec3d coord1, coord2;
|
||||
//SGGeodesy::SGGeodToCart(SGGeod::fromDegM(bucket.get_center_lon() -0.5*bucket.get_width(), bucket.get_center_lat() -0.5*bucket.get_height(), 0.0), coord1);
|
||||
//SGGeodesy::SGGeodToCart(SGGeod::fromDegM(bucket.get_center_lon() +0.5*bucket.get_width(), bucket.get_center_lat() +0.5*bucket.get_height(), 0.0), coord2);
|
||||
//osg::BoundingBox bbox = osg::BoundingBox(toOsg(coord1), toOsg(coord2));
|
||||
//n->setInitialBound(bbox);
|
||||
|
||||
SGVec3d coord;
|
||||
SGGeodesy::SGGeodToCart(SGGeod::fromDegM(bucket.get_center_lon(), bucket.get_center_lat(), 0.0), coord);
|
||||
n->setInitialBound(osg::BoundingSphere(toOsg(coord), max(bucket.get_width_m(), bucket.get_height_m())));
|
||||
|
||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "Adding line features to " << bucket.gen_index_str());
|
||||
TerrainVisitor ftv(n, TerrainTile::ALL_DIRTY, 0);
|
||||
terrainNode->accept(ftv);
|
||||
}
|
||||
|
||||
void VPBTechnique::unloadFeatures(SGBucket bucket)
|
||||
{
|
||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "Erasing all roads with entry " << bucket);
|
||||
@@ -2152,8 +2373,7 @@ void VPBTechnique::unloadFeatures(SGBucket bucket)
|
||||
// C++ 20...
|
||||
//std::erase_if(_lineFeatureLists, [bucket](BucketLineFeatureBinList p) { return p.first == bucket; } );
|
||||
//std::erase_if(_lineFeatureLists, [bucket](BucketAreaFeatureBinList p) { return p.first == bucket; } );
|
||||
//std::erase_if(_coastFeatureLists, [bucket](BucketCoastlineBinList p) { return p.first == bucket; } );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <simgear/scene/material/matlib.hxx>
|
||||
#include <simgear/scene/tgdb/AreaFeatureBin.hxx>
|
||||
#include <simgear/scene/tgdb/LineFeatureBin.hxx>
|
||||
#include <simgear/scene/tgdb/CoastlineBin.hxx>
|
||||
|
||||
using namespace osgTerrain;
|
||||
|
||||
@@ -95,9 +96,10 @@ class VPBTechnique : public TerrainTechnique
|
||||
static void removeElevationConstraint(osg::ref_ptr<osg::Node> constraint);
|
||||
static osg::Vec3d checkAgainstElevationConstraints(osg::Vec3d origin, osg::Vec3d vertex, float vertex_gap);
|
||||
|
||||
// LineFeatures and AreaFeaturesare draped over the underlying mesh.
|
||||
// LineFeatures and AreaFeatures are draped over the underlying mesh.
|
||||
static void addLineFeatureList(SGBucket bucket, LineFeatureBinList roadList, osg::ref_ptr<osg::Node> terrainNode);
|
||||
static void addAreaFeatureList(SGBucket bucket, AreaFeatureBinList areaList, osg::ref_ptr<osg::Node> terrainNode);
|
||||
static void addCoastlineList(SGBucket bucket, CoastlineBinList areaList, osg::ref_ptr<osg::Node> terrainNode);
|
||||
static void unloadFeatures(SGBucket bucket);
|
||||
|
||||
protected:
|
||||
@@ -136,8 +138,9 @@ class VPBTechnique : public TerrainTechnique
|
||||
virtual void applyTrees(BufferData& buffer, Locator* masterLocator);
|
||||
|
||||
virtual void applyLineFeatures(BufferData& buffer, Locator* masterLocator);
|
||||
virtual void generateLineFeature(BufferData& buffer, Locator*
|
||||
masterLocator, LineFeatureBin::LineFeature road,
|
||||
virtual void generateLineFeature(BufferData& buffer,
|
||||
Locator* masterLocator,
|
||||
LineFeatureBin::LineFeature road,
|
||||
osg::Vec3d modelCenter,
|
||||
osg::Vec3Array* v,
|
||||
osg::Vec2Array* t,
|
||||
@@ -146,8 +149,9 @@ class VPBTechnique : public TerrainTechnique
|
||||
unsigned int ysize);
|
||||
|
||||
virtual void applyAreaFeatures(BufferData& buffer, Locator* masterLocator);
|
||||
virtual void generateAreaFeature(BufferData& buffer, Locator*
|
||||
masterLocator, AreaFeatureBin::AreaFeature area,
|
||||
virtual void generateAreaFeature(BufferData& buffer,
|
||||
Locator* masterLocator,
|
||||
AreaFeatureBin::AreaFeature area,
|
||||
osg::Vec3d modelCenter,
|
||||
osg::Geometry* geometry,
|
||||
osg::Vec3Array* v,
|
||||
@@ -156,6 +160,17 @@ class VPBTechnique : public TerrainTechnique
|
||||
unsigned int xsize,
|
||||
unsigned int ysize);
|
||||
|
||||
virtual void applyCoastline(BufferData& buffer, Locator* masterLocator);
|
||||
virtual void generateCoastlineFeature(BufferData& buffer,
|
||||
Locator* masterLocator,
|
||||
LineFeatureBin::LineFeature coastLine,
|
||||
osg::Vec3d modelCenter,
|
||||
osg::Vec3Array* v,
|
||||
osg::Vec2Array* t,
|
||||
osg::Vec3Array* n,
|
||||
unsigned int xsize,
|
||||
unsigned int ysize);
|
||||
|
||||
virtual osg::Vec3d getMeshIntersection(BufferData& buffer, Locator* masterLocator, osg::Vec3d pt, osg::Vec3d up);
|
||||
|
||||
OpenThreads::Mutex _writeBufferMutex;
|
||||
@@ -176,6 +191,7 @@ class VPBTechnique : public TerrainTechnique
|
||||
|
||||
typedef std::pair<SGBucket, LineFeatureBinList> BucketLineFeatureBinList;
|
||||
typedef std::pair<SGBucket, AreaFeatureBinList> BucketAreaFeatureBinList;
|
||||
typedef std::pair<SGBucket, CoastlineBinList> BucketCoastlineBinList;
|
||||
|
||||
inline static std::list<BucketLineFeatureBinList> _lineFeatureLists;
|
||||
inline static std::mutex _lineFeatureLists_mutex; // protects the _lineFeatureLists;
|
||||
@@ -183,8 +199,12 @@ class VPBTechnique : public TerrainTechnique
|
||||
inline static std::list<BucketAreaFeatureBinList> _areaFeatureLists;
|
||||
inline static std::mutex _areaFeatureLists_mutex; // protects the _areaFeatureLists;
|
||||
|
||||
inline static std::list<BucketCoastlineBinList> _coastFeatureLists;
|
||||
inline static std::mutex _coastFeatureLists_mutex; // protects the _areaFeatureLists;
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
146
simgear/scene/tgdb/VPBTileBounds.cxx
Normal file
146
simgear/scene/tgdb/VPBTileBounds.cxx
Normal file
@@ -0,0 +1,146 @@
|
||||
// VPBTileBounds.cxx -- VirtualPlanetBuilder Tile bounds for clipping
|
||||
//
|
||||
// Copyright (C) 2021 Stuart Buchanan
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#include "VPBTileBounds.hxx"
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
|
||||
TileBounds::TileBounds(Locator *locator, osg::Vec3d up) {
|
||||
// Determine the corners of the tile;
|
||||
locator->convertLocalToModel(osg::Vec3d(0.0, 0.0, 0.0), v00);
|
||||
locator->convertLocalToModel(osg::Vec3d(1.0, 0.0, 0.0), v10);
|
||||
locator->convertLocalToModel(osg::Vec3d(0.0, 1.0, 0.0), v01);
|
||||
locator->convertLocalToModel(osg::Vec3d(1.0, 1.0, 0.0), v11);
|
||||
|
||||
corner[0] = v10;
|
||||
corner[1] = v11;
|
||||
corner[2] = v01;
|
||||
corner[3] = v00;
|
||||
|
||||
// Determine the normals of the planes defining the vertical edges of the tiles.
|
||||
// This can be found using the cross product of the horizontal line and an appropriate "up"
|
||||
// vector. We will approximate the last using the center rather than working out different
|
||||
// "up" vectors for each edge individually. We assume that (0,0) in local coords is bottom left.
|
||||
south = (v10 - v00) ^ up;
|
||||
east = (v11 - v10) ^ up;
|
||||
north = (v01 - v11) ^ up;
|
||||
west = (v00 - v01) ^ up;
|
||||
}
|
||||
|
||||
std::list<osg::Vec3d> TileBounds::clipToTile(std::list<osg::Vec3d> points) {
|
||||
|
||||
std::list<osg::Vec3d> lreturn;
|
||||
|
||||
bool last_in = false;
|
||||
auto last_pt = points.begin();
|
||||
|
||||
for (auto p = points.begin(); p != points.end(); p++) {
|
||||
if (insideTile(*p)) {
|
||||
|
||||
/*
|
||||
if ((last_in == false) && (last_pt != p)) {
|
||||
// Last point was outside the border of the tile, so we need to
|
||||
// add the actual intersection as an additional point if required.
|
||||
lreturn.push_back(getTileIntersection(*p, *last_pt));
|
||||
}
|
||||
*/
|
||||
|
||||
// Last point wasn't in, but we need to include it to ensure we get an
|
||||
// intersection with the edge of the tile.
|
||||
if (last_in == false) lreturn.push_back(*last_pt);
|
||||
|
||||
// Point is within bounds, so add it.
|
||||
lreturn.push_back(*p);
|
||||
|
||||
last_in = true;
|
||||
} else if (last_in) {
|
||||
// Point is outside bounds, but last point was inside. So add it to ensure
|
||||
// we catch the intersection with the mesh edge.
|
||||
lreturn.push_back(*p);
|
||||
last_in = false;
|
||||
}
|
||||
|
||||
last_pt = p;
|
||||
}
|
||||
|
||||
return lreturn;
|
||||
}
|
||||
|
||||
bool TileBounds::insideTile(osg::Vec3d pt) {
|
||||
|
||||
float s = south * (pt - v00);
|
||||
float e = east * (pt - v10);
|
||||
float n = north * (pt - v11);
|
||||
float w = west * (pt - v01);
|
||||
|
||||
return ((s<0) && (e<0) && (n<0) && (w<0));
|
||||
}
|
||||
|
||||
// Get the Tile intersection, and also the corner of the tile to the right of the intersection.
|
||||
// This corner can be used to define the seaward edge of some coastline.
|
||||
osg::Vec3d TileBounds::getTileIntersection(osg::Vec3d inside, osg::Vec3d outside) {
|
||||
|
||||
if (! insideTile(inside)) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Invalid VPB Tile intersection - \"inside\" point not inside!");
|
||||
return inside;
|
||||
}
|
||||
|
||||
if (insideTile(outside)) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Invalid VPB Tile intersection - \"outside\" point not outside!");
|
||||
return outside;
|
||||
}
|
||||
|
||||
// Simply clip against each of the planes in turn.
|
||||
osg::Vec3d intersect = outside;
|
||||
intersect = getPlaneIntersection(inside, intersect, south, v00);
|
||||
intersect = getPlaneIntersection(inside, intersect, east, v10);
|
||||
intersect = getPlaneIntersection(inside, intersect, north, v11);
|
||||
intersect = getPlaneIntersection(inside, intersect, west, v01);
|
||||
|
||||
return intersect;
|
||||
}
|
||||
|
||||
osg::Vec3d TileBounds::getPlaneIntersection(osg::Vec3d inside, osg::Vec3d outside, osg::Vec3d normal, osg::Vec3d plane) {
|
||||
// Check for any intersection at all first
|
||||
osg::Vec3d n = normal;
|
||||
osg::Vec3d p0 = plane;
|
||||
osg::Vec3d l0 = inside;
|
||||
osg::Vec3d l = outside-inside;
|
||||
|
||||
if (fabs(l * n) < 0.01) return outside;
|
||||
|
||||
float d = ((p0 - l0) * n) / (l * n);
|
||||
return l0 + l * d;
|
||||
|
||||
|
||||
/*
|
||||
float i = normal * (outside - plane);
|
||||
|
||||
if (i < 0) {
|
||||
// There's an intersection, so calculate it
|
||||
double d = ((plane - inside) * normal) / ((outside - inside) * normal);
|
||||
return inside + (outside - inside) * d;
|
||||
} else {
|
||||
// No intersection
|
||||
return outside;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
49
simgear/scene/tgdb/VPBTileBounds.hxx
Normal file
49
simgear/scene/tgdb/VPBTileBounds.hxx
Normal file
@@ -0,0 +1,49 @@
|
||||
// VPBTileBounds.hxx -- VirtualPlanetBuilder Tile bounds for clipping
|
||||
//
|
||||
// Copyright (C) 2021 Stuart Buchanan
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#ifndef VPBTILEBOUNDS
|
||||
#define VPBTILEBOUNDS 1
|
||||
|
||||
#include <osg/Geometry>
|
||||
#include <osgTerrain/TerrainTile>
|
||||
|
||||
using namespace osgTerrain;
|
||||
|
||||
|
||||
class TileBounds {
|
||||
public:
|
||||
TileBounds(Locator *locator, osg::Vec3d up);
|
||||
virtual std::list<osg::Vec3d> clipToTile(std::list<osg::Vec3d> points);
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool insideTile(osg::Vec3d pt);
|
||||
virtual osg::Vec3d getTileIntersection(osg::Vec3d inside, osg::Vec3d outside);
|
||||
virtual osg::Vec3d getPlaneIntersection(osg::Vec3d inside, osg::Vec3d outside, osg::Vec3d normal, osg::Vec3d plane);
|
||||
|
||||
// Corners of the tile
|
||||
osg::Vec3d v00, v01, v10, v11;
|
||||
osg::Vec3d corner[4];
|
||||
|
||||
// Plan normals for the tile bounds
|
||||
osg::Vec3d north, east, south, west;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user