ThinkGeo.com    |     Documentation    |     Premium Support

Filterstyle/-condition issue

Hi Ben,

It might be connected to my own code, can you check?
I added this to show the length of the line during drawing.
The user picks a point and starts moving the mouse. While moving the mouse, the length of the line is projected. When the user double-clicks this temporary length is deleted.

    ' Add event handlers for tracking line measurements
    AddHandler Me.TrackOverlay.MouseMoved, AddressOf TrackOverlay_MouseMoved
    AddHandler Me.TrackOverlay.TrackEnded, AddressOf TrackOverlay_TrackEnded


' Event handler for real-time line measurement display
Private Sub TrackOverlay_MouseMoved(sender As Object, e As MouseMovedTrackInteractiveOverlayEventArgs)
    ' Show label in real-time while drawing lines
    If TypeOf e.AffectedFeature.GetShape() Is LineBaseShape AndAlso Me.TrackOverlay.TrackMode = TrackMode.Line Then
        Dim line As LineBaseShape = CType(e.AffectedFeature.GetShape(), LineBaseShape)

        ' Use a temporary label ID for the line being drawn
        Dim tempLabelId As String = "temp_line_label"

        ' Remove existing temporary label
        If MapLabelLayer.InternalFeatures.Contains(tempLabelId) Then
            MapLabelLayer.InternalFeatures.Remove(tempLabelId)
        End If

        ' Add new temporary label
        AddLineLengthLabelWithId(tempLabelId, line)

        ' Refresh the overlay to show the label
        Me.RefreshAsync(MapLabelOverlay)
    End If
End Sub

Hi Guido,

I found some issue on our side and fixed it in beta042, can you pull the latest and have another try?

Also, a performance tip for your label overlay:

    ' Refresh the overlay to show the label
    Me.RefreshAsync(MapLabelOverlay)

If MapLabelOverlay is a LayerOverlay , consider switching to a FeatureLayerWpfDrawingOverlay instead. Unlike a LayerOverlay , which renders into an offscreen bitmap each time, a WpfDrawingOverlay draws directly to the canvas. That makes it much more efficient when you’re only drawing a handful of labels or features. You can find a complete example in the “How Do I --> Vector Data Styling --> Render Labels” sample.

Thanks,
Ben

Hi Ben,

I tried beta042 and it’s working perfectly—thanks!

I also changed the LayerOverlay to FeatureLayerWpfDrawingOverlay and it’s much faster. I had read about this in the What’s New section, but I didn’t realize the extent of the speed improvements.

Thanks again.

Best regards, Guido van den Boom

That’s awesome! A couple more quick tips on when to use each overlay type:

  1. Rendering model
  • WpfDrawingOverlay draws directly to a WPF Canvas via hardware acceleration (GPU).
  • LayerOverlay first renders into a bitmap on the CPU, then blits that image to the Canvas.
  1. Pan/zoom behavior
  • WpfDrawingOverlay will re-draw all of its features on every pan or zoom—great for small feature sets, but can bog down if you overload it.
  • LayerOverlay simply shifts or stretches its pre‐rendered image during pan/zoom, which makes it more efficient when you have lots of features.

So use WpfDrawingOverlay for lightweight, dynamic layers (like a handful of labels), and LayerOverlay for heavier, more static content. Hope that helps!

Thanks,
Ben

Hi Ben,

All tips to improve and speed up the software are always welcome!!

I have a question right away. Is it possible to display the tile cache immediately after defining an overlay, if it exists for the respective overlay?

If I’ve used the overlay before, the cache files are still on disk. Some overlays take up to 10 seconds to load, so it would be nice if the cache is shown immediately. Currently, it first waits until all features are retrieved via WFS and then the cache is still shown afterwards.

The current order is:

  1. Create wfsfeaturelayer with reference to WFS
  2. Create Overlay
  3. Create FileRasterTileCache
  4. Assign FilterRasterTileCache to Overlay (Overlay.Tilecache = FileRasterTilecache). Now the cache could possibly be shown immediately (???)
  5. Retrieve all features from WFS and distribute to Layers using InMemoryFeatureLayers.
  6. Stylesets are assigned per layer.

Is it possible to show the cache tiles immediately after step 4?
This part is very old code from the early days since we started developing with ThinkGeo, so I think it can me much improved :wink:

Thanks,
Guido

Hi Guido,

The LayerOverlay won’t attempt to render a layer until it first checks for an existing cache entry. I bet it’s because your cache isn’t being set up with a stable ID, so it never “sees” the saved tiles.

Make sure you pass the same CacheId each time you create your file cache, for example:

var tileCache = new FileRasterTileCache("cacheFolder", "myCacheId");

If you omit the CacheId, it defaults to a new GUID on every run—so the cache is effectively empty each time.

Thanks,
Ben

Hi Ben,

That’s not it, because I always use the overlay name as cache ID, so that’s always the same.
What I have discovered is that at least 1 layer must be added to the overlay, otherwise it won’t show the cache.
I solved this by adding a dummy layer, after which the cache becomes nicely visible. Or am I missing out on something?

Unfortunately, on some overlays the following code is very slow and causes the map to become unresponsive (10 seconds):

Is this function possible to make Async?

Return Layer.FeatureSource.GetAllFeatures(ReturningColumnsType.AllColumns)

I’ve now solved this by wrapping it in an Await Task.Run…

What I’ve now created with all these work-arounds works reasonably well, but not optimally.

Dim KaartlaagCache2 As New FileRasterTileCache(sCacheFolder, sValue, GeoImageFormat.Png)
Overlay.TileCache = KaartlaagCache2
' Make sure the cached tiles are shown as the user clicks the button
Overlay.IsCacheOnly = True
Overlay.AddDummyLayer()
Await mapView2.RefreshAsync(Overlay)
Await Task.Delay(1000) ' Wait for the overlay to be ready

' Get all features from Wfs in Await Task.Run otherwise UI is blocked
Dim LayerFeatures As New Collection(Of Feature)
LayerFeatures = Await Task.Run(Function()
                                   Return WfsLayer.FeatureSource.GetAllFeatures(ReturningColumnsType.AllColumns)
                               End Function)
Overlay.RemoveDummyLayer()

*** Perform all sorts of actions to create layers based on column values and set styles ***

'After all layers are made, CacheOnly can be turned off so overlay can create the missing tiles.
Overlay.IsCacheOnly = False
Await mapView2.RefreshAsync(Overlay)

I also want the user to know that the features are still be loaded, because when the user zooms in, those tiles might not have been created yet.
Any ideas and tips would be great :wink:

Kind regards,
Guido van den Boom

Hi Guido,

  1. it doesn’t sound a good idea to GetAllFeatrures from a WfsLayer
  • If your server is using WFS V2, it would support the dynamic loading. So, for example if you have 1000 features within the current extent, it can return the first 100, and then the next 100, etc. We have WfsV2Overlay which handles this dynamic loading/rendering. Here is the sample: HowDoI->Map OnlineData ->WFS

  • Even if the server doesn’t support the dynamic loading, you can use GetFeaturesInsideBoundingBox instead of GetAllFeatures. Unless you want to cache all the features at the very beginning.

  • Making it async is on the todo list. The biggest concern is it would bring in some breaking changes and we are not sure what the best approach would be. For now, put it to Task.Run is an OK workaround.

  1. A LayerOverlay without any layer added is treated as an empty overlay, which will not be drawn. I’m wondering how the cached tiles are generated? are they created by one overlay and you are now trying to consume them using another brand-new overlay? Can you use the same overlay, which generates the cache tiles if not existed, and use the cach only if IsCacheOnly is true? If you want to keep the current way, you can create a custom overlay, override bool IsEmpty and always return false.

  2. I’m still not very sure what the role the WfsLayer played here and why it was not added to the overlay, I’m thinking adding it to the overlay, so

  • If a tile existed in the cache, the overlay immediately loads it and shows on the map.
  • If a tile doesn’t exist, the overlay renders the missing tile without blocking the UI. And the tile will be cached after the rendering.

I hope that helps :slight_smile:

Thanks,
Ben

Hi Ben,

I’ll look into it next week, it’s weekend now :wink:

For your information: The cached tiles were created in previous sessions. The overlays are quite static and have a fixed name, so I can refer to that name when “re-displaying” an overlay when a user restarts the program several days later.

The intention is that when a user wants to see an overlay, the cached files are displayed as much as possible. What doesn’t exist yet, because the user chooses a zoom level they haven’t been to before, the cache gets further populated. This way the cache keeps growing and the map gets faster and faster.

So I thought after starting the application and choosing an overlay, I could directly show the cache. However, retrieving all those features takes > 10 seconds

I will test your suggestions and see if there’s a smarter option among them.

For now, thank you very much for your response.

Kind regards, Guido van den Boom

Hi Ben,

Unfortunately, my attempts via WFS v2 and getfeaturesinsideboundarybox have all failed. This probably has to do with my lack of knowledge of GIS and APIs.

For now, I think I’ll just leave it for the time being. My work-around seems to work reasonably well for what I want, but it’s not optimal with the dummy layer, turning tile caches on/off, and tile caches being read-only, etc.

What I notice now is that after panning/zooming the map is only refreshed after all overlays are done rendering. Is it possible to re-introduce refreshing the overlay one by one?
That gives a better user experience.

Best regards,
Guido

Hi Guido,

Please check out MapView.DefaultOverlaysRenderSequenceType.

If it equals to Concurrent(by default), all the overlays will be rendered at the same time; if it’s set to Sequential, they will be rendered one by one, in the same order they were added to the collection.

And about the performance improvements, you might need to first confirm if the server is consistent with WFS v2, and if it supports querying features within an extent. If not, I’m afraid you have to use GetAllFeatures and cache those features.

Thanks,
Ben