pycadkit 0.3.0__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pycadkit-0.3.0 → pycadkit-0.3.2}/Cargo.lock +10 -10
- {pycadkit-0.3.0 → pycadkit-0.3.2}/Cargo.toml +7 -7
- {pycadkit-0.3.0 → pycadkit-0.3.2}/PKG-INFO +1 -1
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/lib.rs +1 -1
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/map/mod.rs +107 -39
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/writer/encode.rs +7 -2
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/writer/mod.rs +109 -6
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/writer/raster.rs +72 -37
- pycadkit-0.3.2/crates/cadkit-dgn/src/writer/raster_template.rs +571 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/writer/tables.rs +42 -4
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/writer/tests/raster.rs +1 -1
- pycadkit-0.3.2/crates/cadkit-dgn/src/writer/tests/raster_template.rs +649 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/writer/tests/regressions.rs +88 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/writer/tests.rs +1 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/tests/common/mod.rs +25 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/tests/private_corpus.rs +161 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/LICENSE-APACHE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/LICENSE-MIT +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/NOTICE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/README.md +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit/Cargo.toml +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit/LICENSE-APACHE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit/LICENSE-MIT +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit/NOTICE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit/README.md +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit/examples/interchange.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit/src/lib.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/Cargo.toml +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/LICENSE-APACHE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/LICENSE-MIT +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/NOTICE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/README.md +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/src/aci.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/src/bytes.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/src/error.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/src/export.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/src/geom.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/src/geom_ops.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/src/lib.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/src/model.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/src/ops.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/src/options.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/src/polygon.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/src/svg.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/src/text.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-core/src/units.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/Cargo.toml +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/LICENSE-APACHE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/LICENSE-MIT +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/NOTICE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/README.md +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/examples/dgn_summary.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/examples/raster_structure.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/budget.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/cfb.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/fuzz_tests.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/le.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/level_names.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/map/v7.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/map/v8.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/native/decode_v8.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/native/element.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/native/linkage.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/native/mod.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/native/v7.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/native/v8.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/palette.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/text.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/writer/container.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/writer/polyline.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/writer/tests/application.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/writer/tests/microstation.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/writer/tests/text.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/writer/text.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/src/zlib.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/tests/robustness.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/tests/v7_corpus.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/tests/v8_oracle.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/tests/v8_public.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dgn/tests/v8_range.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/Cargo.toml +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/LICENSE-APACHE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/LICENSE-MIT +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/NOTICE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/README.md +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/examples/docsummary.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/examples/dwgdump.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/bits.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/classes.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/codepage.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/container/lz77_r2004.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/container/lz77_r2007.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/container/mod.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/container/r13.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/container/r2004.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/container/r2007.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/container/reed_solomon.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/crc.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/handles.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/header.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/lib.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/mapping/entity.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/mapping/mod.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/native/entities.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/native/mod.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/object/annotation.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/object/curves.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/object/entities.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/object/hatch.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/object/misc.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/object/mod.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/object/registry.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/object/tables.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/reader.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/src/version.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/tests/corpus.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/tests/oracle.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dwg/tests/robustness.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/Cargo.toml +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/LICENSE-APACHE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/LICENSE-MIT +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/NOTICE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/README.md +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/examples/dump.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/src/lib.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/src/native/mod.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/src/native/text.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/src/ocs.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/src/reader/common.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/src/reader/entities.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/src/reader/hatch.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/src/reader/mod.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/src/reader/records.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/src/reader/tables.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/src/writer/curves.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/src/writer/entities.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/src/writer/mod.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/src/writer/out.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/tests/ascii_vs_binary.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/tests/common/mod.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/tests/compare_reader_with_ezdxf.py +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/tests/review_fixes.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/tests/robustness.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/tests/roundtrip.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/tests/synthetic_read.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/tests/synthetic_write.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-dxf/tests/validate_with_ezdxf.py +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/Cargo.toml +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/LICENSE-APACHE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/LICENSE-MIT +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/NOTICE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/README.md +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/src/curves.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/src/export.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/src/geometry.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/src/lib.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/src/mapping.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/src/native.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/src/tkgm.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/src/validate.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/src/xml.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/tests/roundtrip.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/tests/support/export_cases.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-gml/tests/support/tkgm_cases.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-py/Cargo.toml +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-py/LICENSE-APACHE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-py/LICENSE-MIT +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-py/NOTICE +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-py/README.md +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-py/src/lib.rs +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-py/tests/conftest.py +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-py/tests/test_cadkit.py +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/crates/cadkit-py/tests/test_citygml.py +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/pyproject.toml +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/python/cadkit/__init__.py +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/python/cadkit/__init__.pyi +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/python/cadkit/_cadkit.pyi +0 -0
- {pycadkit-0.3.0 → pycadkit-0.3.2}/python/cadkit/py.typed +0 -0
|
@@ -66,7 +66,7 @@ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
|
|
66
66
|
|
|
67
67
|
[[package]]
|
|
68
68
|
name = "cadkit"
|
|
69
|
-
version = "0.3.
|
|
69
|
+
version = "0.3.2"
|
|
70
70
|
dependencies = [
|
|
71
71
|
"cadkit-core",
|
|
72
72
|
"cadkit-dgn",
|
|
@@ -78,7 +78,7 @@ dependencies = [
|
|
|
78
78
|
|
|
79
79
|
[[package]]
|
|
80
80
|
name = "cadkit-capi"
|
|
81
|
-
version = "0.3.
|
|
81
|
+
version = "0.3.2"
|
|
82
82
|
dependencies = [
|
|
83
83
|
"cadkit",
|
|
84
84
|
"serde",
|
|
@@ -87,7 +87,7 @@ dependencies = [
|
|
|
87
87
|
|
|
88
88
|
[[package]]
|
|
89
89
|
name = "cadkit-cli"
|
|
90
|
-
version = "0.3.
|
|
90
|
+
version = "0.3.2"
|
|
91
91
|
dependencies = [
|
|
92
92
|
"cadkit",
|
|
93
93
|
"clap",
|
|
@@ -96,7 +96,7 @@ dependencies = [
|
|
|
96
96
|
|
|
97
97
|
[[package]]
|
|
98
98
|
name = "cadkit-core"
|
|
99
|
-
version = "0.3.
|
|
99
|
+
version = "0.3.2"
|
|
100
100
|
dependencies = [
|
|
101
101
|
"serde",
|
|
102
102
|
"serde_json",
|
|
@@ -105,7 +105,7 @@ dependencies = [
|
|
|
105
105
|
|
|
106
106
|
[[package]]
|
|
107
107
|
name = "cadkit-dgn"
|
|
108
|
-
version = "0.3.
|
|
108
|
+
version = "0.3.2"
|
|
109
109
|
dependencies = [
|
|
110
110
|
"cadkit-core",
|
|
111
111
|
"cfb",
|
|
@@ -116,7 +116,7 @@ dependencies = [
|
|
|
116
116
|
|
|
117
117
|
[[package]]
|
|
118
118
|
name = "cadkit-dwg"
|
|
119
|
-
version = "0.3.
|
|
119
|
+
version = "0.3.2"
|
|
120
120
|
dependencies = [
|
|
121
121
|
"cadkit-core",
|
|
122
122
|
"cadkit-dxf",
|
|
@@ -126,7 +126,7 @@ dependencies = [
|
|
|
126
126
|
|
|
127
127
|
[[package]]
|
|
128
128
|
name = "cadkit-dxf"
|
|
129
|
-
version = "0.3.
|
|
129
|
+
version = "0.3.2"
|
|
130
130
|
dependencies = [
|
|
131
131
|
"cadkit-core",
|
|
132
132
|
"encoding_rs",
|
|
@@ -135,7 +135,7 @@ dependencies = [
|
|
|
135
135
|
|
|
136
136
|
[[package]]
|
|
137
137
|
name = "cadkit-gml"
|
|
138
|
-
version = "0.3.
|
|
138
|
+
version = "0.3.2"
|
|
139
139
|
dependencies = [
|
|
140
140
|
"cadkit-core",
|
|
141
141
|
"quick-xml",
|
|
@@ -145,7 +145,7 @@ dependencies = [
|
|
|
145
145
|
|
|
146
146
|
[[package]]
|
|
147
147
|
name = "cadkit-py"
|
|
148
|
-
version = "0.3.
|
|
148
|
+
version = "0.3.2"
|
|
149
149
|
dependencies = [
|
|
150
150
|
"cadkit",
|
|
151
151
|
"pyo3",
|
|
@@ -155,7 +155,7 @@ dependencies = [
|
|
|
155
155
|
|
|
156
156
|
[[package]]
|
|
157
157
|
name = "cadkit-wasm"
|
|
158
|
-
version = "0.3.
|
|
158
|
+
version = "0.3.2"
|
|
159
159
|
dependencies = [
|
|
160
160
|
"cadkit",
|
|
161
161
|
"js-sys",
|
|
@@ -4,7 +4,7 @@ members = ["crates/*"]
|
|
|
4
4
|
exclude = ["fuzz"]
|
|
5
5
|
|
|
6
6
|
[workspace.package]
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.2"
|
|
8
8
|
edition = "2024"
|
|
9
9
|
rust-version = "1.85"
|
|
10
10
|
license = "MIT OR Apache-2.0"
|
|
@@ -14,12 +14,12 @@ keywords = ["cad", "dwg", "dgn", "dxf", "citygml"]
|
|
|
14
14
|
categories = ["parser-implementations", "graphics", "encoding", "science::geo"]
|
|
15
15
|
|
|
16
16
|
[workspace.dependencies]
|
|
17
|
-
cadkit-core = { path = "crates/cadkit-core", version = "0.3.
|
|
18
|
-
cadkit-dgn = { path = "crates/cadkit-dgn", version = "0.3.
|
|
19
|
-
cadkit-dwg = { path = "crates/cadkit-dwg", version = "0.3.
|
|
20
|
-
cadkit-dxf = { path = "crates/cadkit-dxf", version = "0.3.
|
|
21
|
-
cadkit-gml = { path = "crates/cadkit-gml", version = "0.3.
|
|
22
|
-
cadkit = { path = "crates/cadkit", version = "0.3.
|
|
17
|
+
cadkit-core = { path = "crates/cadkit-core", version = "0.3.2" }
|
|
18
|
+
cadkit-dgn = { path = "crates/cadkit-dgn", version = "0.3.2" }
|
|
19
|
+
cadkit-dwg = { path = "crates/cadkit-dwg", version = "0.3.2" }
|
|
20
|
+
cadkit-dxf = { path = "crates/cadkit-dxf", version = "0.3.2" }
|
|
21
|
+
cadkit-gml = { path = "crates/cadkit-gml", version = "0.3.2" }
|
|
22
|
+
cadkit = { path = "crates/cadkit", version = "0.3.2" }
|
|
23
23
|
serde = { version = "1", features = ["derive"] }
|
|
24
24
|
serde_json = "1"
|
|
25
25
|
thiserror = "2"
|
|
@@ -671,7 +671,7 @@ impl Mapper {
|
|
|
671
671
|
e.props.insert("dgn.point_string".into(), Value::Bool(true));
|
|
672
672
|
}
|
|
673
673
|
ElementData::RasterFrame { matrix, .. } => {
|
|
674
|
-
// Pixel-to-UOR matrix as stored; the
|
|
674
|
+
// Pixel-to-UOR matrix as stored; the range only checks the placement.
|
|
675
675
|
if let Some([lo, hi]) = item.el.header.range {
|
|
676
676
|
let (a, b) = (xf.pt(lo), xf.pt(hi));
|
|
677
677
|
e.props.insert(
|
|
@@ -683,6 +683,19 @@ impl Mapper {
|
|
|
683
683
|
"dgn.raster_matrix".into(),
|
|
684
684
|
Value::List(matrix.iter().map(|v| Value::Float(*v)).collect()),
|
|
685
685
|
);
|
|
686
|
+
// `0x118` / `0x120`: horizontal and vertical resolution in dots per inch.
|
|
687
|
+
let dpi = crate::le::f64_at(item.raw, 0x118);
|
|
688
|
+
if let Some(x) = dpi {
|
|
689
|
+
e.props.insert("dgn.raster_dpi".into(), Value::Float(x));
|
|
690
|
+
}
|
|
691
|
+
if let Some(y) = crate::le::f64_at(item.raw, 0x120).filter(|y| Some(*y) != dpi) {
|
|
692
|
+
e.props.insert("dgn.raster_dpi_y".into(), Value::Float(y));
|
|
693
|
+
}
|
|
694
|
+
if let Some((rotation, skew)) = frame_angles(matrix) {
|
|
695
|
+
e.props
|
|
696
|
+
.insert("dgn.raster_rotation".into(), Value::Float(rotation));
|
|
697
|
+
e.props.insert("dgn.raster_skew".into(), Value::Float(skew));
|
|
698
|
+
}
|
|
686
699
|
let id = item.el.header.id.unwrap_or(0);
|
|
687
700
|
if let Some((name, full)) = self.raster_paths.get(&id) {
|
|
688
701
|
if let Some(n) = name {
|
|
@@ -873,34 +886,33 @@ impl Mapper {
|
|
|
873
886
|
fn image(&mut self, item: &Item<'_>, xf: &Xf) -> EntityKind {
|
|
874
887
|
let id = item.el.header.id.unwrap_or(0);
|
|
875
888
|
let range = item.el.header.range;
|
|
876
|
-
let (matrix_placement, axes) = match &item.el.data {
|
|
877
|
-
ElementData::RasterFrame { matrix, corner } =>
|
|
878
|
-
|
|
879
|
-
(
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
}
|
|
884
|
-
_ => (None, None),
|
|
889
|
+
let (matrix_placement, pixels, axes) = match &item.el.data {
|
|
890
|
+
ElementData::RasterFrame { matrix, corner } => (
|
|
891
|
+
frame_placement(matrix, *corner),
|
|
892
|
+
frame_pixels(matrix, *corner),
|
|
893
|
+
Some(frame_axes(matrix)),
|
|
894
|
+
),
|
|
895
|
+
_ => (None, None, None),
|
|
885
896
|
};
|
|
886
|
-
// The element range is MicroStation's own bounding box
|
|
887
|
-
// not fit inside it is
|
|
888
|
-
|
|
897
|
+
// The element range is MicroStation's own bounding box. It only checks the matrix
|
|
898
|
+
// placement: one that does not fit inside it is replaced by a placement derived from
|
|
899
|
+
// the range, and the pixel size is then not trusted either.
|
|
900
|
+
let (placement, size_px) = match (matrix_placement, range) {
|
|
889
901
|
(Some(p), Some(r)) if !within_range(&p, &r, RASTER_RANGE_TOLERANCE) => {
|
|
890
902
|
self.note("dgn.raster_outside_range", || {
|
|
891
903
|
"raster transform places the image outside its element range; the range was used"
|
|
892
904
|
.into()
|
|
893
905
|
});
|
|
894
|
-
Some(range_placement(&r, axes))
|
|
906
|
+
(Some(range_placement(&r, axes)), None)
|
|
895
907
|
}
|
|
896
|
-
(Some(p), _) => Some(p),
|
|
908
|
+
(Some(p), _) => (Some(p), pixels),
|
|
897
909
|
(None, Some(r)) => {
|
|
898
910
|
self.note("dgn.raster_range_placement", || {
|
|
899
911
|
"raster frame placed from its range (no usable transform)".into()
|
|
900
912
|
});
|
|
901
|
-
Some(range_placement(&r, axes))
|
|
913
|
+
(Some(range_placement(&r, axes)), None)
|
|
902
914
|
}
|
|
903
|
-
(None, None) => None,
|
|
915
|
+
(None, None) => (None, None),
|
|
904
916
|
};
|
|
905
917
|
let Some((origin, u, v)) = placement else {
|
|
906
918
|
return EntityKind::Unknown {
|
|
@@ -921,7 +933,7 @@ impl Mapper {
|
|
|
921
933
|
position: xf.pt(origin),
|
|
922
934
|
u_vector: tidy(u.scaled(xf.scale)),
|
|
923
935
|
v_vector: tidy(v.scaled(xf.scale)),
|
|
924
|
-
size_px
|
|
936
|
+
size_px,
|
|
925
937
|
}
|
|
926
938
|
}
|
|
927
939
|
|
|
@@ -1109,30 +1121,63 @@ fn curve(points: &[UorPoint], xf: &Xf) -> EntityKind {
|
|
|
1109
1121
|
}
|
|
1110
1122
|
}
|
|
1111
1123
|
|
|
1124
|
+
/// Pixel X and Y axes of a raster frame matrix (row-major 4x4): its first two columns,
|
|
1125
|
+
/// one pixel long each, in UOR.
|
|
1126
|
+
pub(crate) fn frame_axes(m: &[f64; 16]) -> (Vec3, Vec3) {
|
|
1127
|
+
let [m00, m01, _, _, m10, m11, _, _, m20, m21, ..] = *m;
|
|
1128
|
+
(Vec3::new(m00, m10, m20), Vec3::new(m01, m11, m21))
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1112
1131
|
/// Raster frame placement from its pixel-to-UOR matrix (row-major, translation in the
|
|
1113
|
-
/// last column)
|
|
1114
|
-
///
|
|
1115
|
-
///
|
|
1132
|
+
/// last column) and its edge lengths (`0x108`/`0x110`, UOR): the image starts at the
|
|
1133
|
+
/// translation (its lower-left corner) and its edges run along the unit matrix X / Y
|
|
1134
|
+
/// columns for those lengths, `u = â·ext_x`, `v = b̂·ext_y`. The lengths are measured
|
|
1135
|
+
/// along the image axes (width·|a| and height·|b|), not as an XY extent, so rotated and
|
|
1136
|
+
/// sheared frames need no solving. `None` when an axis or a length is degenerate.
|
|
1116
1137
|
pub(crate) fn frame_placement(
|
|
1117
1138
|
m: &[f64; 16],
|
|
1118
|
-
|
|
1139
|
+
edges: Option<[f64; 2]>,
|
|
1119
1140
|
) -> Option<(UorPoint, Vec3, Vec3)> {
|
|
1120
|
-
let [
|
|
1121
|
-
let a =
|
|
1122
|
-
let
|
|
1123
|
-
|
|
1124
|
-
// element range extent on the private sample), not an absolute corner.
|
|
1125
|
-
let [dx, dy] = corner?;
|
|
1126
|
-
let det = a.x * b.y - a.y * b.x;
|
|
1127
|
-
if !det.is_finite() || det.abs() <= 1e-12 * a.length() * b.length() {
|
|
1141
|
+
let [_, _, _, m03, _, _, _, m13, _, _, _, m23, ..] = *m;
|
|
1142
|
+
let (a, b) = frame_axes(m);
|
|
1143
|
+
let [ex, ey] = edges?;
|
|
1144
|
+
if !(ex.is_finite() && ey.is_finite() && ex > 0.0 && ey > 0.0) {
|
|
1128
1145
|
return None;
|
|
1129
1146
|
}
|
|
1130
|
-
let
|
|
1131
|
-
|
|
1132
|
-
if
|
|
1147
|
+
let (ua, ub) = (a.normalized()?, b.normalized()?);
|
|
1148
|
+
// Parallel axes span no rectangle.
|
|
1149
|
+
if ua.cross(ub).length() <= 1e-9 {
|
|
1133
1150
|
return None;
|
|
1134
1151
|
}
|
|
1135
|
-
|
|
1152
|
+
if ![m03, m13, m23].iter().all(|v| v.is_finite()) {
|
|
1153
|
+
return None;
|
|
1154
|
+
}
|
|
1155
|
+
Some(([m03, m13, m23], ua.scaled(ex), ub.scaled(ey)))
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
/// Pixel size of a raster frame: its edge lengths over the pixel lengths `|a|` and `|b|`
|
|
1159
|
+
/// of the matrix axes, rounded. `None` when that is not a positive `u32`.
|
|
1160
|
+
pub(crate) fn frame_pixels(m: &[f64; 16], edges: Option<[f64; 2]>) -> Option<[u32; 2]> {
|
|
1161
|
+
let (a, b) = frame_axes(m);
|
|
1162
|
+
let [ex, ey] = edges?;
|
|
1163
|
+
let count = |edge: f64, axis: Vec3| {
|
|
1164
|
+
let n = (edge / axis.length()).round();
|
|
1165
|
+
(n.is_finite() && n >= 1.0 && n <= f64::from(u32::MAX)).then_some(n as u32)
|
|
1166
|
+
};
|
|
1167
|
+
Some([count(ex, a)?, count(ey, b)?])
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
/// Rotation of the image X axis and skew of its Y axis from the perpendicular, both in
|
|
1171
|
+
/// the XY plane, in radians within (-π, π].
|
|
1172
|
+
fn frame_angles(m: &[f64; 16]) -> Option<(f64, f64)> {
|
|
1173
|
+
let (a, b) = frame_axes(m);
|
|
1174
|
+
if a.normalized().is_none() || b.normalized().is_none() {
|
|
1175
|
+
return None;
|
|
1176
|
+
}
|
|
1177
|
+
let rotation = a.y.atan2(a.x);
|
|
1178
|
+
let skew = b.y.atan2(b.x) - rotation - FRAC_PI_2;
|
|
1179
|
+
let skew = skew.sin().atan2(skew.cos());
|
|
1180
|
+
(rotation.is_finite() && skew.is_finite()).then_some((rotation, skew))
|
|
1136
1181
|
}
|
|
1137
1182
|
|
|
1138
1183
|
/// Most XAttribute kinds listed on one entity (the count is always complete).
|
|
@@ -1529,23 +1574,46 @@ mod tests {
|
|
|
1529
1574
|
|
|
1530
1575
|
#[test]
|
|
1531
1576
|
fn raster_placement_follows_the_matrix() {
|
|
1532
|
-
// 30 degree rotation, 2 UOR per pixel, translation (100, 50); a 300 x 200 pixel
|
|
1533
|
-
//
|
|
1577
|
+
// 30 degree rotation, 2 UOR per pixel, translation (100, 50); a 300 x 200 pixel
|
|
1578
|
+
// image. `0x108`/`0x110` hold the edge lengths along the image axes (W·|a|, H·|b|).
|
|
1534
1579
|
let (s, c) = 30f64.to_radians().sin_cos();
|
|
1535
1580
|
let (a, b) = ([2.0 * c, 2.0 * s], [-2.0 * s, 2.0 * c]);
|
|
1536
1581
|
let m = [
|
|
1537
1582
|
a[0], b[0], 0.0, 100.0, a[1], b[1], 0.0, 50.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
|
|
1538
1583
|
];
|
|
1539
|
-
let
|
|
1540
|
-
let (o, u, v) = frame_placement(&m, Some(
|
|
1584
|
+
let edges = [600.0, 400.0];
|
|
1585
|
+
let (o, u, v) = frame_placement(&m, Some(edges)).unwrap();
|
|
1541
1586
|
assert_eq!(o, [100.0, 50.0, 0.0]);
|
|
1542
1587
|
assert!(close(u.x, 600.0 * c) && close(u.y, 600.0 * s));
|
|
1543
1588
|
assert!(close(v.x, -400.0 * s) && close(v.y, 400.0 * c));
|
|
1589
|
+
assert_eq!(frame_pixels(&m, Some(edges)), Some([300, 200]));
|
|
1590
|
+
let (rotation, skew) = frame_angles(&m).unwrap();
|
|
1591
|
+
assert!(close(rotation, 30f64.to_radians()) && close(skew, 0.0));
|
|
1544
1592
|
assert!(frame_placement(&m, None).is_none());
|
|
1593
|
+
assert!(frame_placement(&m, Some([0.0, 400.0])).is_none());
|
|
1545
1594
|
let mut flat = m;
|
|
1546
1595
|
flat[1] = flat[0];
|
|
1547
1596
|
flat[5] = flat[4];
|
|
1548
|
-
assert!(frame_placement(&flat, Some(
|
|
1597
|
+
assert!(frame_placement(&flat, Some(edges)).is_none(), "degenerate");
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
#[test]
|
|
1601
|
+
fn sheared_raster_frames_keep_their_axes() {
|
|
1602
|
+
// X axis 3 UOR per pixel along +X; Y axis 2 UOR per pixel tilted 10 degrees left of
|
|
1603
|
+
// +Y. The Y edge runs along the tilted axis for H·|b| UOR.
|
|
1604
|
+
let (s, c) = 10f64.to_radians().sin_cos();
|
|
1605
|
+
let (a, b) = ([3.0, 0.0], [-2.0 * s, 2.0 * c]);
|
|
1606
|
+
let m = [
|
|
1607
|
+
a[0], b[0], 0.0, -5.0, a[1], b[1], 0.0, 7.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
|
|
1608
|
+
];
|
|
1609
|
+
let edges = [3.0 * 120.0, 2.0 * 80.0];
|
|
1610
|
+
let (o, u, v) = frame_placement(&m, Some(edges)).unwrap();
|
|
1611
|
+
assert_eq!(o, [-5.0, 7.0, 0.0]);
|
|
1612
|
+
assert!(close(u.x, 360.0) && close(u.y, 0.0));
|
|
1613
|
+
assert!(close(v.x, -160.0 * s) && close(v.y, 160.0 * c));
|
|
1614
|
+
assert_eq!(frame_pixels(&m, Some(edges)), Some([120, 80]));
|
|
1615
|
+
let (rotation, skew) = frame_angles(&m).unwrap();
|
|
1616
|
+
assert!(close(rotation, 0.0) && close(skew, 10f64.to_radians()));
|
|
1549
1617
|
}
|
|
1550
1618
|
|
|
1551
1619
|
#[test]
|
|
@@ -240,7 +240,12 @@ pub(super) fn utf16_unterminated(value: &str) -> Result<Vec<u8>> {
|
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
pub(super) fn string_link(id: u32, value: &str) -> Result<Vec<u8>> {
|
|
243
|
-
|
|
243
|
+
string_link_bytes(id, &utf16_unterminated(value)?)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/// String linkage holding `text` as already encoded (`ff fd` + UTF-16LE or 8-bit bytes),
|
|
247
|
+
/// zero padded to 8 bytes; its length counts no terminator.
|
|
248
|
+
pub(super) fn string_link_bytes(id: u32, text: &[u8]) -> Result<Vec<u8>> {
|
|
244
249
|
let size = (12 + text.len() + 7) & !7;
|
|
245
250
|
if size > 512 {
|
|
246
251
|
return Err(Error::LimitExceeded(
|
|
@@ -252,7 +257,7 @@ pub(super) fn string_link(id: u32, value: &str) -> Result<Vec<u8>> {
|
|
|
252
257
|
put(&mut b, 2, &0x56d2u16.to_le_bytes())?;
|
|
253
258
|
u32_at(&mut b, 4, id)?;
|
|
254
259
|
u32_at(&mut b, 8, text.len() as u32)?;
|
|
255
|
-
put(&mut b, 12,
|
|
260
|
+
put(&mut b, 12, text)?;
|
|
256
261
|
Ok(b)
|
|
257
262
|
}
|
|
258
263
|
pub(super) fn dependency(app: u16, id: u64) -> Result<Vec<u8>> {
|
|
@@ -4,12 +4,13 @@ mod container;
|
|
|
4
4
|
mod encode;
|
|
5
5
|
mod polyline;
|
|
6
6
|
mod raster;
|
|
7
|
+
mod raster_template;
|
|
7
8
|
mod tables;
|
|
8
9
|
mod text;
|
|
9
10
|
|
|
10
11
|
use crate::{
|
|
11
12
|
le,
|
|
12
|
-
native::v8::{self, ModelHeader, RawElement},
|
|
13
|
+
native::v8::{self, AuxRecord, ModelHeader, PageHeader, RawElement},
|
|
13
14
|
};
|
|
14
15
|
use cadkit_core::{
|
|
15
16
|
Attribute, Document, Entity, EntityKind, Error, GroupKind, Limits, Point3, ReadOptions, Result,
|
|
@@ -39,7 +40,9 @@ pub struct WriteOptions {
|
|
|
39
40
|
/// drawing units. Defaults to 0.01 (1 cm for metres), allowing coordinate rounding.
|
|
40
41
|
pub planarity_tolerance: f64,
|
|
41
42
|
/// Preserve unchanged raster attachments from the same seed, including their
|
|
42
|
-
/// opaque control and auxiliary records.
|
|
43
|
+
/// opaque control and auxiliary records. Edited attachments are rejected; images
|
|
44
|
+
/// without an id are new attachments cloned from a seed attachment (see
|
|
45
|
+
/// [`seed_has_raster_template`]) whatever this option says.
|
|
43
46
|
pub preserve_seed_rasters: bool,
|
|
44
47
|
/// Keep the seed model's control records that reference no seed graphic (coordinate
|
|
45
48
|
/// system, model settings and similar) with their auxiliary data, byte for byte.
|
|
@@ -68,6 +71,20 @@ pub fn repack_v8(seed: &[u8], options: &ReadOptions) -> Result<Vec<u8>> {
|
|
|
68
71
|
container::rewrite(seed, &BTreeMap::new(), options)
|
|
69
72
|
}
|
|
70
73
|
|
|
74
|
+
/// Whether `seed` can receive new raster attachments: its single model holds at least one
|
|
75
|
+
/// complete raster attachment (the records 92, 93, 93, 90, 91 x 5 in the control pages,
|
|
76
|
+
/// the frame 94 they point at and its XAttribute 170) that [`write_v8`] clones for every
|
|
77
|
+
/// [`EntityKind::Image`] without an id. Seeds with several models return `false`, as
|
|
78
|
+
/// `write_v8` accepts single-model seeds only. `Err` when the seed is not a readable
|
|
79
|
+
/// DGN V8 file.
|
|
80
|
+
pub fn seed_has_raster_template(seed: &[u8], options: &ReadOptions) -> Result<bool> {
|
|
81
|
+
let native = v8::read(seed, options)?;
|
|
82
|
+
Ok(match native.models.as_slice() {
|
|
83
|
+
[model] => raster_template::Template::capture(model).is_some(),
|
|
84
|
+
_ => false,
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
71
88
|
fn compressed(bytes: &[u8]) -> Result<Vec<u8>> {
|
|
72
89
|
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
|
|
73
90
|
encoder.write_all(bytes)?;
|
|
@@ -232,6 +249,8 @@ pub fn write_v8(doc: &Document, seed: &[u8], options: &WriteOptions) -> Result<V
|
|
|
232
249
|
rasters: &rasters,
|
|
233
250
|
records: vec![],
|
|
234
251
|
tags: vec![],
|
|
252
|
+
new_controls: vec![],
|
|
253
|
+
new_xattributes: vec![],
|
|
235
254
|
work: 0,
|
|
236
255
|
vertices: 0,
|
|
237
256
|
bytes: rasters.bytes,
|
|
@@ -245,6 +264,8 @@ pub fn write_v8(doc: &Document, seed: &[u8], options: &WriteOptions) -> Result<V
|
|
|
245
264
|
state.entity(entity, 0, false)?;
|
|
246
265
|
}
|
|
247
266
|
state.records.append(&mut state.tags);
|
|
267
|
+
let new_controls = std::mem::take(&mut state.new_controls);
|
|
268
|
+
let new_xattributes = std::mem::take(&mut state.new_xattributes);
|
|
248
269
|
let records = state.records;
|
|
249
270
|
let named = state.tables.finish(options.timestamp_ms)?;
|
|
250
271
|
let max_id = records
|
|
@@ -305,14 +326,50 @@ pub fn write_v8(doc: &Document, seed: &[u8], options: &WriteOptions) -> Result<V
|
|
|
305
326
|
.map(|p| p.header.format_version)
|
|
306
327
|
.filter(|v| matches!(v, 2 | 3))
|
|
307
328
|
.unwrap_or(3);
|
|
308
|
-
put_pages(
|
|
329
|
+
let record_pages = put_pages(
|
|
309
330
|
&mut replacements,
|
|
310
331
|
&format!("Dgn-Md/{}/Dgn^G", model.storage),
|
|
311
332
|
&records,
|
|
312
333
|
version,
|
|
313
334
|
options.limits.max_decompressed_bytes,
|
|
314
335
|
)?;
|
|
315
|
-
rasters.write_auxiliary(&mut replacements)?;
|
|
336
|
+
rasters.write_auxiliary(&mut replacements, &new_controls)?;
|
|
337
|
+
if let Some(template) = rasters
|
|
338
|
+
.template
|
|
339
|
+
.as_ref()
|
|
340
|
+
.filter(|_| !new_xattributes.is_empty())
|
|
341
|
+
{
|
|
342
|
+
// An XAttribute sits in the auxiliary page numbered like the graphic page of its
|
|
343
|
+
// element, as in every observed attachment.
|
|
344
|
+
let mut pages: BTreeMap<u32, Vec<AuxRecord>> = BTreeMap::new();
|
|
345
|
+
for (index, record) in new_xattributes {
|
|
346
|
+
let number = record_pages
|
|
347
|
+
.get(index)
|
|
348
|
+
.copied()
|
|
349
|
+
.ok_or_else(|| Error::invalid(0, "raster frame record outside the pages"))?;
|
|
350
|
+
pages.entry(number).or_default().push(record);
|
|
351
|
+
}
|
|
352
|
+
let mut last = 0;
|
|
353
|
+
for (number, records) in &pages {
|
|
354
|
+
let header = PageHeader {
|
|
355
|
+
record_count: 0,
|
|
356
|
+
format_version: template.aux_version,
|
|
357
|
+
page_number: *number,
|
|
358
|
+
population: 0,
|
|
359
|
+
};
|
|
360
|
+
replacements.insert(
|
|
361
|
+
format!("Dgn-Md/{}/Dgn^GA/${number}", model.storage),
|
|
362
|
+
Some(raster::aux_page(records, header)?),
|
|
363
|
+
);
|
|
364
|
+
last = *number;
|
|
365
|
+
}
|
|
366
|
+
// `^AH` is at least the highest page number in every observed file; the next free
|
|
367
|
+
// number is the most common value.
|
|
368
|
+
replacements.insert(
|
|
369
|
+
format!("Dgn-Md/{}/Dgn^GA/^AH", model.storage),
|
|
370
|
+
Some(last.saturating_add(1).to_le_bytes().to_vec()),
|
|
371
|
+
);
|
|
372
|
+
}
|
|
316
373
|
if rasters.keep_control_counter {
|
|
317
374
|
// Every control auxiliary page is retained as is; so is its page counter.
|
|
318
375
|
replacements.remove(&format!("Dgn-Md/{}/Dgn^CA/^AH", model.storage));
|
|
@@ -391,13 +448,15 @@ pub fn write_v8(doc: &Document, seed: &[u8], options: &WriteOptions) -> Result<V
|
|
|
391
448
|
#[cfg(test)]
|
|
392
449
|
mod tests;
|
|
393
450
|
|
|
451
|
+
/// Writes `records` to pages `{prefix}/$1`, `$2`, ... of at most 256 KiB and returns the
|
|
452
|
+
/// page number of every record.
|
|
394
453
|
fn put_pages(
|
|
395
454
|
replacements: &mut BTreeMap<String, Option<Vec<u8>>>,
|
|
396
455
|
prefix: &str,
|
|
397
456
|
records: &[Vec<u8>],
|
|
398
457
|
version: u32,
|
|
399
458
|
max: u64,
|
|
400
|
-
) -> Result<
|
|
459
|
+
) -> Result<Vec<u32>> {
|
|
401
460
|
let total = records
|
|
402
461
|
.iter()
|
|
403
462
|
.try_fold(0u64, |sum, r| sum.checked_add(r.len() as u64 + 4))
|
|
@@ -408,6 +467,7 @@ fn put_pages(
|
|
|
408
467
|
let mut first = 0;
|
|
409
468
|
let mut bytes = 0usize;
|
|
410
469
|
let mut number = 1u32;
|
|
470
|
+
let mut numbers = Vec::with_capacity(records.len());
|
|
411
471
|
for (i, r) in records.iter().enumerate() {
|
|
412
472
|
if bytes > 0 && bytes.saturating_add(r.len() + 4) > 256 * 1024 {
|
|
413
473
|
replacements.insert(
|
|
@@ -421,12 +481,13 @@ fn put_pages(
|
|
|
421
481
|
.ok_or_else(|| Error::LimitExceeded("DGN page count".into()))?;
|
|
422
482
|
}
|
|
423
483
|
bytes = bytes.saturating_add(r.len() + 4);
|
|
484
|
+
numbers.push(number);
|
|
424
485
|
}
|
|
425
486
|
replacements.insert(
|
|
426
487
|
format!("{prefix}/${number}"),
|
|
427
488
|
Some(page(records.get(first..).unwrap_or(&[]), version, number)?),
|
|
428
489
|
);
|
|
429
|
-
Ok(
|
|
490
|
+
Ok(numbers)
|
|
430
491
|
}
|
|
431
492
|
|
|
432
493
|
/// An absent tag set is distinct from every explicitly named tag set.
|
|
@@ -476,6 +537,10 @@ struct State<'a> {
|
|
|
476
537
|
rasters: &'a raster::Preserved,
|
|
477
538
|
records: Vec<Vec<u8>>,
|
|
478
539
|
tags: Vec<Vec<u8>>,
|
|
540
|
+
/// Control records of new raster attachments, in stored order.
|
|
541
|
+
new_controls: Vec<Vec<u8>>,
|
|
542
|
+
/// XAttributes of new raster frames with the index of the frame in `records`.
|
|
543
|
+
new_xattributes: Vec<(usize, AuxRecord)>,
|
|
479
544
|
work: u64,
|
|
480
545
|
vertices: u64,
|
|
481
546
|
bytes: u64,
|
|
@@ -584,9 +649,14 @@ impl State<'_> {
|
|
|
584
649
|
|
|
585
650
|
fn add(&mut self, b: Vec<u8>, tag: bool) -> Result<()> {
|
|
586
651
|
self.bytes = self.bytes.saturating_add(b.len() as u64);
|
|
652
|
+
let new_rasters = self
|
|
653
|
+
.new_controls
|
|
654
|
+
.len()
|
|
655
|
+
.saturating_add(self.new_xattributes.len()) as u64;
|
|
587
656
|
if self.bytes > self.options.limits.max_decompressed_bytes
|
|
588
657
|
|| (self.records.len().saturating_add(self.tags.len()) as u64)
|
|
589
658
|
.saturating_add(self.rasters.objects)
|
|
659
|
+
.saturating_add(new_rasters)
|
|
590
660
|
>= self.options.limits.max_objects
|
|
591
661
|
{
|
|
592
662
|
return Err(Error::LimitExceeded("DGN output record budget".into()));
|
|
@@ -607,6 +677,9 @@ impl State<'_> {
|
|
|
607
677
|
.tables
|
|
608
678
|
.level(e.layer.as_deref(), self.options.timestamp_ms)?;
|
|
609
679
|
if matches!(e.kind, EntityKind::Image { .. }) {
|
|
680
|
+
if e.id.is_none() {
|
|
681
|
+
return self.new_raster(e, level, component);
|
|
682
|
+
}
|
|
610
683
|
let (id, record) = self.rasters.frame(e, component)?;
|
|
611
684
|
self.add(record, false)?;
|
|
612
685
|
return self.attributes(e, id, level);
|
|
@@ -964,6 +1037,36 @@ impl State<'_> {
|
|
|
964
1037
|
self.add(finish(b, &links)?, false)?;
|
|
965
1038
|
self.attributes(e, id, level)
|
|
966
1039
|
}
|
|
1040
|
+
/// A new raster attachment cloned from the seed template (see `raster_template`).
|
|
1041
|
+
fn new_raster(&mut self, e: &Entity, level: u32, component: bool) -> Result<()> {
|
|
1042
|
+
if component {
|
|
1043
|
+
return Err(Error::Unsupported(
|
|
1044
|
+
"new DGN raster attachments cannot be complex group components".into(),
|
|
1045
|
+
));
|
|
1046
|
+
}
|
|
1047
|
+
let template = self
|
|
1048
|
+
.rasters
|
|
1049
|
+
.template
|
|
1050
|
+
.as_ref()
|
|
1051
|
+
.ok_or_else(|| Error::Unsupported(raster_template::NO_TEMPLATE.into()))?;
|
|
1052
|
+
let mut ids = [0u64; 10];
|
|
1053
|
+
for id in &mut ids {
|
|
1054
|
+
*id = self.tables.id()?;
|
|
1055
|
+
}
|
|
1056
|
+
let group = template.instantiate(e, ids, level, self.model, self.options.timestamp_ms)?;
|
|
1057
|
+
let extra = group
|
|
1058
|
+
.controls
|
|
1059
|
+
.iter()
|
|
1060
|
+
.map(|c| c.len() as u64)
|
|
1061
|
+
.sum::<u64>()
|
|
1062
|
+
.saturating_add(group.xattribute.payload.len() as u64 + 28);
|
|
1063
|
+
self.bytes = self.bytes.saturating_add(extra);
|
|
1064
|
+
let index = self.records.len();
|
|
1065
|
+
self.new_controls.extend(group.controls);
|
|
1066
|
+
self.new_xattributes.push((index, group.xattribute));
|
|
1067
|
+
self.add(group.frame, false)?;
|
|
1068
|
+
self.attributes(e, group.frame_id, level)
|
|
1069
|
+
}
|
|
967
1070
|
fn points(
|
|
968
1071
|
&mut self,
|
|
969
1072
|
e: &Entity,
|