Commit Graph
14 Commits
Author SHA1 Message Date
Claude 5f1eb94fcc Merge main into the MLT branch
main moved each tool's option table to file scope so that usage.cpp can
generate the usage message from it (#409), which conflicted with the
tables the MLT options had been added to. The three MLT options move to
the file-scope tables, under the same headings they were listed with
before: "Setting or disabling tile size limits" in tippecanoe and
tile-join, and "Output tile" in tippecanoe-overzoom.

Also combine the new radix-sort-test with the MLT tests in the test
target, add usage.o to the tools that gained MLT objects, keep both the
MLT=0 and the new docs CI jobs, and regenerate the man page for the
README changes, which the docs job now checks.
2026-08-07 17:04:02 +00:00
Erica FischerandClaude Opus 5 905fe84459 Generate the man page with go-md2man instead of md2man-roff (#408)
* Generate the man page with go-md2man instead of md2man-roff

md2man-roff is distributed only as a Ruby gem -- it is in neither Homebrew
nor apt -- so in practice nobody has it installed and man/tippecanoe.1
drifts away from README.md. It was stale again as of #400: the man page
still had the dead All Streets link that commit fixed.

Switch to go-md2man, the maintained Go port of the same converter (it is
what Docker, podman and runc use). It is packaged as a single static
binary for Homebrew, apt, Fedora and Alpine, and it renders inline code as
bold the same way md2man-roff did, so the man page still reads the way it
used to.

It also emits valid roff, which md2man-roff did not. `mandoc -T lint` goes
from 621 errors and warnings to 1 (an empty .TH date, left empty on
purpose so that generation stays reproducible). 590 of those were
`invalid escape sequence: \fC`, from md2man-roff wrapping every inline
code span in `\fB\fC` -- `\fC` is not a font escape.

md2man-roff was losing content, too:

  README:      1/(2^32) of the size of Earth
  md2man-roff: 1/(2 of the size of Earth
  go-md2man:   1/(2^32) of the size of Earth

  README:      '{"attr": "operation", "attr2": "operation2"}'
  md2man-roff: '{"attr": "operation", "attr2", "operation2"}'
  go-md2man:   '{"attr": "operation", "attr2": "operation2"}'

Prepend a title block and a NAME section during generation rather than
adding them to README.md, where they would render as noise on GitHub.
The man page had neither, so its header rendered as "tippecanoe()" with no
section, and `man -k tippecanoe` and `whatis tippecanoe` found nothing.
It now renders as TIPPECANOE(1) and is indexed.

Finally, add a CI job that regenerates the man page and fails if the
committed copy differs, so a README edit that needs `make docs` gets
caught rather than sitting stale until someone notices. This is what
makes the missing-tool problem stop mattering: contributors no longer
need go-md2man installed to keep the man page current, since CI will
tell them when it needs regenerating. The go-md2man version is pinned
there because different versions produce different roff for the same
input.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015B6PcMbNY779iaczo6S6Pu

* Strip the redundant blank lines go-md2man puts between paragraphs

go-md2man separates paragraphs with a blank line as well as a .PP macro.
A blank line is itself a break in roff, so the two together double-space
the page: every paragraph was followed by two blank lines rather than one.
md2man-roff did not do this, so it showed up as a regression -- the source
went from 13 blank lines to 200.

Filter them out after generation. Blank lines inside .EX and .TS blocks
are kept, since there they are part of the example or the table rather
than spacing around it; that is all 13 of the ones md2man-roff emitted.

The rendered page loses 186 blank lines and the source loses 187, with
byte-identical non-blank output under both groff -t -man and mandoc.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015B6PcMbNY779iaczo6S6Pu

* Decouple the man page from version.hpp, and name the first section

Review feedback on #408.

Making man/tippecanoe.1 depend on version.hpp turned the docs job into a
hard CI failure on any release commit that bumps the version without
regenerating -- #406, which is open and moves version.hpp to v2.81.0
without touching the man page, would have tripped it as soon as either
merged. The only thing the dependency bought was the version in the page
footer, so every release would have had to regenerate the whole file to
rewrite that one line, gated by CI. Drop it: the source field is now just
"tippecanoe", and the page depends on README.md alone.

Separately, README.md's own title heading became the second .SH, directly
below the NAME section this branch adds, so the page opened with a stray
"tippecanoe" section. Rename it to DESCRIPTION, which is where that text
belongs and what a reader expects after NAME.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015B6PcMbNY779iaczo6S6Pu

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-06 16:47:13 -07:00
Claude 13f1c3b6e4 Let tile-join and tippecanoe-overzoom write MLT tiles too
Both tools could read MapLibre Tiles but only ever wrote Mapbox Vector
Tiles, so there was no way to convert a tileset into MLT, or to keep a
tileset in MLT once it had been through either of them.

Give them the same --output-format, --pretessellate, and
--no-mlt-feature-sort options that tippecanoe has. tile-join writes the
chosen format to mbtiles files, PMTiles archives, and tile directories,
naming directory tiles and the tileset metadata format accordingly, and
tippecanoe-overzoom writes it to its output tile. Either tool will read
whichever format its sources are in regardless of what it is writing.

The output format selection and the MLT encoder options now live in
mlt.cpp, shared by all three tools rather than defined in main.cpp for
tippecanoe alone, along with encode_tile() for encoding a tile in the
selected format. overzoom() takes the format as a parameter, since
tile-join uses it internally to rescale tiles that will be re-encoded
afterward, and those intermediate tiles should stay MVT.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LxhELiLtpUFwrPSWwTYdHG
2026-08-06 17:34:02 +00:00
Claude 2410727242 Read MapLibre Tiles in tippecanoe-decode, tile-join, and tippecanoe-overzoom
Tilesets written with --output-format=mlt could not be read back by any of
tippecanoe's own tools, which made MLT a dead end rather than a tile format.

Build the mlt-cpp decoder from the vendored maplibre-tile-spec submodule
alongside the encoder, and convert a decoded MapLibre Tile back into the
equivalent mvt_tile: geometry, feature ids, and property columns. MLT rings
come back explicitly closed, so the repeated final point becomes an MVT
closepath, and the property columns, which are held in an unordered map,
are sorted by name so that the attributes of a decoded tile come out in a
stable order.

Rather than adding an option to each tool, mvt_tile::decode() detects the
encoding and dispatches, so everywhere tippecanoe already reads a vector
tile can read MLT. An MLT tile begins with a varint layer length followed
by a varint layer tag whose only defined value is 1, while an MVT tile is
a protobuf whose only field is the repeated layer field 3, so it begins
with 0x1a followed by a layer length that can never be as short as the one
byte that would be needed to look like an MLT layer tag.

Tile directories also needed a fix: enumerate_dirtiles() recognized .mlt
file names but still recorded .pbf as the extension to read them back
with, so decoding an MLT directory failed to find any of its tiles.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LxhELiLtpUFwrPSWwTYdHG
2026-08-06 17:12:28 +00:00
Danila Poyarkov 776a7b3b84 Tighten MLT wording 2026-07-04 19:56:35 +03:00
Danila Poyarkov 0e536bcec4 Update MLT encoder dependency 2026-07-03 15:11:19 +03:00
Danila Poyarkov 53b98d76c4 Add MLT (MapLibre Tile) output format
Integrate the C++ MLT encoder from maplibre-tile-spec as a submodule.
Tiles are encoded by converting the existing mvt_tile to
mlt::Encoder::Layer and calling the encoder library directly.

New CLI flags:
  --output-format=mlt     Encode tiles as MLT instead of MVT
  --pretessellate         Pre-triangulate polygons (MLT only)
  --no-mlt-feature-sort   Disable within-tile Hilbert sorting (MLT only)

MLT tiles use .mlt extension in directory output and format=mlt in
mbtiles metadata. Compression and all existing flags work unchanged.
2026-07-02 17:29:24 +03:00
Dane Springmeyer 266ef3c286 Add tippecanoe-overzoom to .gitignore (#224)
add tippecanoe-overzoom to .gitignore
2024-03-25 11:00:18 -07:00
jingsam 752f77d58e chore: ignore geobuf tests files and node_modules 2018-11-07 14:49:51 +08:00
jingsam 5d6e6e07d6 chore: ignore generated check and mbtiles files in tests 2018-08-23 14:16:50 +08:00
jingsam cc6a97f112 Ignore tippecanoe-json-tool 2018-04-08 17:19:19 +08:00
Eric Fischer 0ecc6fa1c5 Put everything normally generated during compilation in .gitignore 2017-04-23 15:31:57 -07:00
Shan-Chun Kuo f03b89656c Seperated out to method and added test for --raw-tiles 2017-04-05 15:59:37 +01:00
jingsam eb1c724fc4 Create .gitignore 2016-11-16 16:10:41 +08:00