Compare commits
1453 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9a13e4de5c | |||
| 424b2589d9 | |||
| 05f6ed1084 | |||
| 9ec80cee0d | |||
| a5daf4177a | |||
| 1b1eccb0c1 | |||
| ece9e5c834 | |||
| 6005ff641b | |||
| fa603244b9 | |||
| 6d6010be3b | |||
| 3691052f06 | |||
| e38eafd034 | |||
| 976eeaef20 | |||
| 09da42d649 | |||
| 97b23a9ac6 | |||
| 5e8a57f089 | |||
| 7f34d18bbf | |||
| 97cc19ed43 | |||
| d49faf7412 | |||
| fcaac6bd98 | |||
| c35cdcfcad | |||
| 205da63d8e | |||
| 3f529ae21b | |||
| 89f7105e9c | |||
| e5dd06c461 | |||
| ec7af4e719 | |||
| a755ec99f9 | |||
| 812389bce2 | |||
| b67b5e8d9f | |||
| e2a06e10b6 | |||
| 7fa26b2d60 | |||
| cdd332d1ee | |||
| 22f21a3f0b | |||
| ee27bc3b74 | |||
| 8307bf5877 | |||
| 09e473a0dc | |||
| abeefeeee7 | |||
| d949180461 | |||
| 708bd3207e | |||
| 68d9d04e5b | |||
| 7c7bd3dc53 | |||
| 24d2b59a2e | |||
| ac2684af8d | |||
| 8291a0ca6a | |||
| b72b23741e | |||
| 858692f3f5 | |||
| c74bfa24d2 | |||
| 66c29f0da1 | |||
| f20fd3357f | |||
| e4eb76d4e0 | |||
| 22c95828ce | |||
| e87ca960e8 | |||
| 6881e7d220 | |||
| 28b54c869a | |||
| 9596117953 | |||
| 8dbeb928e3 | |||
| 4fdb78aebc | |||
| 01724913e1 | |||
| 44dd07547e | |||
| cc157239a2 | |||
| 0576914e07 | |||
| a064173ffe | |||
| 8e502c9bb7 | |||
| 4d23706145 | |||
| 6e8de292c6 | |||
| d209cc9ff4 | |||
| ddfaf3308b | |||
| 301ddab1ee | |||
| 1160d20d33 | |||
| 28099ddc8f | |||
| c1bca22638 | |||
| 3d5d868812 | |||
| b015647543 | |||
| c54f2131af | |||
| 2a832202fa | |||
| a3d970e014 | |||
| 24912bb827 | |||
| 1cd0bc9e7d | |||
| 8880ab0fe9 | |||
| 1c052d1417 | |||
| 20cb6ab007 | |||
| e854447714 | |||
| 7f394a5807 | |||
| c80b437682 | |||
| b793ab63cc | |||
| 8c28f52e6a | |||
| 9d71b7483f | |||
| e6e71adba7 | |||
| 7ab8a5921b | |||
| d68d4d54a9 | |||
| bce0f0d8d4 | |||
| 50648fd350 | |||
| b7e26bacea | |||
| a2fdd93e6b | |||
| aef00a4dfc | |||
| efae8ebdcd | |||
| 61403fcf42 | |||
| badee8fdc5 | |||
| 36e779e32f | |||
| c50ac3db4f | |||
| b17c261344 | |||
| 956aae37a8 | |||
| 48d6cc8a28 | |||
| cf9d3026f4 | |||
| e2f0b1ed5c | |||
| b833cffbd3 | |||
| 7a7c89e475 | |||
| 01b0164e0d | |||
| 13f26d9b70 | |||
| 8a88b0b3a1 | |||
| a15e293db5 | |||
| 9509f07da8 | |||
| 37b15de3e4 | |||
| 66b4509b06 | |||
| 41dcb83bdb | |||
| 0bda41710c | |||
| cbd85fafda | |||
| dc7ebab0d1 | |||
| 0c2a3ff400 | |||
| 6af6fda799 | |||
| 2c9e443425 | |||
| 2bede1cdf0 | |||
| 4f3397a04e | |||
| 9b8adad8c8 | |||
| c48bccf727 | |||
| 5d41336342 | |||
| b8628cc9df | |||
| 519cb86163 | |||
| 0008d8bd2a | |||
| bc7946091a | |||
| ac2db7b4c9 | |||
| 0b57d5fc5f | |||
| 82af25d09a | |||
| 4a82525bdb | |||
| 002112dd50 | |||
| 844a9842cf | |||
| 3a098e55c4 | |||
| e186b81f0c | |||
| 527d16c5f0 | |||
| 8c1b33e1d5 | |||
| e46f18f686 | |||
| 931fd9cc9f | |||
| aebc073416 | |||
| 56e00d059b | |||
| 8a6b4aa5fb | |||
| 46bee8aed9 | |||
| eaa2aa05a4 | |||
| abfa6edc5c | |||
| e3a1c29593 | |||
| e6691989dc | |||
| 83845bdd6d | |||
| 0f4c19fd2d | |||
| ce8bdffe57 | |||
| 53e052eb77 | |||
| f21b472cfe | |||
| 324b440f5c | |||
| 37a7049a61 | |||
| 1c1035e251 | |||
| d83924b73e | |||
| a04542dfd1 | |||
| 066616707a | |||
| c1cd228911 | |||
| 515830e52d | |||
| a971860094 | |||
| f872906e0c | |||
| 0597100356 | |||
| d5feaaa1af | |||
| caca209c8f | |||
| 2e45d4a57e | |||
| 0d8c86a0f6 | |||
| 7f0df72fec | |||
| 863a8248af | |||
| bdc991856c | |||
| 1a38b7f5c6 | |||
| 91199308a9 | |||
| 1f7930c5c8 | |||
| 54c7f355ff | |||
| 551f3b0d8d | |||
| 049c796629 | |||
| 412700c8fd | |||
| 96a8c1e8ae | |||
| 602e18a262 | |||
| 9e30e1ad31 | |||
| b6f939f1b1 | |||
| d964f924d7 | |||
| 36b702630d | |||
| ccf70c7aad | |||
| a2ff63f9ec | |||
| a82b0f30b0 | |||
| bc2fd232d0 | |||
| 5d7b6ad998 | |||
| 0e0678b926 | |||
| 1d4dfd0eb3 | |||
| 65179db444 | |||
| 5457ee3a40 | |||
| 4f3ba7ae22 | |||
| a33a1700dc | |||
| 8a48769760 | |||
| 7e55872ca8 | |||
| edbe1d80bf | |||
| bd093303c4 | |||
| c5c7363a93 | |||
| 5014fef129 | |||
| d710a01df5 | |||
| 23c65742e1 | |||
| d8f52afa6c | |||
| 29ce8d5d80 | |||
| 5e5de0bbd8 | |||
| b9b58f5726 | |||
| 5c7271ddc8 | |||
| 2db35556e9 | |||
| 2449656311 | |||
| c66cf0a22b | |||
| e1a1ba62c5 | |||
| 6489f4dc1d | |||
| beab99bb0d | |||
| 8b50f1bcd6 | |||
| 4617834578 | |||
| 426dcbee43 | |||
| 2a12151c07 | |||
| c08958c1bd | |||
| e355a33d48 | |||
| ece9e2fdd1 | |||
| c0d84713bc | |||
| ca9f165b6a | |||
| 8f9c97a663 | |||
| 4ed8310b93 | |||
| 31be899dc9 | |||
| 4463dd8af9 | |||
| 95c0ac901f | |||
| 6d7a6eeda7 | |||
| c520e0eeb5 | |||
| 73817acdff | |||
| 3d7e8d7c6c | |||
| a701840826 | |||
| 5de2ac9042 | |||
| 573e2626ad | |||
| 9de59afd49 | |||
| 74a9671075 | |||
| 799658ff41 | |||
| bd64f42a54 | |||
| 8eab7f155e | |||
| 5351966430 | |||
| 2663c079f4 | |||
| 6747bd9c8f | |||
| 6ece295be4 | |||
| 64a9f85f25 | |||
| d8fa853308 | |||
| ce37c49624 | |||
| 0da3270c7f | |||
| fda6fc6c48 | |||
| 3865f01df9 | |||
| 6bf61d7163 | |||
| b8ad73668f | |||
| b7a3dd4164 | |||
| 566fd443db | |||
| 51b5a507cf | |||
| a44357dad5 | |||
| 8e792ebb50 | |||
| 352321364c | |||
| 2ab32e41b2 | |||
| 3fbd9d7cdf | |||
| 7a7fde0a2a | |||
| 7992bd9902 | |||
| 3182fe9c15 | |||
| e8858aeeb3 | |||
| ec79d61095 | |||
| 266236ee49 | |||
| 192e4e43a4 | |||
| b22c92e951 | |||
| 7634e71434 | |||
| dda803df2e | |||
| c3ded31a6a | |||
| f2d19ab2c3 | |||
| ab80400e16 | |||
| c88496c6a6 | |||
| 0ee07fb8cc | |||
| 36cf458498 | |||
| e7c25bf99f | |||
| 50a3c8c2f3 | |||
| f18298d1fd | |||
| d4770bdee3 | |||
| 1fb107c361 | |||
| 0fa1e2d585 | |||
| dc13f4c5cc | |||
| d197c3f49a | |||
| c05200a5c6 | |||
| 235bb198da | |||
| 40f332d674 | |||
| e8a272dc97 | |||
| 0b308770a6 | |||
| 96c8323a06 | |||
| 25573cd0e0 | |||
| ff3c7786f6 | |||
| 5f4dfcf215 | |||
| 9a89555a53 | |||
| fc69a2acbe | |||
| 85a2a5ad12 | |||
| 49c3d28a0b | |||
| a8f20b2c6b | |||
| 66fa1cedd9 | |||
| eb971d3d73 | |||
| a30a796c07 | |||
| 9e46bacc12 | |||
| b33378e135 | |||
| d42e19f491 | |||
| 2597827ab3 | |||
| 3f71efea6d | |||
| 2d279b7a7f | |||
| e5fe039fd0 | |||
| 9e14829cc1 | |||
| e867602d9d | |||
| aecc3d56b8 | |||
| e3f5d3d2b7 | |||
| 65f8b1a532 | |||
| 96b4df10ba | |||
| 98b56aea42 | |||
| ba6ba29da8 | |||
| 1112b102f7 | |||
| 04b8172ea9 | |||
| f5f3edbc79 | |||
| 30029e3dc7 | |||
| ed836f5b4a | |||
| a88b708442 | |||
| 764c3bbb85 | |||
| 382d3f1f9f | |||
| c92f607a15 | |||
| b57b7080fd | |||
| 860ff4e513 | |||
| 3546f13593 | |||
| 663966e08d | |||
| f077ebdc81 | |||
| eb888fd116 | |||
| 40b6b3bf17 | |||
| 2ef2f923d0 | |||
| 75fab58831 | |||
| ce26c6e19b | |||
| 8728fa38b9 | |||
| 3037795199 | |||
| 39ee9cd8b1 | |||
| b375bbf558 | |||
| f2cae79dea | |||
| aadc77f6b6 | |||
| 35223d968c | |||
| e106dc4502 | |||
| 2995b73c2d | |||
| 770bc6ea61 | |||
| f5736a7144 | |||
| b4120b1cab | |||
| f44ca67ab9 | |||
| 77eae1c8e8 | |||
| 02d79f0687 | |||
| 83d364574a | |||
| 688d2b7bd1 | |||
| bf35239979 | |||
| ca8e014647 | |||
| b5f63ec4f3 | |||
| aec2141128 | |||
| 778344c804 | |||
| 3ede9b254f | |||
| 8df40dc4a6 | |||
| 75dd4f3132 | |||
| be11df3dc1 | |||
| 09ac212aa9 | |||
| e159151b44 | |||
| 27f6ac0575 | |||
| f840da3ffd | |||
| 034df852b2 | |||
| f242071ebb | |||
| b6663e9189 | |||
| 39d143668c | |||
| 6ea1e378c5 | |||
| a33f30e8ce | |||
| e79fb2ff0b | |||
| 054b4d0ee2 | |||
| 43bebf4eee | |||
| 532869a48a | |||
| 6569d0031f | |||
| bfaa61e592 | |||
| 1a09ce40e9 | |||
| 6f1b40fc86 | |||
| 734eec7715 | |||
| bfabc0db0f | |||
| e71aac84dc | |||
| c156100be2 | |||
| 48c2b43a58 | |||
| 2f8cfb5a95 | |||
| 1c4cc34c1b | |||
| b81e03d9c2 | |||
| eb96858460 | |||
| 5c7e70e987 | |||
| 9093c9d419 | |||
| 02a5b8d997 | |||
| f1b5f7d558 | |||
| 742a9ecd81 | |||
| 77a497cdf7 | |||
| 00576ef574 | |||
| c26caaa58d | |||
| b260bd3877 | |||
| cd6246c382 | |||
| a96d6dacc7 | |||
| 64c711a02a | |||
| 68a2480a66 | |||
| d5e2fd5d3c | |||
| bb445663f8 | |||
| 1f7db75572 | |||
| f478ec8d6b | |||
| cf3ba334b7 | |||
| c36af110c4 | |||
| 91eac7085b | |||
| 239d1d6fd2 | |||
| 831709d514 | |||
| 5925476ed9 | |||
| 3edb3c8df3 | |||
| 72badd8427 | |||
| ff251b7a6a | |||
| dbce57ffc5 | |||
| 8ff9bcef32 | |||
| 82b2006686 | |||
| ca4181c714 | |||
| 3928dd7c9c | |||
| 925964ee2a | |||
| 7201df8d22 | |||
| 7b65108a76 | |||
| 0fbe4d80c7 | |||
| 54c689d615 | |||
| ab828b1a8b | |||
| 8ddd349f8b | |||
| 3221219f4a | |||
| 36387f348e | |||
| c39c6d81e3 | |||
| e8042de1ed | |||
| 78fd999c53 | |||
| 91d1cb79c2 | |||
| 832618b84a | |||
| e4ce53d548 | |||
| 7b92b5c7e2 | |||
| c8c08439b2 | |||
| 3476ee8fd5 | |||
| d2f331c813 | |||
| 9e9b294f44 | |||
| f824ee8ca4 | |||
| 919f673108 | |||
| b034b40b09 | |||
| 34f038530f | |||
| 1c70990b06 | |||
| 07eecad433 | |||
| ef87f0fe74 | |||
| 23c2d73e8e | |||
| 0b47fb5987 | |||
| 8a1dee532b | |||
| f0c6c4ca59 | |||
| 92cf0d9265 | |||
| 7c438b6b9b | |||
| 46454c5c94 | |||
| 73aeafb063 | |||
| e06297940f | |||
| 1652629332 | |||
| 3d8de40407 | |||
| 308457300e | |||
| 6ef96841ac | |||
| 289b2d1e9d | |||
| 96db699ad2 | |||
| 6b7eec0db6 | |||
| 80f35d0bda | |||
| df390a655d | |||
| 593fca7c3d | |||
| 9335c8a0c8 | |||
| eccc21277d | |||
| 2ce7e16537 | |||
| 49835ee303 | |||
| f5500da0af | |||
| c9552fac29 | |||
| b11b3b7fa8 | |||
| 8aecee5836 | |||
| 2f3b3011ec | |||
| 491c9203b0 | |||
| 7f2b996d23 | |||
| d2ea6f6656 | |||
| 25128e8aa8 | |||
| 30fa917e69 | |||
| 40e494996d | |||
| cfdc54064e | |||
| 6daead6b61 | |||
| 241d52f0ad | |||
| 68dd93da1d | |||
| 82703670f0 | |||
| cb8462a0d0 | |||
| 000245c26c | |||
| d97ee8eed4 | |||
| f8af28f12a | |||
| f6fab30d0a | |||
| f1a4ed702b | |||
| c4080626df | |||
| a8078e38d2 | |||
| c52fe8abf9 | |||
| b310b5aaba | |||
| 7246e75085 | |||
| 48c0378bff | |||
| 91c90e7b86 | |||
| 72abdb0569 | |||
| 7947ba4aaf | |||
| 2520a93055 | |||
| fa480d99a2 | |||
| 72c057e7a0 | |||
| 61cfb361fa | |||
| 3786cfa666 | |||
| cabc06821f | |||
| f9fef4f5f6 | |||
| 7c89d072e2 | |||
| dbb9e8c907 | |||
| 2df5b4c70e | |||
| a5aa608240 | |||
| f7454366cc | |||
| f773480917 | |||
| 89f9cd0403 | |||
| b21159c6b3 | |||
| 227f556669 | |||
| 42bd69929c | |||
| a3532b24b3 | |||
| 5486c4c8e9 | |||
| 0259d4c0cd | |||
| 66c4c61dc2 | |||
| 0f32ffe232 | |||
| 72630de77a | |||
| 9395bed72b | |||
| 507a5cab83 | |||
| a46a60996d | |||
| 3106168889 | |||
| 7e0c0c5c83 | |||
| 19205c8774 | |||
| 62b5f1d728 | |||
| 299df62758 | |||
| e58bfde500 | |||
| b60306cdbd | |||
| 61e0549e65 | |||
| 52ae759218 | |||
| 9b41614eff | |||
| 58e01751c1 | |||
| 624134d033 | |||
| 22f83b68e4 | |||
| 1b35ea122e | |||
| f1deefbcb3 | |||
| d6c020b5ee | |||
| ff4eddf38a | |||
| 2b34dc4ce7 | |||
| 530260ebe7 | |||
| 594268c860 | |||
| e5fa8a01b4 | |||
| ad934cd9a6 | |||
| 92fe325816 | |||
| 818bb9c823 | |||
| d71fad988d | |||
| ff0d6c810f | |||
| 8b72929d22 | |||
| 6452872e83 | |||
| 88d2c61453 | |||
| f777be6403 | |||
| 9aad249586 | |||
| 7168f8eeff | |||
| da306c6141 | |||
| e53c0b74b1 | |||
| cb2f58ba0f | |||
| c0c7727f36 | |||
| 60526e62b4 | |||
| 496e58418a | |||
| b976ad3880 | |||
| 31a763fe12 | |||
| 93ef2d0349 | |||
| 7828508179 | |||
| 7aa6be8e8a | |||
| 0679956add | |||
| b86f924543 | |||
| 962b8fac67 | |||
| fdcb705551 | |||
| b80ca3c167 | |||
| e8bd272189 | |||
| 25bd94e84a | |||
| 5face7170f | |||
| 434a11a502 | |||
| eb91f5179b | |||
| c6643da4ba | |||
| 18c93a13ec | |||
| 7cb582de5d | |||
| a5bb458d3d | |||
| c7f6a5e621 | |||
| 141e0240d4 | |||
| 15cd2b6075 | |||
| fab8b5b702 | |||
| 844f4c4944 | |||
| 03809b3d5e | |||
| 3e268be5c7 | |||
| 6e932ec2fb | |||
| 58414777be | |||
| 14f1acadb7 | |||
| f215670381 | |||
| 11df5065e4 | |||
| ed47b6b227 | |||
| 6216ee9a98 | |||
| 848d6b294e | |||
| 795a372ac9 | |||
| 03a6ee9121 | |||
| 5299a9d8a2 | |||
| a5d5d72064 | |||
| b6f2a76385 | |||
| ea6c8fe2f8 | |||
| c7268b6f42 | |||
| 5937ed4b63 | |||
| 8f650c56e5 | |||
| 1d972a6a6f | |||
| 70a1d7d345 | |||
| 519d59effe | |||
| 7f5f67b131 | |||
| 8c64d9ddcc | |||
| 397f333db0 | |||
| b01bd8afb3 | |||
| 1dd8624825 | |||
| bc0c2e641b | |||
| f5f68ea150 | |||
| 76ce117b46 | |||
| 52cad9d11c | |||
| 58af81e256 | |||
| fc2da4ee8f | |||
| c04fa12051 | |||
| 623d2b5be1 | |||
| 46319634fb | |||
| 91d2e5ccd1 | |||
| d23e32c64a | |||
| 764efa1fed | |||
| b051adcc6c | |||
| b815719477 | |||
| 0612d2b615 | |||
| 0da210b732 | |||
| 9429e478fe | |||
| 2f6c50d9c2 | |||
| 640341715c | |||
| 42878e325e | |||
| ac5cf95f9e | |||
| c9189055c7 | |||
| 6a08993f5e | |||
| df2a50b335 | |||
| c7543ff48d | |||
| 1f75fa09ae | |||
| 94ce8e2c9c | |||
| 85e94d2cfc | |||
| c2b332da48 | |||
| 6ee4edd0a0 | |||
| 0d757027e3 | |||
| 9ffe56e64d | |||
| 37a9a1b5d9 | |||
| c30c9d50c9 | |||
| 8e64b55290 | |||
| b45001a95a | |||
| fd65009f5a | |||
| 52036e9bd4 | |||
| 5399767898 | |||
| f96d477d2b | |||
| d5f3991d06 | |||
| 2f2e81f585 | |||
| 0b7442b288 | |||
| 229c7285c2 | |||
| 4fb99d2eed | |||
| 123557939f | |||
| 3c396d3180 | |||
| 5d39603308 | |||
| b792673f88 | |||
| cf65612a96 | |||
| 50bbe849ff | |||
| dc438b2560 | |||
| 6750dd927c | |||
| 9fb1986cad | |||
| 60f8d30fc1 | |||
| 67be2e8ce8 | |||
| 2557580500 | |||
| c0d2ac6ff9 | |||
| 52c168051e | |||
| e072da8d65 | |||
| 8a63275db0 | |||
| 69be3a005c | |||
| ad9ad3f060 | |||
| f0e5304b8e | |||
| c6454803ee | |||
| e8aa8c44e5 | |||
| 48b237ab54 | |||
| 608b3e5401 | |||
| c5d38227fc | |||
| e98ff136c2 | |||
| 02ebc80525 | |||
| 66431158b5 | |||
| dd044c8516 | |||
| 55763ea7df | |||
| 8fe92e810f | |||
| c26988b292 | |||
| 46e70c92c5 | |||
| 325c3665d9 | |||
| 9a80dc14e9 | |||
| 6bda066e1b | |||
| 912b01587b | |||
| 5d4d953320 | |||
| 11ed8cc787 | |||
| d1a7b99eda | |||
| 85bdeaeef4 | |||
| a5f0de4d19 | |||
| cb3392ec70 | |||
| 1dbe42061d | |||
| a024d5c07f | |||
| ea5e3c30b6 | |||
| ebfc8ef619 | |||
| c0d8467154 | |||
| d0adbab9c2 | |||
| 8e80f456cb | |||
| 61bd98e7db | |||
| 4bf0d9ccff | |||
| 1e36ac8740 | |||
| af864e8556 | |||
| 8cd9fb9015 | |||
| d9fdc0908a | |||
| a218ce5160 | |||
| b3a6b8e07f | |||
| 52700452d9 | |||
| aab011f7bf | |||
| 5f129e2357 | |||
| 4e76f36af1 | |||
| 6f3ff51d91 | |||
| 0de0422c2e | |||
| 98de86e0ba | |||
| 142e41b3ad | |||
| 1e0dc7749d | |||
| 0f29de0391 | |||
| 9933cc1b20 | |||
| fa6192e9bc | |||
| bfd4559da8 | |||
| 01f52e069e | |||
| 2fbc9e4424 | |||
| ba97da20eb | |||
| 44f5be142f | |||
| 2f951d352b | |||
| 8b23c615c3 | |||
| 7c694e5b3e | |||
| 8eeb212003 | |||
| 7bf8d58cde | |||
| b6e24559e5 | |||
| 0d87d5927e | |||
| dfd5cc4728 | |||
| 20b7ee009d | |||
| 19a3f56941 | |||
| 3b298d44c1 | |||
| 038d3bc41c | |||
| 235e89ae14 | |||
| e2de9efc33 | |||
| 8126085037 | |||
| bbe14834e4 | |||
| 45f2d301b3 | |||
| 2ecd11d71f | |||
| b42f072bd5 | |||
| 3b3668eedf | |||
| 7f7f353131 | |||
| 53594de1ff | |||
| 4fbbfb5191 | |||
| 4e1daea838 | |||
| d8ff83da73 | |||
| a7712a923f | |||
| 01b5f8f237 | |||
| b9ad15c50f | |||
| db06cff997 | |||
| f0028c0094 | |||
| 1c954801b0 | |||
| 973e4f0064 | |||
| be5d291bd9 | |||
| cbec56c2f0 | |||
| 880d0ba753 | |||
| db85689364 | |||
| 48a0d8c508 | |||
| df4cd493ee | |||
| 74132dcd49 | |||
| ef72cd3250 | |||
| 5cf1dd4249 | |||
| 29bd30d3bf | |||
| 3f8a0a91b3 | |||
| 416a572664 | |||
| 388c72360d | |||
| b841afc2e4 | |||
| f10d340254 | |||
| 0d0b91ee9b | |||
| 4f1e59a613 | |||
| 5960e4153c | |||
| 8032333a17 | |||
| 712ec6def3 | |||
| 0d43ef0736 | |||
| b318509cba | |||
| f3b541f00a | |||
| 4f64dcdbd4 | |||
| 68acf84e26 | |||
| aaceb923ad | |||
| 074de2741a | |||
| 0e4bc320cb | |||
| 9e9412bec0 | |||
| 7e92471ac9 | |||
| 078a7eb290 | |||
| df3876b438 | |||
| d414de450b | |||
| 9e89bb5044 | |||
| aa0c42e1ec | |||
| a4daa0e3d9 | |||
| 162ac39570 | |||
| 8c73fa69a1 | |||
| 159eeeb3a4 | |||
| 66f735fde9 | |||
| 1a3aa7f031 | |||
| ac41a9e63a | |||
| eb0873996f | |||
| c85826ef2e | |||
| 627cf63a4c | |||
| 744c08e13e | |||
| dd7a6a80eb | |||
| ab807e3b9b | |||
| c35be50c83 | |||
| 37ab9c80e3 | |||
| 7ff98d2918 | |||
| 35d66f5d8c | |||
| 3f018a4195 | |||
| 578e15adb2 | |||
| c4474455e9 | |||
| 8f43854cbf | |||
| 787149da13 | |||
| 3b31f6932a | |||
| 6c9e130ca8 | |||
| 86a234d17e | |||
| f68baee5c3 | |||
| 0028fd3e9c | |||
| f5f9862b78 | |||
| f38952dc51 | |||
| 24eb149221 | |||
| ce8598a0b4 | |||
| fb9cf75412 | |||
| 68f5df73b9 | |||
| e068c523ec | |||
| aa182bf047 | |||
| 6e9639446d | |||
| c48c1c3b32 | |||
| 14224ac538 | |||
| 58be92d3fc | |||
| 7107a91f6f | |||
| 438ed22f8f | |||
| a9dfc9a9fd | |||
| f8b09b3525 | |||
| f1ab02b311 | |||
| 4e833e26ca | |||
| 25df2f6414 | |||
| 42719d3fe3 | |||
| 1f6d23c19c | |||
| 94db9ec522 | |||
| a47c57c22c | |||
| 8f4bc0ea00 | |||
| dd70b09fb1 | |||
| c930050da6 | |||
| 55a7a72e61 | |||
| ca2ae36d41 | |||
| 81b4e42ca2 | |||
| 55e61b55d8 | |||
| a99529cb1e | |||
| bf43efe509 | |||
| da7f5b015b | |||
| 3de9915389 | |||
| 418444a196 | |||
| 171251b27d | |||
| 9fef920a6f | |||
| 5bff837a61 | |||
| 05f6f4efab | |||
| e4f5b0e3d8 | |||
| 49b733f660 | |||
| 36ed618adf | |||
| 48042011e2 | |||
| 0e1939a871 | |||
| bea1e61739 | |||
| 72cd82f450 | |||
| befa059591 | |||
| 7229f7271c | |||
| 9c5970e757 | |||
| 2fe3f0a9df | |||
| 3929f02e94 | |||
| 1abf80c310 | |||
| 2c18c89807 | |||
| 1b81fa5aa1 | |||
| baa08b3221 | |||
| b9a9abd30d | |||
| 33536957d8 | |||
| d092fd45ba | |||
| 78c748df5d | |||
| 3d76de3041 | |||
| ed3e9f3347 | |||
| eb836436b9 | |||
| c34a9c52d0 | |||
| 88d96f7d57 | |||
| 69e447be1c | |||
| df09acfa31 | |||
| 6343f77c0d | |||
| 285fc2269e | |||
| 68a1da9190 | |||
| ceae7d4fdb | |||
| 371daa6c80 | |||
| 948993e066 | |||
| ec4f0e5ad6 | |||
| ef56c6ce7e | |||
| 3c02da416e | |||
| 6660bf7618 | |||
| 000e5ec29a | |||
| ef8f4df4ab | |||
| dff70f2608 | |||
| 0d7967ff62 | |||
| 4fe459dab6 | |||
| 0e5e1f7873 | |||
| 82d4829c83 | |||
| a24fab6d92 | |||
| 748055dcf1 | |||
| 3904162360 | |||
| 7ca24ede4c | |||
| 1e59b10479 | |||
| cda61bff5b | |||
| 09a9753ca7 | |||
| 1621449143 | |||
| d0ef7f69b1 | |||
| 3df95b8970 | |||
| ddd4b0e262 | |||
| 6b05b6e7fb | |||
| 9dd728ce7e | |||
| 90b40ff0dc | |||
| 3c27c52c9f | |||
| 05d4dc5666 | |||
| edaabf5bd2 | |||
| ad79c63a37 | |||
| 9461bf2129 | |||
| f2097c0c5f | |||
| d838e1808d | |||
| 5ed54d9e7c | |||
| 78aba1c7e4 | |||
| 3faaee80ec | |||
| a847b8f4e4 | |||
| 24170a8a16 | |||
| 5438331fe1 | |||
| 3c957e0cbe | |||
| 10672f3e1a | |||
| fa90e420eb | |||
| 347bb2df4b | |||
| 986ffe66f8 | |||
| c1bedec354 | |||
| 182b6c7b07 | |||
| 22edbddd84 | |||
| 50f6f44d26 | |||
| e93a697179 | |||
| f1a5805b1c | |||
| 126f530af1 | |||
| 5dfbbb8d96 | |||
| 6962e505f9 | |||
| 5c2523e752 | |||
| 635dff73b4 | |||
| c85e4e7ceb | |||
| 7ed4301c6c | |||
| 1193e7025a | |||
| cc1ee19115 | |||
| e975eac4a7 | |||
| 779fc35228 | |||
| 8e59282fe0 | |||
| 11c8d47909 | |||
| 2661999f3e | |||
| e4bfb05875 | |||
| fe14988d50 | |||
| d45bef5e70 | |||
| 82d03b98c6 | |||
| 9c1ecf3f2c | |||
| 8f6be60c6e | |||
| 81a1bd9206 | |||
| 9f7dffb29d | |||
| eee799bfc4 | |||
| 9665adb61d | |||
| e40019f3cb | |||
| b2f95bfa60 | |||
| be2c7a62fd | |||
| 38f5468f19 | |||
| 31dcbc0159 | |||
| bd81320c08 | |||
| 0707f37247 | |||
| 0993736cea | |||
| cc3e2204e2 | |||
| 8ac5f0318b | |||
| 270a61e73a | |||
| 1c057b1ce1 | |||
| e74e824417 | |||
| 73d1de5dcf | |||
| 4549be0d05 | |||
| e3f2f2175d | |||
| a604cf2b2a | |||
| d6b4c1f454 | |||
| d3258693b2 | |||
| 9eba3b6eaa | |||
| 7b75364feb | |||
| 4a4a0f09ef | |||
| 6d14c2d448 | |||
| 57edd47ed7 | |||
| aefcedf754 | |||
| 2c685c846f | |||
| 6536f7b56b | |||
| 9d3881b00e | |||
| baffbd6a32 | |||
| 9e4702c102 | |||
| b63f3f335c | |||
| 29b0bcb6b9 | |||
| 62fa0bb218 | |||
| 9e67565c71 | |||
| dee4cf591e | |||
| bc5d6ee113 | |||
| 5af3b537da | |||
| 4b159d400c | |||
| f3c012660a | |||
| b5b8b5df26 | |||
| 6d38d9b538 | |||
| ef11ae6540 | |||
| a3802c25c0 | |||
| 377bcfe6da | |||
| 63a5c0986f | |||
| 8320623210 | |||
| 90c4a2fd41 | |||
| 4ee66caaf9 | |||
| 23251de6f1 | |||
| 37287bac7e | |||
| 43a7340f5d | |||
| 2363b5e167 | |||
| 62bf8c2287 | |||
| a5a958d6e2 | |||
| 812d8508f4 | |||
| c40cc3f740 | |||
| 56040951f1 | |||
| 39b1a65dc5 | |||
| 438f35fe88 | |||
| 9240518066 | |||
| 27b71a9d07 | |||
| 0f1d675bef | |||
| 19345ff538 | |||
| 7b28bc9c68 | |||
| d67eae55df | |||
| 8e375dcf73 | |||
| a34d0cabfc | |||
| a668743d10 | |||
| b13cbbb244 | |||
| b6ae5fd344 | |||
| 1c85034e19 | |||
| b0d1823968 | |||
| f0e03c79df | |||
| 6109cdf41b | |||
| ec0873d527 | |||
| 63223172b4 | |||
| 9778253d21 | |||
| 0140b4ded1 | |||
| dca60b83a9 | |||
| 42e683375c | |||
| 66e07c2f69 | |||
| 2b067b9dec | |||
| c22d7d2f41 | |||
| ea3d489c24 | |||
| 97683a14ef | |||
| d79b912e0e | |||
| 7ec8f8b03e | |||
| 58199ef7c9 | |||
| d5c46514d3 | |||
| f400973557 | |||
| 148d6e7b1b | |||
| 74dec650a7 | |||
| 5f6e003e4e | |||
| d3df22b44b | |||
| 257208d55b | |||
| d8b9b09d14 | |||
| 6f9e14ceb0 | |||
| d854984dda | |||
| 2951721886 | |||
| 02801b32a6 | |||
| b243e04fd2 | |||
| 02902d9a41 | |||
| 5c33034455 | |||
| 7541293a3c | |||
| da7d4dac7a | |||
| 507ab8ec11 | |||
| e93ff7a6b1 | |||
| 098ae2b69f | |||
| a58a10e93d | |||
| 9be7d951c3 | |||
| 6cf482dc63 | |||
| aaa4683462 | |||
| 0b5535b6d4 | |||
| 45feaeaec4 | |||
| 90f92cd139 | |||
| 0285d97e3f | |||
| bf80e4b5e1 | |||
| d4e4717857 | |||
| fca90e9b0f | |||
| ffbb91216f | |||
| 09620e060f | |||
| 0ea38384cc | |||
| aae659c5fd | |||
| b7a481ec79 | |||
| 763eaf83da | |||
| 2843d1e13e | |||
| e897797955 | |||
| cc8f103465 | |||
| f1c3a90bc5 | |||
| c90c438324 | |||
| ae1ff3f6f7 | |||
| e2224386bf | |||
| 6ad51ebd18 | |||
| 0fb9f584cb | |||
| 9a34b94568 | |||
| 7bca3bcac3 | |||
| de27554043 | |||
| 306ee3dfa4 | |||
| 3593b6b5c2 | |||
| e06acab39b | |||
| 6dd4e0f53a | |||
| 2c2a37cacb | |||
| 7935bd22c2 | |||
| 6887210a1a | |||
| 33dc3a4b06 | |||
| ba4610155f | |||
| 28eeba49ba | |||
| 0a00e529c3 | |||
| c5024cf6be | |||
| 0f3b416c3f | |||
| addacd9ce5 | |||
| 5582bb2d4c | |||
| 8b27c0e755 | |||
| ca4efa6e50 | |||
| cfac835607 | |||
| 3aa72ae74a | |||
| 07579ee9a1 | |||
| fe4823681f | |||
| 6816ad5c0f | |||
| aace987149 | |||
| 339ab9eeab | |||
| eee844e204 | |||
| 46cfe70181 | |||
| 294935ceed | |||
| f2097b9036 | |||
| e48a3a06c0 | |||
| c07371cb76 | |||
| 8d450aa500 | |||
| 726c792fbe | |||
| 83dda3e73f | |||
| 5c78e29849 | |||
| e6d48cd37f | |||
| a3ecde3ad9 | |||
| 2bb64a6cae | |||
| 764c818d10 | |||
| 2d18185928 | |||
| 43468166d2 | |||
| fbfd6bc485 | |||
| 1578efe366 | |||
| 76948c5156 | |||
| 562ed5908d | |||
| 9caac14014 | |||
| 695f75f3a7 | |||
| 7d7c04ddc0 | |||
| 863bf8ebbe | |||
| 0fcc28f50c | |||
| 04e9a08f3d | |||
| 837c401116 | |||
| b087d5125f | |||
| a6bff09c78 | |||
| 4716c0b7b7 | |||
| 1d040a170e | |||
| 951026a95c | |||
| c6b82bfa56 | |||
| 01b6d90432 | |||
| 504a116ebf | |||
| be785a878c | |||
| 5c2b7404d2 | |||
| 84e9e2396a | |||
| 7687d5e26e | |||
| 25ce3b039e | |||
| 9c4c42e27e | |||
| 26dd850ac1 | |||
| 0380c286a5 | |||
| 10aca77de4 | |||
| b6f2fdef77 | |||
| 9cc1f5f0e3 | |||
| adcf22f281 | |||
| ad0c49ac37 | |||
| 73d77b8382 | |||
| 3e45f39ea2 | |||
| a2bb015c79 | |||
| b231f43fc7 | |||
| 383038fdb4 | |||
| fbd8ea1edb | |||
| 26e292dd34 | |||
| c520e16031 | |||
| 101972fbad | |||
| f23ebc4031 | |||
| 44431db092 | |||
| d1b6c1ffe4 | |||
| 4d98151b62 | |||
| 5e8e18e3b5 | |||
| 808ff548ec | |||
| bc9b482373 | |||
| 4506eb0df9 | |||
| 921d412fc7 | |||
| 6089d3af78 | |||
| b8168ca606 | |||
| 61a7325bc0 | |||
| c483116b32 | |||
| 55a623dc97 | |||
| ad420108b0 | |||
| 9944c7d2de | |||
| 1a8f2be4fd | |||
| 13f64fdfe2 | |||
| 38a9e29102 | |||
| 3c23a57138 | |||
| 7baed872c6 | |||
| 9a7a284561 | |||
| e9c24a2656 | |||
| 5c73ef0a6d | |||
| 6c29c53a72 | |||
| dadcbe61ea | |||
| 93502a05ea | |||
| 5ebde4c79a | |||
| cf21ae22f1 | |||
| cc500ae833 | |||
| 256c0baa14 | |||
| 66decc604e | |||
| 356bc18078 | |||
| 1344cbc192 | |||
| e00ffb07ad | |||
| dba43590a5 | |||
| a0613cfee6 | |||
| c3de72b71a | |||
| 39fc60a482 | |||
| 0d7e71a269 | |||
| 78a2f65ec3 | |||
| 802bd74c52 | |||
| 33cf40debb | |||
| ff63fd9f6f | |||
| 5b207e6f54 | |||
| 695dc6ec5a | |||
| d3bcb8c6b9 | |||
| 6226aea3c3 | |||
| a30ad9b886 | |||
| 2b1e17681f | |||
| 8f25a31f19 | |||
| 1c7e6cf1b9 | |||
| fc7459c07f | |||
| 8f6932de64 | |||
| b708100c03 | |||
| d4e2d3d2dd | |||
| 13309cb8c4 | |||
| 5a4bc0909b | |||
| 39540e5794 | |||
| 0a0f977b5c | |||
| 13a75e7ad7 | |||
| 99574d6255 | |||
| 968cceb725 | |||
| 002985a446 | |||
| 5adc29b0b3 | |||
| 52ea4ff44d | |||
| 4e31a87c20 | |||
| 5d85390715 | |||
| 3e13eb8942 | |||
| 262c6d1fcb | |||
| 12b5a88861 | |||
| 2ccc9d886e | |||
| a78769c8ff | |||
| 1a142ad5eb | |||
| 2bc22e150c | |||
| aad5d280fd | |||
| 7ab07ed149 | |||
| 3690998dbc | |||
| 1b83fcc1c7 | |||
| 5cf25c45f9 | |||
| efa734c06e | |||
| e242244ec0 | |||
| 6f9da163fb | |||
| a3fd169bb6 | |||
| 899056f929 | |||
| 132fef1b76 | |||
| 422f772c40 | |||
| 66f5081ada | |||
| 839e35f1da | |||
| 40d9713326 | |||
| 17b04ad697 | |||
| 2f99dd8e98 | |||
| 49f825ba82 | |||
| 3f18ad0bc5 | |||
| 991c42e816 | |||
| 20d6eae50a | |||
| 9740582a84 | |||
| a8046a6d69 | |||
| d6655a5c14 | |||
| 0a3a2db4ae | |||
| 499eb5ea14 | |||
| b8ca287883 | |||
| 52f3392ece | |||
| d53641ce5e | |||
| 7a3ad6c3a1 | |||
| 0b2007011e | |||
| eae6983ca5 | |||
| 0ec337748f | |||
| 2699278ba3 | |||
| 0406166d8a | |||
| 2128eda87b | |||
| 59e11aa804 | |||
| 21f4fb169f | |||
| 30fc52ebd9 | |||
| 64bc7af4ef | |||
| b3f1fc667a | |||
| fcbb28f9d8 | |||
| 240a31db3a | |||
| c1bde09585 | |||
| 5dd2b5e555 | |||
| 37dcb92220 | |||
| 6c43c60d04 | |||
| b8d191ac1c | |||
| 57173c7740 | |||
| 2d3295ec54 | |||
| 941ede117c | |||
| 4210b8333f | |||
| 1723d1e5a9 | |||
| 3ee06ee7a0 | |||
| d3e8da58dc | |||
| 29e000b939 | |||
| 6686a72d1f | |||
| 7dd20f69d7 | |||
| 0044ef5588 | |||
| ffa5686b22 | |||
| ab8d6bea99 | |||
| e7bb89f582 | |||
| c80b0464e5 | |||
| 7e3547b309 | |||
| 45c7432ff7 | |||
| c98c20d403 | |||
| d26a2580ea | |||
| f84c4ab2e5 | |||
| de6676a516 | |||
| bfbb7bec94 | |||
| ac00aaae4d | |||
| 422222a7cb | |||
| e1c7b37d62 | |||
| dec978743b | |||
| 10fae033c8 | |||
| b23180d287 | |||
| 99ccd81b3f | |||
| e2d3f3a351 | |||
| 5e6a444aa2 | |||
| 72cf5cfc59 | |||
| 75cb68d2f1 | |||
| 7f40a9d723 | |||
| dcc9d0e9cd | |||
| 7228329f5e | |||
| d8786717b6 | |||
| b73bd3506f | |||
| bdb2791b35 | |||
| 549ea11945 | |||
| aed01b5703 | |||
| 13eb8562e0 | |||
| c022a12835 | |||
| 04eb47ff65 | |||
| 10ecd16f0c | |||
| 75852bfa75 | |||
| 750c720c9b | |||
| 4697681fcb | |||
| 9398363cbf | |||
| ae45e6b960 | |||
| 88c002703e | |||
| 51c78a89bd | |||
| e36a958c0d | |||
| a8126a6f90 | |||
| 9b857cdefa | |||
| 90e6400115 | |||
| 2dcfcf9708 | |||
| f4971da42e | |||
| 008f953b6c | |||
| 5481237480 | |||
| 4f7564e5ae | |||
| d214cbaece | |||
| d0c5f1e69f | |||
| 4ba3240fb4 | |||
| 6d8e5e4c83 | |||
| cd1402570b | |||
| 6c0e528dd2 | |||
| 297a513d21 | |||
| 9f0a4ba064 | |||
| 8813ed66e0 | |||
| fafcd5dfca | |||
| 155a8b79da | |||
| f523870b57 | |||
| 2ed24434c8 | |||
| 6878b2c072 | |||
| 0ed8dc970d | |||
| bc85f09109 | |||
| 793b28e43b | |||
| ed4abacd1e | |||
| 8bf55ab46c | |||
| 7edabce657 | |||
| 56187e4da3 | |||
| 31a12faef1 | |||
| eb94c16465 | |||
| e8437a9c54 | |||
| 840039ef1e | |||
| 84a749605e | |||
| c1283d2ab0 | |||
| 07b5c4918b | |||
| 703f0a6b70 | |||
| 5e98dee46f | |||
| b2eddf55d2 | |||
| db7be640d4 | |||
| 04fa597844 | |||
| 694dbeb96c | |||
| 7afd358c3c | |||
| b0a5a570a9 | |||
| c45b84c850 | |||
| d575a43aee | |||
| 0b151ea559 | |||
| 926970b256 | |||
| d58af0bfa5 | |||
| 429da7c6f3 | |||
| 60a7433573 | |||
| 08a5d444d4 | |||
| 1982069b69 | |||
| 7c06c65df3 | |||
| 6263766202 | |||
| 66fbbeff54 | |||
| 3c5ad1328f | |||
| 3345d7e088 | |||
| 2bb25cb874 | |||
| 444a728e7a | |||
| 70bea0c865 | |||
| 6eea1e9035 | |||
| 4deb1836ad | |||
| 4c8007dcfe | |||
| 000116bb3d | |||
| a2b6f21c7a | |||
| a374ee39d3 | |||
| 0f5c82dffd | |||
| 268fed761e | |||
| fe01d252db | |||
| dc36d74337 | |||
| 7a0da7bd8e | |||
| 530d5a4e63 | |||
| 2d847d1704 | |||
| 631d8fcfb1 | |||
| a8888efb88 | |||
| a51ecea9b1 | |||
| 4d49517111 | |||
| d5d1b3567b | |||
| 7827ce3448 | |||
| a05059db01 | |||
| b78490ca56 | |||
| b46ccc9b78 | |||
| 4f1e21dfb0 |
@@ -0,0 +1,57 @@
|
||||
name: ci-bcf-pypi
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# ┌───────────── minute (0 - 59)
|
||||
# │ ┌───────────── hour (0 - 23)
|
||||
# │ │ ┌───────────── day of the month (1 - 31)
|
||||
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
|
||||
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
|
||||
# * * * * *
|
||||
- cron: "0 0 18 * *"
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/ci-bcf-pypi.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
major: 0
|
||||
minor: 0
|
||||
name: ifcopenshell
|
||||
|
||||
jobs:
|
||||
activate:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.repository == 'IfcOpenShell/IfcOpenShell'
|
||||
steps:
|
||||
- name: Set env
|
||||
run: echo ok go
|
||||
|
||||
build:
|
||||
needs: activate
|
||||
name: ${{ matrix.config.name }}-${{ matrix.pyver }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v2 # https://github.com/actions/checkout
|
||||
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.10' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
- run: echo ${{ env.DATE }}
|
||||
- name: Get current date
|
||||
id: date
|
||||
run: echo "::set-output name=date::$(date +'%y%m%d')"
|
||||
- name: Compile
|
||||
run: |
|
||||
pip install build
|
||||
cd src/bcf &&
|
||||
make dist
|
||||
- name: Publish a Python distribution to PyPI
|
||||
uses: ortega2247/pypi-upload-action@master
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.PYPI_API_TOKEN }}
|
||||
packages_dir: src/bcf/dist
|
||||
@@ -1,37 +0,0 @@
|
||||
name: ci-bcf
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
activate:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.repository == 'IfcOpenShell/IfcOpenShell' &&
|
||||
contains(github.event.head_commit.message, '[bcf release]')
|
||||
steps:
|
||||
- run: echo ok go
|
||||
upload:
|
||||
needs: activate
|
||||
name: Upload BCF package to Pypi
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: Build package
|
||||
run: |
|
||||
cd src/bcf
|
||||
pip install build
|
||||
python -m build
|
||||
- name: Test
|
||||
run: |
|
||||
cd src/bcf
|
||||
make test
|
||||
- name: Publish package
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.PYPI_TOKEN }}
|
||||
packages_dir: src/bcf/dist
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pyver: [py39, py310]
|
||||
pyver: [py39, py310, py311]
|
||||
config:
|
||||
- {
|
||||
name: "Windows Build",
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
|
||||
with:
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
python-version: '3.10'
|
||||
python-version: '3.11'
|
||||
- run: echo ${{ env.DATE }}
|
||||
- name: Get current date
|
||||
id: date
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
name: ci-ifcopenshell-conda-daily
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- .github/workflows/ci-ifcopenshell-conda-daily.yml
|
||||
- conda/**
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# ┌───────────── minute (0 - 59)
|
||||
# │ ┌───────────── hour (0 - 23)
|
||||
@@ -15,17 +12,8 @@ on:
|
||||
- cron: "49 23 * * *" # 11min before utc midnight every day
|
||||
|
||||
jobs:
|
||||
activate:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.repository == 'IfcOpenShell/IfcOpenShell'
|
||||
steps:
|
||||
- name: Set env
|
||||
run: echo ok go
|
||||
|
||||
test:
|
||||
name: ${{ matrix.platform.distver }}-${{ matrix.pyver.name }}
|
||||
needs: activate
|
||||
name: ${{ matrix.platform.distver }}-${{ matrix.pyver.name }}-${{ matrix.variant }}
|
||||
runs-on: ${{ matrix.platform.distver }}
|
||||
defaults:
|
||||
run:
|
||||
@@ -34,18 +22,23 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pyver: [
|
||||
{ name: py310, distver: '3.10'},
|
||||
{ name: py311, distver: '3.11'}
|
||||
{ name: py311, distver: '3.11'},
|
||||
{ name: py312, distver: '3.12'}
|
||||
]
|
||||
platform: [
|
||||
{ name: Windows, distver: windows-2022, upload: 'true' },
|
||||
{ name: Linux, distver: ubuntu-22.04, upload: 'true' },
|
||||
{ name: macOS, distver: macos-12, upload: 'true' }
|
||||
]
|
||||
variant: [
|
||||
'novtk',
|
||||
# 'all'
|
||||
]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Download MacOSX SDK
|
||||
if: ${{ matrix.platform.name == 'macOS' }}
|
||||
run: |
|
||||
@@ -53,21 +46,22 @@ jobs:
|
||||
tar xf MacOSX10.13.sdk.tar.xz && \
|
||||
sudo mv -v MacOSX10.13.sdk /opt/ && \
|
||||
ls /opt/
|
||||
- uses: seanmiddleditch/gha-setup-ninja@master
|
||||
- uses: mamba-org/provision-with-micromamba@main # https://github.com/mamba-org/provision-with-micromamba
|
||||
|
||||
- uses: mamba-org/setup-micromamba@v1 # https://github.com/mamba-org/setup-micromamba
|
||||
with:
|
||||
channels: conda-forge
|
||||
channel-priority: strict
|
||||
environment-file: conda/environment.yml
|
||||
extra-specs: |
|
||||
python=${{ matrix.pyver.distver }}
|
||||
environment-name: build-env
|
||||
cache-environment: true
|
||||
condarc: |
|
||||
channels:
|
||||
- conda-forge
|
||||
channel_priority: strict
|
||||
create-args: >-
|
||||
python=3.11
|
||||
anaconda-client
|
||||
boa
|
||||
|
||||
- name: build, test and upload ifcopenshell
|
||||
if: ${{ matrix.platform.upload == 'true' }}
|
||||
run: |
|
||||
conda-build . --python ${{ matrix.pyver.distver }} -c conda-forge --token ${{ secrets.ANACONDA_TOKEN }} --user ifcopenshell
|
||||
working-directory: ./conda
|
||||
- name: build & test ifcopenshell
|
||||
if: ${{ matrix.platform.upload == 'false' }}
|
||||
run: |
|
||||
conda-build . --python ${{ matrix.pyver.distver }} -c conda-forge
|
||||
conda mambabuild . --python ${{ matrix.pyver.distver }} -c conda-forge --variants "{variant: ${{ matrix.variant }}}" --token ${{ secrets.ANACONDA_TOKEN }} --user ifcopenshell
|
||||
working-directory: ./conda
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
name: ci_py_only
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'src/**'
|
||||
- 'test/**'
|
||||
- 'conda/**'
|
||||
- 'cmake/**'
|
||||
- '.github/workflows/ci-py-only.yml'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
activate:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.repository == 'IfcOpenShell/IfcOpenShell' &&
|
||||
!contains(github.event.head_commit.message, 'skip ci')
|
||||
steps:
|
||||
- run: echo ok go
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
needs: activate
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install C++ dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install --no-install-recommends \
|
||||
git cmake gcc g++ \
|
||||
libboost-date-time-dev \
|
||||
libboost-filesystem-dev \
|
||||
libboost-iostreams-dev \
|
||||
libboost-program-options-dev \
|
||||
libboost-regex-dev \
|
||||
libboost-system-dev \
|
||||
libboost-thread-dev \
|
||||
python3-all-dev python3-pip \
|
||||
swig libpcre3-dev libxml2-dev \
|
||||
libtbb-dev nlohmann-json3-dev \
|
||||
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
|
||||
libhdf5-dev libcgal-dev
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
with:
|
||||
key: ${GITHUB_WORKFLOW}
|
||||
|
||||
- name: Build ifcopenshell
|
||||
run: |
|
||||
sudo /usr/sbin/update-ccache-symlinks
|
||||
mkdir build && cd build
|
||||
PATH="/usr/lib/ccache:$PATH" cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH=/usr \
|
||||
-DCMAKE_SYSTEM_PREFIX_PATH=/usr \
|
||||
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
|
||||
-DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 \
|
||||
-DPYTHON_INCLUDE_DIR:PATH=/usr/include/python3.8 \
|
||||
-DPYTHON_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libpython3.8.so \
|
||||
-DCOLLADA_SUPPORT=Off \
|
||||
"-DSCHEMA_VERSIONS=2x3;4;4x3_add1" \
|
||||
-DBUILD_CONVERT=Off \
|
||||
-DGLTF_SUPPORT=On \
|
||||
-DJSON_INCLUDE_DIR=/usr/include \
|
||||
-DCGAL_INCLUDE_DIR=/usr/include \
|
||||
-DGMP_INCLUDE_DIR=/usr/include \
|
||||
-DMPFR_INCLUDE_DIR=/usr/include \
|
||||
-DGMP_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DMPFR_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DHDF5_INCLUDE_DIR=/usr/include/hdf5/serial \
|
||||
../cmake
|
||||
sudo make -j $(nproc)
|
||||
sudo make install
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
sudo /usr/bin/python -m pip install -U pip
|
||||
sudo /usr/bin/python -m pip install xmlschema xsdata numpy lxml
|
||||
sudo /usr/bin/python -m pip install src/bcf --no-deps
|
||||
sudo /usr/bin/python -m pip install pytest
|
||||
sudo /usr/bin/python -m pip install isodate
|
||||
sudo /usr/bin/python -m pip install lark
|
||||
sudo /usr/bin/python -m pip install networkx
|
||||
sudo /usr/bin/python -m pip install tabulate
|
||||
sudo /usr/bin/python -m pip install python-dateutil
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
cd test
|
||||
sudo /usr/bin/python tests.py
|
||||
cd ../src/ifcopenshell-python
|
||||
mv ifcopenshell ifcopenshell-local # Force testing on installed module
|
||||
make test
|
||||
@@ -31,12 +31,25 @@ jobs:
|
||||
- run: echo ok go
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
needs: activate
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.11
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install xmlschema xsdata numpy lxml pytest isodate lark networkx tabulate python-dateutil
|
||||
pip install src/bcf --no-deps
|
||||
pip install https://github.com/Andrej730/aud/archive/refs/heads/master-reduced-size.zip
|
||||
|
||||
- name: Install C++ dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
@@ -49,7 +62,6 @@ jobs:
|
||||
libboost-regex-dev \
|
||||
libboost-system-dev \
|
||||
libboost-thread-dev \
|
||||
python3-all-dev python3-pip \
|
||||
swig libpcre3-dev libxml2-dev \
|
||||
libtbb-dev nlohmann-json3-dev \
|
||||
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
|
||||
@@ -62,6 +74,9 @@ jobs:
|
||||
|
||||
- name: Build ifcopenshell
|
||||
run: |
|
||||
echo $Python3_ROOT_DIR
|
||||
echo ${{ env.pythonLocation }}
|
||||
|
||||
mkdir build && cd build
|
||||
cmake \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
@@ -71,9 +86,9 @@ jobs:
|
||||
-DCMAKE_SYSTEM_PREFIX_PATH=/usr \
|
||||
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
|
||||
-DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 \
|
||||
-DPYTHON_INCLUDE_DIR:PATH=/usr/include/python3.8 \
|
||||
-DPYTHON_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libpython3.8.so \
|
||||
-DPYTHON_EXECUTABLE:FILEPATH=${{ env.pythonLocation }}/bin/python \
|
||||
-DPYTHON_INCLUDE_DIR:PATH=${{ env.pythonLocation }}/include/python3.11 \
|
||||
-DPYTHON_LIBRARY:FILEPATH=${{ env.pythonLocation }}/lib/libpython3.11.so \
|
||||
-DCOLLADA_SUPPORT=Off \
|
||||
"-DSCHEMA_VERSIONS=2x3;4;4x3_add1" \
|
||||
-DGLTF_SUPPORT=On \
|
||||
@@ -102,23 +117,11 @@ jobs:
|
||||
grep 0$ statuses
|
||||
grep 0$ statuses | wc -l
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
sudo /usr/bin/python -m pip install -U pip
|
||||
sudo /usr/bin/python -m pip install xmlschema xsdata numpy lxml
|
||||
sudo /usr/bin/python -m pip install src/bcf --no-deps
|
||||
sudo /usr/bin/python -m pip install pytest
|
||||
sudo /usr/bin/python -m pip install isodate
|
||||
sudo /usr/bin/python -m pip install lark
|
||||
sudo /usr/bin/python -m pip install networkx
|
||||
sudo /usr/bin/python -m pip install https://github.com/Andrej730/aud/archive/refs/heads/master-reduced-size.zip
|
||||
sudo /usr/bin/python -m pip install tabulate
|
||||
sudo /usr/bin/python -m pip install python-dateutil
|
||||
|
||||
- name: Test
|
||||
- name: Test ifcopenshell-python
|
||||
run: |
|
||||
cd test
|
||||
sudo /usr/bin/python tests.py
|
||||
python tests.py
|
||||
cd ../src/ifcopenshell-python
|
||||
mv ifcopenshell ifcopenshell-local # Force testing on installed module
|
||||
make test
|
||||
make test-safe
|
||||
|
||||
@@ -7,34 +7,26 @@
|
||||
|
||||
# output directories
|
||||
/cmake/out/
|
||||
/docs/out/
|
||||
/src/examples/out/
|
||||
/src/ifcmax/out/
|
||||
/src/ifcwrap/out/
|
||||
/src/qtviewer/out/
|
||||
|
||||
|
||||
/win/BuildDepsCache*.txt
|
||||
# IfcExpressParser residue
|
||||
/src/ifcexpressparser/express_parser.py
|
||||
|
||||
# General Python residue
|
||||
__pycache__
|
||||
*.py.bak
|
||||
|
||||
# Visual Studio Code files
|
||||
.vscode
|
||||
.vs
|
||||
|
||||
# PyCharm files
|
||||
.idea
|
||||
|
||||
#Virtual Env Files
|
||||
Pipfile
|
||||
Pipfile.lock
|
||||
|
||||
# Docs
|
||||
/docs/output
|
||||
/docs/rst_files
|
||||
/docs/doxygen
|
||||
/src/ifcblenderexport/docs/_build
|
||||
/docs/cpp-api/output
|
||||
|
||||
# gettext binary translation files
|
||||
*.mo
|
||||
@@ -84,6 +76,9 @@ src/ifcopenshell-python/test/build
|
||||
# blenderbim libs
|
||||
src/blenderbim/blenderbim/libs
|
||||
|
||||
# blenderbim i18n
|
||||
src/blenderbim/blenderbim/translations.py
|
||||
|
||||
# blenderbim test temp files
|
||||
src/blenderbim/test/files/temp
|
||||
src/blenderbim/drawings
|
||||
@@ -96,5 +91,10 @@ src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py
|
||||
# apple
|
||||
.DS_Store
|
||||
|
||||
# clangd config
|
||||
.clangd
|
||||
# clangd cache
|
||||
.cache
|
||||
|
||||
# Brickschema
|
||||
src/blenderbim/blenderbim/bim/schema/Brick.ttl
|
||||
src/blenderbim/blenderbim/bim/schema/Brick.ttl
|
||||
|
||||
@@ -10,4 +10,7 @@
|
||||
url = https://github.com/IfcOpenShell/svgfill
|
||||
[submodule "src/ifcopenshell-python/test/Sample-BIM-Files"]
|
||||
path = src/ifcopenshell-python/test/Sample-BIM-Files
|
||||
url = https://github.com/IfcOpenShell/ids-test-files
|
||||
url = https://github.com/IfcOpenShell/ids-test-files
|
||||
[submodule "docs/cpp-api/assets/doxygen-awesome-css"]
|
||||
path = docs/cpp-api/assets/doxygen-awesome-css
|
||||
url = https://github.com/jothepro/doxygen-awesome-css.git
|
||||
|
||||
@@ -7,13 +7,13 @@ IfcOpenShell
|
||||
</p>
|
||||
|
||||
IfcOpenShell is an open source ([LGPL]) software library for working with Industry Foundation Classes ([IFC]). Complete
|
||||
parsing support is provided for [IFC2x3 TC1], [IFC4 Add2 TC1], IFC4x1, IFC4x2, and IFC4x3. Extensive geometric support
|
||||
parsing support is provided for [IFC2x3 TC1], [IFC4 Add2 TC1], IFC4x1, IFC4x2, and [IFC4x3 Add2]. Extensive geometric support
|
||||
is implemented for the IFC releases [IFC2x3 TC1] and [IFC4 Add2 TC1]. Extending with support for arbitrary IFC schemas
|
||||
is possible at compile-time when using C++ and at run-time when using Python.
|
||||
|
||||
In addition to a C++ and Python API, IfcOpenShell comes with an ecosystem of tools, notably including IfcConvert (an application to convert IFC models to
|
||||
other formats), the BlenderBIM Add-on (an add-on to Blender providing a graphical IFC authoring platform), and many
|
||||
other libraries, CLI apps, and more. Support is also provided for auxiliary standards such as BCF and IDS.
|
||||
In addition to a C++ and Python API, IfcOpenShell comes with an ecosystem of tools, notably including IfcConvert (an application
|
||||
to convert IFC models to other formats), the BlenderBIM Add-on (an add-on to Blender providing a graphical IFC authoring platform),
|
||||
and many other libraries, CLI apps, and more. Support is also provided for auxiliary standards such as BCF and IDS.
|
||||
|
||||
For more information, see:
|
||||
|
||||
@@ -32,8 +32,8 @@ For more information, see:
|
||||
| Anaconda Daily Build | [](https://anaconda.org/ifcopenshell/ifcopenshell) |
|
||||
| Anaconda v0.7.0 Stable | [](https://anaconda.org/conda-forge/ifcopenshell) |
|
||||
| PyPi Daily Build | [](https://pypi.org/project/ifcopenshell/) |
|
||||
| ArchLinux AUR Package Stable | [](https://aur.archlinux.org/packages/ifcopenshell) |
|
||||
| ArchLinux AUR Package git | [](https://aur.archlinux.org/packages/ifcopenshell-git) |
|
||||
| ArchLinux AUR Package Stable | [](https://aur.archlinux.org/packages/ifcopenshell) |
|
||||
| ArchLinux AUR Package git | [](https://aur.archlinux.org/packages/ifcopenshell-git) |
|
||||
| BlenderBIM Add-on Chocolatey (under moderation) | [](https://community.chocolatey.org/packages/blenderbim-nightly/) |
|
||||
| Sponsor development on OpenCollective | [](https://opencollective.com/opensourcebim/) |
|
||||
| Docker hub | [](https://hub.docker.com/r/aecgeeks/ifcopenshell) |
|
||||
@@ -44,7 +44,7 @@ Contents
|
||||
Those marked with an asterisk are part of IfcOpenShell.
|
||||
|
||||
| Name | Description | License |
|
||||
| ------------------------- | ----------------------------------------------------------------------| ------------------- |
|
||||
| ------------------------- | --------------------------------------------------------------------- | ------------------- |
|
||||
| bcf | Library to read and write BCF-XML and query OpenCDE BCF-API modules | LGPL-3.0-or-later |
|
||||
| blenderbim | Add-on to Blender providing a graphical native IFC authoring platform | GPL-3.0-or-later |
|
||||
| bsdd | Library to query the bSDD API | LGPL-3.0-or-later |
|
||||
@@ -55,7 +55,6 @@ Those marked with an asterisk are part of IfcOpenShell.
|
||||
| ifcblender | Historic Blender IFC import add-on | LGPL-3.0-or-later\* |
|
||||
| ifccityjson | Convert CityJSON to IFC | LGPL-3.0-or-later |
|
||||
| ifcclash | Clash detection library and CLI app | LGPL-3.0-or-later |
|
||||
| ifccobie | Extract IFC data for COBie handover requirements | LGPL-3.0-or-later |
|
||||
| ifcconvert | CLI app to convert IFC to many other formats | LGPL-3.0-or-later\* |
|
||||
| ifccsv | Library and CLI app to export and import schedules from IFC | LGPL-3.0-or-later |
|
||||
| ifcdiff | Compare changes between IFC models | LGPL-3.0-or-later |
|
||||
@@ -78,6 +77,7 @@ Those marked with an asterisk are part of IfcOpenShell.
|
||||
[IFC]: https://technical.buildingsmart.org/standards/ifc/ "IFC"
|
||||
[IFC2x3 TC1]: https://standards.buildingsmart.org/IFC/RELEASE/IFC2x3/TC1/HTML/ "IFC2x3 TC1"
|
||||
[IFC4 Add2 TC1]: https://standards.buildingsmart.org/IFC/RELEASE/IFC4/ADD2_TC1/HTML/ "IFC4 Add2 TC1"
|
||||
[IFC4x3 Add2]: https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/ "IFC4x3 Add2"
|
||||
[Visual Studio]: https://www.visualstudio.com/ "Visual Studio"
|
||||
[Visual C++ Build Tools]: http://landinghub.visualstudio.com/visual-cpp-build-tools "Visual C++ Build Tools"
|
||||
[MSYS2]: https://msys2.github.io/ "MSYS2"
|
||||
|
||||
@@ -29,7 +29,7 @@ URL_CHOCO_PACKAGE = "https://community.chocolatey.org/packages/blender"
|
||||
URL_BLENDER_CMAKE = "https://raw.githubusercontent.com/blender/blender/{}/build_files/cmake/Modules/FindPythonLibsUnix.cmake"
|
||||
RE_BLENDER_VERSION_MIN_MAJ = r"Latest Version.+<span>Blender (\d+\.\d+)\..+</span>"
|
||||
RE_BLENDER_VERSION_MIN_MAJ_PAT = r"Latest Version.+<span>Blender (\d+\.\d+\.\d+)</span>"
|
||||
RE_BLENDER_PYTHON_VERSION_MAJ_MIN = r"SET\(_PYTHON_VERSION_SUPPORTED (\d+\.\d+)\)"
|
||||
RE_BLENDER_PYTHON_VERSION_MAJ_MIN = r"(?:set|SET)\(_PYTHON_VERSION_SUPPORTED (\d+\.\d+)\)"
|
||||
|
||||
|
||||
if sys.argv[1] == "--do_choco_release?":
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
|
||||
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
|
||||
endif()
|
||||
|
||||
file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
|
||||
string(REGEX REPLACE "\n" ";" files "${files}")
|
||||
|
||||
foreach(file ${files})
|
||||
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
|
||||
|
||||
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
||||
exec_program(
|
||||
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RETURN_VALUE rm_retval
|
||||
)
|
||||
|
||||
if(NOT "${rm_retval}" STREQUAL 0)
|
||||
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
|
||||
endif()
|
||||
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
||||
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
|
||||
endif()
|
||||
endforeach()
|
||||
@@ -1,8 +0,0 @@
|
||||
compile:
|
||||
conda activate conda-build && conda-build -c conda-forge . --keep-old-work --python 3.10.5
|
||||
|
||||
debug:
|
||||
conda activate conda-build && conda-debug -c conda-forge . --python 3.10.4
|
||||
|
||||
env:
|
||||
conda env update --f environment.yml --prune
|
||||
@@ -4,6 +4,7 @@ set MY_PY_VER=%PY_VER:.=%
|
||||
set LIBXML2="%LIBRARY_PREFIX%/lib/libxml2.lib"
|
||||
|
||||
cmake -G "Ninja" ^
|
||||
-D SCHEMA_VERSIONS="2x3;4;4x1;4x3;4x3_add1" ^
|
||||
-D CMAKE_BUILD_TYPE:STRING=Release ^
|
||||
-D CMAKE_INSTALL_PREFIX:FILEPATH="%LIBRARY_PREFIX%" ^
|
||||
-D CMAKE_PREFIX_PATH:FILEPATH="%LIBRARY_PREFIX%" ^
|
||||
|
||||
@@ -13,6 +13,7 @@ if [ `uname` == Darwin ]; then
|
||||
fi
|
||||
|
||||
cmake -G Ninja \
|
||||
-DSCHEMA_VERSIONS="2x3;4;4x1;4x3;4x3_add1" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=$PREFIX \
|
||||
${CMAKE_PLATFORM_FLAGS[@]} \
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
CONDA_BUILD_SYSROOT:
|
||||
- /opt/MacOSX10.13.sdk # [osx]
|
||||
- /opt/MacOSX10.13.sdk # [osx]
|
||||
|
||||
variant:
|
||||
- novtk
|
||||
- all
|
||||
@@ -1,13 +0,0 @@
|
||||
name: conda-build
|
||||
channels:
|
||||
- conda-forge
|
||||
dependencies:
|
||||
- conda-build
|
||||
- conda-verify
|
||||
- anaconda-client
|
||||
- ninja
|
||||
- doxygen
|
||||
- ripgrep
|
||||
- pip
|
||||
- pip:
|
||||
- lief==0.13
|
||||
@@ -1,6 +1,10 @@
|
||||
{% set name = "ifcopenshell" %}
|
||||
{% set version = "0.7.0" %}
|
||||
{% set build = 1 %}
|
||||
|
||||
# Higher number -> Always prioritize "novtk" variant over "all" variant
|
||||
{% set build = build + 200 %} # [variant == "novtk"]
|
||||
{% set build = build + 100 %} # [variant == "all"]
|
||||
|
||||
package:
|
||||
name: {{ name }}
|
||||
@@ -10,8 +14,9 @@ source:
|
||||
path: ..
|
||||
|
||||
build:
|
||||
string: py{{ CONDA_PY }}_{{ variant }}_h{{ PKG_HASH }}_{{ build }}
|
||||
binary_relocation: false [osx]
|
||||
number: 1
|
||||
number: {{ build }}
|
||||
|
||||
requirements:
|
||||
build:
|
||||
@@ -19,12 +24,12 @@ requirements:
|
||||
- {{ compiler('cxx') }}
|
||||
- ninja >=1.10.2
|
||||
- cmake
|
||||
- swig >=4.0.2
|
||||
- swig 4.1.1
|
||||
|
||||
host:
|
||||
- python
|
||||
- boost-cpp
|
||||
- occt ==7.7.0
|
||||
- occt 7.7.2 *{{ variant }}*
|
||||
- libxml2
|
||||
- cgal-cpp
|
||||
- hdf5
|
||||
@@ -36,11 +41,11 @@ requirements:
|
||||
|
||||
run:
|
||||
- python
|
||||
- boost-cpp
|
||||
- occt ==7.7.0
|
||||
- occt 7.7.2 *{{ variant }}*
|
||||
- {{ pin_compatible('cgal-cpp', max_pin='x.x.x') }}
|
||||
- {{ pin_compatible('boost-cpp', max_pin='x.x.x') }}
|
||||
- {{ pin_compatible('hdf5', max_pin='x.x.x') }}
|
||||
- libxml2
|
||||
- cgal-cpp
|
||||
- hdf5
|
||||
- mpfr
|
||||
- gmp # [unix]
|
||||
- mpir # [win]
|
||||
@@ -52,12 +57,12 @@ test:
|
||||
- ifcopenshell
|
||||
|
||||
about:
|
||||
home: http://ifcopenshell.org
|
||||
home: https://ifcopenshell.org
|
||||
license: LGPL-3.0-or-later
|
||||
license_file: COPYING
|
||||
summary: 'IfcOpenShell is a library to support the IFC file format'
|
||||
description: |
|
||||
IfcOpenShell is an open source (LGPL) software library for
|
||||
working with the Industry Foundation Classes (IFC) file format.
|
||||
doc_url: http://ifcopenshell.org/
|
||||
doc_url: https://ifcopenshell.org/
|
||||
dev_url: https://github.com/IfcOpenShell/IfcOpenShell
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#Look for an executable called sphinx-build
|
||||
find_program(SPHINX_EXECUTABLE
|
||||
NAMES sphinx-build
|
||||
DOC "Path to sphinx-build executable")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
#Handle standard arguments to find_package like REQUIRED and QUIET
|
||||
find_package_handle_standard_args(Sphinx
|
||||
"Failed to find sphinx-build executable"
|
||||
SPHINX_EXECUTABLE)
|
||||
@@ -1,11 +0,0 @@
|
||||
#Look for an executable called sphinx-build
|
||||
find_program(SPHINX_EXECUTABLE
|
||||
NAMES sphinx-build
|
||||
DOC "Path to sphinx-build executable")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
#Handle standard arguments to find_package like REQUIRED and QUIET
|
||||
find_package_handle_standard_args(Sphinx
|
||||
"Failed to find sphinx-build executable"
|
||||
SPHINX_EXECUTABLE)
|
||||
@@ -0,0 +1,33 @@
|
||||
# IfcOpenShell C++ API documentation
|
||||
|
||||
This folder contains the setup to build the IfcOpenShell C++ API documentation from the source code.
|
||||
|
||||
## Generating the documentation
|
||||
|
||||
> Prerequisites:
|
||||
>
|
||||
> Make sure to have [Doxygen](https://www.doxygen.nl) and [Graphviz](https://graphviz.org) installed into your `$PATH` variable.
|
||||
>
|
||||
> The documentation also use the [doxygen-awesome](https://jothepro.github.io/doxygen-awesome-css) theme as a git submodule.
|
||||
|
||||
Build with the command (from within the `/docs/cpp-api` folder):
|
||||
|
||||
```shell
|
||||
$ doxygen
|
||||
```
|
||||
|
||||
To include the current git commit hash into the build documentation, use the following command:
|
||||
|
||||
```shell
|
||||
$ PROJECT_NUMBER=$(git rev-parse --short HEAD) doxygen
|
||||
```
|
||||
|
||||
This will extract the current commit hash in short version and sets the propper ENV variable used by doxygen.
|
||||
|
||||
The generation of the documentation might take a while depending on your systems hardware, as it is configured to generate the Class graphs using .
|
||||
|
||||
The resulting documentation is located unter `/cpp-api/output/html` and can be directly accessed with your browser:
|
||||
|
||||
```shell
|
||||
$ open ./output/html/index.html
|
||||
```
|
||||
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 120 KiB |
@@ -1,240 +0,0 @@
|
||||
APPLY_DEFAULT_MATERIALS
|
||||
-----------------------
|
||||
|
||||
Given the command invocation:
|
||||
|
||||
Duplex_A_20110907_optimized.ifc d.dae -yv --include attribute GlobalId 3bXiCStxP6Fgxdej$yc50U
|
||||
|
||||
You will find log messages along the lines of
|
||||
|
||||
[Warning] {3bXiCStxP6Fgxdej$yc50U} No material and surface styles for:
|
||||
#333=IfcCovering('3bXiCStxP6Fgxdej$yc50U',#1,'Compound Ceiling:Gypsum Board:187483',$,'Compound Ceiling:Gypsum Board',#17840,#17052,'187483',.CEILING.)
|
||||
|
||||
This means that there is no IfcStyledItem associated to the representation items and that the element does not have an IfcMaterial association with IfcMaterialRepresentation from which we can derive a style (colour) for the element.
|
||||
|
||||
The interactive session below shows how with this setting enabled you will get a default generated material from the IFC element entity type and material indices of 0 pointing to that. With this setting disabled the material index would be -1 to indicate a missing style. Note that there is one material index for every triangle in the list of `shp.geometry.faces`.
|
||||
|
||||
>>> import ifcopenshell, ifcopenshell.geom
|
||||
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
|
||||
>>> s = ifcopenshell.geom.settings()
|
||||
>>> c = f["3bXiCStxP6Fgxdej$yc50U"]
|
||||
>>>
|
||||
>>> shp = ifcopenshell.geom.create_shape(s, c)
|
||||
>>> shp.geometry.material_ids
|
||||
(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
|
||||
>>> [(m.name, m.diffuse) for m in shp.geometry.materials]
|
||||
[]
|
||||
>>>
|
||||
>>> s.set(s.APPLY_DEFAULT_MATERIALS, True)
|
||||
>>> shp = ifcopenshell.geom.create_shape(s, c)
|
||||
>>> shp.geometry.material_ids
|
||||
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
>>> [(m.name, m.diffuse) for m in shp.geometry.materials]
|
||||
[('IfcCovering', (0.7, 0.7, 0.7))]
|
||||
|
||||
This is enabled by default for the IfcConvert serializers as they will not gracefully handle -1 material indices and allows users to quickly assign colours based on entity types in their modelling applications.
|
||||
|
||||
APPLY_LAYERSETS
|
||||
---------------
|
||||
|
||||
This setting is available in IfcConvert as `--enable-layerset-slicing`.
|
||||
|
||||
For IfcWall and IfcSlab elements, takes the associated IfcMaterialLayerSet and builds a set of surfaces to segment the building element geometry.
|
||||
|
||||
Note that enabling this settings is computationally intensive as it involves 3D Boolean operations.
|
||||
|
||||
Duplex_A_20110907_optimized.ifc d1.dae -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
|
||||
|
||||

|
||||
|
||||
Duplex_A_20110907_optimized.ifc d2.dae --enable-layerset-slicing -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
|
||||
|
||||

|
||||
|
||||
BUILDING_LOCAL_PLACEMENT
|
||||
------------------------
|
||||
|
||||
This setting is available in IfcConvert using `--building-local-placement`.
|
||||
|
||||
In the typical IfcSite > IfcBuilding > IfcBuildingStorey > ... hierarchy of elements, don't incorporate the ObjectPlacement of the IfcBuilding and above in the placement of elements in the output. This is useful when there is a large offset in this placement that reduces precision in further processing.
|
||||
|
||||
CONVERT_BACK_UNITS
|
||||
------------------
|
||||
|
||||
This setting is available in IfcConvert using `--convert-back-units`.
|
||||
|
||||
Internally IfcOpenShell uses meters as the global length unit to do calculations. This setting restores the coordinate positions after conversion by multiplying the factor of the IfcUnit with UnitType=LENGTHUNIT into the output geometry coordinate values.
|
||||
|
||||
DISABLE_OPENING_SUBTRACTIONS
|
||||
----------------------------
|
||||
|
||||
This setting is available in IfcConvert using `--disable-opening-subtraction`.
|
||||
|
||||
As in most viewer applications, IfcOpeningElement geometry is subtracted from their host elements. This setting disables this behavior.
|
||||
|
||||
Duplex_A_20110907_optimized.ifc d1.dae -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
|
||||
|
||||

|
||||
|
||||
Duplex_A_20110907_optimized.ifc d3.dae --disable-opening-subtraction -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
|
||||
|
||||

|
||||
|
||||
Note that disabling this settings will reduce processing time and improve robustness as it involves 3D Boolean operations.
|
||||
|
||||
DISABLE_TRIANGULATION
|
||||
---------------------
|
||||
|
||||
To be used in conjunction with `USE_BREP_DATA`. Do not apply the triangulation and - when `USE_BREP_DATA` is set - return a OpenCASCADE serialized TopoDS_Shape from `create_shape()` and `iterator`.
|
||||
|
||||
>>> import ifcopenshell, ifcopenshell.geom
|
||||
>>> s = ifcopenshell.geom.settings()
|
||||
>>> s.set(s.DISABLE_TRIANGULATION, True)
|
||||
>>> s.set(s.USE_BREP_DATA, True)
|
||||
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
|
||||
>>> c = f["3bXiCStxP6Fgxdej$yc50U"]
|
||||
>>> shp = ifcopenshell.geom.create_shape(s, c)
|
||||
>>> print(shp.geometry.brep_data)
|
||||
|
||||
CASCADE Topology V1, (c) Matra-Datavision
|
||||
Locations 0
|
||||
Curve2ds 0
|
||||
Curves 12
|
||||
1 4.6750000000000034 -8.0749999999999904 2.657 -2.0455514041918775e-15 -1 0
|
||||
1 4.6750000000000034 -8.0749999999999904 2.657 1 -3.435893306383461e-15 0
|
||||
1 6.2260000000000044 -8.0749999999999957 2.657 -2.0455514041918724e-15 -1 0
|
||||
1 6.226 -10.246000000000031 2.657 -1 6.8717866127669219e-15 0
|
||||
...
|
||||
|
||||
EDGE_ARROWS
|
||||
-----------
|
||||
|
||||
When `INCLUDE_CURVES` is true and geometric elements include curves (such as the wall axis), add arrow heads to the edges to indicate direction of the curve.
|
||||
|
||||
Duplex_A_20110907_optimized.ifc d4.dae --model --plan --edge-arrows -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
|
||||
|
||||

|
||||
|
||||
EXCLUDE_SOLIDS_AND_SURFACES
|
||||
---------------------------
|
||||
|
||||
Exclude faces, shells and solids from geometrical output. Implied when using `--plan` without `--model` in IfcConvert.
|
||||
|
||||
FASTER_BOOLEANS
|
||||
---------------
|
||||
|
||||
NOTE: Only applicable when using OCCT 6.9 and earlier.
|
||||
|
||||
This setting is available in IfcConvert using `--merge-boolean-operands`.
|
||||
|
||||
Fuse the collection of all boolean operands into a single union before applying the boolean subtraction, as opposed to doing individual subtractions. This likely improves performance. From OCCT 7.0 onwards the boolean operations with multiple arguments is used.
|
||||
|
||||
GENERATE_UVS
|
||||
------------
|
||||
|
||||
This setting is available in IfcConvert using `--generate-uvs`.
|
||||
|
||||
Applies a box projection on the generated geometry for the element to obtain UV coordinates. This is purely generated, it does not involve texture coordinates stored in the IFC model.
|
||||
|
||||
Duplex_A_20110907_optimized.ifc d5.dae --generate-uvs -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
|
||||
|
||||

|
||||
|
||||
INCLUDE_CURVES
|
||||
--------------
|
||||
|
||||
This setting is available in IfcConvert using `--plan`.
|
||||
|
||||
Include edge and wire geometries in the geometric output.
|
||||
|
||||
LAYERSET_FIRST
|
||||
--------------
|
||||
|
||||
This setting is available in IfcConvert using `--layerset-first`.
|
||||
|
||||
When not using APPLY_LAYERSETS, take the first material layer from the set to use as the material for the overall element.
|
||||
|
||||
NO_NORMALS
|
||||
----------
|
||||
|
||||
This setting is available in IfcConvert using `--no-normals`.
|
||||
|
||||
Do not emit normals on geometric output
|
||||
|
||||
SEARCH_FLOOR
|
||||
------------
|
||||
|
||||
Note: Only applicable to Collada .DAE output when used from IfcConvert.
|
||||
|
||||
This setting is available in IfcConvert using `--use-element-hierarchy`.
|
||||
|
||||
Include the spatial hierarchy in the elements.
|
||||
|
||||
SEW_SHELLS
|
||||
----------
|
||||
|
||||
This setting is available in IfcConvert using `--orient-shells`.
|
||||
|
||||
Re-orient or sew connected face sets to have a consistent outwards orientation.
|
||||
|
||||
SITE_LOCAL_PLACEMENT
|
||||
--------------------
|
||||
|
||||
This setting is available in IfcConvert using `--site-local-placement`.
|
||||
|
||||
See `BUILDING_LOCAL_PLACEMENT`, but exclude also the ObjectPlacement of the IfcSite.
|
||||
|
||||
USE_BREP_DATA
|
||||
-------------
|
||||
|
||||
See `DISABLE_TRIANGULATION`.
|
||||
|
||||
USE_PYTHON_OPENCASCADE
|
||||
----------------------
|
||||
|
||||
Note: Only available when an import of `OCC.Core.BRepTools` or `OCC.BRepTools` succeeds.
|
||||
|
||||
This implies `USE_WORLD_COORDS` `USE_BREP_DATA` and `DISABLE_TRIANGULATION`. The serialized TopoDS_Shape of `USE_BREP_DATA` is deserialized by Python OpenCASCADE.
|
||||
|
||||
USE_WORLD_COORDS
|
||||
----------------
|
||||
|
||||
Apply the ObjectPlacement of the building elements to the geometric output. This is implied when using the Wavefront .OBJ output in IfcConvert. Note that this also eliminates the possibility for geometric elements to point to the same interpreted geometry result.
|
||||
|
||||
VALIDATE_QUANTITIES
|
||||
-------------------
|
||||
|
||||
This setting is available in IfcConvert using `--validate`.
|
||||
|
||||
Running IfcConvert with `--validate` will set a non-zero exit code when ever a log message with severity equal or greater than ERROR has been emitted.
|
||||
|
||||
Currently for internal use only. For every building element geometry converted, looks for an associated quantity set where the OwnerHistory's organization name is IfcOpenShell. And looks for the quantities "Total Surface Area", "Volume", "Shape Validation Properties.Surface Genus" and validates these according to the interpreted geometry definition. Emit Logger::Error when calculated values are outside of the tolerance range for the value stored in the model.
|
||||
|
||||
WELD_VERTICES
|
||||
-------------
|
||||
|
||||
Note: In Python, this setting is *on* by default.
|
||||
|
||||
Note: This setting only affects triangulated output.
|
||||
|
||||
This setting is available in IfcConvert using `--weld-vertices`.
|
||||
|
||||
Discards normals and joins vertices solely based on position. This is useful when output is to be modified in a modeling application.
|
||||
|
||||
>>> import ifcopenshell, ifcopenshell.geom
|
||||
>>> s = ifcopenshell.geom.settings()
|
||||
>>> s.set(s.WELD_VERTICES, False)
|
||||
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
|
||||
>>> c = f["3bXiCStxP6Fgxdej$yc50U"]
|
||||
>>> shp = ifcopenshell.geom.create_shape(s, c)
|
||||
>>> shp.geometry.verts
|
||||
(4.675000000000003, -8.07499999999999, 2.657, 4.674999999999999, -10.24600000000002, 2.657, 6.226000000000004, -8.074999999999996, 2.657, 6.226, -10.24600000000003, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 4.674999999999999, -10.24600000000002, 2.6, 6.226000000000004, -8.074999999999996, 2.6, 6.226, -10.24600000000003, 2.6, 4.674999999999999, -10.24600000000002, 2.657, 4.674999999999999, -10.24600000000002, 2.6, 4.675000000000003, -8.07499999999999, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 6.226, -10.24600000000003, 2.657, 4.674999999999999, -10.24600000000002, 2.657, 6.226, -10.24600000000003, 2.6, 4.674999999999999, -10.24600000000002, 2.6, 6.226000000000004, -8.074999999999996, 2.657, 6.226, -10.24600000000003, 2.657, 6.226000000000004, -8.074999999999996, 2.6, 6.226, -10.24600000000003, 2.6, 4.675000000000003, -8.07499999999999, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 6.226000000000004, -8.074999999999996, 2.657, 6.226000000000004, -8.074999999999996, 2.6)
|
||||
>>> shp.geometry.normals
|
||||
(3.059754518198021e-17, 0.0, -1.0, 3.059754518198021e-17, 0.0, -1.0, 3.059754518198021e-17, 0.0, -1.0, 3.059754518198021e-17, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, 6.8717866127669046e-15, 1.0, 0.0, 6.8717866127669046e-15, 1.0, 0.0, 6.8717866127669046e-15, 1.0, 0.0, 6.8717866127669046e-15, 1.0, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, 3.4358933063834523e-15, 1.0, 0.0, 3.4358933063834523e-15, 1.0, 0.0, 3.4358933063834523e-15, 1.0, 0.0, 3.4358933063834523e-15, 1.0, 0.0)
|
||||
>>>
|
||||
>>> s.set(s.WELD_VERTICES, True)
|
||||
>>> shp = ifcopenshell.geom.create_shape(s, c)
|
||||
>>> shp.geometry.verts
|
||||
(4.675000000000003, -8.07499999999999, 2.657, 4.674999999999999, -10.24600000000002, 2.657, 6.226000000000004, -8.074999999999996, 2.657, 6.226, -10.24600000000003, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 4.674999999999999, -10.24600000000002, 2.6, 6.226000000000004, -8.074999999999996, 2.6, 6.226, -10.24600000000003, 2.6)
|
||||
>>> shp.geometry.normals
|
||||
()
|
||||
@@ -76,7 +76,7 @@ PROJECT_NAME = "IfcOpenShell"
|
||||
USE_CURRENT_PYTHON_VERSION = os.getenv("USE_CURRENT_PYTHON_VERSION")
|
||||
ADD_COMMIT_SHA = os.getenv("ADD_COMMIT_SHA")
|
||||
|
||||
PYTHON_VERSIONS = ["3.6.14", "3.7.13", "3.8.13", "3.9.11", "3.10.3", "3.11.0"]
|
||||
PYTHON_VERSIONS = ["3.9.11", "3.10.3", "3.11.8", "3.12.1"]
|
||||
JSON_VERSION = "v3.6.1"
|
||||
OCE_VERSION = "0.18.3"
|
||||
OCCT_VERSION = "7.5.3"
|
||||
@@ -254,6 +254,11 @@ if not os.path.exists(LOG_FILE):
|
||||
open(LOG_FILE, "w").close()
|
||||
logger.info(f"using command log file '{LOG_FILE}'")
|
||||
|
||||
# Causing havoc in python 3.11 build
|
||||
try:
|
||||
del os.environ['__PYVENV_LAUNCHER__']
|
||||
except: pass
|
||||
|
||||
def run(cmds, cwd=None, can_fail=False):
|
||||
|
||||
"""
|
||||
@@ -284,8 +289,9 @@ if platform.system() == "Darwin":
|
||||
# Apparently not supported
|
||||
PYTHON_VERSIONS = [pv for pv in PYTHON_VERSIONS if tuple(map(int, pv.split("."))) >= (3, 7)]
|
||||
if run(["sw_vers", "-productVersion"]) < "10.16":
|
||||
# Apparently not supported
|
||||
PYTHON_VERSIONS = [pv for pv in PYTHON_VERSIONS if tuple(map(int, pv.split("."))) < (3, 11)]
|
||||
# This is now solved with the '__PYVENV_LAUNCHER__' hack
|
||||
# PYTHON_VERSIONS = [pv for pv in PYTHON_VERSIONS if tuple(map(int, pv.split("."))) < (3, 11)]
|
||||
pass
|
||||
|
||||
BOOST_VERSION_UNDERSCORE = BOOST_VERSION.replace(".", "_")
|
||||
|
||||
@@ -892,8 +898,9 @@ if "IfcOpenShell-Python" in targets:
|
||||
module_dir = os.path.dirname(run([python_executable, "-c", "import inspect, ifcopenshell; print(inspect.getfile(ifcopenshell))"]))
|
||||
|
||||
if platform.system() != "Darwin":
|
||||
# TODO: This symbol name depends on the Python version?
|
||||
run([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", "_ifcopenshell_wrapper.so"], cwd=module_dir)
|
||||
if BUILD_CFG == "Release":
|
||||
# TODO: This symbol name depends on the Python version?
|
||||
run([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", "_ifcopenshell_wrapper.so"], cwd=module_dir)
|
||||
|
||||
return module_dir
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
VERSION:=`date '+%y%m%d'`
|
||||
SED:=sed -i
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
SED:=sed -i '' -e
|
||||
endif
|
||||
|
||||
.PHONY: ci
|
||||
ci:
|
||||
tox
|
||||
@@ -12,6 +18,13 @@ models:
|
||||
cd src && xsdata generate -p bcf.v2.model --unnest-classes --kw-only --slots -ds Google bcf/v2/xsd
|
||||
cd src && xsdata generate -p bcf.v3.model --unnest-classes --kw-only --slots -ds Google bcf/v3/xsd
|
||||
|
||||
.PHONY: dist
|
||||
dist:
|
||||
rm -rf dist
|
||||
$(SED) "s/999999/$(VERSION)/" pyproject.toml
|
||||
python -m build
|
||||
$(SED) "s/$(VERSION)/999999/" pyproject.toml
|
||||
|
||||
# .PHONY
|
||||
# api:
|
||||
# openapi-python-client generate --url https://api.swaggerhub.com/apis/buildingSMART/BCF/3.0
|
||||
# openapi-python-client generate --url https://api.swaggerhub.com/apis/buildingSMART/BCF/3.0
|
||||
@@ -1,84 +1,5 @@
|
||||
# bcf
|
||||
|
||||
A simple Python implementation of BCF.
|
||||
Manipulation of BCF-XML is available via `bcfxml.py` and manipulation of BCF-API
|
||||
is available via `bcfapi.py`.
|
||||
|
||||
It tries to support BCF-XML version 2.1 and 3.0, and BCF-API 3.0.
|
||||
|
||||
## bcfxml
|
||||
|
||||
The `bcfxml.load` function lets you read a BCF-XML file.
|
||||
It takes care of using the right version based on the "bcf.version" file contained in the BCF package.
|
||||
|
||||
The BCF files are extracted and parsed on-demand, and edits are stored in memory until you call the `save` method.
|
||||
|
||||
```python
|
||||
from bcf.bcfxml import load
|
||||
|
||||
# Load a project
|
||||
with load("/path/to/file.bcf") as bcfxml:
|
||||
project = bcfxml.project
|
||||
print(project.name)
|
||||
|
||||
# To edit a project, just modify the object directly
|
||||
bcfxml.project.name = "New name"
|
||||
|
||||
# Get a dictionary of topics
|
||||
topics = bcfxml.topics
|
||||
|
||||
for topic_guid, topic_handler in bcfxml.topics.items():
|
||||
topic = topic_handler.topic
|
||||
print("Topic guid is", topic.guid)
|
||||
print("Topic title is", topic.title)
|
||||
|
||||
# Fetch extra data about a topic
|
||||
header = topic_handler.header
|
||||
comments = topic_handler.comments
|
||||
viewpoints = topic_handler.viewpoints
|
||||
|
||||
for comment in comments:
|
||||
print(comment.guid)
|
||||
print(comment.comment)
|
||||
print(comment.author)
|
||||
|
||||
# Get a particular topic
|
||||
topic = bcfxml.get_topic(guid)
|
||||
|
||||
# Modify a topic
|
||||
topic.title = "New title"
|
||||
|
||||
bcfxml.save()
|
||||
```
|
||||
|
||||
## bcfapi
|
||||
|
||||
The `bcfapi` module lets you interact with the BCF-API standard.
|
||||
|
||||
```python
|
||||
from bcf.v3.bcfapi import FoundationClient, BcfClient
|
||||
|
||||
foundation_client = FoundationClient("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET", "OPENCDE_BASEURL")
|
||||
auth_methods = foundation_client.get_auth_methods()
|
||||
|
||||
# Our library currently only implements the authorization_code flow
|
||||
if "authorization_code" in auth_methods:
|
||||
foundation_client.login()
|
||||
|
||||
bcf_client = BcfClient(foundation_client)
|
||||
|
||||
versions = foundation_client.get_versions()
|
||||
for version in versions:
|
||||
if "3.0" in versions:
|
||||
if version["api_id"] == "bcf" and version["version_id"] == "3.0":
|
||||
bcf_client.set_version(version)
|
||||
|
||||
data = bcf_client.get_projects()
|
||||
print(data)
|
||||
project_id = data[0]["project_id"]
|
||||
print(project_id)
|
||||
data = bcf_client.get_project(project_id)
|
||||
print(data)
|
||||
data = bcf_client.get_extensions(project_id)
|
||||
print(data)
|
||||
```
|
||||
A simple Python implementation of the BCF standard. Manipulation of BCF-XML is
|
||||
available via `bcfxml.py` and manipulation of BCF-API is available via
|
||||
`bcfapi.py`.
|
||||
|
||||
@@ -17,7 +17,7 @@ dependencies = [
|
||||
"numpy",
|
||||
"ifcopenshell",
|
||||
]
|
||||
version = "0.0.1"
|
||||
version = "0.0.999999"
|
||||
classifiers = [
|
||||
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
||||
"Operating System :: OS Independent",
|
||||
@@ -76,7 +76,7 @@ deps =
|
||||
black
|
||||
isort
|
||||
pylint
|
||||
commands =
|
||||
commands =
|
||||
black {posargs:.}
|
||||
isort {posargs:.}
|
||||
pylint {posargs:.} --output-format=colorized
|
||||
@@ -138,4 +138,4 @@ max-attributes = 10
|
||||
|
||||
[tool.pylint.format]
|
||||
expected-line-ending-format = "LF"
|
||||
max-line-length = 120
|
||||
max-line-length = 120
|
||||
@@ -38,113 +38,86 @@ endif
|
||||
VERSION:=`date '+%y%m%d'`
|
||||
LAST_COMMIT_HASH:=$(shell git rev-parse HEAD)
|
||||
PYVERSION:=py310
|
||||
PYPI_IMP:=cp
|
||||
|
||||
ifeq ($(PYVERSION), py39)
|
||||
PYLIBDIR:=python3.9
|
||||
PYNUMBER:=39
|
||||
PYPI_VERSION:=3.9
|
||||
endif
|
||||
ifeq ($(PYVERSION), py310)
|
||||
PYLIBDIR:=python3.10
|
||||
PYNUMBER:=310
|
||||
PYPI_VERSION:=3.10
|
||||
endif
|
||||
ifeq ($(PYVERSION), py311)
|
||||
PYLIBDIR:=python3.11
|
||||
PYNUMBER:=311
|
||||
PYPI_VERSION:=3.11
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), linux)
|
||||
ifeq ($(PYVERSION), py39)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/linux-64/hpp-fcl-2.3.4-py39h40a70d0_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/linux-64/eigenpy-3.1.0-py39hdfdd6bb_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/linux-64/boost-1.78.0-py39h7c9e3ff_4.tar.bz2
|
||||
QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/linux-64/qhull-2020.2-h4bd325d_2.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/19/d9/a69c6aff5673554df48120565a14a50eaa41d29ae03b02faa0b023666318/lxml-4.6.3-cp39-cp39-manylinux2014_x86_64.whl
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/2d/f2/8ec281d357e8bb7d08dc8d727f0e4c8ef3dae7d3fa75c69c8e452bb82d50/shapely-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/01/61/3ff85fb4bb596ce3d223c8fcf93c8df5c12bc8899dfb4fb3cb1c5b20dd5f/Pillow-9.2.0-cp39-cp39-manylinux_2_28_x86_64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py310)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/linux-64/hpp-fcl-2.3.4-py310h995690b_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/linux-64/eigenpy-3.1.0-py310hf02b7e0_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/linux-64/boost-1.78.0-py310hc4a4660_4.tar.bz2
|
||||
QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/linux-64/qhull-2020.2-h4bd325d_2.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/25/1e/19b46d8e8881fe0df2e20945d51919eeb1817836d62a90efa8506530e45c/lxml-4.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/a8/a5/403728b5614b28083f6424dfdefec5fcf58068495fb03bb08532671c642f/shapely-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/f6/51/320986ebd6d46a0e95c2240468ced73153b691ce07617078bcdf30c609ec/Pillow-9.2.0-cp310-cp310-manylinux_2_28_x86_64.whl
|
||||
endif
|
||||
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/linux-64/assimp-5.0.1-hedfc422_6.tar.bz2
|
||||
OCTOMAP_URL:=https://anaconda.org/conda-forge/octomap/1.9.8/download/linux-64/octomap-1.9.8-h924138e_0.tar.bz2
|
||||
BOOSTCPP_URL:=https://anaconda.org/conda-forge/boost-cpp/1.78.0/download/linux-64/boost-cpp-1.78.0-h6582d0a_3.conda
|
||||
ZLIB_URL:=https://anaconda.org/conda-forge/zlib/1.2.11/download/linux-64/zlib-1.2.11-h516909a_1010.tar.bz2
|
||||
PYPI_PLATFORM:=--platform manylinux_2_17_x86_64
|
||||
LXML_ARCH:=manylinux_2_28_x86_64
|
||||
SHAPELY_ARCH:=manylinux_2_17_x86_64.manylinux2014_x86_64
|
||||
PILLOW_ARCH:=manylinux_2_28_x86_64
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), macos)
|
||||
PYPI_PLATFORM:=--platform macosx_10_9_x86_64
|
||||
SHAPELY_ARCH:=macosx_10_9_x86_64
|
||||
PILLOW_ARCH:=macosx_10_10_x86_64
|
||||
ifeq ($(PYVERSION), py39)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-64/hpp-fcl-2.3.4-py39hd85b194_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-64/eigenpy-3.1.0-py39hc4d6e28_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-64/boost-1.78.0-py39h953a6b8_4.tar.bz2
|
||||
QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/osx-64/qhull-2020.2-h940c156_2.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/b8/74/a71f7ad72e8db54ce899efab84507b801660750cbbfa6a39e6717557d36a/lxml-4.6.3-cp39-cp39-macosx_10_9_x86_64.whl
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/36/a4/7e542a209f862f967d7cb8e939eff155f4294a27d17e16441fb8bdd51a2c/shapely-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/88/7a/ddfe28b485b623361457d4783007c1f9ba83a87f93e7fec32f64793efb6c/Pillow-9.2.0-cp39-cp39-macosx_10_10_x86_64.whl
|
||||
LXML_ARCH:=macosx_11_0_x86_64
|
||||
endif
|
||||
ifeq ($(PYVERSION), py310)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-64/hpp-fcl-2.3.4-py310h1db6f5f_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-64/eigenpy-3.1.0-py310h43da829_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-64/boost-1.78.0-py310h3e792ce_4.tar.bz2
|
||||
QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/osx-64/qhull-2020.2-h940c156_2.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/a1/44/17b7dac7a18807d30e2fe10c3328c152808f5464565e230bfd0e77f178c6/lxml-4.8.0-cp310-cp310-macosx_10_15_x86_64.whl
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/1f/2a/dc3353c2431cf53e8d04bb8fba27e584410ca3435c9c85f76d71bf0c0e80/shapely-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/d8/60/b13c00d403f34110e96c1b5c0afa73ce461efe3fe960c3a7e3e7fe190d82/Pillow-9.2.0-cp310-cp310-macosx_10_10_x86_64.whl
|
||||
LXML_ARCH:=macosx_11_0_x86_64
|
||||
endif
|
||||
ifeq ($(PYVERSION), py311)
|
||||
LXML_ARCH:=macosx_11_0_universal2
|
||||
endif
|
||||
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/osx-64/assimp-5.0.1-h1224e73_6.tar.bz2
|
||||
OCTOMAP_URL:=https://anaconda.org/conda-forge/octomap/1.9.8/download/osx-64/octomap-1.9.8-hb8565cd_0.tar.bz2
|
||||
BOOSTCPP_URL:=https://anaconda.org/conda-forge/boost-cpp/1.78.0/download/osx-64/boost-cpp-1.78.0-hf5ba120_3.conda
|
||||
ZLIB_URL:=https://anaconda.org/conda-forge/zlib/1.2.11/download/osx-64/zlib-1.2.11-h7795811_1010.tar.bz2
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
ifeq ($(PYVERSION), py39)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-arm64/hpp-fcl-2.3.4-py39hc34188a_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-arm64/eigenpy-3.1.0-py39h13cfc01_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-arm64/boost-1.78.0-py39h99de9ae_4.tar.bz2
|
||||
QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/osx-arm64/qhull-2020.2-hc021e02_2.tar.bz2
|
||||
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py39h9eb174b_0.tar.bz2
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/ea/aa/45fbd031edf3149cb767d8b9f9db45d5faf0324d743c6b8fb0298cc022d0/shapely-2.0.1-cp39-cp39-macosx_11_0_arm64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/aa/bc/21097cd891dd2fa02f2b3d767e02e883e026482e59d29975d1bc30024aa3/Pillow-9.2.0-cp39-cp39-macosx_11_0_arm64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py310)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-arm64/hpp-fcl-2.3.4-py310h46fc4cd_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-arm64/eigenpy-3.1.0-py310ha2643af_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-arm64/boost-1.78.0-py310h629746b_4.tar.bz2
|
||||
QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/osx-arm64/qhull-2020.2-hc021e02_2.tar.bz2
|
||||
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py310h02f21da_0.tar.bz2
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/ec/41/d59208743e737184e1b403e95a937aebb022b8459e99efbcd5208fc8be46/shapely-2.0.1-cp310-cp310-macosx_11_0_arm64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/0c/5f/117b653cad585f3aedfe0de996c292e67d4b020ed77f652e5a6c8c24f908/Pillow-9.2.0-cp310-cp310-macosx_11_0_arm64.whl
|
||||
endif
|
||||
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/osx-arm64/assimp-5.0.1-h0f81e16_7.tar.bz2
|
||||
OCTOMAP_URL:=https://anaconda.org/conda-forge/octomap/1.9.8/download/osx-arm64/octomap-1.9.8-hffc8910_0.tar.bz2
|
||||
BOOSTCPP_URL:=https://anaconda.org/conda-forge/boost-cpp/1.78.0/download/osx-arm64/boost-cpp-1.78.0-h9ed8d21_3.conda
|
||||
ZLIB_URL:=https://anaconda.org/conda-forge/zlib/1.2.11/download/osx-arm64/zlib-1.2.11-h90dfc92_1014.tar.bz2
|
||||
PYPI_PLATFORM:=--platform macosx_11_0_arm64
|
||||
LXML_ARCH:=macosx_11_0_universal2
|
||||
SHAPELY_ARCH:=macosx_11_0_arm64
|
||||
PILLOW_ARCH:=macosx_11_0_arm64
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), win)
|
||||
PYPI_PLATFORM:=--platform win_amd64
|
||||
LXML_ARCH:=win_amd64
|
||||
SHAPELY_ARCH:=win_amd64
|
||||
PILLOW_ARCH:=win_amd64
|
||||
endif
|
||||
|
||||
LXML_NAME:=lxml
|
||||
LXML_VER:=4.9.4
|
||||
SHAPELY_NAME:=shapely
|
||||
SHAPELY_VER:=2.0.2
|
||||
PILLOW_NAME:=pillow
|
||||
PILLOW_PKG_NAME:=Pillow
|
||||
PILLOW_VER:=9.5.0
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/cp$(PYNUMBER)/s/$(SHAPELY_NAME)/$(SHAPELY_NAME)-$(SHAPELY_VER)-cp$(PYNUMBER)-cp$(PYNUMBER)-$(SHAPELY_ARCH).whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/cp$(PYNUMBER)/p/$(PILLOW_NAME)/$(PILLOW_PKG_NAME)-$(PILLOW_VER)-cp$(PYNUMBER)-cp$(PYNUMBER)-$(PILLOW_ARCH).whl
|
||||
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
ifeq ($(PYVERSION), py39)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/win-64/hpp-fcl-2.3.4-py39h39b25cb_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/win-64/eigenpy-3.1.0-py39hb6c915b_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/win-64/boost-1.78.0-py39hea4d8d1_4.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/72/d4/426ecb8849c47c3e370c87aa0ac05d85768df917ffea27fcd6686a5e6495/lxml-4.6.3-cp39-cp39-win_amd64.whl
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/a7/ae/eab645c4075093584b7a65ab71cb8ff4563a015bd935c9b55dba14b2c1eb/shapely-2.0.1-cp39-cp39-win_amd64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/19/3f/b4d4bcf05dbcbe07f2e9613a8f4180c297395e73a91d8ad22c32c6624f8c/Pillow-9.2.0-cp39-cp39-win_amd64.whl
|
||||
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py39h0520ce3_1.tar.bz2
|
||||
endif
|
||||
ifeq ($(PYVERSION), py310)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/win-64/hpp-fcl-2.3.4-py310heb59267_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/win-64/eigenpy-3.1.0-py310hd146abe_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/win-64/boost-1.78.0-py310h220cb41_4.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/f6/71/65c80a4caa1617a4c6e8fe1500cebb179db96232e2f623bfe6a1f4294e39/lxml-4.8.0-cp310-cp310-win_amd64.whl
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/81/8a/7ac076a86b2632f1872284c5e60ed5f2fc26094875a85b35d9fa17b52504/shapely-2.0.1-cp310-cp310-win_amd64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/02/55/67a3c17b9e7d972ed8c246f104da99ca4f3ea42fba566697e479011b84b6/Pillow-9.2.0-cp310-cp310-win_amd64.whl
|
||||
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py310h02f21da_0.tar.bz2
|
||||
endif
|
||||
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/win-64/assimp-5.0.1-hc2aa0de_6.tar.bz2
|
||||
OCTOMAP_URL:=https://anaconda.org/conda-forge/octomap/1.9.8/download/win-64/octomap-1.9.8-h91493d7_0.tar.bz2
|
||||
BOOSTCPP_URL:=https://anaconda.org/conda-forge/boost-cpp/1.78.0/download/win-64/boost-cpp-1.78.0-h9f4b32c_3.conda
|
||||
ZLIB_URL:=https://anaconda.org/conda-forge/zlib/1.2.11/download/win-64/zlib-1.2.11-h62dcd97_1010.tar.bz2
|
||||
ifeq ($(PYVERSION), py311)
|
||||
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py311h246f609_1.tar.bz2
|
||||
endif
|
||||
else
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/cp$(PYNUMBER)/l/$(LXML_NAME)/$(LXML_NAME)-$(LXML_VER)-cp$(PYNUMBER)-cp$(PYNUMBER)-$(LXML_ARCH).whl
|
||||
endif
|
||||
$(info $$LXML_URL is [${LXML_URL}])
|
||||
$(info $$SHAPELY_URL is [${SHAPELY_URL}])
|
||||
$(info $$PILLOW_URL is [${PILLOW_URL}])
|
||||
|
||||
.PHONY: bump
|
||||
bump:
|
||||
@@ -164,7 +137,7 @@ endif
|
||||
cp -r blenderbim/* dist/blenderbim/
|
||||
|
||||
# Provides IfcOpenShell Python functionality
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-fc50bdd-$(PLATFORM)64.zip
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-e38eafd-$(PLATFORM)64.zip
|
||||
cd dist/working && unzip ifcopenshell-python*
|
||||
cp -r dist/working/ifcopenshell dist/blenderbim/libs/site/packages/
|
||||
|
||||
@@ -194,8 +167,10 @@ endif
|
||||
cp -r dist/working/IfcOpenShell-0.7.0/src/ifcbimtester/bimtester dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCTester functionality
|
||||
cp -r dist/working/IfcOpenShell-0.7.0/src/ifctester/ifctester dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCCOBie functionality
|
||||
cp -r dist/working/IfcOpenShell-0.7.0/src/ifccobie/* dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCFM functionality
|
||||
cp -r dist/working/IfcOpenShell-0.7.0/src/ifcfm/ifcfm dist/blenderbim/libs/site/packages/
|
||||
# Provides bSDD functionality
|
||||
cp -r dist/working/IfcOpenShell-0.7.0/src/bsdd/* dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCDiff functionality
|
||||
cp -r dist/working/IfcOpenShell-0.7.0/src/ifcdiff/* dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCCSV functionality
|
||||
@@ -376,6 +351,12 @@ endif
|
||||
mkdir dist/working
|
||||
cd dist/working && $(PYTHON) -m venv env
|
||||
cd dist/working && mkdir site-packages
|
||||
# Required by IfcCSV
|
||||
cd dist/working && . env/bin/activate && $(PIP) install pandas $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --target=./site-packages
|
||||
# Pandas ships with very heavy tests
|
||||
cd dist/working/site-packages/pandas && rm -rf tests
|
||||
cd dist/working && . env/bin/activate && $(PIP) install openpyxl --target=./site-packages
|
||||
cd dist/working && . env/bin/activate && $(PIP) install odfpy --target=./site-packages
|
||||
# Required by IFCCityJSON
|
||||
cd dist/working && . env/bin/activate && $(PIP) install cjio --target=./site-packages
|
||||
# Provides express rule validation for ifcopenshell.validate
|
||||
@@ -385,156 +366,6 @@ endif
|
||||
cp -r dist/working/site-packages/* dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by IFCClash
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(HPPFCL_URL)
|
||||
cd dist/working && unzip hpp-fcl*
|
||||
cd dist/working && tar -I zstd -xvf pkg*
|
||||
ifeq ($(PLATFORM), linux)
|
||||
cp -r dist/working/lib/$(PYLIBDIR)/site-packages/hppfcl dist/blenderbim/libs/site/packages/
|
||||
cp -r dist/working/lib/*.so* dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macos)
|
||||
cp -r dist/working/lib/$(PYLIBDIR)/site-packages/hppfcl dist/blenderbim/libs/site/packages/
|
||||
cp -r dist/working/lib/*.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
cp -r dist/working/lib/$(PYLIBDIR)/site-packages/hppfcl dist/blenderbim/libs/site/packages/
|
||||
cp -r dist/working/lib/*.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), win)
|
||||
cp -r dist/working/Lib/site-packages/hppfcl dist/blenderbim/libs/site/packages/
|
||||
cp -r dist/working/Library/bin/*.dll dist/blenderbim/libs/site/packages/hppfcl/
|
||||
endif
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by hpp-fcl
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(ASSIMP_URL)
|
||||
cd dist/working && tar -xf assimp*
|
||||
ifeq ($(PLATFORM), linux)
|
||||
cp -r dist/working/lib/*.so* dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macos)
|
||||
cp -r dist/working/lib/*.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
cp -r dist/working/lib/*.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), win)
|
||||
cp -r dist/working/Library/bin/*.dll dist/blenderbim/libs/site/packages/hppfcl/
|
||||
endif
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by hpp-fcl except on Windows
|
||||
ifneq ($(PLATFORM), win)
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(QHULL_URL)
|
||||
cd dist/working && tar -xf qhull*
|
||||
ifeq ($(PLATFORM), linux)
|
||||
cp -r dist/working/lib/*.so* dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macos)
|
||||
cp -r dist/working/lib/*.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
cp -r dist/working/lib/*.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
rm -rf dist/working
|
||||
endif
|
||||
|
||||
# Required by hpp-fcl
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(EIGENPY_URL)
|
||||
cd dist/working && unzip eigenpy*
|
||||
cd dist/working && tar -I zstd -xvf pkg*
|
||||
ifeq ($(PLATFORM), linux)
|
||||
cp -r dist/working/lib/*.so* dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macos)
|
||||
cp -r dist/working/lib/*.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
cp -r dist/working/lib/*.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), win)
|
||||
cp -r dist/working/Library/bin/*.dll dist/blenderbim/libs/site/packages/hppfcl/
|
||||
endif
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by hpp-fcl
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(OCTOMAP_URL)
|
||||
cd dist/working && tar -xf octomap*
|
||||
ifeq ($(PLATFORM), linux)
|
||||
cp -r dist/working/lib/*.so* dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macos)
|
||||
cp -r dist/working/lib/*.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
cp -r dist/working/lib/*.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), win)
|
||||
# Uh, do nothing, apparently? No DLLs are shipped.
|
||||
endif
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by hpp-fcl
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(BOOST_URL)
|
||||
cd dist/working && tar -xf boost*
|
||||
ifeq ($(PLATFORM), linux)
|
||||
cp -r dist/working/lib/*.so* dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macos)
|
||||
cp -r dist/working/lib/*.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
cp -r dist/working/lib/*.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), win)
|
||||
cp -r dist/working/Library/bin/*.dll dist/blenderbim/libs/site/packages/hppfcl/
|
||||
endif
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by hpp-fcl
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(BOOSTCPP_URL)
|
||||
cd dist/working && unzip boost-cpp*
|
||||
cd dist/working && tar -I zstd -xvf pkg*
|
||||
ifeq ($(PLATFORM), linux)
|
||||
cp -r dist/working/lib/libboost_serialization.so* dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macos)
|
||||
cp -r dist/working/lib/libboost_serialization.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
cp -r dist/working/lib/libboost_serialization.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), win)
|
||||
cp -r dist/working/Library/bin/boost_serialization.dll dist/blenderbim/libs/site/packages/hppfcl/
|
||||
endif
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by hpp-fcl
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(ZLIB_URL)
|
||||
cd dist/working && tar -xf zlib*
|
||||
ifeq ($(PLATFORM), linux)
|
||||
cp -r dist/working/lib/*.so* dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macos)
|
||||
cp -r dist/working/lib/*.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
cp -r dist/working/lib/*.dylib dist/blenderbim/libs/
|
||||
endif
|
||||
ifeq ($(PLATFORM), win)
|
||||
cp -r dist/working/Library/bin/*.dll dist/blenderbim/libs/site/packages/hppfcl/
|
||||
endif
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by BIMTester
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/c8/4b/d0a8c23b6c8985e5544ea96d27105a273ea22051317f850c2cdbf2029fe4/behave-1.2.6.tar.gz
|
||||
@@ -582,56 +413,6 @@ endif
|
||||
cd dist/working/parse_type-0.5.2/ && cp -r parse_type ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by IFCCOBie for XLSX support
|
||||
# TODO: see if we can replace this with openpyxl which does both read/write
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/0c/bc/82d6783f83f65f56d8b77d052773c4a2f952fa86385f0cd54e1e006658d7/XlsxWriter-1.2.9.tar.gz
|
||||
cd dist/working && tar -xzvf XlsxWriter*
|
||||
cd dist/working/XlsxWriter-1.2.9/ && cp -r xlsxwriter ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by IFCCOBie for ODS support
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/97/73/8ade73f6749177003f7ce3304f524774adda96e6aaab30ea79fd8fda7934/odfpy-1.4.1.tar.gz
|
||||
cd dist/working && tar -xzvf odfpy*
|
||||
cd dist/working/odfpy-1.4.1/ && cp -r odf ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by odfpy
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/a4/5f/f8aa58ca0cf01cbcee728abc9d88bfeb74e95e6cb4334cfd5bed5673ea77/defusedxml-0.6.0.tar.gz
|
||||
cd dist/working && tar -xzvf defusedxml*
|
||||
cd dist/working/defusedxml-0.6.0/ && cp -r defusedxml ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by augin
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/76/b4/b7baffbda025efd5dc8fcd8d2e953e3aa939c236a484084fa8f4c3588ee9/boto3-1.17.17.tar.gz
|
||||
cd dist/working && tar -xzvf boto3*
|
||||
cd dist/working/boto3-1.17.17/ && cp -r boto3 ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by boto3
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/7f/2e/e02fdfd0f0377c4e44e61de27b05d5cfe93575770661ef9ded80ed90fa88/botocore-1.20.17.tar.gz
|
||||
cd dist/working && tar -xzvf botocore*
|
||||
cd dist/working/botocore-1.20.17/ && cp -r botocore ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by boto3
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/3c/56/3f325b1eef9791759784aa5046a8f6a1aff8f7c898a2e34506771d3b99d8/jmespath-0.10.0.tar.gz
|
||||
cd dist/working && tar -xzvf jmespath*
|
||||
cd dist/working/jmespath-0.10.0/ && cp -r jmespath ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by boto3
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/08/e1/3ee2096ebaeeb8c186d20ed16c8faf4a503913e5c9a0e14cd6b8ffc405a3/s3transfer-0.3.4.tar.gz
|
||||
cd dist/working && tar -xzvf s3transfer*
|
||||
cd dist/working/s3transfer-0.3.4/ && cp -r s3transfer ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides IFCJSON functionality
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://github.com/IFCJSON-Team/IFC2JSON_python/archive/master.zip
|
||||
@@ -639,13 +420,6 @@ endif
|
||||
cp -r dist/working/IFC2JSON_python-master/file_converters/ifcjson dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides OpenLCA functionality
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/85/33/f91b96e9e8608ff65a003b692e8a9cdd60f2178f60617e5b1d21334c009c/olca-ipc-0.0.10.tar.gz
|
||||
cd dist/working && tar -xzvf olca-ipc*
|
||||
cd dist/working/olca-ipc-0.0.10/ && cp -r olca ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides Brickschema functionality
|
||||
mkdir dist/working
|
||||
# For now lets bundle the latest nightly schema
|
||||
@@ -671,11 +445,17 @@ endif
|
||||
# Required for Desktop icon and file association
|
||||
cp -r blenderbim/libs/desktop dist/blenderbim/libs/
|
||||
|
||||
# Generate translations module for BBIM build
|
||||
git clone https://github.com/IfcOpenShell/blenderbim-translations.git dist/working
|
||||
$(PYTHON) scripts/bbim_translations.py -i "dist/working" -o "dist/blenderbim"
|
||||
rm -rf dist/working
|
||||
|
||||
# Remove dependencies also bundled with Blender
|
||||
rm -rf dist/blenderbim/libs/site/packages/numpy
|
||||
rm -rf dist/blenderbim/libs/site/packages/numpy.libs
|
||||
|
||||
cd dist/blenderbim && $(SED) "s/999999/$(VERSION)/" __init__.py
|
||||
cd dist/blenderbim && $(SED) "s/999999/$(VERSION)/" blender_manifest.toml
|
||||
cd dist/blenderbim/bim && $(SED) "s/8888888/$(LAST_COMMIT_HASH)/" __init__.py
|
||||
cd dist && zip -r blenderbim-$(VERSION)-$(PYVERSION)-$(PLATFORM).zip ./*
|
||||
rm -rf dist/blenderbim
|
||||
|
||||
@@ -24,12 +24,17 @@ import blenderbim
|
||||
import importlib
|
||||
from . import handler, ui, prop, operator, helper
|
||||
|
||||
try:
|
||||
from blenderbim.translations import translations_dict
|
||||
except ImportError:
|
||||
translations_dict = {}
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
modules = {
|
||||
"project": None,
|
||||
"search": None,
|
||||
"bcf": None,
|
||||
"bsdd": None,
|
||||
"root": None,
|
||||
"unit": None,
|
||||
"model": None,
|
||||
@@ -43,8 +48,9 @@ modules = {
|
||||
"spatial": None,
|
||||
"void": None,
|
||||
"aggregate": None,
|
||||
"nest": None,
|
||||
"geometry": None,
|
||||
"cobie": None,
|
||||
"fm": None,
|
||||
"resource": None,
|
||||
"cost": None,
|
||||
"sequence": None,
|
||||
@@ -66,7 +72,6 @@ modules = {
|
||||
"document": None,
|
||||
"pset_template": None,
|
||||
"clash": None,
|
||||
"lca": None,
|
||||
"csv": None,
|
||||
"tester": None,
|
||||
"bimtester": None,
|
||||
@@ -77,6 +82,7 @@ modules = {
|
||||
"augin": None,
|
||||
"debug": None,
|
||||
"ifcgit": None,
|
||||
"covering": None,
|
||||
# Uncomment this line to enable loading of the demo module. Happy hacking!
|
||||
# The name "demo" must correlate to a folder name in `bim/module/`.
|
||||
# "demo": None,
|
||||
@@ -90,28 +96,30 @@ for name in modules.keys():
|
||||
classes = [
|
||||
operator.AddIfcFile,
|
||||
operator.BIM_OT_add_section_plane,
|
||||
operator.BIM_OT_open_webbrowser,
|
||||
operator.BIM_OT_remove_section_plane,
|
||||
operator.OpenUpstream,
|
||||
operator.OpenUri,
|
||||
operator.SwitchTab,
|
||||
operator.SetTab,
|
||||
operator.ReloadIfcFile,
|
||||
operator.RemoveIfcFile,
|
||||
operator.SelectDataDir,
|
||||
operator.SelectIfcFile,
|
||||
operator.ReloadSelectedIfcFile,
|
||||
operator.SelectSchemaDir,
|
||||
operator.BIM_OT_show_description,
|
||||
operator.ClippingPlaneCutWithCappings,
|
||||
operator.EditBlenderCollection,
|
||||
operator.FileAssociate,
|
||||
operator.FileUnassociate,
|
||||
operator.OpenUpstream,
|
||||
operator.OpenUri,
|
||||
operator.ReloadIfcFile,
|
||||
operator.RemoveIfcFile,
|
||||
operator.RevertClippingPlaneCut,
|
||||
operator.SelectDataDir,
|
||||
operator.SelectIfcFile,
|
||||
operator.SelectSchemaDir,
|
||||
operator.SelectURIAttribute,
|
||||
operator.EditBlenderCollection,
|
||||
operator.BIM_OT_open_webbrowser,
|
||||
operator.BIM_OT_show_description,
|
||||
operator.SetTab,
|
||||
operator.SwitchTab,
|
||||
prop.StrProperty,
|
||||
operator.BIM_OT_enum_property_search, # /!\ Register AFTER prop.StrProperty
|
||||
prop.ObjProperty,
|
||||
prop.Attribute,
|
||||
prop.BIMAreaProperties,
|
||||
prop.BIMTabProperties,
|
||||
prop.BIMProperties,
|
||||
prop.IfcParameter,
|
||||
prop.PsetQto,
|
||||
@@ -120,40 +128,56 @@ classes = [
|
||||
prop.BIMCollectionProperties,
|
||||
prop.BIMMaterialProperties,
|
||||
prop.BIMMeshProperties,
|
||||
prop.BIMFacet,
|
||||
prop.BIMFilterGroup,
|
||||
ui.BIM_UL_generic,
|
||||
ui.BIM_UL_topics,
|
||||
ui.BIM_ADDON_preferences,
|
||||
# Project overview
|
||||
ui.BIM_PT_project_info,
|
||||
ui.BIM_PT_project_setup,
|
||||
ui.BIM_PT_geometry,
|
||||
ui.BIM_PT_tab_grouping_and_filtering,
|
||||
# Tabs panel
|
||||
ui.BIM_PT_tabs,
|
||||
# Project overview
|
||||
ui.BIM_PT_tab_project_info,
|
||||
ui.BIM_PT_tab_project_setup,
|
||||
ui.BIM_PT_tab_geometry,
|
||||
ui.BIM_PT_tab_stakeholders,
|
||||
ui.BIM_PT_tab_grouping_and_filtering,
|
||||
# Object information
|
||||
ui.BIM_PT_tab_object_metadata,
|
||||
ui.BIM_PT_tab_misc,
|
||||
# Geometry and materials
|
||||
ui.BIM_PT_tab_placement,
|
||||
ui.BIM_PT_tab_representations,
|
||||
ui.BIM_PT_tab_geometric_relationships,
|
||||
ui.BIM_PT_tab_parametric_geometry,
|
||||
ui.BIM_PT_tab_profiles,
|
||||
ui.BIM_PT_tab_materials,
|
||||
ui.BIM_PT_tab_styles,
|
||||
# Drawings and documents
|
||||
ui.BIM_PT_tab_sheets,
|
||||
ui.BIM_PT_tab_drawings,
|
||||
ui.BIM_PT_tab_schedules,
|
||||
ui.BIM_PT_tab_references,
|
||||
# Services and systems
|
||||
ui.BIM_PT_tab_services,
|
||||
ui.BIM_PT_tab_services_object,
|
||||
ui.BIM_PT_tab_zones,
|
||||
# Structural analysis
|
||||
ui.BIM_PT_tab_structural,
|
||||
# Construction scheduling
|
||||
ui.BIM_PT_tab_status,
|
||||
ui.BIM_PT_tab_resources,
|
||||
ui.BIM_PT_tab_cost,
|
||||
ui.BIM_PT_tab_sequence,
|
||||
# Facility management
|
||||
ui.BIM_PT_tab_handover,
|
||||
ui.BIM_PT_tab_operations,
|
||||
# Quality and coordination
|
||||
ui.BIM_PT_tab_quality_control,
|
||||
ui.BIM_PT_tab_clash_detection,
|
||||
ui.BIM_PT_tab_collaboration,
|
||||
ui.BIM_PT_tab_sandbox,
|
||||
# TODO: move this somewhere else and clean it up
|
||||
ui.BIM_PT_section_plane,
|
||||
ui.BIM_PT_section_with_cappings,
|
||||
]
|
||||
|
||||
for mod in modules.values():
|
||||
@@ -163,6 +187,7 @@ addon_keymaps = []
|
||||
icons = None
|
||||
is_registering = False
|
||||
last_commit_hash = "8888888"
|
||||
overridden_scene_panels = dict()
|
||||
|
||||
|
||||
def on_register(scene):
|
||||
@@ -187,6 +212,7 @@ def register():
|
||||
bpy.app.handlers.load_post.append(handler.loadIfcStore)
|
||||
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
|
||||
bpy.types.Screen.BIMAreaProperties = bpy.props.CollectionProperty(type=prop.BIMAreaProperties)
|
||||
bpy.types.Screen.BIMTabProperties = bpy.props.PointerProperty(type=prop.BIMTabProperties)
|
||||
bpy.types.Collection.BIMCollectionProperties = bpy.props.PointerProperty(type=prop.BIMCollectionProperties)
|
||||
bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
|
||||
bpy.types.Material.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
|
||||
@@ -204,8 +230,8 @@ def register():
|
||||
|
||||
wm = bpy.context.window_manager
|
||||
if wm.keyconfigs.addon:
|
||||
km = wm.keyconfigs.addon.keymaps.new(name='Window', space_type='EMPTY')
|
||||
kmi = km.keymap_items.new('bim.switch_tab', 'TAB', 'PRESS', ctrl=True)
|
||||
km = wm.keyconfigs.addon.keymaps.new(name="Window", space_type="EMPTY")
|
||||
kmi = km.keymap_items.new("bim.switch_tab", "TAB", "PRESS", ctrl=True)
|
||||
addon_keymaps.append((km, kmi))
|
||||
|
||||
global icons
|
||||
@@ -223,12 +249,16 @@ def register():
|
||||
global last_commit_hash
|
||||
try:
|
||||
import git
|
||||
|
||||
path = Path(__file__).resolve().parent
|
||||
repo = git.Repo(str(path), search_parent_directories=True)
|
||||
last_commit_hash = repo.head.object.hexsha
|
||||
except:
|
||||
pass
|
||||
|
||||
bpy.app.translations.register("blenderbim", translations_dict)
|
||||
|
||||
|
||||
def unregister():
|
||||
global icons
|
||||
|
||||
@@ -265,16 +295,10 @@ def unregister():
|
||||
km.keymap_items.remove(kmi)
|
||||
addon_keymaps.clear()
|
||||
|
||||
for panel in [
|
||||
"SCENE_PT_scene",
|
||||
"SCENE_PT_unit",
|
||||
"SCENE_PT_physics",
|
||||
"SCENE_PT_rigid_body_world",
|
||||
"SCENE_PT_audio",
|
||||
"SCENE_PT_keying_sets",
|
||||
"SCENE_PT_custom_props",
|
||||
]:
|
||||
try:
|
||||
bpy.utils.unregister_class(getattr(handler, f"Override_{panel}"))
|
||||
except:
|
||||
pass
|
||||
for panel in tuple(overridden_scene_panels.keys()):
|
||||
original_panel, override_panel = overridden_scene_panels[panel]
|
||||
bpy.utils.unregister_class(override_panel)
|
||||
bpy.utils.register_class(original_panel)
|
||||
del overridden_scene_panels[panel]
|
||||
|
||||
bpy.app.translations.unregister("blenderbim")
|
||||
|
||||
@@ -44,17 +44,29 @@
|
||||
<circle r="5" fill="white" stroke="black" style="stroke-width: 0.25;" />
|
||||
<line x1="-5" y1="0" x2="5" y2="0" style="stroke: black; stroke-width: 0.25;" />
|
||||
</g>
|
||||
<g id="SurveyArea">
|
||||
<g id="dot">
|
||||
<circle r="1" fill="black" stroke="black" style="stroke-width: 0.25;" />
|
||||
</g>
|
||||
<g id="SurveyArea-CONTROLPOINT">
|
||||
<path style="fill: white; stroke: black; stroke-width: 0.25;" d="M 2.286165,1.4798666 H -1.0000316e-7 -2.2861651 L -1.1430826,-0.5000101 -1.0000316e-7,-2.479888 1.1430827,-0.5000101 Z" />
|
||||
<g id="setout-tag">
|
||||
<circle fill="white" stroke="black" r="2.5" style="stroke-width: 0.5"/>
|
||||
<path d="M 0 0 L -2.5 0 A 2.5 2.5 0 0 1 0 -2.5 Z" fill="black"/>
|
||||
<path d="M 0 0 L 2.5 0 A 2.5 2.5 0 0 1 0 2.5 Z" fill="black"/>
|
||||
<text x="3" y="-8" class="regular" text-anchor="start" dominant-baseline="auto" data-type="text-template"></text>
|
||||
<text x="3" y="-4" class="regular" text-anchor="start" dominant-baseline="auto" data-type="text-template"></text>
|
||||
</g>
|
||||
<g id="setout-point">
|
||||
<circle fill="white" stroke="black" r="2.5" style="stroke-width: 0.5"/>
|
||||
<path d="M 0 0 L -2.5 0 A 2.5 2.5 0 0 1 0 -2.5 Z" fill="black"/>
|
||||
<path d="M 0 0 L 2.5 0 A 2.5 2.5 0 0 1 0 2.5 Z" fill="black"/>
|
||||
</g>
|
||||
<g id="control-point">
|
||||
<path style="fill: white; stroke: black; stroke-width: 0.5;" d="M 2.286165,1.4798666 H -1.0000316e-7 -2.2861651 L -1.1430826,-0.5000101 -1.0000316e-7,-2.479888 1.1430827,-0.5000101 Z" />
|
||||
<circle r="0.5" fill="black" stroke="black" style="stroke-width: 0.25;" />
|
||||
</g>
|
||||
<g id="SurveyArea-TRAVERSEPOINT">
|
||||
<g id="traverse-point">
|
||||
<path style="fill: white; stroke: black; stroke-width: 0.5;" d="M -2,-2 2,2 M -2,2 2,-2" />
|
||||
</g>
|
||||
<g id="SurveyArea-SPOTELEVATION">
|
||||
<g id="spot-elevation">
|
||||
<path style="fill: white; stroke: black; stroke-width: 0.5;" d="M 0,-2 0,2 M -2,0 2,0" />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 4.2 KiB |
@@ -51,5 +51,5 @@ var json_data = `{{{json_data}}}`;
|
||||
<script>
|
||||
var data = `{{{data}}}`;
|
||||
setupPage(data);
|
||||
create_gantt_chart(json_data)
|
||||
</script>
|
||||
create_gantt_chart(atob(json_data))
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
ISO-10303-21;
|
||||
HEADER;
|
||||
FILE_DESCRIPTION(('ViewDefinition[DesignTransferView]'),'2;1');
|
||||
FILE_NAME('/dev/null','2023-07-30T21:07:33+10:00',(),(),'IfcOpenShell v0.7.0-8f41ae0c1','IfcOpenShell v0.7.0-8f41ae0c1','Nobody');
|
||||
FILE_NAME('/dev/null','2024-03-03T16:03:58+11:00',(),(),'IfcOpenShell v0.7.0-eaa2aa05a','IfcOpenShell v0.7.0-eaa2aa05a','Nobody');
|
||||
FILE_SCHEMA(('IFC4'));
|
||||
ENDSEC;
|
||||
DATA;
|
||||
#1=IFCPROJECT('0TszJmTqLCyxcP10DtK_MP',$,'BlenderBIM Demo',$,$,$,$,(#12,#16),#7);
|
||||
#2=IFCPROJECTLIBRARY('0Y_CJXSsbCgBlSGFw0mbLa',$,'BlenderBIM Demo Library',$,$,$,$,$,$);
|
||||
#3=IFCRELDECLARES('3IxQaOPH5Fx90CGmGm1gtQ',$,$,$,#1,(#2));
|
||||
#1=IFCPROJECT('3NJUxHyTzEv96oezyDYEqf',$,'BlenderBIM Demo',$,$,$,$,(#12,#16),#7);
|
||||
#2=IFCPROJECTLIBRARY('0D39k7hbT5ce$jWaCd2niG',$,'BlenderBIM Demo Library',$,$,$,$,$,$);
|
||||
#3=IFCRELDECLARES('2RWVohyP57PBHT9zCs4H2O',$,$,$,#1,(#2));
|
||||
#4=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
|
||||
#5=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
|
||||
#6=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.);
|
||||
@@ -23,84 +23,84 @@ DATA;
|
||||
#16=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Plan',2,1.E-05,#15,$);
|
||||
#17=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#12,$,.MODEL_VIEW.,$);
|
||||
#18=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Plan',*,*,*,*,#16,$,.PLAN_VIEW.,$);
|
||||
#19=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Plan',*,*,*,*,#16,$,.PLAN_VIEW.,$);
|
||||
#19=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Model',*,*,*,*,#16,$,.MODEL_VIEW.,$);
|
||||
#20=IFCMATERIAL('Unknown',$,$);
|
||||
#21=IFCWALLTYPE('3U0gAUglf9WBlcfpB15EK0',$,'WAL50',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#21=IFCWALLTYPE('2F1k78lI53fwS0rg3rqrRb',$,'WAL50',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#22=IFCMATERIALLAYERSET((#24),$,$);
|
||||
#23=IFCRELASSOCIATESMATERIAL('3J36H22Gz1ovVzdiKgApaM',$,$,$,(#21),#22);
|
||||
#23=IFCRELASSOCIATESMATERIAL('0khP_Smdj12f2JrOTRbRKj',$,$,$,(#21),#22);
|
||||
#24=IFCMATERIALLAYER(#20,0.05,$,$,$,$,$);
|
||||
#25=IFCRELDECLARES('28ApgMJzH10h$Ng$fmCpYf',$,$,$,#2,(#63,#21,#54,#87,#153,#34,#67,#210,#38,#82,#77,#42,#26,#48,#72,#59,#92,#30,#96));
|
||||
#26=IFCWALLTYPE('1wGfdUdC10TuASJo4jnO99',$,'WAL100',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#25=IFCRELDECLARES('31JriXdev6BP2sC9lcxdC1',$,$,$,#2,(#26,#48,#72,#59,#92,#30,#96,#63,#21,#54,#87,#210,#153,#34,#67,#38,#82,#77,#42));
|
||||
#26=IFCWALLTYPE('3R5onkTtX1IxdCMPoThRaw',$,'WAL100',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#27=IFCMATERIALLAYERSET((#29),$,$);
|
||||
#28=IFCRELASSOCIATESMATERIAL('0NRoxSQPzCgQHfsu5ru91z',$,$,$,(#26),#27);
|
||||
#28=IFCRELASSOCIATESMATERIAL('0$mXRPCT16nP6Q70XFNvZv',$,$,$,(#26),#27);
|
||||
#29=IFCMATERIALLAYER(#20,0.1,$,$,$,$,$);
|
||||
#30=IFCWALLTYPE('1lt5MuGLLDfwmZd0tNruF7',$,'WAL200',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#30=IFCWALLTYPE('1juanculbDJPqvqT2FCm8m',$,'WAL200',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#31=IFCMATERIALLAYERSET((#33),$,$);
|
||||
#32=IFCRELASSOCIATESMATERIAL('21rGVxPODC$xmWYFaDy1T6',$,$,$,(#30),#31);
|
||||
#32=IFCRELASSOCIATESMATERIAL('0FsB2A$frFn9AZW2IG38ny',$,$,$,(#30),#31);
|
||||
#33=IFCMATERIALLAYER(#20,0.2,$,$,$,$,$);
|
||||
#34=IFCWALLTYPE('0NZm1D8h12xAxyW7fL5nc1',$,'WAL300',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#34=IFCWALLTYPE('05UYduR9r1vRxZZgP64Rdw',$,'WAL300',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#35=IFCMATERIALLAYERSET((#37),$,$);
|
||||
#36=IFCRELASSOCIATESMATERIAL('2yvmN42crCJevtirp5cMeV',$,$,$,(#34),#35);
|
||||
#36=IFCRELASSOCIATESMATERIAL('2FYhYrvmv4SBoZHVWDTTte',$,$,$,(#34),#35);
|
||||
#37=IFCMATERIALLAYER(#20,0.3,$,$,$,$,$);
|
||||
#38=IFCCOVERINGTYPE('1eb4wZ_5n6xRGrs3rlKMiM',$,'COV10',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#38=IFCCOVERINGTYPE('0iLxgfHB9F2hRH2vMcw7Yv',$,'COV10',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#39=IFCMATERIALLAYERSET((#41),$,$);
|
||||
#40=IFCRELASSOCIATESMATERIAL('3HKIKf06T6xRqM6Lp69$OM',$,$,$,(#38),#39);
|
||||
#40=IFCRELASSOCIATESMATERIAL('0yvFX0zgb9uvJ3ARnf4mfe',$,$,$,(#38),#39);
|
||||
#41=IFCMATERIALLAYER(#20,0.01,$,$,$,$,$);
|
||||
#42=IFCCOVERINGTYPE('2E89aYmtrEfxhX_jsNqviN',$,'COV20',$,$,(#46),$,$,$,.NOTDEFINED.);
|
||||
#42=IFCCOVERINGTYPE('15Riw2WTrAUPwvfLyKXJ2g',$,'COV20',$,$,(#46),$,$,$,.NOTDEFINED.);
|
||||
#43=IFCMATERIALLAYERSET((#45),$,$);
|
||||
#44=IFCRELASSOCIATESMATERIAL('2115lEhhP4Z9G1Yhd_DqSC',$,$,$,(#42),#43);
|
||||
#44=IFCRELASSOCIATESMATERIAL('1iAOG6NK9FBxitFtzN9qP5',$,$,$,(#42),#43);
|
||||
#45=IFCMATERIALLAYER(#20,0.02,$,$,$,$,$);
|
||||
#46=IFCPROPERTYSET('0vtU63YmjAgg8DeHlTgNx7',$,'EPset_Parametric',$,(#47));
|
||||
#46=IFCPROPERTYSET('18ICCZ0fjDG9UXMyzrsFBA',$,'EPset_Parametric',$,(#47));
|
||||
#47=IFCPROPERTYSINGLEVALUE('LayerSetDirection',$,IFCLABEL('AXIS2'),$);
|
||||
#48=IFCCOVERINGTYPE('0XiSBI57L9Uf8f2NaQ_ksi',$,'COV30',$,$,(#52),$,$,$,.NOTDEFINED.);
|
||||
#48=IFCCOVERINGTYPE('0gEOtYULD0F9KD9zPoA6cJ',$,'COV30',$,$,(#52),$,$,$,.NOTDEFINED.);
|
||||
#49=IFCMATERIALLAYERSET((#51),$,$);
|
||||
#50=IFCRELASSOCIATESMATERIAL('3U3JdGAmbABA4mB$Fgpq1l',$,$,$,(#48),#49);
|
||||
#50=IFCRELASSOCIATESMATERIAL('0xd6dsjf13JA98q9fnAMpQ',$,$,$,(#48),#49);
|
||||
#51=IFCMATERIALLAYER(#20,0.03,$,$,$,$,$);
|
||||
#52=IFCPROPERTYSET('17nhQ5I4b9ZvhDu4gRJLKO',$,'EPset_Parametric',$,(#53));
|
||||
#52=IFCPROPERTYSET('3qCbs1tuDCvuOXam5RrA$a',$,'EPset_Parametric',$,(#53));
|
||||
#53=IFCPROPERTYSINGLEVALUE('LayerSetDirection',$,IFCLABEL('AXIS3'),$);
|
||||
#54=IFCRAMPTYPE('1BTHjVDP19tgb3MDCSkWCJ',$,'RAM200',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#54=IFCRAMPTYPE('2yW1ePlyb8cOR6HdEntpRh',$,'RAM200',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#55=IFCMATERIALLAYERSET((#57),$,$);
|
||||
#56=IFCRELASSOCIATESMATERIAL('3HN21bHtL16vvHA2GnnxH1',$,$,$,(#54),#55);
|
||||
#56=IFCRELASSOCIATESMATERIAL('1x9ZyVim19AQtJhfEE06XR',$,$,$,(#54),#55);
|
||||
#57=IFCMATERIALLAYER(#20,0.2,$,$,$,$,$);
|
||||
#58=IFCCIRCLEPROFILEDEF(.AREA.,$,$,0.3);
|
||||
#59=IFCPILETYPE('04_2WZSqH8TgT7ET6DCCpd',$,'P1',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#59=IFCPILETYPE('25MTkMtaH5QeCf$gFbvSSw',$,'P1',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#60=IFCMATERIALPROFILESET($,$,(#62),$);
|
||||
#61=IFCRELASSOCIATESMATERIAL('1qTZZRXsPF9hmYwT$tgFgp',$,$,$,(#59),#60);
|
||||
#61=IFCRELASSOCIATESMATERIAL('09FXUZCnrFEffxBrtg16gx',$,$,$,(#59),#60);
|
||||
#62=IFCMATERIALPROFILE($,$,#20,#58,$,$);
|
||||
#63=IFCSLABTYPE('3_OV9$Sd52KRhIW2TWIxbW',$,'FLR150',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#63=IFCSLABTYPE('1Akbal7tP5DAPW0ti$Qp30',$,'FLR150',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#64=IFCMATERIALLAYERSET((#66),$,$);
|
||||
#65=IFCRELASSOCIATESMATERIAL('1agyf45$X1NhR127pUL0Iw',$,$,$,(#63),#64);
|
||||
#65=IFCRELASSOCIATESMATERIAL('0jzkXlkBL4HhmQ_FTWW6Cj',$,$,$,(#63),#64);
|
||||
#66=IFCMATERIALLAYER(#20,0.2,$,$,$,$,$);
|
||||
#67=IFCSLABTYPE('0LvmpIGf9AVPcG$Kt06TEk',$,'FLR250',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#67=IFCSLABTYPE('0$gpYNi3T08BrxaR67CxgI',$,'FLR250',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#68=IFCMATERIALLAYERSET((#70),$,$);
|
||||
#69=IFCRELASSOCIATESMATERIAL('0EKQPSL656secN86SgeutH',$,$,$,(#67),#68);
|
||||
#69=IFCRELASSOCIATESMATERIAL('3a6kjEM29DleYTlSkA8_DK',$,$,$,(#67),#68);
|
||||
#70=IFCMATERIALLAYER(#20,0.3,$,$,$,$,$);
|
||||
#71=IFCRECTANGLEPROFILEDEF(.AREA.,'500x600',$,0.5,0.6);
|
||||
#72=IFCCOLUMNTYPE('1SI8m9m813tAXfSnM1fCbm',$,'C1',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#72=IFCCOLUMNTYPE('278sjptdDDzgOZseERj390',$,'C1',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#73=IFCMATERIALPROFILESET($,$,(#75),$);
|
||||
#74=IFCRELASSOCIATESMATERIAL('1EhwSTRtPBQgBt2x6dhuT$',$,$,$,(#72),#73);
|
||||
#74=IFCRELASSOCIATESMATERIAL('1ppYXw39v6kBwi3rrIm4ZE',$,$,$,(#72),#73);
|
||||
#75=IFCMATERIALPROFILE($,$,#20,#71,$,$);
|
||||
#76=IFCCIRCLEHOLLOWPROFILEDEF(.AREA.,'500.0x5.0 CHS',$,0.25,0.005);
|
||||
#77=IFCCOLUMNTYPE('25GZwy2zLFcgi57r5S8iY3',$,'C2',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#77=IFCCOLUMNTYPE('3aSZOvGmr7jggSNwsq5PJE',$,'C2',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#78=IFCMATERIALPROFILESET($,$,(#80),$);
|
||||
#79=IFCRELASSOCIATESMATERIAL('2VURAOhz93ZQqT9YJUA1DO',$,$,$,(#77),#78);
|
||||
#79=IFCRELASSOCIATESMATERIAL('1AtNJPaD14DgINbAjXvbU4',$,$,$,(#77),#78);
|
||||
#80=IFCMATERIALPROFILE($,$,#20,#76,$,$);
|
||||
#81=IFCRECTANGLEHOLLOWPROFILEDEF(.AREA.,'150x75x2.0 RHS',$,0.075,0.15,0.002,0.005,0.005);
|
||||
#82=IFCCOLUMNTYPE('1Wg$I84s9BTh$iDuZnmSkH',$,'C3',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#82=IFCCOLUMNTYPE('28iv3Kru12yQ7R7RRwNjvD',$,'C3',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#83=IFCMATERIALPROFILESET($,$,(#85),$);
|
||||
#84=IFCRELASSOCIATESMATERIAL('3fIIwEe7DAle7x_zISvMUD',$,$,$,(#82),#83);
|
||||
#84=IFCRELASSOCIATESMATERIAL('2M_oL$n3j6rBRnOW5RSk87',$,$,$,(#82),#83);
|
||||
#85=IFCMATERIALPROFILE($,$,#20,#81,$,$);
|
||||
#86=IFCISHAPEPROFILEDEF(.AREA.,'DEMO-I',$,0.1,0.2,0.005,0.01,0.005,$,$);
|
||||
#87=IFCBEAMTYPE('2yg2Irs7L26gFsD_AvvFUu',$,'B1',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#87=IFCBEAMTYPE('2E$V5l4b54dxuToJ1A6IHp',$,'B1',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#88=IFCMATERIALPROFILESET($,$,(#90),$);
|
||||
#89=IFCRELASSOCIATESMATERIAL('1PU_gbkifF9hYpi9DvXTAU',$,$,$,(#87),#88);
|
||||
#89=IFCRELASSOCIATESMATERIAL('3PUNnY7cj8LhyXbHKVqZnf',$,$,$,(#87),#88);
|
||||
#90=IFCMATERIALPROFILE($,$,#20,#86,$,$);
|
||||
#91=IFCCSHAPEPROFILEDEF(.AREA.,'DEMO-C',$,0.2,0.1,0.0015,0.03,0.005);
|
||||
#92=IFCBEAMTYPE('2Nf2L5qpz8K8KhUNFBg_fT',$,'B2',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#92=IFCBEAMTYPE('3qutoZTvP0lvLWNXyjPhPm',$,'B2',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#93=IFCMATERIALPROFILESET($,$,(#95),$);
|
||||
#94=IFCRELASSOCIATESMATERIAL('1SgarGNCzEQQpfs29NMq0y',$,$,$,(#92),#93);
|
||||
#94=IFCRELASSOCIATESMATERIAL('3dGyQf42H2ahch2bSYPPHP',$,$,$,(#92),#93);
|
||||
#95=IFCMATERIALPROFILE($,$,#20,#91,$,$);
|
||||
#96=IFCWINDOWTYPE('2zRUFP8Ef81xDOR2iJx1zK',$,'WT01',$,$,$,(#135,#152),$,$,.NOTDEFINED.,.NOTDEFINED.,$,$);
|
||||
#96=IFCWINDOWTYPE('0bK3c4PWL3eOMNwkPN$rlg',$,'WT01',$,$,$,(#135,#152),$,$,.NOTDEFINED.,.NOTDEFINED.,$,$);
|
||||
#97=IFCINDEXEDPOLYGONALFACE((13,17,18,14));
|
||||
#98=IFCINDEXEDPOLYGONALFACE((5,6,3,4));
|
||||
#99=IFCINDEXEDPOLYGONALFACE((7,8,2,1));
|
||||
@@ -157,7 +157,7 @@ DATA;
|
||||
#150=IFCDIRECTION((0.,0.,1.));
|
||||
#151=IFCAXIS2PLACEMENT3D(#148,#150,#149);
|
||||
#152=IFCREPRESENTATIONMAP(#151,#147);
|
||||
#153=IFCDOORTYPE('0oekOIA$z8lxWiQs9_tFWU',$,'DT01',$,$,$,(#196,#209),$,$,.NOTDEFINED.,.NOTDEFINED.,$,$);
|
||||
#153=IFCDOORTYPE('2j0vIBgkH0ERnBCP0cpcCz',$,'DT01',$,$,$,(#196,#209),$,$,.NOTDEFINED.,.NOTDEFINED.,$,$);
|
||||
#154=IFCINDEXEDPOLYGONALFACE((17,16,15,14));
|
||||
#155=IFCINDEXEDPOLYGONALFACE((2,3,29,28));
|
||||
#156=IFCINDEXEDPOLYGONALFACE((27,28,29,30,32,31));
|
||||
@@ -214,7 +214,7 @@ DATA;
|
||||
#207=IFCDIRECTION((0.,0.,1.));
|
||||
#208=IFCAXIS2PLACEMENT3D(#205,#207,#206);
|
||||
#209=IFCREPRESENTATIONMAP(#208,#204);
|
||||
#210=IFCFURNITURETYPE('0I2mc$m3T60hLXZYg9Y1wu',$,'BUN01',$,$,$,(#931,#952),$,$,.NOTDEFINED.,.NOTDEFINED.);
|
||||
#210=IFCFURNITURETYPE('02XxQ_3oT0SPrmFPATrt7o',$,'BUN01',$,$,$,(#931,#952),$,$,.NOTDEFINED.,.NOTDEFINED.);
|
||||
#211=IFCINDEXEDPOLYGONALFACE((187,278,44));
|
||||
#212=IFCINDEXEDPOLYGONALFACE((21,52,60));
|
||||
#213=IFCINDEXEDPOLYGONALFACE((91,100,31));
|
||||
@@ -957,131 +957,161 @@ DATA;
|
||||
#950=IFCDIRECTION((0.,0.,1.));
|
||||
#951=IFCAXIS2PLACEMENT3D(#948,#950,#949);
|
||||
#952=IFCREPRESENTATIONMAP(#951,#947);
|
||||
#953=IFCTYPEPRODUCT('2be705eyD4DPBr6j4K7ZEx',$,'DASHED',$,'IfcAnnotation/LINEWORK',(#954),$,$);
|
||||
#954=IFCPROPERTYSET('0uEfutIxDDIxMIBUJOZpSM',$,'EPset_Annotation',$,(#955));
|
||||
#955=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('dashed'),$);
|
||||
#956=IFCTYPEPRODUCT('1M7mm9wUHFoxdM0MdAMyqM',$,'FINE',$,'IfcAnnotation/LINEWORK',(#957),$,$);
|
||||
#957=IFCPROPERTYSET('3AZ8m1Bdn1gfbvagzKr2c3',$,'EPset_Annotation',$,(#958));
|
||||
#958=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('fine'),$);
|
||||
#959=IFCTYPEPRODUCT('3LdrNIFOvAkBzrNnqWAZfA',$,'THIN',$,'IfcAnnotation/LINEWORK',(#960),$,$);
|
||||
#960=IFCPROPERTYSET('0$9iwgSID7xBul4Tb9r2du',$,'EPset_Annotation',$,(#961));
|
||||
#961=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('thin'),$);
|
||||
#962=IFCTYPEPRODUCT('3fFNO0t1TB$wYRaIkKwUCH',$,'MEDIUM',$,'IfcAnnotation/LINEWORK',(#963),$,$);
|
||||
#963=IFCPROPERTYSET('33Fm$9zgb1cgsCOy859RlR',$,'EPset_Annotation',$,(#964));
|
||||
#964=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('medium'),$);
|
||||
#965=IFCTYPEPRODUCT('1CpMBhemj5VQC43bU9J7zG',$,'THICK',$,'IfcAnnotation/LINEWORK',(#966),$,$);
|
||||
#966=IFCPROPERTYSET('1OLDsFSDz2TPz5ifkQvWo8',$,'EPset_Annotation',$,(#967));
|
||||
#967=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('thick'),$);
|
||||
#968=IFCTYPEPRODUCT('0NITtya3b16hoA3sh17SL4',$,'STRONG',$,'IfcAnnotation/LINEWORK',(#969),$,$);
|
||||
#969=IFCPROPERTYSET('1_kfqWVDn0puI29Ah6eitX',$,'EPset_Annotation',$,(#970));
|
||||
#970=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('strong'),$);
|
||||
#971=IFCTYPEPRODUCT('0rRN9EsvL5AQ3PorxrZSKM',$,'DOOR-TAG',$,'IfcAnnotation/TEXT',(#972),(#991),$);
|
||||
#972=IFCPROPERTYSET('3lRZ$d2VH8cxZYh$mm45iq',$,'EPset_Annotation',$,(#973));
|
||||
#973=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('door-tag'),$);
|
||||
#974=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#975=IFCDIRECTION((0.,0.,1.));
|
||||
#976=IFCDIRECTION((1.,0.,0.));
|
||||
#977=IFCAXIS2PLACEMENT3D(#974,#975,#976);
|
||||
#978=IFCPLANAREXTENT(1000.,1000.);
|
||||
#979=IFCTEXTLITERALWITHEXTENT('{{type.Name}}',#977,.RIGHT.,#978,'center');
|
||||
#980=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#981=IFCDIRECTION((0.,0.,1.));
|
||||
#982=IFCDIRECTION((1.,0.,0.));
|
||||
#983=IFCAXIS2PLACEMENT3D(#980,#981,#982);
|
||||
#984=IFCPLANAREXTENT(1000.,1000.);
|
||||
#985=IFCTEXTLITERALWITHEXTENT('{{Name}}',#983,.RIGHT.,#984,'center');
|
||||
#986=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#979,#985));
|
||||
#987=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#988=IFCDIRECTION((1.,0.,0.));
|
||||
#989=IFCDIRECTION((0.,0.,1.));
|
||||
#990=IFCAXIS2PLACEMENT3D(#987,#989,#988);
|
||||
#991=IFCREPRESENTATIONMAP(#990,#986);
|
||||
#992=IFCTYPEPRODUCT('0bFZUWHjbA2e03hRHNinTt',$,'WINDOW-TAG',$,'IfcAnnotation/TEXT',(#993),(#1006),$);
|
||||
#993=IFCPROPERTYSET('3TJOWv5NDBXBNCshYFjsFV',$,'EPset_Annotation',$,(#994));
|
||||
#994=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('window-tag'),$);
|
||||
#995=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#996=IFCDIRECTION((0.,0.,1.));
|
||||
#953=IFCTYPEPRODUCT('0UrP0fLdD5OwzwD41aRKao',$,'SETOUT-POINT',$,'IfcAnnotation/SYMBOL',(#954),$,$);
|
||||
#954=IFCPROPERTYSET('27lmSbeAXC08EWkEq8XdUG',$,'EPset_Annotation',$,(#955));
|
||||
#955=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('setout-point'),$);
|
||||
#956=IFCTYPEPRODUCT('3IQrQOSFP0WfkuLk0ak7_0',$,'CONTROL-POINT',$,'IfcAnnotation/SYMBOL',(#957),$,$);
|
||||
#957=IFCPROPERTYSET('23aN9DsdjFcfWq8KGSIVoN',$,'EPset_Annotation',$,(#958));
|
||||
#958=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('control-point'),$);
|
||||
#959=IFCTYPEPRODUCT('3wvbaiaIz8agQgDRzt01vz',$,'TRAVERSE-POINT',$,'IfcAnnotation/SYMBOL',(#960),$,$);
|
||||
#960=IFCPROPERTYSET('1j7aFM1Rb9BRuKgUEn1U10',$,'EPset_Annotation',$,(#961));
|
||||
#961=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('traverse-point'),$);
|
||||
#962=IFCTYPEPRODUCT('0p5ZTfTnX9ZOywroa7Ffql',$,'DASHED',$,'IfcAnnotation/LINEWORK',(#963),$,$);
|
||||
#963=IFCPROPERTYSET('27smSHyiv39vhBRSwfDVCD',$,'EPset_Annotation',$,(#964));
|
||||
#964=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('dashed'),$);
|
||||
#965=IFCTYPEPRODUCT('2EvrG9Vuf6t9etgMeWFuJ2',$,'FINE',$,'IfcAnnotation/LINEWORK',(#966),$,$);
|
||||
#966=IFCPROPERTYSET('0gVTuDcZ5ByRdR3sZnEZUR',$,'EPset_Annotation',$,(#967));
|
||||
#967=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('fine'),$);
|
||||
#968=IFCTYPEPRODUCT('0IeM1ywXn1qhR_6NhB6N4s',$,'THIN',$,'IfcAnnotation/LINEWORK',(#969),$,$);
|
||||
#969=IFCPROPERTYSET('0t6c$uCeT9092GYkbm8hDS',$,'EPset_Annotation',$,(#970));
|
||||
#970=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('thin'),$);
|
||||
#971=IFCTYPEPRODUCT('1jZVbCwrTCGhZdKbH4uqTP',$,'MEDIUM',$,'IfcAnnotation/LINEWORK',(#972),$,$);
|
||||
#972=IFCPROPERTYSET('2uTJ11lF98GeN8pPIf340N',$,'EPset_Annotation',$,(#973));
|
||||
#973=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('medium'),$);
|
||||
#974=IFCTYPEPRODUCT('38zW9E1uH2ae$zat9KrieS',$,'THICK',$,'IfcAnnotation/LINEWORK',(#975),$,$);
|
||||
#975=IFCPROPERTYSET('2XQxgO16v9vxjvuIJpaPpG',$,'EPset_Annotation',$,(#976));
|
||||
#976=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('thick'),$);
|
||||
#977=IFCTYPEPRODUCT('3G2s7ZLzfDJh5J$2iIzHw9',$,'STRONG',$,'IfcAnnotation/LINEWORK',(#978),$,$);
|
||||
#978=IFCPROPERTYSET('0TcB8Gal96vebTrLWa5CEw',$,'EPset_Annotation',$,(#979));
|
||||
#979=IFCPROPERTYSINGLEVALUE('Classes',$,IFCLABEL('strong'),$);
|
||||
#980=IFCTYPEPRODUCT('3pq2B$0k52ZOv2bFuRYkxO',$,'SETOUT-TAG',$,'IfcAnnotation/TEXT',(#981),(#1000),$);
|
||||
#981=IFCPROPERTYSET('39$oNFI052cBhtpZCVVLfj',$,'EPset_Annotation',$,(#982));
|
||||
#982=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('setout-tag'),$);
|
||||
#983=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#984=IFCDIRECTION((0.,0.,1.));
|
||||
#985=IFCDIRECTION((1.,0.,0.));
|
||||
#986=IFCAXIS2PLACEMENT3D(#983,#984,#985);
|
||||
#987=IFCPLANAREXTENT(1000.,1000.);
|
||||
#988=IFCTEXTLITERALWITHEXTENT('E ``round({{easting}}, 0.001)``',#986,.RIGHT.,#987,'center');
|
||||
#989=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#990=IFCDIRECTION((0.,0.,1.));
|
||||
#991=IFCDIRECTION((1.,0.,0.));
|
||||
#992=IFCAXIS2PLACEMENT3D(#989,#990,#991);
|
||||
#993=IFCPLANAREXTENT(1000.,1000.);
|
||||
#994=IFCTEXTLITERALWITHEXTENT('N ``round({{northing}}, 0.001)``',#992,.RIGHT.,#993,'center');
|
||||
#995=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#988,#994));
|
||||
#996=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#997=IFCDIRECTION((1.,0.,0.));
|
||||
#998=IFCAXIS2PLACEMENT3D(#995,#996,#997);
|
||||
#999=IFCPLANAREXTENT(1000.,1000.);
|
||||
#1000=IFCTEXTLITERALWITHEXTENT('{{Name}}',#998,.RIGHT.,#999,'center');
|
||||
#1001=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1000));
|
||||
#1002=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1003=IFCDIRECTION((1.,0.,0.));
|
||||
#1004=IFCDIRECTION((0.,0.,1.));
|
||||
#1005=IFCAXIS2PLACEMENT3D(#1002,#1004,#1003);
|
||||
#1006=IFCREPRESENTATIONMAP(#1005,#1001);
|
||||
#1007=IFCTYPEPRODUCT('2DlmDdasX05un_uMP4O23U',$,'SPACE-TAG',$,'IfcAnnotation/TEXT',(#1008),(#1033),$);
|
||||
#1008=IFCPROPERTYSET('1$OAHURHr3GON7ZzAJnv72',$,'EPset_Annotation',$,(#1009));
|
||||
#1009=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('space-tag'),$);
|
||||
#998=IFCDIRECTION((0.,0.,1.));
|
||||
#999=IFCAXIS2PLACEMENT3D(#996,#998,#997);
|
||||
#1000=IFCREPRESENTATIONMAP(#999,#995);
|
||||
#1001=IFCTYPEPRODUCT('11M3ahhrr9NBdB29YEazzw',$,'DOOR-TAG',$,'IfcAnnotation/TEXT',(#1002),(#1021),$);
|
||||
#1002=IFCPROPERTYSET('3xUNoLKPT9kB4LMdoctm5k',$,'EPset_Annotation',$,(#1003));
|
||||
#1003=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('door-tag'),$);
|
||||
#1004=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1005=IFCDIRECTION((0.,0.,1.));
|
||||
#1006=IFCDIRECTION((1.,0.,0.));
|
||||
#1007=IFCAXIS2PLACEMENT3D(#1004,#1005,#1006);
|
||||
#1008=IFCPLANAREXTENT(1000.,1000.);
|
||||
#1009=IFCTEXTLITERALWITHEXTENT('{{type.Name}}',#1007,.RIGHT.,#1008,'center');
|
||||
#1010=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1011=IFCDIRECTION((0.,0.,1.));
|
||||
#1012=IFCDIRECTION((1.,0.,0.));
|
||||
#1013=IFCAXIS2PLACEMENT3D(#1010,#1011,#1012);
|
||||
#1014=IFCPLANAREXTENT(1000.,1000.);
|
||||
#1015=IFCTEXTLITERALWITHEXTENT('{{Name}}',#1013,.RIGHT.,#1014,'center');
|
||||
#1016=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1017=IFCDIRECTION((0.,0.,1.));
|
||||
#1016=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1009,#1015));
|
||||
#1017=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1018=IFCDIRECTION((1.,0.,0.));
|
||||
#1019=IFCAXIS2PLACEMENT3D(#1016,#1017,#1018);
|
||||
#1020=IFCPLANAREXTENT(1000.,1000.);
|
||||
#1021=IFCTEXTLITERALWITHEXTENT('{{Description}}',#1019,.RIGHT.,#1020,'center');
|
||||
#1022=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1023=IFCDIRECTION((0.,0.,1.));
|
||||
#1024=IFCDIRECTION((1.,0.,0.));
|
||||
#1025=IFCAXIS2PLACEMENT3D(#1022,#1023,#1024);
|
||||
#1026=IFCPLANAREXTENT(1000.,1000.);
|
||||
#1027=IFCTEXTLITERALWITHEXTENT('``round({{Qto_SpaceBaseQuantities.NetFloorArea}} or 0., 2)``',#1025,.RIGHT.,#1026,'center');
|
||||
#1028=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1015,#1021,#1027));
|
||||
#1029=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1030=IFCDIRECTION((1.,0.,0.));
|
||||
#1031=IFCDIRECTION((0.,0.,1.));
|
||||
#1032=IFCAXIS2PLACEMENT3D(#1029,#1031,#1030);
|
||||
#1033=IFCREPRESENTATIONMAP(#1032,#1028);
|
||||
#1034=IFCTYPEPRODUCT('2vNx3CIlrFs8bLFlmGvJF3',$,'MATERIAL-TAG',$,'IfcAnnotation/TEXT',(#1035),(#1048),$);
|
||||
#1035=IFCPROPERTYSET('1l$T4lUqnBb93zcgfbSPvx',$,'EPset_Annotation',$,(#1036));
|
||||
#1036=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('rectangle-tag'),$);
|
||||
#1037=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1038=IFCDIRECTION((0.,0.,1.));
|
||||
#1039=IFCDIRECTION((1.,0.,0.));
|
||||
#1040=IFCAXIS2PLACEMENT3D(#1037,#1038,#1039);
|
||||
#1041=IFCPLANAREXTENT(1000.,1000.);
|
||||
#1042=IFCTEXTLITERALWITHEXTENT('{{material.Name}}',#1040,.RIGHT.,#1041,'center');
|
||||
#1043=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1042));
|
||||
#1044=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1045=IFCDIRECTION((1.,0.,0.));
|
||||
#1046=IFCDIRECTION((0.,0.,1.));
|
||||
#1047=IFCAXIS2PLACEMENT3D(#1044,#1046,#1045);
|
||||
#1048=IFCREPRESENTATIONMAP(#1047,#1043);
|
||||
#1049=IFCTYPEPRODUCT('3hqzFtbSb56RjhAZNaB4Vh',$,'TYPE-TAG',$,'IfcAnnotation/TEXT',(#1050),(#1063),$);
|
||||
#1050=IFCPROPERTYSET('3U7kaKt_nBUvD$U2ryif_H',$,'EPset_Annotation',$,(#1051));
|
||||
#1051=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('capsule-tag'),$);
|
||||
#1019=IFCDIRECTION((0.,0.,1.));
|
||||
#1020=IFCAXIS2PLACEMENT3D(#1017,#1019,#1018);
|
||||
#1021=IFCREPRESENTATIONMAP(#1020,#1016);
|
||||
#1022=IFCTYPEPRODUCT('1eE8Y$BVDFDgG8Fj6d9wiV',$,'WINDOW-TAG',$,'IfcAnnotation/TEXT',(#1023),(#1036),$);
|
||||
#1023=IFCPROPERTYSET('2MqzSGkXDBcPSolaAQvYO4',$,'EPset_Annotation',$,(#1024));
|
||||
#1024=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('window-tag'),$);
|
||||
#1025=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1026=IFCDIRECTION((0.,0.,1.));
|
||||
#1027=IFCDIRECTION((1.,0.,0.));
|
||||
#1028=IFCAXIS2PLACEMENT3D(#1025,#1026,#1027);
|
||||
#1029=IFCPLANAREXTENT(1000.,1000.);
|
||||
#1030=IFCTEXTLITERALWITHEXTENT('{{Name}}',#1028,.RIGHT.,#1029,'center');
|
||||
#1031=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1030));
|
||||
#1032=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1033=IFCDIRECTION((1.,0.,0.));
|
||||
#1034=IFCDIRECTION((0.,0.,1.));
|
||||
#1035=IFCAXIS2PLACEMENT3D(#1032,#1034,#1033);
|
||||
#1036=IFCREPRESENTATIONMAP(#1035,#1031);
|
||||
#1037=IFCTYPEPRODUCT('0vvfHSiaPBxewA$32C4LdW',$,'SPACE-TAG',$,'IfcAnnotation/TEXT',(#1038),(#1063),$);
|
||||
#1038=IFCPROPERTYSET('2zKuFdTPj3DhNdQ0U2kd5u',$,'EPset_Annotation',$,(#1039));
|
||||
#1039=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('space-tag'),$);
|
||||
#1040=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1041=IFCDIRECTION((0.,0.,1.));
|
||||
#1042=IFCDIRECTION((1.,0.,0.));
|
||||
#1043=IFCAXIS2PLACEMENT3D(#1040,#1041,#1042);
|
||||
#1044=IFCPLANAREXTENT(1000.,1000.);
|
||||
#1045=IFCTEXTLITERALWITHEXTENT('{{Name}}',#1043,.RIGHT.,#1044,'center');
|
||||
#1046=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1047=IFCDIRECTION((0.,0.,1.));
|
||||
#1048=IFCDIRECTION((1.,0.,0.));
|
||||
#1049=IFCAXIS2PLACEMENT3D(#1046,#1047,#1048);
|
||||
#1050=IFCPLANAREXTENT(1000.,1000.);
|
||||
#1051=IFCTEXTLITERALWITHEXTENT('{{Description}}',#1049,.RIGHT.,#1050,'center');
|
||||
#1052=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1053=IFCDIRECTION((0.,0.,1.));
|
||||
#1054=IFCDIRECTION((1.,0.,0.));
|
||||
#1055=IFCAXIS2PLACEMENT3D(#1052,#1053,#1054);
|
||||
#1056=IFCPLANAREXTENT(1000.,1000.);
|
||||
#1057=IFCTEXTLITERALWITHEXTENT('{{type.Name}}',#1055,.RIGHT.,#1056,'center');
|
||||
#1058=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1057));
|
||||
#1057=IFCTEXTLITERALWITHEXTENT('``round({{Qto_SpaceBaseQuantities.NetFloorArea}}, 0.01)``',#1055,.RIGHT.,#1056,'center');
|
||||
#1058=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1045,#1051,#1057));
|
||||
#1059=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1060=IFCDIRECTION((1.,0.,0.));
|
||||
#1061=IFCDIRECTION((0.,0.,1.));
|
||||
#1062=IFCAXIS2PLACEMENT3D(#1059,#1061,#1060);
|
||||
#1063=IFCREPRESENTATIONMAP(#1062,#1058);
|
||||
#1064=IFCTYPEPRODUCT('2SnSxJPiD9sh$NDx92OCSS',$,'NAME-TAG',$,'IfcAnnotation/TEXT',(#1065),(#1078),$);
|
||||
#1065=IFCPROPERTYSET('3Lu86QVuv5nfjkuPLvdQSH',$,'EPset_Annotation',$,(#1066));
|
||||
#1066=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('capsule-tag'),$);
|
||||
#1064=IFCTYPEPRODUCT('36lTcd9yT8UBNDejQUNWrq',$,'MATERIAL-TAG',$,'IfcAnnotation/TEXT',(#1065),(#1078),$);
|
||||
#1065=IFCPROPERTYSET('1x86VNVk1Drwe5XOj$GZX3',$,'EPset_Annotation',$,(#1066));
|
||||
#1066=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('rectangle-tag'),$);
|
||||
#1067=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1068=IFCDIRECTION((0.,0.,1.));
|
||||
#1069=IFCDIRECTION((1.,0.,0.));
|
||||
#1070=IFCAXIS2PLACEMENT3D(#1067,#1068,#1069);
|
||||
#1071=IFCPLANAREXTENT(1000.,1000.);
|
||||
#1072=IFCTEXTLITERALWITHEXTENT('{{Name}}',#1070,.RIGHT.,#1071,'center');
|
||||
#1072=IFCTEXTLITERALWITHEXTENT('{{material.Name}}',#1070,.RIGHT.,#1071,'center');
|
||||
#1073=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1072));
|
||||
#1074=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1075=IFCDIRECTION((1.,0.,0.));
|
||||
#1076=IFCDIRECTION((0.,0.,1.));
|
||||
#1077=IFCAXIS2PLACEMENT3D(#1074,#1076,#1075);
|
||||
#1078=IFCREPRESENTATIONMAP(#1077,#1073);
|
||||
#1079=IFCTYPEPRODUCT('1rxhEX6I16oPqglXaGZ7Sw',$,'TYPE-TAG',$,'IfcAnnotation/TEXT',(#1080),(#1093),$);
|
||||
#1080=IFCPROPERTYSET('3BeqEbDzX0xORamqqSx_kZ',$,'EPset_Annotation',$,(#1081));
|
||||
#1081=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('capsule-tag'),$);
|
||||
#1082=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1083=IFCDIRECTION((0.,0.,1.));
|
||||
#1084=IFCDIRECTION((1.,0.,0.));
|
||||
#1085=IFCAXIS2PLACEMENT3D(#1082,#1083,#1084);
|
||||
#1086=IFCPLANAREXTENT(1000.,1000.);
|
||||
#1087=IFCTEXTLITERALWITHEXTENT('{{type.Name}}',#1085,.RIGHT.,#1086,'center');
|
||||
#1088=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1087));
|
||||
#1089=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1090=IFCDIRECTION((1.,0.,0.));
|
||||
#1091=IFCDIRECTION((0.,0.,1.));
|
||||
#1092=IFCAXIS2PLACEMENT3D(#1089,#1091,#1090);
|
||||
#1093=IFCREPRESENTATIONMAP(#1092,#1088);
|
||||
#1094=IFCTYPEPRODUCT('0sws1hxNb2Og1etXqyoEh1',$,'NAME-TAG',$,'IfcAnnotation/TEXT',(#1095),(#1108),$);
|
||||
#1095=IFCPROPERTYSET('11L$PtdnX8LfYigzRZ$g0a',$,'EPset_Annotation',$,(#1096));
|
||||
#1096=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('capsule-tag'),$);
|
||||
#1097=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1098=IFCDIRECTION((0.,0.,1.));
|
||||
#1099=IFCDIRECTION((1.,0.,0.));
|
||||
#1100=IFCAXIS2PLACEMENT3D(#1097,#1098,#1099);
|
||||
#1101=IFCPLANAREXTENT(1000.,1000.);
|
||||
#1102=IFCTEXTLITERALWITHEXTENT('{{Name}}',#1100,.RIGHT.,#1101,'center');
|
||||
#1103=IFCSHAPEREPRESENTATION(#19,'Annotation','Annotation2D',(#1102));
|
||||
#1104=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#1105=IFCDIRECTION((1.,0.,0.));
|
||||
#1106=IFCDIRECTION((0.,0.,1.));
|
||||
#1107=IFCAXIS2PLACEMENT3D(#1104,#1106,#1105);
|
||||
#1108=IFCREPRESENTATIONMAP(#1107,#1103);
|
||||
ENDSEC;
|
||||
END-ISO-10303-21;
|
||||
|
||||
@@ -5,27 +5,28 @@ FILE_NAME('EPset_Drawing.ifc','2020-01-01T00:00:00',(),(),'EPset_Drawing','EPset
|
||||
FILE_SCHEMA(('IFC4'));
|
||||
ENDSEC;
|
||||
DATA;
|
||||
#1=IFCPROPERTYSETTEMPLATE('2JhNIvqZrFnAgxfhK0XVQX',$,'EPset_Drawing','',.PSET_OCCURRENCEDRIVEN.,'IfcAnnotation',(#2,#3,#4,#5,#6,#7,#8,#9,#10,#11,#12,#13,#14,#15,#16,#17,#18,#19,#20,#21));
|
||||
#1=IFCPROPERTYSETTEMPLATE('2JhNIvqZrFnAgxfhK0XVQX',$,'EPset_Drawing','',.PSET_OCCURRENCEDRIVEN.,'IfcAnnotation',(#2,#3,#4,#5,#6,#7,#8,#9,#10,#11,#12,#13,#14,#15,#16,#17,#18,#19,#20,#21,#22,#23));
|
||||
#2=IFCSIMPLEPROPERTYTEMPLATE('23JavTMk98ZxXhrUEnjAcf',$,'TargetView','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#3=IFCSIMPLEPROPERTYTEMPLATE('1yVWUt5H9DAOuu0OaMMLpe',$,'Scale','The scale of this drawing represented as a numerator and denominator, such as 1/100',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#4=IFCSIMPLEPROPERTYTEMPLATE('3gsuPBtU93b8f0gg1pjkq6',$,'HumanScale','The scale of this drawing in human readable format, such as 1:100',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#4=IFCSIMPLEPROPERTYTEMPLATE('2T$a4OFsv2LeD5JeBKEV4f',$,'IsNTS','Whether or not the scale is intended to be significant',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||
#5=IFCSIMPLEPROPERTYTEMPLATE('0AK5C2UpL4$eaac2LszAx$',$,'HasUnderlay','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||
#6=IFCSIMPLEPROPERTYTEMPLATE('2j2ZEZR8X5tONm7kli5hM6',$,'HasLinework','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||
#7=IFCSIMPLEPROPERTYTEMPLATE('1ttChRysH9UuEX2FeMj5Hu',$,'HasAnnotation','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||
#8=IFCSIMPLEPROPERTYTEMPLATE('2NPPxuABv1huDTVh32TFgw',$,'GlobalReferencing','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||
#9=IFCSIMPLEPROPERTYTEMPLATE('10hT_1zrzEbRRKMXYAWvtD',$,'Metadata','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#10=IFCSIMPLEPROPERTYTEMPLATE('3Z0BXPSG5CWgtI33ioV7aj',$,'Include','Selector expression to include ifc elements in the drawing',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#11=IFCSIMPLEPROPERTYTEMPLATE('1RVts_g3PAw98PJA2yL3bO',$,'Exclude','Selector expression to exclude ifc elements in the drawing',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#12=IFCSIMPLEPROPERTYTEMPLATE('0c1$8NpYDEaBiJrj16jHIo',$,'Stylesheet','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#13=IFCSIMPLEPROPERTYTEMPLATE('3mRF52q81FQB$h4oTh7M45',$,'Markers','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#14=IFCSIMPLEPROPERTYTEMPLATE('1rhr_0N3LDtuORcEJP0KXM',$,'Symbols','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#15=IFCSIMPLEPROPERTYTEMPLATE('2sHDBuW7P4TROy$hL2w7ct',$,'Patterns','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#16=IFCSIMPLEPROPERTYTEMPLATE('1$xfo9EVb26QLqmPll2_RK',$,'MetricPrecision','',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
|
||||
#17=IFCSIMPLEPROPERTYTEMPLATE('38uAtrp9nD_901NO42zd$7',$,'ImperialPrecision','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#18=IFCSIMPLEPROPERTYTEMPLATE('1MX0uffTL6TOvtvEJpxFmk',$,'DecimalPlaces','',.P_SINGLEVALUE.,'IfcInteger',$,$,$,$,$,.READWRITE.);
|
||||
#19=IFCSIMPLEPROPERTYTEMPLATE('0joEq0Rd10cxweEh0NeHT6',$,'JoinCriteria','Comma separated selection keys which determine what cut objects are to be joined.',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#20=IFCSIMPLEPROPERTYTEMPLATE('0nYMT3OSj5gArVniCWZRtv',$,'ShadingStyles','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#21=IFCSIMPLEPROPERTYTEMPLATE('3VWG22eZXBdQwdKlzMeVQH',$,'CurrentShadingStyle','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#5=IFCSIMPLEPROPERTYTEMPLATE('2T$a4OFsv2LeD5JeBKEV4f',$,'IsNTS','Whether or not the scale is intended to be significant',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||
#6=IFCSIMPLEPROPERTYTEMPLATE('0AK5C2UpL4$eaac2LszAx$',$,'HasUnderlay','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||
#7=IFCSIMPLEPROPERTYTEMPLATE('2j2ZEZR8X5tONm7kli5hM6',$,'HasLinework','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||
#8=IFCSIMPLEPROPERTYTEMPLATE('1ttChRysH9UuEX2FeMj5Hu',$,'HasAnnotation','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||
#9=IFCSIMPLEPROPERTYTEMPLATE('2NPPxuABv1huDTVh32TFgw',$,'GlobalReferencing','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||
#10=IFCSIMPLEPROPERTYTEMPLATE('10hT_1zrzEbRRKMXYAWvtD',$,'Metadata','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#11=IFCSIMPLEPROPERTYTEMPLATE('3Z0BXPSG5CWgtI33ioV7aj',$,'Include','Selector expression to include ifc elements in the drawing',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#12=IFCSIMPLEPROPERTYTEMPLATE('1RVts_g3PAw98PJA2yL3bO',$,'Exclude','Selector expression to exclude ifc elements in the drawing',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#13=IFCSIMPLEPROPERTYTEMPLATE('0c1$8NpYDEaBiJrj16jHIo',$,'Stylesheet','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#14=IFCSIMPLEPROPERTYTEMPLATE('3mRF52q81FQB$h4oTh7M45',$,'Markers','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#15=IFCSIMPLEPROPERTYTEMPLATE('1rhr_0N3LDtuORcEJP0KXM',$,'Symbols','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#16=IFCSIMPLEPROPERTYTEMPLATE('2sHDBuW7P4TROy$hL2w7ct',$,'Patterns','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#17=IFCSIMPLEPROPERTYTEMPLATE('1$xfo9EVb26QLqmPll2_RK',$,'MetricPrecision','',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
|
||||
#18=IFCSIMPLEPROPERTYTEMPLATE('38uAtrp9nD_901NO42zd$7',$,'ImperialPrecision','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#19=IFCSIMPLEPROPERTYTEMPLATE('1MX0uffTL6TOvtvEJpxFmk',$,'DecimalPlaces','',.P_SINGLEVALUE.,'IfcInteger',$,$,$,$,$,.READWRITE.);
|
||||
#20=IFCSIMPLEPROPERTYTEMPLATE('0joEq0Rd10cxweEh0NeHT6',$,'JoinCriteria','Comma separated selection keys which determine what cut objects are to be joined.',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#21=IFCSIMPLEPROPERTYTEMPLATE('0nYMT3OSj5gArVniCWZRtv',$,'ShadingStyles','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#22=IFCSIMPLEPROPERTYTEMPLATE('3VWG22eZXBdQwdKlzMeVQH',$,'CurrentShadingStyle','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#23=IFCSIMPLEPROPERTYTEMPLATE('28mJ$GDxb7kBbKFH_rACMQ',$,'AngleDecimalPlaces','',.P_SINGLEVALUE.,'IfcInteger',$,$,$,$,$,.READWRITE.);
|
||||
ENDSEC;
|
||||
END-ISO-10303-21;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
ISO-10303-21;
|
||||
HEADER;
|
||||
FILE_DESCRIPTION((),'2;1');
|
||||
FILE_NAME('EPset_Status.ifc','2020-01-01T00:00:00',(),(),'EPset_Status','EPset_Status',$);
|
||||
FILE_SCHEMA(('IFC4'));
|
||||
ENDSEC;
|
||||
DATA;
|
||||
#1=IFCPROPERTYSETTEMPLATE('3JoyTt$cz4fhYuQvJeTMhs',$,'EPset_Status','',.PSET_TYPEDRIVENOVERRIDE.,'IfcProduct',(#2,#4));
|
||||
#2= IFCSIMPLEPROPERTYTEMPLATE('2HBOdOfz5E3hZ7IBLCq$$D',$,'Status','Status of the element, predominately used in renovation or retrofitting projects. The status can be assigned to as "New" - element designed as new addition, "Existing" - element exists and remains, "Demolish" - element existed but is to be demolished, "Temporary" - element will exists only temporary (like a temporary support structure).',.P_ENUMERATEDVALUE.,'IfcLabel',$,#3,$,$,$,.READWRITE.);
|
||||
#3= IFCPROPERTYENUMERATION('EPEnum_ElementStatus',(IFCLABEL('NEW'),IFCLABEL('EXISTING'),IFCLABEL('DEMOLISH'),IFCLABEL('TEMPORARY'),IFCLABEL('OTHER'),IFCLABEL('NOTKNOWN'),IFCLABEL('UNSET')),$);
|
||||
#4=IFCSIMPLEPROPERTYTEMPLATE('3ttXxqmlz62BlxjzEPpqvH',$,'UserDefinedStatus','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
ENDSEC;
|
||||
END-ISO-10303-21;
|
||||
@@ -0,0 +1,23 @@
|
||||
ISO-10303-21;
|
||||
HEADER;
|
||||
FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1');
|
||||
FILE_NAME('','2023-09-28T23:00:50',(),(),'IfcOpenShell v0.7.0-fbd8ea1ed','IfcOpenShell v0.7.0-fbd8ea1ed','');
|
||||
FILE_SCHEMA(('IFC4'));
|
||||
ENDSEC;
|
||||
DATA;
|
||||
#1=IFCPROPERTYSETTEMPLATE('1TLQmgUKf0I8Zi07bm9Jqn',$,'ePSet_ProjectedCRS','',.PSET_OCCURRENCEDRIVEN.,'IfcProject',(#2,#3,#4,#5,#6,#7));
|
||||
#2=IFCSIMPLEPROPERTYTEMPLATE('2cH53PtVT3v88uf_uGFblG',$,'Name','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#3=IFCSIMPLEPROPERTYTEMPLATE('3JsReA6vXDqR7aNC$haRYW',$,'Description','',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#4=IFCSIMPLEPROPERTYTEMPLATE('0u0uEsT5HFtuX5GvozO9ba',$,'GeodeticDatum','',.P_SINGLEVALUE.,'IfcIdentifier',$,$,$,$,$,.READWRITE.);
|
||||
#5=IFCSIMPLEPROPERTYTEMPLATE('1JgEX9Fsf0$ggxYltdkqiY',$,'VerticalDatum','',.P_SINGLEVALUE.,'IfcIdentifier',$,$,$,$,$,.READWRITE.);
|
||||
#6=IFCSIMPLEPROPERTYTEMPLATE('3ahTZjYrD0MAOo5IH6QuGH',$,'MapProjection','',.P_SINGLEVALUE.,'IfcIdentifier',$,$,$,$,$,.READWRITE.);
|
||||
#7=IFCSIMPLEPROPERTYTEMPLATE('3hqJR2ghD0GAti7q4sXKj7',$,'MapZone','',.P_SINGLEVALUE.,'IfcIdentifier',$,$,$,$,$,.READWRITE.);
|
||||
#8=IFCPROPERTYSETTEMPLATE('1jGHTycOj0vA8xHfRl4TNs',$,'ePSet_MapConversion','',.PSET_OCCURRENCEDRIVEN.,'IfcProject',(#9,#10,#11,#12,#13,#15));
|
||||
#9=IFCSIMPLEPROPERTYTEMPLATE('0nxsULXo17JRrAvNteYtNR',$,'Eastings','',.P_SINGLEVALUE.,'IfcLengthMeasure',$,$,$,$,$,.READWRITE.);
|
||||
#10=IFCSIMPLEPROPERTYTEMPLATE('26RfaGJs5CqemN0Xin12XL',$,'Northings','',.P_SINGLEVALUE.,'IfcLengthMeasure',$,$,$,$,$,.READWRITE.);
|
||||
#11=IFCSIMPLEPROPERTYTEMPLATE('0ziCn3nZv3m850VEUwWH42',$,'OrthogonalHeight','',.P_SINGLEVALUE.,'IfcLengthMeasure',$,$,$,$,$,.READWRITE.);
|
||||
#12=IFCSIMPLEPROPERTYTEMPLATE('3d4BOt4In8WR119ms1SaAe',$,'XAxisAbscissa','',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
|
||||
#13=IFCSIMPLEPROPERTYTEMPLATE('1Q4Voqj2j84RQRI8l67m28',$,'XAxisOrdinate','',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
|
||||
#15=IFCSIMPLEPROPERTYTEMPLATE('0O1Hc0$XnDNOG_jPBmbW5r',$,'Scale','',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
|
||||
ENDSEC;
|
||||
END-ISO-10303-21;
|
||||
@@ -27,6 +27,7 @@ import addon_utils
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.placement
|
||||
import ifcopenshell.util.unit
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.geometry
|
||||
import blenderbim.core.aggregate
|
||||
@@ -82,7 +83,7 @@ class IfcExporter:
|
||||
)
|
||||
self.file.wrapped_data.header.file_name.preprocessor_version = "IfcOpenShell {}".format(ifcopenshell.version)
|
||||
self.file.wrapped_data.header.file_name.originating_system = "{} {}".format(
|
||||
self.get_application_name(), self.get_application_version()
|
||||
self.get_application_name(), tool.Blender.get_blenderbim_version()
|
||||
)
|
||||
|
||||
def sync_all_objects(self):
|
||||
@@ -93,6 +94,8 @@ class IfcExporter:
|
||||
try:
|
||||
if isinstance(obj, bpy.types.Material):
|
||||
continue
|
||||
if obj.library:
|
||||
continue
|
||||
tool.Collector.sync(obj)
|
||||
result = self.sync_object_placement(obj)
|
||||
if result:
|
||||
@@ -162,7 +165,7 @@ class IfcExporter:
|
||||
return "BlenderBIM"
|
||||
|
||||
def get_application_version(self):
|
||||
return ".".join(
|
||||
version = ".".join(
|
||||
[
|
||||
str(x)
|
||||
for x in [
|
||||
@@ -172,6 +175,9 @@ class IfcExporter:
|
||||
][0]
|
||||
]
|
||||
)
|
||||
if blenderbim.bim.last_commit_hash != "8888888":
|
||||
version += f"-{blenderbim.bim.last_commit_hash[:7]}"
|
||||
return version
|
||||
|
||||
|
||||
class IfcExportSettings:
|
||||
|
||||
@@ -21,12 +21,14 @@ import bpy
|
||||
import json
|
||||
import addon_utils
|
||||
import ifcopenshell.api.owner.settings
|
||||
import blenderbim.bim
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.owner as core_owner
|
||||
from bpy.app.handlers import persistent
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.owner.prop import get_user_person, get_user_organisation
|
||||
from blenderbim.bim.module.model.data import AuthoringData
|
||||
from blenderbim.bim.module.model.workspace import LIST_OF_TOOLS, TOOLS_TO_CLASSES_MAP
|
||||
from mathutils import Vector
|
||||
from math import cos, degrees
|
||||
|
||||
@@ -35,24 +37,6 @@ cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
global_subscription_owner = object()
|
||||
|
||||
|
||||
def mode_callback(obj, data):
|
||||
objects = bpy.context.selected_objects
|
||||
if bpy.context.active_object:
|
||||
objects += [bpy.context.active_object]
|
||||
for obj in objects:
|
||||
if (
|
||||
obj.mode != "EDIT"
|
||||
or not obj.data
|
||||
or not isinstance(obj.data, (bpy.types.Mesh, bpy.types.Curve, bpy.types.TextCurve))
|
||||
or not obj.BIMObjectProperties.ifc_definition_id
|
||||
):
|
||||
continue
|
||||
if obj.data.BIMMeshProperties.ifc_definition_id:
|
||||
tool.Ifc.edit(obj)
|
||||
elif IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id).is_a("IfcGridAxis"):
|
||||
tool.Ifc.edit(obj)
|
||||
|
||||
|
||||
def name_callback(obj, data):
|
||||
try:
|
||||
obj.name
|
||||
@@ -73,17 +57,31 @@ def name_callback(obj, data):
|
||||
refresh_ui_data()
|
||||
return
|
||||
|
||||
if not obj.BIMObjectProperties.ifc_definition_id or "/" not in obj.name:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
return
|
||||
|
||||
if obj.BIMObjectProperties.is_renaming:
|
||||
obj.BIMObjectProperties.is_renaming = False
|
||||
return
|
||||
|
||||
element = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
if "/" in obj.name:
|
||||
object_name = obj.name
|
||||
element_name = obj.name.split("/", 1)[1]
|
||||
else:
|
||||
element_name = obj.name
|
||||
object_name = element.is_a() + f"/{element_name}"
|
||||
obj.name = object_name # NOTE: doesn't trigger infinite recursion
|
||||
|
||||
if element.is_a("IfcGridAxis"):
|
||||
element.AxisTag = obj.name.split("/")[1]
|
||||
element.AxisTag = object_name.split("/")[1]
|
||||
refresh_ui_data()
|
||||
|
||||
if not element.is_a("IfcRoot"):
|
||||
return
|
||||
element.Name = element_name
|
||||
if obj.BIMObjectProperties.collection:
|
||||
obj.BIMObjectProperties.collection.name = obj.name
|
||||
element.Name = "/".join(obj.name.split("/")[1:])
|
||||
obj.BIMObjectProperties.collection.name = object_name
|
||||
refresh_ui_data()
|
||||
|
||||
|
||||
@@ -106,7 +104,7 @@ def update_bim_tool_props():
|
||||
return
|
||||
mode = bpy.context.mode
|
||||
current_tool = bpy.context.workspace.tools.from_space_view3d_mode(mode)
|
||||
if not current_tool or current_tool.idname != "bim.bim_tool":
|
||||
if not current_tool or current_tool.idname not in LIST_OF_TOOLS:
|
||||
return
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
@@ -114,6 +112,16 @@ def update_bim_tool_props():
|
||||
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||
if not representation:
|
||||
return
|
||||
|
||||
props = bpy.context.scene.BIMModelProperties
|
||||
if element.is_a("IfcElementType") or element.is_a("IfcElement"):
|
||||
element_type = ifcopenshell.util.element.get_type(element)
|
||||
if element_type:
|
||||
is_bim_tool = current_tool.idname == "bim.bim_tool"
|
||||
if is_bim_tool:
|
||||
props.ifc_class = element_type.is_a()
|
||||
if is_bim_tool or TOOLS_TO_CLASSES_MAP.get(current_tool.idname) == element_type.is_a():
|
||||
props.relating_type_id = str(element_type.id())
|
||||
extrusion = tool.Model.get_extrusion(representation)
|
||||
if not extrusion:
|
||||
return
|
||||
@@ -124,7 +132,6 @@ def update_bim_tool_props():
|
||||
return x_angle
|
||||
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
props = bpy.context.scene.BIMModelProperties
|
||||
if not AuthoringData.is_loaded:
|
||||
AuthoringData.load()
|
||||
|
||||
@@ -175,30 +182,20 @@ def refresh_ui_data():
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if isinstance(tool.Ifc.get(), ifcopenshell.sqlite):
|
||||
tool.Ifc.get().clear_cache()
|
||||
|
||||
|
||||
def purge_module_data():
|
||||
from blenderbim.bim import modules
|
||||
|
||||
refresh_ui_data()
|
||||
for name, value in modules.items():
|
||||
try:
|
||||
getattr(getattr(getattr(ifcopenshell.api, name), "data"), "Data").purge()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# TODO: deprecate prop purge functions and refactor into data classes.
|
||||
try:
|
||||
getattr(value, "prop").purge()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if isinstance(tool.Ifc.get(), ifcopenshell.sqlite):
|
||||
tool.Ifc.get().clear_cache()
|
||||
|
||||
|
||||
@persistent
|
||||
def loadIfcStore(scene):
|
||||
IfcStore.purge()
|
||||
purge_module_data()
|
||||
refresh_ui_data()
|
||||
if not IfcStore.get_file():
|
||||
return
|
||||
IfcStore.get_schema()
|
||||
@@ -210,7 +207,7 @@ def undo_post(scene):
|
||||
if IfcStore.last_transaction != bpy.context.scene.BIMProperties.last_transaction:
|
||||
IfcStore.last_transaction = bpy.context.scene.BIMProperties.last_transaction
|
||||
IfcStore.undo(until_key=bpy.context.scene.BIMProperties.last_transaction)
|
||||
purge_module_data()
|
||||
refresh_ui_data()
|
||||
tool.Ifc.rebuild_element_maps()
|
||||
|
||||
|
||||
@@ -219,7 +216,7 @@ def redo_post(scene):
|
||||
if IfcStore.last_transaction != bpy.context.scene.BIMProperties.last_transaction:
|
||||
IfcStore.last_transaction = bpy.context.scene.BIMProperties.last_transaction
|
||||
IfcStore.redo(until_key=bpy.context.scene.BIMProperties.last_transaction)
|
||||
purge_module_data()
|
||||
refresh_ui_data()
|
||||
tool.Ifc.rebuild_element_maps()
|
||||
|
||||
|
||||
@@ -257,74 +254,58 @@ def viewport_shading_changed_callback(area):
|
||||
bpy.context.scene.BIMStylesProperties.active_style_type = "External"
|
||||
|
||||
|
||||
if getattr(bpy.types, "SCENE_PT_scene"):
|
||||
@classmethod
|
||||
def poll_check_blender_tab(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
|
||||
class Override_SCENE_PT_scene(bpy.types.SCENE_PT_scene):
|
||||
bl_idname = "SCENE_PT_scene_override"
|
||||
|
||||
def get_override_scene_panel(panel_name):
|
||||
original_panel = getattr(bpy.types, panel_name)
|
||||
|
||||
override_panel = type(f"Override_{panel_name}", (original_panel,), {})
|
||||
override_panel.bl_idname = f"{panel_name}_override"
|
||||
|
||||
# some blender panel depend on other and register_class will throw an error
|
||||
# if we won't override their `bl_parent_id`
|
||||
bl_parent_id = getattr(override_panel, "bl_parent_id", None)
|
||||
if bl_parent_id is not None:
|
||||
override_panel.bl_parent_id = f"{bl_parent_id}_override"
|
||||
|
||||
# override poll method
|
||||
poll = getattr(override_panel, "poll", None)
|
||||
if poll is None:
|
||||
override_panel.poll = poll_check_blender_tab
|
||||
else:
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
def wrapped_poll(cls, context):
|
||||
return super(override_panel, cls).poll(context) and poll_check_blender_tab.__func__(cls, context)
|
||||
|
||||
override_panel.poll = wrapped_poll
|
||||
|
||||
return override_panel
|
||||
|
||||
|
||||
if getattr(bpy.types, "SCENE_PT_unit"):
|
||||
|
||||
class Override_SCENE_PT_unit(bpy.types.SCENE_PT_unit):
|
||||
bl_idname = "SCENE_PT_unit_override"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
|
||||
|
||||
if getattr(bpy.types, "SCENE_PT_physics"):
|
||||
|
||||
class Override_SCENE_PT_physics(bpy.types.SCENE_PT_physics):
|
||||
bl_idname = "SCENE_PT_physics_override"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
|
||||
|
||||
if getattr(bpy.types, "SCENE_PT_rigid_body_world"):
|
||||
|
||||
class Override_SCENE_PT_rigid_body_world(bpy.types.SCENE_PT_rigid_body_world):
|
||||
bl_idname = "SCENE_PT_rigid_body_world_override"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
|
||||
|
||||
if getattr(bpy.types, "SCENE_PT_audio"):
|
||||
|
||||
class Override_SCENE_PT_audio(bpy.types.SCENE_PT_audio):
|
||||
bl_idname = "SCENE_PT_audio_override"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
|
||||
|
||||
if getattr(bpy.types, "SCENE_PT_keying_sets"):
|
||||
|
||||
class Override_SCENE_PT_keying_sets(bpy.types.SCENE_PT_keying_sets):
|
||||
bl_idname = "SCENE_PT_keying_sets_override"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
|
||||
|
||||
if getattr(bpy.types, "SCENE_PT_custom_props"):
|
||||
|
||||
class Override_SCENE_PT_custom_props(bpy.types.SCENE_PT_custom_props):
|
||||
bl_idname = "SCENE_PT_custom_props_override"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
# TODO: possibly override scene panels from other addons too?
|
||||
# list can be updated from
|
||||
# https://projects.blender.org/blender/blender/src/branch/main/scripts/startup/bl_ui/properties_scene.py#L421
|
||||
OVERRIDE_SCENE_PANELS = (
|
||||
"SCENE_PT_scene",
|
||||
"SCENE_PT_unit",
|
||||
"SCENE_PT_physics",
|
||||
"SCENE_PT_rigid_body_world",
|
||||
"SCENE_PT_rigid_body_world_settings",
|
||||
"SCENE_PT_rigid_body_cache",
|
||||
"SCENE_PT_rigid_body_field_weights",
|
||||
"SCENE_PT_audio",
|
||||
"SCENE_PT_keying_sets",
|
||||
"SCENE_PT_custom_props",
|
||||
# after SCENE_PT_keying_sets
|
||||
"SCENE_PT_keying_set_paths",
|
||||
"SCENE_PT_keyframing_settings",
|
||||
)
|
||||
if bpy.app.version >= (4, 0):
|
||||
OVERRIDE_SCENE_PANELS += ("SCENE_PT_simulation",)
|
||||
|
||||
|
||||
@persistent
|
||||
@@ -353,6 +334,9 @@ def load_post(scene):
|
||||
ifcopenshell.api.owner.settings.get_application = get_application
|
||||
AuthoringData.type_thumbnails = {}
|
||||
|
||||
if not bpy.context.preferences.addons["blenderbim"].preferences.should_setup_toolbar:
|
||||
tool.Blender.unregister_toolbar()
|
||||
|
||||
if bpy.context.preferences.addons["blenderbim"].preferences.should_setup_workspace:
|
||||
if "BIM" in bpy.data.workspaces:
|
||||
bpy.context.window.workspace = bpy.data.workspaces["BIM"]
|
||||
@@ -362,26 +346,12 @@ def load_post(scene):
|
||||
# To improve usability for new users, we hijack the scene properties
|
||||
# tab. We override default scene properties panels with our own poll
|
||||
# to hide them unless the user has chosen to view Blender properties.
|
||||
for panel in [
|
||||
"SCENE_PT_scene",
|
||||
"SCENE_PT_unit",
|
||||
"SCENE_PT_physics",
|
||||
"SCENE_PT_rigid_body_world",
|
||||
"SCENE_PT_audio",
|
||||
"SCENE_PT_keying_sets",
|
||||
"SCENE_PT_custom_props",
|
||||
]:
|
||||
if getattr(bpy.types, panel, None):
|
||||
try:
|
||||
bpy.utils.register_class(globals()[f"Override_{panel}"])
|
||||
bpy.utils.unregister_class(getattr(bpy.types, panel))
|
||||
except:
|
||||
pass
|
||||
|
||||
# https://blender.stackexchange.com/questions/140644/how-can-make-the-state-of-a-boolean-property-relative-to-the-3d-view-area
|
||||
for screen in bpy.data.screens:
|
||||
if len(screen.BIMAreaProperties) == 20:
|
||||
continue
|
||||
screen.BIMAreaProperties.clear()
|
||||
for i in range(20): # 20 is an arbitrary value of split areas
|
||||
screen.BIMAreaProperties.add()
|
||||
for panel in OVERRIDE_SCENE_PANELS:
|
||||
if panel in blenderbim.bim.overridden_scene_panels:
|
||||
continue
|
||||
override_panel = get_override_scene_panel(panel)
|
||||
original_panel = getattr(bpy.types, panel)
|
||||
bpy.utils.register_class(override_panel)
|
||||
bpy.utils.unregister_class(original_panel)
|
||||
blenderbim.bim.overridden_scene_panels[panel] = (original_panel, override_panel)
|
||||
tool.Blender.setup_tabs()
|
||||
|
||||
@@ -87,8 +87,15 @@ def import_attributes(ifc_class, props, data, callback=None):
|
||||
|
||||
# A more elegant attribute importer signature, intended to supersede import_attributes
|
||||
def import_attributes2(element, props, callback=None):
|
||||
for attribute in element.wrapped_data.declaration().as_entity().all_attributes():
|
||||
import_attribute(attribute, props, element.get_info(), callback=callback)
|
||||
if isinstance(element, str):
|
||||
attributes = tool.Ifc.schema().declaration_by_name(element).as_entity().all_attributes()
|
||||
info = {a.name(): None for a in attributes}
|
||||
info["type"] = element
|
||||
else:
|
||||
attributes = element.wrapped_data.declaration().as_entity().all_attributes()
|
||||
info = element.get_info()
|
||||
for attribute in attributes:
|
||||
import_attribute(attribute, props, info, callback=callback)
|
||||
|
||||
|
||||
def import_attribute(attribute, props, data, callback=None):
|
||||
@@ -238,7 +245,9 @@ def get_obj_ifc_definition_id(context, obj, obj_type):
|
||||
].ifc_definition_id
|
||||
elif obj_type == "WorkSchedule":
|
||||
return context.scene.BIMWorkScheduleProperties.active_work_schedule_id
|
||||
|
||||
elif obj_type == "Group":
|
||||
prop = context.scene.BIMGroupProperties
|
||||
return prop.groups[prop.active_group_index].ifc_definition_id
|
||||
|
||||
# hack to close popup
|
||||
# https://blender.stackexchange.com/a/202576/130742
|
||||
@@ -260,12 +269,7 @@ def convert_property_group_from_si(property_group, skip_props=()):
|
||||
for prop_name in property_group.bl_rna.properties.keys():
|
||||
if prop_name in skip_props:
|
||||
continue
|
||||
prop_bl_rna = property_group.bl_rna.properties[prop_name]
|
||||
if prop_bl_rna.array_length > 0:
|
||||
prop_value = prop_bl_rna.default_array
|
||||
else:
|
||||
prop_value = prop_bl_rna.default
|
||||
|
||||
prop_value = tool.Blender.get_blender_prop_default_value(property_group, prop_name)
|
||||
if type(prop_value) is float:
|
||||
prop_value = prop_value * conversion_k
|
||||
elif type(prop_value) is bpy.types.bpy_prop_array:
|
||||
@@ -273,6 +277,85 @@ def convert_property_group_from_si(property_group, skip_props=()):
|
||||
setattr(property_group, prop_name, prop_value)
|
||||
|
||||
|
||||
def draw_filter(layout, filter_groups, data, module):
|
||||
if not data.is_loaded:
|
||||
data.load()
|
||||
|
||||
sprops = bpy.context.scene.BIMSearchProperties
|
||||
|
||||
if tool.Ifc.get():
|
||||
row = layout.row(align=True)
|
||||
row.label(text=f"{len(data.data['saved_searches'])} Saved Searches")
|
||||
|
||||
if data.data["saved_searches"]:
|
||||
row.operator("bim.load_search", text="", icon="IMPORT").module = module
|
||||
row.operator("bim.save_search", text="", icon="EXPORT").module = module
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.operator("bim.add_filter_group", text="Add Search Group", icon="ADD").module = module
|
||||
row.operator("bim.edit_filter_query", text="", icon="FILTER").module = module
|
||||
|
||||
for i, filter_group in enumerate(filter_groups):
|
||||
box = layout.box()
|
||||
|
||||
row = box.row(align=True)
|
||||
row.prop(sprops, "facet", text="")
|
||||
op = row.operator("bim.add_filter", text="Add Filter", icon="ADD")
|
||||
op.type = sprops.facet
|
||||
op.index = i
|
||||
op.module = module
|
||||
|
||||
for j, ifc_filter in enumerate(filter_group.filters):
|
||||
if ifc_filter.type == "entity":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="FILE_3D")
|
||||
elif ifc_filter.type == "attribute":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "name", text="", icon="COPY_ID")
|
||||
row.prop(ifc_filter, "value", text="")
|
||||
elif ifc_filter.type == "type":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="FILE_VOLUME")
|
||||
elif ifc_filter.type == "material":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="MATERIAL")
|
||||
elif ifc_filter.type == "property":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "pset", text="", icon="PROPERTIES")
|
||||
row.prop(ifc_filter, "name", text="")
|
||||
row.prop(ifc_filter, "comparison", text="")
|
||||
row.prop(ifc_filter, "value", text="")
|
||||
elif ifc_filter.type == "classification":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="OUTLINER")
|
||||
elif ifc_filter.type == "location":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="PACKAGE")
|
||||
elif ifc_filter.type == "group":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="OUTLINER_COLLECTION")
|
||||
elif ifc_filter.type == "query":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "name", text="", icon="POINTCLOUD_DATA")
|
||||
row.prop(ifc_filter, "value", text="")
|
||||
elif ifc_filter.type == "instance":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="GRIP")
|
||||
op = row.operator("bim.select_filter_elements", text="", icon="EYEDROPPER")
|
||||
op.group_index = i
|
||||
op.index = j
|
||||
op.module = module
|
||||
op = row.operator("bim.remove_filter", text="", icon="X")
|
||||
op.group_index = i
|
||||
op.index = j
|
||||
op.module = module
|
||||
|
||||
row = box.row()
|
||||
op = row.operator("bim.remove_filter_group", icon="X")
|
||||
op.index = i
|
||||
op.module = module
|
||||
|
||||
|
||||
# TODO this should move into ifcopenshell.util
|
||||
|
||||
|
||||
|
||||
@@ -23,33 +23,39 @@ import hashlib
|
||||
import zipfile
|
||||
import tempfile
|
||||
import ifcopenshell
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.ifcopenshell_wrapper
|
||||
import blenderbim.bim.handler
|
||||
import blenderbim.tool as tool
|
||||
from pathlib import Path
|
||||
from blenderbim.tool.brick import BrickStore
|
||||
from typing import Set, Union, Optional
|
||||
|
||||
|
||||
IFC_CONNECTED_TYPE = Union[bpy.types.Material, bpy.types.Object]
|
||||
|
||||
|
||||
class IfcStore:
|
||||
path = ""
|
||||
file = None
|
||||
schema = None
|
||||
cache = None
|
||||
cache_path = None
|
||||
id_map = {}
|
||||
guid_map = {}
|
||||
edited_objs = set()
|
||||
pset_template_path = ""
|
||||
pset_template_file = None
|
||||
classification_path = ""
|
||||
classification_file = None
|
||||
library_path = ""
|
||||
library_file = None
|
||||
path: str = ""
|
||||
file: ifcopenshell.file = None
|
||||
schema: ifcopenshell.ifcopenshell_wrapper.schema_definition = None
|
||||
cache: ifcopenshell.ifcopenshell_wrapper.HdfSerializer = None
|
||||
cache_path: str = None
|
||||
id_map: dict[int, IFC_CONNECTED_TYPE] = {}
|
||||
guid_map: dict[str, IFC_CONNECTED_TYPE] = {}
|
||||
edited_objs: Set[bpy.types.Object] = set()
|
||||
pset_template_path: str = ""
|
||||
pset_template_file: ifcopenshell.file = None
|
||||
classification_path: str = ""
|
||||
classification_file: ifcopenshell.file = None
|
||||
library_path: str = ""
|
||||
library_file: ifcopenshell.file = None
|
||||
current_transaction = ""
|
||||
last_transaction = ""
|
||||
history = []
|
||||
future = []
|
||||
schema_identifiers = ["IFC4", "IFC2X3", "IFC4X3"]
|
||||
session_files = {}
|
||||
session_files: dict[str, ifcopenshell.file] = {}
|
||||
|
||||
@staticmethod
|
||||
def purge():
|
||||
@@ -80,8 +86,8 @@ class IfcStore:
|
||||
if IfcStore.path:
|
||||
try:
|
||||
IfcStore.load_file(IfcStore.path)
|
||||
except:
|
||||
pass
|
||||
except Exception as e:
|
||||
print(f"Failed to load file {IfcStore.path}. Error details: {e}")
|
||||
return IfcStore.file
|
||||
|
||||
@staticmethod
|
||||
@@ -117,7 +123,7 @@ class IfcStore:
|
||||
IfcStore.get_cache()
|
||||
|
||||
@staticmethod
|
||||
def load_file(path):
|
||||
def load_file(path) -> None:
|
||||
if not os.path.isfile(path):
|
||||
return
|
||||
extension = path.split(".")[-1]
|
||||
@@ -146,7 +152,7 @@ class IfcStore:
|
||||
return IfcStore.schema
|
||||
|
||||
@staticmethod
|
||||
def get_element(id_or_guid):
|
||||
def get_element(id_or_guid: Union[int, str]) -> IFC_CONNECTED_TYPE:
|
||||
if isinstance(id_or_guid, int):
|
||||
map_object = IfcStore.id_map
|
||||
else:
|
||||
@@ -159,16 +165,20 @@ class IfcStore:
|
||||
return obj
|
||||
|
||||
@staticmethod
|
||||
def relink_all_objects():
|
||||
def relink_all_objects() -> None:
|
||||
if not IfcStore.get_file():
|
||||
return
|
||||
for obj in bpy.data.objects:
|
||||
if obj.library:
|
||||
continue
|
||||
IfcStore.relink_object(obj)
|
||||
for obj in bpy.data.materials:
|
||||
if obj.library:
|
||||
continue
|
||||
IfcStore.relink_object(obj)
|
||||
|
||||
@staticmethod
|
||||
def relink_object(obj):
|
||||
def relink_object(obj: IFC_CONNECTED_TYPE) -> None:
|
||||
if not obj:
|
||||
return
|
||||
if obj.BIMObjectProperties.ifc_definition_id:
|
||||
@@ -189,7 +199,7 @@ class IfcStore:
|
||||
IfcStore.commit_link_element(data)
|
||||
|
||||
@staticmethod
|
||||
def link_element(element, obj):
|
||||
def link_element(element: ifcopenshell.entity_instance, obj: IFC_CONNECTED_TYPE) -> None:
|
||||
# Please use tool.Ifc.link() instead of this method. We want to
|
||||
# refactor this class and deprecate usage of IfcStore in favour of
|
||||
# tools.
|
||||
@@ -220,8 +230,9 @@ class IfcStore:
|
||||
if isinstance(obj, bpy.types.Material):
|
||||
blenderbim.bim.handler.subscribe_to(obj, "diffuse_color", blenderbim.bim.handler.color_callback)
|
||||
elif isinstance(obj, bpy.types.Object):
|
||||
blenderbim.bim.handler.subscribe_to(obj, "mode", blenderbim.bim.handler.mode_callback)
|
||||
blenderbim.bim.handler.subscribe_to(obj, "active_material_index", blenderbim.bim.handler.active_material_index_callback)
|
||||
blenderbim.bim.handler.subscribe_to(
|
||||
obj, "active_material_index", blenderbim.bim.handler.active_material_index_callback
|
||||
)
|
||||
|
||||
if IfcStore.history:
|
||||
data = {"id": element.id(), "guid": getattr(element, "GlobalId", None), "obj": obj.name}
|
||||
@@ -247,13 +258,14 @@ class IfcStore:
|
||||
if isinstance(obj, bpy.types.Material):
|
||||
blenderbim.bim.handler.subscribe_to(obj, "diffuse_color", blenderbim.bim.handler.color_callback)
|
||||
elif isinstance(obj, bpy.types.Object):
|
||||
blenderbim.bim.handler.subscribe_to(obj, "mode", blenderbim.bim.handler.mode_callback)
|
||||
blenderbim.bim.handler.subscribe_to(obj, "active_material_index", blenderbim.bim.handler.active_material_index_callback)
|
||||
blenderbim.bim.handler.subscribe_to(
|
||||
obj, "active_material_index", blenderbim.bim.handler.active_material_index_callback
|
||||
)
|
||||
# TODO Listeners are not re-registered. Does this cause nasty problems to debug later on?
|
||||
# TODO We're handling id_map and guid_map, but what about edited_objs? This might cause big problems.
|
||||
|
||||
@staticmethod
|
||||
def rollback_unlink_element(data):
|
||||
def rollback_unlink_element(data) -> None:
|
||||
if "id" not in data or "obj" not in data:
|
||||
return
|
||||
obj = bpy.data.objects.get(data["obj"])
|
||||
@@ -262,13 +274,15 @@ class IfcStore:
|
||||
IfcStore.guid_map[data["guid"]] = obj
|
||||
|
||||
@staticmethod
|
||||
def commit_unlink_element(data):
|
||||
def commit_unlink_element(data) -> None:
|
||||
del IfcStore.id_map[data["id"]]
|
||||
if data["guid"]:
|
||||
del IfcStore.guid_map[data["guid"]]
|
||||
|
||||
@staticmethod
|
||||
def unlink_element(element=None, obj=None):
|
||||
def unlink_element(
|
||||
element: Optional[ifcopenshell.entity_instance] = None, obj: Optional[IFC_CONNECTED_TYPE] = None
|
||||
) -> None:
|
||||
if element is None:
|
||||
try:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
@@ -314,14 +328,15 @@ class IfcStore:
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def execute_ifc_operator(operator, context, is_invoke=False):
|
||||
def execute_ifc_operator(operator: bpy.types.Operator, context: bpy.types.Context, is_invoke=False):
|
||||
bpy.context.scene.BIMProperties.is_dirty = True
|
||||
is_top_level_operator = not bool(IfcStore.current_transaction)
|
||||
|
||||
if is_top_level_operator:
|
||||
IfcStore.begin_transaction(operator)
|
||||
if tool.Ifc.get():
|
||||
tool.Ifc.get().begin_transaction()
|
||||
if BrickStore.graph:
|
||||
if BrickStore.graph is not None: # `if BrickStore.graph` by itself takes ages.
|
||||
BrickStore.begin_transaction()
|
||||
# This empty transaction ensures that each operator has at least one transaction
|
||||
IfcStore.add_transaction_operation(operator, rollback=lambda data: True, commit=lambda data: True)
|
||||
@@ -339,7 +354,7 @@ class IfcStore:
|
||||
IfcStore.add_transaction_operation(
|
||||
operator, rollback=lambda d: tool.Ifc.get().undo(), commit=lambda d: tool.Ifc.get().redo()
|
||||
)
|
||||
if BrickStore.graph:
|
||||
if BrickStore.graph is not None: # `if BrickStore.graph` by itself takes ages.
|
||||
BrickStore.end_transaction()
|
||||
IfcStore.end_transaction(operator)
|
||||
blenderbim.bim.handler.refresh_ui_data()
|
||||
@@ -347,17 +362,17 @@ class IfcStore:
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def begin_transaction(operator):
|
||||
def begin_transaction(operator: bpy.types.Operator) -> None:
|
||||
IfcStore.current_transaction = str(uuid.uuid4())
|
||||
operator.transaction_key = IfcStore.current_transaction
|
||||
|
||||
@staticmethod
|
||||
def end_transaction(operator):
|
||||
def end_transaction(operator: bpy.types.Operator) -> None:
|
||||
IfcStore.current_transaction = ""
|
||||
operator.transaction_key = ""
|
||||
|
||||
@staticmethod
|
||||
def add_transaction_operation(operator, rollback=None, commit=None):
|
||||
def add_transaction_operation(operator: bpy.types.Operator, rollback=None, commit=None) -> None:
|
||||
key = getattr(operator, "transaction_key", None)
|
||||
data = getattr(operator, "transaction_data", None)
|
||||
bpy.context.scene.BIMProperties.last_transaction = key
|
||||
@@ -373,7 +388,7 @@ class IfcStore:
|
||||
IfcStore.future = []
|
||||
|
||||
@staticmethod
|
||||
def undo(until_key=None):
|
||||
def undo(until_key=None) -> None:
|
||||
BrickStore.undo()
|
||||
if not IfcStore.history:
|
||||
return
|
||||
@@ -388,7 +403,7 @@ class IfcStore:
|
||||
IfcStore.future.append(event)
|
||||
|
||||
@staticmethod
|
||||
def redo(until_key=None):
|
||||
def redo(until_key=None) -> None:
|
||||
BrickStore.redo()
|
||||
|
||||
if not IfcStore.future:
|
||||
|
||||
@@ -20,16 +20,19 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.BIM_OT_assign_object,
|
||||
operator.BIM_OT_unassign_object,
|
||||
operator.BIM_OT_enable_editing_aggregate,
|
||||
operator.BIM_OT_disable_editing_aggregate,
|
||||
operator.BIM_OT_add_aggregate,
|
||||
operator.BIM_OT_select_parts,
|
||||
operator.BIM_OT_select_aggregate,
|
||||
operator.BIM_OT_add_part_to_object,
|
||||
operator.BIM_OT_aggregate_assign_object,
|
||||
operator.BIM_OT_disable_editing_aggregate,
|
||||
operator.BIM_OT_enable_editing_aggregate,
|
||||
operator.BIM_OT_select_aggregate,
|
||||
operator.BIM_OT_select_parts,
|
||||
operator.BIM_OT_aggregate_unassign_object,
|
||||
operator.BIM_OT_break_link_to_other_aggregates,
|
||||
operator.BIM_OT_select_linked_aggregates,
|
||||
prop.BIMObjectAggregateProperties,
|
||||
ui.BIM_PT_aggregate,
|
||||
ui.BIM_PT_linked_aggregate,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -35,8 +35,9 @@ class AggregateData:
|
||||
"has_relating_object": cls.has_relating_object(),
|
||||
"relating_object_label": cls.get_relating_object_label(),
|
||||
"has_related_objects": cls.has_related_objects(),
|
||||
"related_objects_amount": cls.get_related_objects_amount(),
|
||||
"total_parts": cls.total_parts(),
|
||||
"ifc_class": cls.ifc_class(),
|
||||
"total_linked_aggregate": cls.total_linked_aggregate(),
|
||||
}
|
||||
cls.is_loaded = True
|
||||
|
||||
@@ -59,7 +60,7 @@ class AggregateData:
|
||||
return ifcopenshell.util.element.get_parts(tool.Ifc.get_entity(bpy.context.active_object))
|
||||
|
||||
@classmethod
|
||||
def get_related_objects_amount(cls):
|
||||
def total_parts(cls):
|
||||
parts = cls.get_related_objects()
|
||||
return len(parts) if parts else 0
|
||||
|
||||
@@ -72,3 +73,26 @@ class AggregateData:
|
||||
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||
if element:
|
||||
return element.is_a()
|
||||
|
||||
@classmethod
|
||||
def total_linked_aggregate(cls):
|
||||
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||
aggregate = ifcopenshell.util.element.get_aggregate(element)
|
||||
if not aggregate:
|
||||
return []
|
||||
if not element:
|
||||
return []
|
||||
|
||||
product_linked_agg_group = [
|
||||
r
|
||||
for r in getattr(aggregate, "HasAssignments", []) or []
|
||||
if r.is_a("IfcRelAssignsToGroup")
|
||||
if "BBIM_Linked_Aggregate" in r.RelatingGroup.Name
|
||||
]
|
||||
|
||||
if not product_linked_agg_group:
|
||||
return []
|
||||
|
||||
total = len(product_linked_agg_group[0].RelatedObjects)
|
||||
return total
|
||||
|
||||
|
||||
@@ -33,18 +33,23 @@ class Operator:
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class BIM_OT_assign_object(bpy.types.Operator, Operator):
|
||||
class BIM_OT_aggregate_assign_object(bpy.types.Operator, Operator):
|
||||
"""Create aggregation relationship between two ifc elements"""
|
||||
|
||||
bl_idname = "bim.assign_object"
|
||||
bl_label = "Assign Object"
|
||||
bl_idname = "bim.aggregate_assign_object"
|
||||
bl_label = "Assign Object To Aggregation"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
relating_object: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
relating_obj = None
|
||||
if self.relating_object:
|
||||
relating_obj = tool.Ifc.get_object(tool.Ifc.get().by_id(self.relating_object))
|
||||
element = tool.Ifc.get().by_id(self.relating_object)
|
||||
if element.IsDecomposedBy:
|
||||
relating_obj = tool.Ifc.get_object(element)
|
||||
else:
|
||||
assembly = element.Decomposes[0].RelatingObject
|
||||
relating_obj = tool.Ifc.get_object(assembly)
|
||||
elif context.active_object:
|
||||
relating_obj = context.active_object
|
||||
if not relating_obj:
|
||||
@@ -67,11 +72,11 @@ class BIM_OT_assign_object(bpy.types.Operator, Operator):
|
||||
self.report({"ERROR"}, f" Cannot aggregate {obj.name} to {relating_obj.name}")
|
||||
|
||||
|
||||
class BIM_OT_unassign_object(bpy.types.Operator, Operator):
|
||||
class BIM_OT_aggregate_unassign_object(bpy.types.Operator, Operator):
|
||||
"""Remove aggregation relationship between two ifc elements"""
|
||||
|
||||
bl_idname = "bim.unassign_object"
|
||||
bl_label = "Unassign Object"
|
||||
bl_idname = "bim.aggregate_unassign_object"
|
||||
bl_label = "Unassign Object From Aggregation"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
@@ -89,6 +94,12 @@ class BIM_OT_unassign_object(bpy.types.Operator, Operator):
|
||||
relating_obj=tool.Ifc.get_object(aggregate),
|
||||
related_obj=tool.Ifc.get_object(element),
|
||||
)
|
||||
|
||||
# Removes Pset related to Linked Aggregates
|
||||
pset = ifcopenshell.util.element.get_pset(element, 'BBIM_Linked_Aggregate')
|
||||
if pset:
|
||||
pset = tool.Ifc.get().by_id(pset["id"])
|
||||
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), pset=pset)
|
||||
|
||||
|
||||
class BIM_OT_enable_editing_aggregate(bpy.types.Operator, Operator):
|
||||
@@ -164,6 +175,7 @@ class BIM_OT_add_aggregate(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def create_aggregate(self, context, ifc_class):
|
||||
aggregate = bpy.data.objects.new("Assembly", None)
|
||||
aggregate.location = context.scene.cursor.location
|
||||
bpy.ops.bim.assign_class(obj=aggregate.name, ifc_class=ifc_class)
|
||||
return aggregate
|
||||
|
||||
@@ -202,6 +214,7 @@ class BIM_OT_select_aggregate(bpy.types.Operator):
|
||||
aggregate_obj = tool.Ifc.get_object(aggregate)
|
||||
if aggregate_obj in context.selectable_objects:
|
||||
aggregate_obj.select_set(True)
|
||||
bpy.context.view_layer.objects.active = aggregate_obj
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -228,3 +241,63 @@ class BIM_OT_add_part_to_object(bpy.types.Operator, Operator):
|
||||
part_class=self.part_class,
|
||||
part_name=self.part_name,
|
||||
)
|
||||
|
||||
class BIM_OT_break_link_to_other_aggregates(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.break_link_to_other_aggregates"
|
||||
bl_label = "Break link to other aggregates"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||
aggregate = ifcopenshell.util.element.get_aggregate(element)
|
||||
if not aggregate:
|
||||
return []
|
||||
if not element:
|
||||
return []
|
||||
|
||||
parts = ifcopenshell.util.element.get_parts(aggregate)
|
||||
|
||||
for part in parts:
|
||||
pset = ifcopenshell.util.element.get_pset(part, 'BBIM_Linked_Aggregate')
|
||||
pset = tool.Ifc.get().by_id(pset["id"])
|
||||
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), pset=pset)
|
||||
|
||||
linked_aggregate_group = [
|
||||
r.RelatingGroup
|
||||
for r in getattr(aggregate, "HasAssignments", []) or []
|
||||
if r.is_a("IfcRelAssignsToGroup")
|
||||
if "BBIM_Linked_Aggregate" in r.RelatingGroup.Name
|
||||
]
|
||||
tool.Ifc.run("group.unassign_group", group=linked_aggregate_group[0], product=aggregate)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
class BIM_OT_select_linked_aggregates(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.select_linked_aggregates"
|
||||
bl_label = "Select linked aggregates"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||
aggregate = ifcopenshell.util.element.get_aggregate(element)
|
||||
if not aggregate:
|
||||
return []
|
||||
if not element:
|
||||
return []
|
||||
|
||||
linked_aggregate_group = [
|
||||
r.RelatingGroup
|
||||
for r in getattr(aggregate, "HasAssignments", []) or []
|
||||
if r.is_a("IfcRelAssignsToGroup")
|
||||
if "BBIM_Linked_Aggregate" in r.RelatingGroup.Name
|
||||
]
|
||||
|
||||
for obj in context.selected_objects:
|
||||
obj.select_set(False)
|
||||
|
||||
for rel in linked_aggregate_group[0].IsGroupedBy or []:
|
||||
for element in rel.RelatedObjects:
|
||||
obj = tool.Ifc.get_object(element)
|
||||
obj.select_set(True)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
from bpy.types import Panel
|
||||
from blenderbim.bim.module.aggregate.data import AggregateData
|
||||
from blenderbim.bim.module.group.data import GroupsData, ObjectGroupsData
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
@@ -54,7 +55,7 @@ class BIM_PT_aggregate(Panel):
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, "relating_object", text="")
|
||||
if props.relating_object:
|
||||
op = row.operator("bim.assign_object", icon="CHECKMARK", text="")
|
||||
op = row.operator("bim.aggregate_assign_object", icon="CHECKMARK", text="")
|
||||
op.relating_object = props.relating_object.BIMObjectProperties.ifc_definition_id
|
||||
row.operator("bim.disable_editing_aggregate", icon="CANCEL", text="")
|
||||
else:
|
||||
@@ -65,15 +66,21 @@ class BIM_PT_aggregate(Panel):
|
||||
op.obj = context.active_object.name
|
||||
row.operator("bim.enable_editing_aggregate", icon="GREASEPENCIL", text="")
|
||||
row.operator("bim.add_aggregate", icon="ADD", text="")
|
||||
op = row.operator("bim.unassign_object", icon="X", text="")
|
||||
op = row.operator("bim.aggregate_unassign_object", icon="X", text="")
|
||||
else:
|
||||
row.label(text="No Aggregate", icon="TRIA_UP")
|
||||
row.operator("bim.enable_editing_aggregate", icon="GREASEPENCIL", text="")
|
||||
row.operator("bim.add_aggregate", icon="ADD", text="")
|
||||
|
||||
row = layout.row(align=True)
|
||||
parts = AggregateData.data["related_objects_amount"]
|
||||
row.label(text=f"{parts or 'No'} Part{'s' if parts > 1 else ''}", icon="TRIA_DOWN")
|
||||
total_parts = AggregateData.data["total_parts"]
|
||||
if total_parts == 0:
|
||||
row.label(text="No Parts", icon="TRIA_DOWN")
|
||||
elif total_parts == 1:
|
||||
row.label(text="1 Part", icon="TRIA_DOWN")
|
||||
else:
|
||||
row.label(text=f"{total_parts} Parts", icon="TRIA_DOWN")
|
||||
|
||||
if AggregateData.data["has_related_objects"]:
|
||||
op = row.operator("bim.select_parts", icon="RESTRICT_SELECT_OFF", text="")
|
||||
op.obj = context.active_object.name
|
||||
@@ -90,3 +97,49 @@ class BIM_PT_aggregate(Panel):
|
||||
op = layout.operator("bim.add_part_to_object", text="Add " + part_class.lstrip("Ifc"))
|
||||
op.part_class = part_class
|
||||
op.obj = context.active_object.name
|
||||
|
||||
|
||||
class BIM_PT_linked_aggregate(Panel):
|
||||
bl_label = "Linked Aggregates"
|
||||
bl_idname = "BIM_PT_linked_aggregate"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "object"
|
||||
bl_order = 2
|
||||
bl_parent_id = "BIM_PT_aggregate"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
return False
|
||||
props = context.active_object.BIMObjectProperties
|
||||
if not props.ifc_definition_id:
|
||||
return False
|
||||
if not IfcStore.get_element(props.ifc_definition_id):
|
||||
return False
|
||||
if not IfcStore.get_file().by_id(props.ifc_definition_id).is_a("IfcObjectDefinition"):
|
||||
return False
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
if not AggregateData.is_loaded:
|
||||
AggregateData.load()
|
||||
|
||||
props = context.active_object.BIMObjectAggregateProperties
|
||||
row = layout.row(align=True)
|
||||
row.label(text="Advanced Users Only", icon="ERROR")
|
||||
row = layout.row(align=True)
|
||||
|
||||
if type(AggregateData.data['total_linked_aggregate']) is int:
|
||||
if AggregateData.data['total_linked_aggregate'] > 0:
|
||||
row.label(text=f"{AggregateData.data['total_linked_aggregate']} Linked Aggregates")
|
||||
row.operator("bim.select_linked_aggregates", text="", icon="RESTRICT_SELECT_OFF")
|
||||
row.operator("bim.refresh_linked_aggregate", text="", icon="FILE_REFRESH")
|
||||
op = row.operator("bim.break_link_to_other_aggregates", text="", icon="X")
|
||||
else:
|
||||
row.label(text="No Linked Aggregates")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import bpy
|
||||
import bcf
|
||||
import bcf.v2.bcfxml
|
||||
|
||||
@@ -23,12 +25,31 @@ import bcf.v2.bcfxml
|
||||
class BcfStore:
|
||||
bcfxml = None
|
||||
|
||||
@staticmethod
|
||||
def get_bcfxml():
|
||||
if not BcfStore.bcfxml:
|
||||
BcfStore.bcfxml = bcf.v2.bcfxml.BcfXml()
|
||||
return BcfStore.bcfxml
|
||||
@classmethod
|
||||
def get_bcfxml(cls):
|
||||
if not cls.bcfxml:
|
||||
bcf_filepath = bpy.context.scene.BCFProperties.bcf_file
|
||||
if not os.path.isabs(bcf_filepath):
|
||||
bcf_filepath = os.path.abspath(os.path.join(bpy.path.abspath("//"), bcf_filepath))
|
||||
if bcf_filepath:
|
||||
try:
|
||||
cls.bcfxml = bcf.bcfxml.load(bcf_filepath)
|
||||
except:
|
||||
# there will be a plenty of "Permission denied" errors
|
||||
# as many poll() methods will try to access the bcfxml simultaneously
|
||||
# the first time it's loaded
|
||||
pass
|
||||
return cls.bcfxml
|
||||
|
||||
@classmethod
|
||||
def set(cls, bcfxml):
|
||||
def set(cls, bcfxml, filepath):
|
||||
cls.bcfxml = bcfxml
|
||||
bpy.context.scene.BCFProperties.bcf_file = filepath
|
||||
|
||||
@classmethod
|
||||
def set_by_filepath(cls, filepath):
|
||||
cls.set(None, filepath)
|
||||
|
||||
@classmethod
|
||||
def unload_bcfxml(cls):
|
||||
cls.set(None, "")
|
||||
|
||||
@@ -42,11 +42,9 @@ class NewBcfProject(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BCFProperties.is_loaded = False
|
||||
bcfxml = bcf.v2.bcfxml.BcfXml.create_new("New Project")
|
||||
bcfstore.BcfStore.set(bcfxml)
|
||||
bcfstore.BcfStore.set(bcfxml, "")
|
||||
bpy.ops.bim.load_bcf_project()
|
||||
context.scene.BCFProperties.is_loaded = True
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -59,11 +57,10 @@ class LoadBcfProject(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
if self.filepath:
|
||||
bcfstore.BcfStore.bcfxml = bcf.bcfxml.load(self.filepath)
|
||||
bcfstore.BcfStore.set_by_filepath(self.filepath)
|
||||
bcfxml = bcfstore.BcfStore.get_bcfxml()
|
||||
context.scene.BCFProperties.name = bcfxml.project.name
|
||||
bpy.ops.bim.load_bcf_topics()
|
||||
context.scene.BCFProperties.is_loaded = True
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
@@ -77,8 +74,7 @@ class UnloadBcfProject(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
bcfstore.BcfStore.set(None)
|
||||
context.scene.BCFProperties.is_loaded = False
|
||||
bcfstore.BcfStore.unload_bcfxml()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -267,6 +263,7 @@ class SaveBcfProject(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
bcfxml = bcfstore.BcfStore.get_bcfxml()
|
||||
bcfxml.save(self.filepath)
|
||||
bcfstore.BcfStore.set(bcfxml, self.filepath)
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
@@ -964,7 +961,8 @@ class ActivateBcfViewpoint(bpy.types.Operator):
|
||||
context_override = {}
|
||||
context_override["object"] = context_override["active_object"] = objs[0]
|
||||
context_override["selected_objects"] = context_override["selected_editable_objects"] = objs
|
||||
bpy.ops.object.hide_view_set(context_override, unselected=True)
|
||||
with context.temp_override(**context_override):
|
||||
bpy.ops.object.hide_view_set(unselected=True)
|
||||
context.area.type = old
|
||||
|
||||
if viewpoint.visualization_info.components.view_setup_hints:
|
||||
@@ -978,14 +976,16 @@ class ActivateBcfViewpoint(bpy.types.Operator):
|
||||
self.hide_spaces(context)
|
||||
self.set_openings_visibility(False, context)
|
||||
|
||||
# set selection at the end not to conflict with .hide_spaces
|
||||
self.set_selection(viewpoint)
|
||||
self.set_colours(viewpoint)
|
||||
|
||||
def hide_spaces(self, context):
|
||||
old = context.area.type
|
||||
context.area.type = "VIEW_3D"
|
||||
bpy.ops.object.select_all(action="DESELECT")
|
||||
bpy.ops.object.select_pattern(pattern="IfcSpace/*")
|
||||
bpy.ops.object.hide_view_set({})
|
||||
bpy.ops.object.hide_view_set()
|
||||
context.area.type = old
|
||||
|
||||
def set_openings_visibility(self, is_visible, context):
|
||||
|
||||
@@ -41,37 +41,37 @@ def purge():
|
||||
|
||||
|
||||
def updateBcfReferenceLink(self, context):
|
||||
if context.scene.BCFProperties.is_loaded:
|
||||
if bcfstore.BcfStore.get_bcfxml():
|
||||
bpy.ops.bim.edit_bcf_reference_links()
|
||||
|
||||
|
||||
def updateBcfLabel(self, context):
|
||||
if context.scene.BCFProperties.is_loaded:
|
||||
if bcfstore.BcfStore.get_bcfxml():
|
||||
bpy.ops.bim.edit_bcf_labels()
|
||||
|
||||
|
||||
def updateBcfProjectName(self, context):
|
||||
if self.is_loaded:
|
||||
if bcfstore.BcfStore.get_bcfxml():
|
||||
bpy.ops.bim.edit_bcf_project_name()
|
||||
|
||||
|
||||
def updateBcfAuthor(self, context):
|
||||
if self.is_loaded:
|
||||
if bcfstore.BcfStore.get_bcfxml():
|
||||
bpy.ops.bim.edit_bcf_author()
|
||||
|
||||
|
||||
def updateBcfTopicName(self, context):
|
||||
if context.scene.BCFProperties.is_loaded:
|
||||
if bcfstore.BcfStore.get_bcfxml():
|
||||
bpy.ops.bim.edit_bcf_topic_name()
|
||||
|
||||
|
||||
def updateBcfTopicIsEditable(self, context):
|
||||
if context.scene.BCFProperties.is_loaded and not self.is_editable:
|
||||
if bcfstore.BcfStore.get_bcfxml() and not self.is_editable:
|
||||
bpy.ops.bim.edit_bcf_topic()
|
||||
|
||||
|
||||
def updateBcfCommentIsEditable(self, context):
|
||||
if context.scene.BCFProperties.is_loaded and not self.is_editable:
|
||||
if bcfstore.BcfStore.get_bcfxml() and not self.is_editable:
|
||||
bpy.ops.bim.edit_bcf_comment(comment_guid=self.name)
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ class BcfTopic(PropertyGroup):
|
||||
|
||||
|
||||
class BCFProperties(PropertyGroup):
|
||||
is_loaded: BoolProperty(name="Is Loaded", default=False)
|
||||
bcf_file: StringProperty(name="BCF File")
|
||||
comment_text_width: IntProperty(name="Comment Text Width", default=40)
|
||||
name: StringProperty(default="", name="Project Name", update=updateBcfProjectName)
|
||||
author: StringProperty(default="john@doe.com", name="Author Email", update=updateBcfAuthor)
|
||||
|
||||
@@ -39,8 +39,7 @@ class BIM_PT_bcf(Panel):
|
||||
scene = context.scene
|
||||
props = scene.BCFProperties
|
||||
|
||||
|
||||
if not props.is_loaded:
|
||||
if not bcfstore.BcfStore.get_bcfxml():
|
||||
row = layout.row(align=True)
|
||||
row.operator("bim.new_bcf_project", text="New Project")
|
||||
row.operator("bim.load_bcf_project", text="Load Project")
|
||||
|
||||
@@ -22,6 +22,7 @@ from . import ui, operator, prop
|
||||
classes = (
|
||||
operator.AddBoundary,
|
||||
operator.ColourByRelatedBuildingElement,
|
||||
operator.DecorateBoundaries,
|
||||
operator.DisableEditingBoundary,
|
||||
operator.DisableEditingBoundaryGeometry,
|
||||
operator.EditBoundaryAttributes,
|
||||
|
||||
@@ -62,14 +62,14 @@ class BoundaryDecorator:
|
||||
gpu.state.point_size_set(6)
|
||||
gpu.state.blend_set("ALPHA")
|
||||
|
||||
self.line_shader = gpu.shader.from_builtin("3D_POLYLINE_UNIFORM_COLOR")
|
||||
self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR")
|
||||
self.line_shader.bind() # required to be able to change uniforms of the shader
|
||||
# POLYLINE_UNIFORM_COLOR specific uniforms
|
||||
self.line_shader.uniform_float("viewportSize", (context.region.width, context.region.height))
|
||||
self.line_shader.uniform_float("lineWidth", 2.0)
|
||||
|
||||
# general shader
|
||||
self.shader = gpu.shader.from_builtin("3D_UNIFORM_COLOR")
|
||||
self.shader = gpu.shader.from_builtin("UNIFORM_COLOR")
|
||||
|
||||
selected_vertices = []
|
||||
selected_edges = []
|
||||
|
||||
@@ -22,7 +22,9 @@ import logging
|
||||
import shapely
|
||||
import mathutils
|
||||
import numpy as np
|
||||
import multiprocessing
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.util.unit
|
||||
import ifcopenshell.util.shape
|
||||
import ifcopenshell.util.element
|
||||
@@ -30,12 +32,13 @@ import ifcopenshell.util.placement
|
||||
import ifcopenshell.util.representation
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim.import_ifc as import_ifc
|
||||
from math import pi, inf
|
||||
from math import pi, inf, degrees, acos, radians
|
||||
from mathutils import Vector, Matrix
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.model.decorator import ProfileDecorator
|
||||
from blenderbim.bim.module.boundary.decorator import BoundaryDecorator
|
||||
import blenderbim.core
|
||||
import blenderbim.core.geometry
|
||||
|
||||
|
||||
def get_boundaries_collection(blender_space):
|
||||
@@ -63,7 +66,8 @@ def disable_editing_boundary_geometry(context):
|
||||
|
||||
|
||||
class Loader:
|
||||
def __init__(self):
|
||||
def __init__(self, operator=None):
|
||||
self.operator = operator
|
||||
self.ifc_file = None
|
||||
self.logger = None
|
||||
self.ifc_importer = None
|
||||
@@ -85,14 +89,33 @@ class Loader:
|
||||
tool.Loader.link_mesh(shape, mesh)
|
||||
except RuntimeError:
|
||||
# Fallback solution for invalid geometry provided by Revit. (InnerBoundaries cuting OuterBoundary)
|
||||
print(f"Failed to create mesh from IfcRelSpaceBoundary with ID {boundary.id()}. Geometry might be invalid")
|
||||
shape = ifcopenshell.geom.create_shape(self.fallback_settings, surface.OuterBoundary)
|
||||
self.operator.report(
|
||||
{"WARNING"},
|
||||
(
|
||||
f"IfcRelSpaceBoundary {boundary.id()} mesh creation failed. Geometry might be invalid. Using fallback solution"
|
||||
),
|
||||
)
|
||||
try:
|
||||
shape = ifcopenshell.geom.create_shape(self.fallback_settings, surface.OuterBoundary)
|
||||
except RuntimeError:
|
||||
self.operator.report(
|
||||
{"WARNING"},
|
||||
f"Skipping IfcRelSpaceBoundary {boundary.id()}. Fallback solution failed. Geometry might be invalid",
|
||||
)
|
||||
return None
|
||||
mesh = bpy.data.meshes.new(str(surface.id()))
|
||||
bm = bmesh.new()
|
||||
verts = [bm.verts.new(shape.verts[i : i + 3]) for i in range(0, len(shape.verts), 3)]
|
||||
bm.faces.new(verts)
|
||||
for inner_boundary in surface.InnerBoundaries:
|
||||
shape = ifcopenshell.geom.create_shape(self.fallback_settings, inner_boundary)
|
||||
try:
|
||||
shape = ifcopenshell.geom.create_shape(self.fallback_settings, inner_boundary)
|
||||
except RuntimeError:
|
||||
self.operator.report(
|
||||
{"WARNING"},
|
||||
f"Skipping an inner boundary for IfcRelSpaceBoundary with ID {boundary.id()}. Geometry might be invalid",
|
||||
)
|
||||
return None
|
||||
verts = [bm.verts.new(shape.verts[i : i + 3]) for i in range(0, len(shape.verts), 3)]
|
||||
for i in range(len(verts) - 1):
|
||||
bm.edges.new(verts[i : i + 2])
|
||||
@@ -103,7 +126,7 @@ class Loader:
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
matrix = mathutils.Matrix(
|
||||
ifcopenshell.util.placement.get_axis2placement(surface.BasisSurface.Position).tolist()
|
||||
)
|
||||
)
|
||||
matrix.translation *= unit_scale
|
||||
mesh.transform(matrix)
|
||||
return mesh
|
||||
@@ -126,7 +149,17 @@ class Loader:
|
||||
self.ifc_importer = import_ifc.IfcImporter(ifc_import_settings)
|
||||
self.ifc_importer.file = self.ifc_file
|
||||
|
||||
def load_boundary(self, boundary, blender_space):
|
||||
def load_boundary(
|
||||
self, boundary: ifcopenshell.entity_instance, blender_space: bpy.types.Object = None
|
||||
) -> bpy.types.Object:
|
||||
if not blender_space:
|
||||
if not boundary.RelatingSpace:
|
||||
self.operator.report(
|
||||
{"WARNING"},
|
||||
f"Skipping IfcRelSpaceBoundary {boundary.id()} which have no relating space. Invalid boundary.",
|
||||
)
|
||||
return
|
||||
blender_space = tool.Ifc.get_object(boundary.RelatingSpace)
|
||||
obj = tool.Ifc.get_object(boundary)
|
||||
if obj:
|
||||
return obj
|
||||
@@ -145,9 +178,9 @@ class LoadProjectSpaceBoundaries(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
loader = Loader()
|
||||
loader = Loader(self)
|
||||
for rel in tool.Ifc.get().by_type("IfcRelSpaceBoundary"):
|
||||
loader.load_boundary(rel, tool.Ifc.get_object(rel.RelatingSpace))
|
||||
loader.load_boundary(rel)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -158,7 +191,7 @@ class LoadBoundary(bpy.types.Operator):
|
||||
boundary_id: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
loader = Loader()
|
||||
loader = Loader(self)
|
||||
for obj in context.visible_objects:
|
||||
obj.select_set(False)
|
||||
obj = loader.load_boundary(tool.Ifc.get().by_id(self.boundary_id), context.active_object)
|
||||
@@ -173,7 +206,7 @@ class LoadSpaceBoundaries(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
loader = Loader()
|
||||
loader = Loader(self)
|
||||
element = tool.Ifc.get_entity(context.active_object)
|
||||
for rel in element.BoundedBy or []:
|
||||
loader.load_boundary(rel, context.active_object)
|
||||
@@ -421,7 +454,7 @@ class EnableEditingBoundaryGeometry(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
ProfileDecorator.install(context, exit_edit_mode_callback=lambda: disable_editing_boundary_geometry(context))
|
||||
if not bpy.app.background:
|
||||
bpy.ops.wm.tool_set_by_id(tool.Blender.get_viewport_context(), name="bim.cad_tool")
|
||||
tool.Blender.set_viewport_tool("bim.cad_tool")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -459,7 +492,7 @@ class EditBoundaryGeometry(bpy.types.Operator, tool.Ifc.Operator):
|
||||
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), old_surface)
|
||||
|
||||
old_mesh = obj.data
|
||||
loader = Loader()
|
||||
loader = Loader(self)
|
||||
obj.data = loader.create_mesh(element)
|
||||
tool.Geometry.delete_data(old_mesh)
|
||||
|
||||
@@ -480,11 +513,11 @@ class DisableEditingBoundaryGeometry(bpy.types.Operator, tool.Ifc.Operator):
|
||||
class ShowBoundaries(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.show_boundaries"
|
||||
bl_label = "Show Boundaries"
|
||||
bl_description = "Load selected objects boundaries if they are not loaded"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = bpy.context.scene.BIMBoundaryProperties
|
||||
loader = Loader()
|
||||
loader = Loader(self)
|
||||
for obj in context.selected_objects:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element or not getattr(element, "BoundedBy", None):
|
||||
@@ -495,7 +528,7 @@ class ShowBoundaries(bpy.types.Operator, tool.Ifc.Operator):
|
||||
for rel in element.BoundedBy or []:
|
||||
boundary_obj = loader.load_boundary(rel, obj)
|
||||
tool.Boundary.decorate_boundary(boundary_obj)
|
||||
BoundaryDecorator.install(bpy.context)
|
||||
BoundaryDecorator.install(context)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -528,6 +561,36 @@ class HideBoundaries(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DecorateBoundaries(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.decorate_boundaries"
|
||||
bl_label = "Toggle Boundaries Decorations"
|
||||
bl_description = "Add special decorations for all boundaries in the scene or hide them if they are already added"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMBoundaryProperties
|
||||
# filter not decorated boundaries and add decorations for them
|
||||
decorated_boundaries = set([i.obj for i in props.boundaries])
|
||||
active_boundaries = set()
|
||||
for element in tool.Ifc.get().by_type("IfcRelSpaceBoundary"):
|
||||
obj = tool.Ifc.get_object(element)
|
||||
if obj is not None:
|
||||
active_boundaries.add(obj)
|
||||
|
||||
boundaries_to_decorate = active_boundaries - decorated_boundaries
|
||||
if boundaries_to_decorate:
|
||||
for obj in boundaries_to_decorate:
|
||||
tool.Boundary.decorate_boundary(obj)
|
||||
BoundaryDecorator.install(context)
|
||||
else:
|
||||
for obj in decorated_boundaries:
|
||||
tool.Boundary.undecorate_boundary(obj)
|
||||
props.boundaries.clear()
|
||||
BoundaryDecorator.uninstall()
|
||||
tool.Blender.update_viewport()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_boundary"
|
||||
bl_label = "Add Boundary"
|
||||
@@ -538,6 +601,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
related_building_element = None
|
||||
relating_space_obj = None
|
||||
related_building_element_obj = None
|
||||
parent_boundaries = []
|
||||
|
||||
objs = context.selected_objects
|
||||
if len(objs) == 2:
|
||||
@@ -552,8 +616,19 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
else:
|
||||
related_building_element = element
|
||||
related_building_element_obj = obj
|
||||
parent_boundary = self.create_element_boundary(
|
||||
context, relating_space, relating_space_obj, related_building_element, related_building_element_obj
|
||||
)
|
||||
if parent_boundary:
|
||||
parent_boundaries.append(parent_boundary)
|
||||
elif len(objs) == 1:
|
||||
# New prototype, old code not yet removed. Still testing.
|
||||
space = tool.Ifc.get_entity(objs[0])
|
||||
if space.is_a("IfcSpace"):
|
||||
self.auto_generate_boundaries(space, objs[0])
|
||||
elif len(objs) == 1:
|
||||
# Optionally the user may select just the space, and the building element shall be auto-detected
|
||||
# TODO : refactor to be able to generate all boundaries for selected space automatically or with an option
|
||||
|
||||
def msg(self, context):
|
||||
self.layout.label(text="NO ACTIVE STOREY")
|
||||
@@ -563,8 +638,6 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
relating_space = element
|
||||
relating_space_obj = objs[0]
|
||||
|
||||
target = bpy.context.scene.cursor.location
|
||||
|
||||
collection = context.view_layer.active_layer_collection.collection
|
||||
collection_obj = bpy.data.objects.get(collection.name)
|
||||
if not collection_obj:
|
||||
@@ -576,19 +649,258 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return
|
||||
|
||||
for subelement in ifcopenshell.util.element.get_decomposition(spatial_element):
|
||||
if not (subelement.is_a("IfcWall") or subelement.is_a("IfcSlab")):
|
||||
if not (
|
||||
subelement.is_a("IfcWall") or subelement.is_a("IfcSlab") or subelement.is_a("IfcVirtualElement")
|
||||
):
|
||||
continue
|
||||
obj = tool.Ifc.get_object(subelement)
|
||||
if obj:
|
||||
raycast = obj.closest_point_on_mesh(obj.matrix_world.inverted() @ target, distance=0.1)
|
||||
if raycast[0]:
|
||||
related_building_element = subelement
|
||||
related_building_element_obj = obj
|
||||
break
|
||||
related_building_element = subelement
|
||||
related_building_element_obj = obj
|
||||
parent_boundary = self.create_element_boundary(
|
||||
context,
|
||||
relating_space,
|
||||
relating_space_obj,
|
||||
related_building_element,
|
||||
related_building_element_obj,
|
||||
)
|
||||
if parent_boundary:
|
||||
parent_boundaries.append(parent_boundary)
|
||||
|
||||
bpy.ops.bim.show_boundaries()
|
||||
for parent_boundary in parent_boundaries:
|
||||
obj = tool.Ifc.get_object(parent_boundary)
|
||||
obj.select_set(True)
|
||||
|
||||
def auto_generate_boundaries(self, space, space_obj):
|
||||
# Identify all potential building elements
|
||||
# TODO: don't select everything, use AABB culling in Blender
|
||||
building_elements = (
|
||||
tool.Ifc.get().by_type("IfcWall")
|
||||
+ tool.Ifc.get().by_type("IfcSlab")
|
||||
+ tool.Ifc.get().by_type("IfcVirtualElement")
|
||||
)
|
||||
|
||||
# Don't generate boundaries of building elements that we've already got bounaries for.
|
||||
for boundary in space.BoundedBy:
|
||||
if boundary.RelatedBuildingElement in building_elements:
|
||||
building_elements.remove(boundary.RelatedBuildingElement)
|
||||
|
||||
# Create tree of gross shapes of all potential related building elements
|
||||
include = building_elements + [space]
|
||||
tree = ifcopenshell.geom.tree()
|
||||
shapes = {}
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set(settings.STRICT_TOLERANCE, True)
|
||||
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, True)
|
||||
iterator = ifcopenshell.geom.iterator(settings, tool.Ifc.get(), multiprocessing.cpu_count(), include=include)
|
||||
if iterator.initialize():
|
||||
while True:
|
||||
tree.add_element(iterator.get_native())
|
||||
shape = iterator.get()
|
||||
shapes[shape.id] = shape
|
||||
if not iterator.next():
|
||||
break
|
||||
|
||||
# Spatially query all potential boundary elements via a 100mm extension of the space
|
||||
building_elements = [e for e in tree.select(space, extend=0.1) if e != space]
|
||||
|
||||
if not building_elements:
|
||||
return
|
||||
|
||||
# Create a dissolved bmesh for the space
|
||||
space_bm = bmesh.new()
|
||||
space_bm.from_mesh(space_obj.data)
|
||||
bmesh.ops.dissolve_limit(space_bm, angle_limit=pi * 2 / 360, verts=space_bm.verts, edges=space_bm.edges)
|
||||
|
||||
# Create dissolved bmeshes for all boundary elements
|
||||
building_element_bms = {}
|
||||
for building_element in building_elements:
|
||||
bm = bmesh.new()
|
||||
shape = shapes[building_element.id()]
|
||||
|
||||
verts = ifcopenshell.util.shape.get_vertices(shape.geometry)
|
||||
for vert in verts:
|
||||
bm.verts.new(Vector(vert))
|
||||
bm.verts.ensure_lookup_table()
|
||||
|
||||
faces = ifcopenshell.util.shape.get_faces(shape.geometry)
|
||||
for face in faces:
|
||||
bm.faces.new([bm.verts[i] for i in face])
|
||||
bm.verts.ensure_lookup_table()
|
||||
bm.faces.ensure_lookup_table()
|
||||
bm.normal_update() # Needed so that dissolve_limit will work.
|
||||
bmesh.ops.dissolve_limit(bm, angle_limit=radians(1), verts=bm.verts[:], edges=bm.edges[:])
|
||||
bm.verts.ensure_lookup_table()
|
||||
bm.faces.ensure_lookup_table()
|
||||
building_element_bms[building_element.id()] = bm
|
||||
|
||||
# Compare space faces and building element faces to see if they relate to one another
|
||||
for space_face in space_bm.faces:
|
||||
space_face_normal = space_obj.matrix_world.to_3x3() @ space_face.normal
|
||||
space_face_vert = space_obj.matrix_world @ space_face.verts[0].co
|
||||
for building_element in building_elements:
|
||||
for face in building_element_bms[building_element.id()].faces:
|
||||
building_obj = tool.Ifc.get_object(building_element)
|
||||
face_normal = building_obj.matrix_world.to_3x3() @ face.normal
|
||||
angle = degrees(acos(max(min(space_face_normal.dot(face_normal), 1), -1)))
|
||||
if tool.Cad.is_x(angle, 180, tolerance=2):
|
||||
pass # Faces need to be parallel and have opposite normals to be related.
|
||||
elif building_element.is_a("IfcVirtualElement") and tool.Cad.is_x(angle, 0, tolerance=2):
|
||||
pass # Virtual elements only need to be parallel to be related, since they are planes.
|
||||
else:
|
||||
continue
|
||||
|
||||
# Both faces should be close to one another. Say within 50mm.
|
||||
space_vert = building_obj.matrix_world.inverted() @ space_face_vert
|
||||
dist = mathutils.geometry.distance_point_to_plane(space_vert, face.verts[0].co, face.normal)
|
||||
if abs(dist) > 0.05:
|
||||
continue
|
||||
|
||||
# Project the building element face onto the space face
|
||||
space_face_verts = [v.co.copy() for v in space_face.verts]
|
||||
space_face_matrix = self.get_face_matrix(*[v.copy() for v in space_face_verts[0:3]])
|
||||
space_face_matrix_i = space_face_matrix.inverted()
|
||||
|
||||
space_face_polygon = shapely.Polygon(
|
||||
[tuple((space_face_matrix_i @ v).xy) for v in space_face_verts]
|
||||
)
|
||||
|
||||
space_matrix_world_i = space_obj.matrix_world.inverted()
|
||||
face_verts = [space_matrix_world_i @ building_obj.matrix_world @ v.co.copy() for v in face.verts]
|
||||
face_polygon = shapely.Polygon([tuple((space_face_matrix_i @ v).xy) for v in face_verts])
|
||||
|
||||
gross_boundary_polygon = space_face_polygon.intersection(face_polygon)
|
||||
|
||||
if type(gross_boundary_polygon) == shapely.GeometryCollection:
|
||||
for geom in gross_boundary_polygon.geoms:
|
||||
if type(geom) == shapely.Polygon:
|
||||
gross_boundary_polygon = geom
|
||||
break
|
||||
|
||||
if (
|
||||
not (isinstance(gross_boundary_polygon, shapely.Polygon) and gross_boundary_polygon.is_valid)
|
||||
or gross_boundary_polygon.is_empty
|
||||
):
|
||||
continue
|
||||
|
||||
# The gross boundary polygon may not be a true gross boundary since it
|
||||
# may have openings already removed, such as in IFC4 Reference View. So
|
||||
# we cheat by using the exterior boundary to mean "gross".
|
||||
exterior_boundary_polygon = shapely.Polygon(gross_boundary_polygon.exterior.coords)
|
||||
|
||||
parent_boundary = tool.Ifc.run(
|
||||
"root.create_entity", ifc_class=bpy.context.scene.BIMModelProperties.boundary_class
|
||||
)
|
||||
if building_element.is_a("IfcVirtualElement"):
|
||||
parent_boundary.PhysicalOrVirtualBoundary = "VIRTUAL"
|
||||
else:
|
||||
parent_boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
|
||||
parent_boundary.InternalOrExternalBoundary = "NOTDEFINED"
|
||||
if building_element.is_a("IfcWall"):
|
||||
is_external = ifcopenshell.util.element.get_pset(
|
||||
building_element, "Pset_WallCommon", "IsExternal"
|
||||
)
|
||||
if is_external is True:
|
||||
parent_boundary.InternalOrExternalBoundary = "EXTERNAL"
|
||||
elif is_external is False:
|
||||
parent_boundary.InternalOrExternalBoundary = "INTERNAL"
|
||||
elif building_element.is_a("IfcSlab"):
|
||||
predefined_type = ifcopenshell.util.element.get_predefined_type(building_element)
|
||||
if predefined_type == "BASESLAB":
|
||||
parent_boundary.InternalOrExternalBoundary = "EXTERNAL_EARTH"
|
||||
else:
|
||||
is_external = ifcopenshell.util.element.get_pset(
|
||||
building_element, "Pset_SlabCommon", "IsExternal"
|
||||
)
|
||||
if is_external is True:
|
||||
parent_boundary.InternalOrExternalBoundary = "EXTERNAL"
|
||||
elif is_external is False:
|
||||
parent_boundary.InternalOrExternalBoundary = "INTERNAL"
|
||||
parent_boundary.RelatingSpace = space
|
||||
parent_boundary.RelatedBuildingElement = building_element
|
||||
parent_boundary.ConnectionGeometry = self.create_connection_geometry_from_polygon(
|
||||
exterior_boundary_polygon, space_face_matrix
|
||||
)
|
||||
self.set_boundary_name(parent_boundary)
|
||||
|
||||
for rel in getattr(building_element, "HasOpenings", []):
|
||||
opening = rel.RelatedOpeningElement
|
||||
filling = opening.HasFillings[0].RelatedBuildingElement if opening.HasFillings else None
|
||||
|
||||
# Create shape of opening as a dissolved BMesh
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set(settings.STRICT_TOLERANCE, True)
|
||||
shape = ifcopenshell.geom.create_shape(settings, opening)
|
||||
m = shape.transformation.matrix.data
|
||||
mat = Matrix(
|
||||
(
|
||||
[m[0], m[3], m[6], m[9]],
|
||||
[m[1], m[4], m[7], m[10]],
|
||||
[m[2], m[5], m[8], m[11]],
|
||||
[0, 0, 0, 1],
|
||||
)
|
||||
)
|
||||
opening_bm = bmesh.new()
|
||||
verts = ifcopenshell.util.shape.get_vertices(shape.geometry)
|
||||
for vert in verts:
|
||||
opening_bm.verts.new(Vector(vert))
|
||||
opening_bm.verts.ensure_lookup_table()
|
||||
faces = ifcopenshell.util.shape.get_faces(shape.geometry)
|
||||
for face in faces:
|
||||
opening_bm.faces.new([opening_bm.verts[i] for i in face])
|
||||
opening_bm.verts.ensure_lookup_table()
|
||||
opening_bm.faces.ensure_lookup_table()
|
||||
opening_bm.normal_update() # Needed so that dissolve_limit will work.
|
||||
bmesh.ops.dissolve_limit(
|
||||
opening_bm, angle_limit=radians(1), verts=opening_bm.verts[:], edges=opening_bm.edges[:]
|
||||
)
|
||||
opening_bm.verts.ensure_lookup_table()
|
||||
opening_bm.faces.ensure_lookup_table()
|
||||
|
||||
# Get relevant faces of BMesh that can turn into boundaries
|
||||
opening_polygons = []
|
||||
for opening_face in opening_bm.faces:
|
||||
opening_face_normal = mat.to_3x3() @ opening_face.normal
|
||||
angle = degrees(acos(max(min(opening_face_normal.dot(face_normal), 1), -1)))
|
||||
if not tool.Cad.is_x(angle, 180, tolerance=2):
|
||||
continue # Any non-parallel faces are not relevant
|
||||
opening_face_verts = [space_matrix_world_i @ mat @ v.co.copy() for v in opening_face.verts]
|
||||
polygon = shapely.Polygon([tuple((space_face_matrix_i @ v).xy) for v in opening_face_verts])
|
||||
opening_polygons.append(polygon)
|
||||
|
||||
# Merge them all into a single opening polygon for our boundary
|
||||
opening_polygon = shapely.ops.unary_union(opening_polygons)
|
||||
|
||||
# Only openings that are projected onto our exterior boundary are relevant.
|
||||
if opening_polygon.intersection(exterior_boundary_polygon).area == 0:
|
||||
continue
|
||||
|
||||
boundary = tool.Ifc.run(
|
||||
"root.create_entity", ifc_class=bpy.context.scene.BIMModelProperties.boundary_class
|
||||
)
|
||||
boundary.RelatingSpace = space
|
||||
boundary.RelatedBuildingElement = filling or opening
|
||||
boundary.ConnectionGeometry = self.create_connection_geometry_from_polygon(
|
||||
opening_polygon, space_face_matrix
|
||||
)
|
||||
if filling:
|
||||
boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
|
||||
else:
|
||||
boundary.PhysicalOrVirtualBoundary = "VIRTUAL"
|
||||
boundary.InternalOrExternalBoundary = parent_boundary.InternalOrExternalBoundary
|
||||
if boundary.is_a() != "IfcRelSpaceBoundary":
|
||||
boundary.ParentBoundary = parent_boundary
|
||||
self.set_boundary_name(boundary)
|
||||
|
||||
def create_element_boundary(
|
||||
self, context, relating_space, relating_space_obj, related_building_element, related_building_element_obj
|
||||
):
|
||||
if not relating_space or not related_building_element:
|
||||
return
|
||||
|
||||
# Find which face on space should be bounded to related building element
|
||||
# TODO: Handle round wall where multiple faces need to be bound to the same related building element
|
||||
bm = bmesh.new()
|
||||
bm.from_mesh(relating_space_obj.data)
|
||||
bmesh.ops.dissolve_limit(bm, angle_limit=pi * 2 / 360, verts=bm.verts, edges=bm.edges)
|
||||
@@ -609,8 +921,6 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
if not target_face:
|
||||
return
|
||||
|
||||
parent_boundary = tool.Ifc.run("root.create_entity", ifc_class=context.scene.BIMModelProperties.boundary_class)
|
||||
|
||||
# Is this right? Or should I use loop?
|
||||
target_face_verts = [v.co.copy() for v in target_face.verts]
|
||||
target_face_matrix = self.get_face_matrix(*[v.copy() for v in target_face_verts[0:3]])
|
||||
@@ -630,6 +940,18 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
gross_boundary_polygon = geom
|
||||
break
|
||||
|
||||
if (
|
||||
not (isinstance(gross_boundary_polygon, shapely.Polygon) and gross_boundary_polygon.is_valid)
|
||||
or gross_boundary_polygon.is_empty
|
||||
):
|
||||
return
|
||||
|
||||
parent_boundary = tool.Ifc.run("root.create_entity", ifc_class=context.scene.BIMModelProperties.boundary_class)
|
||||
parent_boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
|
||||
# Set to EXTERNAL by default and turn later to internal if there is a corresponding boundary relating to an
|
||||
# internal space
|
||||
parent_boundary.InternalOrExternalBoundary = "EXTERNAL"
|
||||
|
||||
# The gross boundary polygon may not be a true gross boundary since it
|
||||
# may have openings already removed, such as in IFC4 Reference View. So
|
||||
# we cheat by using the exterior boundary to mean "gross". Later, we
|
||||
@@ -637,19 +959,25 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
# space.
|
||||
exterior_boundary_polygon = shapely.Polygon(gross_boundary_polygon.exterior.coords)
|
||||
|
||||
net_boundary_polygon = shapely.Polygon(gross_boundary_polygon)
|
||||
|
||||
inner_boundaries = []
|
||||
|
||||
for rel in getattr(related_building_element, "HasOpenings", []):
|
||||
opening = rel.RelatedOpeningElement
|
||||
filling = None
|
||||
if opening.HasFillings:
|
||||
filling = opening.HasFillings[0].RelatedBuildingElement
|
||||
if not opening.HasFillings:
|
||||
continue
|
||||
# TODO: HasFilling is a zero to many relationship. How to handle many ?
|
||||
filling = opening.HasFillings[0].RelatedBuildingElement
|
||||
|
||||
opening_polygon = self.get_flattened_polygon(opening, relating_space_obj, target_face_matrix_i)
|
||||
|
||||
net_boundary_polygon = net_boundary_polygon.difference(opening_polygon)
|
||||
# An inner boundary is supposed to overlap its parent boundary according to IFC4 documentation
|
||||
# so we extend our exterior boundary with all opening which has a filling
|
||||
# Also see Implementation aggreement SB 1.1 for IFC 2x3 TC1 Space Boundary Addon View
|
||||
# https://standards.buildingsmart.org/MVD/RELEASE/IFC2x3/TC1/SB1_1/IFC%20Space%20Boundary%20Implementation%20Agreement%20Addendum%202010-03-22.pdf
|
||||
unionised_object = exterior_boundary_polygon.union(opening_polygon)
|
||||
if isinstance(unionised_object, shapely.Polygon):
|
||||
exterior_boundary_polygon = unionised_object
|
||||
|
||||
# Only openings that are projected onto our exterior boundary are relevant.
|
||||
if opening_polygon.intersection(exterior_boundary_polygon).area == 0:
|
||||
continue
|
||||
@@ -657,24 +985,25 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
connection_geometry = self.create_connection_geometry_from_polygon(opening_polygon, target_face_matrix)
|
||||
boundary = tool.Ifc.run("root.create_entity", ifc_class=context.scene.BIMModelProperties.boundary_class)
|
||||
boundary.RelatingSpace = relating_space
|
||||
boundary.RelatedBuildingElement = filling or related_building_element
|
||||
boundary.RelatedBuildingElement = filling
|
||||
boundary.ConnectionGeometry = connection_geometry
|
||||
boundary.PhysicalOrVirtualBoundary = "PHYSICAL" if filling else "VIRTUAL"
|
||||
boundary.InternalOrExternalBoundary = "INTERNAL"
|
||||
|
||||
if related_building_element.is_a("IfcVirtualElement"):
|
||||
boundary.PhysicalOrVirtualBoundary = "VIRTUAL"
|
||||
else:
|
||||
boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
|
||||
boundary.InternalOrExternalBoundary = parent_boundary.InternalOrExternalBoundary
|
||||
self.set_boundary_name(boundary)
|
||||
if boundary.is_a("IfcRelSpaceBoundary2ndLevel"):
|
||||
boundary.ParentBoundary = parent_boundary
|
||||
|
||||
connection_geometry = self.create_connection_geometry_from_polygon(net_boundary_polygon, target_face_matrix)
|
||||
connection_geometry = self.create_connection_geometry_from_polygon(
|
||||
exterior_boundary_polygon, target_face_matrix
|
||||
)
|
||||
parent_boundary.RelatingSpace = relating_space
|
||||
parent_boundary.RelatedBuildingElement = related_building_element
|
||||
parent_boundary.ConnectionGeometry = connection_geometry
|
||||
parent_boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
|
||||
parent_boundary.InternalOrExternalBoundary = "INTERNAL"
|
||||
|
||||
bpy.ops.bim.show_boundaries()
|
||||
obj = tool.Ifc.get_object(parent_boundary)
|
||||
obj.select_set(True)
|
||||
self.set_boundary_name(parent_boundary)
|
||||
return parent_boundary
|
||||
|
||||
def get_face_matrix(self, p1, p2, p3):
|
||||
edge1 = p2 - p1
|
||||
@@ -729,11 +1058,13 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
tool.Model.unit_scale = self.unit_scale
|
||||
|
||||
surface = tool.Ifc.get().createIfcCurveBoundedPlane()
|
||||
surface.BasisSurface = tool.Ifc.get().createIfcPlane(tool.Ifc.get().createIfcAxis2Placement3D(
|
||||
tool.Ifc.get().createIfcCartesianPoint([o / self.unit_scale for o in p1]),
|
||||
tool.Ifc.get().createIfcDirection([float(o) for o in z_axis]),
|
||||
tool.Ifc.get().createIfcDirection([float(o) for o in x_axis]),
|
||||
))
|
||||
surface.BasisSurface = tool.Ifc.get().createIfcPlane(
|
||||
tool.Ifc.get().createIfcAxis2Placement3D(
|
||||
tool.Ifc.get().createIfcCartesianPoint([o / self.unit_scale for o in p1]),
|
||||
tool.Ifc.get().createIfcDirection([float(o) for o in z_axis]),
|
||||
tool.Ifc.get().createIfcDirection([float(o) for o in x_axis]),
|
||||
)
|
||||
)
|
||||
|
||||
if tool.Ifc.get().schema != "IFC2X3":
|
||||
points = [tool.Model.convert_si_to_unit(list(co)) for co in polygon.exterior.coords]
|
||||
@@ -746,9 +1077,24 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
point_list = tool.Ifc.get().createIfcCartesianPointList2D(points)
|
||||
inner_boundaries.append(tool.Ifc.get().createIfcIndexedPolyCurve(point_list, None, False))
|
||||
else:
|
||||
pass # TODO
|
||||
pass # TODO
|
||||
|
||||
surface.OuterBoundary = outer_boundary
|
||||
surface.InnerBoundaries = inner_boundaries
|
||||
|
||||
return surface
|
||||
|
||||
def set_boundary_name(self, boundary):
|
||||
"""
|
||||
By convention 1stLevel and 2ndLevel boundary have specific name and description
|
||||
See https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRelSpaceBoundary.htm
|
||||
Warning: IfcRelSpaceBoundary2ndLevel is a subclass of IfcRelSpaceBoundary1stLevel test order matter
|
||||
"""
|
||||
if boundary.is_a("IfcRelSpaceBoundary2ndLevel"):
|
||||
boundary.Name = "2ndLevel"
|
||||
if boundary.CorrespondingBoundary:
|
||||
boundary.Description = "2a"
|
||||
else:
|
||||
boundary.Description = "2b"
|
||||
elif boundary.is_a("IfcRelSpaceBoundary1stLevel"):
|
||||
boundary.Name = "1stLevel"
|
||||
|
||||
@@ -31,7 +31,7 @@ class BIM_PT_SceneBoundaries(Panel):
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_geometry"
|
||||
bl_parent_id = "BIM_PT_tab_geometry"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
||||
@@ -35,13 +35,16 @@ classes = (
|
||||
operator.ViewBrickItem,
|
||||
operator.SerializeBrick,
|
||||
operator.AddBrickNamespace,
|
||||
operator.SetBrickListRoot,
|
||||
operator.RemoveBrickRelation,
|
||||
prop.Brick,
|
||||
prop.BIMBrickProperties,
|
||||
ui.BIM_PT_brickschema,
|
||||
ui.BIM_PT_ifc_brickschema_references,
|
||||
ui.BIM_PT_brickschema_project_info,
|
||||
ui.BIM_PT_brickschema_namespaces,
|
||||
ui.BIM_PT_brickschema_create_entity,
|
||||
ui.BIM_PT_brickschema_viewport,
|
||||
ui.BIM_UL_bricks,
|
||||
ui.BIM_PT_ifc_brickschema_references,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class BrickschemaData:
|
||||
|
||||
@classmethod
|
||||
def get_is_loaded(cls):
|
||||
return BrickStore.graph is not None
|
||||
return BrickStore.graph is not None # `if BrickStore.graph` by itself takes ages.
|
||||
|
||||
@classmethod
|
||||
def active_relations(cls):
|
||||
@@ -67,45 +67,63 @@ class BrickschemaData:
|
||||
PREFIX brick: <https://brickschema.org/schema/Brick#>
|
||||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||||
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
||||
SELECT DISTINCT ?predicate ?object ?sp ?sv WHERE {
|
||||
<{uri}> ?predicate ?object .
|
||||
OPTIONAL {
|
||||
{ ?predicate rdfs:range brick:TimeseriesReference . }
|
||||
UNION
|
||||
{ ?predicate a brick:EntityProperty . }
|
||||
?object ?sp ?sv }
|
||||
SELECT DISTINCT ?predicate ?object ?label ?sp ?sv WHERE {
|
||||
<{uri}> ?predicate ?object .
|
||||
OPTIONAL {
|
||||
?object rdfs:label ?label .
|
||||
}
|
||||
OPTIONAL {
|
||||
{ ?predicate rdfs:range brick:TimeseriesReference . }
|
||||
UNION
|
||||
{ ?predicate a brick:EntityProperty . }
|
||||
?object ?sp ?sv .
|
||||
}
|
||||
}
|
||||
GROUP BY ?object
|
||||
""".replace(
|
||||
"{uri}", uri
|
||||
)
|
||||
)
|
||||
for row in query:
|
||||
predicate = row.get("predicate")
|
||||
predicate_name = predicate.toPython().split("#")[-1]
|
||||
object = row.get("object")
|
||||
object_name = object.toPython().split("#")[-1]
|
||||
predicate_uri = row.get("predicate")
|
||||
predicate_name = predicate_uri.toPython().split("#")[-1]
|
||||
object_uri = row.get("object")
|
||||
object_name = row.get("label")
|
||||
if not object_name:
|
||||
if isinstance(object_uri, BNode):
|
||||
object_name = "[]"
|
||||
else:
|
||||
try:
|
||||
object_name = object_uri.toPython().split("#")[-1]
|
||||
except:
|
||||
object_name = str(object_uri)
|
||||
results.append(
|
||||
{
|
||||
"predicate": predicate,
|
||||
"predicate_uri": predicate_uri,
|
||||
"predicate_name": predicate_name,
|
||||
"object": object,
|
||||
"object_uri": object_uri,
|
||||
"object_name": object_name,
|
||||
"is_uri": isinstance(object, URIRef),
|
||||
"object_uri": object.toPython(),
|
||||
"is_globalid": predicate == "globalID",
|
||||
"is_uri": isinstance(object_uri, URIRef),
|
||||
"is_globalid": predicate_name == "ifcGlobalID",
|
||||
}
|
||||
)
|
||||
# if isinstance(row.get("object"), BNode):
|
||||
# for s, p, o in BrickStore.graph.triples((object, None, None)):
|
||||
# results.append(
|
||||
# {
|
||||
# "predicate": predicate + ":" + p.toPython().split("#")[-1],
|
||||
# "object": o.toPython().split("#")[-1],
|
||||
# "is_uri": isinstance(o, URIRef),
|
||||
# "object_uri": o.toPython(),
|
||||
# "is_globalid": p.toPython().split("#")[-1] == "globalID",
|
||||
# }
|
||||
# )
|
||||
if isinstance(object_uri, BNode):
|
||||
for subject2, predicate2, object2 in BrickStore.graph.triples((object_uri, None, None)):
|
||||
predicate2_name = predicate2.toPython().split("#")[-1]
|
||||
try:
|
||||
object2_name = object2.toPython().split("#")[-1]
|
||||
except:
|
||||
object2_name = str(object2)
|
||||
results.append(
|
||||
{
|
||||
"predicate_uri": None,
|
||||
"predicate_name": predicate_name + ":" + predicate2_name,
|
||||
"object_uri": object2,
|
||||
"object_name": object2_name,
|
||||
"is_uri": isinstance(object2, URIRef),
|
||||
"is_globalid": predicate2_name == "ifcGlobalID",
|
||||
}
|
||||
)
|
||||
return results
|
||||
|
||||
|
||||
@@ -131,7 +149,7 @@ class BrickschemaReferencesData:
|
||||
for library in ifc.by_type("IfcLibraryInformation"):
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
results.append((str(library.id()), library.Name or "Unnamed", ""))
|
||||
elif ".ttl" in library.Location:
|
||||
elif library.Location and ".ttl" in library.Location:
|
||||
results.append((str(library.id()), library.Name or "Unnamed", ""))
|
||||
return results
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ class LoadBrickProject(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.load_brick_project"
|
||||
bl_label = "Load Brickschema Project"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Load in a Brick project from a file"
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
filter_glob: bpy.props.StringProperty(default="*.ttl", options={"HIDDEN"})
|
||||
|
||||
@@ -56,6 +57,7 @@ class ViewBrickClass(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.view_brick_class"
|
||||
bl_label = "View Brick Class"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Inspect the subclasses of this class"
|
||||
brick_class: bpy.props.StringProperty(name="Brick Class")
|
||||
split_screen: bpy.props.BoolProperty(name="Split Screen", default=False, options={"HIDDEN"})
|
||||
|
||||
@@ -67,17 +69,22 @@ class ViewBrickItem(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.view_brick_item"
|
||||
bl_label = "View Brick Item"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Inspect this entity in the viewer"
|
||||
item: bpy.props.StringProperty(name="Brick Item")
|
||||
split_screen: bpy.props.BoolProperty(name="Split Screen", default=False, options={"HIDDEN"})
|
||||
|
||||
def _execute(self, context):
|
||||
core.view_brick_item(tool.Brick, item=self.item, split_screen=self.split_screen)
|
||||
try:
|
||||
core.view_brick_item(tool.Brick, item=self.item, split_screen=self.split_screen)
|
||||
except:
|
||||
self.report({'ERROR'}, f'Could not find {self.item}')
|
||||
|
||||
|
||||
class RewindBrickClass(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.rewind_brick_class"
|
||||
bl_label = "Rewind Brick Class"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Go back to the previous list view"
|
||||
split_screen: bpy.props.BoolProperty(name="Split Screen", default=False, options={"HIDDEN"})
|
||||
|
||||
def _execute(self, context):
|
||||
@@ -88,6 +95,7 @@ class CloseBrickProject(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.close_brick_project"
|
||||
bl_label = "Close Brick Project"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Close the Brick project"
|
||||
|
||||
def _execute(self, context):
|
||||
core.close_brick_project(tool.Brick)
|
||||
@@ -97,6 +105,7 @@ class ConvertBrickProject(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.convert_brick_project"
|
||||
bl_label = "Convert Brick Project"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Create an Ifc library for this Brick project"
|
||||
|
||||
def _execute(self, context):
|
||||
core.convert_brick_project(tool.Ifc, tool.Brick)
|
||||
@@ -106,9 +115,18 @@ class AssignBrickReference(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.assign_brick_reference"
|
||||
bl_label = "Assign Brick Reference"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Assign the selected Ifc entity to the selected Brick entity"
|
||||
|
||||
def _execute(self, context):
|
||||
if not context.active_object:
|
||||
self.report({'ERROR'}, f'No Ifc selected')
|
||||
return
|
||||
props = context.scene.BIMBrickProperties
|
||||
try:
|
||||
props.bricks[props.active_brick_index]
|
||||
except:
|
||||
self.report({'ERROR'}, f'No Brick selected')
|
||||
return
|
||||
core.assign_brick_reference(
|
||||
tool.Ifc,
|
||||
tool.Brick,
|
||||
@@ -122,19 +140,17 @@ class AddBrick(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.add_brick"
|
||||
bl_label = "Add Brick"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Create the Brick entity"
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMBrickProperties
|
||||
library = None
|
||||
if props.libraries:
|
||||
library = tool.Ifc.get().by_id(int(props.libraries))
|
||||
core.add_brick(
|
||||
tool.Ifc,
|
||||
tool.Brick,
|
||||
element=tool.Ifc.get_entity(context.active_object) if context.selected_objects else None,
|
||||
namespace=props.namespace,
|
||||
brick_class=props.brick_entity_class,
|
||||
library=library,
|
||||
library=tool.Ifc.get().by_id(int(props.libraries)) if props.libraries else None,
|
||||
label=props.new_brick_label,
|
||||
)
|
||||
|
||||
@@ -143,6 +159,7 @@ class AddBrickRelation(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.add_brick_relation"
|
||||
bl_label = "Add Brick Relation"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Create the Brick relationship"
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMBrickProperties
|
||||
@@ -152,7 +169,7 @@ class AddBrickRelation(bpy.types.Operator, Operator):
|
||||
elif props.split_screen_toggled:
|
||||
object = props.split_screen_bricks[props.split_screen_active_brick_index].uri
|
||||
else:
|
||||
object = props.new_brick_relation_namespace + props.new_brick_relation_object
|
||||
object = props.namespace + props.new_brick_relation_object
|
||||
core.add_brick_relation(
|
||||
tool.Brick,
|
||||
brick_uri=brick.uri,
|
||||
@@ -165,6 +182,7 @@ class ConvertIfcToBrick(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.convert_ifc_to_brick"
|
||||
bl_label = "Convert IFC To Brick"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Convert Ifc entities and relations to Brick entities and relations"
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMBrickProperties
|
||||
@@ -178,6 +196,7 @@ class NewBrickFile(bpy.types.Operator):
|
||||
bl_idname = "bim.new_brick_file"
|
||||
bl_label = "New Brick File"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Create a Brick project from scratch"
|
||||
|
||||
def execute(self, context):
|
||||
IfcStore.begin_transaction(self)
|
||||
@@ -210,16 +229,17 @@ class RefreshBrickViewer(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.refresh_brick_viewer"
|
||||
bl_label = "Refresh Brick Viewer"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
split_screen: bpy.props.BoolProperty(name="Split Screen", default=False, options={"HIDDEN"})
|
||||
bl_description = "Refresh the list view"
|
||||
|
||||
def _execute(self, context):
|
||||
core.refresh_brick_viewer(tool.Brick, split_screen=self.split_screen)
|
||||
core.refresh_brick_viewer(tool.Brick)
|
||||
|
||||
|
||||
class RemoveBrick(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.remove_brick"
|
||||
bl_label = "Remove Brick"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Delete this entity"
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMBrickProperties
|
||||
@@ -262,32 +282,20 @@ class SerializeBrick(bpy.types.Operator):
|
||||
class AddBrickNamespace(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.add_brick_namespace"
|
||||
bl_label = "Add Brick Namespace"
|
||||
bl_description = "Bind a new namespace to the Brick project"
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMBrickProperties
|
||||
alias = props.new_brick_namespace_alias
|
||||
uri = props.new_brick_namespace_uri
|
||||
core.add_namespace(tool.Brick, alias=alias, uri=uri)
|
||||
|
||||
|
||||
class SetBrickListRoot(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.set_brick_list_root"
|
||||
bl_label = "Set Brick View Type"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
split_screen: bpy.props.BoolProperty(name="Split Screen", default=False, options={"HIDDEN"})
|
||||
|
||||
def _execute(self, context):
|
||||
if self.split_screen:
|
||||
root = context.scene.BIMBrickProperties.split_screen_brick_list_root
|
||||
else:
|
||||
root = context.scene.BIMBrickProperties.brick_list_root
|
||||
core.set_brick_list_root(tool.Brick, brick_root=root, split_screen=self.split_screen)
|
||||
core.add_brick_namespace(tool.Brick, alias=alias, uri=uri)
|
||||
|
||||
|
||||
class RemoveBrickRelation(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.remove_brick_relation"
|
||||
bl_label = "Remove Relation"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Delete this relationship"
|
||||
predicate: bpy.props.StringProperty(name="Relation")
|
||||
object: bpy.props.StringProperty(name="Object")
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ from bpy.props import (
|
||||
FloatVectorProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
import blenderbim.core.brick as core
|
||||
import blenderbim.tool.brick as tool
|
||||
from blenderbim.tool.brick import BrickStore
|
||||
|
||||
def update_active_brick_index(self, context):
|
||||
@@ -43,12 +45,12 @@ def get_libraries(self, context):
|
||||
|
||||
|
||||
def get_namespaces(self, context):
|
||||
return BrickStore.namespaces
|
||||
return [(uri, f"{alias}: {uri}", "") for alias, uri in BrickStore.namespaces]
|
||||
|
||||
|
||||
def get_brick_entity_classes(self, context):
|
||||
entity = self.brick_entity_create_type
|
||||
return BrickStore.entity_classes[entity]
|
||||
return [(uri, uri.split("#")[-1], "") for uri in BrickStore.entity_classes[entity]]
|
||||
|
||||
|
||||
def get_brick_roots(self, context):
|
||||
@@ -56,13 +58,22 @@ def get_brick_roots(self, context):
|
||||
|
||||
|
||||
def get_brick_relations(self, context):
|
||||
def is_label(relation):
|
||||
return relation["predicate_name"] == "label"
|
||||
if not list(filter(is_label, BrickschemaData.data["active_relations"])):
|
||||
new_relations = BrickStore.relationships.copy()
|
||||
new_relations.append(("http://www.w3.org/2000/01/rdf-schema#label", "label", ""))
|
||||
return new_relations
|
||||
return BrickStore.relationships
|
||||
relations = [(uri, uri.split("#")[-1], "") for uri in BrickStore.relationships]
|
||||
for relation in BrickschemaData.data["active_relations"]:
|
||||
if relation["predicate_name"] == "label":
|
||||
return relations
|
||||
relations.append(("http://www.w3.org/2000/01/rdf-schema#label", "label", ""))
|
||||
return relations
|
||||
|
||||
|
||||
|
||||
def update_view(self, context):
|
||||
root = context.scene.BIMBrickProperties.brick_list_root
|
||||
core.set_brick_list_root(tool.Brick, brick_root=root, split_screen=False)
|
||||
|
||||
def split_screen_update_view(self, context):
|
||||
root = context.scene.BIMBrickProperties.split_screen_brick_list_root
|
||||
core.set_brick_list_root(tool.Brick, brick_root=root, split_screen=True)
|
||||
|
||||
|
||||
class Brick(PropertyGroup):
|
||||
@@ -79,10 +90,9 @@ class BIMBrickProperties(PropertyGroup):
|
||||
active_brick_index: IntProperty(name="Active Brick Index", update=update_active_brick_index)
|
||||
libraries: EnumProperty(name="Libraries", items=get_libraries)
|
||||
set_list_root_toggled: BoolProperty(name="Set List Root Toggled", default=False)
|
||||
brick_list_root: EnumProperty(name="Brick List Root", items=get_brick_roots)
|
||||
brick_list_root: EnumProperty(name="Brick List Root", items=get_brick_roots, update=update_view)
|
||||
# namespace manager
|
||||
namespace: EnumProperty(name="Namespace", items=get_namespaces)
|
||||
brick_settings_toggled: BoolProperty(name="Brick Settings Toggled", default=False)
|
||||
new_brick_namespace_alias: StringProperty(name="New Brick Namespace Alias")
|
||||
new_brick_namespace_uri: StringProperty(name="New Brick Namespace URI")
|
||||
# create brick entity
|
||||
@@ -93,13 +103,12 @@ class BIMBrickProperties(PropertyGroup):
|
||||
brick_create_relations_toggled: BoolProperty(name="Brick Create Relations Toggled", default=False)
|
||||
brick_edit_relations_toggled: BoolProperty(name="Brick Edit Relations Toggled", default=False)
|
||||
new_brick_relation_type: EnumProperty(name="New Brick Relation Type", items=get_brick_relations)
|
||||
new_brick_relation_namespace: EnumProperty(name="New Brick Relation Namespace", items=get_namespaces)
|
||||
new_brick_relation_object: StringProperty(name="New Brick Relation Object")
|
||||
add_relation_failed: BoolProperty(name="Add Relation Failed", default=False)
|
||||
add_brick_relation_failed: BoolProperty(name="Add Relation Failed", default=False)
|
||||
# create relations split screen
|
||||
split_screen_toggled: BoolProperty(name="Split Screen Toggled", default=False)
|
||||
split_screen_bricks: CollectionProperty(name="Split Screen Bricks", type=Brick)
|
||||
split_screen_active_brick_index: IntProperty(name="Split Screen Active Brick Index", update=update_active_brick_index)
|
||||
split_screen_active_brick_class: StringProperty(name="Split Screen Active Brick Class")
|
||||
split_screen_brick_breadcrumbs: CollectionProperty(name="Split Screen Brick Breadcrumbs", type=StrProperty)
|
||||
split_screen_brick_list_root: EnumProperty(name="Split Screen Brick List Root", items=get_brick_roots)
|
||||
split_screen_brick_list_root: EnumProperty(name="Split Screen Brick List Root", items=get_brick_roots, update=split_screen_update_view)
|
||||
@@ -34,17 +34,36 @@ class BIM_PT_brickschema(Panel):
|
||||
def draw(self, context):
|
||||
if not BrickschemaData.is_loaded:
|
||||
BrickschemaData.load()
|
||||
self.props = context.scene.BIMBrickProperties
|
||||
|
||||
|
||||
class BIM_PT_brickschema_project_info(Panel):
|
||||
bl_label = "Project Info"
|
||||
bl_idname = "BIM_PT_brickschema_project_info"
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_brickschema"
|
||||
|
||||
def draw(self, context):
|
||||
self.props = context.scene.BIMBrickProperties
|
||||
|
||||
if not BrickschemaData.data["is_loaded"]:
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.new_brick_file", text="Create Project")
|
||||
row.operator("bim.load_brick_project", text="Load Project")
|
||||
return
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
if BrickStore.path:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=BrickStore.path, icon="FILEBROWSER")
|
||||
else:
|
||||
row.label(text="No file", icon="FILEBROWSER")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
if BrickStore.last_saved:
|
||||
row.label(text=BrickStore.last_saved, icon="TIME")
|
||||
else:
|
||||
row.label(text="Not saved", icon="TIME")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
op = row.operator("bim.serialize_brick", icon="EXPORT", text="Save")
|
||||
@@ -53,134 +72,173 @@ class BIM_PT_brickschema(Panel):
|
||||
op.should_save_as = True
|
||||
row.operator("bim.close_brick_project", text="", icon="CANCEL")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(data=self.props, property="brick_settings_toggled", text="", icon="PREFERENCES")
|
||||
|
||||
if self.props.brick_settings_toggled:
|
||||
box = self.layout.box()
|
||||
row = box.row(align=True)
|
||||
row.label(text="Active Namespace:")
|
||||
|
||||
row = box.row(align=True)
|
||||
prop_with_search(row, self.props, "namespace", text="")
|
||||
class BIM_PT_brickschema_namespaces(Panel):
|
||||
bl_label = "Namespaces"
|
||||
bl_idname = "BIM_PT_brickschema_namespaces"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_brickschema"
|
||||
|
||||
row = box.row(align=True)
|
||||
row.label(text="Bind New Namespace:")
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return BrickStore.graph != None
|
||||
|
||||
row = box.row(align=True)
|
||||
row.prop(data=self.props, property="new_brick_namespace_alias", text="")
|
||||
col = row.column()
|
||||
col.alignment = "CENTER"
|
||||
col.scale_x = 1.1
|
||||
col.label(text=":")
|
||||
row.prop(data=self.props, property="new_brick_namespace_uri", text="")
|
||||
row.operator("bim.add_brick_namespace", text="", icon="ADD")
|
||||
def draw(self, context):
|
||||
self.props = context.scene.BIMBrickProperties
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Create Entity:")
|
||||
row.label(text="Active Namespace:")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(data=self.props, property="brick_entity_create_type", text="")
|
||||
prop_with_search(row, self.props, "namespace", text="")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(data=self.props, property="new_brick_label", text="")
|
||||
prop_with_search(row, self.props, "brick_entity_class", text="")
|
||||
row.operator("bim.add_brick", text="", icon="ADD")
|
||||
# row.operator("bim.refresh_brick_viewer", text="", icon="FILE_REFRESH")
|
||||
row.label(text="Bind New Namespace:")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(data=self.props, property="new_brick_namespace_alias", text="")
|
||||
col = row.column()
|
||||
col.alignment = "RIGHT"
|
||||
col.alignment = "CENTER"
|
||||
col.scale_x = 1.1
|
||||
col.label(text=":")
|
||||
row.prop(data=self.props, property="new_brick_namespace_uri", text="")
|
||||
row.operator("bim.add_brick_namespace", text="", icon="ADD")
|
||||
|
||||
|
||||
class BIM_PT_brickschema_create_entity(Panel):
|
||||
bl_label = "Create Entity"
|
||||
bl_idname = "BIM_PT_brickschema_create_entity"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_brickschema"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return BrickStore.graph != None
|
||||
|
||||
def draw(self, context):
|
||||
self.props = context.scene.BIMBrickProperties
|
||||
# TO DO: hide this if selected entity already has a reference, or something similar
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(data=self.props, property="brick_entity_create_type", text="Class")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
prop_with_search(row, self.props, "brick_entity_class", text="Type")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
active = tool.Ifc.get_entity(context.active_object)
|
||||
if active and context.selected_objects:
|
||||
row.label(text="Label:")
|
||||
row.label(text=active.Name if active.Name else "Unnamed")
|
||||
else:
|
||||
row.prop(data=self.props, property="new_brick_label", text="Label")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.add_brick", text="Create Entity")
|
||||
|
||||
|
||||
class BIM_PT_brickschema_viewport(Panel):
|
||||
bl_label = "Viewport"
|
||||
bl_idname = "BIM_PT_brickschema_viewport"
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_brickschema"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return BrickStore.graph != None
|
||||
|
||||
def draw(self, context):
|
||||
self.props = context.scene.BIMBrickProperties
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.column().alignment = "RIGHT"
|
||||
row.prop(data=self.props, property="set_list_root_toggled", text="", icon="OUTLINER")
|
||||
row.prop(data=self.props, property="split_screen_toggled", text="", icon="WINDOW")
|
||||
row.operator("bim.refresh_brick_viewer", text="", icon="FILE_REFRESH")
|
||||
|
||||
grid = self.layout.grid_flow(even_columns=True)
|
||||
grid1 = grid.column(align=True)
|
||||
row = grid1.row(align=True)
|
||||
grid_left = grid.column(align=True)
|
||||
row = grid_left.row(align=True)
|
||||
if len(self.props.brick_breadcrumbs):
|
||||
op = row.operator("bim.rewind_brick_class", text="", icon="FRAME_PREV")
|
||||
op.split_screen = False
|
||||
row.prop(data=self.props, property="set_list_root_toggled", text="", icon="OUTLINER")
|
||||
row.label(text=self.props.active_brick_class)
|
||||
|
||||
if self.props.set_list_root_toggled:
|
||||
row = grid1.row(align=True)
|
||||
op = row.operator("bim.set_brick_list_root", text="Set View")
|
||||
op.split_screen = False
|
||||
row = grid_left.row(align=True)
|
||||
row.prop(data=self.props, property="brick_list_root", text="")
|
||||
|
||||
row = grid1.row()
|
||||
row = grid_left.row()
|
||||
BIM_UL_bricks.split_screen = False
|
||||
row.template_list("BIM_UL_bricks", "", self.props, "bricks", self.props, "active_brick_index")
|
||||
|
||||
if self.props.split_screen_toggled:
|
||||
grid2 = grid.column(align=True)
|
||||
row = grid2.row(align=True)
|
||||
grid_right = grid.column(align=True)
|
||||
row = grid_right.row(align=True)
|
||||
if len(self.props.split_screen_brick_breadcrumbs):
|
||||
op = row.operator("bim.rewind_brick_class", text="", icon="FRAME_PREV")
|
||||
op.split_screen = True
|
||||
row.label(text=self.props.split_screen_active_brick_class)
|
||||
|
||||
if self.props.set_list_root_toggled:
|
||||
row = grid2.row(align=True)
|
||||
op = row.operator("bim.set_brick_list_root", text="Set View")
|
||||
op.split_screen = True
|
||||
row = grid_right.row(align=True)
|
||||
row.prop(data=self.props, property="split_screen_brick_list_root", text="")
|
||||
|
||||
row = grid2.row()
|
||||
row = grid_right.row()
|
||||
BIM_UL_bricks.split_screen = True
|
||||
row.template_list("BIM_UL_bricks", "", self.props, "split_screen_bricks", self.props, "split_screen_active_brick_index")
|
||||
|
||||
if BrickschemaData.data["active_relations"]:
|
||||
row = self.layout.row(align=True)
|
||||
col = row.column()
|
||||
col.alignment = "RIGHT"
|
||||
row.column().alignment = "RIGHT"
|
||||
row.prop(data=self.props, property="brick_create_relations_toggled", text="", icon="PLUGIN")
|
||||
row.prop(data=self.props, property="brick_edit_relations_toggled", text="", icon="TOOL_SETTINGS")
|
||||
row.operator("bim.remove_brick", text="", icon="X")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Create Relation:")
|
||||
|
||||
if self.props.brick_create_relations_toggled and self.props.new_brick_relation_type == "http://www.w3.org/2000/01/rdf-schema#label":
|
||||
if self.props.brick_create_relations_toggled and self.props.split_screen_toggled:
|
||||
row = self.layout.row(align=True)
|
||||
prop_with_search(row, self.props, "new_brick_relation_type", text="")
|
||||
row.prop(data=self.props, property="new_brick_relation_object", text="")
|
||||
row.operator("bim.add_brick_relation", text="", icon="ADD")
|
||||
|
||||
elif self.props.brick_create_relations_toggled and self.props.split_screen_toggled:
|
||||
row = self.layout.row(align=True)
|
||||
split_screen_selection = self.props.split_screen_bricks[self.props.split_screen_active_brick_index]
|
||||
if split_screen_selection.total_items:
|
||||
try:
|
||||
split_screen_selection = self.props.split_screen_bricks[self.props.split_screen_active_brick_index]
|
||||
except:
|
||||
split_screen_selection = None
|
||||
if not split_screen_selection or split_screen_selection.total_items:
|
||||
row.label(text="No selection", icon="INFO")
|
||||
else:
|
||||
prop_with_search(row, self.props, "new_brick_relation_type", text="")
|
||||
row.label(text=split_screen_selection.label if split_screen_selection.label else split_screen_selection.name)
|
||||
row.operator("bim.add_brick_relation", text="", icon="ADD")
|
||||
|
||||
elif self.props.brick_create_relations_toggled:
|
||||
row = self.layout.row(align=True)
|
||||
prop_with_search(row, self.props, "new_brick_relation_namespace", text="")
|
||||
|
||||
elif self.props.brick_create_relations_toggled:
|
||||
row = self.layout.row(align=True)
|
||||
prop_with_search(row, self.props, "new_brick_relation_type", text="")
|
||||
row.prop(data=self.props, property="new_brick_relation_object", text="")
|
||||
row.operator("bim.add_brick_relation", text="", icon="ADD")
|
||||
|
||||
|
||||
if self.props.brick_create_relations_toggled and self.props.add_relation_failed:
|
||||
if self.props.brick_create_relations_toggled and self.props.add_brick_relation_failed:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Failed to find this entity!", icon="ERROR")
|
||||
|
||||
|
||||
for relation in BrickschemaData.data["active_relations"]:
|
||||
row = self.layout.row(align=True)
|
||||
split = self.layout.split(factor=0.85, align=True)
|
||||
row = split.row(align=True)
|
||||
row.label(text=relation["predicate_name"])
|
||||
row.separator()
|
||||
row.label(text=relation["object_name"])
|
||||
if self.props.brick_edit_relations_toggled and relation["predicate_name"] != "type":
|
||||
row = split.row(align=True)
|
||||
row.column().alignment = "RIGHT"
|
||||
if self.props.brick_edit_relations_toggled and relation["predicate_uri"] and relation["predicate_name"] != "type":
|
||||
op = row.operator("bim.remove_brick_relation", text="", icon="UNLINKED")
|
||||
op.predicate = relation["predicate"]
|
||||
op.object = relation["object"]
|
||||
if relation["is_uri"] and relation["predicate_name"] != "type":
|
||||
op.predicate = relation["predicate_uri"]
|
||||
op.object = relation["object_uri"]
|
||||
if relation["is_uri"] and relation["object_uri"].toPython().split("#")[-1] != self.props.active_brick_class:
|
||||
op = row.operator("bim.view_brick_item", text="", icon="DISCLOSURE_TRI_RIGHT")
|
||||
op.item = relation["object_uri"]
|
||||
if relation["is_globalid"]:
|
||||
@@ -188,6 +246,23 @@ class BIM_PT_brickschema(Panel):
|
||||
op.global_id = relation["object_name"]
|
||||
|
||||
|
||||
class BIM_UL_bricks(UIList):
|
||||
split_screen = False
|
||||
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
if item:
|
||||
split = layout.split(factor=0.85, align=True)
|
||||
row = split.row()
|
||||
label = item.label if item.label else item.name
|
||||
if item.total_items:
|
||||
op = row.operator("bim.view_brick_class", text="", icon="DISCLOSURE_TRI_RIGHT", emboss=False)
|
||||
op.brick_class = item.name
|
||||
op.split_screen = self.split_screen
|
||||
row.label(text=label)
|
||||
if item.total_items:
|
||||
row = split.row()
|
||||
row.label(text=str(item.total_items))
|
||||
|
||||
class BIM_PT_ifc_brickschema_references(Panel):
|
||||
bl_label = "Brickschema References"
|
||||
bl_idname = "BIM_PT_ifc_brickschema_references"
|
||||
@@ -211,15 +286,24 @@ class BIM_PT_ifc_brickschema_references(Panel):
|
||||
row.label(text="No Brickschema Project Loaded")
|
||||
return
|
||||
|
||||
if not BrickschemaReferencesData.data["libraries"]:
|
||||
if not BrickschemaReferencesData.data["libraries"] and BrickStore.path:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="No IFC Libraries")
|
||||
row.operator("bim.convert_brick_project", text="", icon="ADD")
|
||||
return
|
||||
|
||||
elif not BrickschemaReferencesData.data["libraries"]:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="No IFC Libraries: save the Brick project to create a new library", icon="ERROR")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Libraries must have location pointing to a \".ttl\" file", icon="INFO")
|
||||
return
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
prop_with_search(row, self.props, "libraries")
|
||||
row.operator("bim.convert_brick_project", text="", icon="ADD")
|
||||
if BrickStore.path:
|
||||
row.operator("bim.convert_brick_project", text="", icon="ADD")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.assign_brick_reference", icon="ADD")
|
||||
@@ -234,19 +318,4 @@ class BIM_PT_ifc_brickschema_references(Panel):
|
||||
row.label(text=reference["identification"], icon="ASSET_MANAGER")
|
||||
row.label(text=reference["name"])
|
||||
row.operator("bim.unassign_library_reference", text="", icon="X").reference = reference["id"]
|
||||
row.operator("bim.view_brick_item", text="", icon="DISCLOSURE_TRI_RIGHT").item = reference["identification"]
|
||||
|
||||
|
||||
class BIM_UL_bricks(UIList):
|
||||
split_screen = False
|
||||
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
label = item.label if item.label else item.name
|
||||
if item.total_items:
|
||||
op = row.operator("bim.view_brick_class", text="", icon="DISCLOSURE_TRI_RIGHT", emboss=False)
|
||||
op.brick_class = item.name
|
||||
op.split_screen = self.split_screen
|
||||
label = label + " (" + str(item.total_items) + ")"
|
||||
row.label(text=label)
|
||||
row.operator("bim.view_brick_item", text="", icon="DISCLOSURE_TRI_RIGHT").item = reference["identification"]
|
||||
@@ -0,0 +1,42 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.GetBSDDClassificationProperties,
|
||||
operator.LoadBSDDDomains,
|
||||
operator.SearchBSDDClass,
|
||||
operator.SetActiveBSDDDictionary,
|
||||
prop.BSDDDomain,
|
||||
prop.BSDDClassification,
|
||||
prop.BSDDPset,
|
||||
prop.BIMBSDDProperties,
|
||||
ui.BIM_UL_bsdd_domains,
|
||||
ui.BIM_UL_bsdd_classifications,
|
||||
ui.BIM_PT_bsdd,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Scene.BIMBSDDProperties = bpy.props.PointerProperty(type=prop.BIMBSDDProperties)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.BIMBSDDProperties
|
||||
@@ -0,0 +1,65 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import bsdd
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.core import bsdd as core
|
||||
|
||||
|
||||
class LoadBSDDDomains(bpy.types.Operator):
|
||||
bl_idname = "bim.load_bsdd_domains"
|
||||
bl_label = "Load bSDD Dictionaries"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
core.load_bsdd(bsdd.Client(), tool.Bsdd)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SetActiveBSDDDictionary(bpy.types.Operator):
|
||||
bl_idname = "bim.set_active_bsdd_domain"
|
||||
bl_label = "Load bSDD Dictionary"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
name: bpy.props.StringProperty()
|
||||
uri: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
core.set_active_bsdd_dictionary(self.name, self.uri, tool.Bsdd)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SearchBSDDClass(bpy.types.Operator):
|
||||
bl_idname = "bim.search_bsdd_classifications"
|
||||
bl_label = "Search bSDD Class"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
keyword = context.scene.BIMBSDDProperties.keyword
|
||||
core.search_class(keyword, bsdd.Client(), tool.Bsdd)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class GetBSDDClassificationProperties(bpy.types.Operator):
|
||||
bl_idname = "bim.get_bsdd_classification_properties"
|
||||
bl_label = "Search bSDD Classifications"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
core.get_class_properties(bsdd.Client(), tool.Bsdd)
|
||||
return {"FINISHED"}
|
||||
@@ -0,0 +1,67 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
from bpy.types import PropertyGroup
|
||||
from blenderbim.bim.prop import Attribute, StrProperty
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
StringProperty,
|
||||
EnumProperty,
|
||||
BoolProperty,
|
||||
IntProperty,
|
||||
FloatProperty,
|
||||
FloatVectorProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
|
||||
|
||||
class BSDDDomain(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
uri: StringProperty(name="URI")
|
||||
default_language_code: StringProperty(name="Language")
|
||||
organization_name_owner: StringProperty(name="Organization")
|
||||
status: StringProperty(name="Status")
|
||||
version: StringProperty(name="Version")
|
||||
|
||||
|
||||
class BSDDClassification(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
reference_code: StringProperty(name="Reference Code")
|
||||
description: StringProperty(name="Description")
|
||||
uri: StringProperty(name="Namespace URI")
|
||||
domain_name: StringProperty(name="Domain Name")
|
||||
domain_namespace_uri: StringProperty(name="Domain Namespace URI")
|
||||
|
||||
|
||||
class BSDDPset(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
properties: CollectionProperty(name="Properties", type=Attribute)
|
||||
|
||||
|
||||
class BIMBSDDProperties(PropertyGroup):
|
||||
active_domain: StringProperty(name="Active Domain")
|
||||
active_uri: StringProperty(name="Active URI")
|
||||
domains: CollectionProperty(name="Domains", type=BSDDDomain)
|
||||
active_domain_index: IntProperty(name="Active Domain Index")
|
||||
classifications: CollectionProperty(name="Classifications", type=BSDDClassification)
|
||||
active_classification_index: IntProperty(name="Active Classification Index")
|
||||
keyword: StringProperty(name="Keyword")
|
||||
should_filter_ifc_class: BoolProperty(name="Filter Active IFC Class", default=True)
|
||||
load_preview_domains: BoolProperty(name="Load Preview Domains", default=False)
|
||||
classification_psets: CollectionProperty(name="Classification Psets", type=BSDDPset)
|
||||
@@ -0,0 +1,79 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import blenderbim.tool as tool
|
||||
from bpy.types import Panel, UIList
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
class BIM_PT_bsdd(Panel):
|
||||
bl_label = "buildingSMART Data Dictionary"
|
||||
bl_idname = "BIM_PT_bsdd"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_tab_project_setup"
|
||||
|
||||
def draw(self, context):
|
||||
props = context.scene.BIMBSDDProperties
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "load_preview_domains")
|
||||
if len(props.domains):
|
||||
row.operator("bim.load_bsdd_domains", text="", icon="FILE_REFRESH")
|
||||
|
||||
if props.active_domain:
|
||||
row = self.layout.row()
|
||||
row.label(text="Active: " + props.active_domain, icon="URL")
|
||||
else:
|
||||
row = self.layout.row()
|
||||
row.label(text="No Active bSDD Domain", icon="ERROR")
|
||||
|
||||
if len(props.domains):
|
||||
self.layout.template_list(
|
||||
"BIM_UL_bsdd_domains",
|
||||
"",
|
||||
props,
|
||||
"domains",
|
||||
props,
|
||||
"active_domain_index",
|
||||
)
|
||||
else:
|
||||
row = self.layout.row()
|
||||
row.operator("bim.load_bsdd_domains")
|
||||
|
||||
|
||||
class BIM_UL_bsdd_domains(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
if item.status != "Active":
|
||||
row.label(text=f"{item.name} ({item.organization_name_owner}) - {item.status}", icon="ERROR")
|
||||
else:
|
||||
row.label(text=f"{item.name} ({item.organization_name_owner})")
|
||||
op = row.operator("bim.set_active_bsdd_domain", text="", icon="RESTRICT_SELECT_OFF")
|
||||
op.name = item.name
|
||||
op.uri = item.uri
|
||||
|
||||
|
||||
class BIM_UL_bsdd_classifications(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
row.label(text=item.reference_code)
|
||||
row.label(text=item.name)
|
||||
@@ -37,7 +37,7 @@ classes = (
|
||||
|
||||
def register():
|
||||
if not bpy.app.background:
|
||||
bpy.utils.register_tool(workspace.CadTool, after={"builtin.transform"}, separator=True, group=True)
|
||||
bpy.utils.register_tool(workspace.CadTool, after={"builtin.transform"}, separator=True, group=False)
|
||||
bpy.types.Scene.BIMCadProperties = bpy.props.PointerProperty(type=prop.BIMCadProperties)
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ import bpy_extras
|
||||
import blenderbim.tool as tool
|
||||
from mathutils import Vector, Matrix
|
||||
from math import pi, radians, sin, cos, sqrt
|
||||
import ifcopenshell.util.unit
|
||||
|
||||
|
||||
messages = {
|
||||
"SHARED_VERTEX": "Shared Vertex, no intersection possible",
|
||||
@@ -140,6 +142,9 @@ class CadFillet(bpy.types.Operator):
|
||||
layout.prop(self, prop)
|
||||
|
||||
def execute(self, context):
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
self.radius = self.radius * si_conversion
|
||||
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
|
||||
@@ -361,6 +366,10 @@ class CadOffset(bpy.types.Operator):
|
||||
# dialog that Mesh Tools has. Sverchok is 2D based, but has a weird side
|
||||
# effect of converting an unclosed loop into a closed loop which is also
|
||||
# not what users expect.
|
||||
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
self.distance = self.distance * si_conversion
|
||||
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
|
||||
@@ -498,6 +507,8 @@ class CadOffset(bpy.types.Operator):
|
||||
local_direction = (rotation_i @ direction).normalized()
|
||||
normals.append(local_direction)
|
||||
|
||||
|
||||
|
||||
if len(normals) == 2:
|
||||
# https://stackoverflow.com/a/54042831/9627415
|
||||
new_normal = (normals[0].lerp(normals[1], 0.5)).normalized()
|
||||
@@ -531,7 +542,7 @@ class CadOffset(bpy.types.Operator):
|
||||
class AddIfcCircle(bpy.types.Operator):
|
||||
bl_idname = "bim.add_ifccircle"
|
||||
bl_label = "Add IfcCircle"
|
||||
radius: bpy.props.FloatProperty(name="Radius", default=0.1)
|
||||
radius: bpy.props.FloatProperty(name="Radius", default=0.5)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
@@ -539,6 +550,9 @@ class AddIfcCircle(bpy.types.Operator):
|
||||
return bool(obj) and obj.type == "MESH"
|
||||
|
||||
def execute(self, context):
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
self.radius = self.radius * si_conversion
|
||||
|
||||
if self.has_selected_existing_circle(context):
|
||||
self.change_radius(context)
|
||||
else:
|
||||
@@ -622,6 +636,9 @@ class AddIfcArcIndexFillet(bpy.types.Operator):
|
||||
layout.prop(self, prop)
|
||||
|
||||
def execute(self, context):
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
self.radius = self.radius * si_conversion
|
||||
|
||||
if self.has_selected_existing_arc(context):
|
||||
self.change_radius(context)
|
||||
else:
|
||||
@@ -786,8 +803,8 @@ class AlignViewToProfile(bpy.types.Operator):
|
||||
class AddRectangle(bpy.types.Operator):
|
||||
bl_idname = "bim.add_rectangle"
|
||||
bl_label = "Add Rectangle"
|
||||
x: bpy.props.FloatProperty(name="X", default=0.1)
|
||||
y: bpy.props.FloatProperty(name="Y", default=0.1)
|
||||
x: bpy.props.FloatProperty(name="X", default=1)
|
||||
y: bpy.props.FloatProperty(name="Y", default=1)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
@@ -795,6 +812,10 @@ class AddRectangle(bpy.types.Operator):
|
||||
return bool(obj) and obj.type == "MESH"
|
||||
|
||||
def execute(self, context):
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
self.x = self.x * si_conversion
|
||||
self.y = self.y * si_conversion
|
||||
|
||||
obj = context.active_object
|
||||
bm = bmesh.from_edit_mesh(obj.data)
|
||||
cursor = obj.matrix_world.inverted() @ context.scene.cursor.location
|
||||
|
||||
@@ -20,26 +20,33 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.AddClashSet,
|
||||
operator.AddClashSource,
|
||||
operator.ExecuteIfcClash,
|
||||
operator.ExportClashSets,
|
||||
operator.ImportClashSets,
|
||||
operator.AddClashSet,
|
||||
operator.LoadIfcClashes,
|
||||
operator.SaveIfcClashes,
|
||||
operator.LoadSmartGroupsForActiveClashSet,
|
||||
operator.RemoveClashSet,
|
||||
operator.AddClashSource,
|
||||
operator.RemoveClashSource,
|
||||
operator.SelectClashSource,
|
||||
operator.ExecuteIfcClash,
|
||||
operator.SelectIfcClashResults,
|
||||
operator.SelectClash,
|
||||
operator.SelectClashResults,
|
||||
operator.SelectClashSource,
|
||||
operator.SelectIfcClashResults,
|
||||
operator.SelectSmartGroup,
|
||||
operator.SelectSmartGroupedClashesPath,
|
||||
operator.SmartClashGroup,
|
||||
operator.SelectSmartGroup,
|
||||
operator.LoadSmartGroupsForActiveClashSet,
|
||||
prop.Clash,
|
||||
prop.ClashSource,
|
||||
prop.ClashSet,
|
||||
prop.SmartClashGroup,
|
||||
prop.BIMClashProperties,
|
||||
ui.BIM_PT_ifcclash,
|
||||
ui.BIM_PT_clash_manager,
|
||||
ui.BIM_PT_dumb_clash_manager,
|
||||
ui.BIM_PT_smart_clash_manager,
|
||||
ui.BIM_UL_clashes,
|
||||
ui.BIM_UL_clash_sets,
|
||||
ui.BIM_UL_smart_groups,
|
||||
)
|
||||
|
||||
@@ -26,6 +26,7 @@ import ifcopenshell
|
||||
from mathutils import Matrix, Vector
|
||||
from math import radians
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
import blenderbim.tool as tool
|
||||
|
||||
|
||||
class ExportClashSets(bpy.types.Operator):
|
||||
@@ -245,12 +246,14 @@ class ExecuteIfcClash(bpy.types.Operator):
|
||||
y = Vector([y.x, y.y, y.z])
|
||||
x = y.cross(z)
|
||||
|
||||
mat = Matrix([
|
||||
[x[0], y[0], z[0], p.x],
|
||||
[x[1], y[1], z[1], p.y],
|
||||
[x[2], y[2], z[2], p.z],
|
||||
[0, 0, 0, 0],
|
||||
])
|
||||
mat = Matrix(
|
||||
[
|
||||
[x[0], y[0], z[0], p.x],
|
||||
[x[1], y[1], z[1], p.y],
|
||||
[x[2], y[2], z[2], p.z],
|
||||
[0, 0, 0, 0],
|
||||
]
|
||||
)
|
||||
|
||||
camera.matrix_world = mat
|
||||
context.scene.camera = camera
|
||||
@@ -336,12 +339,132 @@ class SelectIfcClashResults(bpy.types.Operator):
|
||||
else:
|
||||
element_file = self.file
|
||||
|
||||
element = element_file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
if element.GlobalId in global_ids:
|
||||
try:
|
||||
element = element_file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
except:
|
||||
continue
|
||||
|
||||
global_id = getattr(element, "GlobalId", None)
|
||||
if not global_id:
|
||||
continue
|
||||
if global_id in global_ids:
|
||||
obj.select_set(True)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class LoadIfcClashes(bpy.types.Operator):
|
||||
bl_idname = "bim.load_ifc_clashes"
|
||||
bl_label = "Load IFC Clashes"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Load the clashing IFC geometry stored in a file"
|
||||
filename_ext = ".json"
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".json")
|
||||
WindowManager = context.window_manager
|
||||
WindowManager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
self.filepath = bpy.path.ensure_ext(self.filepath, ".json")
|
||||
with open(self.filepath) as f:
|
||||
clash_sets_json = json.load(f)
|
||||
active_clash_set = context.scene.BIMClashProperties.active_clash_set
|
||||
|
||||
for clash_set in clash_sets_json:
|
||||
if not "clashes" in clash_set.keys():
|
||||
self.report({"WARNING"}, "No clashes found for the selected Clash Set.")
|
||||
return {"CANCELLED"}
|
||||
active_clash_set.clashes.clear()
|
||||
for clash in clash_set["clashes"].values():
|
||||
blender_clash = active_clash_set.clashes.add()
|
||||
blender_clash.a_global_id = clash["a_global_id"]
|
||||
blender_clash.b_global_id = clash["b_global_id"]
|
||||
blender_clash.a_name = "{}/{}".format(clash["a_ifc_class"], clash["a_name"])
|
||||
blender_clash.b_name = "{}/{}".format(clash["b_ifc_class"], clash["b_name"])
|
||||
blender_clash.status = False if not "status" in clash.keys() else clash["status"]
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SaveIfcClashes(bpy.types.Operator):
|
||||
bl_idname = "bim.save_ifc_clashes"
|
||||
bl_label = "Save IFC Clashes"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Save the clashing IFC geometry stored in a file"
|
||||
filename_ext = ".json"
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".json")
|
||||
WindowManager = context.window_manager
|
||||
WindowManager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
self.filepath = bpy.path.ensure_ext(self.filepath, ".json")
|
||||
clash_sets_json = self.load_json()
|
||||
active_clash_set = context.scene.BIMClashProperties.active_clash_set
|
||||
self.update_clash_sets(clash_sets_json, active_clash_set)
|
||||
self.save_json(clash_sets_json)
|
||||
return {"FINISHED"}
|
||||
|
||||
def load_json(self):
|
||||
with open(self.filepath) as f:
|
||||
return json.load(f)
|
||||
|
||||
def update_clash_sets(self, clash_sets_json, active_clash_set):
|
||||
for clash_set in clash_sets_json:
|
||||
if clash_set["name"] != active_clash_set.name or "clashes" not in clash_set.keys():
|
||||
continue
|
||||
for clash in active_clash_set.clashes:
|
||||
clash_key = clash.a_global_id + "-" + clash.b_global_id
|
||||
if clash_set.get("clashes", {}).get(clash_key, None) is not None:
|
||||
clash_set["clashes"][clash_key]["status"] = clash.status
|
||||
|
||||
def save_json(self, clash_sets_json):
|
||||
with open(self.filepath, "w") as destination:
|
||||
json.dump(clash_sets_json, destination, indent=4)
|
||||
|
||||
|
||||
class SelectClash(bpy.types.Operator):
|
||||
bl_idname = "bim.select_clash"
|
||||
bl_label = "Select Clash"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Select the clashing IFC geometry stored in a file"
|
||||
index: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
clash = context.scene.BIMClashProperties.active_clash
|
||||
|
||||
products = []
|
||||
linked_objects = []
|
||||
try:
|
||||
products.append(tool.Ifc.get().by_guid(clash.a_global_id))
|
||||
except:
|
||||
linked_objects.append(clash.a_name)
|
||||
try:
|
||||
products.append(tool.Ifc.get().by_guid(clash.b_global_id))
|
||||
except:
|
||||
linked_objects.append(clash.b_name)
|
||||
|
||||
tool.Spatial.select_products(products, unhide=True)
|
||||
print(linked_objects)
|
||||
for obj_name in linked_objects:
|
||||
obj = bpy.data.objects.get(obj_name)
|
||||
if obj:
|
||||
obj.select_set(True)
|
||||
else:
|
||||
print("Object not found:", obj_name)
|
||||
if context.scene.BIMClashProperties.sould_focus_on_clash:
|
||||
context_override = tool.Blender.get_viewport_context()
|
||||
with bpy.context.temp_override(**context_override):
|
||||
bpy.ops.view3d.view_selected()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SmartClashGroup(bpy.types.Operator):
|
||||
bl_idname = "bim.smart_clash_group"
|
||||
bl_label = "Smart Group Clashes"
|
||||
@@ -426,9 +549,9 @@ class LoadSmartGroupsForActiveClashSet(bpy.types.Operator):
|
||||
new_group = context.scene.BIMClashProperties.smart_clash_groups.add()
|
||||
new_group.number = f"{smart_group}"
|
||||
for pair in global_id_pairs:
|
||||
for id in pair:
|
||||
for guid in pair:
|
||||
new_global_id = new_group.global_ids.add()
|
||||
new_global_id.name = id
|
||||
new_global_id.guid = guid
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -443,20 +566,16 @@ class SelectSmartGroup(bpy.types.Operator):
|
||||
return IfcStore.get_file() and context.visible_objects and context.scene.BIMClashProperties.active_smart_group
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
# Select smart group in view
|
||||
selected_smart_group = context.scene.BIMClashProperties.active_smart_group
|
||||
# print(selected_smart_group.number)
|
||||
|
||||
for obj in context.visible_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
products = []
|
||||
for global_id in selected_smart_group.global_ids:
|
||||
try:
|
||||
products.append(tool.Ifc.get().by_guid(global_id.guid))
|
||||
except:
|
||||
continue
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
for id in selected_smart_group.global_ids:
|
||||
# print("Id: ", id)
|
||||
# print("Global id: ", element.GlobalId)
|
||||
if element.GlobalId in id.name:
|
||||
# print("object match: ", global_id)
|
||||
obj.select_set(True)
|
||||
|
||||
tool.Spatial.select_products(products, unhide=True)
|
||||
context_override = tool.Blender.get_viewport_context()
|
||||
with bpy.context.temp_override(**context_override):
|
||||
bpy.ops.view3d.view_selected()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -43,11 +43,20 @@ class ClashSource(PropertyGroup):
|
||||
)
|
||||
|
||||
|
||||
class Clash(PropertyGroup):
|
||||
a_global_id: StringProperty(name="A")
|
||||
b_global_id: StringProperty(name="B")
|
||||
a_name: StringProperty(name="A Name")
|
||||
b_name: StringProperty(name="B Name")
|
||||
status: BoolProperty(name="Status", default=False)
|
||||
|
||||
|
||||
class ClashSet(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
tolerance: FloatProperty(name="Tolerance")
|
||||
a: CollectionProperty(name="Group A", type=ClashSource)
|
||||
b: CollectionProperty(name="Group B", type=ClashSource)
|
||||
clashes: CollectionProperty(name="Clashes", type=Clash)
|
||||
|
||||
|
||||
class SmartClashGroup(PropertyGroup):
|
||||
@@ -63,11 +72,13 @@ class BIMClashProperties(PropertyGroup):
|
||||
clash_results_path: StringProperty(name="Clash Results Path")
|
||||
smart_grouped_clashes_path: StringProperty(name="Smart Grouped Clashes Path")
|
||||
active_clash_set_index: IntProperty(name="Active Clash Set Index")
|
||||
active_clash_index: IntProperty(name="Active Clash Index")
|
||||
smart_clash_groups: CollectionProperty(name="Smart Clash Groups", type=SmartClashGroup)
|
||||
active_smart_group_index: IntProperty(name="Active Smart Group Index")
|
||||
smart_clash_grouping_max_distance: IntProperty(
|
||||
name="Smart Clash Grouping Max Distance", default=3, soft_min=1, soft_max=10
|
||||
)
|
||||
sould_focus_on_clash: BoolProperty(name="Show Focus Clash", default=False)
|
||||
|
||||
@property
|
||||
def active_clash_set(self):
|
||||
@@ -80,3 +91,9 @@ class BIMClashProperties(PropertyGroup):
|
||||
if not self.smart_clash_groups:
|
||||
return None
|
||||
return self.smart_clash_groups[self.active_smart_group_index]
|
||||
|
||||
@property
|
||||
def active_clash(self):
|
||||
if not self.active_clash_set:
|
||||
return None
|
||||
return self.active_clash_set.clashes[self.active_clash_index]
|
||||
|
||||
@@ -27,7 +27,7 @@ class BIM_PT_ifcclash(Panel):
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_tab_quality_control"
|
||||
bl_parent_id = "BIM_PT_tab_clash_detection"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@@ -102,9 +102,46 @@ class BIM_PT_clash_manager(Panel):
|
||||
bl_idname = "BIM_PT_clash_manager"
|
||||
bl_label = "Clash Manager"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "BlenderBIM"
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_tab_clash_detection"
|
||||
|
||||
def draw(self, context):
|
||||
pass
|
||||
|
||||
|
||||
class BIM_PT_dumb_clash_manager(Panel):
|
||||
bl_idname = "BIM_PT_dumb_clash_manager"
|
||||
bl_label = "Dumb Manager"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_clash_manager"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
props = context.scene.BIMClashProperties
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.operator("bim.load_ifc_clashes", text="LOAD IFC CLASHES", icon="IMPORT")
|
||||
row.operator("bim.save_ifc_clashes", text="SAVE CLASH RESULTS", icon="EXPORT")
|
||||
layout.template_list("BIM_UL_clashes", "", props.active_clash_set, "clashes", props, "active_clash_index")
|
||||
# bim.select_clash
|
||||
row = layout.row(align=True)
|
||||
row.operator("bim.select_clash", text="SELECT CLASH", icon="IMPORT")
|
||||
row.prop(props, "sould_focus_on_clash", icon="RESTRICT_VIEW_OFF")
|
||||
|
||||
|
||||
class BIM_PT_smart_clash_manager(Panel):
|
||||
bl_idname = "BIM_PT_smart_clash_manager"
|
||||
bl_label = "Smart Clash Manager"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_clash_manager"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@@ -155,3 +192,14 @@ class BIM_UL_smart_groups(bpy.types.UIList):
|
||||
layout.label(text=str(item.number), translate=False, icon="NONE", icon_value=0)
|
||||
else:
|
||||
layout.label(text="", translate=False)
|
||||
|
||||
|
||||
class BIM_UL_clashes(bpy.types.UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
row.label(text=str(item.a_name), translate=False, icon="NONE", icon_value=0)
|
||||
row.label(text=str(item.b_name), translate=False, icon="NONE", icon_value=0)
|
||||
row.prop(item, "status", text="")
|
||||
else:
|
||||
layout.label(text="", translate=False)
|
||||
|
||||
@@ -21,13 +21,21 @@ from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.AddClassification,
|
||||
operator.AddClassificationFromBSDD,
|
||||
operator.AddClassificationReference,
|
||||
operator.AddClassificationReferenceFromBSDD,
|
||||
operator.AddManualClassification,
|
||||
operator.AddManualClassificationReference,
|
||||
operator.ChangeClassificationLevel,
|
||||
operator.DisableAddingManualClassification,
|
||||
operator.DisableAddingManualClassificationReference,
|
||||
operator.DisableEditingClassification,
|
||||
operator.DisableEditingClassificationReference,
|
||||
operator.DisableEditingClassificationReferences,
|
||||
operator.EditClassification,
|
||||
operator.EditClassificationReference,
|
||||
operator.EnableAddingManualClassification,
|
||||
operator.EnableAddingManualClassificationReference,
|
||||
operator.EnableEditingClassification,
|
||||
operator.EnableEditingClassificationReference,
|
||||
operator.LoadClassificationLibrary,
|
||||
|
||||
@@ -73,6 +73,10 @@ class ReferencesData:
|
||||
if name in [e.Name for e in tool.Ifc.get().by_type("IfcClassification")]:
|
||||
return name
|
||||
|
||||
@classmethod
|
||||
def classifications(cls):
|
||||
return [(str(e.id()), e.Name, "") for e in tool.Ifc.get().by_type("IfcClassification")]
|
||||
|
||||
|
||||
class ClassificationReferencesData(ReferencesData):
|
||||
data = {}
|
||||
@@ -83,6 +87,8 @@ class ClassificationReferencesData(ReferencesData):
|
||||
cls.is_loaded = True
|
||||
cls.data["references"] = cls.references()
|
||||
cls.data["active_classification_library"] = cls.active_classification_library()
|
||||
cls.data["classifications"] = cls.classifications()
|
||||
cls.data["object_type"] = "OBJECT"
|
||||
|
||||
@classmethod
|
||||
def references(cls):
|
||||
@@ -105,6 +111,8 @@ class MaterialClassificationsData(ReferencesData):
|
||||
cls.is_loaded = True
|
||||
cls.data["references"] = cls.references()
|
||||
cls.data["active_classification_library"] = cls.active_classification_library()
|
||||
cls.data["classifications"] = cls.classifications()
|
||||
cls.data["object_type"] = "MATERIAL"
|
||||
|
||||
@classmethod
|
||||
def references(cls):
|
||||
@@ -127,6 +135,8 @@ class CostClassificationsData(ReferencesData):
|
||||
cls.is_loaded = True
|
||||
cls.data["references"] = cls.references()
|
||||
cls.data["active_classification_library"] = cls.active_classification_library()
|
||||
cls.data["classifications"] = cls.classifications()
|
||||
cls.data["object_type"] = "COST"
|
||||
|
||||
@classmethod
|
||||
def references(cls):
|
||||
|
||||
@@ -54,6 +54,120 @@ class AddClassification(bpy.types.Operator, tool.Ifc.Operator):
|
||||
)
|
||||
|
||||
|
||||
class AddManualClassification(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_manual_classification"
|
||||
bl_label = "Add Manual Classification"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMClassificationProperties
|
||||
attributes = blenderbim.bim.helper.export_attributes(props.classification_attributes)
|
||||
classification = ifcopenshell.api.run(
|
||||
"classification.add_classification", tool.Ifc.get(), classification="Unnamed"
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"classification.edit_classification", tool.Ifc.get(), classification=classification, attributes=attributes
|
||||
)
|
||||
props.is_adding = False
|
||||
|
||||
|
||||
class AddManualClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_manual_classification_reference"
|
||||
bl_label = "Add Manual Classification Reference"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj_type: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMClassificationReferenceProperties
|
||||
attributes = blenderbim.bim.helper.export_attributes(props.reference_attributes)
|
||||
product = tool.Ifc.get_entity(obj)
|
||||
# TODO: refactor and support material and cost item classifications
|
||||
classification = tool.Ifc.get().by_id(int(props.classifications))
|
||||
reference = ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
tool.Ifc.get(),
|
||||
product=product,
|
||||
classification=classification,
|
||||
identification="X",
|
||||
name="Unnamed",
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"classification.edit_reference", tool.Ifc.get(), reference=reference, attributes=attributes
|
||||
)
|
||||
props.is_adding = False
|
||||
|
||||
|
||||
class AddClassificationFromBSDD(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_classification_from_bsdd"
|
||||
bl_label = "Add Classification From bSDD"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMBSDDProperties
|
||||
domain = [d for d in props.domains if d.name == props.active_domain][0]
|
||||
for element in tool.Ifc.get().by_type("IfcClassification"):
|
||||
if element.Name == props.active_domain or element.Location == domain.uri:
|
||||
return
|
||||
classification = ifcopenshell.api.run(
|
||||
"classification.add_classification", tool.Ifc.get(), classification=props.active_domain
|
||||
)
|
||||
classification.Source = domain.organization_name_owner
|
||||
classification.Location = domain.uri
|
||||
classification.Edition = domain.version
|
||||
|
||||
|
||||
class EnableAddingManualClassification(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_adding_manual_classification"
|
||||
bl_label = "Enable Adding Manual Classification"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMClassificationProperties
|
||||
props.is_adding = True
|
||||
props.active_classification_id = 0
|
||||
props.classification_attributes.clear()
|
||||
blenderbim.bim.helper.import_attributes2("IfcClassification", props.classification_attributes)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableAddingManualClassification(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_adding_manual_classification"
|
||||
bl_label = "Disable Adding Manual Classification"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMClassificationProperties
|
||||
props.is_adding = False
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableAddingManualClassificationReference(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_adding_manual_classification_reference"
|
||||
bl_label = "Enable Adding Manual Classification Reference"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMClassificationReferenceProperties
|
||||
props.is_adding = True
|
||||
props.reference_attributes.clear()
|
||||
blenderbim.bim.helper.import_attributes2("IfcClassificationReference", props.reference_attributes)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableAddingManualClassificationReference(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_adding_manual_classification_reference"
|
||||
bl_label = "Disable Adding Manual Classification Reference"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMClassificationReferenceProperties
|
||||
props.is_adding = False
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingClassification(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_classification"
|
||||
bl_label = "Enable Editing Classification"
|
||||
@@ -175,21 +289,23 @@ class RemoveClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||
else:
|
||||
objects = [self.obj]
|
||||
|
||||
identification = tool.Ifc.get().by_id(self.reference)[0]
|
||||
active_reference = tool.Ifc.get().by_id(self.reference)
|
||||
identification = active_reference[1]
|
||||
|
||||
for obj in objects:
|
||||
ifc_definition_id = blenderbim.bim.helper.get_obj_ifc_definition_id(context, obj, self.obj_type)
|
||||
element = tool.Ifc.get().by_id(ifc_definition_id)
|
||||
references = ifcopenshell.util.classification.get_references(element, should_inherit=False)
|
||||
for reference in references:
|
||||
if reference[0] == identification:
|
||||
if (identification and reference[1] == identification) or (
|
||||
not identification and reference == active_reference
|
||||
):
|
||||
ifcopenshell.api.run(
|
||||
"classification.remove_reference",
|
||||
tool.Ifc.get(),
|
||||
reference=reference,
|
||||
product=element,
|
||||
)
|
||||
break
|
||||
|
||||
|
||||
class EditClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||
@@ -254,6 +370,85 @@ class AddClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||
)
|
||||
|
||||
|
||||
class AddClassificationReferenceFromBSDD(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_classification_reference_from_bsdd"
|
||||
bl_label = "Add Classification Reference From bSDD"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj: bpy.props.StringProperty()
|
||||
obj_type: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
if self.obj_type == "Object":
|
||||
if context.selected_objects:
|
||||
objects = [o.name for o in context.selected_objects]
|
||||
else:
|
||||
objects = [context.active_object.name]
|
||||
else:
|
||||
objects = [self.obj]
|
||||
props = context.scene.BIMClassificationProperties
|
||||
bprops = context.scene.BIMBSDDProperties
|
||||
|
||||
bsdd_classification = bprops.classifications[bprops.active_classification_index]
|
||||
|
||||
classification = None
|
||||
for element in tool.Ifc.get().by_type("IfcClassification"):
|
||||
if (
|
||||
element.Name == bsdd_classification.domain_name
|
||||
or element.Location == bsdd_classification.domain_namespace_uri
|
||||
):
|
||||
classification = element
|
||||
break
|
||||
|
||||
if not classification:
|
||||
classification = ifcopenshell.api.run(
|
||||
"classification.add_classification", tool.Ifc.get(), classification=bsdd_classification.domain_name
|
||||
)
|
||||
classification.Location = bsdd_classification.domain_namespace_uri
|
||||
|
||||
for obj in objects:
|
||||
ifc_definition_id = blenderbim.bim.helper.get_obj_ifc_definition_id(context, obj, self.obj_type)
|
||||
if not ifc_definition_id:
|
||||
continue
|
||||
element = tool.Ifc.get().by_id(ifc_definition_id)
|
||||
reference = ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
tool.Ifc.get(),
|
||||
product=element,
|
||||
classification=classification,
|
||||
identification=bsdd_classification.reference_code,
|
||||
name=bsdd_classification.name,
|
||||
)
|
||||
reference.Location = bsdd_classification.uri
|
||||
|
||||
for classification_pset in bprops.classification_psets:
|
||||
is_pset = not classification_pset.name.startswith("Qto_")
|
||||
|
||||
if is_pset:
|
||||
pset = ifcopenshell.util.element.get_pset(element, classification_pset.name, psets_only=True)
|
||||
else:
|
||||
pset = ifcopenshell.util.element.get_pset(element, classification_pset.name, qtos_only=True)
|
||||
|
||||
if pset:
|
||||
pset = tool.Ifc.get().by_id(pset["id"])
|
||||
elif is_pset:
|
||||
pset = ifcopenshell.api.run(
|
||||
"pset.add_pset", tool.Ifc.get(), product=element, name=classification_pset.name
|
||||
)
|
||||
else:
|
||||
pset = ifcopenshell.api.run(
|
||||
"pset.add_qto", tool.Ifc.get(), product=element, name=classification_pset.name
|
||||
)
|
||||
|
||||
properties = {}
|
||||
for prop in classification_pset.properties:
|
||||
properties[prop.name] = prop.get_value()
|
||||
|
||||
if is_pset:
|
||||
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties=properties)
|
||||
else:
|
||||
ifcopenshell.api.run("pset.edit_qto", tool.Ifc.get(), qto=pset, properties=properties)
|
||||
|
||||
|
||||
class ChangeClassificationLevel(bpy.types.Operator):
|
||||
bl_idname = "bim.change_classification_level"
|
||||
bl_label = "Change Classification Level"
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import blenderbim.bim.helper
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
from blenderbim.bim.module.classification.data import ClassificationsData
|
||||
from blenderbim.bim.module.classification.data import ClassificationsData, ClassificationReferencesData
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
@@ -39,6 +40,12 @@ def get_available_classifications(self, context):
|
||||
return ClassificationsData.data["available_classifications"]
|
||||
|
||||
|
||||
def get_classifications(self, context):
|
||||
if not ClassificationReferencesData.is_loaded:
|
||||
ClassificationReferencesData.load()
|
||||
return ClassificationReferencesData.data["classifications"]
|
||||
|
||||
|
||||
class ClassificationReference(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
identification: StringProperty(name="Identification")
|
||||
@@ -48,6 +55,16 @@ class ClassificationReference(PropertyGroup):
|
||||
|
||||
|
||||
class BIMClassificationProperties(PropertyGroup):
|
||||
is_adding: BoolProperty(name="Is Adding", default=False)
|
||||
classification_source: EnumProperty(
|
||||
items=[
|
||||
("FILE", "IFC File", ""),
|
||||
("BSDD", "buildingSMART Data Dictionary", ""),
|
||||
("MANUAL", "Manual Entry", ""),
|
||||
],
|
||||
name="Classification Source",
|
||||
default="FILE",
|
||||
)
|
||||
available_classifications: EnumProperty(items=get_available_classifications, name="Available Classifications")
|
||||
classification_attributes: CollectionProperty(name="Classification Attributes", type=Attribute)
|
||||
active_classification_id: IntProperty(name="Active Classification Id")
|
||||
@@ -57,5 +74,7 @@ class BIMClassificationProperties(PropertyGroup):
|
||||
|
||||
|
||||
class BIMClassificationReferenceProperties(PropertyGroup):
|
||||
is_adding: BoolProperty(name="Is Adding", default=False)
|
||||
classifications: EnumProperty(items=get_classifications, name="Classifications")
|
||||
reference_attributes: CollectionProperty(name="Reference Attributes", type=Attribute)
|
||||
active_reference_id: IntProperty(name="Active Reference Id")
|
||||
|
||||
@@ -36,7 +36,7 @@ class BIM_PT_classifications(Panel):
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_project_setup"
|
||||
bl_parent_id = "BIM_PT_tab_project_setup"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
@@ -48,6 +48,48 @@ class BIM_PT_classifications(Panel):
|
||||
|
||||
self.props = context.scene.BIMClassificationProperties
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Source", icon="OUTLINER")
|
||||
row.prop(self.props, "classification_source", text="")
|
||||
|
||||
if self.props.classification_source == "FILE":
|
||||
self.draw_add_file_ui(context)
|
||||
elif self.props.classification_source == "BSDD":
|
||||
self.draw_add_bsdd_ui(context)
|
||||
elif self.props.classification_source == "MANUAL":
|
||||
self.draw_add_manual_ui(context)
|
||||
|
||||
for classification in ClassificationsData.data["classifications"]:
|
||||
if self.props.active_classification_id == classification["id"]:
|
||||
self.draw_editable_ui()
|
||||
else:
|
||||
self.draw_ui(classification)
|
||||
|
||||
def draw_add_manual_ui(self, context):
|
||||
if self.props.is_adding:
|
||||
blenderbim.bim.helper.draw_attributes(self.props.classification_attributes, self.layout)
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.add_manual_classification", text="Save", icon="CHECKMARK")
|
||||
row.operator("bim.disable_adding_manual_classification", text="", icon="CANCEL")
|
||||
else:
|
||||
row = self.layout.row()
|
||||
row.operator("bim.enable_adding_manual_classification", text="Add Classification", icon="ADD")
|
||||
|
||||
def draw_add_bsdd_ui(self, context):
|
||||
self.bprops = context.scene.BIMBSDDProperties
|
||||
|
||||
if not self.bprops.active_domain:
|
||||
row = self.layout.row()
|
||||
row.label(text="No Active bSDD Domain", icon="ERROR")
|
||||
return
|
||||
|
||||
row = self.layout.row()
|
||||
row.label(text="Active: " + self.bprops.active_domain, icon="URL")
|
||||
|
||||
row = self.layout.row()
|
||||
row.operator("bim.add_classification_from_bsdd", icon="ADD")
|
||||
|
||||
def draw_add_file_ui(self, context):
|
||||
if ClassificationsData.data["has_classification_file"]:
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(self.props, "available_classifications", text="")
|
||||
@@ -58,12 +100,6 @@ class BIM_PT_classifications(Panel):
|
||||
row.label(text="No Active Classification Library")
|
||||
row.operator("bim.load_classification_library", text="", icon="IMPORT")
|
||||
|
||||
for classification in ClassificationsData.data["classifications"]:
|
||||
if self.props.active_classification_id == classification["id"]:
|
||||
self.draw_editable_ui()
|
||||
else:
|
||||
self.draw_ui(classification)
|
||||
|
||||
def draw_editable_ui(self):
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.edit_classification", text="Save changes", icon="CHECKMARK")
|
||||
@@ -84,6 +120,7 @@ class ReferenceUI:
|
||||
obj = context.active_object
|
||||
self.oprops = obj.BIMObjectProperties
|
||||
self.sprops = context.scene.BIMClassificationProperties
|
||||
self.bprops = context.scene.BIMBSDDProperties
|
||||
self.props = obj.BIMClassificationReferenceProperties
|
||||
self.file = IfcStore.get_file()
|
||||
|
||||
@@ -100,14 +137,85 @@ class ReferenceUI:
|
||||
self.draw_reference_ui(reference)
|
||||
|
||||
def draw_add_ui(self, context):
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Source", icon="OUTLINER")
|
||||
row.prop(self.sprops, "classification_source", text="")
|
||||
|
||||
if self.sprops.classification_source == "FILE":
|
||||
self.draw_add_file_ui(context)
|
||||
elif self.sprops.classification_source == "BSDD":
|
||||
self.draw_add_bsdd_ui(context)
|
||||
elif self.sprops.classification_source == "MANUAL":
|
||||
self.draw_add_manual_ui(context)
|
||||
|
||||
def draw_add_manual_ui(self, context):
|
||||
row = self.layout.row()
|
||||
row.prop(self.props, "classifications", text="")
|
||||
if self.props.is_adding:
|
||||
blenderbim.bim.helper.draw_attributes(self.props.reference_attributes, self.layout)
|
||||
row = self.layout.row(align=True)
|
||||
op = row.operator("bim.add_manual_classification_reference", text="Save", icon="CHECKMARK")
|
||||
op.type = self.data.data["object_type"]
|
||||
row.operator("bim.disable_adding_manual_classification_reference", text="", icon="CANCEL")
|
||||
else:
|
||||
row = self.layout.row()
|
||||
row.operator("bim.enable_adding_manual_classification_reference", text="Add Reference", icon="ADD")
|
||||
|
||||
def draw_add_bsdd_ui(self, context):
|
||||
if not self.bprops.active_domain:
|
||||
row = self.layout.row()
|
||||
row.label(text="No Active bSDD Domain", icon="ERROR")
|
||||
return
|
||||
|
||||
row = self.layout.row()
|
||||
row.label(text="Active: " + self.bprops.active_domain, icon="URL")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(self.bprops, "keyword", text="")
|
||||
row.operator("bim.search_bsdd_classifications", text="", icon="VIEWZOOM")
|
||||
|
||||
row = self.layout.row()
|
||||
row.prop(self.bprops, "should_filter_ifc_class")
|
||||
|
||||
if len(self.bprops.classifications):
|
||||
self.layout.template_list(
|
||||
"BIM_UL_bsdd_classifications",
|
||||
"",
|
||||
self.bprops,
|
||||
"classifications",
|
||||
self.bprops,
|
||||
"active_classification_index",
|
||||
)
|
||||
else:
|
||||
row = self.layout.row()
|
||||
row.label(text="No Search Results")
|
||||
|
||||
if self.bprops.active_classification_index < len(self.bprops.classifications):
|
||||
row = self.layout.row(align=True)
|
||||
op = row.operator(
|
||||
"bim.add_classification_reference_from_bsdd", text="Add Classification Reference", icon="ADD"
|
||||
)
|
||||
op.obj = self.obj
|
||||
op.obj_type = self.obj_type
|
||||
row.operator("bim.get_bsdd_classification_properties", text="", icon="COPY_ID")
|
||||
|
||||
if len(self.bprops.classification_psets):
|
||||
for pset in self.bprops.classification_psets:
|
||||
box = self.layout.box()
|
||||
row = box.row()
|
||||
row.label(text=pset.name, icon="COPY_ID")
|
||||
blenderbim.bim.helper.draw_attributes(pset.properties, box)
|
||||
|
||||
def draw_add_file_ui(self, context):
|
||||
if not self.data.data["active_classification_library"]:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="No Active Classification Library")
|
||||
row.label(text="No Active Classification Library", icon="ERROR")
|
||||
row.operator("bim.load_classification_library", text="", icon="IMPORT")
|
||||
return
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=f"Active Classification Library: {self.data.data['active_classification_library']}")
|
||||
#row.prop(self.sprops, "available_classifications", text="")
|
||||
# row.prop(self.sprops, "available_classifications", text="")
|
||||
if not self.sprops.available_library_references:
|
||||
op = row.operator("bim.change_classification_level", text="", icon="GREASEPENCIL")
|
||||
op.parent_id = int(self.sprops.available_classifications)
|
||||
@@ -146,6 +254,8 @@ class ReferenceUI:
|
||||
name = reference["Identification"] or "No Identification"
|
||||
row.label(text=name, icon="ASSET_MANAGER")
|
||||
row.label(text=reference["Name"] or "")
|
||||
if reference["Location"]:
|
||||
row.operator("bim.open_uri", icon="URL", text="").uri = reference["Location"]
|
||||
if not self.props.active_reference_id:
|
||||
op = row.operator("bim.enable_editing_classification_reference", text="", icon="GREASEPENCIL")
|
||||
op.reference = reference["id"]
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import os
|
||||
import logging
|
||||
import ifcopenshell
|
||||
import json
|
||||
import webbrowser
|
||||
import tempfile
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
class SelectCobieIfcFile(bpy.types.Operator):
|
||||
bl_idname = "bim.select_cobie_ifc_file"
|
||||
bl_label = "Select COBie IFC File"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.COBieProperties.cobie_ifc_file = self.filepath
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
context.window_manager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
|
||||
class SelectCobieJsonFile(bpy.types.Operator):
|
||||
bl_idname = "bim.select_cobie_json_file"
|
||||
bl_label = "Select COBie JSON File"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.COBieProperties.cobie_json_file = self.filepath
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
context.window_manager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
|
||||
class ExecuteIfcCobie(bpy.types.Operator):
|
||||
bl_idname = "bim.execute_ifc_cobie"
|
||||
bl_label = "Execute IFCCOBie"
|
||||
file_format: bpy.props.StringProperty()
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
props = context.scene.COBieProperties
|
||||
return props.should_load_from_memory or props.cobie_ifc_file
|
||||
|
||||
def execute(self, context):
|
||||
from cobie import IfcCobieParser
|
||||
|
||||
props = context.scene.COBieProperties
|
||||
|
||||
if props.should_load_from_memory:
|
||||
output_dir = tempfile.gettempdir()
|
||||
else:
|
||||
output_dir = os.path.dirname(props.cobie_ifc_file)
|
||||
|
||||
output = os.path.join(output_dir, "output")
|
||||
logger = logging.getLogger("IFCtoCOBie")
|
||||
fh = logging.FileHandler(os.path.join(output_dir, "cobie.log"))
|
||||
fh.setLevel(logging.DEBUG)
|
||||
fh.setFormatter(logging.Formatter("%(asctime)s : %(levelname)s : %(message)s"))
|
||||
logger = logging.getLogger("IFCtoCOBie")
|
||||
logger.addHandler(fh)
|
||||
selector = ifcopenshell.util.selector.Selector()
|
||||
if props.cobie_json_file:
|
||||
with open(props.cobie_json_file, "r") as f:
|
||||
custom_data = json.load(f)
|
||||
else:
|
||||
custom_data = {}
|
||||
parser = IfcCobieParser(logger, selector)
|
||||
|
||||
ifc_file = IfcStore.get_file()
|
||||
|
||||
if not (ifc_file and props.should_load_from_memory):
|
||||
ifc_file = props.cobie_ifc_file
|
||||
|
||||
parser.parse(
|
||||
ifc_file,
|
||||
props.cobie_types,
|
||||
props.cobie_components,
|
||||
custom_data,
|
||||
)
|
||||
if self.file_format == "xlsx":
|
||||
from cobie import CobieXlsWriter
|
||||
|
||||
writer = CobieXlsWriter(parser, output)
|
||||
writer.write()
|
||||
webbrowser.open("file://" + output + "." + self.file_format)
|
||||
elif self.file_format == "ods":
|
||||
from cobie import CobieOdsWriter
|
||||
|
||||
writer = CobieOdsWriter(parser, output)
|
||||
writer.write()
|
||||
webbrowser.open("file://" + output + "." + self.file_format)
|
||||
else:
|
||||
from cobie import CobieCsvWriter
|
||||
|
||||
writer = CobieCsvWriter(parser, output_dir)
|
||||
writer.write()
|
||||
webbrowser.open("file://" + output_dir)
|
||||
webbrowser.open("file://" + output_dir + "/cobie.log")
|
||||
return {"FINISHED"}
|
||||
@@ -29,7 +29,7 @@ class BIM_PT_constraints(Panel):
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_project_setup"
|
||||
bl_parent_id = "BIM_PT_tab_project_setup"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
||||
@@ -29,7 +29,7 @@ class BIM_PT_context(bpy.types.Panel):
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_geometry"
|
||||
bl_parent_id = "BIM_PT_tab_geometry"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
||||
@@ -20,64 +20,65 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.AddCostColumn,
|
||||
operator.AddCostItem,
|
||||
operator.AddCostItemQuantity,
|
||||
operator.AddCostSchedule,
|
||||
operator.RemoveCostSchedule,
|
||||
operator.EditCostSchedule,
|
||||
operator.AddCostValue,
|
||||
operator.AddCurrency,
|
||||
operator.AddSummaryCostItem,
|
||||
operator.AssignCostItemQuantity,
|
||||
operator.AssignCostItemType,
|
||||
operator.AssignCostValue,
|
||||
operator.CalculateCostItemResourceValue,
|
||||
operator.ChangeParentCostItem,
|
||||
operator.ClearCostItemAssignments,
|
||||
operator.ContractCostItem,
|
||||
operator.ContractCostItemRate,
|
||||
operator.ContractCostItems,
|
||||
operator.CopyCostItem,
|
||||
operator.CopyCostItemValues,
|
||||
operator.DisableEditingCostItem,
|
||||
operator.DisableEditingCostItemQuantity,
|
||||
operator.DisableEditingCostItemValue,
|
||||
operator.DisableEditingCostSchedule,
|
||||
operator.EditCostItem,
|
||||
operator.EditCostItemQuantity,
|
||||
operator.EditCostItemValue,
|
||||
operator.EditCostItemValueFormula,
|
||||
operator.EnableEditingCostSchedule,
|
||||
operator.EnableEditingCostItems,
|
||||
operator.EditCostSchedule,
|
||||
operator.EnableEditingCostItem,
|
||||
operator.ExportCostSchedules,
|
||||
operator.ExpandCostItems,
|
||||
operator.EnableEditingCostItemQuantities,
|
||||
operator.EnableEditingCostItemQuantity,
|
||||
operator.EnableEditingCostItemValues,
|
||||
operator.EnableEditingCostItems,
|
||||
operator.EnableEditingCostItemValue,
|
||||
operator.EnableEditingCostItemValueFormula,
|
||||
operator.DisableEditingCostItem,
|
||||
operator.DisableEditingCostSchedule,
|
||||
operator.DisableEditingCostItemQuantity,
|
||||
operator.DisableEditingCostItemValue,
|
||||
operator.AddCostColumn,
|
||||
operator.RemoveCostColumn,
|
||||
operator.AddCostItem,
|
||||
operator.AddSummaryCostItem,
|
||||
operator.EnableEditingCostItemValues,
|
||||
operator.EnableEditingCostSchedule,
|
||||
operator.ExpandCostItem,
|
||||
operator.ContractCostItem,
|
||||
operator.ExpandCostItemRate,
|
||||
operator.ExpandCostItems,
|
||||
operator.ExportCostSchedules,
|
||||
operator.HighlightProductCostItem,
|
||||
operator.ImportCostScheduleCsv,
|
||||
operator.LoadCostItemElementQuantities,
|
||||
operator.LoadCostItemQuantities,
|
||||
operator.LoadCostItemResourceQuantities,
|
||||
operator.LoadCostItemTaskQuantities,
|
||||
operator.LoadCostItemTypes,
|
||||
operator.LoadProductCostItems,
|
||||
operator.LoadScheduleOfRates,
|
||||
operator.RemoveCostColumn,
|
||||
operator.RemoveCostItem,
|
||||
operator.AssignCostItemType,
|
||||
operator.UnassignCostItemType,
|
||||
operator.AssignCostItemQuantity,
|
||||
operator.UnassignCostItemQuantity,
|
||||
operator.AddCostItemQuantity,
|
||||
operator.RemoveCostItemQuantity,
|
||||
operator.AddCostValue,
|
||||
operator.RemoveCostItemValue,
|
||||
operator.CopyCostItemValues,
|
||||
operator.RemoveCostSchedule,
|
||||
operator.ReorderCostItem,
|
||||
operator.SelectCostItemProducts,
|
||||
operator.SelectCostScheduleProducts,
|
||||
operator.ImportCostScheduleCsv,
|
||||
operator.LoadCostItemQuantities,
|
||||
operator.LoadCostItemTypes,
|
||||
operator.AssignCostValue,
|
||||
operator.LoadScheduleOfRates,
|
||||
operator.ExpandCostItemRate,
|
||||
operator.ContractCostItemRate,
|
||||
operator.CalculateCostItemResourceValue,
|
||||
operator.ClearCostItemAssignments,
|
||||
operator.HighlightProductCostItem,
|
||||
operator.LoadProductCostItems,
|
||||
operator.ReorderCostItem,
|
||||
operator.SelectUnassignedProducts,
|
||||
operator.LoadCostItemElementQuantities,
|
||||
operator.LoadCostItemTaskQuantities,
|
||||
operator.LoadCostItemResourceQuantities,
|
||||
operator.ChangeParentCostItem,
|
||||
operator.CopyCostItem,
|
||||
operator.AddCurrency,
|
||||
operator.UnassignCostItemQuantity,
|
||||
operator.UnassignCostItemType,
|
||||
prop.CostItem,
|
||||
prop.CostItemQuantity,
|
||||
prop.CostItemType,
|
||||
|
||||
@@ -117,6 +117,7 @@ class CostSchedulesData:
|
||||
data["TotalAppliedValue"] = 0.0
|
||||
data["TotalCost"] = 0.0
|
||||
has_unit_basis = False
|
||||
is_sum = False
|
||||
if root_element.is_a("IfcCostItem"):
|
||||
values = root_element.CostValues
|
||||
elif root_element.is_a("IfcConstructionResource"):
|
||||
@@ -130,14 +131,18 @@ class CostSchedulesData:
|
||||
data["UnitBasisValueComponent"] = cost_value_data["UnitBasis"]["ValueComponent"]
|
||||
data["UnitBasisUnitSymbol"] = cost_value_data["UnitBasis"]["UnitSymbol"]
|
||||
has_unit_basis = True
|
||||
if has_unit_basis:
|
||||
data["TotalCost"] = data["TotalAppliedValue"] / data["UnitBasisValueComponent"]
|
||||
else:
|
||||
if data["TotalCostQuantity"] is not None:
|
||||
data["TotalCost"] = data["TotalAppliedValue"] * data["TotalCostQuantity"]
|
||||
else:
|
||||
data["TotalCost"] = data["TotalAppliedValue"]
|
||||
data["TotalAppliedValue"] = None
|
||||
data["UnitBasisValueComponent"] = 1
|
||||
data["UnitBasisUnitSymbol"] = "U"
|
||||
if cost_value.Category == "*":
|
||||
is_sum = True
|
||||
cost_quantity = data["TotalCostQuantity"] or 1
|
||||
if has_unit_basis:
|
||||
data["TotalCost"] = data["TotalAppliedValue"] * cost_quantity / data["UnitBasisValueComponent"]
|
||||
else:
|
||||
data["TotalCost"] = data["TotalAppliedValue"] * cost_quantity
|
||||
if is_sum:
|
||||
data["TotalAppliedValue"] = None
|
||||
|
||||
@classmethod
|
||||
def _load_cost_item_quantities(cls, cost_item, data):
|
||||
@@ -153,8 +158,10 @@ class CostSchedulesData:
|
||||
unit = ifcopenshell.util.unit.get_property_unit(quantity, tool.Ifc.get())
|
||||
if unit:
|
||||
data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(unit)
|
||||
else:
|
||||
data["UnitSymbol"] = None
|
||||
if quantity.is_a("IfcPhysicalSimpleQuantity"):
|
||||
measure_class = quantity.wrapped_data.declaration().as_entity().attribute_by_index(3).type_of_attribute().declared_type().name()
|
||||
if "Count" in measure_class:
|
||||
data["UnitSymbol"] = "U"
|
||||
|
||||
# same_unit_nested_cost_item = set()
|
||||
# data["DerivedTotalCostQuantity"] = None
|
||||
@@ -249,7 +256,7 @@ class CostSchedulesData:
|
||||
for cost_value in cost_item.CostValues or []:
|
||||
label = "{0:.2f}".format(ifcopenshell.util.cost.calculate_applied_value(cost_item, cost_value))
|
||||
label += " = {}".format(ifcopenshell.util.cost.serialise_cost_value(cost_value))
|
||||
results.append({"id": cost_value.id(), "label": label})
|
||||
results.append({"id": cost_value.id(), "label": label, "name": cost_value.Name})
|
||||
return results
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -33,9 +33,24 @@ class AddCostSchedule(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_label = "Add Cost Schedule"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Add a new cost schedule"
|
||||
name: bpy.props.StringProperty()
|
||||
object_type: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
core.add_cost_schedule(tool.Ifc, predefined_type=context.scene.BIMCostProperties.cost_schedule_predefined_types)
|
||||
predefined_type = context.scene.BIMCostProperties.cost_schedule_predefined_types
|
||||
if predefined_type == "USERDEFINED":
|
||||
predefined_type = self.object_type
|
||||
core.add_cost_schedule(tool.Ifc, name=self.name, predefined_type=predefined_type)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(self, "name", text="Name")
|
||||
layout.prop(context.scene.BIMCostProperties, "cost_schedule_predefined_types", text="Type")
|
||||
if context.scene.BIMCostProperties.cost_schedule_predefined_types == "USERDEFINED":
|
||||
layout.prop(self, "object_type", text="Object type")
|
||||
|
||||
def invoke(self, context, event):
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
|
||||
|
||||
class EditCostSchedule(bpy.types.Operator, tool.Ifc.Operator):
|
||||
@@ -156,6 +171,17 @@ class ContractCostItem(bpy.types.Operator, tool.Ifc.Operator):
|
||||
core.contract_cost_item(tool.Cost, cost_item=tool.Ifc.get().by_id(self.cost_item))
|
||||
|
||||
|
||||
class ContractCostItems(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.contract_cost_items"
|
||||
bl_label = "Contract Cost Item"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Collapse cost item tree"
|
||||
cost_item: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
core.contract_cost_items(tool.Cost)
|
||||
|
||||
|
||||
class RemoveCostItem(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.remove_cost_item"
|
||||
bl_label = "Remove Cost Item"
|
||||
@@ -635,7 +661,9 @@ class ExportCostSchedules(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
cost_schedule = tool.Ifc.get().by_id(self.cost_schedule) if self.cost_schedule else None
|
||||
r = core.export_cost_schedules(tool.Cost, filepath=self.filepath, format=self.format, cost_schedule=cost_schedule)
|
||||
r = core.export_cost_schedules(
|
||||
tool.Cost, filepath=self.filepath, format=self.format, cost_schedule=cost_schedule
|
||||
)
|
||||
if isinstance(r, str):
|
||||
self.report({"ERROR"}, r)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -21,7 +21,6 @@ import blenderbim.bim.module.cost.prop as CostProp
|
||||
from bpy.types import Panel, UIList
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.cost.data import CostSchedulesData
|
||||
import blenderbim.tool as tool
|
||||
|
||||
|
||||
class BIM_PT_cost_schedules(Panel):
|
||||
@@ -30,27 +29,31 @@ class BIM_PT_cost_schedules(Panel):
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_tab_cost"
|
||||
bl_options = {"HIDE_HEADER"}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "SCHEDULING") and tool.Ifc.get() and tool.Ifc.get().schema != "IFC2X3"
|
||||
file = IfcStore.get_file()
|
||||
return file and hasattr(file, "schema") and file.schema != "IFC2X3"
|
||||
|
||||
def draw(self, context):
|
||||
if not CostSchedulesData.is_loaded:
|
||||
CostSchedulesData.load()
|
||||
|
||||
self.props = context.scene.BIMCostProperties
|
||||
row = self.layout.row()
|
||||
if not self.props.active_cost_schedule_id:
|
||||
row = self.layout.row(align=True)
|
||||
if CostSchedulesData.data["total_cost_schedules"]:
|
||||
row.alignment = "RIGHT"
|
||||
row.operator("bim.export_cost_schedules",icon="EXPORT",text="Export All Schedules")
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=f"{CostSchedulesData.data['total_cost_schedules']} Cost Schedules Found", icon="TEXT")
|
||||
row.operator("bim.export_cost_schedules", text="Export as spreadsheet", icon="EXPORT")
|
||||
else:
|
||||
row.label(text="No Cost Schedules found.", icon="COMMUNITY")
|
||||
row = self.layout.row()
|
||||
row.alignment = "RIGHT"
|
||||
row.prop(self.props, "cost_schedule_predefined_types")
|
||||
row.operator("bim.add_cost_schedule", icon="ADD", text="Add")
|
||||
row.label(text="No Cost Schedules found.", icon="TEXT")
|
||||
|
||||
row.operator("bim.add_cost_schedule", icon="ADD", text="")
|
||||
row.operator("import_cost_schedule_csv.bim",icon="IMPORT",text="")
|
||||
|
||||
for schedule in CostSchedulesData.data["schedules"]:
|
||||
self.draw_cost_schedule_ui(schedule)
|
||||
@@ -138,8 +141,8 @@ class BIM_PT_cost_schedules(Panel):
|
||||
row = self.layout.row(align=True)
|
||||
row.alignment = "RIGHT"
|
||||
row.operator("bim.add_summary_cost_item", text="Add Summary Cost", icon="ADD")
|
||||
row.operator("bim.expand_all_tasks", text="Expand All")
|
||||
row.operator("bim.contract_all_tasks", text="Contract All")
|
||||
row.operator("bim.expand_cost_items", text="Expand All")
|
||||
row.operator("bim.contract_cost_items", text="Contract All")
|
||||
row = self.layout.row(align=True)
|
||||
row.alignment = "RIGHT"
|
||||
if self.props.cost_items and self.props.active_cost_item_index < len(self.props.cost_items):
|
||||
@@ -235,6 +238,8 @@ class BIM_PT_cost_schedules(Panel):
|
||||
blenderbim.bim.helper.draw_attributes(self.props.cost_value_attributes, self.layout.box())
|
||||
|
||||
def draw_readonly_cost_value_ui(self, layout, cost_value):
|
||||
if cost_value["name"]:
|
||||
layout.label(text=f"{cost_value['name']}: ")
|
||||
if self.props.active_cost_value_id == cost_value["id"] and self.props.cost_value_editing_type == "FORMULA":
|
||||
layout.prop(self.props, "cost_value_formula", text="")
|
||||
else:
|
||||
@@ -619,18 +624,22 @@ class BIM_UL_cost_items_trait:
|
||||
else:
|
||||
row.label(text="", icon="DOT")
|
||||
|
||||
def draw_total_cost_column(self, layout, cost_item):
|
||||
format_numbers = "{0:,.2f}".format(cost_item["TotalCost"]).replace(",", " ")
|
||||
currency = CostSchedulesData.data["currency"]
|
||||
text = "{} {}".format(format_numbers, currency["name"]) if currency else format_numbers
|
||||
layout.label(text=text)
|
||||
|
||||
def draw_quantity_column(self, layout, cost_item):
|
||||
if CostSchedulesData.data["is_editing_rates"]:
|
||||
self.draw_uom_column(layout, cost_item)
|
||||
else:
|
||||
self.draw_total_quantity_column(layout, cost_item)
|
||||
|
||||
def draw_uom_column(self, layout, cost_item):
|
||||
layout.label(text=cost_item["UnitBasisUnitSymbol"])
|
||||
|
||||
def draw_total_quantity_column(self, layout, cost_item):
|
||||
if cost_item["TotalCostQuantity"]:
|
||||
label = "{0:.2f}".format(cost_item["TotalCostQuantity"]) + f" {cost_item['UnitSymbol'] or '-'}"
|
||||
layout.label(text=label)
|
||||
else:
|
||||
layout.label(text="-")
|
||||
|
||||
def draw_value_column(self, layout, cost_item):
|
||||
if cost_item["TotalAppliedValue"]:
|
||||
text = "{0:,.2f}".format(cost_item["TotalAppliedValue"]).replace(",", " ")
|
||||
@@ -642,8 +651,11 @@ class BIM_UL_cost_items_trait:
|
||||
else:
|
||||
layout.label(text="-")
|
||||
|
||||
def draw_uom_column(self, layout, cost_item):
|
||||
layout.label(text=cost_item["UnitBasisUnitSymbol"] or "-" if cost_item["UnitBasisValueComponent"] else "-")
|
||||
def draw_total_cost_column(self, layout, cost_item):
|
||||
format_numbers = "{0:,.2f}".format(cost_item["TotalCost"]).replace(",", " ")
|
||||
currency = CostSchedulesData.data["currency"]
|
||||
text = "{} {}".format(format_numbers, currency["name"]) if currency else format_numbers
|
||||
layout.label(text=text)
|
||||
|
||||
def draw_order_operator(self, row, ifc_definition_id, cost_item):
|
||||
if cost_item["NestingIndex"] is not None:
|
||||
@@ -656,20 +668,6 @@ class BIM_UL_cost_items_trait:
|
||||
op.cost_item = ifc_definition_id
|
||||
op.new_index = cost_item["NestingIndex"] - 1
|
||||
|
||||
def draw_total_quantity_column(self, layout, cost_item):
|
||||
if cost_item["TotalCostQuantity"]:
|
||||
label = "{0:.2f}".format(cost_item["TotalCostQuantity"]) + f" {cost_item['UnitSymbol'] or '-'}"
|
||||
layout.label(text=label)
|
||||
else:
|
||||
layout.label(text="-")
|
||||
# if cost_item["DerivedTotalCostQuantity"] not in [None, 0]:
|
||||
# layout.label(text="{0:.2f}".format(cost_item["DerivedTotalCostQuantity"]) + f" {cost_item['DerivedUnitSymbol'] or '-'}")
|
||||
# else:
|
||||
# if cost_item["TotalCostQuantity"] == 0:
|
||||
# layout.label(text="-")
|
||||
# else:
|
||||
# layout.label(text="{0:.2f}".format(cost_item["TotalCostQuantity"]) + f" {cost_item['UnitSymbol'] or '-'}")
|
||||
|
||||
|
||||
class BIM_UL_cost_items(BIM_UL_cost_items_trait, UIList):
|
||||
def __init__(self):
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
from . import prop, workspace
|
||||
|
||||
classes = (
|
||||
prop.BIMCoveringProperties,
|
||||
workspace.Hotkey,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
if not bpy.app.background:
|
||||
bpy.utils.register_tool(workspace.CoveringTool, after={"bim.structural_tool"}, separator=False, group=False)
|
||||
bpy.types.Scene.BIMCoveringProperties = bpy.props.PointerProperty(type=prop.BIMCoveringProperties)
|
||||
# bpy.types.Object.BIMObjectSpatialProperties = bpy.props.PointerProperty(type=prop.BIMObjectSpatialProperties)
|
||||
# bpy.types.Scene.BIMSpatialManagerProperties = bpy.props.PointerProperty(type=prop.BIMSpatialManagerProperties)
|
||||
|
||||
|
||||
def unregister():
|
||||
if not bpy.app.background:
|
||||
bpy.utils.unregister_tool(workspace.CoveringTool)
|
||||
del bpy.types.Scene.BIMCoveringProperties
|
||||
# del bpy.types.Object.BIMObjectSpatialProperties
|
||||
# del bpy.types.Scene.BIMSpatialManagerProperties
|
||||
@@ -17,8 +17,8 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
from blenderbim.bim.module.lca.data import LcaData
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
#from blenderbim.bim.module.spatial.data import SpatialData
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
@@ -30,15 +30,10 @@ from bpy.props import (
|
||||
FloatVectorProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
#import blenderbim.tool as tool
|
||||
#import blenderbim.core.geometry
|
||||
#import ifcopenshell
|
||||
|
||||
|
||||
def get_product_systems(self, context):
|
||||
if not LcaData.is_loaded:
|
||||
LcaData.load()
|
||||
return LcaData.data["product_systems"]
|
||||
|
||||
|
||||
class BIMLCAProperties(PropertyGroup):
|
||||
is_connected: BoolProperty(name="Is Connected")
|
||||
amount: FloatProperty(name="Amount")
|
||||
product_systems: EnumProperty(items=get_product_systems, name="Product Systems")
|
||||
class BIMCoveringProperties(PropertyGroup):
|
||||
ceiling_height: bpy.props.FloatProperty(name="ceiling_height", default=2.7, subtype="DISTANCE", description="Ceiling height")
|
||||
@@ -0,0 +1,272 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2023 @Andrej730
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
import os
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.helper import prop_with_search
|
||||
from blenderbim.bim.module.model.data import AuthoringData
|
||||
from bpy.types import WorkSpaceTool
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
import blenderbim.bim.handler
|
||||
|
||||
|
||||
# declaring it here to avoid circular import problems
|
||||
class Operator:
|
||||
def execute(self, context):
|
||||
IfcStore.execute_ifc_operator(self, context)
|
||||
blenderbim.bim.handler.refresh_ui_data()
|
||||
return {"FINISHED"}
|
||||
|
||||
class CoveringTool(WorkSpaceTool):
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_context_mode = "OBJECT"
|
||||
bl_idname = "bim.covering_tool"
|
||||
bl_label = "Covering Tool"
|
||||
bl_description = "Create and edit coverings"
|
||||
bl_icon = os.path.join(os.path.dirname(__file__), "ops.authoring.covering")
|
||||
bl_widget = None
|
||||
ifc_element_type = "IfcCoveringType"
|
||||
bl_keymap = tool.Blender.get_default_selection_keypmap() + (
|
||||
("bim.covering_hotkey", {"type": "A", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_A")]}),
|
||||
("bim.covering_hotkey", {"type": "G", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_G")]}),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def draw_settings(cls, context, layout, ws_tool):
|
||||
CoveringToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
|
||||
|
||||
def add_layout_hotkey(layout, text, hotkey, description):
|
||||
args = ["covering", layout, text, hotkey, description]
|
||||
tool.Blender.add_layout_hotkey_operator(*args)
|
||||
|
||||
class CoveringToolUI:
|
||||
@classmethod
|
||||
def draw(cls, context, layout, ifc_element_type = None):
|
||||
cls.layout = layout
|
||||
cls.props = context.scene.BIMModelProperties
|
||||
cls.covering_props = context.scene.BIMCoveringProperties
|
||||
|
||||
|
||||
row = cls.layout.row(align=True)
|
||||
if not tool.Ifc.get():
|
||||
row.label(text="No IFC Project", icon="ERROR")
|
||||
return
|
||||
|
||||
if not AuthoringData.is_loaded:
|
||||
AuthoringData.load(ifc_element_type)
|
||||
elif AuthoringData.data["ifc_element_type"] != ifc_element_type:
|
||||
AuthoringData.load(ifc_element_type)
|
||||
|
||||
if context.region.type == "TOOL_HEADER":
|
||||
cls.draw_header_interface()
|
||||
elif context.region.type in ("UI", "WINDOW"):
|
||||
cls.draw_basic_bim_tool_interface()
|
||||
|
||||
cls.draw_default_interface()
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def draw_header_interface(cls):
|
||||
cls.draw_type_selection_interface()
|
||||
|
||||
@classmethod
|
||||
def draw_default_interface(cls):
|
||||
row = cls.layout.row(align=True)
|
||||
row.prop(data=cls.props, property="rl3", text="RL")
|
||||
row = cls.layout.row(align=True)
|
||||
row.prop(data=cls.covering_props, property="ceiling_height", text="Ceiling Height")
|
||||
if AuthoringData.data["ifc_classes"]:
|
||||
active_obj = bpy.context.active_object
|
||||
element = tool.Ifc.get_entity(active_obj)
|
||||
collection = bpy.context.view_layer.active_layer_collection.collection
|
||||
collection_obj = collection.BIMCollectionProperties.obj
|
||||
|
||||
relating_type_id = int(cls.props.relating_type_id)
|
||||
type_material_usage = ifcopenshell.util.element.get_material(tool.Ifc.get().by_id(relating_type_id)).is_a()
|
||||
|
||||
# PLEASE KEEP COMMENTS AS A REMINDER
|
||||
# elif element and bpy.context.selected_objects and element.is_a("IfcSpace"):
|
||||
# op. = row.operator("bim.add_istance_flooring_from_spaces"):
|
||||
|
||||
if (type_material_usage == "IfcMaterialLayerSet" and
|
||||
not bpy.context.selected_objects):
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_A")
|
||||
if tool.Ifc.get_entity(collection_obj):
|
||||
if AuthoringData.data["predefined_type"] == "FLOORING":
|
||||
op = row.operator("bim.add_instance_flooring_covering_from_cursor")
|
||||
elif AuthoringData.data["predefined_type"] == "CEILING":
|
||||
op = row.operator("bim.add_instance_ceiling_covering_from_cursor")
|
||||
else:
|
||||
op = row.operator("bim.add_constr_type_instance", text="Add")
|
||||
op.from_invoke = True
|
||||
if cls.props.relating_type_id.isnumeric():
|
||||
op.relating_type_id = int(cls.props.relating_type_id)
|
||||
|
||||
else:
|
||||
op = row.operator("bim.add_constr_type_instance", text="Add")
|
||||
op.from_invoke = True
|
||||
if cls.props.relating_type_id.isnumeric():
|
||||
op.relating_type_id = int(cls.props.relating_type_id)
|
||||
|
||||
elif (AuthoringData.data["predefined_type"] == "FLOORING" and
|
||||
type_material_usage == "IfcMaterialLayerSet" and
|
||||
element and
|
||||
bpy.context.selected_objects and
|
||||
element.is_a("IfcWall")):
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_A")
|
||||
op = row.operator("bim.add_instance_flooring_coverings_from_walls")
|
||||
|
||||
elif (AuthoringData.data["predefined_type"] == "CEILING" and
|
||||
type_material_usage == "IfcMaterialLayerSet" and
|
||||
element and
|
||||
bpy.context.selected_objects and
|
||||
element.is_a("IfcWall")):
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_A")
|
||||
op = row.operator("bim.add_instance_ceiling_coverings_from_walls")
|
||||
|
||||
elif (element and
|
||||
bpy.context.selected_objects and
|
||||
element.is_a("IfcCovering") and
|
||||
# AuthoringData.data["predefined_type"] == "FLOORING" and
|
||||
AuthoringData.data["active_material_usage"] == "LAYER3"):
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_G")
|
||||
op = row.operator("bim.regen_selected_covering_object")
|
||||
|
||||
|
||||
|
||||
# elif AuthoringData.data["predefined_type"] == "CEILING":
|
||||
# row = cls.layout.row(align=True)
|
||||
# row.prop(data=cls.props, property="ceiling_height", text="ceiling height")
|
||||
# if element and bpy.context.selected_objects and element.is_a("IfcWall"):
|
||||
# op = row.operator("bim.add_instance_ceiling_coverings_from_walls")
|
||||
# elif element and bpy.context.selected_objects and element.is_a("IfcSpace"):
|
||||
# op. = row.operator("bim.add_istance_flooring_from_spaces"):
|
||||
# else:
|
||||
# op = row.operator("bim.add_instance_ceiling_from_cursor")
|
||||
# op = row.operator("bim.add_constr_type_instance", text="Add")
|
||||
# op.from_invoke = True
|
||||
# if cls.props.relating_type_id.isnumeric():
|
||||
# op.relating_type_id = int(cls.props.relating_type_id)
|
||||
else:
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_A")
|
||||
op = row.operator("bim.add_constr_type_instance", text="Add")
|
||||
op.from_invoke = True
|
||||
if cls.props.relating_type_id.isnumeric():
|
||||
op.relating_type_id = int(cls.props.relating_type_id)
|
||||
|
||||
@classmethod
|
||||
def draw_type_selection_interface(cls):
|
||||
# shared by both sidebar and header
|
||||
row = cls.layout.row(align=True)
|
||||
if AuthoringData.data["ifc_classes"]:
|
||||
row = cls.layout.row(align=True)
|
||||
row.label(text="", icon="FILE_3D")
|
||||
prop_with_search(row, cls.props, "relating_type_id", text="")
|
||||
row.operator("bim.launch_type_manager", icon="LIGHTPROBE_GRID", text="")
|
||||
else:
|
||||
row.label(text=f"No {AuthoringData.data['ifc_element_type']} Found", icon="ERROR")
|
||||
row = cls.layout.row()
|
||||
row.operator("bim.launch_type_manager", icon="LIGHTPROBE_GRID", text="Launch Type Manager")
|
||||
|
||||
@classmethod
|
||||
def draw_basic_bim_tool_interface(cls):
|
||||
cls.draw_type_selection_interface()
|
||||
|
||||
if AuthoringData.data["ifc_classes"]:
|
||||
if cls.props.ifc_class:
|
||||
box = cls.layout.box()
|
||||
if AuthoringData.data["type_thumbnail"]:
|
||||
box.template_icon(icon_value=AuthoringData.data["type_thumbnail"], scale=5)
|
||||
else:
|
||||
op = box.operator("bim.load_type_thumbnails", text="Load Thumbnails", icon="FILE_REFRESH")
|
||||
op.ifc_class = cls.props.ifc_class
|
||||
|
||||
|
||||
class Hotkey(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.covering_hotkey"
|
||||
bl_label = "Hotkey"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
hotkey: bpy.props.StringProperty()
|
||||
description: bpy.props.StringProperty()
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Ifc.get()
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, operator):
|
||||
return operator.description or ""
|
||||
|
||||
def _execute(self, context):
|
||||
# self.props = context.scene.BIMCoveringProperties
|
||||
getattr(self, f"hotkey_{self.hotkey}")()
|
||||
|
||||
def invoke(self, context, event):
|
||||
# https://blender.stackexchange.com/questions/276035/how-do-i-make-operators-remember-their-property-values-when-called-from-a-hotkey
|
||||
# self.props = context.scene.BIMSpatialProperties
|
||||
return self.execute(context)
|
||||
|
||||
def draw(self, context):
|
||||
pass
|
||||
|
||||
def hotkey_S_A(self):
|
||||
active_obj = bpy.context.active_object
|
||||
element = tool.Ifc.get_entity(active_obj)
|
||||
collection = bpy.context.view_layer.active_layer_collection.collection
|
||||
collection_obj = collection.BIMCollectionProperties.obj
|
||||
|
||||
if AuthoringData.data["predefined_type"] == "FLOORING":
|
||||
if element and bpy.context.selected_objects and element.is_a("IfcWall"):
|
||||
bpy.ops.bim.add_instance_flooring_coverings_from_walls()
|
||||
elif tool.Ifc.get_entity(collection_obj):
|
||||
bpy.ops.bim.add_instance_flooring_covering_from_cursor()
|
||||
else:
|
||||
bpy.ops.bim.add_constr_type_instance()
|
||||
elif AuthoringData.data["predefined_type"] == "CEILING":
|
||||
if element and bpy.context.selected_objects and element.is_a("IfcWall"):
|
||||
bpy.ops.bim.add_instance_ceiling_coverings_from_walls()
|
||||
elif tool.Ifc.get_entity(collection_obj):
|
||||
bpy.ops.bim.add_instance_ceiling_covering_from_cursor()
|
||||
else:
|
||||
bpy.ops.bim.add_constr_type_instance()
|
||||
else:
|
||||
bpy.ops.bim.add_constr_type_instance()
|
||||
|
||||
def hotkey_S_G(self):
|
||||
active_obj = bpy.context.active_object
|
||||
element = tool.Ifc.get_entity(active_obj)
|
||||
if (element and
|
||||
bpy.context.selected_objects and
|
||||
element.is_a("IfcCovering") and
|
||||
AuthoringData.data["active_material_usage"] == "LAYER3"):
|
||||
bpy.ops.bim.regen_selected_covering_object()
|
||||
|
||||
@@ -21,14 +21,15 @@ from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.AddCsvAttribute,
|
||||
operator.RemoveCsvAttribute,
|
||||
operator.RemoveAllCsvAttributes,
|
||||
operator.ExportIfcCsv,
|
||||
operator.ImportIfcCsv,
|
||||
operator.EyedropIfcCsv,
|
||||
operator.SelectCsvIfcFile,
|
||||
operator.ImportCsvAttributes,
|
||||
operator.ExportCsvAttributes,
|
||||
operator.ExportIfcCsv,
|
||||
operator.ImportCsvAttributes,
|
||||
operator.ImportIfcCsv,
|
||||
operator.RemoveAllCsvAttributes,
|
||||
operator.RemoveCsvAttribute,
|
||||
operator.ReorderCsvAttribute,
|
||||
operator.SelectCsvIfcFile,
|
||||
prop.CsvAttribute,
|
||||
prop.CsvProperties,
|
||||
ui.BIM_PT_ifccsv,
|
||||
)
|
||||
|
||||
@@ -16,16 +16,17 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import ifccsv
|
||||
import ifcopenshell
|
||||
import os
|
||||
import logging
|
||||
import bpy
|
||||
import json
|
||||
import webbrowser
|
||||
import ifccsv
|
||||
import logging
|
||||
import tempfile
|
||||
import ifcopenshell
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim.module.drawing.scheduler as scheduler
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.handler import purge_module_data
|
||||
from blenderbim.bim.handler import refresh_ui_data
|
||||
|
||||
|
||||
class AddCsvAttribute(bpy.types.Operator):
|
||||
@@ -61,28 +62,57 @@ class RemoveAllCsvAttributes(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class ReorderCsvAttribute(bpy.types.Operator):
|
||||
bl_idname = "bim.reorder_csv_attribute"
|
||||
bl_label = "Reorder CSV Attribute"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
old_index: bpy.props.IntProperty()
|
||||
new_index: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
old = context.scene.CsvProperties.csv_attributes[self.old_index]
|
||||
new = context.scene.CsvProperties.csv_attributes[self.new_index]
|
||||
props = ["name", "header", "sort", "group", "varies_value", "summary"]
|
||||
for prop in props:
|
||||
value = getattr(new, prop)
|
||||
setattr(new, prop, getattr(old, prop))
|
||||
setattr(old, prop, value)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class ImportCsvAttributes(bpy.types.Operator):
|
||||
bl_idname = "bim.import_csv_attributes"
|
||||
bl_label = "Import CSV Template"
|
||||
bl_label = "Load CSV Settings"
|
||||
bl_description = "Import a json template for CSV export"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filter_glob: bpy.props.StringProperty(default="*.json", options={"HIDDEN"})
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def execute(self, context):
|
||||
csv_props = context.scene.CsvProperties
|
||||
csv_json = json.load(open(self.filepath))
|
||||
props = context.scene.CsvProperties
|
||||
data = json.load(open(self.filepath))
|
||||
tool.Search.import_filter_query(data["query"], props.filter_groups)
|
||||
|
||||
expression = csv_json.get("expression", "")
|
||||
if expression:
|
||||
csv_props.ifc_selector = expression
|
||||
|
||||
attributes = csv_json.get("attributes", [])
|
||||
if attributes:
|
||||
csv_props.csv_attributes.clear()
|
||||
for attribute in attributes:
|
||||
csv_props.csv_attributes.add().name = attribute
|
||||
for prop in [
|
||||
"should_generate_svg",
|
||||
"should_preserve_existing",
|
||||
"include_global_id",
|
||||
"null_value",
|
||||
"empty_value",
|
||||
"true_value",
|
||||
"false_value",
|
||||
"concat_value",
|
||||
"csv_delimiter",
|
||||
"format",
|
||||
"csv_custom_delimiter",
|
||||
]:
|
||||
setattr(props, prop, data["settings"][prop])
|
||||
|
||||
props.csv_attributes.clear()
|
||||
for attribute in data["attributes"]:
|
||||
new = props.csv_attributes.add()
|
||||
for prop in ["name", "header", "sort", "group", "summary", "formatting"]:
|
||||
setattr(new, prop, attribute[prop])
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
@@ -92,7 +122,7 @@ class ImportCsvAttributes(bpy.types.Operator):
|
||||
|
||||
class ExportCsvAttributes(bpy.types.Operator):
|
||||
bl_idname = "bim.export_csv_attributes"
|
||||
bl_label = "Export CSV Template"
|
||||
bl_label = "Save CSV Settings"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Save a json template for CSV export"
|
||||
filename_ext = ".json"
|
||||
@@ -100,22 +130,42 @@ class ExportCsvAttributes(bpy.types.Operator):
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def execute(self, context):
|
||||
csv_props = context.scene.CsvProperties
|
||||
props = context.scene.CsvProperties
|
||||
|
||||
csv_template = {}
|
||||
expression = csv_props.ifc_selector
|
||||
if expression:
|
||||
csv_template["expression"] = expression
|
||||
settings = {}
|
||||
for prop in [
|
||||
"should_generate_svg",
|
||||
"should_preserve_existing",
|
||||
"include_global_id",
|
||||
"null_value",
|
||||
"empty_value",
|
||||
"true_value",
|
||||
"false_value",
|
||||
"concat_value",
|
||||
"csv_delimiter",
|
||||
"format",
|
||||
"csv_custom_delimiter",
|
||||
]:
|
||||
settings[prop] = getattr(props, prop)
|
||||
|
||||
csv_attributes = []
|
||||
for attribute in csv_props.csv_attributes:
|
||||
attribute_name = attribute.name
|
||||
csv_attributes.append(attribute_name)
|
||||
if csv_attributes:
|
||||
csv_template["attributes"] = csv_attributes
|
||||
data = {
|
||||
"query": tool.Search.export_filter_query(props.filter_groups),
|
||||
"attributes": [
|
||||
{
|
||||
"name": a.name,
|
||||
"header": a.header,
|
||||
"sort": a.sort,
|
||||
"group": a.group,
|
||||
"summary": a.summary,
|
||||
"formatting": a.formatting,
|
||||
}
|
||||
for a in props.csv_attributes
|
||||
],
|
||||
"settings": settings,
|
||||
}
|
||||
|
||||
with open(self.filepath, "w") as outfile:
|
||||
json.dump(csv_template, outfile)
|
||||
json.dump(data, outfile)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -129,9 +179,8 @@ class ExportCsvAttributes(bpy.types.Operator):
|
||||
class ExportIfcCsv(bpy.types.Operator):
|
||||
bl_idname = "bim.export_ifccsv"
|
||||
bl_label = "Export IFC"
|
||||
#filename_ext = ".csv"
|
||||
filename_ext = ".csv"
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
|
||||
def invoke(self, context, event):
|
||||
props = context.scene.CsvProperties
|
||||
@@ -149,19 +198,61 @@ class ExportIfcCsv(bpy.types.Operator):
|
||||
ifc_file = IfcStore.get_file()
|
||||
else:
|
||||
ifc_file = ifcopenshell.open(props.csv_ifc_file)
|
||||
selector = ifcopenshell.util.selector.Selector()
|
||||
results = selector.parse(ifc_file, props.ifc_selector)
|
||||
results = ifcopenshell.util.selector.filter_elements(
|
||||
ifc_file, tool.Search.export_filter_query(props.filter_groups)
|
||||
)
|
||||
|
||||
ifc_csv = ifccsv.IfcCsv()
|
||||
attributes = [a.name for a in props.csv_attributes]
|
||||
headers = [a.header for a in props.csv_attributes]
|
||||
|
||||
sort = []
|
||||
groups = []
|
||||
summaries = []
|
||||
formatting = []
|
||||
for attribute in props.csv_attributes:
|
||||
if attribute.sort != "NONE":
|
||||
sort.append({"name": attribute.name, "order": attribute.sort})
|
||||
if attribute.group != "NONE":
|
||||
groups.append({"name": attribute.name, "type": attribute.group, "varies_value": attribute.varies_value})
|
||||
if attribute.summary != "NONE":
|
||||
summaries.append({"name": attribute.name, "type": attribute.summary})
|
||||
|
||||
if attribute.formatting != "{{value}}" and "{{value}}" in attribute.formatting:
|
||||
formatting.append({"name": attribute.name, "format": attribute.formatting})
|
||||
|
||||
sep = props.csv_custom_delimiter if props.csv_delimiter == "CUSTOM" else props.csv_delimiter
|
||||
ifc_csv.export(ifc_file, results, attributes, output=self.filepath, format=props.format, delimiter=sep)
|
||||
ifc_csv.export(
|
||||
ifc_file,
|
||||
results,
|
||||
attributes,
|
||||
headers=headers,
|
||||
output=self.filepath,
|
||||
format=props.format,
|
||||
should_preserve_existing=props.should_preserve_existing,
|
||||
delimiter=sep,
|
||||
include_global_id=props.include_global_id,
|
||||
null=props.null_value,
|
||||
empty=props.empty_value,
|
||||
bool_true=props.true_value,
|
||||
bool_false=props.false_value,
|
||||
concat=props.concat_value,
|
||||
sort=sort,
|
||||
groups=groups,
|
||||
summaries=summaries,
|
||||
formatting=formatting,
|
||||
)
|
||||
|
||||
if props.format != "csv" and props.should_generate_svg:
|
||||
schedule_creator = scheduler.Scheduler()
|
||||
schedule_creator.schedule(self.filepath, tool.Drawing.get_path_with_ext(self.filepath, "svg"))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class ImportIfcCsv(bpy.types.Operator):
|
||||
bl_idname = "bim.import_ifccsv"
|
||||
bl_label = "Import CSV to IFC"
|
||||
filename_ext = ".csv"
|
||||
bl_label = "Import to IFC"
|
||||
filter_glob: bpy.props.StringProperty(default="*.csv;*.ods;*.xlsx", options={"HIDDEN"})
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def invoke(self, context, event):
|
||||
@@ -180,25 +271,20 @@ class ImportIfcCsv(bpy.types.Operator):
|
||||
ifc_file = ifcopenshell.open(props.csv_ifc_file)
|
||||
ifc_csv = ifccsv.IfcCsv()
|
||||
sep = props.csv_custom_delimiter if props.csv_delimiter == "CUSTOM" else props.csv_delimiter
|
||||
ifc_csv.Import(ifc_file, self.filepath, delimiter=sep)
|
||||
attributes = [a.name for a in props.csv_attributes]
|
||||
ifc_csv.Import(
|
||||
ifc_file,
|
||||
self.filepath,
|
||||
attributes=attributes,
|
||||
delimiter=sep,
|
||||
null=props.null_value,
|
||||
empty=props.empty_value,
|
||||
bool_true=props.true_value,
|
||||
bool_false=props.false_value,
|
||||
)
|
||||
if not props.should_load_from_memory:
|
||||
ifc_file.write(props.csv_ifc_file)
|
||||
purge_module_data()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EyedropIfcCsv(bpy.types.Operator):
|
||||
bl_idname = "bim.eyedrop_ifccsv"
|
||||
bl_label = "Query Selected Items"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
global_ids = []
|
||||
self.file = IfcStore.get_file()
|
||||
for obj in context.selected_objects:
|
||||
if hasattr(obj, "BIMObjectProperties") and obj.BIMObjectProperties.ifc_definition_id:
|
||||
global_ids.append("#" + self.file.by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId)
|
||||
context.scene.CsvProperties.ifc_selector = "|".join(global_ids)
|
||||
refresh_ui_data()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
from blenderbim.bim.prop import StrProperty
|
||||
from blenderbim.bim.prop import StrProperty, BIMFilterGroup
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
@@ -31,10 +31,48 @@ from bpy.props import (
|
||||
)
|
||||
|
||||
|
||||
class CsvAttribute(PropertyGroup):
|
||||
name: StringProperty(name="Query", default="class")
|
||||
header: StringProperty(name="Header Value", default="IFC Class")
|
||||
sort: EnumProperty(items=[("NONE", "None", ""), ("ASC", "Ascending", ""), ("DESC", "Descending", "")])
|
||||
group: EnumProperty(
|
||||
items=[
|
||||
("NONE", "None", "Don't group any rows"),
|
||||
("GROUP", "Group", "All rows where this value is identical will be merged"),
|
||||
("CONCAT", "Concatenation", "Concatenate values if values vary within a group"),
|
||||
("VARIES", "Varies", "Show a custom value if values vary within a group"),
|
||||
("SUM", "Sum", "Sums the total value of rows in a group"),
|
||||
("AVERAGE", "Average", "Averages the total value of rows in a group"),
|
||||
("MIN", "Min", "Gets the minimum value of rows in a group"),
|
||||
("MAX", "Max", "Gets the maximum value of rows in a group"),
|
||||
]
|
||||
)
|
||||
varies_value: StringProperty(default="Varies", name="Varies Value")
|
||||
summary: EnumProperty(
|
||||
items=[
|
||||
("NONE", "None", "Don't provide a summary row"),
|
||||
("SUM", "Sum", "Sums the total value of all rows"),
|
||||
("AVERAGE", "Average", "Averages the total value of all rows"),
|
||||
("MIN", "Min", "Gets the minimum value of all rows"),
|
||||
("MAX", "Max", "Gets the maximum value of all rows"),
|
||||
]
|
||||
)
|
||||
formatting: StringProperty(default="{{value}}", name="Formatting")
|
||||
|
||||
|
||||
class CsvProperties(PropertyGroup):
|
||||
csv_ifc_file: StringProperty(default="", name="IFC File")
|
||||
ifc_selector: StringProperty(default="", name="IFC Selector")
|
||||
csv_attributes: CollectionProperty(name="CSV Attributes", type=StrProperty)
|
||||
filter_groups: CollectionProperty(type=BIMFilterGroup, name="Filter Groups")
|
||||
csv_attributes: CollectionProperty(name="CSV Attributes", type=CsvAttribute)
|
||||
should_generate_svg: BoolProperty(default=False, name="Generate SVG")
|
||||
should_preserve_existing: BoolProperty(default=False, name="Preserve Existing")
|
||||
include_global_id: BoolProperty(default=True, name="Include GlobalId")
|
||||
null_value: StringProperty(default="N/A", name="Null Value")
|
||||
empty_value: StringProperty(default="-", name="Empty String Value")
|
||||
true_value: StringProperty(default="YES", name="True Value")
|
||||
false_value: StringProperty(default="NO", name="False Value")
|
||||
concat_value: StringProperty(default=", ", name="Concat Value")
|
||||
csv_delimiter: EnumProperty(
|
||||
items=[
|
||||
(";", ";", ""),
|
||||
@@ -55,4 +93,9 @@ class CsvProperties(PropertyGroup):
|
||||
default="csv",
|
||||
)
|
||||
csv_custom_delimiter: StringProperty(default="", name="Custom Delimiter")
|
||||
should_show_settings: BoolProperty(default=False, name="Show Settings")
|
||||
should_show_sort: BoolProperty(default=False, name="Show Sorting")
|
||||
should_show_group: BoolProperty(default=False, name="Show Grouping")
|
||||
should_show_summary: BoolProperty(default=False, name="Show Summary")
|
||||
should_show_formatting: BoolProperty(default=False, name="Show Formatting")
|
||||
should_load_from_memory: BoolProperty(default=False, name="Load from Memory")
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import blenderbim.bim.helper
|
||||
from bpy.types import Panel
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.search.data import SearchData
|
||||
|
||||
|
||||
class BIM_PT_ifccsv(Panel):
|
||||
bl_label = "CSV Import/Export"
|
||||
bl_label = "Spreadsheet Import/Export"
|
||||
bl_idname = "BIM_PT_ifccsv"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
@@ -36,45 +38,88 @@ class BIM_PT_ifccsv(Panel):
|
||||
props = scene.CsvProperties
|
||||
|
||||
if IfcStore.get_file():
|
||||
row = layout.row()
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, "should_load_from_memory")
|
||||
row.operator("bim.import_csv_attributes", icon="IMPORT", text="")
|
||||
row.operator("bim.export_csv_attributes", icon="EXPORT", text="")
|
||||
else:
|
||||
row = layout.row(align=True)
|
||||
row.alignment = "RIGHT"
|
||||
row.operator("bim.import_csv_attributes", icon="IMPORT", text="")
|
||||
row.operator("bim.export_csv_attributes", icon="EXPORT", text="")
|
||||
row.prop(props, "should_show_settings", icon="PREFERENCES", text="")
|
||||
|
||||
if not IfcStore.get_file() or not props.should_load_from_memory:
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, "csv_ifc_file")
|
||||
row.operator("bim.select_csv_ifc_file", icon="FILE_FOLDER", text="")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, "ifc_selector")
|
||||
row.operator("bim.eyedrop_ifccsv", icon="EYEDROPPER", text="")
|
||||
layout.separator()
|
||||
if props.should_show_settings:
|
||||
layout.use_property_split = True
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, "format")
|
||||
|
||||
if props.format == "csv":
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, "csv_delimiter")
|
||||
|
||||
if props.csv_delimiter == "CUSTOM":
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, "csv_custom_delimiter")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(props, "should_generate_svg")
|
||||
row = layout.row()
|
||||
row.prop(props, "should_preserve_existing")
|
||||
row = layout.row()
|
||||
row.prop(props, "include_global_id")
|
||||
row = layout.row()
|
||||
row.prop(props, "null_value")
|
||||
row = layout.row()
|
||||
row.prop(props, "empty_value")
|
||||
row = layout.row()
|
||||
row.prop(props, "true_value")
|
||||
row = layout.row()
|
||||
row.prop(props, "false_value")
|
||||
row = layout.row()
|
||||
row.prop(props, "concat_value")
|
||||
layout.use_property_split = False
|
||||
|
||||
blenderbim.bim.helper.draw_filter(self.layout, props.filter_groups, SearchData, "csv")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.operator("bim.add_csv_attribute", icon="ADD")
|
||||
row.operator("bim.remove_all_csv_attributes", icon="CANCEL")
|
||||
row = layout.row(align=True)
|
||||
row.operator("bim.import_csv_attributes", icon="IMPORT")
|
||||
row.operator("bim.export_csv_attributes", icon="EXPORT")
|
||||
row.prop(props, "should_show_sort", icon="SORTSIZE", text="")
|
||||
row.prop(props, "should_show_group", icon="OUTLINER_COLLECTION", text="")
|
||||
row.prop(props, "should_show_summary", icon="SYNTAX_ON", text="")
|
||||
row.prop(props, "should_show_formatting", icon="CON_TRANSLIKE", text="")
|
||||
|
||||
total = len(props.csv_attributes)
|
||||
for index, attribute in enumerate(props.csv_attributes):
|
||||
row = layout.row(align=True)
|
||||
row.prop(attribute, "name", text="")
|
||||
row.prop(attribute, "header", text="")
|
||||
if props.should_show_sort:
|
||||
row.prop(attribute, "sort", text="")
|
||||
if props.should_show_group:
|
||||
row.prop(attribute, "group", text="")
|
||||
if attribute.group == "VARIES":
|
||||
row.prop(attribute, "varies_value", text="")
|
||||
if props.should_show_summary:
|
||||
row.prop(attribute, "summary", text="")
|
||||
if props.should_show_formatting:
|
||||
row.prop(attribute, "formatting", text="")
|
||||
if total > 1:
|
||||
if index != 0:
|
||||
op = row.operator(f"bim.reorder_csv_attribute", icon="TRIA_UP", text="")
|
||||
op.old_index = index
|
||||
op.new_index = index - 1
|
||||
if index + 1 != total:
|
||||
op = row.operator(f"bim.reorder_csv_attribute", icon="TRIA_DOWN", text="")
|
||||
op.old_index = index
|
||||
op.new_index = index + 1
|
||||
row.operator("bim.remove_csv_attribute", icon="X", text="").index = index
|
||||
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, "format")
|
||||
|
||||
if props.format == 'csv':
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, "csv_delimiter")
|
||||
|
||||
if props.csv_delimiter == "CUSTOM":
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, "csv_custom_delimiter")
|
||||
|
||||
row = layout.row()
|
||||
split = row.split(factor=0.5)
|
||||
c = split.column()
|
||||
c.operator("bim.export_ifccsv", icon="EXPORT", text="Export IFC to " + props.format.upper())
|
||||
c = split.column()
|
||||
c.operator("bim.import_ifccsv", icon="IMPORT")
|
||||
row.operator("bim.export_ifccsv", icon="EXPORT", text="Export IFC to " + props.format.upper())
|
||||
row.operator("bim.import_ifccsv", icon="IMPORT")
|
||||
|
||||
@@ -20,18 +20,22 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.ConvertToBlender,
|
||||
operator.CopyDebugInformation,
|
||||
operator.CreateAllShapes,
|
||||
operator.CreateShapeFromStepId,
|
||||
operator.InspectFromObject,
|
||||
operator.InspectFromStepId,
|
||||
operator.OverrideDisplayType,
|
||||
operator.ParseExpress,
|
||||
operator.PipInstall,
|
||||
operator.PrintIfcFile,
|
||||
operator.PrintObjectPlacement,
|
||||
operator.PrintUnusedElementStats,
|
||||
operator.ProfileImportIFC,
|
||||
operator.PurgeHdf5Cache,
|
||||
operator.PurgeIfcLinks,
|
||||
operator.ConvertToBlender,
|
||||
operator.PurgeUnusedElementsByClass,
|
||||
operator.RewindInspector,
|
||||
operator.SelectExpressFile,
|
||||
operator.SelectHighPolygonMeshes,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import bpy
|
||||
import time
|
||||
import logging
|
||||
@@ -116,7 +117,7 @@ class PurgeIfcLinks(bpy.types.Operator):
|
||||
context.scene.BIMProperties.ifc_file = ""
|
||||
context.scene.BIMDebugProperties.attributes.clear()
|
||||
IfcStore.purge()
|
||||
blenderbim.bim.handler.purge_module_data()
|
||||
blenderbim.bim.handler.refresh_ui_data()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -136,7 +137,7 @@ class ConvertToBlender(bpy.types.Operator):
|
||||
m.BIMMaterialProperties.ifc_style_id = False
|
||||
bpy.context.scene.BIMProperties.ifc_file = ""
|
||||
IfcStore.purge()
|
||||
blenderbim.bim.handler.purge_module_data()
|
||||
blenderbim.bim.handler.refresh_ui_data()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -146,14 +147,33 @@ class ValidateIfcFile(bpy.types.Operator):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return IfcStore.get_file()
|
||||
return tool.Ifc.get()
|
||||
|
||||
def execute(self, context):
|
||||
import ifcopenshell.validate
|
||||
|
||||
class LogDetectionHandler(logging.Handler):
|
||||
message_logged = False
|
||||
|
||||
def emit(self, record):
|
||||
if not self.message_logged:
|
||||
self.message_logged = True
|
||||
|
||||
logger = logging.getLogger("validate")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
ifcopenshell.validate.validate(IfcStore.get_file(), logger, express_rules=True)
|
||||
|
||||
# use LogDetectionHandler to check whether there were any validation errors
|
||||
# during `ifcopenshell.validate.validate`
|
||||
handler = LogDetectionHandler()
|
||||
logger.addHandler(handler)
|
||||
ifcopenshell.validate.validate(tool.Ifc.get(), logger, express_rules=True)
|
||||
logger.removeHandler(handler)
|
||||
|
||||
if handler.message_logged:
|
||||
self.report({"INFO"}, "Check validation results in the system console.")
|
||||
else:
|
||||
self.report({"INFO"}, "No validation issues found.")
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -194,7 +214,7 @@ class CreateAllShapes(bpy.types.Operator):
|
||||
settings_2d.set(settings_2d.INCLUDE_CURVES, True)
|
||||
failures = []
|
||||
excludes = () # For the developer to debug with
|
||||
for i, element in enumerate(elements):
|
||||
for i, element in enumerate(elements, 1):
|
||||
if element.GlobalId in excludes:
|
||||
continue
|
||||
print(f"{i}/{total}:", element)
|
||||
@@ -216,7 +236,7 @@ class CreateAllShapes(bpy.types.Operator):
|
||||
len(shape.geometry.edges),
|
||||
len(shape.geometry.faces),
|
||||
)
|
||||
print(f"Failures: {len(failures)}")
|
||||
self.report({"INFO"}, f"Failed shapes: {len(failures)}, check the system console for details.")
|
||||
for failure in failures:
|
||||
print(failure)
|
||||
return {"FINISHED"}
|
||||
@@ -441,3 +461,202 @@ class PurgeHdf5Cache(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
core.purge_hdf5_cache(tool.Debug)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class OverrideDisplayType(bpy.types.Operator):
|
||||
bl_idname = "bim.override_display_type"
|
||||
bl_label = "Override Display Type"
|
||||
display: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
for obj in context.selected_objects:
|
||||
obj.display_type = self.display
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class PrintUnusedElementStats(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.print_unused_elements_stats"
|
||||
bl_label = "Print Unused Elements Stats"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = (
|
||||
"Print all unused elements in current IFC project in system console, not limited to the selected class"
|
||||
)
|
||||
|
||||
ignore_contexts: bpy.props.BoolProperty(name="Ignore Contexts", default=True)
|
||||
ignore_relationships: bpy.props.BoolProperty(name="Ignore Relationships", default=True)
|
||||
ignore_types: bpy.props.BoolProperty(name="Ignore Types", default=True)
|
||||
ignore_styled_items: bpy.props.BoolProperty(name="Ignoer Styled Items", default=True)
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMDebugProperties
|
||||
# ignore some classes that could have zero 0 inverse references by their nature
|
||||
ignore_classes = []
|
||||
if self.ignore_contexts:
|
||||
ignore_classes += ["IfcRepresentationContext"]
|
||||
if self.ignore_relationships:
|
||||
ignore_classes += ["IfcRelationship"]
|
||||
if self.ignore_types:
|
||||
ignore_classes += ["IfcTypeProduct"]
|
||||
if self.ignore_styled_items:
|
||||
ignore_classes += ["IfcStyledItem"]
|
||||
|
||||
unused_elements = tool.Debug.print_unused_elements_stats(props.ifc_class_purge, ignore_classes)
|
||||
self.report({"INFO"}, f"{unused_elements} unused elements found, check the system console for the details.")
|
||||
|
||||
|
||||
class PurgeUnusedElementsByClass(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.purge_unused_elements_by_class"
|
||||
bl_label = "Purge Unused Elements By Class"
|
||||
bl_description = (
|
||||
"Will find all elements of class that have no inverse refernces and will remove them, use very carefully"
|
||||
)
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"})
|
||||
|
||||
def invoke(self, context, event):
|
||||
context.window_manager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMDebugProperties
|
||||
if props.ifc_class_purge:
|
||||
purged_elements = core.purge_unused_elements(tool.Ifc, tool.Debug, props.ifc_class_purge)
|
||||
self.report({"INFO"}, f"{purged_elements} unused elements found and removed.")
|
||||
tool.Ifc.get().write(self.filepath)
|
||||
return
|
||||
|
||||
# A whitelisted class is a class that only contains simple data that
|
||||
# has no meaning by itself (only has meaning when combined with other
|
||||
# data). E.g. a colour by itself has no meaning so is whitelisted, but
|
||||
# a material by itself may be part of your materials library.
|
||||
|
||||
# There are classes I don't know enough about to decide. Not whitelisting in case.
|
||||
# IfcAlignmentParameterSegment
|
||||
# IfcBoundaryCondition
|
||||
# IfcStructuralConnectionCondition
|
||||
# IfcStructuralLoad
|
||||
|
||||
whitelisted_classes = [
|
||||
"IfcActorRole",
|
||||
"IfcAddress",
|
||||
"IfcApplication",
|
||||
"IfcAppliedValue",
|
||||
"IfcConnectionGeometry",
|
||||
"IfcCoordinateReferenceSystem",
|
||||
"IfcDerivedUnit",
|
||||
"IfcDerivedUnitElement",
|
||||
"IfcDimensionalExponents",
|
||||
"IfcExternalReference",
|
||||
"IfcGridAxis",
|
||||
"IfcIrregularTimeSeriesValue",
|
||||
"IfcLightDistributionData",
|
||||
"IfcLightIntensityDistribution",
|
||||
"IfcMeasureWithUnit",
|
||||
"IfcMonetaryUnit",
|
||||
"IfcNamedUnit",
|
||||
"IfcObjectPlacement",
|
||||
"IfcOrganization", # Should be referenced as part of an actor
|
||||
"IfcOwnerHistory",
|
||||
"IfcPerson", # Should be referenced as part of an actor
|
||||
"IfcPersonAndOrganization", # Should be referenced as part of an actor
|
||||
"IfcPhysicalQuantity",
|
||||
"IfcPresentationItem",
|
||||
"IfcProductDefinitionShape",
|
||||
"IfcPropertyAbstraction",
|
||||
"IfcRecurrencePattern",
|
||||
"IfcReference",
|
||||
"IfcRepresentation",
|
||||
"IfcRepresentationContext",
|
||||
"IfcRepresentationItem",
|
||||
"IfcRepresentationMap",
|
||||
"IfcPropertyDefinition", # A bit of a questionable one, and the odd one out from IfcRoot.
|
||||
"IfcSchedulingTime",
|
||||
"IfcShapeAspect",
|
||||
"IfcTable",
|
||||
"IfcTableColumn",
|
||||
"IfcTableRow",
|
||||
"IfcTextureCoordinateIndices",
|
||||
"IfcTimePeriod",
|
||||
"IfcTimeSeries",
|
||||
"IfcTimeSeriesValue",
|
||||
"IfcUnitAssignment",
|
||||
"IfcVirtualGridIntersection",
|
||||
]
|
||||
|
||||
total_purged = 0
|
||||
while True:
|
||||
total_batches = 0
|
||||
print("*" * 100)
|
||||
total_batch_purged = 0
|
||||
for ifc_class in whitelisted_classes:
|
||||
total_class_purged = 0
|
||||
try:
|
||||
elements = tool.Ifc.get().by_type(ifc_class)
|
||||
except:
|
||||
continue # Probably not in this schema?
|
||||
to_purge = set()
|
||||
for element in elements:
|
||||
try:
|
||||
if ifc_class == "IfcRepresentationItem" and element.is_a("IfcStyledItem") and element.Item:
|
||||
continue
|
||||
except:
|
||||
to_purge.add(element.id()) # It's invalid, definitely purge it.
|
||||
if tool.Ifc.get().get_total_inverses(element) == 0:
|
||||
to_purge.add(element.id())
|
||||
for element_id in to_purge:
|
||||
try:
|
||||
element = tool.Ifc.get().by_id(element_id)
|
||||
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), element)
|
||||
total_class_purged += 1
|
||||
except:
|
||||
continue
|
||||
if total_class_purged > 0:
|
||||
total_batch_purged += total_class_purged
|
||||
print(f"Auto purged {total_class_purged} {ifc_class}")
|
||||
if total_batch_purged > 0:
|
||||
total_purged += total_batch_purged
|
||||
print(f"Auto purged in batch: {total_batch_purged}")
|
||||
total_batches += 1
|
||||
if total_batch_purged == 0:
|
||||
break
|
||||
elif total_batches > 20:
|
||||
print("Finished 20 batches. Manually stopping in case of infinite loop.")
|
||||
self.report({"INFO"}, f"Auto purged {total_purged} orphaned elements")
|
||||
tool.Ifc.get().write(self.filepath)
|
||||
|
||||
|
||||
class PipInstall(bpy.types.Operator):
|
||||
bl_idname = "bim.pip_install"
|
||||
bl_label = "Pip Install"
|
||||
bl_description = "Installs a package from PyPI"
|
||||
name: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
import blenderbim.bim
|
||||
|
||||
target = [p for p in sys.path if p.endswith("packages") and "addons" in p][0]
|
||||
py_exec = str(sys.executable)
|
||||
|
||||
print("Detected executable:", py_exec)
|
||||
print("Installing to:", target)
|
||||
|
||||
subprocess.call([py_exec, "-m", "ensurepip", "--user"])
|
||||
subprocess.call([py_exec, "-m", "pip", "install", "--upgrade", "pip"])
|
||||
# Trusted host to make things simpler due to some enterprise network restrictions
|
||||
subprocess.call(
|
||||
[
|
||||
py_exec,
|
||||
"-m",
|
||||
"pip",
|
||||
"install",
|
||||
f"--target={target}",
|
||||
"--upgrade",
|
||||
self.name,
|
||||
"--trusted-host",
|
||||
"pypi.org",
|
||||
"--trusted-host",
|
||||
"files.pythonhosted.org",
|
||||
]
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -40,3 +40,15 @@ class BIMDebugProperties(PropertyGroup):
|
||||
inverse_attributes: CollectionProperty(name="Inverse Attributes", type=Attribute)
|
||||
inverse_references: CollectionProperty(name="Inverse References", type=Attribute)
|
||||
express_file: StringProperty(name="Express File")
|
||||
display_type: EnumProperty(
|
||||
items=[
|
||||
("BOUNDS", "Bounds", ""),
|
||||
("WIRE", "Wire", ""),
|
||||
("SOLID", "Solid", ""),
|
||||
("TEXTURED", "Textured", ""),
|
||||
],
|
||||
name="Display Type",
|
||||
default="BOUNDS",
|
||||
)
|
||||
ifc_class_purge: StringProperty(name="Unused Elements IFC Class", default="")
|
||||
package_name: StringProperty(name="Package Name", default="")
|
||||
|
||||
@@ -37,7 +37,6 @@ class BIM_PT_debug(Panel):
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(context.scene.BIMProperties, "ifc_file", text="")
|
||||
row.operator("bim.validate_ifc_file", icon="CHECKMARK", text="")
|
||||
row.operator("bim.reload_selected_ifc_file", icon="FILE_REFRESH", text="")
|
||||
row.operator("bim.select_ifc_file", icon="FILE_FOLDER", text="")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
@@ -45,6 +44,13 @@ class BIM_PT_debug(Panel):
|
||||
row.operator("bim.parse_express", icon="IMPORT", text="")
|
||||
row.operator("bim.select_express_file", icon="FILE_FOLDER", text="")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "package_name", text="")
|
||||
row.operator("bim.pip_install", icon="EVENT_PAGEDOWN").name = props.package_name
|
||||
|
||||
row = layout.row()
|
||||
row.operator("bim.reload_ifc_file", text="Incrementally Reload Changes")
|
||||
|
||||
row = layout.row()
|
||||
row.operator("bim.print_ifc_file")
|
||||
|
||||
@@ -83,6 +89,17 @@ class BIM_PT_debug(Panel):
|
||||
).percentile = context.scene.BIMDebugProperties.percentile_of_polygons
|
||||
row.prop(props, "percentile_of_polygons", text="")
|
||||
|
||||
row = layout.split(factor=0.5, align=True)
|
||||
row.prop(props, "display_type", text="")
|
||||
row.operator("bim.override_display_type").display = context.scene.BIMDebugProperties.display_type
|
||||
|
||||
layout.operator("bim.purge_unused_representations")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(context.scene.BIMDebugProperties, "ifc_class_purge", text="")
|
||||
row.operator("bim.purge_unused_elements_by_class", text="Purge Orphaned", icon="TRASH")
|
||||
row.operator("bim.print_unused_elements_stats", text="", icon="INFO")
|
||||
|
||||
if context.active_object and context.active_object.data:
|
||||
mprops = context.active_object.data.BIMMeshProperties
|
||||
row = layout.row()
|
||||
|
||||