Table of Contents

Reading AML data sets

NATO Additional Military Layers (AML) cells are S-57 data sets with their own object catalogue. EncDotNet.S57 reads them with the same S57DocumentReader and S57Chart it uses for ENC cells, so everything in Reading S-57 charts applies to them. This page covers what's different about AML cells:

  • S57ProductIdentity, from S57DataSetIdentification.Product, says whether a cell is an AML cell, and which AML product and edition it is.
  • AmlDataSetMetadata parses the structured comment in an AML cell's data set identification field (DSID).
  • S57ObjectCatalogue gives the AML object class and attribute codes their acronyms, names and enumerated values.
  • AmlDataSet puts these together in one view over a chart.

Detect an AML cell

The product specification code (PRSP) in DSID identifies the product. Codes 51 to 57 are AML products. Product.Kind is S57ProductKind.Aml for them, and Product.AmlProduct says which one:

using EncDotNet.S57;

S57Document document = S57DocumentReader.ReadFromFile("path/to/cell.000");
S57ProductIdentity? product = document.DataSetIdentification?.Product;

if (product?.Kind == S57ProductKind.Aml)
{
    Console.WriteLine($"AML {product.Value.AmlProduct} edition {product.Value.Edition}, update: {product.Value.IsUpdate}");
}
PRSP AmlProduct Product
51 MFF Maritime Foundation and Facilities
52 RAL Routes, Areas and Limits
53 LBO Large Bottom Objects
54 CLB Contour Line Bathymetry
55 ESB Environment, Seabed and Beach
56 SBO Small Bottom Objects
57 Integrated AML 3.0, every layer in one data set

Edition is the product specification edition (PRED) as recorded, and Version is the same edition parsed as a version number. IsUpdate comes from the application profile (PROF), or from the file extension when the profile doesn't say.

Read the cell metadata

AML cells put their title, status and security classification in the DSID comment (COMT) as key=value pairs separated by semicolons, for example title=Wrecks; IDO Status = Final; Protective Marking = UNCLASSIFIED. AmlDataSetMetadata.TryParse reads them:

using EncDotNet.S57;
using EncDotNet.S57.Aml;

S57Document document = S57DocumentReader.ReadFromFile("path/to/cell.000");

if (AmlDataSetMetadata.TryParse(document.DataSetIdentification?.Comment, out AmlDataSetMetadata? metadata))
{
    Console.WriteLine($"{metadata.Title}: {metadata.ProtectiveMarking}, {metadata.IdoStatus}, owned by {metadata.OwnerAuthority}");

    foreach ((string key, string value) in metadata.Entries)
    {
        Console.WriteLine($"  {key} = {value}");
    }
}

Keys are matched without regard to case or spaces. The well-known keys are properties, which are null when the comment doesn't have them, and Entries holds every pair, including keys AmlDataSetMetadata doesn't recognise. TryParse returns false for a comment that isn't a list of pairs, such as free text.

Important

AML data is classified. If your application shows AML data, display the cell's protective marking (ProtectiveMarking) prominently wherever the data is shown.

Look up AML codes

An S-57 cell encodes object classes (OBJL) and attributes (ATTL) as numbers. AML classes and attributes have codes from 20000, which aren't in the IHO catalogue or in the S57ObjectCode enumeration. The AML catalogues hold them, on top of the IHO entries that AML cells also use, such as C_ASSO and M_COVR:

Catalogue Edition (PRED major number)
S57ObjectCatalogue.Aml10 1
S57ObjectCatalogue.Aml21 2
S57ObjectCatalogue.Aml30 3

S57Document.GetObjectCatalogue() and S57Chart.GetObjectCatalogue() choose the catalogue for a cell's product and edition. When the edition is missing or unrecognised, the integrated product gets the AML 3.0 catalogue and the other products get AML 2.1:

using EncDotNet.S57;

S57Document document = S57DocumentReader.ReadFromFile("path/to/cell.000");
S57ObjectCatalogue catalogue = document.GetObjectCatalogue();

foreach (S57FeatureRecord feature in document.FeatureRecords)
{
    S57ObjectClassDefinition? objectClass = catalogue.GetObjectClass(feature.ObjectCode);
    Console.WriteLine($"{objectClass?.Acronym ?? feature.ObjectCode.ToString()}: {objectClass?.Name}");

    foreach (S57AttributeValue value in feature.Attributes)
    {
        S57AttributeDefinition? attribute = catalogue.GetAttribute(value.AttributeCode);
        Console.WriteLine($"  {attribute?.Acronym ?? value.AttributeCode.ToString()} = {value.Value}");
    }
}

Acronyms of AML classes and attributes are lower case, such as atsctl and databa, and acronym lookups are case-sensitive. The catalogues hold codes, acronyms, names, attribute types and enumerated values, but not definitions.

S57AttributeDefinition.Class says whether an attribute is a feature, national, spatial or cartographic attribute, and IsNational whether a feature stores it in NATF rather than ATTF. The AML catalogues don't classify their own attributes, so codes 20000 and up are feature attributes; the IHO attributes they include keep their IHO class.

Use the AML data set view

AmlDataSet is a view over the S57Chart of an AML cell. It doesn't copy the chart; it adds the cell's product, its metadata and its catalogue, and looks codes up in that catalogue. Load one from a file or stream, or create one from a chart or document you already have:

using EncDotNet.S57.Aml;
using EncDotNet.S57.Charts;

AmlDataSet dataSet = AmlDataSet.FromFile("path/to/cell.000");

Console.WriteLine($"{dataSet.AmlProduct}, {dataSet.Catalogue.Name}, {dataSet.Metadata?.ProtectiveMarking}");

foreach (S57TypedFeature feature in dataSet.Chart.AllFeatures.Values)
{
    Console.WriteLine($"{dataSet.GetObjectClass(feature)?.Acronym ?? feature.ObjectCode.ToString()}");

    foreach (AmlAttributeValue attribute in dataSet.GetAttributes(feature))
    {
        Console.WriteLine($"  {attribute.Acronym ?? attribute.Code.ToString()} = {attribute.Value.Value}");
    }
}

GetAttributes and GetNationalAttributes pair each of a feature's ATTF and NATF values with its S57AttributeDefinition, which is null for a code the catalogue doesn't have. GetObjectClass and GetAttribute look up a single feature or value.

Metadata is null when the cell's comment isn't structured. Creating an AmlDataSet from a cell that isn't an AML cell throws ArgumentException. To check first, use TryCreate:

using EncDotNet.S57;
using EncDotNet.S57.Aml;

S57Document document = S57DocumentReader.ReadFromFile("path/to/cell.000");

if (AmlDataSet.TryCreate(document, out AmlDataSet? dataSet))
{
    Console.WriteLine($"{dataSet.Identification.DataSetName} is an AML {dataSet.AmlProduct} cell");
}

AML update cells are read and applied like ENC update cells; see Apply update cells. Create the AmlDataSet from the document after you've applied them.

Read arc edges

Some AML cells, such as Routes, Areas and Limits cells, give edges as arcs rather than as lists of points. S57Edge.IntermediatePoints already holds them as points, and S57ArcDensifier densifies them to a tolerance you choose. See Read arc edges.