Another project
0

Configure Feed

Select the types of activity you want to include in your feed.

feat(kernel): brep arena builder, truck assembly, deps

Lewis: May this revision serve well! <lu5a@proton.me>

author
Lewis
date (May 28, 2026, 9:22 AM +0300) commit a1577d7f parent c40064c4 change-id snzqvyzz
+671 -13
+330 -12
Cargo.lock
··· 103 103 104 104 [[package]] 105 105 name = "approx" 106 + version = "0.4.0" 107 + source = "registry+https://github.com/rust-lang/crates.io-index" 108 + checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" 109 + dependencies = [ 110 + "num-traits", 111 + ] 112 + 113 + [[package]] 114 + name = "approx" 106 115 version = "0.5.1" 107 116 source = "registry+https://github.com/rust-lang/crates.io-index" 108 117 checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" 109 118 dependencies = [ 110 119 "num-traits", 111 120 ] 121 + 122 + [[package]] 123 + name = "array-macro" 124 + version = "2.1.8" 125 + source = "registry+https://github.com/rust-lang/crates.io-index" 126 + checksum = "220a2c618ab466efe41d0eace94dfeff1c35e3aa47891bdb95e1c0fefffd3c99" 112 127 113 128 [[package]] 114 129 name = "arrayref" ··· 418 433 dependencies = [ 419 434 "bone-types", 420 435 "insta", 436 + "slotmap", 421 437 "thiserror 2.0.18", 438 + "truck-modeling", 422 439 "uom", 423 440 ] 424 441 ··· 497 514 "thiserror 2.0.18", 498 515 "unicode-segmentation", 499 516 "uom", 517 + ] 518 + 519 + [[package]] 520 + name = "branches" 521 + version = "0.3.0" 522 + source = "registry+https://github.com/rust-lang/crates.io-index" 523 + checksum = "f11502672c5570f77f6bdf573332483f8475bab6a7fda00f1fae8ddb5a6245c0" 524 + dependencies = [ 525 + "rustc_version", 500 526 ] 501 527 502 528 [[package]] ··· 594 620 checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 595 621 596 622 [[package]] 623 + name = "cgmath" 624 + version = "0.18.0" 625 + source = "registry+https://github.com/rust-lang/crates.io-index" 626 + checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317" 627 + dependencies = [ 628 + "approx 0.4.0", 629 + "num-traits", 630 + "serde", 631 + ] 632 + 633 + [[package]] 597 634 name = "codespan-reporting" 598 635 version = "0.13.1" 599 636 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 639 676 version = "0.4.2" 640 677 source = "registry+https://github.com/rust-lang/crates.io-index" 641 678 checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" 679 + 680 + [[package]] 681 + name = "convert_case" 682 + version = "0.4.0" 683 + source = "registry+https://github.com/rust-lang/crates.io-index" 684 + checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" 642 685 643 686 [[package]] 644 687 name = "core-foundation" ··· 708 751 ] 709 752 710 753 [[package]] 754 + name = "crossbeam-deque" 755 + version = "0.8.6" 756 + source = "registry+https://github.com/rust-lang/crates.io-index" 757 + checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" 758 + dependencies = [ 759 + "crossbeam-epoch", 760 + "crossbeam-utils", 761 + ] 762 + 763 + [[package]] 764 + name = "crossbeam-epoch" 765 + version = "0.9.18" 766 + source = "registry+https://github.com/rust-lang/crates.io-index" 767 + checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 768 + dependencies = [ 769 + "crossbeam-utils", 770 + ] 771 + 772 + [[package]] 711 773 name = "crossbeam-utils" 712 774 version = "0.8.21" 713 775 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 730 792 version = "0.2.1" 731 793 source = "registry+https://github.com/rust-lang/crates.io-index" 732 794 checksum = "930c7171c8df9fb1782bdf9b918ed9ed2d33d1d22300abb754f9085bc48bf8e8" 795 + 796 + [[package]] 797 + name = "derive_more" 798 + version = "0.99.20" 799 + source = "registry+https://github.com/rust-lang/crates.io-index" 800 + checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" 801 + dependencies = [ 802 + "convert_case", 803 + "proc-macro2", 804 + "quote", 805 + "rustc_version", 806 + "syn 2.0.117", 807 + ] 733 808 734 809 [[package]] 735 810 name = "dispatch" ··· 803 878 version = "0.1.3" 804 879 source = "registry+https://github.com/rust-lang/crates.io-index" 805 880 checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9" 881 + 882 + [[package]] 883 + name = "either" 884 + version = "1.16.0" 885 + source = "registry+https://github.com/rust-lang/crates.io-index" 886 + checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" 806 887 807 888 [[package]] 808 889 name = "encode_unicode" ··· 1265 1346 1266 1347 [[package]] 1267 1348 name = "getrandom" 1349 + version = "0.2.17" 1350 + source = "registry+https://github.com/rust-lang/crates.io-index" 1351 + checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" 1352 + dependencies = [ 1353 + "cfg-if", 1354 + "js-sys", 1355 + "libc", 1356 + "wasi", 1357 + "wasm-bindgen", 1358 + ] 1359 + 1360 + [[package]] 1361 + name = "getrandom" 1268 1362 version = "0.3.4" 1269 1363 source = "registry+https://github.com/rust-lang/crates.io-index" 1270 1364 checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" ··· 1610 1704 ] 1611 1705 1612 1706 [[package]] 1707 + name = "itertools" 1708 + version = "0.13.0" 1709 + source = "registry+https://github.com/rust-lang/crates.io-index" 1710 + checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" 1711 + dependencies = [ 1712 + "either", 1713 + ] 1714 + 1715 + [[package]] 1613 1716 name = "itoa" 1614 1717 version = "1.0.18" 1615 1718 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1696 1799 ] 1697 1800 1698 1801 [[package]] 1802 + name = "katexit" 1803 + version = "0.1.5" 1804 + source = "registry+https://github.com/rust-lang/crates.io-index" 1805 + checksum = "ccfb0b7ce7938f84a5ecbdca5d0a991e46bc9d6d078934ad5e92c5270fe547db" 1806 + dependencies = [ 1807 + "proc-macro2", 1808 + "quote", 1809 + "syn 2.0.117", 1810 + ] 1811 + 1812 + [[package]] 1699 1813 name = "khronos-egl" 1700 1814 version = "6.0.0" 1701 1815 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1845 1959 ] 1846 1960 1847 1961 [[package]] 1962 + name = "matext4cgmath" 1963 + version = "0.1.0" 1964 + source = "registry+https://github.com/rust-lang/crates.io-index" 1965 + checksum = "e6541e181de37f70f0aceb25441823a3d0efa9cc1d23f475a0d3926678949178" 1966 + dependencies = [ 1967 + "cgmath", 1968 + "katexit", 1969 + "num-complex", 1970 + ] 1971 + 1972 + [[package]] 1848 1973 name = "matrixmultiply" 1849 1974 version = "0.3.10" 1850 1975 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1908 2033 "log", 1909 2034 "num-traits", 1910 2035 "once_cell", 1911 - "rustc-hash", 2036 + "rustc-hash 1.1.0", 1912 2037 "spirv", 1913 2038 "thiserror 2.0.18", 1914 2039 "unicode-ident", ··· 1920 2045 source = "registry+https://github.com/rust-lang/crates.io-index" 1921 2046 checksum = "9d43ddcacf343185dfd6de2ee786d9e8b1c2301622afab66b6c73baf9882abfd" 1922 2047 dependencies = [ 1923 - "approx", 2048 + "approx 0.5.1", 1924 2049 "matrixmultiply", 1925 2050 "num-complex", 1926 2051 "num-rational", ··· 2429 2554 source = "registry+https://github.com/rust-lang/crates.io-index" 2430 2555 checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" 2431 2556 dependencies = [ 2432 - "approx", 2557 + "approx 0.5.1", 2433 2558 "fast-srgb8", 2434 2559 "palette_derive", 2435 2560 ] ··· 2675 2800 ] 2676 2801 2677 2802 [[package]] 2803 + name = "proc-macro-error" 2804 + version = "1.0.4" 2805 + source = "registry+https://github.com/rust-lang/crates.io-index" 2806 + checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 2807 + dependencies = [ 2808 + "proc-macro-error-attr", 2809 + "proc-macro2", 2810 + "quote", 2811 + "syn 1.0.109", 2812 + "version_check", 2813 + ] 2814 + 2815 + [[package]] 2816 + name = "proc-macro-error-attr" 2817 + version = "1.0.4" 2818 + source = "registry+https://github.com/rust-lang/crates.io-index" 2819 + checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 2820 + dependencies = [ 2821 + "proc-macro2", 2822 + "quote", 2823 + "version_check", 2824 + ] 2825 + 2826 + [[package]] 2678 2827 name = "proc-macro2" 2679 2828 version = "1.0.106" 2680 2829 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2697 2846 dependencies = [ 2698 2847 "bitflags 2.11.1", 2699 2848 "num-traits", 2700 - "rand", 2701 - "rand_chacha", 2849 + "rand 0.9.4", 2850 + "rand_chacha 0.9.0", 2702 2851 "rand_xorshift", 2703 2852 "regex-syntax", 2704 2853 "unarray", ··· 2771 2920 2772 2921 [[package]] 2773 2922 name = "rand" 2923 + version = "0.8.6" 2924 + source = "registry+https://github.com/rust-lang/crates.io-index" 2925 + checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" 2926 + dependencies = [ 2927 + "libc", 2928 + "rand_chacha 0.3.1", 2929 + "rand_core 0.6.4", 2930 + ] 2931 + 2932 + [[package]] 2933 + name = "rand" 2774 2934 version = "0.9.4" 2775 2935 source = "registry+https://github.com/rust-lang/crates.io-index" 2776 2936 checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" 2777 2937 dependencies = [ 2778 - "rand_chacha", 2779 - "rand_core", 2938 + "rand_chacha 0.9.0", 2939 + "rand_core 0.9.5", 2940 + ] 2941 + 2942 + [[package]] 2943 + name = "rand_chacha" 2944 + version = "0.3.1" 2945 + source = "registry+https://github.com/rust-lang/crates.io-index" 2946 + checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 2947 + dependencies = [ 2948 + "ppv-lite86", 2949 + "rand_core 0.6.4", 2780 2950 ] 2781 2951 2782 2952 [[package]] ··· 2786 2956 checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 2787 2957 dependencies = [ 2788 2958 "ppv-lite86", 2789 - "rand_core", 2959 + "rand_core 0.9.5", 2960 + ] 2961 + 2962 + [[package]] 2963 + name = "rand_core" 2964 + version = "0.6.4" 2965 + source = "registry+https://github.com/rust-lang/crates.io-index" 2966 + checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 2967 + dependencies = [ 2968 + "getrandom 0.2.17", 2790 2969 ] 2791 2970 2792 2971 [[package]] ··· 2804 2983 source = "registry+https://github.com/rust-lang/crates.io-index" 2805 2984 checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" 2806 2985 dependencies = [ 2807 - "rand_core", 2986 + "rand_core 0.9.5", 2808 2987 ] 2809 2988 2810 2989 [[package]] ··· 2847 3026 checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" 2848 3027 2849 3028 [[package]] 3029 + name = "rayon" 3030 + version = "1.12.0" 3031 + source = "registry+https://github.com/rust-lang/crates.io-index" 3032 + checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" 3033 + dependencies = [ 3034 + "either", 3035 + "rayon-core", 3036 + ] 3037 + 3038 + [[package]] 3039 + name = "rayon-core" 3040 + version = "1.13.0" 3041 + source = "registry+https://github.com/rust-lang/crates.io-index" 3042 + checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" 3043 + dependencies = [ 3044 + "crossbeam-deque", 3045 + "crossbeam-utils", 3046 + ] 3047 + 3048 + [[package]] 3049 + name = "rclite" 3050 + version = "0.2.8" 3051 + source = "registry+https://github.com/rust-lang/crates.io-index" 3052 + checksum = "e09665c494a9de2bd230e1aedc0c2fb20481a51f28f7db84d0c9bcfe2fe537b2" 3053 + dependencies = [ 3054 + "branches", 3055 + ] 3056 + 3057 + [[package]] 2850 3058 name = "read-fonts" 2851 3059 version = "0.37.0" 2852 3060 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2944 3152 checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 2945 3153 2946 3154 [[package]] 3155 + name = "rustc-hash" 3156 + version = "2.1.2" 3157 + source = "registry+https://github.com/rust-lang/crates.io-index" 3158 + checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" 3159 + 3160 + [[package]] 2947 3161 name = "rustc_version" 2948 3162 version = "0.4.1" 2949 3163 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3124 3338 source = "registry+https://github.com/rust-lang/crates.io-index" 3125 3339 checksum = "c99284beb21666094ba2b75bbceda012e610f5479dfcc2d6e2426f53197ffd95" 3126 3340 dependencies = [ 3127 - "approx", 3341 + "approx 0.5.1", 3128 3342 "num-complex", 3129 3343 "num-traits", 3130 3344 "paste", ··· 3339 3553 checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" 3340 3554 dependencies = [ 3341 3555 "fastrand", 3342 - "getrandom 0.3.4", 3556 + "getrandom 0.4.2", 3343 3557 "once_cell", 3344 3558 "rustix 1.1.4", 3345 3559 "windows-sys 0.61.2", ··· 3531 3745 ] 3532 3746 3533 3747 [[package]] 3748 + name = "truck-base" 3749 + version = "0.5.0" 3750 + source = "registry+https://github.com/rust-lang/crates.io-index" 3751 + checksum = "4c279de9e92e5dc20a188deb0bb9a4bd421a6a185e57e03e19025e84a36c5a05" 3752 + dependencies = [ 3753 + "cgmath", 3754 + "matext4cgmath", 3755 + "rustc-hash 2.1.2", 3756 + "serde", 3757 + ] 3758 + 3759 + [[package]] 3760 + name = "truck-derivers" 3761 + version = "0.1.0" 3762 + source = "registry+https://github.com/rust-lang/crates.io-index" 3763 + checksum = "421ff1c5a303aed64e295d9b30e8424ee7a2fa251617a59ae4acfd078496009f" 3764 + dependencies = [ 3765 + "proc-macro-error", 3766 + "proc-macro2", 3767 + "quote", 3768 + "syn 2.0.117", 3769 + ] 3770 + 3771 + [[package]] 3772 + name = "truck-geometry" 3773 + version = "0.5.0" 3774 + source = "registry+https://github.com/rust-lang/crates.io-index" 3775 + checksum = "4d9d85f203fdbc2d206a38b8e7c4417a05a2eb589be8b81ecfe9f98faafc425d" 3776 + dependencies = [ 3777 + "serde", 3778 + "thiserror 1.0.69", 3779 + "truck-base", 3780 + "truck-geotrait", 3781 + ] 3782 + 3783 + [[package]] 3784 + name = "truck-geotrait" 3785 + version = "0.4.0" 3786 + source = "registry+https://github.com/rust-lang/crates.io-index" 3787 + checksum = "97a31fe98d5a0589ad20576260e214af23dea21a8d125da81ad3bbcb666f411f" 3788 + dependencies = [ 3789 + "getrandom 0.2.17", 3790 + "rand 0.8.6", 3791 + "thiserror 1.0.69", 3792 + "truck-base", 3793 + "truck-derivers", 3794 + ] 3795 + 3796 + [[package]] 3797 + name = "truck-modeling" 3798 + version = "0.6.0" 3799 + source = "registry+https://github.com/rust-lang/crates.io-index" 3800 + checksum = "8082c2dfac8c2732a014d81807fb5d24dbac0d72ee4de2a705b7fbc05fa05b18" 3801 + dependencies = [ 3802 + "derive_more", 3803 + "rustc-hash 2.1.2", 3804 + "serde", 3805 + "thiserror 1.0.69", 3806 + "truck-base", 3807 + "truck-geometry", 3808 + "truck-geotrait", 3809 + "truck-polymesh", 3810 + "truck-topology", 3811 + ] 3812 + 3813 + [[package]] 3814 + name = "truck-polymesh" 3815 + version = "0.6.0" 3816 + source = "registry+https://github.com/rust-lang/crates.io-index" 3817 + checksum = "b8f22def310af4a89c37beb4839bbf702b302d2c112ea29553759f0e16622fbf" 3818 + dependencies = [ 3819 + "array-macro", 3820 + "bytemuck", 3821 + "itertools", 3822 + "rustc-hash 2.1.2", 3823 + "serde", 3824 + "thiserror 1.0.69", 3825 + "truck-base", 3826 + "truck-geotrait", 3827 + ] 3828 + 3829 + [[package]] 3830 + name = "truck-topology" 3831 + version = "0.6.0" 3832 + source = "registry+https://github.com/rust-lang/crates.io-index" 3833 + checksum = "bf62a1610405c5e39ab5eb6948f326fc1641689734a6b8207a80792133fe0e78" 3834 + dependencies = [ 3835 + "parking_lot", 3836 + "rayon", 3837 + "rclite", 3838 + "rustc-hash 2.1.2", 3839 + "serde", 3840 + "thiserror 1.0.69", 3841 + "truck-base", 3842 + "truck-geotrait", 3843 + ] 3844 + 3845 + [[package]] 3534 3846 name = "ttf-parser" 3535 3847 version = "0.25.1" 3536 3848 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3637 3949 "same-file", 3638 3950 "winapi-util", 3639 3951 ] 3952 + 3953 + [[package]] 3954 + name = "wasi" 3955 + version = "0.11.1+wasi-snapshot-preview1" 3956 + source = "registry+https://github.com/rust-lang/crates.io-index" 3957 + checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 3640 3958 3641 3959 [[package]] 3642 3960 name = "wasip2" ··· 3926 4244 "portable-atomic", 3927 4245 "profiling", 3928 4246 "raw-window-handle", 3929 - "rustc-hash", 4247 + "rustc-hash 1.1.0", 3930 4248 "smallvec", 3931 4249 "thiserror 2.0.18", 3932 4250 "wgpu-core-deps-apple",
+2
crates/bone-kernel/Cargo.toml
··· 7 7 8 8 [dependencies] 9 9 bone-types = { workspace = true } 10 + slotmap = { workspace = true } 10 11 thiserror = { workspace = true } 12 + truck-modeling = "=0.6.0" 11 13 uom = { workspace = true } 12 14 13 15 [dev-dependencies]
+297
crates/bone-kernel/src/brep/build.rs
··· 1 + #![allow( 2 + dead_code, 3 + reason = "facade construction seam exercised only by tests until the extrude evaluator wires the production caller" 4 + )] 5 + 6 + use std::collections::HashMap; 7 + use std::collections::hash_map::Entry; 8 + 9 + use bone_types::{ 10 + BrepEdgeId, BrepFaceId, BrepLoopId, BrepShellId, BrepVertexId, EdgeLabel, FaceLabel, 11 + VertexLabel, 12 + }; 13 + use slotmap::{Key, SlotMap}; 14 + use truck_modeling::{ 15 + BoundedCurve, Edge, EdgeID, FaceID, ParameterDivision1D, Shell, Solid, VertexID, 16 + }; 17 + 18 + use super::{ 19 + BrepEdge, BrepError, BrepFace, BrepLoop, BrepShell, BrepSolid, BrepVertex, LabelKind, TruckGap, 20 + }; 21 + 22 + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] 23 + pub(crate) struct BoundaryIndex(usize); 24 + 25 + #[derive(Clone, Copy, Debug)] 26 + pub(crate) struct EdgeArenaHandle(usize); 27 + 28 + #[derive(Clone)] 29 + pub(crate) struct Arena { 30 + solid: Solid, 31 + edges: Vec<Edge>, 32 + } 33 + 34 + impl Arena { 35 + pub(crate) fn boundary(&self, index: BoundaryIndex) -> &Shell { 36 + &self.solid.boundaries()[index.0] 37 + } 38 + 39 + pub(crate) fn edge(&self, handle: EdgeArenaHandle) -> &Edge { 40 + &self.edges[handle.0] 41 + } 42 + } 43 + 44 + const LENGTH_DIVISION_TOLERANCE: f64 = 1.0e-4; 45 + 46 + pub(crate) fn edge_length(edge: &Edge) -> f64 { 47 + let curve = edge.curve(); 48 + let (_, points) = curve.parameter_division(curve.range_tuple(), LENGTH_DIVISION_TOLERANCE); 49 + points 50 + .windows(2) 51 + .map(|pair| { 52 + let span = pair[1] - pair[0]; 53 + span.x.hypot(span.y).hypot(span.z) 54 + }) 55 + .sum() 56 + } 57 + 58 + pub(crate) struct SolidLabeling { 59 + pub(crate) faces: HashMap<FaceID, FaceLabel>, 60 + pub(crate) edges: HashMap<EdgeID, EdgeLabel>, 61 + pub(crate) vertices: HashMap<VertexID, VertexLabel>, 62 + } 63 + 64 + struct VertexTable { 65 + vertices: SlotMap<BrepVertexId, BrepVertex>, 66 + by_truck: HashMap<VertexID, BrepVertexId>, 67 + } 68 + 69 + struct EdgeTable { 70 + edges: SlotMap<BrepEdgeId, BrepEdge>, 71 + by_truck: HashMap<EdgeID, BrepEdgeId>, 72 + arena: Vec<Edge>, 73 + } 74 + 75 + struct FaceDescription { 76 + label: FaceLabel, 77 + loops: Vec<Vec<BrepEdgeId>>, 78 + } 79 + 80 + struct ShellDescription { 81 + boundary: BoundaryIndex, 82 + faces: Vec<FaceDescription>, 83 + } 84 + 85 + pub(crate) fn assemble(solid: Solid, labeling: &SolidLabeling) -> Result<BrepSolid, BrepError> { 86 + let VertexTable { 87 + vertices, 88 + by_truck: vertex_dedup, 89 + } = build_vertices(&solid, labeling)?; 90 + let EdgeTable { 91 + edges, 92 + by_truck: edge_dedup, 93 + arena: arena_edges, 94 + } = build_edges(&solid, labeling, &vertex_dedup)?; 95 + let described = describe_shells(&solid, labeling, &edge_dedup)?; 96 + let (shells, faces, loops) = mint_topology(described); 97 + 98 + let shell_order = ordered_by(&shells, |shell| shell.boundary_index); 99 + let face_order = ordered_by_label(&faces, BrepFace::label, LabelKind::Face)?; 100 + let edge_order = ordered_by_label(&edges, BrepEdge::label, LabelKind::Edge)?; 101 + let vertex_order = ordered_by_label(&vertices, BrepVertex::label, LabelKind::Vertex)?; 102 + 103 + Ok(BrepSolid { 104 + arena: Arena { 105 + solid, 106 + edges: arena_edges, 107 + }, 108 + shells, 109 + faces, 110 + loops, 111 + edges, 112 + vertices, 113 + shell_order, 114 + face_order, 115 + edge_order, 116 + vertex_order, 117 + }) 118 + } 119 + 120 + fn ordered_by<K: Key, V, T: Ord>(map: &SlotMap<K, V>, key: impl Fn(&V) -> T) -> Vec<K> { 121 + let mut keys: Vec<K> = map.keys().collect(); 122 + keys.sort_by_cached_key(|k| key(&map[*k])); 123 + keys 124 + } 125 + 126 + fn ordered_by_label<K: Key, V, T: Ord>( 127 + map: &SlotMap<K, V>, 128 + label: impl Fn(&V) -> T, 129 + kind: LabelKind, 130 + ) -> Result<Vec<K>, BrepError> { 131 + let order = ordered_by(map, &label); 132 + let unique = order 133 + .windows(2) 134 + .all(|pair| label(&map[pair[0]]) != label(&map[pair[1]])); 135 + if unique { 136 + Ok(order) 137 + } else { 138 + Err(BrepError::DuplicateLabel { kind }) 139 + } 140 + } 141 + 142 + fn build_vertices(solid: &Solid, labeling: &SolidLabeling) -> Result<VertexTable, BrepError> { 143 + solid.vertex_iter().try_fold( 144 + VertexTable { 145 + vertices: SlotMap::with_key(), 146 + by_truck: HashMap::new(), 147 + }, 148 + |mut table, vertex| { 149 + if let Entry::Vacant(slot) = table.by_truck.entry(vertex.id()) { 150 + let label = 151 + *labeling 152 + .vertices 153 + .get(&vertex.id()) 154 + .ok_or(BrepError::TruckUnsupported { 155 + detail: TruckGap::Unlabeled(LabelKind::Vertex), 156 + })?; 157 + let id = table 158 + .vertices 159 + .insert_with_key(|id| BrepVertex { id, label }); 160 + slot.insert(id); 161 + } 162 + Ok(table) 163 + }, 164 + ) 165 + } 166 + 167 + fn build_edges( 168 + solid: &Solid, 169 + labeling: &SolidLabeling, 170 + vertex_dedup: &HashMap<VertexID, BrepVertexId>, 171 + ) -> Result<EdgeTable, BrepError> { 172 + solid.edge_iter().try_fold( 173 + EdgeTable { 174 + edges: SlotMap::with_key(), 175 + by_truck: HashMap::new(), 176 + arena: Vec::new(), 177 + }, 178 + |mut table, edge| { 179 + if let Entry::Vacant(slot) = table.by_truck.entry(edge.id()) { 180 + let label = *labeling 181 + .edges 182 + .get(&edge.id()) 183 + .ok_or(BrepError::TruckUnsupported { 184 + detail: TruckGap::Unlabeled(LabelKind::Edge), 185 + })?; 186 + let front = 187 + *vertex_dedup 188 + .get(&edge.front().id()) 189 + .ok_or(BrepError::TruckUnsupported { 190 + detail: TruckGap::Unlabeled(LabelKind::Vertex), 191 + })?; 192 + let back = 193 + *vertex_dedup 194 + .get(&edge.back().id()) 195 + .ok_or(BrepError::TruckUnsupported { 196 + detail: TruckGap::Unlabeled(LabelKind::Vertex), 197 + })?; 198 + let handle = EdgeArenaHandle(table.arena.len()); 199 + table.arena.push(edge.clone()); 200 + let id = table.edges.insert_with_key(|id| BrepEdge { 201 + id, 202 + label, 203 + handle, 204 + vertices: [front, back], 205 + }); 206 + slot.insert(id); 207 + } 208 + Ok(table) 209 + }, 210 + ) 211 + } 212 + 213 + fn describe_shells( 214 + solid: &Solid, 215 + labeling: &SolidLabeling, 216 + edge_dedup: &HashMap<EdgeID, BrepEdgeId>, 217 + ) -> Result<Vec<ShellDescription>, BrepError> { 218 + solid 219 + .boundaries() 220 + .iter() 221 + .enumerate() 222 + .map(|(boundary_index, shell)| { 223 + let faces = shell 224 + .face_iter() 225 + .map(|face| { 226 + let label = 227 + *labeling 228 + .faces 229 + .get(&face.id()) 230 + .ok_or(BrepError::TruckUnsupported { 231 + detail: TruckGap::Unlabeled(LabelKind::Face), 232 + })?; 233 + let loops = face 234 + .boundaries() 235 + .iter() 236 + .map(|wire| { 237 + wire.edge_iter() 238 + .map(|edge| { 239 + edge_dedup.get(&edge.id()).copied().ok_or( 240 + BrepError::TruckUnsupported { 241 + detail: TruckGap::Unlabeled(LabelKind::Edge), 242 + }, 243 + ) 244 + }) 245 + .collect::<Result<Vec<_>, _>>() 246 + }) 247 + .collect::<Result<Vec<_>, _>>()?; 248 + Ok(FaceDescription { label, loops }) 249 + }) 250 + .collect::<Result<Vec<_>, _>>()?; 251 + Ok(ShellDescription { 252 + boundary: BoundaryIndex(boundary_index), 253 + faces, 254 + }) 255 + }) 256 + .collect() 257 + } 258 + 259 + fn mint_topology( 260 + described: Vec<ShellDescription>, 261 + ) -> ( 262 + SlotMap<BrepShellId, BrepShell>, 263 + SlotMap<BrepFaceId, BrepFace>, 264 + SlotMap<BrepLoopId, BrepLoop>, 265 + ) { 266 + described.into_iter().fold( 267 + ( 268 + SlotMap::with_key(), 269 + SlotMap::with_key(), 270 + SlotMap::with_key(), 271 + ), 272 + |(mut shells, mut faces, mut loops), shell_desc| { 273 + let face_ids = shell_desc 274 + .faces 275 + .into_iter() 276 + .map(|face_desc| { 277 + let loop_ids = face_desc 278 + .loops 279 + .into_iter() 280 + .map(|edges| loops.insert_with_key(|id| BrepLoop { id, edges })) 281 + .collect(); 282 + faces.insert_with_key(|id| BrepFace { 283 + id, 284 + label: face_desc.label, 285 + loops: loop_ids, 286 + }) 287 + }) 288 + .collect(); 289 + shells.insert_with_key(|id| BrepShell { 290 + id, 291 + boundary_index: shell_desc.boundary, 292 + faces: face_ids, 293 + }); 294 + (shells, faces, loops) 295 + }, 296 + ) 297 + }
+35
crates/bone-kernel/src/brep/snapshots/bone_kernel__brep__tests__unit_cube_iteration_is_label_ordered.snap
··· 1 + --- 2 + source: crates/bone-kernel/src/brep/mod.rs 3 + expression: "format!(\"shells:\\n{shells}\\nfaces:\\n{faces}\\nedges:\\n{edges}\\nvertices:\\n{vertices}\")" 4 + --- 5 + shells: 6 + shell faces=6 7 + faces: 8 + face[FeatureId(1v1)]:start_cap 9 + face[FeatureId(1v1)]:side(loop#0, from=SketchEntityId(1v1)) 10 + face[FeatureId(1v1)]:side(loop#0, from=SketchEntityId(2v1)) 11 + face[FeatureId(1v1)]:side(loop#0, from=SketchEntityId(3v1)) 12 + face[FeatureId(1v1)]:side(loop#0, from=SketchEntityId(4v1)) 13 + face[FeatureId(1v1)]:end_cap 14 + edges: 15 + edge[FeatureId(1v1)]:start_cap_edge(from=SketchEntityId(1v1)) 16 + edge[FeatureId(1v1)]:start_cap_edge(from=SketchEntityId(2v1)) 17 + edge[FeatureId(1v1)]:start_cap_edge(from=SketchEntityId(3v1)) 18 + edge[FeatureId(1v1)]:start_cap_edge(from=SketchEntityId(4v1)) 19 + edge[FeatureId(1v1)]:side_edge(corner, from=SketchEntityId(5v1)) 20 + edge[FeatureId(1v1)]:side_edge(corner, from=SketchEntityId(6v1)) 21 + edge[FeatureId(1v1)]:side_edge(corner, from=SketchEntityId(7v1)) 22 + edge[FeatureId(1v1)]:side_edge(corner, from=SketchEntityId(8v1)) 23 + edge[FeatureId(1v1)]:end_cap_edge(from=SketchEntityId(1v1)) 24 + edge[FeatureId(1v1)]:end_cap_edge(from=SketchEntityId(2v1)) 25 + edge[FeatureId(1v1)]:end_cap_edge(from=SketchEntityId(3v1)) 26 + edge[FeatureId(1v1)]:end_cap_edge(from=SketchEntityId(4v1)) 27 + vertices: 28 + vertex[FeatureId(1v1)]:start_cap_vertex(corner, from=SketchEntityId(5v1)) 29 + vertex[FeatureId(1v1)]:start_cap_vertex(corner, from=SketchEntityId(6v1)) 30 + vertex[FeatureId(1v1)]:start_cap_vertex(corner, from=SketchEntityId(7v1)) 31 + vertex[FeatureId(1v1)]:start_cap_vertex(corner, from=SketchEntityId(8v1)) 32 + vertex[FeatureId(1v1)]:end_cap_vertex(corner, from=SketchEntityId(5v1)) 33 + vertex[FeatureId(1v1)]:end_cap_vertex(corner, from=SketchEntityId(6v1)) 34 + vertex[FeatureId(1v1)]:end_cap_vertex(corner, from=SketchEntityId(7v1)) 35 + vertex[FeatureId(1v1)]:end_cap_vertex(corner, from=SketchEntityId(8v1))
+4
crates/bone-kernel/src/lib.rs
··· 2 2 mod angles; 3 3 pub mod arc2; 4 4 pub mod arc3; 5 + pub mod brep; 5 6 pub mod circle2; 6 7 pub mod circle3; 7 8 mod circular3; ··· 22 23 pub use aabb::Aabb2; 23 24 pub use arc2::{Arc2, arc_bounding_box}; 24 25 pub use arc3::Arc3; 26 + pub use brep::{ 27 + BrepEdge, BrepError, BrepFace, BrepLoop, BrepShell, BrepSolid, BrepVertex, LabelKind, TruckGap, 28 + }; 25 29 pub use circle2::Circle2; 26 30 pub use circle3::Circle3; 27 31 pub use closest::{ClosestPoint, ClosestPoint2, ClosestPoint3};
+3 -1
crates/bone-kernel/tests/surfaces3.rs
··· 210 210 assert!(CylinderSurface::new(plane, mm(f64::NAN), rad(0.0), rad(PI), mm(1.0), TOL).is_err()); 211 211 assert!(CylinderSurface::new(plane, mm(1.0), rad(0.0), rad(PI), mm(f64::NAN), TOL).is_err()); 212 212 assert!(CylinderSurface::new(plane, mm(1.0), rad(0.0), rad(f64::NAN), mm(1.0), TOL).is_err()); 213 - assert!(CylinderSurface::new(plane, mm(1.0), rad(0.0), rad(f64::INFINITY), mm(1.0), TOL).is_err()); 213 + assert!( 214 + CylinderSurface::new(plane, mm(1.0), rad(0.0), rad(f64::INFINITY), mm(1.0), TOL).is_err() 215 + ); 214 216 } 215 217 216 218 #[test]