Skip to content

code4history/MaplatTransform

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

104 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Maplat Transform

CI

A JavaScript library that performs coordinate transformation between two plane coordinate systems using transformation definitions generated by Maplat. This is part of the Maplat project.

日本語のREADMEはこちら

Key Features

  • Import Transformation Definitions: Import and build internal structures from transformation definitions generated by Maplat
  • V2/V3 Format Support: Compatible with both legacy V2 compiled format (4 fixed boundary vertices) and the new V3 format (N boundary vertices for higher accuracy)
  • Bidirectional Coordinate Transformation: Convert coordinates between two planes in both directions
  • Topology Preservation: Maintains homeomorphic properties during transformation
  • Multiple Coordinate System Support: Handles transformations between various coordinate systems including standard orthogonal coordinates, Y-axis inverted coordinates, and distorted coordinates like bird's-eye views
  • State Management: Save and restore transformation states
  • Sub-map Selection (Processing 2): For maps with multiple overlapping TIN regions (sub_maps), automatically determines which TIN to apply based on region boundaries, priority, and importance
  • Viewport Transformation (Processing 3): Converts a display viewport (center, zoom, rotation) in pixel coordinate space to a viewport in the map coordinate space (EPSG:3857)
  • Cross-map Viewport Sync (Processing 4): Converts a display viewport from one pixel map directly to the corresponding viewport of another pixel map, via the shared map coordinate space

Requirements

  • Node.js: >= 20
  • pnpm: >= 9 (for development)

Installation

pnpm (Recommended)

pnpm add @maplat/transform

npm

npm install @maplat/transform

Browser

<script src="https://unpkg.com/@maplat/transform/dist/maplat_transform.umd.js"></script>

Basic Usage

import { Transform } from '@maplat/transform';

// Import transformation definition
const transform = new Transform();
transform.setCompiled(compiledData);  // Apply transformation definition generated by Maplat

// Forward transformation (source → target coordinate system)
const transformed = transform.transform([100, 100], false);

// Backward transformation (target → source coordinate system)
const restored = transform.transform(transformed, true);

Error Handling

The library may throw errors in the following cases:

  • Transformation errors in strict mode
  • Attempting backward transformation when not allowed
  • Invalid data structure during transformation

If errors occur, the transformation definition data needs to be modified. Please use editor tools that incorporate @maplat/tin to modify transformation definitions.

MapTransform Usage

Processing 2 — Sub-map selection and coordinate transformation

When a single map image contains multiple overlapping TIN definitions (sub_maps), use MapTransform to automatically select the correct TIN and transform coordinates.

import { MapTransform } from '@maplat/transform';

const mt = new MapTransform();
mt.setMapData({
  compiled: mainCompiledData,   // Main TIN compiled data
  sub_maps: [
    { compiled: sub0Data, priority: 1, importance: 1 },
    { compiled: sub1Data, priority: 2, importance: 2 },
  ],
});

// Forward: pixel XY → EPSG:3857 (returns [layerIndex, mercCoord] or false)
const result = mt.xy2MercWithLayer([320, 240]);
if (result) {
  const [layerIndex, merc] = result;
  console.log('layer:', layerIndex, 'merc:', merc);
}

// Reverse: EPSG:3857 → pixel XY (returns up to 2 layers, each [layerIndex, xyCoord] or undefined)
const results = mt.merc2XyWithLayer([15000000, 4000000]);
results.forEach((r, i) => {
  if (r) console.log(`result ${i}: layer ${r[0]}, xy`, r[1]);
});

Processing 3 — Viewport transformation

Convert a pixel-map viewport (center position, zoom level, rotation angle) to and from a geographic viewport in EPSG:3857. The viewport is represented as five Mercator points (center + four cardinal offsets).

import { MapTransform } from '@maplat/transform';

const mt = new MapTransform();
mt.setMapData({ compiled: compiledData });

const canvasSize = [800, 600];   // [width, height] in pixels

// Pixel viewport → EPSG:3857 five points
const viewpoint = {
  center: [15000000, 4000000],  // EPSG:3857 center of the pixel-space viewport
  zoom: 14,
  rotation: 0,
};
const mercs = mt.viewpoint2Mercs(viewpoint, canvasSize);
// mercs: [[cx,cy], [north], [east], [south], [west]]  (EPSG:3857)

// EPSG:3857 five points → pixel viewport
const vp = mt.mercs2Viewpoint(mercs, canvasSize);
console.log(vp.center, vp.zoom, vp.rotation);

Processing 4 — Cross-map viewport synchronization

Convert the display viewport of one pixel map to the corresponding viewport of another pixel map, using the shared EPSG:3857 space as an intermediary.

import { MapTransform } from '@maplat/transform';

const mtA = new MapTransform();
mtA.setMapData({ compiled: compiledDataA });

const mtB = new MapTransform();
mtB.setMapData({ compiled: compiledDataB });

const canvasSize = [800, 600];

// Map A viewport (pixel space A)
const vpA = { center: [15000000, 4000000], zoom: 14, rotation: 0 };

// Pixel space A → EPSG:3857 five points (Processing 3 forward)
const mercs = mtA.viewpoint2Mercs(vpA, canvasSize);

// EPSG:3857 five points → Map B viewport (Processing 3 reverse)
const vpB = mtB.mercs2Viewpoint(mercs, canvasSize);
console.log('Map B viewport:', vpB);

API Reference

Transform Class

The main class for coordinate transformation.

Constructor

const transform = new Transform();

Methods

setCompiled(compiled: Compiled | CompiledLegacy): void

Import and apply a compiled transformation definition generated by Maplat. Supports legacy format, V2 (4 boundary vertices), and V3 (N boundary vertices) automatically.

  • Parameters:
    • compiled: Compiled transformation definition object (V2, V3, or legacy format)
transform(apoint: number[], backward?: boolean, ignoreBounds?: boolean): number[] | false

Perform coordinate transformation.

  • Parameters:
    • apoint: Coordinate to transform [x, y]
    • backward: Whether to perform backward transformation (default: false)
    • ignoreBounds: Whether to ignore boundary checks (default: false)
  • Returns: Transformed coordinate or false if out of bounds
  • Throws: Error if backward transformation is attempted when strict_status == "strict_error"

Static Constants

Vertex Modes:

  • Transform.VERTEX_PLAIN: Standard plane coordinate system
  • Transform.VERTEX_BIRDEYE: Bird's-eye view coordinate system

Strict Modes:

  • Transform.MODE_STRICT: Strict transformation mode
  • Transform.MODE_AUTO: Automatic mode selection
  • Transform.MODE_LOOSE: Loose transformation mode

Strict Status:

  • Transform.STATUS_STRICT: Strict status
  • Transform.STATUS_ERROR: Error status (backward transformation not allowed)
  • Transform.STATUS_LOOSE: Loose status

Y-axis Modes:

  • Transform.YAXIS_FOLLOW: Follow Y-axis direction
  • Transform.YAXIS_INVERT: Invert Y-axis direction

MapTransform Class

The class for sub-map selection, viewport transformation, and cross-map viewport synchronization (Processings 2–4).

Constructor

const mt = new MapTransform();

Methods

setMapData(mapData: MapData): void

Load a main TIN and optional sub-map TINs.

  • Parameters:
    • mapData: { compiled, maxZoom?, sub_maps? } — main compiled TIN data, optional explicit maxZoom, and optional array of sub-map definitions
xy2Merc(xy: number[]): number[] | false

Transform a pixel coordinate to EPSG:3857 using the main TIN.

  • Parameters: xy — pixel coordinate [x, y]
  • Returns: EPSG:3857 coordinate, or false if out of bounds
merc2Xy(merc: number[]): number[] | false

Transform an EPSG:3857 coordinate to pixel coordinate using the main TIN (reverse).

  • Parameters: merc — EPSG:3857 coordinate [x, y]
  • Returns: Pixel coordinate, or false if out of bounds
xy2MercWithLayer(xy: number[]): [number, number[]] | false

Transform a pixel coordinate to EPSG:3857, automatically selecting the appropriate TIN from sub-maps based on priority and region (Processing 2).

  • Parameters: xy — pixel coordinate [x, y]
  • Returns: [layerIndex, mercCoord] or false if out of bounds
merc2XyWithLayer(merc: number[]): ([number, number[]] | undefined)[]

Transform an EPSG:3857 coordinate to pixel coordinate across all applicable TIN layers, returning up to 2 results ordered by importance (Processing 2).

To return more than 2 layers, increase the limit in the .slice(0, 2) / .filter(i < 2) lines inside the implementation.

  • Parameters: merc — EPSG:3857 coordinate [x, y]
  • Returns: Array of up to 2 elements; each is [layerIndex, xyCoord] or undefined
viewpoint2Mercs(viewpoint: Viewpoint, size: [number, number]): number[][]

Convert a pixel-space viewport to five EPSG:3857 points (Processing 3).

  • Parameters:
    • viewpoint: { center, zoom, rotation } — viewport in pixel space (center as EPSG:3857 equivalent via xy2SysCoord)
    • size: Canvas size [width, height]
  • Returns: Array of 5 EPSG:3857 points [center, north, east, south, west]
  • Throws: Error if the center point is outside the TIN bounds
mercs2Viewpoint(mercs: number[][], size: [number, number]): Viewpoint

Convert five EPSG:3857 points back to a pixel-space viewport (Processing 3 reverse).

  • Parameters:
    • mercs: Array of 5 EPSG:3857 points (as returned by viewpoint2Mercs)
    • size: Canvas size [width, height]
  • Returns: Viewpoint{ center, zoom, rotation } in pixel space
  • Throws: Error if the center point cannot be reverse-transformed

Accessors

  • maxxy: number2^maxZoom × 256; the pixel-to-EPSG:3857 scale factor

Exported Types

  • PointSet, BiDirectionKey, WeightBufferBD, VertexMode, StrictMode, StrictStatus, YaxisMode
  • CentroidBD, TinsBD, KinksBD, VerticesParamsBD, IndexedTinsBD
  • Compiled, CompiledLegacy
  • Tins, Tri, PropertyTriKey
  • Edge, EdgeSet, EdgeSetLegacy
  • Viewpoint{ center: number[], zoom: number, rotation: number }
  • MapData{ compiled: Compiled, maxZoom?: number, sub_maps?: SubMapData[] }
  • SubMapData{ compiled: Compiled, priority: number, importance: number, bounds?: number[][] }

Exported Utility Functions

  • transformArr: Low-level coordinate transformation function
  • rotateVerticesTriangle: Rotate vertices of a triangle
  • counterTri: Counter triangle utility
  • normalizeEdges: Normalize edge definitions

Format Version

import { format_version } from '@maplat/transform';
console.log(format_version); // Current format version

The compiled data format has two modern versions:

  • V2: Uses 4 fixed boundary vertices derived from the map bounding box
  • V3: Uses N boundary vertices (≥4) for more precise boundary definition, improving transformation accuracy especially near map edges

Both formats are handled transparently by setCompiled(). V3 compiled data is generated by @maplat/tin version 3 or later.

Documentation

For detailed technical information about the transformation internals, see:

  • Transform Internals - Runtime notes on how Transform class reconstructs state and performs coordinate lookups

Development

Running Tests

pnpm test

Important Note

This library specializes in executing coordinate transformations and does not include functionality for generating or editing transformation definitions. If you need to create or edit transformation definitions, please use the @maplat/tin package.

License

Maplat Limited License 1.1

Copyright (c) 2025 Code for History

Developers

  • Kohei Otsuka
  • Code for History

We welcome your contributions! Feel free to submit issues and pull requests.

About

Triangulate Irregular Network Transformation Library for Maplat

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • TypeScript 76.9%
  • JavaScript 18.4%
  • HTML 4.7%