We moved highlights from classic overlays into the GPU scene. Ordinary highlights use InMemoryGeometrySource; richer styles use FeatureLayerTranslator. These are SDK/API findings from the application assemblies and supplied v15 samples.
| Case | Finding |
|---|---|
| Dashed lines, hatches, line offsets, thematic/nested styles, layer opacity | Available through FeatureLayerTranslator; absence from our geometry-only implementation was an AGK limitation. We now use that path. |
| Images, glyphs, point masks/rotation/offsets and nested point styles | AGK rasterizes the classic point style into its own GeoImage, doubles the canvas while ink touches an edge, then center-crops it and registers it through Images.Add(name, GeoImage). AGK does not pass sizeInPixels to the Style overload. |
| DirectionPointStyle | Translator explicitly reports that direction points have no GPU translation. |
| TextStyle.Mask / RotationAngle | Translator explicitly reports that masks are omitted and rotated labels become unrotated. |
| AreaStyle offsets with a wide/dashed outline | FillPaint.FromAreaStyle carries X/Y offsets; the translator passes zero offsets when emitting a separate outline. No warning is emitted for this mismatch. |
| Gradient/texture brushes: exception versus warning | An unsupported area fill is caught around FillPaint.FromAreaStyle and recorded as a translation warning. A positive-width GeoPen with the same brush makes Translate throw NotSupportedException: ClassicPaints.HasInk(pen) calls StrokeColorOf, then FillColorOf, without a guard, before LinePaint.FromGeoPen is reached. This affects line strokes and area outlines. AGK rejects non-solid pen brushes before calling the translator. |
| Hatch-brushed pens | FillColorOf returns the hatch’s background color. Translation silently reduces the stroke to that color, losing the pattern without a warning; a transparent background can make the stroke disappear. |
| Scaled image PointStyle through AddFeatureLayer | MapStyle.AddFeatureLayer registers the translator’s sprite styles through Images.Add(key, style), without a size. Its automatic canvas uses SymbolSize and outline width, ignoring ImageScale and offsets. Thus the normal translation/registration path clips scaled images when their rendered bounds exceed that canvas: a 64px image at ImageScale = 1.25 needs 80px before padding. This defect affects the SDK’s normal AddFeatureLayer path. |
| Add/remove translated sources with SetStyleAsync | GpuMapController refuses rebinding when the new vector-source count differs from the opened count. AGK currently rebuilds the host/readers for these transitions. |
AGK’s direct Style-overload registration in GpuHighlightScene is limited to plain
symbol points without images, masks, rotation or offsets, where that automatic size
is appropriate. Richer points use GpuHighlightSprite’s rasterized GeoImage. For the
translated path, AGK also normalizes the baked image style’s SymbolSize to the actual
sprite width before SDK registration.
Could ThinkGeo fix the area-outline offset mismatch and scaled-image clipping in
AddFeatureLayer, make unsupported pen brushes report warnings consistently with
area fills, and stop silently flattening hatch strokes? We also request parity for
direction points/text masks/rotation and live source-count changes. A richer dynamic
geometry styling API would also avoid tiled snapshots for frequently changing styled
highlights.
Minimal style cases to plug into the v15 MigrateAClassicLayer CPU/GPU comparison:
// Line feature: LINESTRING(0 0, 100 100)
var arrows = LineStyle.CreateSimpleLineStyle(GeoColors.Red, 3, true);
arrows.DirectionPointStyle = PointStyle.CreateSimpleCircleStyle(GeoColors.Blue, 8);
// Polygon feature: POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))
// Expected: fill and 4px outline both move 20px right.
var offsetArea = AreaStyle.CreateSimpleAreaStyle(GeoColors.Red, GeoColors.Black, 4);
offsetArea.XOffsetInPixel = 20;
// A feature with a NAME column. Expected: mask and rotation match classic.
var label = new TextStyle("NAME", new GeoFont("Arial", 12), GeoBrushes.Black)
{
Mask = AreaStyle.CreateSimpleAreaStyle(GeoColors.White, GeoColors.Black),
RotationAngle = 30
};
// Translate each case independently and inspect translation.Warnings.
// The outline-offset mismatch currently has no warning.
var translation = FeatureLayerTranslator.Translate(layer, map.ZoomScales);
To reproduce scaled-image clipping through the SDK’s own registration path:
var image = new GeoImage(64, 64);
image.Clear(GeoColors.Blue);
var pointLayer = new InMemoryFeatureLayer();
pointLayer.InternalFeatures.Add(new Feature(0, 0));
pointLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle =
new PointStyle(image) { ImageScale = 1.25 };
pointLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
var translatedPoint = FeatureLayerTranslator.Translate(pointLayer, map.ZoomScales, "scaled-image");
var gpuStyle = new MapStyle().AddFeatureLayer(translatedPoint);
// Compare against a classic overlay: the full blue square should be 80px wide.
For the brush asymmetry, use the same gradient or texture brush first as an area’s
FillBrush with a solid outline, then as the Brush of a positive-width line or outline
GeoPen. Translate each independently: the fill returns a warning; the pen throws.
Repeat the pen case with a hatch brush whose foreground and background colors differ:
the stroke becomes the background color without a warning. These repros must call
ThinkGeo directly, bypassing AGK’s non-solid-pen guard.
For source rebinding, first display a MapStyle containing one translated source and
await Map.RefreshAsync so the host is open. Then call SetStyleAsync with a fresh
MapStyle containing the same translation/source plus a second translated highlight
source. The controller rejects the 1-to-2 source-count change. Expected: support
adding/removing that source while keeping the existing background cache and readers.
Separately, beta148’s opacity compositing group excludes Symbol layers. Overlapping
icons/text combined with geometry therefore still need a CPU/GPU visual comparison;
we are not claiming complete layer-opacity parity for those combinations.