Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e0c39bb68 | ||
|
|
f20b416cfe | ||
|
|
47e06b5216 | ||
|
|
bfcdf22705 | ||
|
|
d0db407faa |
+1
-1
@@ -1 +1 @@
|
|||||||
2020.3.3
|
2020.3.4
|
||||||
|
|||||||
@@ -218,6 +218,9 @@ const float SG_RADIANS_TO_DEGREES = 180.0f / SG_PI;
|
|||||||
#define SG_OBJECT_RANGE_ROUGH 9000.0
|
#define SG_OBJECT_RANGE_ROUGH 9000.0
|
||||||
#define SG_OBJECT_RANGE_DETAILED 1500.0
|
#define SG_OBJECT_RANGE_DETAILED 1500.0
|
||||||
|
|
||||||
|
/** Minimum expiry time of PagedLOD within the Tile. Overridden by /sim/rendering/plod-minimum-expiry-time-secs **/
|
||||||
|
#define SG_TILE_MIN_EXPIRY 180.0
|
||||||
|
|
||||||
/** Radius of scenery tiles in m **/
|
/** Radius of scenery tiles in m **/
|
||||||
#define SG_TILE_RADIUS 14000.0
|
#define SG_TILE_RADIUS 14000.0
|
||||||
|
|
||||||
|
|||||||
@@ -646,16 +646,21 @@ bool SGMetar::scanWind()
|
|||||||
double gust = NaN;
|
double gust = NaN;
|
||||||
if (*m == 'G') {
|
if (*m == 'G') {
|
||||||
m++;
|
m++;
|
||||||
if (!scanNumber(&m, &i, 2, 3))
|
if (!strncmp(m, "//", 2)) // speed not measurable
|
||||||
|
m += 2, i = -1;
|
||||||
|
else if (!scanNumber(&m, &i, 2, 3))
|
||||||
return false;
|
return false;
|
||||||
gust = i;
|
|
||||||
|
if (i != -1)
|
||||||
|
gust = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
double factor;
|
double factor;
|
||||||
if (!strncmp(m, "KT", 2))
|
if (!strncmp(m, "KT", 2))
|
||||||
m += 2, factor = SG_KT_TO_MPS;
|
m += 2, factor = SG_KT_TO_MPS;
|
||||||
else if (!strncmp(m, "KMH", 3))
|
else if (!strncmp(m, "KMH", 3)) // invalid Km/h
|
||||||
m += 3, factor = SG_KMH_TO_MPS;
|
m += 3, factor = SG_KMH_TO_MPS;
|
||||||
else if (!strncmp(m, "KPH", 3)) // ??
|
else if (!strncmp(m, "KPH", 3)) // invalid Km/h
|
||||||
m += 3, factor = SG_KMH_TO_MPS;
|
m += 3, factor = SG_KMH_TO_MPS;
|
||||||
else if (!strncmp(m, "MPS", 3))
|
else if (!strncmp(m, "MPS", 3))
|
||||||
m += 3, factor = 1.0;
|
m += 3, factor = 1.0;
|
||||||
@@ -680,18 +685,28 @@ bool SGMetar::scanVariability()
|
|||||||
{
|
{
|
||||||
char *m = _m;
|
char *m = _m;
|
||||||
int from, to;
|
int from, to;
|
||||||
if (!scanNumber(&m, &from, 3))
|
|
||||||
|
if (!strncmp(m, "///", 3)) // direction not measurable
|
||||||
|
m += 3, from = -1;
|
||||||
|
else if (!scanNumber(&m, &from, 3))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (*m++ != 'V')
|
if (*m++ != 'V')
|
||||||
return false;
|
return false;
|
||||||
if (!scanNumber(&m, &to, 3))
|
|
||||||
|
if (!strncmp(m, "///", 3)) // direction not measurable
|
||||||
|
m += 3, to = -1;
|
||||||
|
else if (!scanNumber(&m, &to, 3))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!scanBoundary(&m))
|
if (!scanBoundary(&m))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_m = m;
|
_m = m;
|
||||||
_wind_range_from = from;
|
_wind_range_from = from;
|
||||||
_wind_range_to = to;
|
_wind_range_to = to;
|
||||||
_grpcount++;
|
_grpcount++;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,15 @@ void test_sensor_failure_wind()
|
|||||||
SGMetar m1("2020/10/23 16:55 LIVD 231655Z /////KT 9999 OVC025 10/08 Q1020 RMK OVC VIS MIN 9999 BLU");
|
SGMetar m1("2020/10/23 16:55 LIVD 231655Z /////KT 9999 OVC025 10/08 Q1020 RMK OVC VIS MIN 9999 BLU");
|
||||||
SG_CHECK_EQUAL(m1.getWindDir(), -1);
|
SG_CHECK_EQUAL(m1.getWindDir(), -1);
|
||||||
SG_CHECK_EQUAL_EP2(m1.getWindSpeed_kt(), -1, TEST_EPSILON);
|
SG_CHECK_EQUAL_EP2(m1.getWindSpeed_kt(), -1, TEST_EPSILON);
|
||||||
|
|
||||||
|
SGMetar m2("2020/10/21 16:55 LIVD 211655Z /////KT CAVOK 07/03 Q1023 RMK SKC VIS MIN 9999 BLU");
|
||||||
|
SG_CHECK_EQUAL(m2.getWindDir(), -1);
|
||||||
|
SG_CHECK_EQUAL_EP2(m2.getWindSpeed_kt(), -1, TEST_EPSILON);
|
||||||
|
|
||||||
|
SGMetar m3("2020/11/17 16:00 CYAZ 171600Z 14040G//KT 10SM -RA OVC012 12/11 A2895 RMK NS8 VIA CYXY SLP806 DENSITY ALT 900FT");
|
||||||
|
SG_CHECK_EQUAL(m3.getWindDir(), 140);
|
||||||
|
SG_CHECK_EQUAL_EP2(m3.getWindSpeed_kt(), 40, TEST_EPSILON);
|
||||||
|
SG_CHECK_EQUAL_EP2(m3.getGustSpeed_kt(), SGMetarNaN, TEST_EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_wind_unit_not_specified()
|
void test_wind_unit_not_specified()
|
||||||
|
|||||||
@@ -994,7 +994,10 @@ HTTPRepository::failure() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onDone() override {
|
void onDone() override {
|
||||||
file->close();
|
if (file) {
|
||||||
|
file->close();
|
||||||
|
}
|
||||||
|
|
||||||
if (responseCode() == 200) {
|
if (responseCode() == 200) {
|
||||||
std::string hash =
|
std::string hash =
|
||||||
strutils::encodeHex(sha1_result(&hashContext), HASH_LENGTH);
|
strutils::encodeHex(sha1_result(&hashContext), HASH_LENGTH);
|
||||||
|
|||||||
+24
-5
@@ -19,6 +19,10 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <exception> // can't use sg_exception becuase of PROPS_STANDALONE
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -51,11 +55,15 @@ using namespace simgear;
|
|||||||
|
|
||||||
struct SGPropertyNodeListeners
|
struct SGPropertyNodeListeners
|
||||||
{
|
{
|
||||||
|
/* Protect _num_iterators and _items. We use a recursive mutex to allow
|
||||||
|
nested access to work as normal. */
|
||||||
|
std::recursive_mutex _rmutex;
|
||||||
|
|
||||||
/* This keeps a count of the current number of nested invocations of
|
/* This keeps a count of the current number of nested invocations of
|
||||||
forEachListener(). If non-zero, other code higher up the stack is iterating
|
forEachListener(). If non-zero, other code higher up the stack is iterating
|
||||||
_items[] so for example code must not erase items in the vector. */
|
_items[] so for example code must not erase items in the vector. */
|
||||||
int _num_iterators = 0;
|
int _num_iterators = 0;
|
||||||
|
|
||||||
std::vector<SGPropertyChangeListener *> _items;
|
std::vector<SGPropertyChangeListener *> _items;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2406,6 +2414,7 @@ SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
|
|||||||
if (_listeners == 0)
|
if (_listeners == 0)
|
||||||
_listeners = new SGPropertyNodeListeners;
|
_listeners = new SGPropertyNodeListeners;
|
||||||
|
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(_listeners->_rmutex);
|
||||||
/* If there's a nullptr entry (a listener that was unregistered), we
|
/* If there's a nullptr entry (a listener that was unregistered), we
|
||||||
overwrite it. This ensures that listeners that routinely unregister+register
|
overwrite it. This ensures that listeners that routinely unregister+register
|
||||||
themselves don't make _listeners->_items grow unnecessarily. Otherwise simply
|
themselves don't make _listeners->_items grow unnecessarily. Otherwise simply
|
||||||
@@ -2429,9 +2438,13 @@ SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
|
|||||||
{
|
{
|
||||||
if (_listeners == 0)
|
if (_listeners == 0)
|
||||||
return;
|
return;
|
||||||
|
/* We use a std::unique_lock rather than a std::lock_guard because we may
|
||||||
|
need to unlock early. */
|
||||||
|
std::unique_lock<std::recursive_mutex> lock(_listeners->_rmutex);
|
||||||
vector<SGPropertyChangeListener*>::iterator it =
|
vector<SGPropertyChangeListener*>::iterator it =
|
||||||
find(_listeners->_items.begin(), _listeners->_items.end(), listener);
|
find(_listeners->_items.begin(), _listeners->_items.end(), listener);
|
||||||
if (it != _listeners->_items.end()) {
|
if (it != _listeners->_items.end()) {
|
||||||
|
assert(_listeners->_num_iterators >= 0);
|
||||||
if (_listeners->_num_iterators) {
|
if (_listeners->_num_iterators) {
|
||||||
/* _listeners._items is currently being iterated further up the stack in
|
/* _listeners._items is currently being iterated further up the stack in
|
||||||
this thread by one or more nested invocations of forEachListener(), so
|
this thread by one or more nested invocations of forEachListener(), so
|
||||||
@@ -2450,6 +2463,7 @@ SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
|
|||||||
_listeners->_items.erase(it);
|
_listeners->_items.erase(it);
|
||||||
listener->unregister_property(this);
|
listener->unregister_property(this);
|
||||||
if (_listeners->_items.empty()) {
|
if (_listeners->_items.empty()) {
|
||||||
|
lock.unlock();
|
||||||
delete _listeners;
|
delete _listeners;
|
||||||
_listeners = 0;
|
_listeners = 0;
|
||||||
}
|
}
|
||||||
@@ -2511,9 +2525,11 @@ static void forEachListener(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (!_listeners) return;
|
if (!_listeners) return;
|
||||||
|
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(_listeners->_rmutex);
|
||||||
|
assert(_listeners->_num_iterators >= 0);
|
||||||
_listeners->_num_iterators += 1;
|
_listeners->_num_iterators += 1;
|
||||||
|
|
||||||
/* We need to use an index here when iterating _listeners->_items, not an
|
/* We need to use an index here when iterating _listeners->_items, not an
|
||||||
iterator. This is because a listener may add new listeners, causing the
|
iterator. This is because a listener may add new listeners, causing the
|
||||||
vector to be reallocated, which would invalidate any iterator. */
|
vector to be reallocated, which would invalidate any iterator. */
|
||||||
@@ -2528,10 +2544,12 @@ static void forEachListener(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_listeners->_num_iterators -= 1;
|
_listeners->_num_iterators -= 1;
|
||||||
|
assert(_listeners->_num_iterators >= 0);
|
||||||
|
|
||||||
if (_listeners->_num_iterators == 0) {
|
if (_listeners->_num_iterators == 0) {
|
||||||
|
|
||||||
/* Remove any items that have been set to nullptr. */
|
/* Remove any items that have been set to nullptr. */
|
||||||
_listeners->_items.erase(
|
_listeners->_items.erase(
|
||||||
std::remove(_listeners->_items.begin(), _listeners->_items.end(), (SGPropertyChangeListener*) nullptr),
|
std::remove(_listeners->_items.begin(), _listeners->_items.end(), (SGPropertyChangeListener*) nullptr),
|
||||||
@@ -2547,6 +2565,7 @@ static void forEachListener(
|
|||||||
int SGPropertyNode::nListeners() const
|
int SGPropertyNode::nListeners() const
|
||||||
{
|
{
|
||||||
if (!_listeners) return 0;
|
if (!_listeners) return 0;
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(_listeners->_rmutex);
|
||||||
int n = 0;
|
int n = 0;
|
||||||
for (auto listener: _listeners->_items) {
|
for (auto listener: _listeners->_items) {
|
||||||
if (listener) n += 1;
|
if (listener) n += 1;
|
||||||
|
|||||||
@@ -212,7 +212,8 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
STGObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD()));
|
STGObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD()));
|
||||||
quadtree.buildQuadTree(_objectStaticList.begin(), _objectStaticList.end());
|
quadtree.buildQuadTree(_objectStaticList.begin(), _objectStaticList.end());
|
||||||
osg::ref_ptr<osg::Group> group = quadtree.getRoot();
|
osg::ref_ptr<osg::Group> group = quadtree.getRoot();
|
||||||
group->setName("STG-group-A");
|
string group_name = string("STG-group-A ").append(_bucket.gen_index_str());
|
||||||
|
group->setName(group_name);
|
||||||
group->setDataVariance(osg::Object::STATIC);
|
group->setDataVariance(osg::Object::STATIC);
|
||||||
|
|
||||||
simgear::AirportSignBuilder signBuilder(_options->getMaterialLib(), _bucket.get_center());
|
simgear::AirportSignBuilder signBuilder(_options->getMaterialLib(), _bucket.get_center());
|
||||||
@@ -586,10 +587,12 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
{
|
{
|
||||||
osg::ref_ptr<SGReaderWriterOptions> options;
|
osg::ref_ptr<SGReaderWriterOptions> options;
|
||||||
options = SGReaderWriterOptions::copyOrCreate(opt);
|
options = SGReaderWriterOptions::copyOrCreate(opt);
|
||||||
|
float pagedLODExpiry = atoi(options->getPluginStringData("SimGear::PAGED_LOD_EXPIRY").c_str());
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> terrainGroup = new osg::Group;
|
osg::ref_ptr<osg::Group> terrainGroup = new osg::Group;
|
||||||
terrainGroup->setDataVariance(osg::Object::STATIC);
|
terrainGroup->setDataVariance(osg::Object::STATIC);
|
||||||
terrainGroup->setName("terrain");
|
std::string terrain_name = string("terrain ").append(bucket.gen_index_str());
|
||||||
|
terrainGroup->setName(terrain_name);
|
||||||
|
|
||||||
if (_foundBase) {
|
if (_foundBase) {
|
||||||
for (auto stgObject : _objectList) {
|
for (auto stgObject : _objectList) {
|
||||||
@@ -637,11 +640,13 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
} else {
|
} else {
|
||||||
osg::PagedLOD* pagedLOD = new osg::PagedLOD;
|
osg::PagedLOD* pagedLOD = new osg::PagedLOD;
|
||||||
pagedLOD->setCenterMode(osg::PagedLOD::USE_BOUNDING_SPHERE_CENTER);
|
pagedLOD->setCenterMode(osg::PagedLOD::USE_BOUNDING_SPHERE_CENTER);
|
||||||
pagedLOD->setName("pagedObjectLOD");
|
std::string name = string("pagedObjectLOD ").append(bucket.gen_index_str());
|
||||||
|
pagedLOD->setName(name);
|
||||||
|
|
||||||
// This should be visible in any case.
|
// This should be visible in any case.
|
||||||
// If this is replaced by some lower level of detail, the parent LOD node handles this.
|
// 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->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
|
// we just need to know about the read file callback that itself holds the data
|
||||||
osg::ref_ptr<DelayLoadReadFileCallback> readFileCallback = new DelayLoadReadFileCallback;
|
osg::ref_ptr<DelayLoadReadFileCallback> readFileCallback = new DelayLoadReadFileCallback;
|
||||||
@@ -658,10 +663,11 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
|
|
||||||
// Objects may end up displayed up to 2x the object range.
|
// Objects may end up displayed up to 2x the object range.
|
||||||
pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 2.0 * _object_range_rough);
|
pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 2.0 * _object_range_rough);
|
||||||
|
pagedLOD->setMinimumExpiryTime(pagedLOD->getNumChildren(), pagedLODExpiry);
|
||||||
pagedLOD->setRadius(SG_TILE_RADIUS);
|
pagedLOD->setRadius(SG_TILE_RADIUS);
|
||||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile PagedLOD Center: " << pagedLOD->getCenter().x() << "," << pagedLOD->getCenter().y() << "," << pagedLOD->getCenter().z() );
|
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 PagedLOD Range: " << (2.0 * _object_range_rough));
|
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 PagedLOD Radius: " << SG_TILE_RADIUS);
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Radius: " << SG_TILE_RADIUS);
|
||||||
return pagedLOD;
|
return pagedLOD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user