Documentation
¶
Overview ¶
Package s57 provides a parser for IHO S-57 Electronic Navigational Charts.
This package is designed for chart rendering applications. It provides fast spatial queries, feature grouping, and a clean API optimized for viewport-based rendering.
Basic Usage ¶
parser := s57.NewParser()
chart, err := parser.Parse("US5MA22M.000")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Chart: %s covers %+v\n", chart.DatasetName(), chart.Bounds())
Rendering Workflow ¶
The typical rendering workflow uses spatial queries to efficiently render only visible features:
// 1. Query features in viewport
viewport := s57.Bounds{
MinLon: -71.5, MaxLon: -71.0,
MinLat: 42.0, MaxLat: 42.5,
}
visibleFeatures := chart.FeaturesInBounds(viewport)
// 2. Pass to S-52 presentation library for rendering
// S-52 handles all grouping, ordering, and symbology based on its lookup tables
s52.Render(visibleFeatures, displaySettings)
Spatial Queries ¶
The chart automatically builds a spatial index for fast viewport queries:
// Get chart coverage bounds := chart.Bounds() // Query visible features visible := chart.FeaturesInBounds(viewport) // Features are returned as a slice - no allocation overhead for iteration
Feature Access ¶
Access all features or query by object class:
// Get all features in the chart
allFeatures := chart.Features()
// Each feature contains everything needed for S-52 symbology lookup:
for _, feature := range allFeatures {
class := feature.ObjectClass() // "ACHARE", "DEPARE", "LNDARE"
attrs := feature.Attributes() // All feature attributes
geom := feature.Geometry() // Geometry with type and coordinates
// Pass to S-52 for symbology lookup and rendering
}
Accessing Feature Data ¶
for _, feature := range visibleFeatures {
id := feature.ID()
class := feature.ObjectClass() // "DEPCNT", "LIGHTS", etc.
geom := feature.Geometry()
// Access coordinates
for _, coord := range geom.Coordinates {
lon, lat := coord[0], coord[1]
// ... project and render
}
// Access attributes for styling
if depth, ok := feature.Attribute("DRVAL1"); ok {
// Apply depth-based color
}
}
Integration with S-52 Presentation Library ¶
This library handles S-57 parsing only. Features are designed to work directly with S-52 presentation libraries for symbology lookup and rendering.
// Parse S-57 chart
chart, _ := s57Parser.Parse("chart.000")
// S-52 uses ObjectClass + Attributes + Geometry for lookup
for _, feature := range chart.Features() {
// S-52 looks up: ObjectClass + GeometryType + Attributes → Symbology
symbology := s52.Lookup(feature.ObjectClass(), feature.GeometryType(), feature.Attributes())
render(feature.Geometry(), symbology)
}
Performance ¶
- Spatial index built automatically during parsing - Viewport queries are O(n) with low constant factor (simple bounding box checks) - No allocations during iteration - Features parsed eagerly (charts fit in memory)
Index ¶
- type Bounds
- type Chart
- func (c *Chart) ApplicationProfile() string
- func (c *Chart) Bounds() Bounds
- func (c *Chart) Comment() string
- func (c *Chart) CompilationScale() int32
- func (c *Chart) CoordinateUnits() CoordinateUnits
- func (c *Chart) DatasetName() string
- func (c *Chart) Edition() string
- func (c *Chart) ExchangePurpose() string
- func (c *Chart) FeatureCount() int
- func (c *Chart) Features() []Feature
- func (c *Chart) FeaturesInBounds(bounds Bounds) []Feature
- func (c *Chart) HorizontalDatum() int
- func (c *Chart) IssueDate() string
- func (c *Chart) ProducingAgency() int
- func (c *Chart) ProductSpecification() string
- func (c *Chart) S57Edition() string
- func (c *Chart) UpdateDate() string
- func (c *Chart) UpdateNumber() string
- func (c *Chart) UsageBand() UsageBand
- type CoordinateUnits
- type Feature
- type Geometry
- type GeometryType
- type ParseOptions
- type Parser
- type UsageBand
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Bounds ¶
type Bounds struct {
MinLon float64 // Western edge
MaxLon float64 // Eastern edge
MinLat float64 // Southern edge
MaxLat float64 // Northern edge
}
Bounds represents a geographic bounding box in WGS-84 coordinates.
Coordinates are in decimal degrees.
func (Bounds) Expand ¶
Expand returns a new Bounds expanded by the given margin in all directions.
Margin is in decimal degrees.
func (Bounds) Intersects ¶
Intersects returns true if the given bounds intersects with this bounds.
type Chart ¶
type Chart struct {
// contains filtered or unexported fields
}
Chart represents a parsed S-57 Electronic Navigational Chart.
A chart contains metadata (cell name, edition, dates, etc.) and a collection of navigational features (depth contours, buoys, lights, hazards, etc.).
Access metadata via methods like DatasetName(), Edition(), IssueDate(). Access features via Features(), FeaturesInBounds(), or FeatureCount().
All fields are private to maintain encapsulation.
func Parse ¶ added in v0.100.0
Parse reads an S-57 file from the OS filesystem and returns the parsed chart. This is a convenience function equivalent to:
parser := s57.NewParser() chart, err := parser.Parse(filename)
Example:
chart, err := s57.Parse("US5MA22M.000")
func ParseFS ¶ added in v0.100.0
ParseFS reads an S-57 file from a custom filesystem and returns the parsed chart. This allows using custom filesystem implementations such as afero.NewMemMapFs() for testing or specialized storage systems.
The filesystem is used for both the base file and any update files (.001, .002, etc.) if ApplyUpdates is enabled in the options.
Example with in-memory filesystem:
fs := afero.NewMemMapFs() afero.WriteFile(fs, "/chart.000", data, 0644) chart, err := s57.ParseFS(fs, "/chart.000")
Example with custom options:
fs := afero.NewMemMapFs()
afero.WriteFile(fs, "/chart.000", data, 0644)
opts := s57.DefaultParseOptions()
opts.Fs = fs
opts.ApplyUpdates = false
chart, err := s57.ParseWithOptions("/chart.000", opts)
func ParseWithOptions ¶ added in v0.100.0
func ParseWithOptions(filename string, opts ParseOptions) (*Chart, error)
ParseWithOptions reads an S-57 file with custom options. This is a convenience function equivalent to:
parser := s57.NewParser() chart, err := parser.ParseWithOptions(filename, opts)
Example:
opts := s57.DefaultParseOptions()
opts.SkipUnknownFeatures = true
chart, err := s57.ParseWithOptions("US5MA22M.000", opts)
func (*Chart) ApplicationProfile ¶
ApplicationProfile returns human-readable application profile.
Examples: "EN (ENC New)", "ER (ENC Revision)"
func (*Chart) Bounds ¶
Bounds returns the geographic coverage area of the chart.
This represents the minimum bounding box containing all features.
func (*Chart) CompilationScale ¶
CompilationScale returns the compilation scale denominator of the chart.
For example, a value of 50000 indicates the chart was compiled at 1:50,000 scale. This helps determine appropriate display scales and SCAMIN filtering.
S-57 §7.3.2.1: CSCL field in DSPM record. Returns 0 if not specified.
func (*Chart) CoordinateUnits ¶
func (c *Chart) CoordinateUnits() CoordinateUnits
CoordinateUnits returns the coordinate system used in the chart.
Most ENC charts use CoordinateUnitsLatLon (lat/lon in WGS-84). Some charts may use CoordinateUnitsEastNorth for projected coordinates.
S-57 §7.3.2.1: COUN field in DSPM record.
func (*Chart) DatasetName ¶
DatasetName returns the chart's dataset name (cell identifier).
Example: "US5MA22M", "GB5X01NE"
func (*Chart) ExchangePurpose ¶
ExchangePurpose returns human-readable exchange purpose.
Returns "New" for new datasets or "Revision" for updates.
func (*Chart) FeatureCount ¶
FeatureCount returns the number of features in the chart.
func (*Chart) Features ¶
Features returns all features in the chart.
Features include depth contours, buoys, lights, hazards, restricted areas, and all other navigational objects defined in the S-57 Object Catalogue.
Each feature contains ObjectClass, Attributes, and Geometry needed for S-52 presentation library symbology lookup and rendering.
func (*Chart) FeaturesInBounds ¶
FeaturesInBounds returns all features that intersect the given bounding box.
This is the primary method for viewport-based rendering. Only features that could be visible in the viewport are returned.
Example:
viewport := s57.Bounds{
MinLon: -71.5, MaxLon: -71.0,
MinLat: 42.0, MaxLat: 42.5,
}
visibleFeatures := chart.FeaturesInBounds(viewport)
for _, feature := range visibleFeatures {
render(feature)
}
func (*Chart) HorizontalDatum ¶
HorizontalDatum returns the horizontal geodetic datum code.
Common values:
- 2: WGS-84 (most common for modern ENCs)
- Other values defined in S-57 Part 3 Table 3.1
S-57 §7.3.2.1: HDAT field in DSPM record.
func (*Chart) IssueDate ¶
IssueDate returns the chart issue date in YYYYMMDD format.
This is when the dataset was released by the producing agency.
func (*Chart) ProducingAgency ¶
ProducingAgency returns the producing agency code.
Example: 550 = NOAA (United States)
Full agency list available in IHO S-57 Appendix A.
func (*Chart) ProductSpecification ¶
ProductSpecification returns human-readable product specification.
Typically "ENC" for Electronic Navigational Charts.
func (*Chart) S57Edition ¶
S57Edition returns the S-57 standard edition used.
Example: "03.1" for S-57 Edition 3.1
func (*Chart) UpdateDate ¶
UpdateDate returns the update application date in YYYYMMDD format.
All updates dated on or before this date must be applied for current data.
func (*Chart) UpdateNumber ¶
UpdateNumber returns the chart's update number.
"0" indicates a base cell, higher numbers indicate applied updates.
func (*Chart) UsageBand ¶
UsageBand returns the ENC usage band of this chart.
This indicates the intended usage and appropriate scale range:
- Overview: ≥1:1,500,000 (route planning)
- General: 1:350,000-1:1,500,000 (open ocean)
- Coastal: 1:90,000-1:350,000 (coastal navigation)
- Approach: 1:22,000-1:90,000 (approaching ports)
- Harbour: 1:4,000-1:22,000 (harbour navigation)
- Berthing: ≤1:4,000 (final approach)
Applications should load the appropriate band based on zoom level.
type CoordinateUnits ¶
type CoordinateUnits int
CoordinateUnits indicates how coordinates are encoded in the chart.
S-57 §7.3.2.1: COUN field in DSPM record defines coordinate units. Reference: S-57 Part 3 Table 3.2
const ( // CoordinateUnitsLatLon indicates coordinates are in latitude/longitude (WGS-84). // This is the most common format for ENC charts. // Coordinates are decimal degrees, typically scaled by 10^7. CoordinateUnitsLatLon CoordinateUnits = 1 // CoordinateUnitsEastNorth indicates coordinates are in projected Easting/Northing. // Less common; requires DSPR record to specify projection parameters. CoordinateUnitsEastNorth CoordinateUnits = 2 // CoordinateUnitsUnknown indicates coordinate units are not specified. // Treat as lat/lon by default (S-57 default assumption). CoordinateUnitsUnknown CoordinateUnits = 0 )
func (CoordinateUnits) String ¶
func (c CoordinateUnits) String() string
String returns a human-readable name for the coordinate units.
type Feature ¶
type Feature struct {
// contains filtered or unexported fields
}
Feature represents a navigational object from an S-57 chart.
Features include depth contours, buoys, lights, hazards, restricted areas, and all other objects defined in the S-57 Object Catalogue.
Access feature data via methods:
- ID() returns the unique identifier
- ObjectClass() returns the S-57 object class (e.g., "DEPCNT", "LIGHTS")
- Geometry() returns the spatial representation
- Attributes() returns all attributes
- Attribute(name) returns a specific attribute value
func (*Feature) Attribute ¶
Attribute returns a specific attribute value by name.
Returns the value and true if the attribute exists, or nil and false if not found.
Example:
if depth, ok := feature.Attribute("DRVAL1"); ok {
fmt.Printf("Depth: %v meters\n", depth)
}
func (*Feature) Attributes ¶
Attributes returns all feature attributes as a map.
Common attributes:
- "DRVAL1": Depth range value 1 (minimum depth)
- "DRVAL2": Depth range value 2 (maximum depth)
- "COLOUR": Color code
- "OBJNAM": Object name
Attribute meanings are defined in the S-57 Object Catalogue.
func (*Feature) ObjectClass ¶
ObjectClass returns the S-57 object class code.
Common examples:
- "DEPCNT": Depth contour
- "DEPARE": Depth area
- "BOYCAR": Buoy, cardinal
- "LIGHTS": Light
- "OBSTRN": Obstruction
- "RESARE": Restricted area
type Geometry ¶
type Geometry struct {
// Type indicates the geometry type (Point, LineString, or Polygon).
Type GeometryType
// Coordinates contains [longitude, latitude] pairs.
//
// For Point: Single coordinate pair
// For LineString: Array of coordinate pairs forming a line
// For Polygon: Array of coordinate pairs forming a closed ring
//
// Note: Coordinates follow GeoJSON convention [lon, lat], not [lat, lon].
Coordinates [][]float64
}
Geometry represents the spatial representation of a feature.
Coordinates follow GeoJSON convention: [longitude, latitude] pairs. All coordinates are in WGS-84 decimal degrees.
type GeometryType ¶
type GeometryType int
GeometryType represents the type of geometry.
const ( // GeometryTypePoint represents a single point location. GeometryTypePoint GeometryType = iota // GeometryTypeLineString represents a line composed of connected points. GeometryTypeLineString // GeometryTypePolygon represents a closed polygon area. GeometryTypePolygon )
func (GeometryType) String ¶
func (g GeometryType) String() string
String returns the string representation of the geometry type.
type ParseOptions ¶
type ParseOptions struct {
SkipUnknownFeatures bool
ValidateGeometry bool
ObjectClassFilter []string
// ApplyUpdates controls whether to automatically discover and apply
// update files (.001, .002, etc.) when parsing a base cell (.000).
// Default is true - updates are automatically applied.
//
// When true, the parser looks for sequential update files in the same
// directory as the base file and applies them in order.
//
// Set to false to parse only the base cell without updates.
ApplyUpdates bool
// Fs is the filesystem to use for reading files.
// If nil, the OS filesystem is used (afero.NewOsFs()).
// This allows using custom filesystem implementations for testing
// (e.g., afero.NewMemMapFs()) or specialized storage systems.
//
// Example with in-memory filesystem:
// fs := afero.NewMemMapFs()
// afero.WriteFile(fs, "/test.000", data, 0644)
// opts := s57.ParseOptions{Fs: fs}
// parser := s57.NewParser()
// chart, err := parser.ParseWithOptions("/test.000", opts)
Fs afero.Fs
}
ParseOptions configures parsing behavior.
func DefaultParseOptions ¶
func DefaultParseOptions() ParseOptions
DefaultParseOptions returns default options.
type Parser ¶
type Parser interface {
// Parse reads an S-57 file and returns the parsed chart.
//
// The filename should point to an S-57 base cell (.000) or update file (.001, .002, etc.).
// Returns an error if the file cannot be read or parsed according to S-57 Edition 3.1.
Parse(filename string) (*Chart, error)
// ParseWithOptions parses an S-57 file with custom options.
//
// Use ParseOptions to control validation, error handling, and feature filtering.
ParseWithOptions(filename string, opts ParseOptions) (*Chart, error)
}
Parser parses S-57 Electronic Navigational Chart files.
Create a parser with NewParser and use Parse or ParseWithOptions to read charts.
type UsageBand ¶
type UsageBand int
UsageBand defines the ENC usage band (navigational purpose) of the chart.
ENC cells are organized by usage band, which determines the level of detail and appropriate display scale. Applications should load the appropriate band based on the current zoom level.
Reference: S-57 Part 3 §7.3.1.1 (INTU field) and S-52 Section 3.4
const ( // UsageBandUnknown indicates the band is not specified. UsageBandUnknown UsageBand = 0 // UsageBandOverview - For overview navigation (≥ 1:1,500,000). // Provides general context and route planning. UsageBandOverview UsageBand = 1 // UsageBandGeneral - For general navigation (1:350,000 - 1:1,500,000). // Used for open ocean and offshore navigation. UsageBandGeneral UsageBand = 2 // UsageBandCoastal - For coastal navigation (1:90,000 - 1:350,000). // Used for navigation along coastlines and approaching ports. UsageBandCoastal UsageBand = 3 // UsageBandApproach - For approach navigation (1:22,000 - 1:90,000). // Used when approaching ports, harbours, and pilot stations. UsageBandApproach UsageBand = 4 // UsageBandHarbour - For harbour navigation (1:4,000 - 1:22,000). // Used for navigation within harbours and restricted waters. UsageBandHarbour UsageBand = 5 // UsageBandBerthing - For berthing (≤ 1:4,000). // Used for final approach to berth and detailed harbour navigation. UsageBandBerthing UsageBand = 6 )
func (UsageBand) ScaleRange ¶
ScaleRange returns the recommended scale range for this usage band.
Returns (minScale, maxScale) where scales are denominators (e.g., 1:90000 returns 90000). For overview and berthing (open-ended ranges), one value may be 0.