moonbit9

    MoonBit Shapefile geometry, index and attribute table reader/writer

    shapefile
    gis
    dbf
    geojson
    Download zip
    Author
    Version
    0.1.0
    License
    MIT
    Last updated
    15 hours ago
    Downloads
    1

    #moonbit9

    Shapefile geometry, index and attribute-table IO in MoonBit.

    MoonBit-native SHP/SHX/DBF reading and writing with checked offsets, typed geometry, aligned attribute rows, GeoJSON conversion, filtering and malformed input diagnostics.

    let files = @moonbit9.write_shp(@moonbit9.Point, [
    { kind: @moonbit9.Point, points: [@moonbit9.coordinate(116.4, 39.9)], parts: [] },
    ])
    let parsed = @moonbit9.read_shp(files.shp)

    Run moon test for the binary, geometry and interoperability regression suite. The accepted scope and explicit non-goals are in docs/design.md.

    ShapeError

    pub suberror ShapeError {
    InvalidData(Int, String)
    } derive(
    Debug
    )

    Errors always identify the byte offset or logical record involved.

    Bounds

    pub(all) struct Bounds {
    xmin : Double
    ymin : Double
    xmax : Double
    ymax : Double
    } derive(Eq,
    Debug
    )

    Bounds::contains

    fn Bounds::contains(self : Bounds, point : Coordinate) -> Bool

    Bounds::intersection

    fn Bounds::intersection(self : Bounds, other : Bounds) -> Bounds? raise ShapeError

    Intersection can be a zero-width/height rectangle when boundaries touch.

    Bounds::intersects

    fn Bounds::intersects(self : Bounds, other : Bounds) -> Bool

    Bounds::union

    fn Bounds::union(self : Bounds, other : Bounds) -> Bounds raise ShapeError

    Combine two valid bounding rectangles. Inputs are validated before use.

    Bounds::validate

    fn Bounds::validate(self : Bounds) -> Unit raise ShapeError

    Coordinate

    pub(all) struct Coordinate {
    x : Double
    y : Double
    z : Double?
    m : Double?
    } derive(Eq,
    Debug
    )

    Dataset

    pub(all) struct Dataset {
    kind : ShapeType
    shapes : Array[Shape]
    table :
    Table

    prj : String?
    } derive(
    Debug
    )

    A geometry table whose rows retain the physical SHP/DBF record alignment.

    Dataset::filter_bbox

    fn Dataset::filter_bbox(self : Dataset, bounds : Bounds, include_deleted? : Bool) -> Dataset raise ShapeError

    Dataset::filter_equal

    fn Dataset::filter_equal(self : Dataset, field : String, value :
    Value
    , include_deleted? : Bool) -> Dataset raise ShapeError

    Dataset::project_fields

    fn Dataset::project_fields(self : Dataset, names : Array[String]) -> Dataset raise ShapeError

    Dataset::select_indices

    fn Dataset::select_indices(self : Dataset, indices : Array[Int]) -> Dataset raise ShapeError

    Dataset::to_geojson

    fn Dataset::to_geojson(self : Dataset, allow_projected? : Bool, include_deleted? : Bool) -> Json raise ShapeError

    Dataset::validate

    fn Dataset::validate(self : Dataset) -> Unit raise ShapeError

    Dataset::write_dataset

    fn Dataset::write_dataset(self : Dataset, encoding? :
    Encoding
    ) -> DatasetFiles raise ShapeError

    DatasetFiles

    pub(all) struct DatasetFiles {
    shp : Bytes
    shx : Bytes
    dbf : Bytes
    prj : String?
    } derive(
    Debug
    )

    pub(all) struct Header {
    file_length : Int
    kind : ShapeType
    bounds : Bounds
    zmin : Double
    zmax : Double
    mmin : Double
    mmax : Double
    } derive(
    Debug
    )

    Parsed file header; ranges remain available for inspection.

    IndexEntry

    pub(all) struct IndexEntry {
    offset : Int
    content_length : Int
    } derive(Eq,
    Debug
    )

    IndexedReader

    pub struct IndexedReader {
    data : Bytes
    file_header : Header
    entries : Array[IndexEntry]
    limits : ReadLimits
    }

    Random access validates file/index structure up front and geometry on access.

    IndexedReader::entry

    fn IndexedReader::entry(self : IndexedReader, index : Int) -> IndexEntry raise ShapeError

    IndexedReader::header

    fn IndexedReader::header(self : IndexedReader) -> Header

    IndexedReader::open

    fn IndexedReader::open(shp : Bytes, shx : Bytes, limits? : ReadLimits) -> IndexedReader raise ShapeError

    IndexedReader::record_at

    fn IndexedReader::record_at(self : IndexedReader, index : Int) -> Record raise ShapeError

    IndexedReader::record_count

    fn IndexedReader::record_count(self : IndexedReader) -> Int

    IndexedReader::select

    fn IndexedReader::select(self : IndexedReader, indices : Array[Int]) -> Array[Record] raise ShapeError

    Only selected records are decoded; order and duplicate indices are preserved.

    ReadLimits

    pub(all) struct ReadLimits {
    max_records : Int
    max_points_per_record : Int
    max_parts_per_record : Int
    max_file_bytes : Int
    } derive(
    Debug
    )

    Resource limits apply before allocating point or record arrays.

    ReadLimits::default

    fn ReadLimits::default() -> ReadLimits

    Record

    pub(all) struct Record {
    number : Int
    offset : Int
    content_length : Int
    shape : Shape
    } derive(
    Debug
    )

    Shape

    pub(all) struct Shape {
    kind : ShapeType
    points : Array[Coordinate]
    parts : Array[Int]
    } derive(Eq,
    Debug
    )

    Shape::bounds

    fn Shape::bounds(self : Shape) -> Bounds?

    Shape::contains_point

    fn Shape::contains_point(self : Shape, point : Coordinate) -> Bool raise ShapeError

    Inclusive planar membership. Polygon boundaries (including hole boundaries) count as contained. Z and M are ignored; exact XY comparisons are used.

    Shape::intersects_bounds

    fn Shape::intersects_bounds(self : Shape, bounds : Bounds) -> Bool raise ShapeError

    True geometric intersection with a closed XY rectangle, including touches. Unlike a bounding-box prefilter, this respects concavities and polygon holes.

    Shape::planar_area

    fn Shape::planar_area(self : Shape) -> Double raise ShapeError

    Area in squared input XY units after topology validation. Winding has no effect; holes subtract and islands add. Non-polygons return zero.

    Shape::planar_length

    fn Shape::planar_length(self : Shape) -> Double raise ShapeError

    Euclidean length in input XY units. Polygon results include hole boundaries; point geometries have zero length. No geodesic interpretation is implied.

    Shape::to_geojson

    fn Shape::to_geojson(self : Shape, allow_projected? : Bool) -> Json raise ShapeError

    Export a geometry object. Input is longitude/latitude by default; the opt-in permits projected output without claiming RFC 7946 coordinate compliance. M is omitted, and Z is retained. Polygon rings may arrive in any order or winding; nesting determines shell/hole roles, including islands in holes.

    Shape::validate

    fn Shape::validate(self : Shape) -> Unit raise ShapeError

    ShapeFiles

    pub(all) struct ShapeFiles {
    shp : Bytes
    shx : Bytes
    } derive(
    Debug
    )

    Matching SHP and SHX byte streams, ready for filesystem or network storage.

    ShapeStats

    pub(all) struct ShapeStats {
    record_count : Int
    point_count : Int
    part_count : Int
    null_count : Int
    bounds : Bounds?
    total_length : Double
    total_area : Double
    } derive(
    Debug
    )

    Summary statistics useful to import pipelines and CLI reports.

    ShapeType

    pub(all) enum ShapeType {
    Null
    Point
    PolyLine
    Polygon
    MultiPoint
    PointZ
    PolyLineZ
    PolygonZ
    MultiPointZ
    PointM
    PolyLineM
    PolygonM
    MultiPointM
    } derive(Eq,
    Debug
    )

    ESRI shape codes. MultiPatch is deliberately unsupported.

    ShapeType::code

    fn ShapeType::code(self : ShapeType) -> Int

    ShapeType::has_m

    fn ShapeType::has_m(self : ShapeType) -> Bool

    ShapeType::has_z

    fn ShapeType::has_z(self : ShapeType) -> Bool

    ShapeType::is_line

    fn ShapeType::is_line(self : ShapeType) -> Bool

    ShapeType::is_multi

    fn ShapeType::is_multi(self : ShapeType) -> Bool

    ShapeType::is_point

    fn ShapeType::is_point(self : ShapeType) -> Bool

    ShapeType::is_polygon

    fn ShapeType::is_polygon(self : ShapeType) -> Bool

    Shapefile

    pub(all) struct Shapefile {
    kind : ShapeType
    records : Array[Record]
    bounds : Bounds?
    } derive(
    Debug
    )

    ShpReader

    pub struct ShpReader {
    data : Bytes
    header : Header
    limits : ReadLimits
    position : Int
    count : Int
    }

    Cursor holds original bytes and decodes one record at a time.

    ShpReader::header

    fn ShpReader::header(self : ShpReader) -> Header

    ShpReader::next

    fn ShpReader::next(self : ShpReader) -> Record? raise ShapeError

    A failed decode does not advance the cursor.

    ShpReader::open

    fn ShpReader::open(data : Bytes, limits? : ReadLimits) -> ShpReader raise ShapeError

    ShpReader::position

    fn ShpReader::position(self : ShpReader) -> Int

    ShpWriter

    pub struct ShpWriter {
    kind : ShapeType
    limits : ReadLimits
    records : Array[Bytes]
    total_bytes : Int
    bounds : Bounds?
    zrange : (Double, Double)?
    mrange : (Double, Double)?
    }

    Accumulates encoded records; append validates a record before mutation.

    ShpWriter::append

    fn ShpWriter::append(self : ShpWriter, shape : Shape) -> Unit raise ShapeError

    ShpWriter::finish

    fn ShpWriter::finish(self : ShpWriter) -> ShapeFiles

    Finishing is repeatable and does not consume the writer.

    ShpWriter::new

    fn ShpWriter::new(kind : ShapeType, limits? : ReadLimits) -> ShpWriter raise ShapeError

    ShpWriter::record_count

    fn ShpWriter::record_count(self : ShpWriter) -> Int

    bounds_of

    fn bounds_of(shapes : Array[Shape]) -> Bounds? raise ShapeError

    bounds_to_text

    fn bounds_to_text(bounds : Bounds?) -> String

    centroid

    fn centroid(shape : Shape) -> Coordinate? raise ShapeError

    clamp_bounds

    fn clamp_bounds(shape : Shape, bounds : Bounds) -> Shape raise ShapeError

    coordinate

    fn coordinate(x : Double, y : Double, z? : Double, m? : Double) -> Coordinate

    count_parts

    fn count_parts(shapes : Array[Shape]) -> Int raise ShapeError

    count_vertices

    fn count_vertices(shapes : Array[Shape]) -> Int raise ShapeError

    intersecting_indices

    fn intersecting_indices(shapes : Array[Shape], query : Bounds) -> Array[Int] raise ShapeError

    Returns physical record indices whose bounding boxes overlap the query.

    locate_point

    fn locate_point(shapes : Array[Shape], point : Coordinate) -> Int? raise ShapeError

    Return the first record that contains a point under inclusive XY semantics.

    m_coverage

    fn m_coverage(shapes : Array[Shape]) -> Double raise ShapeError

    Calculate the fraction of points that carry an M ordinate.

    nearest_vertex

    fn nearest_vertex(shape : Shape, target : Coordinate) -> (Int, Double)? raise ShapeError

    read_dataset

    fn read_dataset(shp : Bytes, shx : Bytes, dbf : Bytes, encoding? :
    Encoding
    , prj? : String?) -> Dataset raise ShapeError

    read_header

    fn read_header(data : Bytes) -> Header raise ShapeError

    Read and verify the 100-byte header. Full file bytes are required.

    read_index

    fn read_index(data : Bytes, limits? : ReadLimits) -> Array[IndexEntry] raise ShapeError

    Decode SHX entries, checking contiguous byte boundaries from offset 100.

    read_shp

    fn read_shp(data : Bytes, limits? : ReadLimits) -> Shapefile raise ShapeError

    rebuild_index

    fn rebuild_index(shp : Bytes, limits? : ReadLimits) -> Bytes raise ShapeError

    Rebuild a missing index from a validated SHP stream.

    reverse_parts

    fn reverse_parts(shape : Shape) -> Shape raise ShapeError

    scale_shape

    fn scale_shape(shape : Shape, sx : Double, sy : Double) -> Shape raise ShapeError

    shape_from_geojson

    fn shape_from_geojson(value : Json, kind : ShapeType) -> Shape raise ShapeError

    Import a GeoJSON geometry into an explicit ESRI shape type. Two ordinates are required for XY/M types, three for Z types. Measures remain absent. Feature wrappers and collections must be handled by the dataset layer. Coordinates are preserved without reprojection or longitude wrapping.

    shape_type

    fn shape_type(code : Int) -> ShapeType raise ShapeError

    shape_type_name

    fn shape_type_name(kind : ShapeType) -> String

    Human-readable summaries for command-line adapters.

    stable_select

    fn stable_select(shapes : Array[Shape], indices : Array[Int]) -> Array[Shape] raise ShapeError

    Stable filter preserving original record order and duplicate indices.

    stats_to_text

    fn stats_to_text(stats : ShapeStats) -> String

    summarize

    fn summarize(shapes : Array[Shape]) -> ShapeStats raise ShapeError

    translate_shape

    fn translate_shape(shape : Shape, dx : Double, dy : Double) -> Shape raise ShapeError

    Small, allocation-conscious geometry operations used by importers.

    type_histogram

    fn type_histogram(shapes : Array[Shape]) -> Map[Int, Int] raise ShapeError

    Compute a histogram of records by ShapeType numeric code.

    validate_bounds

    fn validate_bounds(shapes : Array[Shape], declared : Bounds) -> Unit raise ShapeError

    Check that all bounds are finite and mutually compatible with their shapes.

    validate_filename_prefix

    fn validate_filename_prefix(prefix : String) -> Unit raise ShapeError

    validate_shape_family

    fn validate_shape_family(kind : ShapeType, shapes : Array[Shape]) -> Unit raise ShapeError

    Validate that a collection has one file-compatible shape family.

    validate_shx

    fn validate_shx(shp : Bytes, shx : Bytes, limits? : ReadLimits) -> Unit raise ShapeError

    Fully verifies the SHX table against decoded SHP records.

    write_shp

    fn write_shp(kind : ShapeType, shapes : Array[Shape], limits? : ReadLimits) -> ShapeFiles raise ShapeError

    z_coverage

    fn z_coverage(shapes : Array[Shape]) -> Double raise ShapeError

    Calculate the fraction of points that carry a Z ordinate.

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io