Skip to content

Bump EncDotNet.Iso8211 to 0.4.3 for S-101 parsing fixes#116

Merged
philliphoff merged 6 commits into
mainfrom
philliphoff/fix-s101-multipoint-parsing
May 19, 2026
Merged

Bump EncDotNet.Iso8211 to 0.4.3 for S-101 parsing fixes#116
philliphoff merged 6 commits into
mainfrom
philliphoff/fix-s101-multipoint-parsing

Conversation

@philliphoff
Copy link
Copy Markdown
Owner

@philliphoff philliphoff commented May 19, 2026

Bumps EncDotNet.Iso8211 from 0.4.1 → 0.4.3, picking up two fixes for real-world S-101 datasets:

Fix 1: Nested format controls (0.4.2, philliphoff/EncDotNet#4)

Problem: FormatException when opening datasets whose DDR uses nested parenthesized format controls for the C3IL field (e.g. (b11,(3b24))). Binary coordinate data was misinterpreted as ASCII text.

Root cause: ParseFormatControls didn't handle nested parenthesized groups, causing YCOO/XCOO/ZCOO subfields to fall back to CharacterData format.

Fix 2: UTF-8 text encoding (0.4.3, philliphoff/EncDotNet#5)

Problem: French accented characters garbled — e.g. Île d'Orléans displayed as ??le d'Orl??ans.

Root cause: ConvertCharacterData used Encoding.ASCII for lexical levels 0/1, replacing any byte > 127 with ?. Changed to Encoding.UTF8 which is backward-compatible with ASCII.

Verified with: Canadian Hydrographic Service dataset 101CA00P468N0712W.000.

All 956 tests pass.

Fixes parsing of S-101 datasets whose DDR uses nested parenthesized
format controls (e.g. (b11,(3b24)) for the C3IL field). The ISO 8211
library now correctly expands these nested groups into individual
subfield format entries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 19, 2026

Performance Gate

PASSED — no regressions.

Threshold: 10.0%, MAD multiplier (k): 3.0, retry-zone mult: 2.0×

Scenario summary

Scenario Status Δ median (%) z (Δ/MAD) Base median (ms) Samples (b/c)
exchange-set-open ✅ pass +9.0 +0.90 0.50 20/20
s101-portray-cold ✅ pass 0.0 +0.01 344.07 20/20
s101-portray-warm ✅ pass -1.0 -0.15 168.28 20/20
s101-render-warm ✅ pass +2.2 +0.66 153.98 20/20
s102-coverage ✅ pass +8.8 +1.47 1.34 20/20
s102-coverage-open ✅ pass -2.8 -0.40 1.95 20/20
s102-coverage-render-large ✅ pass -0.3 -0.28 116.79 20/20
s124-vector ✅ pass +4.6 +0.71 0.41 20/20
s201-vector ✅ pass +4.4 +0.85 0.37 20/20

exchange-set-open

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 0.50 0.55
Baseline MAD (ms) 0.05
Δ median +9.0%
z (Δ/MAD) +0.90

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.asset.read 11.05 10.95 -0.9% ▫️
s100.exchangeset.parse 39.44 39.83 +1.0% ▫️

Metrics

Metric Baseline Candidate Delta Status
s100.asset.read.duration 18.97 19.48 +2.7% ▫️

s101-portray-cold

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 344.07 344.16
Baseline MAD (ms) 11.22
Δ median 0.0%
z (Δ/MAD) +0.01

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.lua.execute 4425.70 4329.83 -2.2% ▫️
s100.lua.rule.invoke 3692.20 3608.09 -2.3% ▫️
s100.pipeline.vector.process 4500.63 4405.00 -2.1% ▫️
s100.pipeline.vector.stage.assemble 0.30 0.29 -2.9% ▫️
s100.pipeline.vector.stage.feature_xml 48.87 48.93 +0.1% ▫️
s100.pipeline.vector.stage.lua 4427.50 4331.75 -2.2% ▫️
s100.pipeline.vector.stage.rule_select 5.63 5.78 +2.7% ▫️
s100.pipeline.vector.stage.sort 1.72 1.70 -0.8% ▫️
s100.pipeline.vector.stage.viewing_groups 3.39 3.38 -0.3% ▫️
s100.pipeline.vector.stage.xslt 0.24 0.27 +13.7%
s100.render.frame 5797.85 5818.55 +0.4% ▫️

Metrics

Metric Baseline Candidate Delta Status
s100.catalogue.match.count 7.00 7.00 +0.0% ▫️
s100.featurecatalogue.cache.hit.count 6.00 6.00 +0.0% ▫️
s100.featurecatalogue.cache.miss.count 1.00 1.00 +0.0% ▫️
s100.lua.execute.duration 1181.27 1212.44 +2.6% ▫️
s100.lua.features.count 700.00 700.00 +0.0% ▫️
s100.lua.instructions.emitted.count 735.00 735.00 +0.0% ▫️
s100.lua.rule.invoke.count 7.00 7.00 +0.0% ▫️
s100.lua.rule.invoke.count 77.00 77.00 +0.0% ▫️
s100.lua.rule.invoke.duration 902.81 925.21 +2.5% ▫️
s100.lua.rule.invoke.duration 6.29 6.53 +3.9% ▫️
s100.lua.source.cache.hit.count 292.00 292.00 +0.0% ▫️
s100.lua.source.cache.miss.count 23.00 23.00 +0.0% ▫️
s100.pattern.cache.hit.count 63.00 63.00 +0.0% ▫️
s100.pattern.cache.miss.count 28.00 28.00 +0.0% ▫️
s100.pipeline.drawinginstructions.out 735.00 735.00 +0.0% ▫️
s100.pipeline.duration 1212.42 1245.85 +2.8% ▫️
s100.pipeline.features.in 84.00 84.00 +0.0% ▫️
s100.pipeline.stage.duration 0.32 0.32 -1.3% ▫️
s100.pipeline.stage.duration 18.99 20.49 +7.9%
s100.pipeline.stage.duration 1182.65 1213.90 +2.6% ▫️
s100.pipeline.stage.duration 4.30 4.59 +6.5%
s100.pipeline.stage.duration 2.18 2.20 +0.9% ▫️
s100.pipeline.stage.duration 0.86 0.94 +9.5%
s100.pipeline.stage.duration 0.97 0.94 -3.1% ▫️
s100.pipeline.stage.instructions.count 0.00 0.00 N/A ▫️
s100.pipeline.stage.instructions.count 735.00 735.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 735.00 735.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 735.00 735.00 +0.0% ▫️
s100.portrayal.cache.hit.count 24.00 24.00 +0.0% ▫️
s100.portrayal.cache.hit.count 292.00 292.00 +0.0% ▫️
s100.portrayal.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.portrayal.cache.hit.count 36.00 36.00 +0.0% ▫️
s100.portrayal.cache.miss.count 4.00 4.00 +0.0% ▫️
s100.portrayal.cache.miss.count 23.00 23.00 +0.0% ▫️
s100.portrayal.cache.miss.count 6.00 6.00 +0.0% ▫️
s100.render.frame.duration 1512.85 1524.24 +0.8% ▫️
s100.render.instructions.processed.count 735.00 735.00 +0.0% ▫️
s100.render.styles.applied.count 693.00 693.00 +0.0% ▫️
s100.symbol.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.symbol.cache.miss.count 14.00 14.00 +0.0% ▫️
s100.symbol.resolve.duration 0.03 0.04 +8.3%
s100.symbol.resolve.duration 6.75 6.38 -5.4% ▫️

s101-portray-warm

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 168.28 166.55
Baseline MAD (ms) 11.68
Δ median -1.0%
z (Δ/MAD) -0.15

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.lua.execute 5125.37 4871.18 -5.0% ▫️
s100.lua.rule.invoke 4354.18 4159.84 -4.5% ▫️
s100.pipeline.vector.process 5217.60 4958.77 -5.0% ▫️
s100.pipeline.vector.stage.assemble 0.28 0.26 -7.0% ▫️
s100.pipeline.vector.stage.feature_xml 66.74 66.21 -0.8% ▫️
s100.pipeline.vector.stage.lua 5126.85 4872.63 -5.0% ▫️
s100.pipeline.vector.stage.rule_select 4.08 3.97 -2.7% ▫️
s100.pipeline.vector.stage.sort 3.09 2.64 -14.6%
s100.pipeline.vector.stage.viewing_groups 4.72 4.07 -13.9%
s100.pipeline.vector.stage.xslt 0.23 0.23 -0.9% ▫️
s100.render.frame 96.55 92.76 -3.9% ▫️

Metrics

Metric Baseline Candidate Delta Status
s100.catalogue.match.count 1.00 1.00 +0.0% ▫️
s100.featurecatalogue.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.lua.execute.duration 1169.66 1144.52 -2.1% ▫️
s100.lua.features.count 700.00 700.00 +0.0% ▫️
s100.lua.instructions.emitted.count 735.00 735.00 +0.0% ▫️
s100.lua.rule.invoke.count 7.00 7.00 +0.0% ▫️
s100.lua.rule.invoke.count 77.00 77.00 +0.0% ▫️
s100.lua.rule.invoke.duration 973.49 953.62 -2.0% ▫️
s100.lua.rule.invoke.duration 6.28 27.10 +331.2%
s100.lua.source.cache.hit.count 315.00 315.00 +0.0% ▫️
s100.pattern.cache.hit.count 87.00 87.00 +0.0% ▫️
s100.pattern.cache.miss.count 4.00 4.00 +0.0% ▫️
s100.pipeline.drawinginstructions.out 735.00 735.00 +0.0% ▫️
s100.pipeline.duration 1193.22 1160.30 -2.8% ▫️
s100.pipeline.features.in 84.00 84.00 +0.0% ▫️
s100.pipeline.stage.duration 0.02 0.03 +18.1%
s100.pipeline.stage.duration 19.95 12.30 -38.3%
s100.pipeline.stage.duration 1170.02 1144.80 -2.2% ▫️
s100.pipeline.stage.duration 1.17 1.02 -13.2%
s100.pipeline.stage.duration 0.43 0.67 +55.6%
s100.pipeline.stage.duration 0.19 0.19 +1.6% ▫️
s100.pipeline.stage.duration 0.03 0.03 -5.6% ▫️
s100.pipeline.stage.instructions.count 0.00 0.00 N/A ▫️
s100.pipeline.stage.instructions.count 735.00 735.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 735.00 735.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 735.00 735.00 +0.0% ▫️
s100.portrayal.cache.hit.count 4.00 4.00 +0.0% ▫️
s100.portrayal.cache.hit.count 315.00 315.00 +0.0% ▫️
s100.portrayal.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.portrayal.cache.hit.count 6.00 6.00 +0.0% ▫️
s100.render.frame.duration 202.15 205.18 +1.5% ▫️
s100.render.instructions.processed.count 735.00 735.00 +0.0% ▫️
s100.render.styles.applied.count 693.00 693.00 +0.0% ▫️
s100.symbol.cache.hit.count 19.00 19.00 +0.0% ▫️
s100.symbol.cache.miss.count 2.00 2.00 +0.0% ▫️
s100.symbol.resolve.duration 0.04 0.04 +2.3% ▫️
s100.symbol.resolve.duration 0.49 0.34 -31.2%

s101-render-warm

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 153.98 157.43
Baseline MAD (ms) 5.26
Δ median +2.2%
z (Δ/MAD) +0.66

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.lua.execute 4605.64 4959.43 +7.7%
s100.lua.rule.invoke 3782.17 4080.16 +7.9%
s100.pipeline.vector.process 4669.84 5035.67 +7.8%
s100.pipeline.vector.stage.assemble 0.26 0.26 -1.7% ▫️
s100.pipeline.vector.stage.feature_xml 40.95 58.20 +42.1%
s100.pipeline.vector.stage.lua 4606.89 4960.82 +7.7%
s100.pipeline.vector.stage.rule_select 3.65 4.05 +11.0%
s100.pipeline.vector.stage.sort 3.74 3.72 -0.5% ▫️
s100.pipeline.vector.stage.viewing_groups 5.04 5.11 +1.3% ▫️
s100.pipeline.vector.stage.xslt 0.21 0.24 +14.1%
s100.render.frame 50.48 58.54 +16.0%

Metrics

Metric Baseline Candidate Delta Status
s100.catalogue.match.count 1.00 1.00 +0.0% ▫️
s100.featurecatalogue.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.lua.execute.duration 1145.60 1106.07 -3.5% ▫️
s100.lua.features.count 700.00 700.00 +0.0% ▫️
s100.lua.instructions.emitted.count 735.00 735.00 +0.0% ▫️
s100.lua.rule.invoke.count 7.00 7.00 +0.0% ▫️
s100.lua.rule.invoke.count 77.00 77.00 +0.0% ▫️
s100.lua.rule.invoke.duration 947.53 909.91 -4.0% ▫️
s100.lua.rule.invoke.duration 5.24 5.29 +0.8% ▫️
s100.lua.source.cache.hit.count 315.00 315.00 +0.0% ▫️
s100.pattern.cache.hit.count 87.00 87.00 +0.0% ▫️
s100.pattern.cache.miss.count 4.00 4.00 +0.0% ▫️
s100.pipeline.drawinginstructions.out 735.00 735.00 +0.0% ▫️
s100.pipeline.duration 1166.69 1121.98 -3.8% ▫️
s100.pipeline.features.in 84.00 84.00 +0.0% ▫️
s100.pipeline.stage.duration 0.02 0.03 +11.4%
s100.pipeline.stage.duration 17.50 12.27 -29.9%
s100.pipeline.stage.duration 1145.89 1106.34 -3.5% ▫️
s100.pipeline.stage.duration 1.03 1.11 +6.9%
s100.pipeline.stage.duration 0.76 0.86 +12.4%
s100.pipeline.stage.duration 0.19 0.19 -1.2% ▫️
s100.pipeline.stage.duration 0.03 0.04 +16.5%
s100.pipeline.stage.instructions.count 0.00 0.00 N/A ▫️
s100.pipeline.stage.instructions.count 735.00 735.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 735.00 735.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 735.00 735.00 +0.0% ▫️
s100.portrayal.cache.hit.count 4.00 4.00 +0.0% ▫️
s100.portrayal.cache.hit.count 315.00 315.00 +0.0% ▫️
s100.portrayal.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.portrayal.cache.hit.count 6.00 6.00 +0.0% ▫️
s100.render.frame.duration 203.44 197.38 -3.0% ▫️
s100.render.instructions.processed.count 735.00 735.00 +0.0% ▫️
s100.render.styles.applied.count 693.00 693.00 +0.0% ▫️
s100.symbol.cache.hit.count 19.00 19.00 +0.0% ▫️
s100.symbol.cache.miss.count 2.00 2.00 +0.0% ▫️
s100.symbol.resolve.duration 0.04 0.04 -10.4%
s100.symbol.resolve.duration 0.49 0.35 -28.0%

s102-coverage

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 1.34 1.46
Baseline MAD (ms) 0.08
Δ median +8.8%
z (Δ/MAD) +1.47

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.pipeline.coverage.process 54.37 59.23 +8.9%
s100.pipeline.coverage.stage.read 4.94 4.87 -1.4% ▫️
s100.pipeline.coverage.stage.resolve 45.81 51.00 +11.3%
s100.render.coverage.build 78.64 77.27 -1.7% ▫️

Metrics

Metric Baseline Candidate Delta Status
s100.catalogue.match.count 1.00 1.00 +0.0% ▫️
s100.coverage.cells 4557.00 4557.00 +0.0% ▫️
s100.hdf5.read.bytes 5208.00 5208.00 +0.0% ▫️
s100.hdf5.read.duration 21.13 21.09 -0.2% ▫️
s100.hdf5.read.duration 29.53 29.92 +1.3% ▫️
s100.hdf5.read.duration 7.09 7.22 +1.7% ▫️
s100.pipeline.duration 11.76 12.34 +5.0% ▫️
s100.pipeline.stage.duration 0.95 0.90 -5.7% ▫️
s100.pipeline.stage.duration 10.10 10.85 +7.4%
s100.portrayal.cache.hit.count 7.00 7.00 +0.0% ▫️

s102-coverage-open

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 1.95 1.90
Baseline MAD (ms) 0.14
Δ median -2.8%
z (Δ/MAD) -0.40

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.dataset.open 70.97 66.55 -6.2% ▫️
s100.hdf5.dataset.read 12.28 11.59 -5.6% ▫️
s100.hdf5.file.open 13.65 12.28 -10.0% ▫️
s100.hdf5.open 14.10 12.32 -12.6%

Metrics

Metric Baseline Candidate Delta Status
s100.hdf5.read.bytes 36456.00 36456.00 +0.0% ▫️
s100.hdf5.read.duration 5.15 5.05 -2.0% ▫️
s100.hdf5.read.duration 2.23 2.24 +0.8% ▫️
s100.hdf5.read.duration 3.01 3.01 +0.0% ▫️

s102-coverage-render-large

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 116.79 116.39
Baseline MAD (ms) 1.43
Δ median -0.3%
z (Δ/MAD) -0.28

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.pipeline.coverage.process 198.15 212.41 +7.2%
s100.pipeline.coverage.stage.read 136.17 141.72 +4.1% ▫️
s100.pipeline.coverage.stage.resolve 57.87 66.52 +14.9%
s100.render.coverage.build 4025.37 3975.97 -1.2% ▫️

Metrics

Metric Baseline Candidate Delta Status
s100.catalogue.match.count 1.00 1.00 +0.0% ▫️
s100.coverage.cells 7000000.00 7000000.00 +0.0% ▫️
s100.hdf5.read.bytes 8000000.00 8000000.00 +0.0% ▫️
s100.hdf5.read.duration 0.12 0.11 -9.9% ▫️
s100.hdf5.read.duration 3.93 4.12 +4.9% ▫️
s100.hdf5.read.duration 0.97 0.97 +0.8% ▫️
s100.pipeline.duration 39.33 38.90 -1.1% ▫️
s100.pipeline.stage.duration 25.86 27.39 +5.9%
s100.pipeline.stage.duration 12.43 10.56 -15.1%
s100.portrayal.cache.hit.count 7.00 7.00 +0.0% ▫️

s124-vector

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 0.41 0.42
Baseline MAD (ms) 0.03
Δ median +4.6%
z (Δ/MAD) +0.71

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.pipeline.vector.process 8.97 9.19 +2.5% ▫️
s100.pipeline.vector.stage.assemble 0.33 0.35 +6.2%
s100.pipeline.vector.stage.feature_xml 1.18 1.19 +1.1% ▫️
s100.pipeline.vector.stage.rule_select 0.36 0.34 -4.9% ▫️
s100.pipeline.vector.stage.sort 0.33 0.33 -0.9% ▫️
s100.pipeline.vector.stage.viewing_groups 0.67 0.72 +6.4%
s100.pipeline.vector.stage.xslt 4.24 4.39 +3.5% ▫️
s100.render.frame 1.14 1.16 +1.6% ▫️
s100.xslt.transform 1.53 1.62 +5.6%

Metrics

Metric Baseline Candidate Delta Status
s100.catalogue.match.count 1.00 1.00 +0.0% ▫️
s100.featurecatalogue.cache.miss.count 1.00 1.00 +0.0% ▫️
s100.pipeline.drawinginstructions.out 14.00 14.00 +0.0% ▫️
s100.pipeline.duration 56.36 54.67 -3.0% ▫️
s100.pipeline.features.in 7.00 7.00 +0.0% ▫️
s100.pipeline.stage.duration 1.07 1.13 +6.4%
s100.pipeline.stage.duration 3.21 3.21 +0.1% ▫️
s100.pipeline.stage.duration 1.16 1.09 -5.8% ▫️
s100.pipeline.stage.duration 0.07 0.06 -4.3% ▫️
s100.pipeline.stage.duration 0.10 0.09 -4.8% ▫️
s100.pipeline.stage.duration 50.06 48.54 -3.0% ▫️
s100.pipeline.stage.instructions.count 14.00 14.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 14.00 14.00 +0.0% ▫️
s100.pipeline.stage.instructions.count 14.00 14.00 +0.0% ▫️
s100.portrayal.cache.hit.count 13.00 13.00 +0.0% ▫️
s100.portrayal.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.portrayal.cache.hit.count 6.00 6.00 +0.0% ▫️
s100.portrayal.cache.miss.count 1.00 1.00 +0.0% ▫️
s100.portrayal.cache.miss.count 1.00 1.00 +0.0% ▫️
s100.render.frame.duration 2.52 2.46 -2.3% ▫️
s100.render.instructions.processed.count 14.00 14.00 +0.0% ▫️
s100.render.styles.applied.count 14.00 14.00 +0.0% ▫️
s100.xslt.transform.duration 10.52 9.98 -5.1% ▫️

s201-vector

Iteration statistics

Stat Baseline Candidate
Samples 20 20
Median (ms) 0.37 0.39
Baseline MAD (ms) 0.02
Δ median +4.4%
z (Δ/MAD) +0.85

Spans (sum of all iterations)

Span Baseline (ms) Candidate (ms) Delta Status
s100.pipeline.vector.process 8.05 8.70 +8.1%
s100.pipeline.vector.stage.assemble 0.12 0.14 +11.7%
s100.pipeline.vector.stage.feature_xml 0.83 0.90 +9.1%
s100.pipeline.vector.stage.rule_select 0.34 0.35 +2.2% ▫️
s100.pipeline.vector.stage.sort 0.15 0.18 +21.9%
s100.pipeline.vector.stage.viewing_groups 0.53 0.62 +16.0%
s100.pipeline.vector.stage.xslt 4.20 4.55 +8.2%
s100.render.frame 0.53 0.57 +8.1%
s100.xslt.transform 2.56 2.77 +8.2%

Metrics

Metric Baseline Candidate Delta Status
s100.catalogue.match.count 1.00 1.00 +0.0% ▫️
s100.featurecatalogue.cache.miss.count 1.00 1.00 +0.0% ▫️
s100.pipeline.drawinginstructions.out 0.00 0.00 N/A ▫️
s100.pipeline.duration 145.42 143.27 -1.5% ▫️
s100.pipeline.features.in 7.00 7.00 +0.0% ▫️
s100.pipeline.stage.duration 0.02 0.01 -54.5%
s100.pipeline.stage.duration 8.12 7.53 -7.3% ▫️
s100.pipeline.stage.duration 0.17 0.15 -12.8%
s100.pipeline.stage.duration 0.08 0.09 +20.7%
s100.pipeline.stage.duration 0.05 0.05 +7.8%
s100.pipeline.stage.duration 136.41 134.87 -1.1% ▫️
s100.pipeline.stage.instructions.count 0.00 0.00 N/A ▫️
s100.pipeline.stage.instructions.count 0.00 0.00 N/A ▫️
s100.pipeline.stage.instructions.count 0.00 0.00 N/A ▫️
s100.portrayal.cache.hit.count 7.00 7.00 +0.0% ▫️
s100.portrayal.cache.hit.count 6.00 6.00 +0.0% ▫️
s100.portrayal.cache.miss.count 1.00 1.00 +0.0% ▫️
s100.render.frame.duration 0.11 0.10 -11.7%
s100.render.instructions.processed.count 0.00 0.00 N/A ▫️
s100.render.styles.applied.count 0.00 0.00 N/A ▫️
s100.xslt.transform.duration 26.98 27.16 +0.7% ▫️

Generated by EncDotNet.S100.PerfReport gate command

Fixes garbled French accented characters (e.g. Île d'Orléans displayed
as ??le d'Orl??ans) in S-101 datasets. The ISO 8211 library now uses
UTF-8 instead of ASCII for character data decoding.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@philliphoff philliphoff changed the title Bump EncDotNet.Iso8211 to 0.4.2 for nested format controls fix Bump EncDotNet.Iso8211 to 0.4.3 for S-101 parsing fixes May 19, 2026
Phillip Hoff and others added 4 commits May 18, 2026 21:52
Implement data coding format 3 reader that maps per-node positioned
values into the station-series model for rendering. DCF 3 datasets
store explicit per-node lat/lon from Positioning/geometryValues and
per-timestep value arrays — structurally similar to DCF 8 but with
per-timestep (not per-station) organisation.

Changes:
- S111DatasetReader: add ReadUngeorectifiedGrid/ReadUngeorectifiedInstance
  methods that read positions and transpose per-timestep values into
  per-node SurfaceCurrentStation objects
- S111DatasetReader.ReadAny: route DCF 3 through station-series path
- S111StationSeriesDataset: update docs for DCF 3 reuse, remove
  hard-coded DataCodingFormat=8
- S111DatasetProcessor: update doc to mention DCF 3
- Add S111Dcf3FixtureBuilder and S111Dcf3ReaderTests with 3 tests

Spec ref: S-100 Part 10c §10.2.1

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
For DCF 3 (ungeorectified grid) datasets, resolve arrow colors and
scale factors from the S-111 portrayal catalogue speed-band table
instead of using the hardcoded ColorByMagnitude/SymbolScaleForSpeed
palette. This makes DCF 3 rendering faithful to the IHO PC (same
color bands and scaling rules as the DCF 2 regular-grid path).

DCF 8 (time series at fixed stations) retains the inline palette
since those datasets typically originate from tide gauges where the
PC arrow bands are less appropriate.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace SymbolType.Triangle with actual SVG arrow symbols (SCAROW01,
SCAROW02, etc.) from the S-111 portrayal catalogue. Each speed band
resolves to a distinct SVG glyph that is loaded once and cached for
the render pass. The SVG is rendered via Mapsui's ImageStyle with
RasterizeSvg=true, matching the DCF 2 arrow renderer's approach.

Falls back to colored triangles for DCF 8 or when the catalogue
symbol cannot be loaded.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mapsui's Image.Source expects a 'svg-content://' URI scheme, not raw
SVG markup. Process the raw SVG through SvgProcessor (palette color
resolution) and prefix with the required URI scheme, matching how
MapsuiDisplayListRenderer produces symbol sources.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@philliphoff philliphoff merged commit 2188684 into main May 19, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant