Skip to content
This repository was archived by the owner on May 12, 2026. It is now read-only.

Commit 410365d

Browse files
Evict unchanged data from the edit buffer as it is no longer needed
1 parent f08e477 commit 410365d

1 file changed

Lines changed: 149 additions & 0 deletions

File tree

Alidade/Services/EditBufferService.cs

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace Alidade.Services;
1616
public class EditBufferService : IDisposable
1717
{
1818
private const double MinFetchZoom = 17.0;
19+
private const double EvictionMultiplier = 2.0;
1920
private readonly IMediator _mediator;
2021
private readonly NsiService _nsi;
2122
private readonly IndexedDBService _storage;
@@ -96,6 +97,9 @@ private void OnMapStateChanged(object? sender, EventArgs e)
9697
_fetchCts.Cancel();
9798
_fetchCts.Dispose();
9899
_fetchCts = new CancellationTokenSource();
100+
101+
EvictOutOfViewportData(bounds);
102+
99103
_ = _mediator.Publish(new FetchBboxRequested.Notification(bounds), _fetchCts.Token);
100104

101105
if (bounds.Zoom >= MinFetchZoom)
@@ -417,6 +421,151 @@ private async Task SetSourceAsync(string sourceId, IReadOnlyList<NetTopologySuit
417421
#endregion
418422

419423
#region Data fetch
424+
private void EvictOutOfViewportData(MapBounds bounds)
425+
{
426+
EditBufferState state = _editState.State;
427+
428+
double latSpan = bounds.North - bounds.South;
429+
double lonSpan = bounds.East - bounds.West;
430+
double latPad = latSpan * (EvictionMultiplier - 1.0) / 2.0;
431+
double lonPad = lonSpan * (EvictionMultiplier - 1.0) / 2.0;
432+
double keepSouth = bounds.South - latPad;
433+
double keepNorth = bounds.North + latPad;
434+
double keepWest = bounds.West - lonPad;
435+
double keepEast = bounds.East + lonPad;
436+
437+
// Pass 1: evict Fetched ways with no node inside keep-bounds.
438+
List<long> wayIdsToEvict = [];
439+
foreach (KeyValuePair<long, OsmWay> kv in state.Ways)
440+
{
441+
if (state.EditStates.GetValueOrDefault(kv.Value.Ref) != EditState.Fetched)
442+
{
443+
continue;
444+
}
445+
446+
bool hasNodeInBounds = false;
447+
foreach (long nodeId in kv.Value.NodeIds)
448+
{
449+
if (state.Nodes.TryGetValue(nodeId, out OsmNode? n)
450+
&& n.Lat <= keepNorth
451+
&& n.Lon <= keepEast
452+
&& n.Lat >= keepSouth
453+
&& n.Lon >= keepWest)
454+
{
455+
hasNodeInBounds = true;
456+
break;
457+
}
458+
}
459+
460+
if (!hasNodeInBounds)
461+
{
462+
wayIdsToEvict.Add(kv.Key);
463+
}
464+
}
465+
466+
// Node IDs still claimed by surviving ways must be retained.
467+
HashSet<long> survivingWayNodeIds = [];
468+
foreach (KeyValuePair<long, OsmWay> kv in state.Ways)
469+
{
470+
if (!wayIdsToEvict.Contains(kv.Key))
471+
{
472+
foreach (long nodeId in kv.Value.NodeIds)
473+
{
474+
survivingWayNodeIds.Add(nodeId);
475+
}
476+
}
477+
}
478+
479+
// Pass 2: evict Fetched nodes outside keep-bounds not claimed by a surviving way.
480+
List<long> nodeIdsToEvict = [];
481+
foreach (KeyValuePair<long, OsmNode> kv in state.Nodes)
482+
{
483+
if (state.EditStates.GetValueOrDefault(kv.Value.Ref) != EditState.Fetched)
484+
{
485+
continue;
486+
}
487+
488+
OsmNode node = kv.Value;
489+
bool outsideBounds = node.Lat < keepSouth || node.Lat > keepNorth
490+
|| node.Lon < keepWest || node.Lon > keepEast;
491+
492+
if (outsideBounds && !survivingWayNodeIds.Contains(kv.Key))
493+
{
494+
nodeIdsToEvict.Add(kv.Key);
495+
}
496+
}
497+
498+
// Pass 3: evict Fetched relations with no surviving member remaining in the buffer.
499+
HashSet<long> evictedNodeIds = [.. nodeIdsToEvict];
500+
HashSet<long> evictedWayIds = [.. wayIdsToEvict];
501+
502+
List<long> relIdsToEvict = [];
503+
foreach (KeyValuePair<long, OsmRelation> kv in state.Relations)
504+
{
505+
if (state.EditStates.GetValueOrDefault(kv.Value.Ref) != EditState.Fetched)
506+
{
507+
continue;
508+
}
509+
510+
bool hasSurvivingMember = false;
511+
foreach (OsmMember member in kv.Value.Members)
512+
{
513+
switch (member.Type)
514+
{
515+
case OsmElementTypes.Node when state.Nodes.ContainsKey(member.Ref)
516+
&& !evictedNodeIds.Contains(member.Ref):
517+
hasSurvivingMember = true;
518+
break;
519+
520+
case OsmElementTypes.Way when state.Ways.ContainsKey(member.Ref)
521+
&& !evictedWayIds.Contains(member.Ref):
522+
hasSurvivingMember = true;
523+
break;
524+
525+
case OsmElementTypes.Relation when state.Relations.ContainsKey(member.Ref):
526+
hasSurvivingMember = true;
527+
break;
528+
}
529+
530+
if (hasSurvivingMember)
531+
{
532+
break;
533+
}
534+
}
535+
536+
if (!hasSurvivingMember)
537+
{
538+
relIdsToEvict.Add(kv.Key);
539+
}
540+
}
541+
542+
if (wayIdsToEvict.Count == 0 && nodeIdsToEvict.Count == 0 && relIdsToEvict.Count == 0)
543+
{
544+
return;
545+
}
546+
547+
List<OsmElementRef> editStateKeysToEvict = [];
548+
foreach (long id in nodeIdsToEvict)
549+
{
550+
editStateKeysToEvict.Add(new OsmElementRef(OsmElementTypes.Node, id));
551+
}
552+
foreach (long id in wayIdsToEvict)
553+
{
554+
editStateKeysToEvict.Add(new OsmElementRef(OsmElementTypes.Way, id));
555+
}
556+
foreach (long id in relIdsToEvict)
557+
{
558+
editStateKeysToEvict.Add(new OsmElementRef(OsmElementTypes.Relation, id));
559+
}
560+
561+
_editState.SetState(state with
562+
{
563+
Nodes = state.Nodes.RemoveRange(nodeIdsToEvict),
564+
Ways = state.Ways.RemoveRange(wayIdsToEvict),
565+
Relations = state.Relations.RemoveRange(relIdsToEvict),
566+
EditStates = state.EditStates.RemoveRange(editStateKeysToEvict)
567+
});
568+
}
420569

421570
internal async Task RunFetchBboxAsync(MapBounds bounds, IMediator mediator, CancellationToken ct)
422571
{

0 commit comments

Comments
 (0)