pycadkit 0.2.1__tar.gz → 0.3.1__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.2.1 → pycadkit-0.3.1}/Cargo.lock +10 -10
- {pycadkit-0.2.1 → pycadkit-0.3.1}/Cargo.toml +7 -7
- {pycadkit-0.2.1 → pycadkit-0.3.1}/PKG-INFO +1 -1
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit/examples/interchange.rs +1 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/src/model.rs +30 -2
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/lib.rs +1 -1
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/map/mod.rs +202 -64
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/map/v8.rs +0 -42
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/native/decode_v8.rs +9 -1
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/native/element.rs +6 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/native/v7.rs +3 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/writer/encode.rs +98 -23
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/writer/mod.rs +308 -35
- pycadkit-0.3.1/crates/cadkit-dgn/src/writer/raster.rs +323 -0
- pycadkit-0.3.1/crates/cadkit-dgn/src/writer/raster_template.rs +571 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/writer/tables.rs +14 -1
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/writer/tests/application.rs +1 -0
- pycadkit-0.3.1/crates/cadkit-dgn/src/writer/tests/microstation.rs +531 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/writer/tests/raster.rs +4 -3
- pycadkit-0.3.1/crates/cadkit-dgn/src/writer/tests/raster_template.rs +649 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/writer/tests/regressions.rs +3 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/writer/tests.rs +6 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/writer/text.rs +12 -16
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/tests/common/mod.rs +25 -0
- pycadkit-0.3.1/crates/cadkit-dgn/tests/private_corpus.rs +345 -0
- pycadkit-0.3.1/crates/cadkit-dgn/tests/v8_range.rs +61 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/mapping/entity.rs +1 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/src/reader/entities.rs +1 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/tests/review_fixes.rs +1 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/tests/synthetic_write.rs +2 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/src/mapping.rs +1 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/tests/support/export_cases.rs +1 -0
- pycadkit-0.2.1/crates/cadkit-dgn/src/writer/raster.rs +0 -245
- pycadkit-0.2.1/crates/cadkit-dgn/tests/private_corpus.rs +0 -151
- {pycadkit-0.2.1 → pycadkit-0.3.1}/LICENSE-APACHE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/LICENSE-MIT +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/NOTICE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/README.md +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit/Cargo.toml +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit/LICENSE-APACHE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit/LICENSE-MIT +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit/NOTICE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit/README.md +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit/src/lib.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/Cargo.toml +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/LICENSE-APACHE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/LICENSE-MIT +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/NOTICE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/README.md +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/src/aci.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/src/bytes.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/src/error.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/src/export.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/src/geom.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/src/geom_ops.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/src/lib.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/src/ops.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/src/options.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/src/polygon.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/src/svg.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/src/text.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-core/src/units.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/Cargo.toml +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/LICENSE-APACHE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/LICENSE-MIT +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/NOTICE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/README.md +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/examples/dgn_summary.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/examples/raster_structure.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/budget.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/cfb.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/fuzz_tests.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/le.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/level_names.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/map/v7.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/native/linkage.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/native/mod.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/native/v8.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/palette.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/text.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/writer/container.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/writer/polyline.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/writer/tests/text.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/src/zlib.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/tests/robustness.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/tests/v7_corpus.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/tests/v8_oracle.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dgn/tests/v8_public.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/Cargo.toml +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/LICENSE-APACHE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/LICENSE-MIT +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/NOTICE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/README.md +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/examples/docsummary.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/examples/dwgdump.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/bits.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/classes.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/codepage.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/container/lz77_r2004.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/container/lz77_r2007.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/container/mod.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/container/r13.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/container/r2004.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/container/r2007.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/container/reed_solomon.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/crc.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/handles.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/header.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/lib.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/mapping/mod.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/native/entities.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/native/mod.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/object/annotation.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/object/curves.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/object/entities.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/object/hatch.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/object/misc.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/object/mod.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/object/registry.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/object/tables.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/reader.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/src/version.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/tests/corpus.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/tests/oracle.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dwg/tests/robustness.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/Cargo.toml +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/LICENSE-APACHE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/LICENSE-MIT +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/NOTICE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/README.md +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/examples/dump.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/src/lib.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/src/native/mod.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/src/native/text.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/src/ocs.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/src/reader/common.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/src/reader/hatch.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/src/reader/mod.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/src/reader/records.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/src/reader/tables.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/src/writer/curves.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/src/writer/entities.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/src/writer/mod.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/src/writer/out.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/tests/ascii_vs_binary.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/tests/common/mod.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/tests/compare_reader_with_ezdxf.py +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/tests/robustness.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/tests/roundtrip.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/tests/synthetic_read.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-dxf/tests/validate_with_ezdxf.py +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/Cargo.toml +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/LICENSE-APACHE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/LICENSE-MIT +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/NOTICE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/README.md +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/src/curves.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/src/export.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/src/geometry.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/src/lib.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/src/native.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/src/tkgm.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/src/validate.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/src/xml.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/tests/roundtrip.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-gml/tests/support/tkgm_cases.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-py/Cargo.toml +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-py/LICENSE-APACHE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-py/LICENSE-MIT +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-py/NOTICE +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-py/README.md +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-py/src/lib.rs +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-py/tests/conftest.py +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-py/tests/test_cadkit.py +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/crates/cadkit-py/tests/test_citygml.py +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/pyproject.toml +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/python/cadkit/__init__.py +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/python/cadkit/__init__.pyi +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/python/cadkit/_cadkit.pyi +0 -0
- {pycadkit-0.2.1 → pycadkit-0.3.1}/python/cadkit/py.typed +0 -0
|
@@ -66,7 +66,7 @@ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
|
|
66
66
|
|
|
67
67
|
[[package]]
|
|
68
68
|
name = "cadkit"
|
|
69
|
-
version = "0.
|
|
69
|
+
version = "0.3.1"
|
|
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.
|
|
81
|
+
version = "0.3.1"
|
|
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.
|
|
90
|
+
version = "0.3.1"
|
|
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.
|
|
99
|
+
version = "0.3.1"
|
|
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.
|
|
108
|
+
version = "0.3.1"
|
|
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.
|
|
119
|
+
version = "0.3.1"
|
|
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.
|
|
129
|
+
version = "0.3.1"
|
|
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.
|
|
138
|
+
version = "0.3.1"
|
|
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.
|
|
148
|
+
version = "0.3.1"
|
|
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.
|
|
158
|
+
version = "0.3.1"
|
|
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.
|
|
7
|
+
version = "0.3.1"
|
|
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.
|
|
18
|
-
cadkit-dgn = { path = "crates/cadkit-dgn", version = "0.
|
|
19
|
-
cadkit-dwg = { path = "crates/cadkit-dwg", version = "0.
|
|
20
|
-
cadkit-dxf = { path = "crates/cadkit-dxf", version = "0.
|
|
21
|
-
cadkit-gml = { path = "crates/cadkit-gml", version = "0.
|
|
22
|
-
cadkit = { path = "crates/cadkit", version = "0.
|
|
17
|
+
cadkit-core = { path = "crates/cadkit-core", version = "0.3.1" }
|
|
18
|
+
cadkit-dgn = { path = "crates/cadkit-dgn", version = "0.3.1" }
|
|
19
|
+
cadkit-dwg = { path = "crates/cadkit-dwg", version = "0.3.1" }
|
|
20
|
+
cadkit-dxf = { path = "crates/cadkit-dxf", version = "0.3.1" }
|
|
21
|
+
cadkit-gml = { path = "crates/cadkit-gml", version = "0.3.1" }
|
|
22
|
+
cadkit = { path = "crates/cadkit", version = "0.3.1" }
|
|
23
23
|
serde = { version = "1", features = ["derive"] }
|
|
24
24
|
serde_json = "1"
|
|
25
25
|
thiserror = "2"
|
|
@@ -722,7 +722,7 @@ pub enum Lineweight {
|
|
|
722
722
|
}
|
|
723
723
|
|
|
724
724
|
/// Non-graphic data attached to an entity (DWG ATTRIB, DGN tag, item-type property).
|
|
725
|
-
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
725
|
+
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
|
|
726
726
|
pub struct Attribute {
|
|
727
727
|
/// Tag / property name.
|
|
728
728
|
pub tag: String,
|
|
@@ -734,13 +734,41 @@ pub struct Attribute {
|
|
|
734
734
|
pub position: Option<Point3>,
|
|
735
735
|
/// The attribute is not displayed.
|
|
736
736
|
pub invisible: bool,
|
|
737
|
+
/// Layer of the attribute's own record when the format stores one (a DGN tag
|
|
738
|
+
/// element has its own level). `None` uses the owning entity's layer.
|
|
739
|
+
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
740
|
+
pub layer: Option<String>,
|
|
741
|
+
/// How the value text is drawn at `position`; `None` when unknown or not drawn.
|
|
742
|
+
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
743
|
+
pub display: Option<AttributeDisplay>,
|
|
744
|
+
/// Format-specific data with no neutral field (e.g. `dgn.color_index`, `dgn.weight`).
|
|
745
|
+
#[serde(default, skip_serializing_if = "Props::is_empty")]
|
|
746
|
+
pub props: Props,
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/// Text presentation of a displayed attribute value.
|
|
750
|
+
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
|
|
751
|
+
pub struct AttributeDisplay {
|
|
752
|
+
/// Text height, in drawing units.
|
|
753
|
+
pub height: f64,
|
|
754
|
+
/// Character width, in drawing units (DGN stores it separately from the height).
|
|
755
|
+
pub width: f64,
|
|
756
|
+
/// Text style (DGN font) name; `None` leaves the choice to the writer's default.
|
|
757
|
+
pub style: Option<String>,
|
|
758
|
+
/// Horizontal alignment of the text about `Attribute::position`.
|
|
759
|
+
pub halign: HAlign,
|
|
760
|
+
/// Vertical alignment of the text about `Attribute::position`.
|
|
761
|
+
pub valign: VAlign,
|
|
762
|
+
/// Rotation about the drawing Z axis, in radians.
|
|
763
|
+
pub rotation: f64,
|
|
737
764
|
}
|
|
738
765
|
|
|
739
766
|
/// A loosely typed value for attributes and props.
|
|
740
|
-
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
767
|
+
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
|
|
741
768
|
#[serde(untagged)]
|
|
742
769
|
pub enum Value {
|
|
743
770
|
/// No value.
|
|
771
|
+
#[default]
|
|
744
772
|
Null,
|
|
745
773
|
/// Boolean.
|
|
746
774
|
Bool(bool),
|
|
@@ -8,8 +8,8 @@ use std::f64::consts::{FRAC_PI_2, TAU};
|
|
|
8
8
|
|
|
9
9
|
use cadkit_core::geom_ops::{arbitrary_axes, clamped_uniform_knots};
|
|
10
10
|
use cadkit_core::{
|
|
11
|
-
Attribute, Color, Entity, EntityKind, GroupKind, HAlign, LengthUnit,
|
|
12
|
-
Point3, Props, Raw, TextStyle, VAlign, Value, Vec3, Vertex, Warning,
|
|
11
|
+
Attribute, AttributeDisplay, Color, Entity, EntityKind, GroupKind, HAlign, LengthUnit,
|
|
12
|
+
Linetype, Lineweight, Point3, Props, Raw, TextStyle, VAlign, Value, Vec3, Vertex, Warning,
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
use crate::native::element::{
|
|
@@ -203,8 +203,6 @@ pub(crate) struct Mapper {
|
|
|
203
203
|
pub(crate) xattributes: HashMap<u64, Vec<u32>>,
|
|
204
204
|
/// Raster frame id -> image path.
|
|
205
205
|
pub(crate) raster_paths: HashMap<u64, (Option<String>, Option<String>)>,
|
|
206
|
-
/// Raster frames whose stored extent corner and file are shared with another frame.
|
|
207
|
-
pub(crate) shared_raster_extent: HashSet<u64>,
|
|
208
206
|
/// Aggregated warnings: code -> (count, first message).
|
|
209
207
|
counts: BTreeMap<String, (u64, String)>,
|
|
210
208
|
pub(crate) warnings: Vec<Warning>,
|
|
@@ -226,7 +224,6 @@ impl Mapper {
|
|
|
226
224
|
attached: HashSet::new(),
|
|
227
225
|
xattributes: HashMap::new(),
|
|
228
226
|
raster_paths: HashMap::new(),
|
|
229
|
-
shared_raster_extent: HashSet::new(),
|
|
230
227
|
counts: BTreeMap::new(),
|
|
231
228
|
warnings: Vec::new(),
|
|
232
229
|
}
|
|
@@ -402,6 +399,14 @@ impl Mapper {
|
|
|
402
399
|
);
|
|
403
400
|
}
|
|
404
401
|
p.insert("dgn.properties".into(), Value::Int(i64::from(h.properties)));
|
|
402
|
+
// Undocumented type-word flags MicroStation sets on its graphics (`0x00C0`);
|
|
403
|
+
// kept so a rewrite reproduces them.
|
|
404
|
+
if h.type_flags & 0x00c0 != 0 {
|
|
405
|
+
p.insert(
|
|
406
|
+
"dgn.type_flags".into(),
|
|
407
|
+
Value::Int(i64::from(h.type_flags & 0x00c0)),
|
|
408
|
+
);
|
|
409
|
+
}
|
|
405
410
|
if h.properties & 0x8000 != 0 && matches!(h.type_code, 6 | 14) {
|
|
406
411
|
p.insert("dgn.hole".into(), Value::Bool(true));
|
|
407
412
|
}
|
|
@@ -441,7 +446,10 @@ impl Mapper {
|
|
|
441
446
|
}
|
|
442
447
|
if let Some(id) = h.id {
|
|
443
448
|
if let Some(attrs) = self.pending_tags.remove(&id) {
|
|
444
|
-
e.attributes = attrs
|
|
449
|
+
e.attributes = attrs
|
|
450
|
+
.into_iter()
|
|
451
|
+
.map(|(_, a)| relative_to_owner(a, &e))
|
|
452
|
+
.collect();
|
|
445
453
|
}
|
|
446
454
|
}
|
|
447
455
|
e
|
|
@@ -561,7 +569,8 @@ impl Mapper {
|
|
|
561
569
|
type_name: "dgn.type_37".into(),
|
|
562
570
|
},
|
|
563
571
|
);
|
|
564
|
-
|
|
572
|
+
let a = self.attribute(t, &item.el.header, xf);
|
|
573
|
+
e.attributes.push(relative_to_owner(a, &e));
|
|
565
574
|
return Some(e);
|
|
566
575
|
}
|
|
567
576
|
ElementData::RasterFrame { .. } => self.image(item, xf),
|
|
@@ -662,7 +671,7 @@ impl Mapper {
|
|
|
662
671
|
e.props.insert("dgn.point_string".into(), Value::Bool(true));
|
|
663
672
|
}
|
|
664
673
|
ElementData::RasterFrame { matrix, .. } => {
|
|
665
|
-
// Pixel-to-UOR matrix as stored; the
|
|
674
|
+
// Pixel-to-UOR matrix as stored; the range only checks the placement.
|
|
666
675
|
if let Some([lo, hi]) = item.el.header.range {
|
|
667
676
|
let (a, b) = (xf.pt(lo), xf.pt(hi));
|
|
668
677
|
e.props.insert(
|
|
@@ -670,19 +679,23 @@ impl Mapper {
|
|
|
670
679
|
Value::List([a.x, a.y, a.z, b.x, b.y, b.z].map(Value::Float).to_vec()),
|
|
671
680
|
);
|
|
672
681
|
}
|
|
673
|
-
if item
|
|
674
|
-
.el
|
|
675
|
-
.header
|
|
676
|
-
.id
|
|
677
|
-
.is_some_and(|id| self.shared_raster_extent.contains(&id))
|
|
678
|
-
{
|
|
679
|
-
e.props
|
|
680
|
-
.insert("dgn.raster_extent_shared".into(), Value::Bool(true));
|
|
681
|
-
}
|
|
682
682
|
e.props.insert(
|
|
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,13 +933,14 @@ 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
|
|
|
928
|
-
/// A tag as an attribute (`position` = origin + offset).
|
|
940
|
+
/// A tag as an attribute (`position` = origin + offset). The tag element's own level,
|
|
941
|
+
/// its text presentation and its symbology are kept so a writer can reproduce it.
|
|
929
942
|
pub(crate) fn attribute(
|
|
930
|
-
&self,
|
|
943
|
+
&mut self,
|
|
931
944
|
t: &TagData,
|
|
932
945
|
h: &crate::native::element::ElementHeader,
|
|
933
946
|
xf: &Xf,
|
|
@@ -937,18 +950,66 @@ impl Mapper {
|
|
|
937
950
|
.or(t.set_number.map(u64::from))
|
|
938
951
|
.and_then(|k| self.tag_sets.get(&k));
|
|
939
952
|
let def = set.and_then(|s| s.tags.iter().find(|d| d.id == t.tag_index));
|
|
953
|
+
let tag = def
|
|
954
|
+
.map(|d| d.name.clone())
|
|
955
|
+
.unwrap_or_else(|| format!("tag_{}", t.tag_index));
|
|
956
|
+
let set_name = set.and_then(|s| s.name.clone());
|
|
940
957
|
let [ox, oy, oz] = t.origin;
|
|
941
958
|
let [dx, dy, dz] = t.offset;
|
|
942
959
|
let has_pos = t.origin != [0.0; 3] || t.offset != [0.0; 3];
|
|
960
|
+
// Observed: hidden tags carry 0x0080 in the property word (FORMAT_NOTES).
|
|
961
|
+
let invisible = h.properties & 0x0080 != 0;
|
|
962
|
+
let mut props = Props::new();
|
|
963
|
+
let mut layer = None;
|
|
964
|
+
if h.has_display_header {
|
|
965
|
+
layer = Some(self.level_name(h.level));
|
|
966
|
+
props.insert("dgn.color_index".into(), Value::Int(i64::from(h.color)));
|
|
967
|
+
props.insert("dgn.weight".into(), Value::Int(i64::from(h.weight)));
|
|
968
|
+
props.insert("dgn.style".into(), Value::Int(i64::from(h.style)));
|
|
969
|
+
if h.graphic_group != 0 {
|
|
970
|
+
props.insert(
|
|
971
|
+
"dgn.graphic_group".into(),
|
|
972
|
+
Value::Int(i64::from(h.graphic_group)),
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
// Only MicroStation's undecoded property bits add anything to `invisible`.
|
|
976
|
+
if h.properties & 0x0600 != 0 {
|
|
977
|
+
props.insert("dgn.properties".into(), Value::Int(i64::from(h.properties)));
|
|
978
|
+
}
|
|
979
|
+
if h.type_flags & 0x00c0 != 0 {
|
|
980
|
+
props.insert(
|
|
981
|
+
"dgn.type_flags".into(),
|
|
982
|
+
Value::Int(i64::from(h.type_flags & 0x00c0)),
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
// V7 tags and hidden V8 tags without a text size have no usable presentation.
|
|
987
|
+
let display = (t.size[1] > 0.0 && t.size[0] > 0.0).then(|| {
|
|
988
|
+
self.used_fonts.insert(t.font);
|
|
989
|
+
props.insert("dgn.font_number".into(), Value::Int(i64::from(t.font)));
|
|
990
|
+
props.insert(
|
|
991
|
+
"dgn.justification".into(),
|
|
992
|
+
Value::Int(i64::from(t.justification)),
|
|
993
|
+
);
|
|
994
|
+
let (halign, valign, _, _) = justification(t.justification);
|
|
995
|
+
AttributeDisplay {
|
|
996
|
+
height: xf.dist(t.size[1]),
|
|
997
|
+
width: xf.dist(t.size[0]),
|
|
998
|
+
style: Some(self.font_style_name(t.font)),
|
|
999
|
+
halign,
|
|
1000
|
+
valign,
|
|
1001
|
+
rotation: tag_rotation(t.quaternion),
|
|
1002
|
+
}
|
|
1003
|
+
});
|
|
943
1004
|
Attribute {
|
|
944
|
-
tag
|
|
945
|
-
.map(|d| d.name.clone())
|
|
946
|
-
.unwrap_or_else(|| format!("tag_{}", t.tag_index)),
|
|
1005
|
+
tag,
|
|
947
1006
|
value: tag_value(&t.value),
|
|
948
|
-
set:
|
|
1007
|
+
set: set_name,
|
|
949
1008
|
position: has_pos.then(|| xf.pt([ox + dx, oy + dy, oz + dz])),
|
|
950
|
-
|
|
951
|
-
|
|
1009
|
+
invisible,
|
|
1010
|
+
layer,
|
|
1011
|
+
display,
|
|
1012
|
+
props,
|
|
952
1013
|
}
|
|
953
1014
|
}
|
|
954
1015
|
}
|
|
@@ -1060,29 +1121,63 @@ fn curve(points: &[UorPoint], xf: &Xf) -> EntityKind {
|
|
|
1060
1121
|
}
|
|
1061
1122
|
}
|
|
1062
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
|
+
|
|
1063
1131
|
/// Raster frame placement from its pixel-to-UOR matrix (row-major, translation in the
|
|
1064
|
-
/// last column)
|
|
1065
|
-
///
|
|
1066
|
-
///
|
|
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.
|
|
1067
1137
|
pub(crate) fn frame_placement(
|
|
1068
1138
|
m: &[f64; 16],
|
|
1069
|
-
|
|
1139
|
+
edges: Option<[f64; 2]>,
|
|
1070
1140
|
) -> Option<(UorPoint, Vec3, Vec3)> {
|
|
1071
|
-
let [
|
|
1072
|
-
let a =
|
|
1073
|
-
let
|
|
1074
|
-
|
|
1075
|
-
let (dx, dy) = (cx - m03, cy - m13);
|
|
1076
|
-
let det = a.x * b.y - a.y * b.x;
|
|
1077
|
-
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) {
|
|
1078
1145
|
return None;
|
|
1079
1146
|
}
|
|
1080
|
-
let
|
|
1081
|
-
|
|
1082
|
-
if
|
|
1147
|
+
let (ua, ub) = (a.normalized()?, b.normalized()?);
|
|
1148
|
+
// Parallel axes span no rectangle.
|
|
1149
|
+
if ua.cross(ub).length() <= 1e-9 {
|
|
1150
|
+
return None;
|
|
1151
|
+
}
|
|
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() {
|
|
1083
1175
|
return None;
|
|
1084
1176
|
}
|
|
1085
|
-
|
|
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))
|
|
1086
1181
|
}
|
|
1087
1182
|
|
|
1088
1183
|
/// Most XAttribute kinds listed on one entity (the count is always complete).
|
|
@@ -1154,6 +1249,28 @@ pub(crate) fn justification(code: u16) -> (HAlign, VAlign, f64, f64) {
|
|
|
1154
1249
|
(h, v, fx, fy)
|
|
1155
1250
|
}
|
|
1156
1251
|
|
|
1252
|
+
/// Keeps only what a tag element does not share with its owner: `layer` stays `None` on the
|
|
1253
|
+
/// owner's level, and symbology/flag props equal to the owner's are dropped.
|
|
1254
|
+
fn relative_to_owner(mut a: Attribute, owner: &Entity) -> Attribute {
|
|
1255
|
+
if a.layer.is_some() && a.layer == owner.layer {
|
|
1256
|
+
a.layer = None;
|
|
1257
|
+
}
|
|
1258
|
+
a.props
|
|
1259
|
+
.retain(|key, value| owner.props.get(key) != Some(value) || key == "dgn.font_number");
|
|
1260
|
+
a
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
/// Rotation of a displayed tag about +Z in radians, from its stored quaternion (same
|
|
1264
|
+
/// convention as text, see [`Rotation::matrix`]). An all-zero quaternion means none.
|
|
1265
|
+
pub(crate) fn tag_rotation(q: [f64; 4]) -> f64 {
|
|
1266
|
+
if q.iter().all(|v| *v == 0.0) {
|
|
1267
|
+
return 0.0;
|
|
1268
|
+
}
|
|
1269
|
+
let [m00, _, _, m10, ..] = Rotation::Quaternion(q).matrix();
|
|
1270
|
+
let a = m10.atan2(m00);
|
|
1271
|
+
if a.abs() < 1e-12 { 0.0 } else { a }
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1157
1274
|
/// Text length in UOR and whether it is estimated (`characters x character width`, the
|
|
1158
1275
|
/// estimate GDAL dgnlib's writer uses for text bounds).
|
|
1159
1276
|
fn text_length(t: &TextData) -> (f64, bool) {
|
|
@@ -1457,25 +1574,46 @@ mod tests {
|
|
|
1457
1574
|
|
|
1458
1575
|
#[test]
|
|
1459
1576
|
fn raster_placement_follows_the_matrix() {
|
|
1460
|
-
// 30 degree rotation, 2 UOR per pixel, translation (100, 50); a 300 x 200 pixel
|
|
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|).
|
|
1461
1579
|
let (s, c) = 30f64.to_radians().sin_cos();
|
|
1462
1580
|
let (a, b) = ([2.0 * c, 2.0 * s], [-2.0 * s, 2.0 * c]);
|
|
1463
1581
|
let m = [
|
|
1464
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,
|
|
1465
1583
|
];
|
|
1466
|
-
let
|
|
1467
|
-
|
|
1468
|
-
50.0 + 300.0 * a[1] + 200.0 * b[1],
|
|
1469
|
-
];
|
|
1470
|
-
let (o, u, v) = frame_placement(&m, Some(corner)).unwrap();
|
|
1584
|
+
let edges = [600.0, 400.0];
|
|
1585
|
+
let (o, u, v) = frame_placement(&m, Some(edges)).unwrap();
|
|
1471
1586
|
assert_eq!(o, [100.0, 50.0, 0.0]);
|
|
1472
1587
|
assert!(close(u.x, 600.0 * c) && close(u.y, 600.0 * s));
|
|
1473
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));
|
|
1474
1592
|
assert!(frame_placement(&m, None).is_none());
|
|
1593
|
+
assert!(frame_placement(&m, Some([0.0, 400.0])).is_none());
|
|
1475
1594
|
let mut flat = m;
|
|
1476
1595
|
flat[1] = flat[0];
|
|
1477
1596
|
flat[5] = flat[4];
|
|
1478
|
-
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()));
|
|
1479
1617
|
}
|
|
1480
1618
|
|
|
1481
1619
|
#[test]
|
|
@@ -203,48 +203,6 @@ fn map_file(file: &V8File, options: &ReadOptions, enc: &'static encoding_rs::Enc
|
|
|
203
203
|
enc,
|
|
204
204
|
options,
|
|
205
205
|
);
|
|
206
|
-
// Frames that store the same extent corner for the same file: their extents are then
|
|
207
|
-
// not image footprints (private sample: 8 frames, one file, one corner).
|
|
208
|
-
m.shared_raster_extent.clear();
|
|
209
|
-
let mut by_extent: HashMap<(i64, i64, Option<String>), Vec<u64>> = HashMap::new();
|
|
210
|
-
for it in &graphic {
|
|
211
|
-
if let (
|
|
212
|
-
ElementData::RasterFrame {
|
|
213
|
-
corner: Some([cx, cy]),
|
|
214
|
-
..
|
|
215
|
-
},
|
|
216
|
-
Some(id),
|
|
217
|
-
) = (&it.el.data, it.el.header.id)
|
|
218
|
-
{
|
|
219
|
-
let file = m
|
|
220
|
-
.raster_paths
|
|
221
|
-
.get(&id)
|
|
222
|
-
.and_then(|(n, f)| f.clone().or_else(|| n.clone()));
|
|
223
|
-
by_extent
|
|
224
|
-
.entry((cx.round() as i64, cy.round() as i64, file))
|
|
225
|
-
.or_default()
|
|
226
|
-
.push(id);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
let shared: Vec<u64> = by_extent
|
|
230
|
-
.into_values()
|
|
231
|
-
.filter(|v| v.len() > 1)
|
|
232
|
-
.flatten()
|
|
233
|
-
.collect();
|
|
234
|
-
if !shared.is_empty() {
|
|
235
|
-
m.warn(
|
|
236
|
-
"dgn.raster_extent_shared",
|
|
237
|
-
format!(
|
|
238
|
-
"{} raster frames share one stored extent corner and file; their \
|
|
239
|
-
rectangles (as stored, equal to the element ranges) are probably not \
|
|
240
|
-
image footprints",
|
|
241
|
-
shared.len()
|
|
242
|
-
),
|
|
243
|
-
None,
|
|
244
|
-
None,
|
|
245
|
-
);
|
|
246
|
-
m.shared_raster_extent.extend(shared);
|
|
247
|
-
}
|
|
248
206
|
m.pending_tags.clear();
|
|
249
207
|
m.attached.clear();
|
|
250
208
|
for (i, it) in graphic.iter().enumerate() {
|