Merge pull request #397 from AdenKoperczak/speed_up_geolines

Speed up geolines by avoiding iterative finds
This commit is contained in:
Dan Paulat 2025-03-18 18:59:18 -05:00 committed by GitHub
commit e641c0b0e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 55 additions and 52 deletions

View file

@ -50,6 +50,7 @@ struct GeoLineDrawItem : types::EventHandler
units::angle::degrees<float> angle_ {}; units::angle::degrees<float> angle_ {};
std::string hoverText_ {}; std::string hoverText_ {};
GeoLines::HoverCallback hoverCallback_ {nullptr}; GeoLines::HoverCallback hoverCallback_ {nullptr};
size_t lineIndex_ {0};
}; };
class GeoLines::Impl class GeoLines::Impl
@ -87,10 +88,10 @@ public:
void UpdateBuffers(); void UpdateBuffers();
void UpdateModifiedLineBuffers(); void UpdateModifiedLineBuffers();
void UpdateSingleBuffer(const std::shared_ptr<GeoLineDrawItem>& di, void UpdateSingleBuffer(const std::shared_ptr<GeoLineDrawItem>& di,
std::size_t lineIndex,
std::vector<float>& linesBuffer, std::vector<float>& linesBuffer,
std::vector<GLint>& integerBuffer, std::vector<GLint>& integerBuffer,
std::vector<LineHoverEntry>& hoverLines); std::unordered_map<std::shared_ptr<GeoLineDrawItem>,
LineHoverEntry>& hoverLines);
std::shared_ptr<GlContext> context_; std::shared_ptr<GlContext> context_;
@ -112,8 +113,10 @@ public:
std::vector<float> newLinesBuffer_ {}; std::vector<float> newLinesBuffer_ {};
std::vector<GLint> newIntegerBuffer_ {}; std::vector<GLint> newIntegerBuffer_ {};
std::vector<LineHoverEntry> currentHoverLines_ {}; std::unordered_map<std::shared_ptr<GeoLineDrawItem>, LineHoverEntry>
std::vector<LineHoverEntry> newHoverLines_ {}; currentHoverLines_ {};
std::unordered_map<std::shared_ptr<GeoLineDrawItem>, LineHoverEntry>
newHoverLines_ {};
std::shared_ptr<ShaderProgram> shaderProgram_; std::shared_ptr<ShaderProgram> shaderProgram_;
GLint uMVPMatrixLocation_; GLint uMVPMatrixLocation_;
@ -323,7 +326,9 @@ void GeoLines::StartLines()
std::shared_ptr<GeoLineDrawItem> GeoLines::AddLine() std::shared_ptr<GeoLineDrawItem> GeoLines::AddLine()
{ {
return p->newLineList_.emplace_back(std::make_shared<GeoLineDrawItem>()); auto& di = p->newLineList_.emplace_back(std::make_shared<GeoLineDrawItem>());
di->lineIndex_ = p->newLineList_.size() - 1;
return di;
} }
void GeoLines::SetLineLocation(const std::shared_ptr<GeoLineDrawItem>& di, void GeoLines::SetLineLocation(const std::shared_ptr<GeoLineDrawItem>& di,
@ -470,7 +475,7 @@ void GeoLines::Impl::UpdateBuffers()
// Update line buffer // Update line buffer
UpdateSingleBuffer( UpdateSingleBuffer(
di, i, newLinesBuffer_, newIntegerBuffer_, newHoverLines_); di, newLinesBuffer_, newIntegerBuffer_, newHoverLines_);
} }
// All lines have been updated // All lines have been updated
@ -488,23 +493,15 @@ void GeoLines::Impl::UpdateModifiedLineBuffers()
// Update buffers for modified lines // Update buffers for modified lines
for (auto& di : dirtyLines_) for (auto& di : dirtyLines_)
{ {
// Find modified line in the current list // Check if modified line is in the current list
auto it = if (di->lineIndex_ >= currentLineList_.size() ||
std::find(currentLineList_.cbegin(), currentLineList_.cend(), di); currentLineList_[di->lineIndex_] != di)
// Ignore invalid lines
if (it == currentLineList_.cend())
{ {
continue; continue;
} }
auto lineIndex = std::distance(currentLineList_.cbegin(), it); UpdateSingleBuffer(
di, currentLinesBuffer_, currentIntegerBuffer_, currentHoverLines_);
UpdateSingleBuffer(di,
lineIndex,
currentLinesBuffer_,
currentIntegerBuffer_,
currentHoverLines_);
} }
// Clear list of modified lines // Clear list of modified lines
@ -517,10 +514,10 @@ void GeoLines::Impl::UpdateModifiedLineBuffers()
void GeoLines::Impl::UpdateSingleBuffer( void GeoLines::Impl::UpdateSingleBuffer(
const std::shared_ptr<GeoLineDrawItem>& di, const std::shared_ptr<GeoLineDrawItem>& di,
std::size_t lineIndex,
std::vector<float>& lineBuffer, std::vector<float>& lineBuffer,
std::vector<GLint>& integerBuffer, std::vector<GLint>& integerBuffer,
std::vector<LineHoverEntry>& hoverLines) std::unordered_map<std::shared_ptr<GeoLineDrawItem>, LineHoverEntry>&
hoverLines)
{ {
// Threshold value // Threshold value
units::length::nautical_miles<double> threshold = di->threshold_; units::length::nautical_miles<double> threshold = di->threshold_;
@ -588,10 +585,10 @@ void GeoLines::Impl::UpdateSingleBuffer(
// Buffer position data // Buffer position data
auto lineBufferPosition = lineBuffer.end(); auto lineBufferPosition = lineBuffer.end();
auto lineBufferOffset = lineIndex * kLineBufferLength_; auto lineBufferOffset = di->lineIndex_ * kLineBufferLength_;
auto integerBufferPosition = integerBuffer.end(); auto integerBufferPosition = integerBuffer.end();
auto integerBufferOffset = lineIndex * kIntegerBufferLength_; auto integerBufferOffset = di->lineIndex_ * kIntegerBufferLength_;
if (lineBufferOffset < lineBuffer.size()) if (lineBufferOffset < lineBuffer.size())
{ {
@ -620,9 +617,7 @@ void GeoLines::Impl::UpdateSingleBuffer(
std::copy(integerData.begin(), integerData.end(), integerBufferPosition); std::copy(integerData.begin(), integerData.end(), integerBufferPosition);
} }
auto hoverIt = std::find_if(hoverLines.begin(), auto hoverIt = hoverLines.find(di);
hoverLines.end(),
[&di](auto& entry) { return entry.di_ == di; });
if (di->visible_ && (!di->hoverText_.empty() || if (di->visible_ && (!di->hoverText_.empty() ||
di->hoverCallback_ != nullptr || di->event_ != nullptr)) di->hoverCallback_ != nullptr || di->event_ != nullptr))
@ -644,17 +639,23 @@ void GeoLines::Impl::UpdateSingleBuffer(
if (hoverIt == hoverLines.end()) if (hoverIt == hoverLines.end())
{ {
hoverLines.emplace_back( hoverLines.emplace(di,
LineHoverEntry {di, sc1, sc2, otl, otr, obl, obr}); LineHoverEntry {.di_ = di,
.p1_ = sc1,
.p2_ = sc2,
.otl_ = otl,
.otr_ = otr,
.obl_ = obl,
.obr_ = obr});
} }
else else
{ {
hoverIt->p1_ = sc1; hoverIt->second.p1_ = sc1;
hoverIt->p2_ = sc2; hoverIt->second.p2_ = sc2;
hoverIt->otl_ = otl; hoverIt->second.otl_ = otl;
hoverIt->otr_ = otr; hoverIt->second.otr_ = otr;
hoverIt->obl_ = obl; hoverIt->second.obl_ = obl;
hoverIt->obr_ = obr; hoverIt->second.obr_ = obr;
} }
} }
else if (hoverIt != hoverLines.end()) else if (hoverIt != hoverLines.end())
@ -726,10 +727,12 @@ bool GeoLines::RunMousePicking(
// For each pickable line // For each pickable line
auto it = std::find_if( auto it = std::find_if(
std::execution::par_unseq, std::execution::par_unseq,
p->currentHoverLines_.rbegin(), p->currentHoverLines_.cbegin(),
p->currentHoverLines_.rend(), p->currentHoverLines_.cend(),
[&mapDistance, &selectedTime, &mapMatrix, &mouseCoords](const auto& line) [&mapDistance, &selectedTime, &mapMatrix, &mouseCoords](
const auto& lineIt)
{ {
const auto& line = lineIt.second;
if (( if ((
// Placefile is thresholded // Placefile is thresholded
mapDistance > units::length::meters<double> {0.0} && mapDistance > units::length::meters<double> {0.0} &&
@ -785,24 +788,24 @@ bool GeoLines::RunMousePicking(
return util::maplibre::IsPointInPolygon({tl, bl, br, tr}, mouseCoords); return util::maplibre::IsPointInPolygon({tl, bl, br, tr}, mouseCoords);
}); });
if (it != p->currentHoverLines_.crend()) if (it != p->currentHoverLines_.cend())
{ {
itemPicked = true; itemPicked = true;
if (!it->di_->hoverText_.empty()) if (!it->second.di_->hoverText_.empty())
{ {
// Show tooltip // Show tooltip
util::tooltip::Show(it->di_->hoverText_, mouseGlobalPos); util::tooltip::Show(it->second.di_->hoverText_, mouseGlobalPos);
} }
else if (it->di_->hoverCallback_ != nullptr) else if (it->second.di_->hoverCallback_ != nullptr)
{ {
it->di_->hoverCallback_(it->di_, mouseGlobalPos); it->second.di_->hoverCallback_(it->second.di_, mouseGlobalPos);
} }
if (it->di_->event_ != nullptr) if (it->second.di_->event_ != nullptr)
{ {
// Register event handler // Register event handler
eventHandler = it->di_; eventHandler = it->second.di_;
} }
} }

View file

@ -19,9 +19,8 @@ struct GeoLineDrawItem;
class GeoLines : public DrawItem class GeoLines : public DrawItem
{ {
public: public:
typedef std::function<void(std::shared_ptr<GeoLineDrawItem>&, using HoverCallback = std::function<void(
const QPointF&)> const std::shared_ptr<GeoLineDrawItem>&, const QPointF&)>;
HoverCallback;
explicit GeoLines(std::shared_ptr<GlContext> context); explicit GeoLines(std::shared_ptr<GlContext> context);
~GeoLines(); ~GeoLines();

View file

@ -159,8 +159,9 @@ public:
void ConnectSignals(); void ConnectSignals();
void HandleGeoLinesEvent(std::weak_ptr<gl::draw::GeoLineDrawItem>& di, void HandleGeoLinesEvent(std::weak_ptr<gl::draw::GeoLineDrawItem>& di,
QEvent* ev); QEvent* ev);
void HandleGeoLinesHover(std::shared_ptr<gl::draw::GeoLineDrawItem>& di, void
const QPointF& mouseGlobalPos); HandleGeoLinesHover(const std::shared_ptr<gl::draw::GeoLineDrawItem>& di,
const QPointF& mouseGlobalPos);
void ScheduleRefresh(); void ScheduleRefresh();
LineData& GetLineData(const std::shared_ptr<const awips::Segment>& segment, LineData& GetLineData(const std::shared_ptr<const awips::Segment>& segment,
@ -720,8 +721,8 @@ void AlertLayer::Impl::HandleGeoLinesEvent(
} }
void AlertLayer::Impl::HandleGeoLinesHover( void AlertLayer::Impl::HandleGeoLinesHover(
std::shared_ptr<gl::draw::GeoLineDrawItem>& di, const std::shared_ptr<gl::draw::GeoLineDrawItem>& di,
const QPointF& mouseGlobalPos) const QPointF& mouseGlobalPos)
{ {
if (di != lastHoverDi_) if (di != lastHoverDi_)
{ {