Skip to content

Develop - #65

Open
HideBa wants to merge 15 commits into
mainfrom
develop
Open

HideBa wants to merge 15 commits into
mainfrom
develop

Conversation

@HideBa

@HideBa HideBa commented Oct 13, 2026

Copy link
Copy Markdown
Member

No description provided.

HideBa and others added 15 commits August 14, 2026 16:23
Both were last touched at 0.8.0 and sat out the 0.8.1 release: nothing
checks them, and the only signal is a comment above PROJECT_NUMBER
saying it must match CMakeLists.txt. PROJECT_NUMBER stamps the version
on the published C++ API docs; src/cpp/vcpkg.json is the developer
manifest for building this directory, distinct from the registry port.
cjseq 0.5 is a typed rewrite: geometry variants carry their own lod,
semantics, material and texture; values are nested exactly as deep as the
variant needs; indices are newtypes; city objects and themes are ordered
maps. fcb_core, fcb_cli and fcb_api are ported to it.

- The geometry encoder and decoder are generic over the value shape the
  variant names, so the depth comes from the type, not from the arrays.
- A geometry without a lod is now an error on decode, as the schema
  requires. A malformed texture ring is an error instead of a silent value.
- fcb_api builds CityJSON documents with cjseq_to_cj.
- The wire format is unchanged: re-serialising every conformance input
  gives byte-identical .fcb files, and the reader's output is JSON-equal
  to every .expected.jsonl.

Tests: e2e.rs compares whole round-tripped features instead of selected
members. Tests that asserted on depth inference, which the types now fix,
are removed.

The geom_temp fixture's geometry templates pointed past their materials
palette (written by a cjseq `cat` bug, see upstream-findings #37). The
template material indices are renumbered and its conformance pair
regenerated.

cjseq comes from git, HideBa/cjseq pinned to 2b635a1, until 0.5 is
published on crates.io.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GMEezDM6ixvYJNMZupreTu
cjseq's public enums are now #[non_exhaustive], so the matches that
mapped them exhaustively need a `_` arm, and a variant cjseq adds no
longer fails to compile here. It is refused at run time instead, never
mapped to a default: the writer returns the new
Error::UnencodableVariant, and OBJ export an InvalidData error.

Breaking: to_fcb_city_feature, FeatureWriter::finish_to_feature and
obj::to_obj_string now return a Result.

- cjseq is used with default-features = false, so its CLI dependencies
  (clap, rand, getrandom) stay out of the build.
- The workspace clap enables `derive` itself; fcb_cli had been getting
  it only through cjseq's own clap.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GMEezDM6ixvYJNMZupreTu
Replaces the git pin on HideBa/cjseq 0d92c4b with the published
pre-release, pinned exactly because a pre-release may break between
alphas. The crate adds LoD 4 support on top of 0d92c4b; nothing in
flatcitybuf relied on LoD 4 being rejected. Every conformance .fcb is
still written byte for byte.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GMEezDM6ixvYJNMZupreTu
FcbWriter::add_feature took &'a CityJSONFeature, tying every feature's
borrow to the writer, so a caller had to keep the whole dataset alive
until write(). The feature is serialised inside the call, so the borrow
now lasts for the call only, and a caller can stream features from a
reader without holding them.

Breaking: FeatureWriter::new no longer takes a feature, and
finish_to_feature takes the feature to serialise; add_feature is gone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dg6YXaXoHW43fAeFVKMwqX
CityObject gains an optional `address` vector of Address tables, one
per entry of the CityJSON `address` array: the members other than
`location` encoded as attributes with the address's own columns, and
`location` as a MultiPoint Geometry into the feature's vertices.
Before this the writer dropped every address without an error.

Appending an optional field keeps every existing file readable, and the
conformance corpus is byte-identical. New fixture: object_address.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dg6YXaXoHW43fAeFVKMwqX
Each port decodes CityObject.address as the Rust reader does: members
against the address's own columns, location as a MultiPoint geometry.
The C++ writer encodes it in Rust's field order, so its object_address
output is byte-identical to the Rust-written fixture. object_address
joins each port's conformance cases.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dg6YXaXoHW43fAeFVKMwqX
A CityJSON `extensions` entry may carry members beyond url and version;
the CityGML crates write an ADE's xmlns and its constant XML attributes
there, and the CityGML writer needs them back. The header's Extension
table gains `members`, the other members as one JSON object, which the
Rust writer fills and reader restores. Before this they were dropped.

Also: a quantised vertex outside the 32-bit range of a FlatCityBuf
Vertex is an error (VertexOutOfRange) instead of a panic.

Existing corpus files are byte-identical. New fixture:
extension_members.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dg6YXaXoHW43fAeFVKMwqX
…the C++ writer

The C++ writer's extension_members.fcb is byte-identical to Rust's; every
port reads the corpus case line for line.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dg6YXaXoHW43fAeFVKMwqX
The C++ writer cast each quantised coordinate with get<int32_t>, which wraps
silently; it now throws ErrorCode::VertexOutOfRange, as the Rust writer
returns Error::VertexOutOfRange.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dg6YXaXoHW43fAeFVKMwqX
fcb ser reads .gml/.xml inputs through the citygml crates (a git dependency
on cityjson/cityparquet until they are on crates.io); fcb deser writes
CityGML when the output ends in .gml/.xml, --citygml-version 2.0 (default)
or 3.0. Behind the fcb_cli feature citygml, on by default.

The transform is chosen from the documents' envelopes before any feature
is read, with a scale from the CRS's axis units, as cityparquet does.
Features are spooled to a temporary CityJSONSeq while the attribute
schemas are built, so memory holds one feature, not the dataset.

Round trips: GML -> fcb -> CityJSONSeq equals the crates' own CityJSON,
whole features compared; fcb -> CityGML -> fcb equals it again unless the
writer reports leaving something out.

Also: upstream-findings 38-40 (address, extension members, vertex range).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dg6YXaXoHW43fAeFVKMwqX
A document with no gml:boundedBy was quantised from translate 0, so
projected coordinates in the millions overflowed a FlatCityBuf Vertex
(VertexOutOfRange on the OGC Melbourne road sample). The spooled integers
are now shifted onto their own minimum, which moves into translate.

Writing CityGML drops the header extent when the .fcb has none, rather
than declaring the all-zero extent the reader invents (upstream-findings
41, not fixed in the readers).

The round-trip test reads an ADE's attributes as text on the second leg:
the writer names the ADE schema by its URL, which the reader never fetches.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dg6YXaXoHW43fAeFVKMwqX
fcb_cli depends on the single citygml crate (cityjson/cityparquet
fdf8cda) instead of citygml-core, citygml2, citygml3 and
cityparquet-schema. Version dispatch, the reader and writer by version,
and a document's CityJSON header (CRS-aware transform, reference system,
extent, templates, ADE extensions) are the crate's; the local srsName
resolution and header building are gone. A single document now gets
exactly the transform cityparquet picks; the test asserts it.

Several documents still share one transform from their envelopes
together, and a document without an envelope still shifts onto its own
minimum.

The crate keeps appearance numbering and writes no empty geometry, so the
round-trip test compares features without normalising either.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dg6YXaXoHW43fAeFVKMwqX
The merge of cityparquet PR #26; its crates are those of fdf8cda.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dg6YXaXoHW43fAeFVKMwqX
CityGML 2.0 / 3.0 in and out of fcb ser and deser

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants