Compare commits
1174 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b8d36a63a2 | |||
| 51e13c06ba | |||
| 4868edaa83 | |||
| 98cc0b93ce | |||
| d01b894734 | |||
| ef8c82e1c9 | |||
| 04d64de6d0 | |||
| a29d691944 | |||
| 1abca2681e | |||
| a37d36e0c7 | |||
| 1d1e051e0f | |||
| f83d13b97c | |||
| 090aae5ff6 | |||
| 500c7cdc37 | |||
| 8fb218c335 | |||
| 94c009d179 | |||
| 132ec473ec | |||
| 8cde074fd8 | |||
| 92e519de9e | |||
| 70ba681b35 | |||
| e2b5ecf0a1 | |||
| 5efa65195f | |||
| 20e731235c | |||
| 90e481ce2c | |||
| 2dac81ee8d | |||
| 721fe4729a | |||
| 3eb7c7a6a1 | |||
| 2b82eaf019 | |||
| 02a68f6827 | |||
| 2b4d4439ea | |||
| e7a8780828 | |||
| 2dc6a3bcc6 | |||
| 5cee2fb08a | |||
| 8aa790c1c1 | |||
| 2a07f7082a | |||
| 92adeca837 | |||
| 0453db7745 | |||
| 5f29379a6d | |||
| a9f76fc8c0 | |||
| 48cb598975 | |||
| d350a17ce5 | |||
| 9b94c3ceca | |||
| 865c0f4895 | |||
| 95903c965d | |||
| 5b711a23d3 | |||
| 99b776b10e | |||
| ce92aa6e00 | |||
| 33bc0be5ff | |||
| 3004d5424c | |||
| d6aec719e5 | |||
| 55a220751b | |||
| f31ab80731 | |||
| d0eb716738 | |||
| b9084ad0f5 | |||
| 2580cd5e37 | |||
| 177d46b7b6 | |||
| d026fcc900 | |||
| f898893607 | |||
| 6cc842a2ac | |||
| cfc1ddee5e | |||
| 89535e0b6a | |||
| b71684955d | |||
| 81b0442abe | |||
| 88f0938bd2 | |||
| cdd5094d38 | |||
| a1b462a83b | |||
| 41db0f4705 | |||
| 06d3ed7d2a | |||
| 5485177888 | |||
| 8792c6db63 | |||
| 5990d6b66d | |||
| b1b3d7e312 | |||
| 770f35fd97 | |||
| 829ff5e152 | |||
| 4accf30626 | |||
| 0ed38a4128 | |||
| 0a2afa4879 | |||
| 9d4f0730e2 | |||
| 6b33b23a29 | |||
| 6addbd935f | |||
| 5782691cdb | |||
| bcda3d8e93 | |||
| c131b81565 | |||
| 99d7eaaf70 | |||
| c726e8feb9 | |||
| faaeef92de | |||
| 126bac462d | |||
| a4b4c7b37c | |||
| 75a8e4af02 | |||
| 8d5970f002 | |||
| dd0a3d0421 | |||
| b272210a97 | |||
| b99c5036e6 | |||
| 16b34f942a | |||
| 104e9c9ca7 | |||
| 5e1fbacef7 | |||
| c96d1e6387 | |||
| d4ace423a3 | |||
| 9c81418492 | |||
| a60c5367ee | |||
| cb0c124745 | |||
| 6aea3361c1 | |||
| 1ae7bd3a9a | |||
| 00f779fc49 | |||
| 2cfa1d8bc0 | |||
| 6e3484fd46 | |||
| 0a03632e95 | |||
| 178611faa8 | |||
| 8c97b53bd2 | |||
| ae42d91c5c | |||
| 8fa1a99864 | |||
| a430d356c0 | |||
| 112ce48350 | |||
| 486eb4d9a0 | |||
| cb4001b47b | |||
| 1187ad5fea | |||
| a2a04cb341 | |||
| 28864cefb1 | |||
| e9ad1019a4 | |||
| 9513a9ebef | |||
| d27d0acbc0 | |||
| 869d067c94 | |||
| 268241bf5d | |||
| 67c055579c | |||
| 4d7ff493a8 | |||
| afb3d998c8 | |||
| 0d2d5ff16b | |||
| 3c235208de | |||
| 52f4b564b3 | |||
| 6db1a8a85f | |||
| 8178dd330d | |||
| 616f284126 | |||
| 5e6343885c | |||
| fd603f7035 | |||
| 3b36029b1d | |||
| 447c07460a | |||
| 5c62cb244a | |||
| 7fa79a2cec | |||
| 6c6d4c047c | |||
| a0def600e8 | |||
| a37338a6d3 | |||
| 11e36bf744 | |||
| 511e1c8a95 | |||
| 1c9cd058c8 | |||
| b5ff3cd818 | |||
| f904648783 | |||
| 0f38cd712e | |||
| 9b9326721d | |||
| 29cda05025 | |||
| d1a39d8004 | |||
| e0bfa8f55a | |||
| 95f2d939e8 | |||
| a14c3b181d | |||
| 17e61afd59 | |||
| bf6c3e40d3 | |||
| ef557e96a7 | |||
| 59f156bae3 | |||
| 6eaa13b5f1 | |||
| 92f55504e9 | |||
| cb2995a255 | |||
| bbd7264a9b | |||
| a6b8e40829 | |||
| 799fb688b5 | |||
| 2d730fbee7 | |||
| 4b7058e22e | |||
| fb1c340664 | |||
| 4614bde8d7 | |||
| 88669701b2 | |||
| f4fac9210d | |||
| 2c270a7315 | |||
| 912699e63c | |||
| 899a0c6fb5 | |||
| f2aec9440f | |||
| 2284f7b16e | |||
| 2dbf9665be | |||
| 06b43e7f80 | |||
| 1b4d0bf577 | |||
| ee0d594f9f | |||
| be08d0ad1b | |||
| 21c975540d | |||
| f040dbcb6c | |||
| 6b7b81765c | |||
| 6ee0027f33 | |||
| 897d7a6b2d | |||
| b4256c504f | |||
| 745411ee47 | |||
| 296bf0387d | |||
| d22c11c200 | |||
| d7a76bfa11 | |||
| a6c11b7e23 | |||
| f280aa3a13 | |||
| 1515ef98b7 | |||
| 184081ebaf | |||
| 91d1f69d58 | |||
| ca20d94d66 | |||
| 0cc6ca11b1 | |||
| c086104573 | |||
| b29ace296a | |||
| ac9e6cc661 | |||
| 4cb59009b4 | |||
| 0ce35466ff | |||
| 58921e200c | |||
| 3e2b66ef2f | |||
| 8300868a9b | |||
| 305465a898 | |||
| c2530b7a61 | |||
| 2f3c79a0e6 | |||
| 26f800331e | |||
| fd163a3d1e | |||
| 671f1ab9cf | |||
| 2a6d6cfdbf | |||
| 44c868caed | |||
| 83d2548978 | |||
| 199bc86a88 | |||
| 7a5b15e5a2 | |||
| 4b64e096a5 | |||
| b92e3fcf01 | |||
| acb446bfc2 | |||
| 5af0d65306 | |||
| f600186496 | |||
| e8e12a567e | |||
| e21b4479b2 | |||
| 858f48c49d | |||
| 62b8f10677 | |||
| f42b018943 | |||
| dff91e233b | |||
| 2f49658d66 | |||
| 0c27caf522 | |||
| a8fbdb4c92 | |||
| a0f7a70419 | |||
| cb95c93424 | |||
| ab38e6bf7c | |||
| 538029f396 | |||
| ebd84a662e | |||
| f393c5f1d2 | |||
| 1d42ce04eb | |||
| 023dd289fa | |||
| 869bb22830 | |||
| 4bf074f97a | |||
| 4c67137d47 | |||
| 4bb888c862 | |||
| 9a748e640e | |||
| efec360a00 | |||
| d4fc135209 | |||
| 09098c1bdc | |||
| 6899f9fa8f | |||
| a83952cec2 | |||
| 21e064acaf | |||
| 83a8745959 | |||
| 42ae4f9a3c | |||
| 3cd47cdd0f | |||
| 92ca549b0b | |||
| 2213b4e212 | |||
| 7abccbd713 | |||
| b696d302f9 | |||
| 2c66fbf1c4 | |||
| 18a52fd5f8 | |||
| 2033ee1c69 | |||
| c1ae066e76 | |||
| 70f6857325 | |||
| 0d6cacdd73 | |||
| 0183cf3b31 | |||
| ab8fd0a6fe | |||
| 5a52f3aeea | |||
| 0087fa875b | |||
| a874a6b673 | |||
| 176e22af8b | |||
| bcf82984ce | |||
| cdd46066fa | |||
| 10011436d0 | |||
| 00be87ff07 | |||
| e22c68a842 | |||
| 07bf60819a | |||
| 62c5efe591 | |||
| 05ef6542ef | |||
| 326e7e591f | |||
| 4ccadc4f36 | |||
| 7d087d2919 | |||
| 3b5bc531cb | |||
| 47440edb8b | |||
| 0ee881fb32 | |||
| fee5d17f61 | |||
| 94f0612752 | |||
| b149f4f56d | |||
| 00bf08c220 | |||
| 3bb3a8018a | |||
| d71e89f823 | |||
| 562b520233 | |||
| 44f8255296 | |||
| 2c5442accc | |||
| 5cf07a910e | |||
| 4184cff1a0 | |||
| 67740a5f79 | |||
| ecfe8c3799 | |||
| 7403d14001 | |||
| 2b63698d7c | |||
| e0cd74d0ad | |||
| 4fe427558f | |||
| b59a9f5264 | |||
| f25fb0db51 | |||
| bfaa89cdec | |||
| 9625200a2a | |||
| 5562c9d2b5 | |||
| 7c0405fab0 | |||
| 557f8e6d69 | |||
| 2137b34063 | |||
| 86a44c21ac | |||
| a427462646 | |||
| b79d23b3e2 | |||
| 2af1ebc614 | |||
| d2e421382b | |||
| 7b22f9c85b | |||
| e06591bbbd | |||
| 110daf4ca7 | |||
| 6bf692b44d | |||
| c257afbd1c | |||
| cdf18e9f20 | |||
| c715f41972 | |||
| d1e51fb05b | |||
| 99f72a8451 | |||
| 2537349ec2 | |||
| 10b6253a36 | |||
| d88c4fd377 | |||
| 0596e2000c | |||
| b685610900 | |||
| 5cab72deaa | |||
| 52f15d27b1 | |||
| cfa0575263 | |||
| f5e089e0fd | |||
| 5d246a8716 | |||
| 1f241912f2 | |||
| f7765c531b | |||
| 3b401ec28f | |||
| 77206cb761 | |||
| f8e9f81b9b | |||
| 186c4dd118 | |||
| aa9b6b61fa | |||
| 6337d04efc | |||
| c00bcc78e9 | |||
| 07f19ad80a | |||
| 8ca6183313 | |||
| 492df6845b | |||
| 43f8d8547d | |||
| 6e3c72707d | |||
| 08d6c0a2d8 | |||
| 8c1eff5c26 | |||
| fe3ffb7771 | |||
| 6660714308 | |||
| 2420ad2fa7 | |||
| 16fd06a4e9 | |||
| beb5dda6dd | |||
| c04afe1a4b | |||
| d2a1e0193b | |||
| f2f4057c98 | |||
| 347aae9696 | |||
| 1a2d0d702b | |||
| e791449d3d | |||
| 8071e079b3 | |||
| 1c71af058f | |||
| c4f3633ab8 | |||
| c40fd91730 | |||
| a7252273b4 | |||
| 6e0a443cca | |||
| 4574887709 | |||
| f14d349be0 | |||
| 023eb719f5 | |||
| 8ba1b1c9b4 | |||
| 7cb163efef | |||
| e68c57e9ef | |||
| 7d17b3170c | |||
| a968f2b04d | |||
| 9a14406f92 | |||
| 32062e4085 | |||
| 8da17cf4a0 | |||
| 2d6e941c41 | |||
| 0fffbac519 | |||
| db62faa5ae | |||
| 02dc7b5274 | |||
| 1bf136e93c | |||
| cccab9e751 | |||
| 99e74533c3 | |||
| 0f39b09396 | |||
| ac2324a65f | |||
| ca85927a51 | |||
| e3786423c2 | |||
| 8d352ea07a | |||
| fd04066940 | |||
| d34956c2c7 | |||
| ad2585c571 | |||
| a08cf23d63 | |||
| 37fe04ffd2 | |||
| 248b21eab3 | |||
| 63f578315d | |||
| 19b6765994 | |||
| 7456c270ff | |||
| b480b43435 | |||
| 3614587556 | |||
| 86ce367ba8 | |||
| d320c1dac1 | |||
| cf48661a35 | |||
| 5e03846783 | |||
| acddbfd18c | |||
| 791f57072e | |||
| 078f7b3dae | |||
| c02f270993 | |||
| a73178fe3e | |||
| 24808ced60 | |||
| 1d523c9636 | |||
| 6ccb208345 | |||
| af0f0a4f6c | |||
| edd737aa5d | |||
| 5d8f71128e | |||
| 1ea4f50d30 | |||
| 93fad2a5c3 | |||
| 30a03b0c51 | |||
| b0bb2cb58d | |||
| 3837c9d6ff | |||
| d189113b98 | |||
| 6dba96e780 | |||
| c2bdfa9394 | |||
| 519a53dc61 | |||
| 21c4433c75 | |||
| 0e24d4411f | |||
| cb6837b0ac | |||
| 5ec7f65df5 | |||
| db04cc1bb5 | |||
| 1f128fd7e4 | |||
| 56633b8126 | |||
| 6706ad9bd5 | |||
| fb6c670aa6 | |||
| a87637163a | |||
| 4bc5a3ba46 | |||
| 866df1f040 | |||
| 2fa2fddf46 | |||
| 1aeae0bf4d | |||
| 6a2c4aee46 | |||
| 5cfbcf211b | |||
| 3dcd10b478 | |||
| c687e9af05 | |||
| b10c228155 | |||
| b1d731447a | |||
| 32e7083e21 | |||
| 597b5ffbd6 | |||
| f7e550b926 | |||
| 75d67cd719 | |||
| 41a47f14ae | |||
| cca28231ee | |||
| d7b3a1d95a | |||
| 30ba45f6cb | |||
| d832c9780a | |||
| 7f3b7f4e21 | |||
| dc7dea21ce | |||
| d6a9b73657 | |||
| 97cd919a7b | |||
| 41bc109556 | |||
| 4f5d4def1e | |||
| 3a24f03bed | |||
| f3ed96846e | |||
| cbe8165e08 | |||
| 6a7a122de2 | |||
| e44db61fbd | |||
| 72b60e85d4 | |||
| c48263ade9 | |||
| 5ec081c6bc | |||
| cc3f94097c | |||
| 253d478fdc | |||
| 549bc0e1a9 | |||
| 9286de4813 | |||
| b8015644e9 | |||
| 8a917dc050 | |||
| 68b6389794 | |||
| 85bd616f6e | |||
| 4ff60553cc | |||
| dcd6cace03 | |||
| b7cfa53b4d | |||
| e0048f7a3c | |||
| a8dcb2f306 | |||
| a8f0a4807c | |||
| d5539399e8 | |||
| ad8542f244 | |||
| eb89308019 | |||
| e7e7b22fd5 | |||
| b4a422c2b8 | |||
| 30f778e0a7 | |||
| 2032b361c8 | |||
| 529b3a9867 | |||
| cac8c64ac8 | |||
| 3847c9bd7a | |||
| ffbaa6f0e0 | |||
| b5c3812849 | |||
| 30ad915649 | |||
| c2cf3e8639 | |||
| c1527b4199 | |||
| a1032a3bf0 | |||
| 733b7c0e1e | |||
| 6b0a58db7d | |||
| 10bf875e92 | |||
| 2fd2b49709 | |||
| 37a61c549f | |||
| da10a1060e | |||
| ebfb29d6da | |||
| 6e4e6a88a4 | |||
| 312de694b6 | |||
| 788a5a829e | |||
| a4391df9ca | |||
| 1071ac00d4 | |||
| 6ecedaa128 | |||
| 8f154c753c | |||
| e863015e85 | |||
| 2c49b3bde8 | |||
| eaa527f512 | |||
| 99f0e6c93e | |||
| f27fbecc9a | |||
| 650ebeddd6 | |||
| 5d0d3aaa16 | |||
| 54526960c8 | |||
| e0b93a70d3 | |||
| e569b97c56 | |||
| a0b7fe2736 | |||
| 3b270a61df | |||
| 5b94043cdc | |||
| aadb28bb79 | |||
| 2f1f332d31 | |||
| 1ee2f420c8 | |||
| 567bc7b667 | |||
| 2a2f4d692a | |||
| 1b49a10a15 | |||
| a08918fd22 | |||
| 50608d9459 | |||
| 97d0286b57 | |||
| 2a7fbea9c3 | |||
| 257997c2cb | |||
| 2dfc35877c | |||
| 68233a8fb2 | |||
| 76e2f688e5 | |||
| 4d4bedcf9a | |||
| 36a18ea0f9 | |||
| fa1984e89e | |||
| 3be0a74316 | |||
| 90cb56220f | |||
| 8fd4965106 | |||
| ba26772e46 | |||
| 7e02eb923d | |||
| 459149e418 | |||
| 768606571e | |||
| 65fa5768f2 | |||
| 9db01bc6cc | |||
| 4e60ca01c3 | |||
| 8c9ab98697 | |||
| fc05bdf6d6 | |||
| 4c50b2d224 | |||
| 4017097f19 | |||
| b9472c9bae | |||
| 7d841c3f27 | |||
| ca0dac1353 | |||
| 1a962a7f60 | |||
| f3c1d1df31 | |||
| 6a0562d00a | |||
| 137a00225c | |||
| 5a822d5e39 | |||
| d844223367 | |||
| 6a29ab0d61 | |||
| e9c7b21bfc | |||
| ed316ba691 | |||
| cfd5742b5b | |||
| feac601340 | |||
| a8dc734351 | |||
| e0cbbf2eb7 | |||
| 082ee3c95d | |||
| ece6e6c8ca | |||
| 5c1d26ac91 | |||
| 153b6ee24d | |||
| 8b3b1eeb8e | |||
| 8e279ea862 | |||
| 6f8861c030 | |||
| 2ac6fe9eef | |||
| 8338cc72db | |||
| 67b636f5fb | |||
| 3a754c8ecc | |||
| d64d7cf27a | |||
| 6ff4c95ac7 | |||
| 0b6af5f848 | |||
| 3ded4dff5f | |||
| 452631b997 | |||
| c041dd13ad | |||
| 994ccb94f4 | |||
| c7ba643ef7 | |||
| 0b6f3113a7 | |||
| 730efcae49 | |||
| 62b297757e | |||
| 0533a00631 | |||
| 7fe2e93dea | |||
| acc9bd736f | |||
| 478612b6ae | |||
| a24d683613 | |||
| 0b5d7cdbf3 | |||
| b8e20ec1a5 | |||
| 1cd243f13c | |||
| 0a2adbb632 | |||
| 8882c99455 | |||
| 7890ded698 | |||
| 7d2d9b2bcf | |||
| 75ae501ff9 | |||
| 880fbe9533 | |||
| c2684f4fbf | |||
| afdc1e6679 | |||
| 8935a17844 | |||
| 93c59e81c6 | |||
| d423274e62 | |||
| 7958dd837b | |||
| e42a638220 | |||
| f5f314a58f | |||
| 96465bed8f | |||
| 41bdeea981 | |||
| 14e0910e59 | |||
| e0ba1c2183 | |||
| a13b71abf0 | |||
| 32fb359ee2 | |||
| 61661fe6f3 | |||
| 92054b1999 | |||
| 22d9bce591 | |||
| bfe9213f67 | |||
| 1abf854f01 | |||
| 686b2a187d | |||
| 7c2764c98a | |||
| f73a3a8f79 | |||
| b9723c08e4 | |||
| 1e80e67df5 | |||
| 3e8c10b775 | |||
| fd9f209a19 | |||
| 6b72f7322b | |||
| 9b0d9c1f91 | |||
| 26b699be7c | |||
| 294eba24c4 | |||
| 09094c090c | |||
| a0dad0802e | |||
| 97244d1919 | |||
| 1541cbbbb8 | |||
| 82692bb88d | |||
| 77a97233c5 | |||
| 4214a449a8 | |||
| b650c045f5 | |||
| 851ab07192 | |||
| 20a36c39fc | |||
| 38544e2ba9 | |||
| 41a88bcd4d | |||
| 966850c54a | |||
| 319fe13f9e | |||
| 0d5110b7af | |||
| de873461e1 | |||
| cbce3cbec0 | |||
| 0822d1d377 | |||
| e6bf32b832 | |||
| 30c31d694a | |||
| 65c2f9a038 | |||
| 2d42846fa3 | |||
| d3bb895c9d | |||
| aeead1c011 | |||
| ba742d5976 | |||
| 27750e0caf | |||
| 5b02d3214d | |||
| 0f55a98b2f | |||
| 13209b6d03 | |||
| 411855495e | |||
| 79ebbb82ef | |||
| 647a96a655 | |||
| 66d4665498 | |||
| 537efdcb53 | |||
| f2352e9a17 | |||
| e0b3a87fdb | |||
| ff06f452d5 | |||
| 5aec0718f4 | |||
| fdcafa98b3 | |||
| 1776b19c07 | |||
| e1d1dca518 | |||
| e8ab4dcc14 | |||
| 41443d1a64 | |||
| 13c642c6ab | |||
| c40f07f9b5 | |||
| ae7d123aa2 | |||
| 7c6e7996ff | |||
| 6ec23faf26 | |||
| 81ad689478 | |||
| b3c918f15f | |||
| de7ddd9b97 | |||
| 66862a6cba | |||
| 4e014d1a10 | |||
| 3b33977acc | |||
| 5334d2b754 | |||
| 75ed4dcdd8 | |||
| 0276c8271e | |||
| beb813cb21 | |||
| 35ceba2e88 | |||
| 64b8eee077 | |||
| 229ba95d4b | |||
| 3f9e5ca806 | |||
| cf68cf6f5c | |||
| 34386ea27c | |||
| ce76d27acc | |||
| 353281fa4d | |||
| dd6f593e26 | |||
| a9228c0800 | |||
| 5e52abb3cf | |||
| 8384235e10 | |||
| d98ac8ce89 | |||
| 1b4b2a526d | |||
| b1ed85adda | |||
| 02bfbf0144 | |||
| 3224c4fc77 | |||
| 19e67613db | |||
| e98771ae09 | |||
| 58663769c9 | |||
| 28081f7df8 | |||
| a80fbdbc1d | |||
| 46bc688f26 | |||
| f9b79b4beb | |||
| 15927dd501 | |||
| 7919c193b8 | |||
| 6492b93c69 | |||
| 992474fbf2 | |||
| 8a3e023408 | |||
| a13b257452 | |||
| 3f9842e358 | |||
| 764b880ea8 | |||
| a10f4c070a | |||
| 114214e2a1 | |||
| d19d4fca3e | |||
| a031bffe6c | |||
| 6ff792d75c | |||
| 6b3393c003 | |||
| da5a2625a9 | |||
| a1eb2a1ec3 | |||
| 403412e088 | |||
| ee46e76340 | |||
| 925c40c6ba | |||
| dea844dcf6 | |||
| 018d754b2e | |||
| a05d017341 | |||
| f63479c823 | |||
| 8a8bdeeaa3 | |||
| 6b46ff71a6 | |||
| d73a5c46ea | |||
| 037261afb9 | |||
| be87b17909 | |||
| 5419d72a6a | |||
| 9ca1e011e5 | |||
| 932a21309f | |||
| 3b806a5466 | |||
| 7a1b35f7e2 | |||
| 79dcf809ed | |||
| 2f53e43b90 | |||
| cdc9180111 | |||
| a65a34cfe7 | |||
| 2e0d5fa707 | |||
| de40049c9c | |||
| 29fa5bdffa | |||
| d55ad90319 | |||
| 90ece8a058 | |||
| a936a5317d | |||
| f5e5ede0fa | |||
| 2d1ddea3d0 | |||
| df932b90d6 | |||
| 2514e93a8d | |||
| 64e6561828 | |||
| 76685d236c | |||
| fd83564af0 | |||
| 37e3a65ffb | |||
| e5cf0cde2d | |||
| 78e4478242 | |||
| 3497022c78 | |||
| 810d36781c | |||
| f8eb1c178a | |||
| b726ba7816 | |||
| 4ab23d231d | |||
| 00694854af | |||
| fa52ed6dbc | |||
| 319b59a266 | |||
| 357fcded71 | |||
| c3cc5881df | |||
| ca34c95057 | |||
| 5078db8b26 | |||
| 56046dd6f9 | |||
| 9164a7bcc3 | |||
| e0a5c9c8f3 | |||
| 22e087c82a | |||
| 57396e1bb9 | |||
| 389076bff4 | |||
| bfcc067257 | |||
| f88ac5de62 | |||
| cdd456bede | |||
| 7041d17c16 | |||
| de842f7aba | |||
| 6107c39c1c | |||
| 9584687fcf | |||
| b231e9051b | |||
| 40f9875930 | |||
| 328773550d | |||
| 303544dc5c | |||
| 1c66f986cc | |||
| e801629f86 | |||
| 74bbd6d116 | |||
| e06794ef3d | |||
| cd7062c905 | |||
| 42d476cbb0 | |||
| cd0d3908d3 | |||
| cb70f97789 | |||
| 572ed0db0f | |||
| 43d78af767 | |||
| c7aa42bfd5 | |||
| 3104743a02 | |||
| 18d7193efc | |||
| 8da92557cc | |||
| 761b4c035f | |||
| ee0f7f1677 | |||
| dca2e58586 | |||
| 3810255f04 | |||
| d3ca647cd5 | |||
| 8b35a3aadd | |||
| 78314b1ec7 | |||
| ef88b30639 | |||
| 5e815e7832 | |||
| e7b153cbf6 | |||
| 9b855bed2d | |||
| 3143f8c9a5 | |||
| 8dd781aea2 | |||
| 0506475f26 | |||
| ac092fb6f8 | |||
| 9beddca2f7 | |||
| 6d9770542f | |||
| 544d6ee695 | |||
| b8963b3d6e | |||
| f2bd46d699 | |||
| 8ac8ad33b3 | |||
| 44bbd17d97 | |||
| 8f0e67a35b | |||
| d2d4112724 | |||
| 209eea6a18 | |||
| 85426b3fef | |||
| c602f0f233 | |||
| bb6312e174 | |||
| d6d70af5a0 | |||
| 8187c75183 | |||
| 01cfcebb09 | |||
| 75040b6ffb | |||
| 6c8858e51d | |||
| 6bb63817af | |||
| 1e299a0ddd | |||
| 3201c234fa | |||
| f5d27621e7 | |||
| 3e1eb9648f | |||
| 5f9474acb7 | |||
| f4e6e924b1 | |||
| bcfc97037c | |||
| 65d0abd072 | |||
| 776c68e2b0 | |||
| dab2d5ce04 | |||
| 29b33661d7 | |||
| 5dec636584 | |||
| d11b91f152 | |||
| b0fc98e384 | |||
| 56f09d2541 | |||
| 4484b77232 | |||
| f6c054066b | |||
| d5c70e51f2 | |||
| cab9e4d892 | |||
| 14cd8289ea | |||
| 4202c08487 | |||
| a70fb41652 | |||
| df437fd3e3 | |||
| 3102dbcd44 | |||
| 9d838db096 | |||
| 0c9d555693 | |||
| 4b637c7049 | |||
| fd3a873bbd | |||
| 5cea988911 | |||
| 70fcbfa990 | |||
| c541aa78e5 | |||
| b821e62391 | |||
| 41141b8fc9 | |||
| ae0789e4ec | |||
| 13d4a99358 | |||
| becb375ec2 | |||
| a777a558bd | |||
| de37aeb515 | |||
| 23be1a6939 | |||
| 8edced5a0c | |||
| 21937e88e8 | |||
| f7da83737a | |||
| 27663d80ba | |||
| 4ec5d4fc65 | |||
| 2b34ca9eb7 | |||
| 2bb9810072 | |||
| c7e87324de | |||
| ec62d8fbb9 | |||
| 7b5aae9487 | |||
| 12c94fafab | |||
| 09be170820 | |||
| 966af5a757 | |||
| 89557460c8 | |||
| 2bad6b2722 | |||
| e5cd30c6d0 | |||
| 6f2da2896e | |||
| 0387c778f4 | |||
| 76568ea67c | |||
| 8e2a1a1649 | |||
| cb5f57d68a | |||
| e7c6f28312 | |||
| 1820f72bc4 | |||
| 1631dc39f5 | |||
| d2f19e7c28 | |||
| 736703336c | |||
| 44df1f676d | |||
| f1ffb81c86 | |||
| 08ec3fc73f | |||
| f1d7cf1dfb | |||
| 1ee488b148 | |||
| ecb9827e7f | |||
| 88f26eaead | |||
| ce03742aab | |||
| 62540f0b00 | |||
| 406b8b4540 | |||
| ca24838a3f | |||
| ff7219b557 | |||
| 711acfe120 | |||
| f1acda85c9 | |||
| 228f62d218 | |||
| 6186a88568 | |||
| 074a8c287f | |||
| d4736710a5 | |||
| 0bc86631a5 | |||
| 9751b6af05 | |||
| 6d641aaac1 | |||
| 489a248e9a | |||
| 9c00872a57 | |||
| d77bc6bdaa | |||
| 911d703f57 | |||
| 09bf5b85aa | |||
| 41a694d0dc | |||
| 6232ee36f9 | |||
| 5b1cc2cab5 | |||
| f706adfb81 | |||
| b0358a5a7b | |||
| eb09cc8af8 | |||
| 7c61c7d200 | |||
| 92d28901ac | |||
| 32769184b0 | |||
| de7f1d9d46 | |||
| cbd0c8a410 | |||
| f4f40c4b16 | |||
| f9d70fd51d | |||
| bb43405299 | |||
| 00cb3cd0db | |||
| 823f988536 | |||
| d95977a784 | |||
| 4f9991fb13 | |||
| d8b2cc77cc | |||
| 077f9b701d | |||
| 36ade628cf | |||
| 0f59f3e35a | |||
| 31e7bad056 | |||
| eee693dfcb | |||
| 4a8e03862b | |||
| 04f7fc0bdb | |||
| fbe9bb1ee2 | |||
| ca59b3220b | |||
| 39c8c8db37 | |||
| f49de02ab7 | |||
| 8b0a7821b1 | |||
| 0f365cadbd | |||
| 0bc76b1af7 | |||
| efce28c053 | |||
| 071505038d | |||
| 98938acb26 | |||
| 4817360ecd | |||
| b8e3fbba8c | |||
| 49ea774851 | |||
| f4f2a3d24e | |||
| a25ca91ba6 | |||
| fded9b3523 | |||
| 9257f275af | |||
| 40039e65df | |||
| dbce9ec049 | |||
| b9c5c28c54 | |||
| 184a189f2a | |||
| 37f549927d | |||
| a5fe3e77e7 | |||
| 708da97bbd | |||
| f80792091f | |||
| a1e34b0acb | |||
| e618232e70 | |||
| 922fc2beda | |||
| 4564ee3476 | |||
| 510dca1aca | |||
| 5604db8072 | |||
| 5961253c29 | |||
| 624e296d24 | |||
| 6ad605fbeb | |||
| 797a5ec1a0 | |||
| d56869d341 | |||
| 405e8bc5aa | |||
| b607242339 | |||
| f57aa77ac2 | |||
| 01cc1887e0 | |||
| 003441a451 | |||
| 4b64f09aaa | |||
| 4afcca8550 | |||
| 1a7ea1ea05 | |||
| 5616a6ede5 | |||
| 28fa774a9a | |||
| 52d4fa4781 | |||
| 9258dc3104 | |||
| 469fb9c204 | |||
| f7175a67c8 | |||
| ebfaeafeee | |||
| 1f68c3f612 | |||
| aceb2140ad | |||
| 310d13ac75 | |||
| bc2ac6b31a | |||
| 059c405652 | |||
| 28d168b96c | |||
| e4640df6f0 | |||
| 5c3642e1d1 | |||
| 615f567ebf | |||
| a56ca661e8 | |||
| 8ee9835e27 | |||
| b26147c1c7 | |||
| c3847ff38a | |||
| 8299505672 | |||
| 0db743d3f7 | |||
| e7558d0008 | |||
| c9f40126c3 | |||
| b0554e71d5 | |||
| 1bed25408f | |||
| 603a034ac6 | |||
| 6f802ed770 | |||
| c1b9062fa4 | |||
| e4f591babf | |||
| e9c84d1c11 | |||
| e62b7e94a4 | |||
| e89d540236 | |||
| fa23f64e9f | |||
| cfaa90b1fb | |||
| dc909f1fc6 | |||
| 30fc2ad580 | |||
| c542fb2480 | |||
| 25717d002f | |||
| 0181bd7e56 | |||
| 71c6bba36d | |||
| eb539666d9 | |||
| e43eec6203 | |||
| 4ca64ac42e | |||
| f51e0db7fe | |||
| b1e8e0a968 | |||
| be66a98cfa | |||
| 76487ea3bf | |||
| 13fe011c75 | |||
| 266a341c6b | |||
| a5bcbe046f | |||
| ab057e3eff | |||
| 6aa0651190 | |||
| 0f296c486f | |||
| 29f64f7c11 | |||
| d2d4a1b976 | |||
| 249ff95920 | |||
| 4c8d12d978 | |||
| 04d02feb86 | |||
| e6700ea29b | |||
| 9c7c3d7078 | |||
| 0d3175c6ef | |||
| 04abadac22 | |||
| 0b39226869 | |||
| 9e31991e75 | |||
| b40bd681b1 | |||
| 63384a730b | |||
| b9f81b8014 | |||
| c34f357301 | |||
| beb58b89fe | |||
| 97df037c93 | |||
| a7d8bffca5 | |||
| b5f58dc113 | |||
| 4e889b75d7 | |||
| 36cfb0d3f5 | |||
| 5921bcb63d | |||
| 23ad1a8005 | |||
| f257aef8f4 | |||
| 3eacd809b0 | |||
| e1b90ed3b2 | |||
| 28c2d7248e | |||
| 3bee746f49 | |||
| eeb27bb1c7 | |||
| d50c89abee | |||
| 15cf3f5afd | |||
| 1e22dbca1e | |||
| 28fbf0ea99 | |||
| d874a0089d | |||
| 441d842f67 | |||
| 667ac307c3 | |||
| c81031819c | |||
| 7cbb87284c | |||
| d0a9edd186 | |||
| 425379aaad | |||
| 25d86a50c5 | |||
| 0286cd370d | |||
| 0178804feb | |||
| 1892e9cc86 | |||
| 1b46f5c83a | |||
| 3a0edab8c1 | |||
| 7032ee9f11 | |||
| fd19b2d730 | |||
| a65b9f2ba7 | |||
| 2db4a6f89f | |||
| 517b819504 | |||
| a0f79cc0db | |||
| 67666ed70e | |||
| 6bcfa5946f | |||
| 52691b7ee5 | |||
| 780ea707b0 | |||
| 7e7cfbdd5f | |||
| ab102176cc | |||
| d7f289bc8a | |||
| 95a34cb8d0 | |||
| 8369818b88 | |||
| 5251bdabc6 | |||
| 83c33dd5b0 | |||
| bfc695c756 | |||
| 459faec01a | |||
| 4fb65199b8 | |||
| 08576e28d6 | |||
| b3f581d78d | |||
| 89d6b3d21a | |||
| d2bf2cf46e | |||
| 43b2982dbb | |||
| e750a134d0 | |||
| 6bbbc528fe | |||
| 7f4a436708 | |||
| e6592ca706 | |||
| cc2138463e | |||
| 6de3e55d19 | |||
| 595131e6e8 | |||
| 6966da3bdf | |||
| 4e897a0c21 | |||
| 73a9015801 | |||
| 1b2bebecb0 | |||
| e4dee2258d | |||
| 7de3eec1b1 | |||
| 20fe48bd6a | |||
| 1d6b2dcb37 | |||
| 45f3e677df | |||
| 65160f9bb4 | |||
| 333ba08841 | |||
| 2cb3b0817f | |||
| 4ea95960a2 | |||
| 10f4bca5d2 | |||
| d4a01618cd | |||
| c9c6529978 | |||
| 2829a0764b | |||
| 76d61cb4d4 | |||
| e9d2a39166 | |||
| d08f4171e3 | |||
| 23483eafb3 | |||
| 686ba2536b | |||
| 7d5ac99f34 | |||
| 9b8d224aca | |||
| 8939d93333 | |||
| 04aad216ba | |||
| 27eb9d340a | |||
| fbb53f93d8 | |||
| af6aed80da | |||
| 92ba412c95 | |||
| 110c382973 | |||
| 977df60f05 | |||
| 539d77b5ad | |||
| ea34c3de85 | |||
| 9374594920 |
@@ -1,3 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [aothms]
|
||||
open_collective: opensourcebim
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
name: CD
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
|
||||
jobs:
|
||||
|
||||
activate:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.repository == 'IfcOpenShell/IfcOpenShell' &&
|
||||
!startsWith(github.event.head_commit.message, 'Release ') &&
|
||||
!contains(github.event.head_commit.message, 'ci skip')
|
||||
steps:
|
||||
- run: echo ok go
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
needs: activate
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install --no-install-recommends \
|
||||
git cmake gcc g++ libboost1.67-all-dev python3-all-dev swig libpcre3-dev libxml2-dev \
|
||||
liboce-foundation-dev liboce-modeling-dev liboce-ocaf-dev liboce-visualization-dev liboce-ocaf-lite-dev
|
||||
|
||||
-
|
||||
name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
|
||||
-
|
||||
name: Build ifcopenshell
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_INSTALL_PREFIX=$PWD/install/ \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH=/usr \
|
||||
-DCMAKE_SYSTEM_PREFIX_PATH=/usr \
|
||||
-DBUILD_PACKAGE=On \
|
||||
-DOCC_INCLUDE_DIR=/usr/include/oce \
|
||||
-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 \
|
||||
-DLIBXML2_INCLUDE_DIR=/usr/include/libxml2 \
|
||||
-DLIBXML2_LIBRARIES=/usr/lib/x86_64-linux-gnu/libxml2.so \
|
||||
../cmake
|
||||
make -j $(nproc)
|
||||
make install
|
||||
-
|
||||
name: Package
|
||||
run: |
|
||||
make package
|
||||
working-directory: build
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
# Artifact name
|
||||
name: ifcos-artifacts
|
||||
# Directory containing files to upload
|
||||
path: build/assets/Ifc*
|
||||
|
||||
deliver:
|
||||
runs-on: ubuntu-20.04
|
||||
needs: build
|
||||
name: Docker Build, Tag, Push
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
lfs: true
|
||||
|
||||
- name: Download
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
# Artifact name
|
||||
name: ifcos-artifacts
|
||||
path: artifacts/
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
-
|
||||
name: Login to Dockerhub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: aecgeeks
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
-
|
||||
name: Build container image
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: artifacts
|
||||
repository: aecgeeks/ifcopenshell
|
||||
tags: aecgeeks/ifcopenshell:latest
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
@@ -0,0 +1,38 @@
|
||||
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.x'
|
||||
- name: Build package
|
||||
run: |
|
||||
cd src/bcf
|
||||
pip install build
|
||||
python -m build
|
||||
- name: Publish package
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.PYPI_TOKEN }}
|
||||
packages_dir: src/bcf/dist
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
name: Publish-blenderbim-multiplatform
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'src/blenderbim/**'
|
||||
- '.github/workflows/ci-blenderbim-matrix.yml'
|
||||
|
||||
env:
|
||||
major: 0
|
||||
minor: 0
|
||||
name: blenderbim
|
||||
|
||||
jobs:
|
||||
activate:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.repository == 'IfcOpenShell/IfcOpenShell'
|
||||
steps:
|
||||
- name: Set env
|
||||
run: echo ok go
|
||||
|
||||
build:
|
||||
name: ${{ matrix.config.name }}-${{ matrix.pyver }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pyver: [py37, py39]
|
||||
config:
|
||||
- {
|
||||
name: "Windows Build",
|
||||
short_name: win,
|
||||
}
|
||||
- {
|
||||
name: "Linux Build",
|
||||
short_name: linux
|
||||
}
|
||||
- {
|
||||
name: "MacOS Build",
|
||||
short_name: macos
|
||||
}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.7.7' # 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: |
|
||||
cp -r src/blenderbim src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }} &&
|
||||
cd src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }} &&
|
||||
make dist PLATFORM=${{ matrix.config.short_name }} PYVERSION=${{ matrix.pyver }}
|
||||
- name: Upload Zip file to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }}/dist/blenderbim-${{steps.date.outputs.date}}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
|
||||
asset_name: blenderbim-${{steps.date.outputs.date}}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
|
||||
tag: "blenderbim-${{steps.date.outputs.date}}"
|
||||
overwrite: true
|
||||
body: "Daily developer testing build blenderbim-${{steps.date.outputs.date}}"
|
||||
@@ -0,0 +1,85 @@
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'src/**'
|
||||
- 'test/**'
|
||||
- 'conda/**'
|
||||
- 'cmake/**'
|
||||
- '.github/workflows/ci.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 \
|
||||
liboce-foundation-dev liboce-modeling-dev liboce-ocaf-dev liboce-visualization-dev liboce-ocaf-lite-dev
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
|
||||
- name: Build ifcopenshell
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_INSTALL_PREFIX=$PWD/install/ \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH=/usr \
|
||||
-DCMAKE_SYSTEM_PREFIX_PATH=/usr \
|
||||
-DOCC_INCLUDE_DIR=/usr/include/oce \
|
||||
-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" \
|
||||
-DGLTF_SUPPORT=On \
|
||||
-DJSON_INCLUDE_DIR=/usr/include \
|
||||
../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 numpy lxml
|
||||
sudo /usr/bin/python -m pip install src/bcf
|
||||
sudo /usr/bin/python -m pip install pytest
|
||||
sudo /usr/bin/python -m pip install isodate
|
||||
|
||||
- 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
|
||||
@@ -0,0 +1,96 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v[0-9].[0-9].[0-9]*'
|
||||
|
||||
jobs:
|
||||
activate:
|
||||
if: github.repository == 'IfcOpenShell/IfcOpenShell'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo ok go
|
||||
build:
|
||||
needs: activate
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
lfs: true
|
||||
-
|
||||
name: Update ubuntu
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install git cmake gcc g++ libboost1.67-all-dev python3-all-dev swig libpcre3-dev libxml2-dev
|
||||
sudo apt-get install liboce-foundation-dev liboce-modeling-dev liboce-ocaf-dev liboce-visualization-dev liboce-ocaf-lite-dev
|
||||
- name: Build
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CHANGELOG_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake \
|
||||
-DCMAKE_INSTALL_PREFIX=$PWD/install/ \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH=/usr \
|
||||
-DCMAKE_SYSTEM_PREFIX_PATH=/usr \
|
||||
-DBUILD_PACKAGE=On \
|
||||
-DOCC_INCLUDE_DIR=/usr/include/oce \
|
||||
-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 \
|
||||
-DLIBXML2_INCLUDE_DIR=/usr/include/libxml2 \
|
||||
-DLIBXML2_LIBRARIES=/usr/lib/x86_64-linux-gnu/libxml2.so \
|
||||
../cmake
|
||||
make -j $(nproc)
|
||||
make install
|
||||
- name: Package
|
||||
id: package
|
||||
run: |
|
||||
make package
|
||||
echo ::set-output name=tgz::$( ls assets/*.tar.gz | head -n 1 | xargs basename )
|
||||
echo ::set-output name=deb::$( ls assets/*.deb | head -n 1 | xargs basename )
|
||||
working-directory: build
|
||||
env:
|
||||
CHANGELOG_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Release
|
||||
id: release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: true
|
||||
body: |
|
||||
Changes to this release
|
||||
- add github actions support #1306
|
||||
- add boost depends to ifcopenshell deb packaging
|
||||
- <add more changes here>
|
||||
See more details in the documentation
|
||||
# body_path: build/CHANGELOG.md
|
||||
- name: Upload TGZ
|
||||
id: upload-tgz
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
|
||||
asset_path: build/assets/${{ steps.package.outputs.tgz }}
|
||||
asset_name: ${{ steps.package.outputs.tgz }}
|
||||
asset_content_type: application/x-gzip
|
||||
- name: Upload DEB
|
||||
id: upload-deb
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
|
||||
asset_path: build/assets/${{ steps.package.outputs.deb }}
|
||||
asset_name: ${{ steps.package.outputs.deb }}
|
||||
asset_content_type: application/vnd.debian.binary-package
|
||||
@@ -1,4 +1,11 @@
|
||||
# Dependency and build folders created by the build scripts
|
||||
/_build-vs2015-x64/
|
||||
/_deps-vs2015-x64-installed/
|
||||
/_build-vs2017-x64/
|
||||
/_deps-vs2017-x64-installed/
|
||||
/_build-vs2019-x64/
|
||||
/_deps-vs2019-x64-installed/
|
||||
/_deps/
|
||||
/deps*/
|
||||
/build*/
|
||||
/install*/
|
||||
@@ -13,6 +20,10 @@ __pycache__
|
||||
# PyCharm files
|
||||
.idea
|
||||
|
||||
#Virtual Env Files
|
||||
Pipfile
|
||||
Pipfile.lock
|
||||
|
||||
# Docs
|
||||
/docs/output
|
||||
/docs/rst_files
|
||||
@@ -21,5 +32,32 @@ __pycache__
|
||||
|
||||
# gettext binary translation files
|
||||
*.mo
|
||||
|
||||
# Vim
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Flask
|
||||
instance/*
|
||||
!instance/.gitignore
|
||||
.webassets-cache
|
||||
.env
|
||||
*.db
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# pipenv
|
||||
Pipfile
|
||||
Pipfile.lock
|
||||
|
||||
# Database
|
||||
*.db
|
||||
|
||||
# PyTest
|
||||
htmlcov
|
||||
.coverage
|
||||
|
||||
# Blender
|
||||
*.blend1
|
||||
|
||||
@@ -1,57 +1,67 @@
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
cache: ccache
|
||||
os: linux
|
||||
dist: bionic
|
||||
sudo: required
|
||||
|
||||
before_install:
|
||||
- "sudo add-apt-repository -y ppa:freecad-community/ppa"
|
||||
- sudo apt-get update -qq
|
||||
|
||||
dist: focal
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libboost-date-time-dev
|
||||
- libboost-filesystem-dev
|
||||
- libboost-iostreams-dev
|
||||
- libboost-program-options-dev
|
||||
- libboost-regex-dev
|
||||
- libboost-system-dev
|
||||
- libboost-thread-dev
|
||||
- libocct-data-exchange-dev
|
||||
- libocct-foundation-dev
|
||||
- libocct-modeling-algorithms-dev
|
||||
- libocct-modeling-data-dev
|
||||
- libxml2-dev
|
||||
- nlohmann-json3-dev
|
||||
- opencollada-dev
|
||||
- python3-all-dev
|
||||
- python3-pip
|
||||
- swig
|
||||
|
||||
before_script:
|
||||
- if [ $TRAVIS_OS_NAME == "linux" ]; then ccache -z; fi
|
||||
|
||||
install:
|
||||
- |
|
||||
sudo apt-get install -y \
|
||||
libocct-data-exchange-dev libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev \
|
||||
libboost-system-dev libboost-program-options-dev libboost-regex-dev libboost-thread-dev libboost-date-time-dev libboost-iostreams-dev libboost-filesystem-dev \
|
||||
build-essential cmake python2.7 libpython2.7-dev swig zlib1g liblzma5 opencollada-dev wget apt-transport-https
|
||||
- sudo mkdir -p /usr/include/json/nlohmann/
|
||||
- sudo wget https://github.com/nlohmann/json/releases/download/v3.6.1/json.hpp -O /usr/include/json/nlohmann/json.hpp
|
||||
# - sudo sh -c 'curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -'
|
||||
# - sudo sh -c 'curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list'
|
||||
# - sudo apt-get update -qq && sudo apt-get install -y dart
|
||||
# - export PATH=$PATH:/usr/lib/dart/bin:$HOME/.pub-cache/bin
|
||||
# - git clone https://github.com/KhronosGroup/glTF-Validator && pushd glTF-Validator && pub get && pub global activate --source path ./ && popd
|
||||
# for IDS
|
||||
- python3 -m pip install xmlschema
|
||||
|
||||
script:
|
||||
- pwd
|
||||
- cd cmake
|
||||
- mkdir build
|
||||
- cd build
|
||||
- mkdir build && cd build
|
||||
- |
|
||||
cmake \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
|
||||
-DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DPYTHON_LIBRARY=/usr/lib/python2.7/config-x86_64-linux-gnu/libpython2.7.so \
|
||||
-DPYTHON_INCLUDE_DIR=/usr/include/python2.7 \
|
||||
-DPYTHON_EXECUTABLE=/usr/bin/python2.7 \
|
||||
-DLIBXML2_INCLUDE_DIR=/usr/include/libxml2 \
|
||||
-DLIBXML2_LIBRARIES="/usr/lib/x86_64-linux-gnu/libxml2.so;/lib/x86_64-linux-gnu/libz.so.1;/lib/x86_64-linux-gnu/liblzma.so.5;/usr/lib/x86_64-linux-gnu/libicuuc.so.60;/usr/lib/x86_64-linux-gnu/libicudata.so.60" \
|
||||
-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 \
|
||||
"-DSCHEMA_VERSIONS=2x3;4" \
|
||||
-DGLTF_SUPPORT=On \
|
||||
-DJSON_INCLUDE_DIR=/usr/include/json \
|
||||
..
|
||||
- sudo make -j2 install
|
||||
|
||||
- cd ../../test
|
||||
- /usr/bin/python2.7 tests.py
|
||||
-DJSON_INCLUDE_DIR=/usr/include \
|
||||
../cmake
|
||||
|
||||
# TODO: Drop sudo
|
||||
- sudo make -j $(nproc) install
|
||||
|
||||
- cd ../test
|
||||
- /usr/bin/python tests.py
|
||||
- /usr/bin/python ../src/ifcopenshell-python/ifcopenshell/test_ids.py
|
||||
|
||||
- cd input
|
||||
|
||||
|
||||
- /usr/local/bin/IfcConvert -yv acad2010_walls.ifc acad2010_walls.glb
|
||||
# - gltf_validator acad2010_walls.glb
|
||||
|
||||
- /usr/bin/python2.7 -c "from __future__ import print_function; from io import open; import ifcopenshell; f = ifcopenshell.open('encoding.ifc'); assert list(map(ord, f[1][0])) == [39, 97, 39, 32, 49, 109, 179, 32, 8804, 32, 53, 109, 179, 32, 8805, 32, 49, 48, 109, 179]"
|
||||
|
||||
|
||||
- /usr/bin/python -c "from io import open; import ifcopenshell; f = ifcopenshell.open('encoding.ifc'); assert list(map(ord, f[1][0])) == [39, 97, 39, 32, 49, 109, 179, 32, 8804, 32, 53, 109, 179, 32, 8805, 32, 49, 48, 109, 179]"
|
||||
|
||||
- |
|
||||
(for i in *.ifc; do \
|
||||
echo $i | tee -a log; \
|
||||
@@ -64,3 +74,6 @@ script:
|
||||
- echo Succeeded
|
||||
- grep 0$ statuses
|
||||
- grep 0$ statuses | wc -l
|
||||
|
||||
after_script:
|
||||
- if [ $TRAVIS_OS_NAME == "linux" ]; then ccache -s; fi
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
@@ -618,4 +618,4 @@ an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# -*- mode: Dockerfile -*-
|
||||
|
||||
FROM ubuntu:focal
|
||||
|
||||
ARG CHANNEL
|
||||
ENV CHANNEL=${CHANNEL:-latest}
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y \
|
||||
vim \
|
||||
ssh \
|
||||
sudo \
|
||||
wget \
|
||||
software-properties-common ;\
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN useradd --user-group --create-home --shell /bin/bash IfcOpenShell ;\
|
||||
echo "IfcOpenShell ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN echo "deb http://archive.ubuntu.com/ubuntu focal-proposed main restricted" | tee -a /etc/apt/sources.list; \
|
||||
echo "deb http://archive.ubuntu.com/ubuntu focal-proposed universe" | tee -a /etc/apt/sources.list; \
|
||||
echo "deb http://archive.ubuntu.com/ubuntu focal-proposed multiverse" | tee -a /etc/apt/sources.list; \
|
||||
apt-get -qq update; \
|
||||
apt-get -y install tzdata dos2unix rsync; \
|
||||
apt-get -y install python3 libxml2 liboce-foundation11 liboce-modeling11 liboce-ocaf11 liboce-visualization11 \
|
||||
liboce-ocaf-lite11 libpython3.8 libboost-system1.67.0 libboost-program-options1.67.0 \
|
||||
libboost-regex1.67.0 libboost-thread1.67.0 libboost-date-time1.67.0; \
|
||||
rm -rf /var/lib/apt/lists/* ;
|
||||
|
||||
COPY . /home/IfcOpenShell/
|
||||
RUN ls -lrtR /home/IfcOpenShell
|
||||
|
||||
RUN dpkg -i /home/IfcOpenShell/*.deb
|
||||
|
||||
USER IfcOpenShell
|
||||
|
||||
@@ -19,8 +19,8 @@ Prerequisites
|
||||
Dependencies
|
||||
-------------
|
||||
* [Boost](http://www.boost.org/)
|
||||
* [Open Cascade](http://opencascade.org) - *optional*, but required for building IfcGeom
|
||||
([official](http://www.opencascade.org/getocc/download/loadocc/), "OCCT", or [community edition](https://github.com/tpaviot/oce), "OCE")
|
||||
* [Open Cascade](https://dev.opencascade.org/) - *optional*, but required for building IfcGeom
|
||||
([official](https://dev.opencascade.org/release), "OCCT", or [community edition](https://github.com/tpaviot/oce), "OCE")
|
||||
For converting IFC representation items into BRep solids and tesselated meshes
|
||||
* [OpenCOLLADA](https://github.com/khronosGroup/OpenCOLLADA/) - *optional*
|
||||
For IfcConvert to be able to write tessellated Collada (.dae) files
|
||||
@@ -101,7 +101,7 @@ Note: where `make -j` is written, add a number roughly equal to the amount of CP
|
||||
$ make -j
|
||||
$ sudo make install
|
||||
|
||||
**2c)** or obtain and compile OCCT from http://www.opencascade.org/getocc/download/loadocc/
|
||||
**2c)** or obtain and compile OCCT from https://dev.opencascade.org/release
|
||||
|
||||
**3)** For building IfcConvert with COLLADA (.dae) support (on by default), OpenCOLLADA is needed:
|
||||
|
||||
@@ -217,7 +217,44 @@ Usage examples
|
||||
>>> # Writing IFC-SPF files to disk:
|
||||
>>> f.write("out.ifc")
|
||||
|
||||
[LGPL]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/COPYING "LGPL"
|
||||
Extra tools
|
||||
-----------
|
||||
|
||||
Also available are a series of utilities that are based on or related to IfcOpenShell.
|
||||
|
||||
Those marked with an asterisk are part of IfcOpenShell.
|
||||
|
||||
Name | License
|
||||
--- | ---
|
||||
bcf | LGPL-3.0-or-later
|
||||
blenderbim | GPL-3.0-or-later
|
||||
bsdd | LGPL-3.0-or-later
|
||||
ifc2ca | LGPL-3.0-or-later
|
||||
ifc4d | LGPL-3.0-or-later
|
||||
ifc5d | LGPL-3.0-or-later
|
||||
ifcbimtester | LGPL-3.0-or-later
|
||||
ifcblender | LGPL-3.0-or-later\*
|
||||
ifccityjson | LGPL-3.0-or-later
|
||||
ifcclash | LGPL-3.0-or-later
|
||||
ifccobie | LGPL-3.0-or-later
|
||||
ifcconvert | LGPL-3.0-or-later\*
|
||||
ifccsv | LGPL-3.0-or-later
|
||||
ifcdiff | LGPL-3.0-or-later
|
||||
ifcfm | LGPL-3.0-or-later
|
||||
ifcgeom | LGPL-3.0-or-later\*
|
||||
ifcgeom\_schema\_agnostic | LGPL-3.0-or-later\*
|
||||
ifcgeomserver | LGPL-3.0-or-later\*
|
||||
ifcjni | LGPL-3.0-or-later\*
|
||||
ifcmax | LGPL-3.0-or-later\*
|
||||
ifcopenshell-python | LGPL-3.0-or-later\*
|
||||
ifcparse | LGPL-3.0-or-later\*
|
||||
ifcpatch | LGPL-3.0-or-later
|
||||
ifcsverchok | GPL-3.0-or-later
|
||||
ifcwrap | LGPL-3.0-or-later\*
|
||||
qtviewer | LGPL-3.0-or-later\*
|
||||
serializers | LGPL-3.0-or-later\*
|
||||
|
||||
[LGPL]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/COPYING.LESSER "LGPL-3.0-or-later"
|
||||
[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"
|
||||
|
||||
@@ -21,7 +21,10 @@ cmake_minimum_required(VERSION 3.1.3)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON) # not necessary, but encouraged
|
||||
|
||||
project (IfcOpenShell)
|
||||
project (IfcOpenShell VERSION 0.6.0)
|
||||
|
||||
# use extra version to make pre-release using eg semver
|
||||
set( EXTRA_VERSION "-alpha.3")
|
||||
|
||||
foreach(max_year RANGE 2014 2030)
|
||||
set(max_sdk "$ENV{ADSK_3DSMAX_SDK_${max_year}}")
|
||||
@@ -35,6 +38,7 @@ OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLL
|
||||
OPTION(IFCXML_SUPPORT "Build IfcParse with ifcXML support (requires libxml2)." ON)
|
||||
OPTION(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
|
||||
OPTION(IFCCONVERT_DOUBLE_PRECISION "IfcConvert: Use double precision floating-point numbers." ON)
|
||||
OPTION(BUILD_PACKAGE "" OFF)
|
||||
OPTION(BUILD_IFCGEOM "Build IfcGeom." ON)
|
||||
OPTION(BUILD_DOCUMENTATION "Build IfcOpenShell Documentation." OFF)
|
||||
OPTION(BUILD_IFCPYTHON "Build IfcPython." ON)
|
||||
@@ -54,7 +58,7 @@ OPTION(USERSPACE_PYTHON_PREFIX "Installs IfcPython for the current user only ins
|
||||
|
||||
# TODO QtViewer is deprecated ATM as it uses the 0.4 API
|
||||
# OPTION(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer (requires Qt 4 framework)." OFF)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND (NOT BUILD_IFCGEOM))
|
||||
message(STATUS "'IfcGeom' is required with current outputs")
|
||||
set(BUILD_IFCGEOM ON)
|
||||
@@ -65,7 +69,7 @@ IF(NOT BINDIR)
|
||||
set(BINDIR bin)
|
||||
ENDIF()
|
||||
IF(NOT IS_ABSOLUTE ${BINDIR})
|
||||
set(BINDIR ${CMAKE_INSTALL_PREFIX}/${BINDIR})
|
||||
set(BINDIR ${CMAKE_INSTALL_BINDIR})
|
||||
ENDIF()
|
||||
MESSAGE(STATUS "BINDIR: ${BINDIR}")
|
||||
|
||||
@@ -73,7 +77,7 @@ IF(NOT INCLUDEDIR)
|
||||
set(INCLUDEDIR include)
|
||||
ENDIF()
|
||||
IF(NOT IS_ABSOLUTE ${INCLUDEDIR})
|
||||
set(INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${INCLUDEDIR})
|
||||
set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
ENDIF()
|
||||
MESSAGE(STATUS "INCLUDEDIR: ${INCLUDEDIR}")
|
||||
|
||||
@@ -81,11 +85,11 @@ IF(NOT LIBDIR)
|
||||
set(LIBDIR lib)
|
||||
ENDIF()
|
||||
IF(NOT IS_ABSOLUTE ${LIBDIR})
|
||||
set(LIBDIR ${CMAKE_INSTALL_PREFIX}/${LIBDIR})
|
||||
set(LIBDIR ${CMAKE_INSTALL_LIBDIR})
|
||||
ENDIF()
|
||||
MESSAGE(STATUS "LIBDIR: ${LIBDIR}")
|
||||
|
||||
set(IFCOPENSHELL_LIBARY_DIR "") # for *nix rpaths
|
||||
set(IFCOPENSHELL_LIBRARY_DIR "") # for *nix rpaths
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_definitions(-DIFC_SHARED_BUILD)
|
||||
@@ -95,7 +99,7 @@ if (BUILD_SHARED_LIBS)
|
||||
# There will be couple hundreds of these so suppress them away, https://msdn.microsoft.com/en-us/library/esew7y1w.aspx
|
||||
add_definitions(-wd4251)
|
||||
endif()
|
||||
set(IFCOPENSHELL_LIBARY_DIR "${LIBDIR}")
|
||||
set(IFCOPENSHELL_LIBRARY_DIR "${LIBDIR}")
|
||||
endif()
|
||||
|
||||
# Create cache entries if absent for environment variables
|
||||
@@ -175,6 +179,7 @@ if(USE_MMAP)
|
||||
endif()
|
||||
|
||||
if (IFCXML_SUPPORT)
|
||||
find_package(LibXml2 REQUIRED)
|
||||
add_definitions(-DWITH_IFCXML)
|
||||
endif()
|
||||
|
||||
@@ -219,51 +224,63 @@ endfunction()
|
||||
if(BUILD_IFCGEOM)
|
||||
|
||||
IF(MSVC)
|
||||
add_debug_variants(LIBXML2_LIBRARIES "${LIBXML2_LIBRARIES}" d)
|
||||
add_debug_variants(LIBXML2_LIBRARIES "${LIBXML2_LIBRARIES}" d)
|
||||
ENDIF()
|
||||
|
||||
# Find Open CASCADE
|
||||
# Open CASCADE
|
||||
IF("${OCC_INCLUDE_DIR}" STREQUAL "")
|
||||
SET(OCC_INCLUDE_DIR "/usr/include/oce/" CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
|
||||
MESSAGE(STATUS "Use OCC_INCLUDE_DIR to specify another directory")
|
||||
FIND_PATH(OCC_INCLUDE_DIR Standard_Version.hxx
|
||||
[PATHS
|
||||
/usr/include/occt
|
||||
/usr/include/oce
|
||||
/usr/include/opencascade
|
||||
]
|
||||
REQUIRED
|
||||
)
|
||||
IF(OCC_INCLUDE_DIR)
|
||||
MESSAGE(STATUS "Found Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable to find Open CASCADE include directory, specify OCC_INCLUDE_DIR manually.")
|
||||
ENDIF()
|
||||
ELSE()
|
||||
SET(OCC_INCLUDE_DIR ${OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
|
||||
ENDIF()
|
||||
|
||||
FIND_FILE(gp_Pnt_hxx "gp_Pnt.hxx" ${OCC_INCLUDE_DIR})
|
||||
IF(gp_Pnt_hxx)
|
||||
MESSAGE(STATUS "Header files found")
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable to find header files, aborting")
|
||||
SET(OCC_INCLUDE_DIR ${OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
|
||||
ENDIF()
|
||||
|
||||
SET(OPENCASCADE_LIBRARY_NAMES
|
||||
TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO
|
||||
TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset TKHLR
|
||||
TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO
|
||||
TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset TKHLR
|
||||
)
|
||||
|
||||
IF("${OCC_LIBRARY_DIR}" STREQUAL "")
|
||||
SET(OCC_LIBRARY_DIR "/usr/lib/" CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
|
||||
MESSAGE(STATUS "Use OCC_LIBRARY_DIR to specify another directory")
|
||||
find_library(OCC_LIBRARY TKernel
|
||||
[PATHS
|
||||
/usr/lib
|
||||
]
|
||||
REQUIRED
|
||||
)
|
||||
IF(OCC_LIBRARY)
|
||||
GET_FILENAME_COMPONENT(OCC_LIBRARY_DIR ${OCC_LIBRARY} PATH)
|
||||
MESSAGE(STATUS "Found Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable find Open CASCADE library directory, specify OCC_LIBRARY_DIR manually.")
|
||||
ENDIF()
|
||||
ELSE()
|
||||
SET(OCC_LIBRARY_DIR ${OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
|
||||
SET(OCC_LIBRARY_DIR ${OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
|
||||
ENDIF()
|
||||
|
||||
FIND_LIBRARY(libTKernel NAMES TKernel TKerneld PATHS ${OCC_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
IF(libTKernel)
|
||||
MESSAGE(STATUS "Library files found")
|
||||
MESSAGE(STATUS "Required Open Cascade Library files found")
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable to find library files, aborting")
|
||||
MESSAGE(FATAL_ERROR "Unable to find Open Cascade library files, aborting")
|
||||
ENDIF()
|
||||
|
||||
# Use the found libTKernel as a template for all other OCC libraries
|
||||
# TODO Extract this into macro/function
|
||||
foreach(lib ${OPENCASCADE_LIBRARY_NAMES})
|
||||
# Make sure we'll handle the Windows/MSVC debug postfix convetion too.
|
||||
# Make sure we'll handle the Windows/MSVC debug postfix convention too.
|
||||
string(REPLACE TKerneld "${lib}" lib_path "${libTKernel}")
|
||||
string(REPLACE TKernel "${lib}" lib_path "${lib_path}")
|
||||
list(APPEND OPENCASCADE_LIBRARIES "${lib_path}")
|
||||
@@ -338,7 +355,7 @@ IF(COLLADA_SUPPORT AND BUILD_CONVERT)
|
||||
|
||||
# Use the found OpenCOLLADAFramework as a template for all other OpenCOLLADA libraries
|
||||
foreach(lib ${OPENCOLLADA_LIBRARY_NAMES})
|
||||
# Make sure we'll handle the Windows/MSVC debug postfix convetion too.
|
||||
# Make sure we'll handle the Windows/MSVC debug postfix convention too.
|
||||
string(REPLACE OpenCOLLADAFrameworkd "${lib}" lib_path "${OpenCOLLADAFramework}")
|
||||
string(REPLACE OpenCOLLADAFramework "${lib}" lib_path "${lib_path}")
|
||||
list(APPEND OPENCOLLADA_LIBRARIES "${lib_path}")
|
||||
@@ -424,7 +441,7 @@ IF(MSVC)
|
||||
# Disable overeager and false positives causing C4458 ("declaration of 'indentifier' hides class member"), at least for now.
|
||||
ADD_DEFINITIONS(-wd4458)
|
||||
ENDIF()
|
||||
# Enforce standards-conformance on VS > 2015, older Boost versions fail to compile with this
|
||||
# Enforce standards-conformance on VS > 2015, older Boost versions fail to compile with this
|
||||
if (MSVC_VERSION GREATER 1900 AND (Boost_MAJOR_VERSION GREATER 1 OR Boost_MINOR_VERSION GREATER 66))
|
||||
add_definitions(-permissive-)
|
||||
endif()
|
||||
@@ -449,6 +466,10 @@ ElSE()
|
||||
else()
|
||||
add_definitions(-Wno-maybe-uninitialized)
|
||||
endif()
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 9.0))
|
||||
# OpenCascade spews a lot of deprecated-copy warnings
|
||||
add_definitions(-Wno-deprecated-copy)
|
||||
endif()
|
||||
# -fPIC is not relevant on Windows and creates pointless warnings
|
||||
if (UNIX)
|
||||
add_definitions(-fPIC)
|
||||
@@ -465,27 +486,33 @@ INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCL
|
||||
|
||||
function(files_for_ifc_version IFC_VERSION RESULT_NAME)
|
||||
set(IFC_PARSE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse)
|
||||
set(${RESULT_NAME}
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.h
|
||||
set(${RESULT_NAME}
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.h
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}enum.h
|
||||
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endfunction()
|
||||
|
||||
set(SCHEMA_VERSIONS "2x3" "4" "4x1" "4x2" "4x3_rc1")
|
||||
if(NOT SCHEMA_VERSIONS)
|
||||
set(SCHEMA_VERSIONS "2x3" "4" "4x1" "4x2" "4x3_rc1" "4x3_rc2" "4x3_rc3" "4x3_rc4")
|
||||
endif()
|
||||
|
||||
foreach(s ${SCHEMA_VERSIONS})
|
||||
add_definitions(-DHAS_SCHEMA_${s})
|
||||
endforeach()
|
||||
|
||||
if(COMPILE_SCHEMA)
|
||||
# @todo, this appears to be untested at the moment
|
||||
|
||||
find_package(PythonInterp)
|
||||
|
||||
|
||||
IF(NOT PYTHONINTERP_FOUND)
|
||||
MESSAGE(FATAL_ERROR "A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed.")
|
||||
ENDIF()
|
||||
|
||||
|
||||
set(IFC_RELEASE_NOT_USED ${SCHEMA_VERSIONS})
|
||||
|
||||
|
||||
# Install pyparsing if necessary
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
|
||||
if ("${PYTHON_PACKAGE_LIST}" STREQUAL "")
|
||||
@@ -507,23 +534,23 @@ if(COMPILE_SCHEMA)
|
||||
else()
|
||||
message(STATUS "Python interpreter with pyparsing found")
|
||||
endif()
|
||||
|
||||
|
||||
# Bootstrap the parser
|
||||
message(STATUS "Compiling schema, this will take a while...")
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} bootstrap.py express.bnf
|
||||
WORKING_DIRECTORY ../src/ifcexpressparser
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} bootstrap.py express.bnf
|
||||
WORKING_DIRECTORY ../src/ifcexpressparser
|
||||
OUTPUT_FILE express_parser.py
|
||||
RESULT_VARIABLE SUCCESS)
|
||||
|
||||
if (NOT "${SUCCESS}" STREQUAL "0")
|
||||
MESSAGE(FATAL_ERROR "Failed to bootstrap parser. Make sure pyparsing is installed")
|
||||
endif()
|
||||
|
||||
|
||||
# Generate code
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} ../ifcexpressparser/express_parser.py ../../${COMPILE_SCHEMA}
|
||||
WORKING_DIRECTORY ../src/ifcparse
|
||||
OUTPUT_VARIABLE COMPILED_SCHEMA_NAME)
|
||||
|
||||
|
||||
# Prevent the schema that had just been compiled from being excluded
|
||||
foreach(s ${SCHEMA_VERSIONS})
|
||||
if("${COMPILED_SCHEMA_NAME}" STREQUAL "${s}")
|
||||
@@ -552,8 +579,35 @@ if (BUILD_CONVERT)
|
||||
endif()
|
||||
|
||||
# IfcParse
|
||||
file(GLOB IFCPARSE_H_FILES ../src/ifcparse/*.h)
|
||||
file(GLOB IFCPARSE_CPP_FILES ../src/ifcparse/*.cpp)
|
||||
file(GLOB IFCPARSE_H_FILES_ALL ../src/ifcparse/*.h)
|
||||
file(GLOB IFCPARSE_CPP_FILES_ALL ../src/ifcparse/*.cpp)
|
||||
|
||||
foreach(s ${IFCPARSE_H_FILES_ALL})
|
||||
get_filename_component(p "${s}" NAME)
|
||||
if (NOT "${p}" MATCHES "[0-9]")
|
||||
list(APPEND IFCPARSE_H_FILES "${s}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(s ${IFCPARSE_CPP_FILES_ALL})
|
||||
get_filename_component(p "${s}" NAME)
|
||||
if (NOT "${p}" MATCHES "[0-9]")
|
||||
list(APPEND IFCPARSE_CPP_FILES "${s}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(s ${SCHEMA_VERSIONS})
|
||||
list(APPEND IFCPARSE_H_FILES
|
||||
../src/ifcparse/Ifc${s}.h
|
||||
../src/ifcparse/Ifc${s}-definitions.h
|
||||
)
|
||||
list(APPEND IFCPARSE_CPP_FILES
|
||||
../src/ifcparse/Ifc${s}.cpp
|
||||
../src/ifcparse/Ifc${s}-schema.cpp
|
||||
)
|
||||
endforeach()
|
||||
|
||||
|
||||
set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES})
|
||||
|
||||
add_library(IfcParse ${IFCPARSE_FILES})
|
||||
@@ -586,7 +640,7 @@ if (UNIX)
|
||||
find_package(Threads)
|
||||
endif()
|
||||
|
||||
TARGET_LINK_LIBRARIES(IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
TARGET_LINK_LIBRARIES(IfcGeom IfcParse ${IFCGEOM_SCHEMA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
endif(BUILD_IFCGEOM)
|
||||
|
||||
@@ -624,7 +678,7 @@ if ((NOT WIN32) AND BUILD_SHARED_LIBS)
|
||||
# Only set RPATHs when building shared libraries (i.e. IfcParse and
|
||||
# IfcGeom are dynamically linked). Not necessarily a perfect solution
|
||||
# but probably a good indication of whether RPATHs are necessary.
|
||||
SET_INSTALL_RPATHS(IfcConvert "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${OPENCOLLADA_LIBRARY_DIR}")
|
||||
SET_INSTALL_RPATHS(IfcConvert "${IFCOPENSHELL_LIBRARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${OPENCOLLADA_LIBRARY_DIR}")
|
||||
endif()
|
||||
|
||||
INSTALL(TARGETS IfcConvert
|
||||
@@ -645,7 +699,7 @@ ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES})
|
||||
TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES})
|
||||
|
||||
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
|
||||
SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS}")
|
||||
SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBRARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS}")
|
||||
endif()
|
||||
|
||||
INSTALL(TARGETS IfcGeomServer
|
||||
@@ -656,7 +710,7 @@ INSTALL(TARGETS IfcGeomServer
|
||||
|
||||
endif()
|
||||
|
||||
# Documentation
|
||||
# Documentation
|
||||
IF(BUILD_DOCUMENTATION)
|
||||
set(CMAKE_MODULE_PATH "../docs/cmake")
|
||||
ADD_SUBDIRECTORY(../docs docs)
|
||||
@@ -675,7 +729,7 @@ IF(BUILD_IFCMAX)
|
||||
ENDIF()
|
||||
|
||||
# CMake installation targets
|
||||
INSTALL(FILES ${IFCPARSE_H_FILES}
|
||||
INSTALL(FILES ${IFCPARSE_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcparse
|
||||
)
|
||||
|
||||
@@ -686,11 +740,11 @@ INSTALL(TARGETS IfcParse
|
||||
)
|
||||
|
||||
if(BUILD_IFCGEOM)
|
||||
INSTALL(FILES ${IFCGEOM_H_FILES}
|
||||
INSTALL(FILES ${IFCGEOM_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom
|
||||
)
|
||||
|
||||
INSTALL(FILES ${SCHEMA_AGNOSTIC_H_FILES}
|
||||
INSTALL(FILES ${SCHEMA_AGNOSTIC_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom_schema_agnostic
|
||||
)
|
||||
|
||||
@@ -716,3 +770,43 @@ INSTALL(FILES ${SERIALIZERS_S_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/serializers/schema_dependent
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES
|
||||
.git
|
||||
.gitignore
|
||||
)
|
||||
|
||||
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}${EXTRA_VERSION}")
|
||||
SET(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}-${CMAKE_SYSTEM_NAME}")
|
||||
set(CPACK_PACKAGE_DIRECTORY "${PROJECT_BINARY_DIR}/assets")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IfcOpenShell")
|
||||
set(CPACK_PACKAGE_DESCRIPTION "IfcOpenShell.")
|
||||
set(CPACK_PACKAGE_VENDOR "Cemosis")
|
||||
set(CPACK_PACKAGE_CONTACT "Christophe Prud'homme <christophe.prudhomme@cemosis.fr>")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
|
||||
|
||||
|
||||
set(CPACK_GENERATOR "TGZ;DEB")
|
||||
set(CPACK_SOURCE_GENERATOR "TGZ")
|
||||
|
||||
FOREACH(COMPONENT IN ITEMS ${BOOST_COMPONENTS})
|
||||
string(REPLACE "_" "-" COMP ${COMPONENT})
|
||||
set(BOOST_DEPS "${BOOST_DEPS}, libboost-${COMP}1.67.0")
|
||||
endforeach(COMPONENT)
|
||||
|
||||
set(CPACK_DEBIAN_PACKAGE_NAME "${PROJECT_NAME}")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_CONTACT}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "python3, libxml2, liboce-foundation11, liboce-modeling11, liboce-ocaf11, liboce-visualization11, liboce-ocaf-lite11, libpython3.8 ${BOOST_DEPS}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION_SUMMARY "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION}")
|
||||
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION "science")
|
||||
set(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}${EXTRA_VERSION}")
|
||||
set(CPACK_DEBIAN_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}")
|
||||
#set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/cmake/debian/postinst")
|
||||
|
||||
include(CPack)
|
||||
|
||||
@@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8
|
||||
# title of most generated pages and in a few other places.
|
||||
# The default value is: My Project.
|
||||
|
||||
PROJECT_NAME = "My Project"
|
||||
PROJECT_NAME = "IfcOpenShell"
|
||||
|
||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
@@ -829,7 +829,7 @@ WARN_LOGFILE =
|
||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = ../src/ifcgeom ../src/serializers
|
||||
INPUT = ../src/ifcgeom ../src/serializers ../src/ifcgeom_schema_agnostic ../src/ifcparse
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
|
||||
@@ -22,7 +22,7 @@ exhale_args = {
|
||||
# These arguments are required
|
||||
"containmentFolder": "./rst_files",
|
||||
"rootFileName": "library_root.rst",
|
||||
"rootFileTitle": "IfcOpenShell",
|
||||
"rootFileTitle": "IfcOpenShell C++",
|
||||
"doxygenStripFromPath": "..",
|
||||
# Suggested optional arguments
|
||||
"createTreeView": True,
|
||||
@@ -34,15 +34,4 @@ exhale_args = {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
# html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# # Tell sphinx what the primary language being documented is.
|
||||
# primary_domain = 'cpp'
|
||||
|
||||
# # Tell sphinx what the pygments highlight language should be.
|
||||
# highlight_language = 'cpp'
|
||||
|
||||
|
||||
|
||||
cpp_id_attributes = ['IFC_PARSE_API', 'IFC_GEOM_API']
|
||||
|
||||
@@ -7,4 +7,4 @@ IfcOpenShell
|
||||
rst_files/library_root
|
||||
|
||||
|
||||
`ifcopenshell-python documentation <_build/html/index.html>`_
|
||||
* `ifcopenshell-python documentation <python/html/index.html>`_
|
||||
@@ -1,52 +1,39 @@
|
||||
# This program requires doxygen, sphinx, breathe and exhale.
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import shutil
|
||||
import subprocess
|
||||
import multiprocessing
|
||||
|
||||
from sys import platform
|
||||
|
||||
|
||||
def copy_content(content, container):
|
||||
with open(content) as f:
|
||||
with open(container, "w") as f1:
|
||||
for line in f:
|
||||
f1.write(line)
|
||||
|
||||
|
||||
conf_path = "./conf.py"
|
||||
index_path = "./index.rst"
|
||||
# some extra check to see if we can find sphinx in pypy bin dir
|
||||
sphinx_build = os.path.join(os.path.dirname(sys.executable), 'sphinx-build')
|
||||
if not os.path.exists(sphinx_build):
|
||||
sphinx_build = "sphinx-build"
|
||||
# else:
|
||||
# os.environ['PATH'] = os.pathsep + os.path.dirname(sys.executable)
|
||||
|
||||
# not used, -j caused issues in my sphinx install
|
||||
j = str(multiprocessing.cpu_count())
|
||||
|
||||
if not os.path.isdir("./output/doxygen/xml"):
|
||||
os.makedirs("output/doxygen/xml")
|
||||
|
||||
if os.path.isfile(conf_path) and not os.path.isfile(index_path):
|
||||
os.remove(conf_path)
|
||||
if os.path.isfile(index_path) and not os.path.isfile(conf_path):
|
||||
os.remove(index_path)
|
||||
subprocess.check_call([sphinx_build, "-b", "html", ".", "output"])
|
||||
|
||||
if not (os.path.isfile(conf_path) and os.path.isfile(index_path)):
|
||||
subprocess.run(["sphinx-quickstart", "-q", "-p", "IfcOpenShell"])
|
||||
|
||||
conf_copy = ["./conf_to_copy.py", "./conf.py"]
|
||||
index_copy = ["./index_to_copy.rst", "./index.rst"]
|
||||
|
||||
copy_content(conf_copy[0], conf_copy[1])
|
||||
copy_content(index_copy[0], index_copy[1])
|
||||
|
||||
if platform == "linux" or platform == "linux2":
|
||||
subprocess.run(["make", "html"])
|
||||
if not os.path.isdir("/output/_build"):
|
||||
subprocess.run(["cd","../src/ifcblenderexport/docs"])
|
||||
subprocess.run(["make", "html"])
|
||||
subprocess.run(["cd", "../../../docs"])
|
||||
|
||||
subprocess.run(["mv" "../src/ifcblenderexport/docs/_build", "./output"])
|
||||
if sys.platform == "linux" or sys.platform == "linux2":
|
||||
if os.path.isdir("output/python"):
|
||||
shutil.rmtree("output/python")
|
||||
|
||||
if not os.path.exists(os.path.join("../src/ifcblenderexport/docs", "contents.rst")):
|
||||
subprocess.check_call(["ln", "index.rst", "contents.rst"], cwd="../src/ifcblenderexport/docs")
|
||||
|
||||
subprocess.check_call(["sed", "-i", "s/html_theme/# html_theme/g", "conf.py"], cwd="../src/ifcblenderexport/docs")
|
||||
subprocess.check_call(["make", "html"], cwd="../src/ifcblenderexport/docs")
|
||||
subprocess.check_call(["git", "checkout", "conf.py"], cwd="../src/ifcblenderexport/docs")
|
||||
|
||||
shutil.move("../src/ifcblenderexport/docs/_build", "./output")
|
||||
os.rename("./output/_build", "./output/python")
|
||||
|
||||
elif platform == "win32" or platform == "win64":
|
||||
subprocess.run(["make.bat", "html"])
|
||||
|
||||
|
||||
|
||||
elif sys.platform == "win32" or sys.platform == "win64":
|
||||
subprocess.check_call(["make.bat", "html"])
|
||||
|
||||
@@ -7,4 +7,4 @@ IfcOpenShell
|
||||
rst_files/library_root
|
||||
|
||||
|
||||
`ifcopenshell-python documentation <_build/html/index.html>`_
|
||||
* `ifcopenshell-python documentation <python/html/index.html>`_
|
||||
@@ -310,7 +310,7 @@ def run(cmds, cwd=None):
|
||||
BOOST_VERSION_UNDERSCORE=BOOST_VERSION.replace(".", "_")
|
||||
|
||||
OCE_LOCATION="https://github.com/tpaviot/oce/archive/OCE-%s.tar.gz" % (OCE_VERSION,)
|
||||
BOOST_LOCATION="https://dl.bintray.com/boostorg/release/%s/source/" % (BOOST_VERSION,)
|
||||
BOOST_LOCATION="https://boostorg.jfrog.io/artifactory/main/release/%s/source/" % (BOOST_VERSION,)
|
||||
|
||||
# Helper functions
|
||||
|
||||
@@ -336,7 +336,7 @@ def git_clone_or_pull_repository(clone_url, target_dir, revision=None):
|
||||
`None`."""
|
||||
if not os.path.exists(target_dir):
|
||||
logger.info("cloning '%s' into '%s'" % (clone_url, target_dir))
|
||||
run([git, "clone", clone_url, target_dir])
|
||||
run([git, "clone", "--recursive", clone_url, target_dir])
|
||||
else:
|
||||
logger.info("directory '%s' already cloned. Pulling latest changes." % (target_dir,))
|
||||
|
||||
|
||||
@@ -0,0 +1,621 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@@ -0,0 +1,2 @@
|
||||
include src/bcf/v2/xsd/*.xsd
|
||||
include src/bcf/v3/xsd/*.xsd
|
||||
@@ -4,23 +4,26 @@ A simple Python implementation of BCF. The data model is described in `data.py`.
|
||||
Manipulation of BCF-XML is available via `bcfxml.py` and manipulation of BCF-API
|
||||
is available via `bcfapi.py`.
|
||||
|
||||
Currently supports BCF version 2.1.
|
||||
- BCF-XML version 2.1: Fully supported
|
||||
- BCF-API version 2.1: Not supported, will probably tackle this after BCF-API v3.0
|
||||
- BCF-XML version 3.0: Almost fully supported, except for the documents module
|
||||
- BCF-API version 3.0: Almost fully supported, except for two requests.
|
||||
|
||||
## bcfxml
|
||||
|
||||
The `bcfxml` module lets you interact with the BCF-XML standard.
|
||||
|
||||
```
|
||||
from bcf.bcfxml import BcfXml
|
||||
```python
|
||||
from bcf import bcfxml
|
||||
|
||||
bcfxml = BcfXml()
|
||||
|
||||
# Load a project
|
||||
project = bcfxml.get_project("/path/to/file.bcf")
|
||||
bcfxml = bcfxml.load("/path/to/file.bcf")
|
||||
|
||||
|
||||
# The project is also stored in the module
|
||||
# project == bcfxml.project
|
||||
|
||||
project=bcfxml.get_project()
|
||||
print(project.name)
|
||||
|
||||
# To edit a project, just modify the object directly
|
||||
@@ -57,3 +60,42 @@ topic = bcfxml.get_topic(guid)
|
||||
topic.title = "New title"
|
||||
bcfxml.edit_topic(topic)
|
||||
```
|
||||
|
||||
## 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)
|
||||
```
|
||||
|
||||
## Todo List
|
||||
|
||||
The remaining work that needs to be completed in `bcfxml.py` and `bcfapi.py`.
|
||||
|
||||
- For `bcfxml.py` two xsds support is remaining namely 'documents.xsd`and`extensions.xsd`.
|
||||
- For `bcfapi.py` two requests that are `get_topics` and `get_comments` are remaining.
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[build-system]
|
||||
requires = [
|
||||
"setuptools>=42",
|
||||
"wheel"
|
||||
]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
@@ -0,0 +1 @@
|
||||
xmlschema
|
||||
@@ -0,0 +1,37 @@
|
||||
[metadata]
|
||||
name=bcf-client
|
||||
version=0.0.1
|
||||
author = Ifcopenshell
|
||||
description = A simple Python implementation of BCF
|
||||
url = https://github.com/IfcOpenShell/IfcOpenShell
|
||||
project_urls =
|
||||
Code=https://github.com/IfcOpenShell/IfcOpenShell
|
||||
Issues=https://github.com/IfcOpenShell/IfcOpenShell/issues
|
||||
long_description = file: README.md
|
||||
long_description_content_type = text/markdown
|
||||
classifiers =
|
||||
License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
||||
Operating System :: OS Independent
|
||||
Programming Language :: Python :: 3
|
||||
Topic :: Scientific/Engineering
|
||||
Topic :: Utilities
|
||||
keywords =
|
||||
Python
|
||||
file formats
|
||||
engineering
|
||||
|
||||
[options]
|
||||
package_dir =
|
||||
= src
|
||||
packages = find:
|
||||
python_requires = >=3
|
||||
install_requires=
|
||||
xmlschema
|
||||
include_package_data = True
|
||||
|
||||
[options.packages.find]
|
||||
where = src
|
||||
|
||||
[flake8]
|
||||
max-line-length = 120
|
||||
ignore = E24, E121, E123, E126, E203, E226, E704, E741, W503, W504
|
||||
@@ -0,0 +1,17 @@
|
||||
# BCF - BCF Python library
|
||||
# Copyright (C) 2021 Prabhat Singh <singh01prabhat@gmail.com>
|
||||
#
|
||||
# This file is part of BCF.
|
||||
#
|
||||
# BCF is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BCF 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 Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with BCF. If not, see <http://www.gnu.org/licenses/>.
|
||||
@@ -0,0 +1,61 @@
|
||||
# BCF - BCF Python library
|
||||
# Copyright (C) 2021 Prabhat Singh <singh01prabhat@gmail.com>
|
||||
#
|
||||
# This file is part of BCF.
|
||||
#
|
||||
# BCF is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BCF 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 Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with BCF. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
import os.path
|
||||
import zipfile
|
||||
import tempfile
|
||||
from xml.dom import minidom
|
||||
|
||||
|
||||
def load(filepath):
|
||||
filepath = extract_project(filepath)
|
||||
if os.path.isfile(os.path.join(filepath, "bcf.version")):
|
||||
version_path = os.path.join(filepath, "bcf.version")
|
||||
version_id = get_version(version_path)
|
||||
# TODO: we actually coded it for 2.1, let's check the difference between 2.0 and 2.1
|
||||
if version_id == "2.1" or version_id == "2.0":
|
||||
from bcf.v2.bcfxml import BcfXml
|
||||
|
||||
bcfxml = BcfXml()
|
||||
bcfxml.filepath = filepath
|
||||
return bcfxml
|
||||
elif version_id == "3.0":
|
||||
from bcf.v3.bcfxml import BcfXml
|
||||
|
||||
bcfxml = BcfXml()
|
||||
bcfxml.filepath = filepath
|
||||
return bcfxml
|
||||
else:
|
||||
raise Exception(f"Version {version_id} not supported.")
|
||||
|
||||
|
||||
def get_version(version_path):
|
||||
xmlparse = minidom.parse(version_path)
|
||||
version_el = xmlparse.getElementsByTagName("Version")[0]
|
||||
version = version_el.getAttribute("VersionId")
|
||||
return version
|
||||
|
||||
|
||||
def extract_project(filepath):
|
||||
if not filepath:
|
||||
return
|
||||
zip_file = zipfile.ZipFile(filepath)
|
||||
filepath = tempfile.mkdtemp()
|
||||
zip_file.extractall(filepath)
|
||||
return filepath
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
# BCF - BCF Python library
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BCF.
|
||||
#
|
||||
# BCF is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BCF 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 Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with BCF. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
|
||||
# BCF - BCF Python library
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BCF.
|
||||
#
|
||||
# BCF is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BCF 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 Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with BCF. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import uuid
|
||||
import shutil
|
||||
import zipfile
|
||||
import logging
|
||||
import tempfile
|
||||
import bcf.data
|
||||
import bcf.v2.data
|
||||
from datetime import datetime
|
||||
from xml.dom import minidom
|
||||
from xmlschema import XMLSchema
|
||||
@@ -30,7 +49,7 @@ class BcfXml:
|
||||
self.filepath = None
|
||||
self.logger = logging.getLogger("bcfxml")
|
||||
self.author = "john@doe.com"
|
||||
self.project = bcf.data.Project()
|
||||
self.project = bcf.v2.data.Project()
|
||||
self.version = "2.1"
|
||||
self.topics = {}
|
||||
|
||||
@@ -47,12 +66,12 @@ class BcfXml:
|
||||
def get_project(self, filepath=None):
|
||||
if not filepath:
|
||||
return self.project
|
||||
zip_file = zipfile.ZipFile(filepath)
|
||||
self.filepath = tempfile.mkdtemp()
|
||||
zip_file.extractall(self.filepath)
|
||||
data = self._read_xml("project.bcfp", "project.xsd")
|
||||
self.project.project_id = data["Project"]["@ProjectId"]
|
||||
self.project.name = data["Project"]["Name"]
|
||||
if os.path.isfile(os.path.join(self.filepath, "project.bcfp")):
|
||||
data = self._read_xml("project.bcfp", "project.xsd")
|
||||
self.project.extension_schema = data["ExtensionSchema"]
|
||||
if "Project" in data:
|
||||
self.project.project_id = data["Project"]["@ProjectId"]
|
||||
self.project.name = data["Project"].get("Name")
|
||||
return self.project
|
||||
|
||||
def edit_project(self):
|
||||
@@ -92,6 +111,12 @@ class BcfXml:
|
||||
subdirs = dirnames
|
||||
break
|
||||
for subdir in subdirs:
|
||||
try:
|
||||
uuid.UUID(subdir)
|
||||
except ValueError:
|
||||
continue
|
||||
if not os.path.exists(os.path.join(self.filepath, subdir, "markup.bcf")):
|
||||
continue
|
||||
self.topics[subdir] = self.get_topic(subdir)
|
||||
return self.topics
|
||||
|
||||
@@ -99,9 +124,9 @@ class BcfXml:
|
||||
data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd")
|
||||
if "Header" not in data:
|
||||
return
|
||||
header = bcf.data.Header()
|
||||
header = bcf.v2.data.Header()
|
||||
for item in data["Header"]["File"]:
|
||||
header_file = bcf.data.HeaderFile()
|
||||
header_file = bcf.v2.data.HeaderFile()
|
||||
optional_keys = {
|
||||
"filename": "Filename",
|
||||
"date": "Date",
|
||||
@@ -121,7 +146,7 @@ class BcfXml:
|
||||
if guid in self.topics:
|
||||
return self.topics[guid]
|
||||
data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd")
|
||||
topic = bcf.data.Topic()
|
||||
topic = bcf.v2.data.Topic()
|
||||
self.topics[guid] = topic
|
||||
|
||||
mandatory_keys = {
|
||||
@@ -152,7 +177,7 @@ class BcfXml:
|
||||
setattr(topic, key, data["Topic"][value])
|
||||
|
||||
if "BimSnippet" in data["Topic"]:
|
||||
bim_snippet = bcf.data.BimSnippet()
|
||||
bim_snippet = bcf.v2.data.BimSnippet()
|
||||
keys = {
|
||||
"snippet_type": "@SnippetType",
|
||||
"is_external": "@IsExternal",
|
||||
@@ -166,7 +191,7 @@ class BcfXml:
|
||||
|
||||
if "DocumentReference" in data["Topic"]:
|
||||
for item in data["Topic"]["DocumentReference"]:
|
||||
document_reference = bcf.data.DocumentReference()
|
||||
document_reference = bcf.v2.data.DocumentReference()
|
||||
keys = {
|
||||
"referenced_document": "ReferencedDocument",
|
||||
"is_external": "@IsExternal",
|
||||
@@ -180,14 +205,14 @@ class BcfXml:
|
||||
|
||||
if "RelatedTopic" in data["Topic"]:
|
||||
for item in data["Topic"]["RelatedTopic"]:
|
||||
related_topic = bcf.data.RelatedTopic()
|
||||
related_topic = bcf.v2.data.RelatedTopic()
|
||||
related_topic.guid = item["@Guid"]
|
||||
topic.related_topics.append(related_topic)
|
||||
return topic
|
||||
|
||||
def add_topic(self, topic=None):
|
||||
if topic is None:
|
||||
topic = bcf.data.Topic()
|
||||
topic = bcf.v2.data.Topic()
|
||||
if not topic.guid:
|
||||
topic.guid = str(uuid.uuid4())
|
||||
if not topic.title:
|
||||
@@ -285,9 +310,12 @@ class BcfXml:
|
||||
"isExternal": f.is_external,
|
||||
},
|
||||
)
|
||||
self._create_element(file_el, "Filename", text=f.filename)
|
||||
self._create_element(file_el, "Date", text=f.date)
|
||||
self._create_element(file_el, "Reference", text=f.reference)
|
||||
if f.filename:
|
||||
self._create_element(file_el, "Filename", text=f.filename)
|
||||
if f.date:
|
||||
self._create_element(file_el, "Date", text=f.date)
|
||||
if f.reference:
|
||||
self._create_element(file_el, "Reference", text=f.reference)
|
||||
|
||||
def write_comments(self, comments, root):
|
||||
for comment in comments.values():
|
||||
@@ -307,7 +335,7 @@ class BcfXml:
|
||||
|
||||
def add_comment(self, topic, comment=None):
|
||||
if comment is None:
|
||||
comment = bcf.data.Comment()
|
||||
comment = bcf.v2.data.Comment()
|
||||
if not comment.guid:
|
||||
comment.guid = str(uuid.uuid4())
|
||||
if not comment.comment:
|
||||
@@ -441,7 +469,7 @@ class BcfXml:
|
||||
for bitmap in viewpoint.bitmaps:
|
||||
bitmap_el = self._create_element(parent, "Bitmap")
|
||||
|
||||
text_map = {"Bitmap": bitmap.bitmap_type, "Reference": bitmap.reference}
|
||||
text_map = {"Bitmap": bitmap.bitmap_format, "Reference": bitmap.reference}
|
||||
for key, value in text_map.items():
|
||||
self._create_element(bitmap_el, key, text=value)
|
||||
|
||||
@@ -468,7 +496,7 @@ class BcfXml:
|
||||
|
||||
def add_viewpoint(self, topic, viewpoint=None):
|
||||
if not viewpoint:
|
||||
viewpoint = bcf.data.Viewpoint()
|
||||
viewpoint = bcf.v2.data.Viewpoint()
|
||||
if not viewpoint.guid:
|
||||
viewpoint.guid = str(uuid.uuid4())
|
||||
if not viewpoint.viewpoint:
|
||||
@@ -569,7 +597,7 @@ class BcfXml:
|
||||
header_file.is_external = False
|
||||
header_file.date = datetime.utcnow().isoformat()
|
||||
if not topic.header:
|
||||
topic.header = bcf.data.Header()
|
||||
topic.header = bcf.v2.data.Header()
|
||||
topic.header.files.append(header_file)
|
||||
self.edit_topic(topic)
|
||||
|
||||
@@ -579,7 +607,7 @@ class BcfXml:
|
||||
if "Comment" not in data:
|
||||
return comments
|
||||
for item in data["Comment"]:
|
||||
comment = bcf.data.Comment()
|
||||
comment = bcf.v2.data.Comment()
|
||||
mandatory_keys = {"guid": "@Guid", "date": "Date", "author": "Author", "comment": "Comment"}
|
||||
for key, value in mandatory_keys.items():
|
||||
setattr(comment, key, item[value])
|
||||
@@ -588,7 +616,7 @@ class BcfXml:
|
||||
if value in item:
|
||||
setattr(comment, key, item[value])
|
||||
if "Viewpoint" in item:
|
||||
viewpoint = bcf.data.Viewpoint()
|
||||
viewpoint = bcf.v2.data.Viewpoint()
|
||||
viewpoint.guid = item["Viewpoint"]["@Guid"]
|
||||
comment.viewpoint = viewpoint
|
||||
comments[comment.guid] = comment
|
||||
@@ -607,7 +635,7 @@ class BcfXml:
|
||||
return viewpoints
|
||||
|
||||
def get_viewpoint(self, data, topic_guid):
|
||||
viewpoint = bcf.data.Viewpoint()
|
||||
viewpoint = bcf.v2.data.Viewpoint()
|
||||
viewpoint.guid = data["@Guid"]
|
||||
optional_keys = {"viewpoint": "Viewpoint", "snapshot": "Snapshot", "index": "Index"}
|
||||
for key, value in optional_keys.items():
|
||||
@@ -625,10 +653,10 @@ class BcfXml:
|
||||
def get_viewpoint_components(self, visinfo):
|
||||
if "Components" not in visinfo:
|
||||
return None
|
||||
components = bcf.data.Components()
|
||||
components = bcf.v2.data.Components()
|
||||
data = visinfo["Components"]
|
||||
if "ViewSetupHints" in data:
|
||||
view_setup_hints = bcf.data.ViewSetupHints()
|
||||
view_setup_hints = bcf.v2.data.ViewSetupHints()
|
||||
optional_keys = {
|
||||
"spaces_visible": "@SpacesVisible",
|
||||
"space_boundaries_visible": "@SpaceBoundariesVisible",
|
||||
@@ -642,7 +670,7 @@ class BcfXml:
|
||||
for item in data["Selection"]["Component"]:
|
||||
components.selection.append(self.get_component(item))
|
||||
if "Visibility" in data:
|
||||
component_visibility = bcf.data.ComponentVisibility()
|
||||
component_visibility = bcf.v2.data.ComponentVisibility()
|
||||
if "@DefaultVisibility" in data["Visibility"]:
|
||||
component_visibility.default_visibility = data["Visibility"]["@DefaultVisibility"]
|
||||
if "Exceptions" in data["Visibility"] and "Component" in data["Visibility"]["Exceptions"]:
|
||||
@@ -651,7 +679,7 @@ class BcfXml:
|
||||
components.visibility = component_visibility
|
||||
if "Coloring" in data and "Color" in data["Coloring"]:
|
||||
for item in data["Coloring"]["Color"]:
|
||||
color = bcf.data.Color()
|
||||
color = bcf.v2.data.Color()
|
||||
color.color = item["@Color"]
|
||||
for item2 in item["Component"]:
|
||||
color.components.append(self.get_component(item2))
|
||||
@@ -661,7 +689,7 @@ class BcfXml:
|
||||
def get_viewpoint_orthogonal_camera(self, visinfo):
|
||||
if "OrthogonalCamera" not in visinfo:
|
||||
return None
|
||||
camera = bcf.data.OrthogonalCamera()
|
||||
camera = bcf.v2.data.OrthogonalCamera()
|
||||
data = visinfo["OrthogonalCamera"]
|
||||
self.set_vector(camera.camera_view_point, data["CameraViewPoint"])
|
||||
self.set_vector(camera.camera_direction, data["CameraDirection"])
|
||||
@@ -672,7 +700,7 @@ class BcfXml:
|
||||
def get_viewpoint_perspective_camera(self, visinfo):
|
||||
if "PerspectiveCamera" not in visinfo:
|
||||
return None
|
||||
camera = bcf.data.PerspectiveCamera()
|
||||
camera = bcf.v2.data.PerspectiveCamera()
|
||||
data = visinfo["PerspectiveCamera"]
|
||||
self.set_vector(camera.camera_view_point, data["CameraViewPoint"])
|
||||
self.set_vector(camera.camera_direction, data["CameraDirection"])
|
||||
@@ -685,7 +713,7 @@ class BcfXml:
|
||||
return []
|
||||
lines = []
|
||||
for item in visinfo["Lines"]["Line"]:
|
||||
line = bcf.data.Line()
|
||||
line = bcf.v2.data.Line()
|
||||
self.set_vector(line.start_point, item["StartPoint"])
|
||||
self.set_vector(line.end_point, item["EndPoint"])
|
||||
lines.append(line)
|
||||
@@ -696,7 +724,7 @@ class BcfXml:
|
||||
return []
|
||||
planes = []
|
||||
for item in visinfo["ClippingPlanes"]["ClippingPlane"]:
|
||||
plane = bcf.data.ClippingPlane()
|
||||
plane = bcf.v2.data.ClippingPlane()
|
||||
self.set_vector(plane.location, item["Location"])
|
||||
self.set_vector(plane.direction, item["Direction"])
|
||||
planes.append(plane)
|
||||
@@ -707,9 +735,9 @@ class BcfXml:
|
||||
return []
|
||||
bitmaps = []
|
||||
for item in visinfo["Bitmap"]:
|
||||
bitmap = bcf.data.Bitmap()
|
||||
bitmap = bcf.v2.data.Bitmap()
|
||||
bitmap.reference = item["Reference"]
|
||||
bitmap.bitmap_type = item["Bitmap"].upper()
|
||||
bitmap.bitmap_format = item["Bitmap"].upper()
|
||||
self.set_vector(bitmap.location, item["Location"])
|
||||
self.set_vector(bitmap.normal, item["Normal"])
|
||||
self.set_vector(bitmap.up, item["Up"])
|
||||
@@ -723,7 +751,7 @@ class BcfXml:
|
||||
to_obj.z = from_xml["Z"]
|
||||
|
||||
def get_component(self, data):
|
||||
component = bcf.data.Component()
|
||||
component = bcf.v2.data.Component()
|
||||
optional_keys = {
|
||||
"originating_system": "OriginatingSystem",
|
||||
"authoring_tool_id": "AuthoringToolId",
|
||||
@@ -1,7 +1,27 @@
|
||||
|
||||
# BCF - BCF Python library
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BCF.
|
||||
#
|
||||
# BCF is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BCF 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 Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with BCF. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
class Project:
|
||||
def __init__(self):
|
||||
self.project_id = ""
|
||||
self.name = ""
|
||||
self.extension_schema = ""
|
||||
|
||||
|
||||
class BimSnippet:
|
||||
@@ -156,7 +176,7 @@ class Bitmap:
|
||||
def __init__(self):
|
||||
self.reference = "" # Only in BCF-XML
|
||||
self.bitmap_data = None # Only in BCF-API
|
||||
self.bitmap_type = "PNG" # Enum of png or jpg
|
||||
self.bitmap_format = "PNG" # Enum of png or jpg
|
||||
self.location = Point()
|
||||
self.normal = Direction()
|
||||
self.up = Direction()
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
# BCF - BCF Python library
|
||||
# Copyright (C) 2021 Prabhat Singh <singh01prabhat@gmail.com>
|
||||
#
|
||||
# This file is part of BCF.
|
||||
#
|
||||
# BCF is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BCF 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 Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with BCF. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
@@ -0,0 +1,603 @@
|
||||
|
||||
# BCF - BCF Python library
|
||||
# Copyright (C) 2021 Prabhat Singh <singh01prabhat@gmail.com>
|
||||
#
|
||||
# This file is part of BCF.
|
||||
#
|
||||
# BCF is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BCF 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 Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with BCF. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import uuid
|
||||
import time
|
||||
import json
|
||||
import urllib
|
||||
import requests
|
||||
import webbrowser
|
||||
import http.server
|
||||
import base64
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
client_id, client_secret = "", ""
|
||||
|
||||
|
||||
class OAuthReceiver(http.server.BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
query = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
|
||||
self.server.auth_code = query.get("code", [""])[0]
|
||||
self.server.auth_state = query.get("state", [""])[0]
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "text/plain")
|
||||
self.end_headers()
|
||||
self.wfile.write("You have now authenticated :) You may now close this browser window.".encode("utf-8"))
|
||||
|
||||
|
||||
class FoundationClient:
|
||||
def __init__(self, client_id, client_secret, base_url=None, redirect_subdir=None):
|
||||
self.baseurl = base_url
|
||||
self.access_token = ""
|
||||
self.refresh_token = ""
|
||||
self.access_token_expires_on = time.time()
|
||||
self.refresh_token_expires_on = float("inf")
|
||||
self.auth_endpoint = None
|
||||
self.token_endpoint = None
|
||||
self.client_id = client_id
|
||||
self.client_secret = client_secret
|
||||
self.auth_method = None
|
||||
self.redirect_subdir = redirect_subdir
|
||||
|
||||
def get_access_token(self):
|
||||
if self.access_token and self.access_token_expires_on > time.time():
|
||||
return self.access_token
|
||||
elif self.refresh_token and self.refresh_token_expires_on > time.time():
|
||||
self.get_refresh_token()
|
||||
else:
|
||||
self.login()
|
||||
return self.access_token
|
||||
|
||||
def get_auth_methods(self):
|
||||
resp = requests.get(f"{self.baseurl}foundation/1.0/auth")
|
||||
return resp.json()["supported_oauth2_flows"]
|
||||
|
||||
def get_versions(self):
|
||||
resp = requests.get(f"{self.baseurl}foundation/versions")
|
||||
return resp.json()["versions"]
|
||||
|
||||
def login(self):
|
||||
resp = requests.get(f"{self.baseurl}foundation/1.0/auth")
|
||||
values = resp.json()
|
||||
self.auth_endpoint = values["oauth2_auth_url"]
|
||||
self.token_endpoint = values["oauth2_token_url"]
|
||||
|
||||
with http.server.HTTPServer(("", 8080), OAuthReceiver) as server:
|
||||
state = str(uuid.uuid4())
|
||||
query = urllib.parse.urlencode(
|
||||
{
|
||||
"client_id": self.client_id,
|
||||
"response_type": "code",
|
||||
"state": state,
|
||||
"redirect_uri": f"http://localhost:{server.server_address[1]}/{self.redirect_subdir}",
|
||||
}
|
||||
)
|
||||
if "?" in self.auth_endpoint:
|
||||
webbrowser.open(f"{self.auth_endpoint}&{query}")
|
||||
else:
|
||||
webbrowser.open(f"{self.auth_endpoint}?{query}")
|
||||
server.timeout = 100
|
||||
server.state = state
|
||||
server.handle_request()
|
||||
if server.auth_code and server.auth_state == state:
|
||||
data = {
|
||||
"grant_type": "authorization_code",
|
||||
"code": server.auth_code,
|
||||
"redirect_uri": f"http://localhost:{server.server_address[1]}/{self.redirect_subdir}",
|
||||
}
|
||||
auth_string = f"{self.client_id}:{self.client_secret}"
|
||||
header_string = base64.b64encode(auth_string.encode("utf-8")).decode("utf-8")
|
||||
headers = {"Authorization": f"Basic {header_string}"}
|
||||
self.set_tokens_from_response(requests.post(self.token_endpoint, data=data, headers=headers))
|
||||
|
||||
def get_refresh_token(self):
|
||||
self.set_tokens_from_response(
|
||||
requests.post(
|
||||
self.token_endpoint,
|
||||
params={
|
||||
"grant_type": "refresh_token",
|
||||
"refresh_token": self.refresh_token,
|
||||
},
|
||||
).json()
|
||||
)
|
||||
|
||||
def get_new_access_token(self):
|
||||
auth_string = f"{self.client_id}:{self.client_secret}"
|
||||
header_string = base64.b64encode(auth_string.encode("utf-8")).decode("utf-8")
|
||||
headers = {"Authorization": f"Basic {header_string}"}
|
||||
self.set_tokens_from_response(
|
||||
requests.post(
|
||||
self.token_endpoint,
|
||||
data={
|
||||
"grant_type": "refresh_token",
|
||||
"refresh_token": self.refresh_token,
|
||||
},
|
||||
headers=headers,
|
||||
).json()
|
||||
)
|
||||
|
||||
def set_auth_method(self, method="authorization_code_grant"):
|
||||
if method != "authorization_code_grant":
|
||||
raise NotImplementedError(f"{method} not supported")
|
||||
else:
|
||||
self.auth_method = method
|
||||
|
||||
def set_tokens_from_response(self, response):
|
||||
response = response.json()
|
||||
self.access_token = response["access_token"]
|
||||
self.refresh_token = response["refresh_token"]
|
||||
self.access_token_expires_on = time.time() + response["expires_in"]
|
||||
if "refresh_token_expires_in" in response:
|
||||
self.refresh_token_expires_on = time.time() + response["refresh_token_expires_in"]
|
||||
|
||||
|
||||
class BcfClient:
|
||||
def __init__(self, foundation_client):
|
||||
self.foundation_client = foundation_client
|
||||
self.version_id = None
|
||||
self.baseurl = None
|
||||
self.filepath = tempfile.mkdtemp()
|
||||
|
||||
def set_version(self, version):
|
||||
self.version_id = version["version_id"]
|
||||
self.baseurl = version["api_base_url"]
|
||||
|
||||
def get(self, endpoint, params=None, is_auth_required=False):
|
||||
# TODO: handle error http status codes and raise exception. Follow error.json standard.
|
||||
headers = {"Authorization": "Bearer " + self.foundation_client.get_access_token()}
|
||||
response = requests.get(f"{self.baseurl}{endpoint}", headers=headers, params=params or None)
|
||||
try:
|
||||
response = requests.get(f"{self.baseurl}{endpoint}", headers=headers, params=params or None)
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
response.raise_for_status()
|
||||
except requests.exceptions.HTTPError as e:
|
||||
print(f"message: {response.reason}' '{response.status_code}' '{ e }")
|
||||
|
||||
def post(self, endpoint, data=None, params=None):
|
||||
headers = {
|
||||
"Authorization": "Bearer " + self.foundation_client.get_access_token(),
|
||||
"Content-type": "application/json",
|
||||
}
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{self.baseurl}{endpoint}",
|
||||
headers=headers,
|
||||
params=params or None,
|
||||
data=data or None,
|
||||
)
|
||||
if response.status_code == 201:
|
||||
return response.status_code, response.text
|
||||
response.raise_for_status()
|
||||
except requests.exceptions.HTTPError as errh:
|
||||
print(f"message: {response.reason}' '{response.status_code}, {errh}")
|
||||
|
||||
def put(self, endpoint, data=None, params=None):
|
||||
headers = {
|
||||
"Authorization": "Bearer " + self.foundation_client.get_access_token(),
|
||||
"Content-type": "application/json",
|
||||
}
|
||||
try:
|
||||
response = requests.put(
|
||||
f"{self.baseurl}{endpoint}",
|
||||
headers=headers,
|
||||
params=params or None,
|
||||
data=data or None,
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return response.status_code, response.text
|
||||
response.raise_for_status()
|
||||
except requests.exceptions.HTTPError as errh:
|
||||
print(f"message: {response.reason}' '{response.status_code}, {errh}")
|
||||
|
||||
def delete(self, endpoint, params=None):
|
||||
headers = {
|
||||
"Authorization": "Bearer " + self.foundation_client.get_access_token(),
|
||||
"Content-type": "application/json",
|
||||
}
|
||||
try:
|
||||
response = requests.delete(
|
||||
f"{self.baseurl}{endpoint}",
|
||||
headers=headers,
|
||||
params=params or None,
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return response.status_code, response.text
|
||||
response.raise_for_status()
|
||||
except requests.exceptions.HTTPError as errh:
|
||||
print(f"message: {response.reason}' '{response.status_code}, {errh}")
|
||||
|
||||
def get_projects(self) -> list:
|
||||
return self.get(
|
||||
f"/projects",
|
||||
)
|
||||
|
||||
def get_project(
|
||||
self,
|
||||
project_id="",
|
||||
) -> dict:
|
||||
return self.get(
|
||||
f"/projects/{project_id}",
|
||||
{
|
||||
"project_id": project_id,
|
||||
},
|
||||
)
|
||||
|
||||
def update_project(self, project_id="", data=None) -> dict:
|
||||
url = f"{self.baseurl}/projects/{project_id}"
|
||||
headers = {"Authorization": "Bearer " + self.foundation_client.get_access_token()}
|
||||
resp = requests.put(url, headers=headers, data=data)
|
||||
return resp.status_code, resp.text
|
||||
|
||||
def get_extensions(
|
||||
self,
|
||||
project_id="",
|
||||
) -> dict:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/extensions",
|
||||
{
|
||||
"project_id": project_id,
|
||||
},
|
||||
)
|
||||
|
||||
def get_topics(
|
||||
self,
|
||||
project_id="",
|
||||
topics="",
|
||||
query_string=None,
|
||||
) -> list:
|
||||
# return self.get(
|
||||
# f"/projects/{project_id}/topics",
|
||||
# {
|
||||
# "project_id": project_id,
|
||||
# "topics": topics,
|
||||
# "query_string": query_string,
|
||||
# },
|
||||
# )
|
||||
pass
|
||||
|
||||
def get_topic(self, project_id="", topic_id="") -> dict:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
},
|
||||
)
|
||||
|
||||
def create_topic(self, project_id="", data=None):
|
||||
return self.post(f"/projects/{project_id}/topics", data=data)
|
||||
|
||||
def update_topic(self, project_id="", topic_id="", data=None) -> dict:
|
||||
return self.put(f"/projects/{project_id}/topics/{topic_id}", data=data)
|
||||
|
||||
def delete_topic(self, project_id="", topic_id=""):
|
||||
return self.delete(f"/projects/{project_id}/topics/{topic_id}")
|
||||
|
||||
def get_snippet(self, project_id="", topic_id="") -> str:
|
||||
headers = {
|
||||
"Authorization": "Bearer " + self.foundation_client.get_access_token(),
|
||||
"Content-type": "application/octet-stream",
|
||||
}
|
||||
response = requests.get(
|
||||
f"{self.baseurl}/projects/{project_id}/topics/{topic_id}/snippet",
|
||||
headers=headers,
|
||||
)
|
||||
# TODO: write to tmpdir
|
||||
with open(os.path.join(self.filepath, f"{project_id}_{topic_id}_snippet.txt"), "wb") as f:
|
||||
f.write(response.content.decode("utf-8"))
|
||||
return response.status_code, response.content
|
||||
|
||||
def update_snippet(self, project_id="", topic_id="", files=None, data=None):
|
||||
headers = {
|
||||
"Authorization": "Bearer " + self.foundation_client.get_access_token(),
|
||||
"Content-type": "application/octet-stream",
|
||||
}
|
||||
response = requests.put(
|
||||
f"{self.baseurl}/projects/{project_id}/topics/{topic_id}/snippet",
|
||||
headers=headers,
|
||||
files=files,
|
||||
)
|
||||
return response.status_code
|
||||
|
||||
def get_files_information(self, project_id="") -> list:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/files_information",
|
||||
{
|
||||
"project_id": project_id,
|
||||
},
|
||||
)
|
||||
|
||||
def get_files(self, project_id="", topic_id="") -> list:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}/files",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
},
|
||||
)
|
||||
|
||||
def update_files(
|
||||
self,
|
||||
project_id="",
|
||||
topic_id="",
|
||||
data=None,
|
||||
params=None,
|
||||
):
|
||||
return self.put(
|
||||
f"/projects/{project_id}/topics/{topic_id}/files",
|
||||
data=data,
|
||||
)
|
||||
|
||||
def get_comments(self, project_id="", topic_id="") -> list:
|
||||
pass
|
||||
|
||||
def create_comments(
|
||||
self,
|
||||
project_id="",
|
||||
topic_id="",
|
||||
data=None,
|
||||
params=None,
|
||||
):
|
||||
return self.post(
|
||||
f"/projects/{project_id}/topics/{topic_id}/comments",
|
||||
data=data,
|
||||
)
|
||||
|
||||
def get_comment(self, project_id="", topic_id="", comment_id="") -> dict:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}/comments/{comment_id}",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
"comment_id": comment_id,
|
||||
},
|
||||
)
|
||||
|
||||
def delete_comment(self, project_id="", topic_id="", comment_id=""):
|
||||
return self.delete(f"/projects/{project_id}/topics/{topic_id}/comments/{comment_id}")
|
||||
|
||||
def update_comment(
|
||||
self,
|
||||
project_id="",
|
||||
topic_id="",
|
||||
comment_id="",
|
||||
data=None,
|
||||
):
|
||||
return self.put(
|
||||
f"/projects/{project_id}/topics/{topic_id}/comments/{comment_id}",
|
||||
data=data,
|
||||
)
|
||||
|
||||
def get_viewpoints(self, project_id="", topic_id="") -> list:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}/viewpoints",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
},
|
||||
)
|
||||
|
||||
def create_viewpoints(self, project_id="", topic_id="", data=None):
|
||||
return self.post(
|
||||
f"/projects/{project_id}/topics/{topic_id}/viewpoints",
|
||||
data=data,
|
||||
)
|
||||
|
||||
def get_viewpoint(self, project_id="", topic_id="", viewpoint_id="") -> dict:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
"viewpoint_id": viewpoint_id,
|
||||
},
|
||||
)
|
||||
|
||||
def delete_viewpoint(
|
||||
self,
|
||||
project_id="",
|
||||
topic_id="",
|
||||
viewpoint_id="",
|
||||
):
|
||||
return self.delete(
|
||||
f"/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}",
|
||||
)
|
||||
|
||||
def get_snapshot(self, project_id="", topic_id="", viewpoint_id="") -> str:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/snapshot",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
"viewpoint_id": viewpoint_id,
|
||||
},
|
||||
)
|
||||
|
||||
def get_bitmap(self, project_id="", topic_id="", viewpoint_id="", bitmap_id="") -> str:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/bitmaps/{bitmap_id}",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
"viewpoint_id": viewpoint_id,
|
||||
"bitmap_id": bitmap_id,
|
||||
},
|
||||
)
|
||||
|
||||
def get_selection(self, project_id="", topic_id="", viewpoint_id="") -> dict:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/selection",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
"viewpoint_id": viewpoint_id,
|
||||
},
|
||||
)
|
||||
|
||||
def get_coloring(self, project_id="", topic_id="", viewpoint_id="") -> dict:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/coloring",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
"viewpoint_id": viewpoint_id,
|
||||
},
|
||||
)
|
||||
|
||||
def get_visibility(self, project_id="", topic_id="", viewpoint_id="") -> dict:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/visibility",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
"viewpoint_id": viewpoint_id,
|
||||
},
|
||||
)
|
||||
|
||||
def get_related_topics(self, project_id="", topic_id="") -> list:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}/related_topics",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
},
|
||||
)
|
||||
|
||||
def update_related_topics(
|
||||
self,
|
||||
project_id="",
|
||||
topic_id="",
|
||||
data=None,
|
||||
):
|
||||
return self.put(
|
||||
f"/projects/{project_id}/topics/{topic_id}/related_topics",
|
||||
data=data,
|
||||
)
|
||||
|
||||
def get_document_references(self, project_id="", topic_id="") -> list:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}/document_references",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
},
|
||||
)
|
||||
|
||||
def create_document_reference(
|
||||
self,
|
||||
project_id="",
|
||||
topic_id="",
|
||||
data=None,
|
||||
):
|
||||
return self.post(
|
||||
f"/projects/{project_id}/topics/{topic_id}/document_references",
|
||||
data=data,
|
||||
)
|
||||
|
||||
def update_document_references(
|
||||
self,
|
||||
project_id="",
|
||||
topic_id="",
|
||||
document_reference_id="",
|
||||
data=None,
|
||||
):
|
||||
return self.put(
|
||||
f"/projects/{project_id}/topics/{topic_id}/document_references/{document_reference_id}",
|
||||
data=data,
|
||||
)
|
||||
|
||||
def get_documents(self, project_id="", topic_id="") -> list:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}/documents",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
},
|
||||
)
|
||||
|
||||
def create_document(
|
||||
self,
|
||||
project_id="",
|
||||
topic_id="",
|
||||
guid=None,
|
||||
files=None,
|
||||
data=None,
|
||||
):
|
||||
headers = {
|
||||
"Authorization": "Bearer " + self.foundation_client.get_access_token(),
|
||||
"Content-type": "application/octet-stream",
|
||||
}
|
||||
response = requests.post(
|
||||
f"/projects/{project_id}/topics/{topic_id}/documents",
|
||||
data=data,
|
||||
params={guid},
|
||||
files=files,
|
||||
headers=headers,
|
||||
)
|
||||
return response.status_code
|
||||
|
||||
def get_document(self, project_id="", topic_id="", document_id="") -> str:
|
||||
headers = {
|
||||
"Authorization": "Bearer " + self.foundation_client.get_access_token(),
|
||||
"Content-type": "application/octet-stream",
|
||||
}
|
||||
response = requests.get(
|
||||
f"{self.baseurl}/projects/{project_id}/topics/documents/{document_id}",
|
||||
headers=headers,
|
||||
)
|
||||
with open(os.path.join(self.filepath, f"{project_id}_{topic_id}_{document_id}_document.txt"), "wb") as f:
|
||||
f.write(response.content.decode("utf-8"))
|
||||
return response.status_code, response.content
|
||||
|
||||
def get_topics_events(self, project_id="") -> list:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/events",
|
||||
{
|
||||
"project_id": project_id,
|
||||
},
|
||||
)
|
||||
|
||||
def get_topic_events(self, project_id="", topic_id="") -> list:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}/events",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
},
|
||||
)
|
||||
|
||||
def get_comments_events(self, project_id="") -> list:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/comments/events",
|
||||
{
|
||||
"project_id": project_id,
|
||||
},
|
||||
)
|
||||
|
||||
def get_comment_events(self, project_id="", topic_id="", comment_id="") -> list:
|
||||
return self.get(
|
||||
f"/projects/{project_id}/topics/{topic_id}/comments/{comment_id}/events",
|
||||
{
|
||||
"project_id": project_id,
|
||||
"topic_id": topic_id,
|
||||
"comment_id": comment_id,
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,846 @@
|
||||
|
||||
# BCF - BCF Python library
|
||||
# Copyright (C) 2021 Prabhat Singh <singh01prabhat@gmail.com>
|
||||
#
|
||||
# This file is part of BCF.
|
||||
#
|
||||
# BCF is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BCF 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 Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with BCF. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import uuid
|
||||
import shutil
|
||||
import zipfile
|
||||
import logging
|
||||
import tempfile
|
||||
import bcf.v3.data
|
||||
from datetime import datetime
|
||||
from xml.dom import minidom
|
||||
from xmlschema import XMLSchema
|
||||
from contextlib import contextmanager
|
||||
from shutil import copyfile
|
||||
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
|
||||
@contextmanager
|
||||
def cd(newdir):
|
||||
prevdir = os.getcwd()
|
||||
os.chdir(os.path.expanduser(newdir))
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
os.chdir(prevdir)
|
||||
|
||||
|
||||
class BcfXml:
|
||||
def __init__(self):
|
||||
self.filepath = None
|
||||
self.logger = logging.getLogger("bcfxml")
|
||||
self.author = "john@doe.com"
|
||||
self.project = bcf.v3.data.Project()
|
||||
self.version = "3.0"
|
||||
self.topics = {}
|
||||
|
||||
def new_project(self):
|
||||
self.project.project_id = str(uuid.uuid4())
|
||||
self.project.name = "New Project"
|
||||
self.topics = {}
|
||||
if self.filepath:
|
||||
self.close_project()
|
||||
self.filepath = tempfile.mkdtemp()
|
||||
self.edit_project()
|
||||
self.edit_version()
|
||||
|
||||
def get_project(self, filepath=None):
|
||||
if os.path.isfile(os.path.join(self.filepath, "project.bcfp")):
|
||||
data = self._read_xml("project.bcfp", "project.xsd")
|
||||
self.project.project_id = data["Project"]["@ProjectId"]
|
||||
self.project.name = data["Project"].get("Name")
|
||||
return self.project
|
||||
|
||||
def edit_project(self):
|
||||
self.document = minidom.Document()
|
||||
root = self._create_element(self.document, "ProjectInfo")
|
||||
project = self._create_element(root, "Project", {"ProjectId": self.project.project_id})
|
||||
if self.project.name:
|
||||
self._create_element(project, "Name", text=self.project.name)
|
||||
with open(os.path.join(self.filepath, "project.bcfp"), "wb") as f:
|
||||
f.write(self.document.toprettyxml(encoding="utf-8"))
|
||||
|
||||
def save_project(self, filepath):
|
||||
with cd(self.filepath):
|
||||
zip_file = zipfile.ZipFile(filepath, "w", zipfile.ZIP_DEFLATED)
|
||||
for root, dirs, files in os.walk("./"):
|
||||
for file in files:
|
||||
zip_file.write(os.path.join(root, file))
|
||||
zip_file.close()
|
||||
|
||||
def get_version(self):
|
||||
data = self._read_xml("bcf.version", "version.xsd")
|
||||
self.version = data["@VersionId"]
|
||||
return self.version
|
||||
|
||||
def edit_version(self):
|
||||
self.document = minidom.Document()
|
||||
root = self._create_element(self.document, "Version", {"VersionId": self.version})
|
||||
with open(os.path.join(self.filepath, "bcf.version"), "wb") as f:
|
||||
f.write(self.document.toprettyxml(encoding="utf-8"))
|
||||
|
||||
def get_topics(self):
|
||||
self.topics = {}
|
||||
topics = []
|
||||
subdirs = []
|
||||
for (dirpath, dirnames, filenames) in os.walk(self.filepath):
|
||||
subdirs = dirnames
|
||||
break
|
||||
for subdir in subdirs:
|
||||
try:
|
||||
uuid.UUID(subdir)
|
||||
except ValueError:
|
||||
continue
|
||||
if not os.path.exists(os.path.join(self.filepath, subdir, "markup.bcf")):
|
||||
continue
|
||||
self.topics[subdir] = self.get_topic(subdir)
|
||||
return self.topics
|
||||
|
||||
def get_header(self, guid):
|
||||
data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd")
|
||||
if "Header" not in data:
|
||||
return
|
||||
header = bcf.v3.data.Header()
|
||||
if data["Header"].get("Files"):
|
||||
for item in data["Header"]["Files"].get("File", []):
|
||||
header_file = bcf.v3.data.HeaderFile()
|
||||
optional_keys = {
|
||||
"filename": "Filename",
|
||||
"date": "Date",
|
||||
"reference": "Reference",
|
||||
"ifc_project": "@IfcProject",
|
||||
"ifc_spatial_structure_element": "@IfcSpatialStructureElement",
|
||||
"is_external": "@IsExternal",
|
||||
}
|
||||
for key, value in optional_keys.items():
|
||||
if value in item:
|
||||
setattr(header_file, key, item[value])
|
||||
header.files.append(header_file)
|
||||
self.topics[guid].header = header
|
||||
return header
|
||||
|
||||
def get_topic(self, guid):
|
||||
if guid in self.topics:
|
||||
return self.topics[guid]
|
||||
data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd")
|
||||
topic = bcf.v3.data.Topic()
|
||||
self.topics[guid] = topic
|
||||
|
||||
mandatory_keys = {
|
||||
"guid": "@Guid",
|
||||
"title": "Title",
|
||||
"creation_date": "CreationDate",
|
||||
"creation_author": "CreationAuthor",
|
||||
"topic_status": "@TopicStatus",
|
||||
"topic_type": "@TopicType",
|
||||
}
|
||||
for key, value in mandatory_keys.items():
|
||||
setattr(topic, key, data["Topic"][value])
|
||||
|
||||
optional_keys = {
|
||||
"priority": "Priority",
|
||||
"index": "Index",
|
||||
"modified_date": "ModifiedDate",
|
||||
"modified_author": "ModifiedAuthor",
|
||||
"due_date": "DueDate",
|
||||
"assigned_to": "AssignedTo",
|
||||
"stage": "Stage",
|
||||
"description": "Description",
|
||||
"server_assigned_id": "@ServerAssignedId",
|
||||
}
|
||||
for key, value in optional_keys.items():
|
||||
if value in data["Topic"]:
|
||||
setattr(topic, key, data["Topic"][value])
|
||||
|
||||
if data["Topic"].get("ReferenceLinks"):
|
||||
topic.reference_links.extend(data["Topic"]["ReferenceLinks"].get("ReferenceLink", []))
|
||||
|
||||
if data["Topic"].get("Labels"):
|
||||
topic.labels.extend(data["Topic"]["Labels"].get("Label", []))
|
||||
|
||||
if "BimSnippet" in data["Topic"]:
|
||||
bim_snippet = bcf.v3.data.BimSnippet()
|
||||
keys = {
|
||||
"snippet_type": "@SnippetType",
|
||||
"is_external": "@IsExternal",
|
||||
"reference": "Reference",
|
||||
"reference_schema": "ReferenceSchema",
|
||||
}
|
||||
for key, value in keys.items():
|
||||
if value in data["Topic"]["BimSnippet"]:
|
||||
setattr(bim_snippet, key, data["Topic"]["BimSnippet"][value])
|
||||
topic.bim_snippet = bim_snippet
|
||||
|
||||
if data["Topic"].get("DocumentReferences"):
|
||||
for item in data["Topic"]["DocumentReferences"].get("DocumentReference", []):
|
||||
document_reference = bcf.v3.data.DocumentReference()
|
||||
keys = {
|
||||
"document_guid": "DocumentGuid",
|
||||
"url": "Url",
|
||||
"guid": "@Guid",
|
||||
"description": "Description",
|
||||
}
|
||||
for key, value in keys.items():
|
||||
if value in item:
|
||||
setattr(document_reference, key, item[value])
|
||||
topic.document_references.append(document_reference)
|
||||
|
||||
if data["Topic"].get("RelatedTopics"):
|
||||
for item in data["Topic"]["RelatedTopics"].get("RelatedTopic", []):
|
||||
related_topic = bcf.v3.data.RelatedTopic()
|
||||
related_topic.guid = item["@Guid"]
|
||||
topic.related_topics.append(related_topic)
|
||||
return topic
|
||||
|
||||
def add_topic(self, topic=None):
|
||||
if topic is None:
|
||||
topic = bcf.v3.data.Topic()
|
||||
if not topic.guid:
|
||||
topic.guid = str(uuid.uuid4())
|
||||
if not topic.title:
|
||||
topic.title = "New Topic"
|
||||
os.mkdir(os.path.join(self.filepath, topic.guid))
|
||||
self.edit_topic(topic)
|
||||
return topic
|
||||
|
||||
def edit_topic(self, topic):
|
||||
if not topic.creation_date:
|
||||
topic.creation_date = datetime.utcnow().isoformat()
|
||||
topic.creation_author = self.author
|
||||
else:
|
||||
topic.modified_date = datetime.utcnow().isoformat()
|
||||
topic.modified_author = self.author
|
||||
|
||||
self.document = minidom.Document()
|
||||
root = self._create_element(self.document, "Markup")
|
||||
if topic.header:
|
||||
self.write_header(topic.header, root)
|
||||
|
||||
topic_el = self._create_element(
|
||||
root,
|
||||
"Topic",
|
||||
{
|
||||
"Guid": topic.guid,
|
||||
"ServerAssignedId": topic.server_assigned_id,
|
||||
"TopicType": topic.topic_type,
|
||||
"TopicStatus": topic.topic_status,
|
||||
},
|
||||
)
|
||||
if topic.reference_links:
|
||||
reference_Links_el = self._create_element(topic_el, "ReferenceLinks")
|
||||
for reference_link in topic.reference_links:
|
||||
self._create_element(reference_Links_el, "ReferenceLink", text=reference_link)
|
||||
|
||||
text_map = {
|
||||
"Title": topic.title,
|
||||
"Priority": topic.priority,
|
||||
"Index": topic.index,
|
||||
}
|
||||
for key, value in text_map.items():
|
||||
if value:
|
||||
self._create_element(topic_el, key, text=value)
|
||||
if topic.labels:
|
||||
label_el = self._create_element(topic_el, "Labels")
|
||||
for label in topic.labels:
|
||||
self._create_element(label_el, "Label", text=label)
|
||||
|
||||
text_map = {
|
||||
"CreationDate": topic.creation_date,
|
||||
"CreationAuthor": topic.creation_author,
|
||||
"ModifiedDate": topic.modified_date,
|
||||
"ModifiedAuthor": topic.modified_author,
|
||||
"DueDate": topic.due_date,
|
||||
"AssignedTo": topic.assigned_to,
|
||||
"Stage": topic.stage,
|
||||
"Description": topic.description,
|
||||
}
|
||||
for key, value in text_map.items():
|
||||
if value:
|
||||
self._create_element(topic_el, key, text=value)
|
||||
|
||||
if topic.bim_snippet:
|
||||
bim_snippet = self._create_element(
|
||||
topic_el,
|
||||
"BimSnippet",
|
||||
{
|
||||
"SnippetType": topic.bim_snippet.snippet_type,
|
||||
"IsExternal": topic.bim_snippet.is_external,
|
||||
},
|
||||
)
|
||||
self._create_element(bim_snippet, "Reference", text=topic.bim_snippet.reference)
|
||||
self._create_element(
|
||||
bim_snippet,
|
||||
"ReferenceSchema",
|
||||
text=topic.bim_snippet.reference_schema,
|
||||
)
|
||||
if topic.document_references:
|
||||
reference_el = self._create_element(topic_el, "DocumentReferences")
|
||||
self.write_document_references(topic.document_references, reference_el)
|
||||
if topic.related_topics:
|
||||
related_topic_el = self._create_element(topic_el, "RelatedTopics")
|
||||
for related_topic in topic.related_topics:
|
||||
self._create_element(related_topic_el, "RelatedTopic", {"Guid": related_topic.guid})
|
||||
if topic.comments:
|
||||
comment_el = self._create_element(topic_el, "Comments")
|
||||
self.write_comments(topic.comments, comment_el)
|
||||
if topic.viewpoints:
|
||||
viewpoint_el = self._create_element(topic_el, "Viewpoints")
|
||||
self.write_viewpoints(topic.viewpoints, viewpoint_el, topic)
|
||||
with open(os.path.join(self.filepath, topic.guid, "markup.bcf"), "wb") as f:
|
||||
f.write(self.document.toprettyxml(encoding="utf-8"))
|
||||
|
||||
def write_document_references(self, references, root):
|
||||
for reference in references:
|
||||
document_reference_el = self._create_element(root, "DocumentReference", {"Guid": reference.guid})
|
||||
if reference.document_guid:
|
||||
self._create_element(document_reference_el, "DocumentGuid", text=reference.document_guid)
|
||||
elif reference.url:
|
||||
self._create_element(document_reference_el, "Url", text=reference.url)
|
||||
if reference.description:
|
||||
self._create_element(document_reference_el, "Description", text=reference.description)
|
||||
|
||||
def write_header(self, header, root):
|
||||
if not header or not header.files:
|
||||
return
|
||||
header_el = self._create_element(root, "Header")
|
||||
files_el = self._create_element(header_el, "Files")
|
||||
for f in header.files:
|
||||
file_el = self._create_element(
|
||||
files_el,
|
||||
"File",
|
||||
{
|
||||
"IfcProject": f.ifc_project,
|
||||
"IfcSpatialStructureElement": f.ifc_spatial_structure_element,
|
||||
"IsExternal": f.is_external,
|
||||
},
|
||||
)
|
||||
if f.filename:
|
||||
self._create_element(file_el, "Filename", text=f.filename)
|
||||
if f.date:
|
||||
self._create_element(file_el, "Date", text=f.date)
|
||||
if f.reference:
|
||||
self._create_element(file_el, "Reference", text=f.reference)
|
||||
|
||||
def write_comments(self, comments, root):
|
||||
for comment in comments.values():
|
||||
comment_el = self._create_element(root, "Comment", {"Guid": comment.guid})
|
||||
text_map = {
|
||||
"Date": comment.date,
|
||||
"Author": comment.author,
|
||||
"Comment": comment.comment,
|
||||
"ModifiedDate": comment.modified_date,
|
||||
"ModifiedAuthor": comment.modified_author,
|
||||
}
|
||||
for key, value in text_map.items():
|
||||
if value:
|
||||
self._create_element(comment_el, key, text=value)
|
||||
if comment.viewpoint:
|
||||
self._create_element(comment_el, "Viewpoint", {"Guid": comment.viewpoint.guid})
|
||||
|
||||
def add_comment(self, topic, comment=None):
|
||||
if comment is None:
|
||||
comment = bcf.v3.data.Comment()
|
||||
if not comment.guid:
|
||||
comment.guid = str(uuid.uuid4())
|
||||
if not comment.comment:
|
||||
comment.comment = "'Free software' is a matter of liberty, not price. To understand the concept, you should think of 'free' as in 'free speech,' not as in 'free beer'."
|
||||
topic.comments[comment.guid] = comment
|
||||
self.edit_comment(comment, topic)
|
||||
|
||||
def edit_comment(self, comment, topic):
|
||||
if not comment.date:
|
||||
comment.date = datetime.utcnow().isoformat()
|
||||
comment.author = self.author
|
||||
else:
|
||||
comment.modified_date = datetime.utcnow().isoformat()
|
||||
comment.modified_author = self.author
|
||||
self.edit_topic(topic)
|
||||
|
||||
def delete_comment(self, guid, topic):
|
||||
if guid in topic.comments:
|
||||
del topic.comments[guid]
|
||||
self.edit_topic(topic)
|
||||
|
||||
def delete_topic(self, guid):
|
||||
if guid in self.topics:
|
||||
del self.topics[guid]
|
||||
shutil.rmtree(os.path.join(self.filepath, guid))
|
||||
|
||||
def write_viewpoints(self, viewpoints, root, topic):
|
||||
for viewpoint in viewpoints.values():
|
||||
viewpoint_el = self._create_element(root, "ViewPoint", {"Guid": viewpoint.guid})
|
||||
text_map = {
|
||||
"Viewpoint": viewpoint.viewpoint,
|
||||
"Snapshot": viewpoint.snapshot,
|
||||
"Index": viewpoint.index,
|
||||
}
|
||||
for key, value in text_map.items():
|
||||
if value:
|
||||
self._create_element(viewpoint_el, key, text=value)
|
||||
self.write_viewpoint(viewpoint, topic)
|
||||
|
||||
def write_viewpoint(self, viewpoint, topic):
|
||||
document = minidom.Document()
|
||||
root = self._create_element(document, "VisualizationInfo", {"Guid": viewpoint.guid})
|
||||
self.write_viewpoint_components(viewpoint, root)
|
||||
self.write_viewpoint_orthogonal_camera(viewpoint, root)
|
||||
self.write_viewpoint_perspective_camera(viewpoint, root)
|
||||
self.write_viewpoint_lines(viewpoint, root)
|
||||
self.write_viewpoint_clipping_planes(viewpoint, root)
|
||||
self.write_viewpoint_bitmaps(viewpoint, root)
|
||||
with open(os.path.join(self.filepath, topic.guid, viewpoint.viewpoint), "wb") as f:
|
||||
f.write(document.toprettyxml(encoding="utf-8"))
|
||||
|
||||
def write_viewpoint_components(self, viewpoint, parent):
|
||||
if not viewpoint.components:
|
||||
return
|
||||
components_el = self._create_element(parent, "Components")
|
||||
if viewpoint.components.selection:
|
||||
selection_el = self._create_element(components_el, "Selection")
|
||||
for selection in viewpoint.components.selection:
|
||||
self.write_component(selection, selection_el)
|
||||
if viewpoint.components.visibility:
|
||||
visibility = self._create_element(
|
||||
components_el,
|
||||
"Visibility",
|
||||
{"DefaultVisibility": viewpoint.components.visibility.default_visibility},
|
||||
)
|
||||
if viewpoint.components.visibility.view_setup_hints:
|
||||
view_setup_hints = self._create_element(
|
||||
visibility,
|
||||
"ViewSetupHints",
|
||||
{
|
||||
"SpacesVisible": viewpoint.components.visibility.view_setup_hints.spaces_visible,
|
||||
"SpaceBoundariesVisible": viewpoint.components.visibility.view_setup_hints.space_boundaries_visible,
|
||||
"OpeningsVisible": viewpoint.components.visibility.view_setup_hints.openings_visible,
|
||||
},
|
||||
)
|
||||
if viewpoint.components.visibility.exceptions:
|
||||
exceptions_el = self._create_element(visibility, "Exceptions")
|
||||
for exception in viewpoint.components.visibility.exceptions:
|
||||
self.write_component(exception, exceptions_el)
|
||||
if viewpoint.components.coloring:
|
||||
coloring_el = self._create_element(components_el, "Coloring")
|
||||
for color in viewpoint.components.coloring:
|
||||
color_el = self._create_element(coloring_el, "Color", {"Color": color.color})
|
||||
component_el = self._create_element(color_el, "Components")
|
||||
for component in color.components:
|
||||
self.write_component(component, component_el)
|
||||
|
||||
def write_viewpoint_orthogonal_camera(self, viewpoint, parent):
|
||||
if not viewpoint.orthogonal_camera:
|
||||
return
|
||||
camera = viewpoint.orthogonal_camera
|
||||
camera_el = self._create_element(parent, "OrthogonalCamera")
|
||||
camera_view_point = self._create_element(camera_el, "CameraViewPoint")
|
||||
self.write_vector(camera_view_point, camera.camera_view_point)
|
||||
camera_direction = self._create_element(camera_el, "CameraDirection")
|
||||
self.write_vector(camera_direction, camera.camera_direction)
|
||||
camera_up_vector = self._create_element(camera_el, "CameraUpVector")
|
||||
self.write_vector(camera_up_vector, camera.camera_up_vector)
|
||||
self._create_element(camera_el, "ViewToWorldScale", text=camera.view_to_world_scale)
|
||||
self._create_element(camera_el, "AspectRatio", text=camera.aspect_ratio)
|
||||
|
||||
def write_viewpoint_perspective_camera(self, viewpoint, parent):
|
||||
if not viewpoint.perspective_camera:
|
||||
return
|
||||
camera = viewpoint.perspective_camera
|
||||
camera_el = self._create_element(parent, "PerspectiveCamera")
|
||||
camera_view_point = self._create_element(camera_el, "CameraViewPoint")
|
||||
self.write_vector(camera_view_point, camera.camera_view_point)
|
||||
camera_direction = self._create_element(camera_el, "CameraDirection")
|
||||
self.write_vector(camera_direction, camera.camera_direction)
|
||||
camera_up_vector = self._create_element(camera_el, "CameraUpVector")
|
||||
self.write_vector(camera_up_vector, camera.camera_up_vector)
|
||||
self._create_element(camera_el, "FieldOfView", text=camera.field_of_view)
|
||||
self._create_element(camera_el, "AspectRatio", text=camera.aspect_ratio)
|
||||
|
||||
def write_viewpoint_lines(self, viewpoint, parent):
|
||||
if not viewpoint.lines:
|
||||
return
|
||||
lines_el = self._create_element(parent, "Lines")
|
||||
for line in viewpoint.lines:
|
||||
line_el = self._create_element(lines_el, "Line")
|
||||
start_point_el = self._create_element(line_el, "StartPoint")
|
||||
self.write_vector(start_point_el, line.start_point)
|
||||
end_point_el = self._create_element(line_el, "EndPoint")
|
||||
self.write_vector(end_point_el, line.end_point)
|
||||
|
||||
def write_viewpoint_clipping_planes(self, viewpoint, parent):
|
||||
if not viewpoint.clipping_planes:
|
||||
return
|
||||
planes_el = self._create_element(parent, "ClippingPlanes")
|
||||
for plane in viewpoint.clipping_planes:
|
||||
plane_el = self._create_element(planes_el, "ClippingPlane")
|
||||
location_el = self._create_element(plane_el, "Location")
|
||||
self.write_vector(location_el, plane.location)
|
||||
direction_el = self._create_element(plane_el, "Direction")
|
||||
self.write_vector(direction_el, plane.direction)
|
||||
|
||||
def write_viewpoint_bitmaps(self, viewpoint, parent):
|
||||
if not viewpoint.bitmaps:
|
||||
return
|
||||
bitmaps_el = self._create_element(parent, "Bitmaps")
|
||||
for bitmap in viewpoint.bitmaps:
|
||||
bitmap_el = self._create_element(bitmaps_el, "Bitmap")
|
||||
|
||||
text_map = {"Format": bitmap.bitmap_format, "Reference": bitmap.reference}
|
||||
for key, value in text_map.items():
|
||||
self._create_element(bitmap_el, key, text=value)
|
||||
|
||||
location_el = self._create_element(bitmap_el, "Location")
|
||||
self.write_vector(location_el, bitmap.location)
|
||||
normal_el = self._create_element(bitmap_el, "Normal")
|
||||
self.write_vector(normal_el, bitmap.normal)
|
||||
up_el = self._create_element(bitmap_el, "Up")
|
||||
self.write_vector(up_el, bitmap.up)
|
||||
|
||||
self._create_element(bitmap_el, "Height", text=bitmap.height)
|
||||
|
||||
def write_vector(self, parent, from_obj):
|
||||
self._create_element(parent, "X", text=from_obj.x)
|
||||
self._create_element(parent, "Y", text=from_obj.y)
|
||||
self._create_element(parent, "Z", text=from_obj.z)
|
||||
|
||||
def write_component(self, data, parent):
|
||||
component_el = self._create_element(parent, "Component", {"IfcGuid": data.ifc_guid})
|
||||
text_map = {
|
||||
"OriginatingSystem": data.originating_system,
|
||||
"AuthoringToolId": data.authoring_tool_id,
|
||||
}
|
||||
for key, value in text_map.items():
|
||||
if value:
|
||||
self._create_element(component_el, key, text=value)
|
||||
|
||||
def add_viewpoint(self, topic, viewpoint=None):
|
||||
if not viewpoint:
|
||||
viewpoint = bcf.v3.data.Viewpoint()
|
||||
if not viewpoint.guid:
|
||||
viewpoint.guid = str(uuid.uuid4())
|
||||
if not viewpoint.viewpoint:
|
||||
viewpoint.viewpoint = f"{viewpoint.guid}.bcfv"
|
||||
if viewpoint.snapshot:
|
||||
topic_filepath = os.path.join(self.filepath, topic.guid)
|
||||
filepath = os.path.join(topic_filepath, viewpoint.snapshot)
|
||||
if not os.path.exists(filepath):
|
||||
filename = viewpoint.guid + os.path.splitext(viewpoint.snapshot)[-1]
|
||||
copyfile(viewpoint.snapshot, os.path.join(topic_filepath, filename))
|
||||
viewpoint.snapshot = filename
|
||||
topic.viewpoints[viewpoint.guid] = viewpoint
|
||||
self.edit_topic(topic)
|
||||
|
||||
def delete_viewpoint(self, guid, topic):
|
||||
if guid not in topic.viewpoints:
|
||||
return
|
||||
viewpoint = topic.viewpoints[guid]
|
||||
if viewpoint.snapshot:
|
||||
filepath = os.path.join(self.filepath, topic.guid, viewpoint.snapshot)
|
||||
if os.path.exists(filepath):
|
||||
os.remove(filepath)
|
||||
if viewpoint.viewpoint:
|
||||
filepath = os.path.join(self.filepath, topic.guid, viewpoint.viewpoint)
|
||||
if os.path.exists(filepath):
|
||||
os.remove(filepath)
|
||||
for bitmap in viewpoint.bitmaps:
|
||||
if not bitmap.reference:
|
||||
continue
|
||||
filepath = os.path.join(self.filepath, topic.guid, bitmap.reference)
|
||||
if os.path.exists(filepath):
|
||||
os.remove(filepath)
|
||||
del topic.viewpoints[guid]
|
||||
self.edit_topic(topic)
|
||||
|
||||
def delete_file(self, topic, index):
|
||||
if not topic.header:
|
||||
return
|
||||
f = topic.header.files.pop(index)
|
||||
filepath = os.path.join(self.filepath, topic.guid, f.reference)
|
||||
if not f.is_external and os.path.exists(filepath):
|
||||
os.remove(filepath)
|
||||
self.edit_topic(topic)
|
||||
|
||||
def delete_bim_snippet(self, topic):
|
||||
if not topic.bim_snippet:
|
||||
return
|
||||
if topic.bim_snippet.reference and not topic.bim_snippet.is_external:
|
||||
filepath = os.path.join(self.filepath, topic.guid, topic.bim_snippet.reference)
|
||||
if os.path.exists(filepath):
|
||||
os.remove(filepath)
|
||||
topic.bim_snippet = None
|
||||
self.edit_topic(topic)
|
||||
|
||||
def delete_document_reference(self, topic, index):
|
||||
document_reference = topic.document_references[index]
|
||||
if document_reference.referenced_document and not document_reference.is_external:
|
||||
filepath = os.path.join(self.filepath, topic.guid, document_reference.referenced_document)
|
||||
if os.path.exists(filepath):
|
||||
os.remove(filepath)
|
||||
del topic.document_references[index]
|
||||
self.edit_topic(topic)
|
||||
|
||||
def add_document_reference(self, topic, document_reference):
|
||||
if os.path.exists(document_reference.referenced_document):
|
||||
topic_filepath = os.path.join(self.filepath, topic.guid)
|
||||
filename = os.path.basename(document_reference.referenced_document)
|
||||
copyfile(
|
||||
document_reference.referenced_document,
|
||||
os.path.join(topic_filepath, filename),
|
||||
)
|
||||
document_reference.referenced_document = filename
|
||||
document_reference.is_external = False
|
||||
else:
|
||||
document_reference.is_external = True
|
||||
if not document_reference.guid:
|
||||
document_reference.guid = str(uuid.uuid4())
|
||||
topic.document_references.append(document_reference)
|
||||
self.edit_topic(topic)
|
||||
|
||||
def add_bim_snippet(self, topic, bim_snippet):
|
||||
if topic.bim_snippet:
|
||||
self.delete_bim_snippet(topic)
|
||||
if os.path.exists(bim_snippet.reference):
|
||||
topic_filepath = os.path.join(self.filepath, topic.guid)
|
||||
filename = os.path.basename(bim_snippet.reference)
|
||||
copyfile(bim_snippet.reference, os.path.join(topic_filepath, filename))
|
||||
bim_snippet.reference = filename
|
||||
bim_snippet.is_external = False
|
||||
else:
|
||||
bim_snippet.is_external = True
|
||||
topic.bim_snippet = bim_snippet
|
||||
self.edit_topic(topic)
|
||||
|
||||
def add_file(self, topic, header_file):
|
||||
if os.path.exists(header_file.reference):
|
||||
topic_filepath = os.path.join(self.filepath, topic.guid)
|
||||
header_file.filename = os.path.basename(header_file.reference)
|
||||
copyfile(
|
||||
header_file.reference,
|
||||
os.path.join(topic_filepath, header_file.filename),
|
||||
)
|
||||
header_file.reference = header_file.filename
|
||||
header_file.is_external = False
|
||||
header_file.date = datetime.utcnow().isoformat()
|
||||
if not topic.header:
|
||||
topic.header = bcf.v3.data.Header()
|
||||
topic.header.files.append(header_file)
|
||||
self.edit_topic(topic)
|
||||
|
||||
def get_comments(self, guid):
|
||||
comments = {}
|
||||
if "Comments" not in data["Topics"]:
|
||||
return comments
|
||||
data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd")
|
||||
for item in data["Topic"]["Comments"].get("Comment", []):
|
||||
comment = bcf.v3.data.Comment()
|
||||
mandatory_keys = {
|
||||
"guid": "@Guid",
|
||||
"date": "Date",
|
||||
"author": "Author",
|
||||
}
|
||||
for key, value in mandatory_keys.items():
|
||||
setattr(comment, key, item[value])
|
||||
optional_keys = {
|
||||
"comment": "Comment",
|
||||
"modified_date": "ModifiedDate",
|
||||
"modified_author": "ModifiedAuthor",
|
||||
}
|
||||
for key, value in optional_keys.items():
|
||||
if value in item:
|
||||
setattr(comment, key, item[value])
|
||||
if "Viewpoint" in item:
|
||||
viewpoint = bcf.v3.data.Viewpoint()
|
||||
viewpoint.guid = item["Viewpoint"]["@Guid"]
|
||||
comment.viewpoint = viewpoint
|
||||
comments[comment.guid] = comment
|
||||
self.topics[guid].comments = comments
|
||||
return comments
|
||||
|
||||
def get_viewpoints(self, guid):
|
||||
viewpoints = {}
|
||||
if "Viewpoints" not in data["Topic"]:
|
||||
return viewpoints
|
||||
data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd")
|
||||
for item in data["Topic"]["Viewpoints"]:
|
||||
viewpoint = self.get_viewpoint(item, guid)
|
||||
viewpoints[viewpoint.guid] = viewpoint
|
||||
self.topics[guid].viewpoints = viewpoints
|
||||
return viewpoints
|
||||
|
||||
def get_viewpoint(self, data, topic_guid):
|
||||
viewpoint = bcf.v3.data.Viewpoint()
|
||||
viewpoint.guid = data["@Guid"]
|
||||
optional_keys = {
|
||||
"viewpoint": "Viewpoint",
|
||||
"snapshot": "Snapshot",
|
||||
"index": "Index",
|
||||
}
|
||||
for key, value in optional_keys.items():
|
||||
if value in data:
|
||||
setattr(viewpoint, key, data[value])
|
||||
visinfo = self._read_xml(os.path.join(topic_guid, viewpoint.viewpoint), "visinfo.xsd")
|
||||
viewpoint.components = self.get_viewpoint_components(visinfo)
|
||||
viewpoint.orthogonal_camera = self.get_viewpoint_orthogonal_camera(visinfo)
|
||||
viewpoint.perspective_camera = self.get_viewpoint_perspective_camera(visinfo)
|
||||
viewpoint.lines = self.get_viewpoint_lines(visinfo)
|
||||
viewpoint.clipping_planes = self.get_viewpoint_clipping_planes(visinfo)
|
||||
viewpoint.bitmaps = self.get_viewpoint_bitmaps(visinfo)
|
||||
return viewpoint
|
||||
|
||||
def get_viewpoint_components(self, visinfo):
|
||||
if "Components" not in visinfo:
|
||||
return None
|
||||
components = bcf.v3.data.Components()
|
||||
data = visinfo["Components"]
|
||||
if "Selection" in data and "Component" in data["Selection"]:
|
||||
for item in data["Selection"].get("Component", []):
|
||||
components.selection.append(self.get_component(item))
|
||||
if "Visibility" in data:
|
||||
component_visibility = bcf.v3.data.ComponentVisibility()
|
||||
if "@DefaultVisibility" in data["Visibility"]:
|
||||
component_visibility.default_visibility = data["Visibility"]["@DefaultVisibility"]
|
||||
if "Exceptions" in data["Visibility"] and "Component" in data["Visibility"]["Exceptions"]:
|
||||
for item in data["Visibility"]["Exceptions"]["Component"]:
|
||||
component_visibility.exceptions.append(self.get_component(item))
|
||||
if "ViewSetupHints" in data["Visibility"]:
|
||||
view_setup_hints = bcf.v3.data.ViewSetupHints()
|
||||
optional_keys = {
|
||||
"spaces_visible": "@SpacesVisible",
|
||||
"space_boundaries_visible": "@SpaceBoundariesVisible",
|
||||
"openings_visible": "@OpeningsVisible",
|
||||
}
|
||||
for key, value in optional_keys.items():
|
||||
if value in data["Visibility"]["ViewSetupHints"]:
|
||||
setattr(view_setup_hints, key, data["Visibility"]["ViewSetupHints"][value])
|
||||
component_visibility.view_setup_hints = view_setup_hints
|
||||
components.visibility = component_visibility
|
||||
if "Coloring" in data and "Color" in data["Coloring"]:
|
||||
for item in data["Coloring"]["Color"]:
|
||||
color = bcf.v3.data.Color()
|
||||
color.color = item["@Color"]
|
||||
for item2 in item["Components"]["Component"]:
|
||||
color.components.append(self.get_component(item2))
|
||||
components.coloring.append(color)
|
||||
return components
|
||||
|
||||
def get_viewpoint_orthogonal_camera(self, visinfo):
|
||||
if "OrthogonalCamera" not in visinfo:
|
||||
return None
|
||||
camera = bcf.v3.data.OrthogonalCamera()
|
||||
data = visinfo["OrthogonalCamera"]
|
||||
self.set_vector(camera.camera_view_point, data["CameraViewPoint"])
|
||||
self.set_vector(camera.camera_direction, data["CameraDirection"])
|
||||
self.set_vector(camera.camera_up_vector, data["CameraUpVector"])
|
||||
camera.view_to_world_scale = data["ViewToWorldScale"]
|
||||
camera.aspect_ratio = data["AspectRatio"]
|
||||
return camera
|
||||
|
||||
def get_viewpoint_perspective_camera(self, visinfo):
|
||||
if "PerspectiveCamera" not in visinfo:
|
||||
return None
|
||||
camera = bcf.v3.data.PerspectiveCamera()
|
||||
data = visinfo["PerspectiveCamera"]
|
||||
self.set_vector(camera.camera_view_point, data["CameraViewPoint"])
|
||||
self.set_vector(camera.camera_direction, data["CameraDirection"])
|
||||
self.set_vector(camera.camera_up_vector, data["CameraUpVector"])
|
||||
camera.field_of_view = data["FieldOfView"]
|
||||
camera.aspect_ratio = data["AspectRatio"]
|
||||
return camera
|
||||
|
||||
def get_viewpoint_lines(self, visinfo):
|
||||
if "Lines" not in visinfo:
|
||||
return []
|
||||
lines = []
|
||||
for item in visinfo["Lines"].get("Line", []):
|
||||
line = bcf.v3.data.Line()
|
||||
self.set_vector(line.start_point, item["StartPoint"])
|
||||
self.set_vector(line.end_point, item["EndPoint"])
|
||||
lines.append(line)
|
||||
return lines
|
||||
|
||||
def get_viewpoint_clipping_planes(self, visinfo):
|
||||
if "ClippingPlanes" not in visinfo:
|
||||
return []
|
||||
planes = []
|
||||
for item in visinfo["ClippingPlanes"]["ClippingPlane"]:
|
||||
plane = bcf.v3.data.ClippingPlane()
|
||||
self.set_vector(plane.location, item["Location"])
|
||||
self.set_vector(plane.direction, item["Direction"])
|
||||
planes.append(plane)
|
||||
return planes
|
||||
|
||||
def get_viewpoint_bitmaps(self, visinfo):
|
||||
if "Bitmaps" not in visinfo:
|
||||
return []
|
||||
bitmaps = []
|
||||
for item in visinfo["Bitmaps"].get("Bitmap"):
|
||||
bitmap = bcf.v3.data.Bitmap()
|
||||
bitmap.reference = item["Reference"]
|
||||
bitmap.bitmap_format = item["Format"].upper()
|
||||
self.set_vector(bitmap.location, item["Location"])
|
||||
self.set_vector(bitmap.normal, item["Normal"])
|
||||
self.set_vector(bitmap.up, item["Up"])
|
||||
bitmap.height = item["Height"]
|
||||
bitmaps.append(bitmap)
|
||||
return bitmaps
|
||||
|
||||
def set_vector(self, to_obj, from_xml):
|
||||
to_obj.x = from_xml["X"]
|
||||
to_obj.y = from_xml["Y"]
|
||||
to_obj.z = from_xml["Z"]
|
||||
|
||||
def get_component(self, data):
|
||||
component = bcf.v3.data.Component()
|
||||
optional_keys = {
|
||||
"originating_system": "OriginatingSystem",
|
||||
"authoring_tool_id": "AuthoringToolId",
|
||||
"ifc_guid": "@IfcGuid",
|
||||
}
|
||||
for key, value in optional_keys.items():
|
||||
if value in data:
|
||||
setattr(component, key, data[value])
|
||||
return component
|
||||
|
||||
def close_project(self):
|
||||
shutil.rmtree(self.filepath)
|
||||
|
||||
def _read_xml(self, filename, xsd):
|
||||
schema = XMLSchema(os.path.join(cwd, "xsd", xsd))
|
||||
filepath = os.path.join(self.filepath, filename)
|
||||
(data, errors) = schema.to_dict(filepath, validation="lax")
|
||||
for error in errors:
|
||||
self.logger.error(error)
|
||||
return data
|
||||
|
||||
def _create_element(self, parent, name, attributes={}, text=None):
|
||||
element = self.document.createElement(name)
|
||||
for key, value in attributes.items():
|
||||
if isinstance(value, bool):
|
||||
element.setAttribute(key, str(value).lower())
|
||||
elif value:
|
||||
element.setAttribute(key, value)
|
||||
if text is not None:
|
||||
text = self.document.createTextNode(str(text))
|
||||
element.appendChild(text)
|
||||
parent.appendChild(element)
|
||||
return element
|
||||
|
||||
def __del__(self):
|
||||
self.close_project()
|
||||
@@ -0,0 +1,200 @@
|
||||
|
||||
# BCF - BCF Python library
|
||||
# Copyright (C) 2021 Prabhat Singh <singh01prabhat@gmail.com>
|
||||
#
|
||||
# This file is part of BCF.
|
||||
#
|
||||
# BCF is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BCF 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 Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with BCF. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
class Project:
|
||||
def __init__(self):
|
||||
self.project_id = ""
|
||||
self.name = ""
|
||||
|
||||
|
||||
class BimSnippet:
|
||||
def __init__(self):
|
||||
self.snippet_type = None
|
||||
self.is_external = False
|
||||
self.reference = None
|
||||
self.reference_schema = None
|
||||
|
||||
|
||||
class DocumentReference:
|
||||
def __init__(self):
|
||||
self.description = None
|
||||
self.document_guid = None
|
||||
self.url = None
|
||||
self.guid = None
|
||||
|
||||
|
||||
class RelatedTopic:
|
||||
def __init__(self):
|
||||
self.guid = None
|
||||
|
||||
|
||||
class HeaderFile:
|
||||
def __init__(self):
|
||||
self.file_name = ""
|
||||
self.date = None
|
||||
self.reference = ""
|
||||
self.ifc_project = None
|
||||
self.ifc_spatial_structure_element = None
|
||||
self.is_external = True
|
||||
|
||||
|
||||
class Header:
|
||||
def __init__(self):
|
||||
self.files = []
|
||||
|
||||
|
||||
class Topic:
|
||||
def __init__(self):
|
||||
self.reference_links = []
|
||||
self.title = ""
|
||||
self.priority = None
|
||||
self.index = None # Deprecated, stored, but ignored
|
||||
self.labels = []
|
||||
self.creation_date = None
|
||||
self.creation_author = None
|
||||
self.modified_date = None
|
||||
self.modified_author = None
|
||||
self.due_date = None
|
||||
self.assigned_to = None
|
||||
self.stage = None
|
||||
self.description = None
|
||||
self.bim_snippet = None
|
||||
self.document_references = []
|
||||
self.related_topics = []
|
||||
self.topic_status = None
|
||||
self.topic_type = None
|
||||
self.guid = None
|
||||
|
||||
self.header = None
|
||||
self.comments = {}
|
||||
self.viewpoints = {}
|
||||
self.server_assigned_id = ""
|
||||
|
||||
|
||||
class Comment:
|
||||
def __init__(self):
|
||||
self.guid = None
|
||||
self.date = None
|
||||
self.author = ""
|
||||
self.comment = ""
|
||||
self.viewpoint = None
|
||||
self.modified_date = None
|
||||
self.modified_author = ""
|
||||
|
||||
|
||||
class ViewSetupHints:
|
||||
def __init__(self):
|
||||
self.spaces_visible = False
|
||||
self.space_boundaries_visible = False
|
||||
self.openings_visible = False
|
||||
|
||||
|
||||
class Component:
|
||||
def __init__(self):
|
||||
self.originating_system = None
|
||||
self.authoring_tool_id = None
|
||||
self.ifc_guid = None
|
||||
|
||||
|
||||
class ComponentVisibility:
|
||||
def __init__(self):
|
||||
self.exceptions = []
|
||||
self.default_visibility = False
|
||||
self.view_setup_hints = None
|
||||
|
||||
|
||||
class Color:
|
||||
def __init__(self):
|
||||
self.color = None
|
||||
self.components = []
|
||||
|
||||
|
||||
class Components:
|
||||
def __init__(self):
|
||||
|
||||
self.selection = []
|
||||
self.visibility = None
|
||||
self.coloring = []
|
||||
|
||||
|
||||
class Point:
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.z = 0
|
||||
|
||||
|
||||
class Direction(Point):
|
||||
pass
|
||||
|
||||
|
||||
class OrthogonalCamera:
|
||||
def __init__(self):
|
||||
self.camera_view_point = Point()
|
||||
self.camera_direction = Direction()
|
||||
self.camera_up_vector = Direction()
|
||||
self.view_to_world_scale = 1.0
|
||||
self.aspect_ratio = 1.0
|
||||
|
||||
|
||||
class PerspectiveCamera:
|
||||
def __init__(self):
|
||||
self.camera_view_point = Point()
|
||||
self.camera_direction = Direction()
|
||||
self.camera_up_vector = Direction()
|
||||
self.field_of_view = 60.0
|
||||
self.aspect_ratio = 1.0
|
||||
|
||||
|
||||
class Line:
|
||||
def __init__(self):
|
||||
self.start_point = Point()
|
||||
self.end_point = Point()
|
||||
|
||||
|
||||
class ClippingPlane:
|
||||
def __init__(self):
|
||||
self.location = Point()
|
||||
self.direction = Direction()
|
||||
|
||||
|
||||
class Bitmap:
|
||||
def __init__(self):
|
||||
self.reference = "" # Only in BCF-XML
|
||||
self.bitmap_data = None # Only in BCF-API
|
||||
self.bitmap_format = "PNG" # Enum of png or jpg
|
||||
self.location = Point()
|
||||
self.normal = Direction()
|
||||
self.up = Direction()
|
||||
self.height = 1.0
|
||||
|
||||
|
||||
class Viewpoint:
|
||||
def __init__(self):
|
||||
self.guid = None
|
||||
self.viewpoint = None
|
||||
self.snapshot = None
|
||||
self.index = None
|
||||
|
||||
self.components = None # It's not a list, despite the plural name
|
||||
self.orthogonal_camera = None
|
||||
self.perspective_camera = None
|
||||
self.lines = []
|
||||
self.clipping_planes = []
|
||||
self.bitmaps = []
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:include schemaLocation="shared-types.xsd"/>
|
||||
|
||||
<xs:element name="DocumentInfo">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Documents" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Document" type="Document" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:complexType name="Document">
|
||||
<xs:sequence>
|
||||
<!-- Filename of the document with the file extension. Not used to store the file in the BCF -->
|
||||
<xs:element name="Filename" type="NonEmptyOrBlankString"/>
|
||||
<!-- Human readable description of the document -->
|
||||
<xs:element name="Description" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attributeGroup ref="DocumentAttributes"/>
|
||||
</xs:complexType>
|
||||
<xs:attributeGroup name="DocumentAttributes">
|
||||
<!-- Guid of the document. Must match the filename in the BCF -->
|
||||
<xs:attribute name="Guid" type="Guid" use="required"/>
|
||||
</xs:attributeGroup>
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:include schemaLocation="shared-types.xsd"/>
|
||||
|
||||
<xs:element name="Extensions">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="TopicTypes" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="TopicType" type="NonEmptyOrBlankString" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="TopicStatuses" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="TopicStatus" type="NonEmptyOrBlankString" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Priorities" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Priority" type="NonEmptyOrBlankString" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="TopicLabels" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="TopicLabel" type="NonEmptyOrBlankString" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Users" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="User" type="NonEmptyOrBlankString" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="SnippetTypes" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="SnippetType" type="NonEmptyOrBlankString" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Stages" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Stage" type="NonEmptyOrBlankString" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,174 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:include schemaLocation="shared-types.xsd"/>
|
||||
<xs:element name="Markup">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Header" type="Header" minOccurs="0"/>
|
||||
<xs:element name="Topic" type="Topic"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:complexType name="Header">
|
||||
<xs:sequence>
|
||||
<xs:element name="Files" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="File" type="File" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<!-- ISG Jira issue BCF-9. Add support for several viewpoints and snapshots per issue -->
|
||||
<xs:complexType name="ViewPoint">
|
||||
<xs:sequence>
|
||||
<!-- viewpoint file (xml) -->
|
||||
<xs:element name="Viewpoint" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
<!-- the snapshot png -->
|
||||
<xs:element name="Snapshot" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
<!-- the viewpoint index (sort order) -->
|
||||
<xs:element name="Index" type="xs:int" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Guid" type="Guid" use="required"/>
|
||||
<!-- Guid of the viewpoint -->
|
||||
</xs:complexType>
|
||||
<!-- BimSnippet -->
|
||||
<xs:complexType name="BimSnippet">
|
||||
<xs:sequence>
|
||||
<!--
|
||||
Name of the file in the topic folder containing the snippet or a URL.
|
||||
E.G.- Expresscode containing p.e Issue, Request
|
||||
// Maybe some header infos ?? // IfcEntites // Geometry
|
||||
-->
|
||||
<!-- Reference (name) to the snippet file -->
|
||||
<xs:element name="Reference" type="NonEmptyOrBlankString"/>
|
||||
<xs:element name="ReferenceSchema" type="NonEmptyOrBlankString"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="SnippetType" type="NonEmptyOrBlankString" use="required"/>
|
||||
<xs:attribute name="IsExternal" type="xs:boolean" default="false"/>
|
||||
<!-- This flag is true when the reference is a URL pointing outside of the BCF file-->
|
||||
</xs:complexType>
|
||||
<xs:complexType name="Topic">
|
||||
<xs:sequence>
|
||||
<xs:element name="ReferenceLinks" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="ReferenceLink" type="NonEmptyOrBlankString" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Title" type="NonEmptyOrBlankString"/>
|
||||
<xs:element name="Priority" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
<!-- ISG Jira issue BCF-8 Add a way save order the topics -->
|
||||
<!-- This property is deprecated and will be removed in a future release -->
|
||||
<xs:element name="Index" type="xs:int" minOccurs="0"/>
|
||||
<xs:element name="Labels" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Label" type="NonEmptyOrBlankString" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="CreationDate" type="xs:dateTime"/>
|
||||
<xs:element name="CreationAuthor" type="NonEmptyOrBlankString"/>
|
||||
<xs:element name="ModifiedDate" type="xs:dateTime" minOccurs="0"/>
|
||||
<xs:element name="ModifiedAuthor" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
<xs:element name="DueDate" type="xs:dateTime" minOccurs="0"/>
|
||||
<xs:element name="AssignedTo" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
<xs:element name="Stage" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
<xs:element name="Description" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
<xs:element name="BimSnippet" type="BimSnippet" minOccurs="0"/>
|
||||
<xs:element name="DocumentReferences" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="DocumentReference" type="DocumentReference" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="RelatedTopics" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="RelatedTopic" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Guid" type="Guid" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Comments" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Comment" type="Comment" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<!-- ISG Jira issue BCF-9. Add support for several viewpoints and snapshots per issue -->
|
||||
<xs:element name="Viewpoints" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="ViewPoint" type="ViewPoint" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Guid" type="Guid" use="required"/>
|
||||
<xs:attribute name="ServerAssignedId" type="NonEmptyOrBlankString" use="optional"/>
|
||||
<xs:attribute name="TopicType" type="NonEmptyOrBlankString" use="required"/>
|
||||
<xs:attribute name="TopicStatus" type="NonEmptyOrBlankString" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="File">
|
||||
<xs:sequence>
|
||||
<xs:element name="Filename" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
<xs:element name="Date" type="xs:dateTime" minOccurs="0"/>
|
||||
<!-- Reference (URL) of the file -->
|
||||
<xs:element name="Reference" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attributeGroup ref="FileAttributes"/>
|
||||
</xs:complexType>
|
||||
<xs:attributeGroup name="FileAttributes">
|
||||
<xs:attribute name="IfcProject" type="IfcGuid" use="optional"/>
|
||||
<xs:attribute name="IfcSpatialStructureElement" type="IfcGuid" use="optional"/>
|
||||
<xs:attribute name="IsExternal" type="xs:boolean" default="true"/>
|
||||
</xs:attributeGroup>
|
||||
<!-- Reference to a document inside of the topic folder or a url pointing to the web -->
|
||||
<xs:complexType name="DocumentReference">
|
||||
<xs:sequence>
|
||||
<xs:choice>
|
||||
<!-- Guid of the document: If pointing to an internal document -->
|
||||
<xs:element name="DocumentGuid" type="Guid" minOccurs="0"/>
|
||||
<!-- Url of the reference. If pointing to an external document -->
|
||||
<xs:element name="Url" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
</xs:choice>
|
||||
<!-- Human readable description of the document reference -->
|
||||
<xs:element name="Description" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attributeGroup ref="DocumentReferenceAttributes"/>
|
||||
</xs:complexType>
|
||||
<xs:attributeGroup name="DocumentReferenceAttributes">
|
||||
<!-- Guid of the document reference -->
|
||||
<xs:attribute name="Guid" type="Guid" use="required"/>
|
||||
</xs:attributeGroup>
|
||||
<xs:complexType name="Comment">
|
||||
<xs:sequence>
|
||||
<xs:element name="Date" type="xs:dateTime"/>
|
||||
<xs:element name="Author" type="NonEmptyOrBlankString"/>
|
||||
<xs:element name="Comment" minOccurs="0" type="NonEmptyOrBlankString"/>
|
||||
<xs:element name="Viewpoint" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="Guid" type="Guid" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="ModifiedDate" type="xs:dateTime" minOccurs="0"/>
|
||||
<xs:element name="ModifiedAuthor" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="Guid" type="Guid" use="required"/>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="IfcGuid">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:length value="22"/>
|
||||
<xs:pattern value="[0-9A-Za-z_$]*"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:include schemaLocation="shared-types.xsd"/>
|
||||
<xs:element name="ProjectInfo">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Project" type="Project"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:complexType name="Project">
|
||||
<xs:sequence>
|
||||
<xs:element name="Name" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="ProjectId" type="NonEmptyOrBlankString" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:simpleType name="Guid">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="NonEmptyOrBlankString">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:whiteSpace value="collapse"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:element name="Version">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="VersionId" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,220 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
|
||||
<xs:include schemaLocation="shared-types.xsd"/>
|
||||
<xs:element name="VisualizationInfo">
|
||||
<xs:annotation>
|
||||
<xs:documentation>VisualizationInfo documentation</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<!--
|
||||
Although plural, 'Components' is not a collection
|
||||
-->
|
||||
<xs:element name="Components" type="Components" minOccurs="0"/>
|
||||
<xs:choice>
|
||||
<xs:element name="OrthogonalCamera" type="OrthogonalCamera"/>
|
||||
<xs:element name="PerspectiveCamera" type="PerspectiveCamera"/>
|
||||
</xs:choice>
|
||||
<xs:element name="Lines" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Line" type="Line" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="ClippingPlanes" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="ClippingPlane" type="ClippingPlane" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="Bitmaps" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Bitmap" type="Bitmap" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<!-- Guid of the viewpoint -->
|
||||
<xs:attribute name="Guid" type="Guid" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:complexType name="OrthogonalCamera">
|
||||
<xs:sequence>
|
||||
<xs:element name="CameraViewPoint" type="Point"/>
|
||||
<xs:element name="CameraDirection" type="Direction"/>
|
||||
<xs:element name="CameraUpVector" type="Direction"/>
|
||||
<xs:element name="ViewToWorldScale" type="xs:double">
|
||||
<xs:annotation>
|
||||
<xs:documentation>view's visible vertical size in meters</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="AspectRatio" type="PositiveDouble">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Proportional relationship between the width and the height of the view (w/h).
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PerspectiveCamera">
|
||||
<xs:sequence>
|
||||
<xs:element name="CameraViewPoint" type="Point"/>
|
||||
<xs:element name="CameraDirection" type="Direction"/>
|
||||
<xs:element name="CameraUpVector" type="Direction"/>
|
||||
<xs:element name="FieldOfView" type="FieldOfView">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Vertical field of view, in degrees.
|
||||
It is currently limited to a value between 45 and 60 degrees.
|
||||
This limitation will be dropped in the next release and viewers
|
||||
should be expect values outside this range in current implementations.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="AspectRatio" type="PositiveDouble">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Proportional relationship between the width and the height of the view (w/h).
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="Point">
|
||||
<xs:sequence>
|
||||
<xs:element name="X" type="xs:double"/>
|
||||
<xs:element name="Y" type="xs:double"/>
|
||||
<xs:element name="Z" type="xs:double"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="Direction">
|
||||
<xs:sequence>
|
||||
<xs:element name="X" type="xs:double"/>
|
||||
<xs:element name="Y" type="xs:double"/>
|
||||
<xs:element name="Z" type="xs:double"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="PositiveDouble">
|
||||
<xs:restriction base="xs:double">
|
||||
<xs:minExclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="FieldOfView">
|
||||
<xs:restriction base="xs:double">
|
||||
<xs:minExclusive value="0"/>
|
||||
<xs:maxExclusive value="180"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="Components">
|
||||
<xs:sequence>
|
||||
<!-- Components with relevance to the viewpoint. They should be displayed highlighted or selected in a viewer -->
|
||||
<xs:element name="Selection" type="ComponentSelection" minOccurs="0"/>
|
||||
<xs:element name="Visibility" type="ComponentVisibility" minOccurs="0"/>
|
||||
<xs:element name="Coloring" type="ComponentColoring" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="ComponentSelection">
|
||||
<xs:sequence>
|
||||
<xs:element name="Component" type="Component" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="ComponentVisibility">
|
||||
<xs:sequence>
|
||||
<xs:element name="ViewSetupHints" type="ViewSetupHints" minOccurs="0"/>
|
||||
<xs:element name="Exceptions" minOccurs="0">
|
||||
<!-- List Components that are different than the DefaultVisibility. E.g. if DefaultVisibility = false then list
|
||||
Components that should be visible -->
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Component" type="Component" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="DefaultVisibility" type="xs:boolean" default="false"/>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="ViewSetupHints">
|
||||
<xs:attribute name="SpacesVisible" type="xs:boolean" default="false"/>
|
||||
<xs:attribute name="SpaceBoundariesVisible" type="xs:boolean" default="false"/>
|
||||
<xs:attribute name="OpeningsVisible" type="xs:boolean" default="false"/>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="ComponentColoring">
|
||||
<xs:sequence>
|
||||
<xs:element name="Color" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<!-- At least one component is required for a Color. -->
|
||||
<xs:element name="Components">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="Component" type="Component" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute ref="Color" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="Component">
|
||||
<xs:sequence>
|
||||
<xs:element name="OriginatingSystem" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
<xs:element name="AuthoringToolId" type="NonEmptyOrBlankString" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute ref="IfcGuid"/>
|
||||
</xs:complexType>
|
||||
<xs:attribute name="Color">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:normalizedString">
|
||||
<!-- Should either match 3 or 4 hex bytes , e.g. "FF00FF" or "FF00FF99" -->
|
||||
<xs:pattern value="[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IfcGuid">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:normalizedString">
|
||||
<xs:length value="22"/>
|
||||
<xs:pattern value="[0-9A-Za-z_$]*"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:complexType name="Line">
|
||||
<xs:sequence>
|
||||
<xs:element name="StartPoint" type="Point"/>
|
||||
<xs:element name="EndPoint" type="Point"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="ClippingPlane">
|
||||
<xs:sequence>
|
||||
<xs:element name="Location" type="Point"/>
|
||||
<xs:element name="Direction" type="Direction"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="Bitmap">
|
||||
<xs:sequence>
|
||||
<xs:element name="Format" type="BitmapFormat"/>
|
||||
<!-- Name of the bitmap file in the topic folder -->
|
||||
<xs:element name="Reference" type="NonEmptyOrBlankString"/>
|
||||
<!-- Location of the center of the bitmap -->
|
||||
<xs:element name="Location" type="Point"/>
|
||||
<!-- Normal of the bitmap -->
|
||||
<xs:element name="Normal" type="Direction"/>
|
||||
<!-- Upvector of the bitmap -->
|
||||
<xs:element name="Up" type="Direction"/>
|
||||
<!-- Height of the bitmap -->
|
||||
<xs:element name="Height" type="xs:double"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="BitmapFormat">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="png"/>
|
||||
<xs:enumeration value="jpg"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,621 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
@@ -0,0 +1,482 @@
|
||||
# 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/>.
|
||||
|
||||
VERSION:=`date '+%y%m%d'`
|
||||
PYVERSION:=py37
|
||||
|
||||
ifeq ($(PYVERSION), py37)
|
||||
PYLIBDIR:=python3.7
|
||||
PYNUMBER:=37
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
PYLIBDIR:=python3.9
|
||||
PYNUMBER:=39
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), linux)
|
||||
ifeq ($(PYVERSION), py37)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/1.7.5/download/linux-64/hpp-fcl-1.7.5-py37h5f1835d_0.tar.bz2
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/2.6.5/download/linux-64/eigenpy-2.6.5-py37h95e2c48_0.tar.bz2
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.74.0/download/linux-64/boost-1.74.0-py37h0379df6_3.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/30/c0/d0526314971fc661b083ab135747dc68446a3022686da8c16d25fcf6ef07/lxml-4.6.3-cp37-cp37m-manylinux2014_x86_64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/1.7.5/download/linux-64/hpp-fcl-1.7.5-py39hbcdfc36_0.tar.bz2
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/2.6.5/download/linux-64/eigenpy-2.6.5-py39h5aed9d1_0.tar.bz2
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.74.0/download/linux-64/boost-1.74.0-py39h5472131_3.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/19/d9/a69c6aff5673554df48120565a14a50eaa41d29ae03b02faa0b023666318/lxml-4.6.3-cp39-cp39-manylinux2014_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.7/download/linux-64/octomap-1.9.7-h4bd325d_0.tar.bz2
|
||||
ZLIB_URL:=https://anaconda.org/conda-forge/zlib/1.2.11/download/linux-64/zlib-1.2.11-h516909a_1010.tar.bz2
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), macos)
|
||||
ifeq ($(PYVERSION), py37)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/1.7.5/download/osx-64/hpp-fcl-1.7.5-py37h2d7f23a_0.tar.bz2
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/2.6.5/download/osx-64/eigenpy-2.6.5-py37h0695097_0.tar.bz2
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.74.0/download/osx-64/boost-1.74.0-py37hd79e0ac_3.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/1e/3e/f0abc15d5dac50939bccc589aae336d5ead4c72e7ad1039a2e0f3630ea92/lxml-4.6.3-cp37-cp37m-macosx_10_9_x86_64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/1.7.5/download/osx-64/hpp-fcl-1.7.5-py39h1e32b98_0.tar.bz2
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/2.6.5/download/osx-64/eigenpy-2.6.5-py39h5405915_0.tar.bz2
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.74.0/download/osx-64/boost-1.74.0-py39ha641261_3.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/b8/74/a71f7ad72e8db54ce899efab84507b801660750cbbfa6a39e6717557d36a/lxml-4.6.3-cp39-cp39-macosx_10_9_x86_64.whl
|
||||
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.7/download/osx-64/octomap-1.9.7-h940c156_0.tar.bz2
|
||||
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), win)
|
||||
ifeq ($(PYVERSION), py37)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/1.7.5/download/win-64/hpp-fcl-1.7.5-py37h839d6b1_0.tar.bz2
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/2.6.5/download/win-64/eigenpy-2.6.5-py37h2c32e34_0.tar.bz2
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.74.0/download/win-64/boost-1.74.0-py37h3b38789_3.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/9e/5e/171ee9d40a600f565fe691ec5bf7596247ec62cfb2edc00c91afe8ea837b/lxml-4.6.3-cp37-cp37m-win_amd64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/1.7.5/download/win-64/hpp-fcl-1.7.5-py39h2e7c763_0.tar.bz2
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/2.6.5/download/win-64/eigenpy-2.6.5-py39h3ce40e6_0.tar.bz2
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.74.0/download/win-64/boost-1.74.0-py39hefe7e4c_3.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/72/d4/426ecb8849c47c3e370c87aa0ac05d85768df917ffea27fcd6686a5e6495/lxml-4.6.3-cp39-cp39-win_amd64.whl
|
||||
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.7/download/win-64/octomap-1.9.7-h5362a0b_0.tar.bz2
|
||||
ZLIB_URL:=https://anaconda.org/conda-forge/zlib/1.2.11/download/win-64/zlib-1.2.11-h62dcd97_1010.tar.bz2
|
||||
endif
|
||||
|
||||
.PHONY: dist
|
||||
dist:
|
||||
ifndef PLATFORM
|
||||
$(error PLATFORM is not set)
|
||||
endif
|
||||
rm -rf dist
|
||||
mkdir -p dist/working
|
||||
mkdir -p dist/blenderbim
|
||||
cp -r blenderbim/* dist/blenderbim/
|
||||
|
||||
# Provides IfcOpenShell Python functionality
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-$(PYNUMBER)-v0.6.0-721fe47-$(PLATFORM)64.zip
|
||||
cd dist/working && unzip ifcblender*
|
||||
cp -r dist/working/io_import_scene_ifc/ifcopenshell dist/blenderbim/libs/site/packages/
|
||||
|
||||
# See bug #812
|
||||
cd dist/working && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/blenderbim/occ_utils.py
|
||||
cd dist/working && mv occ_utils.py ../blenderbim/libs/site/packages/ifcopenshell/geom/occ_utils.py
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides IfcConvert for construction documentation
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.6.0-81ad689-$(PLATFORM)64.zip
|
||||
cd dist/working && unzip IfcConvert*
|
||||
ifeq ($(PLATFORM), win)
|
||||
cp -r dist/working/IfcConvert.exe dist/blenderbim/libs/
|
||||
else
|
||||
cp -r dist/working/IfcConvert dist/blenderbim/libs/
|
||||
endif
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides dependencies that are part of IfcOpenShell
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://github.com/IfcOpenShell/IfcOpenShell/archive/v0.6.0.zip
|
||||
cd dist/working && unzip v0.6.0.zip
|
||||
# IfcOpenBot sometimes lags behind, so we hotfix the Python utilities
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcopenshell-python/ifcopenshell/util/* dist/blenderbim/libs/site/packages/ifcopenshell/util/
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcopenshell-python/ifcopenshell/api/* dist/blenderbim/libs/site/packages/ifcopenshell/api/
|
||||
cp dist/working/IfcOpenShell-0.6.0/src/ifcopenshell-python/ifcopenshell/entity_instance.py dist/blenderbim/libs/site/packages/ifcopenshell/
|
||||
cp dist/working/IfcOpenShell-0.6.0/src/ifcopenshell-python/ifcopenshell/file.py dist/blenderbim/libs/site/packages/ifcopenshell/
|
||||
# Provides bcf functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/bcf/src/bcf dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCClash functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcclash/ifcclash dist/blenderbim/libs/site/packages/
|
||||
# Provides BIMTester functionality
|
||||
cd dist/working && python -m venv env
|
||||
cd dist/working && . env/bin/activate && pip install pybabel
|
||||
cd dist/working && . env/bin/activate && pip install babel
|
||||
cd dist/working && . env/bin/activate && ./env/bin/pybabel compile -d ./IfcOpenShell-0.6.0/src/ifcbimtester/bimtester/locale/
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcbimtester/bimtester dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCCOBie functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifccobie/* dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCDiff functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcdiff/* dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCCSV functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifccsv/* dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCPatch functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcpatch/ifcpatch dist/blenderbim/libs/site/packages/
|
||||
# Provides IFC4D functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifc4d/ifc4d dist/blenderbim/libs/site/packages/
|
||||
# Provides IFC5D functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifc5d/ifc5d dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides Mustache templating in construction documentation
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/d6/fd/eb8c212053addd941cc90baac307c00ac246ac3fce7166b86434c6eae963/pystache-0.5.4.tar.gz
|
||||
cd dist/working && tar -xzvf pystache*
|
||||
cd dist/working/pystache-0.5.4/ && python setup.py build && cp -r build/lib/pystache ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides SVG export in construction documentation
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/79/e8/7eb2ba188eda14a4b47e33b51f3b4978985f4116655c699bcd18c79279b5/svgwrite-1.3.1.zip
|
||||
cd dist/working && unzip svgwrite*
|
||||
cp -r dist/working/svgwrite-1.3.1/svgwrite dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides fuzzy date parsing for construction sequencing
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/be/ed/5bbc91f03fa4c839c4c7360375da77f9659af5f7086b7a7bdda65771c8e0/python-dateutil-2.8.1.tar.gz
|
||||
cd dist/working && tar -xzvf python-dateutil*
|
||||
cp -r dist/working/python-dateutil-2.8.1/dateutil dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides duration parsing for construction sequencing
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/b1/80/fb8c13a4cd38eb5021dc3741a9e588e4d1de88d895c1910c6fc8a08b7a70/isodate-0.6.0.tar.gz
|
||||
cd dist/working && tar -xzvf isodate*
|
||||
cp -r dist/working/isodate-0.6.0/src/isodate dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides networkx graph analysis for project dependency calculations
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/b0/21/adfbf6168631e28577e4af9eb9f26d75fe72b2bb1d33762a5f2c425e6c2a/networkx-2.5.1.tar.gz
|
||||
cd dist/working && tar -xzvf networkx*
|
||||
cp -r dist/working/networkx-2.5.1/networkx dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by networkx
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/4f/51/15a4f6b8154d292e130e5e566c730d8ec6c9802563d58760666f1818ba58/decorator-5.0.9.tar.gz
|
||||
cd dist/working && tar -xzvf decorator*
|
||||
cp -r dist/working/decorator-5.0.9/src/decorator.py dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides jsgantt-improved supports for web-based construction sequencing gantt charts
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.js
|
||||
cd dist/working && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.css
|
||||
cp dist/working/jsgantt* dist/blenderbim/bim/data/gantt/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by IFCDiff
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://github.com/Moult/deepdiff/archive/master.zip
|
||||
cd dist/working && unzip master.zip
|
||||
cp -r dist/working/deepdiff-master/deepdiff dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by deepdiff
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/00/55/ce2cbc6d64034b30cad81a29ba61bdba456f190f5e83c09831304bf68d6b/jsonpickle-1.2.tar.gz
|
||||
cd dist/working && tar -xzvf jsonpickle*
|
||||
cp -r dist/working/jsonpickle-1.2/jsonpickle dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by deepdiff
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/a3/b7/d4d69641cbe707a45c23b190f2d717466ba5accc4c70b5f7a8a450387895/ordered-set-3.1.1.tar.gz
|
||||
cd dist/working && tar -xzvf ordered-set*
|
||||
cp -r dist/working/ordered-set-3.1.1/ordered_set.py dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by lark
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/00/32/8076fa13e832bb4dcff379f18f228e5a53412be0631808b9ca2610c0f566/pyparsing-2.4.5.tar.gz
|
||||
cd dist/working && tar -xzvf pyparsing*
|
||||
cp -r dist/working/pyparsing-2.4.5/pyparsing.py dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by bcf
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/bb/41/ad9ce53bb978b68af8ae415293cafc89b165b8ad55a593725299dca76729/xmlschema-1.1.1.tar.gz
|
||||
cd dist/working && tar -xzvf xmlschema*
|
||||
cp -r dist/working/xmlschema-1.1.1/xmlschema dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by bcf
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/12/f9/f9960222d5274944b01391749e55e4dcdf28d8f0c108b64ac931ceff6fdb/elementpath-1.4.3.tar.gz
|
||||
cd dist/working && tar -xzvf elementpath*
|
||||
cp -r dist/working/elementpath-1.4.3/elementpath dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by bcf
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/21/9f/b251f7f8a76dec1d6651be194dfba8fb8d7781d10ab3987190de8391d08e/six-1.14.0.tar.gz
|
||||
cd dist/working && tar -xzvf six*
|
||||
cp -r dist/working/six-1.14.0/six.py dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by IFCCSV and ifcopenshell.util.selector
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/18/4d/8d522136c37d9e1ea74062b41b8d5e1318ebf45063ae46ce72ed60af223b/lark-parser-0.8.5.tar.gz
|
||||
cd dist/working && tar -xzvf lark-parser*
|
||||
cp -r dist/working/lark-parser-0.8.5/lark dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by IFCClash
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(HPPFCL_URL)
|
||||
cd dist/working && tar -xf hpp-fcl*
|
||||
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), 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), 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 $(EIGENPY_URL)
|
||||
cd dist/working && tar -xf eigenpy*
|
||||
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), 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), 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), 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 $(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), 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
|
||||
cd dist/working && tar -xzvf behave*
|
||||
cd dist/working/behave-1.2.6/ && cp -r behave ../../blenderbim/libs/site/packages/
|
||||
# See bug #1294
|
||||
cd dist/working/ && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/ifcbimtester/patch/model_core.patch
|
||||
cd dist/working/ && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/ifcbimtester/patch/runner_util.patch
|
||||
cd dist/working/ && patch ../blenderbim/libs/site/packages/behave/model_core.py < model_core.patch
|
||||
cd dist/working/ && patch ../blenderbim/libs/site/packages/behave/runner_util.py < runner_util.patch
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by ids
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(LXML_URL)
|
||||
cd dist/working && cp *.whl lxml.zip && unzip lxml.zip
|
||||
cp -r dist/working/lxml dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by behave
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/f4/65/220bb4075fddb09d5b3ea2c1c1fa66c1c72be9361ec187aab50fa161e576/parse-1.15.0.tar.gz
|
||||
cd dist/working && tar -xzvf parse*
|
||||
cd dist/working/parse-1.15.0/ && cp parse.py ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by behave
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/2e/79/81bebd1b0446d46733db99d74543b4bb80646ef4c988584bae0862e706bc/parse_type-0.5.2.tar.gz
|
||||
cd dist/working && tar -xzvf parse_type*
|
||||
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
|
||||
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
|
||||
cd dist/working && unzip master.zip
|
||||
cp -r dist/working/IFC2JSON_python-master/file_converters/ifcjson dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides OpenLCA fucntionality
|
||||
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
|
||||
|
||||
cd dist/blenderbim && sed -i "s/999999/$(VERSION)/" __init__.py
|
||||
cd dist && zip -r blenderbim-$(VERSION)-$(PYVERSION)-$(PLATFORM).zip ./*
|
||||
rm -rf dist/blenderbim
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
make test-core
|
||||
make test-bim
|
||||
|
||||
.PHONY: test-core
|
||||
test-core:
|
||||
pytest -p no:pytest-blender test/core
|
||||
|
||||
.PHONY: test-bim
|
||||
test-bim:
|
||||
pytest test/bim
|
||||
|
||||
.PHONY: qa
|
||||
qa:
|
||||
black .
|
||||
pylint ./* --output-format=colorized --disable all --enable E --disable import-error
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
coverage run --source blenderbim.core -m pytest -p no:pytest-blender test/core
|
||||
coverage html
|
||||
xdg-open htmlcov/index.html
|
||||
|
||||
.PHONY: license
|
||||
license:
|
||||
copyright-header --license GPL3 --copyright-holder "Dion Moult <dion@thinkmoult.com>" --copyright-year "2021" --copyright-software "BlenderBIM Add-on" --copyright-software-description "OpenBIM Blender Add-on" -a ./ -o ./
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf dist
|
||||
rm -rf htmlcov
|
||||
|
||||
.PHONY: dev
|
||||
dev:
|
||||
blender -p setup_pytest.py
|
||||
|
Before Width: | Height: | Size: 399 KiB After Width: | Height: | Size: 399 KiB |
@@ -0,0 +1,45 @@
|
||||
# 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 os
|
||||
import sys
|
||||
import site
|
||||
|
||||
bl_info = {
|
||||
"name": "BlenderBIM",
|
||||
"description": "Author, import, and export data using the Industry Foundation Classes schema",
|
||||
"author": "IfcOpenShell Contributors",
|
||||
"blender": (2, 80, 0),
|
||||
"version": (0, 0, 999999),
|
||||
"location": "File > Export, File > Import, Scene / Object / Material / Mesh Properties",
|
||||
"tracker_url": "https://github.com/IfcOpenShell/IfcOpenShell/issues",
|
||||
"category": "Import-Export",
|
||||
}
|
||||
|
||||
if sys.modules.get("bpy", None):
|
||||
# Process *.pth in /libs/site/packages to setup globally importable modules
|
||||
# This is 3 levels deep as required by the static RPATH of ../../ from dependencies taken from Anaconda
|
||||
site.addsitedir(os.path.join(os.path.dirname(os.path.realpath(__file__)), "libs", "site", "packages"))
|
||||
|
||||
import blenderbim.bim
|
||||
|
||||
def register():
|
||||
blenderbim.bim.register()
|
||||
|
||||
def unregister():
|
||||
blenderbim.bim.unregister()
|
||||
@@ -0,0 +1,167 @@
|
||||
# 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 importlib
|
||||
from . import handler, ui, prop, operator
|
||||
|
||||
modules = {
|
||||
"project": None,
|
||||
"search": None,
|
||||
"bcf": None,
|
||||
"root": None,
|
||||
"unit": None,
|
||||
"model": None,
|
||||
"georeference": None,
|
||||
"context": None,
|
||||
"drawing": None,
|
||||
"attribute": None,
|
||||
"type": None,
|
||||
"spatial": None,
|
||||
"void": None,
|
||||
"aggregate": None,
|
||||
"geometry": None,
|
||||
"cobie": None,
|
||||
"resource": None,
|
||||
"cost": None,
|
||||
"sequence": None,
|
||||
"group": None,
|
||||
"system": None,
|
||||
"structural": None,
|
||||
"boundary": None,
|
||||
"profile": None,
|
||||
"material": None,
|
||||
"style": None,
|
||||
"layer": None,
|
||||
"owner": None,
|
||||
"pset": None,
|
||||
"qto": None,
|
||||
"classification": None,
|
||||
"constraint": None,
|
||||
"document": None,
|
||||
"pset_template": None,
|
||||
"clash": None,
|
||||
"lca": None,
|
||||
"csv": None,
|
||||
"bimtester": None,
|
||||
"diff": None,
|
||||
"patch": None,
|
||||
"covetool": None,
|
||||
"augin": None,
|
||||
"debug": None,
|
||||
}
|
||||
|
||||
for name in modules.keys():
|
||||
modules[name] = importlib.import_module(f"blenderbim.bim.module.{name}")
|
||||
|
||||
classes = [
|
||||
operator.OpenUri,
|
||||
operator.SelectDataDir,
|
||||
operator.SelectSchemaDir,
|
||||
operator.SelectIfcFile,
|
||||
operator.ExportIFC,
|
||||
operator.ImportIFC,
|
||||
operator.OpenUpstream,
|
||||
operator.AddSectionPlane,
|
||||
operator.RemoveSectionPlane,
|
||||
operator.ReloadIfcFile,
|
||||
operator.AddIfcFile,
|
||||
operator.RemoveIfcFile,
|
||||
operator.SetOverrideColour,
|
||||
operator.SetViewportShadowFromSun,
|
||||
operator.SnapSpacesTogether,
|
||||
operator.OverrideDelete,
|
||||
prop.StrProperty,
|
||||
prop.Attribute,
|
||||
prop.BIMProperties,
|
||||
prop.IfcParameter,
|
||||
prop.PsetQto,
|
||||
prop.GlobalId,
|
||||
prop.BIMObjectProperties,
|
||||
prop.BIMMaterialProperties,
|
||||
prop.BIMMeshProperties,
|
||||
ui.BIM_PT_section_plane,
|
||||
ui.BIM_UL_generic,
|
||||
ui.BIM_UL_topics,
|
||||
ui.BIM_ADDON_preferences,
|
||||
]
|
||||
|
||||
for mod in modules.values():
|
||||
classes.extend(mod.classes)
|
||||
|
||||
|
||||
def menu_func_export(self, context):
|
||||
self.layout.operator(operator.ExportIFC.bl_idname, text="Industry Foundation Classes (.ifc/.ifczip/.ifcjson)")
|
||||
|
||||
|
||||
def menu_func_import(self, context):
|
||||
self.layout.operator(operator.ImportIFC.bl_idname, text="Industry Foundation Classes (.ifc/.ifczip/.ifcxml)")
|
||||
|
||||
|
||||
def on_register(scene):
|
||||
handler.setDefaultProperties(scene)
|
||||
bpy.app.handlers.depsgraph_update_post.remove(on_register)
|
||||
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
bpy.app.handlers.depsgraph_update_post.append(on_register)
|
||||
bpy.app.handlers.undo_pre.append(handler.undo_pre)
|
||||
bpy.app.handlers.undo_post.append(handler.undo_post)
|
||||
bpy.app.handlers.redo_pre.append(handler.redo_pre)
|
||||
bpy.app.handlers.redo_post.append(handler.redo_post)
|
||||
bpy.app.handlers.load_post.append(handler.setDefaultProperties)
|
||||
bpy.app.handlers.load_post.append(handler.loadIfcStore)
|
||||
bpy.app.handlers.save_pre.append(handler.ensureIfcExported)
|
||||
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
|
||||
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
|
||||
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
|
||||
bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
|
||||
bpy.types.Material.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
|
||||
bpy.types.Material.BIMMaterialProperties = bpy.props.PointerProperty(type=prop.BIMMaterialProperties)
|
||||
bpy.types.Mesh.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.Curve.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.Camera.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.PointLight.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.SCENE_PT_unit.append(ui.ifc_units)
|
||||
|
||||
for mod in modules.values():
|
||||
mod.register()
|
||||
|
||||
|
||||
def unregister():
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
bpy.app.handlers.load_post.remove(handler.setDefaultProperties)
|
||||
bpy.app.handlers.load_post.remove(handler.loadIfcStore)
|
||||
bpy.app.handlers.save_pre.remove(handler.ensureIfcExported)
|
||||
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
|
||||
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
|
||||
del bpy.types.Scene.BIMProperties
|
||||
del bpy.types.Object.BIMObjectProperties
|
||||
del bpy.types.Material.BIMObjectProperties
|
||||
del bpy.types.Material.BIMMaterialProperties
|
||||
del bpy.types.Mesh.BIMMeshProperties
|
||||
del bpy.types.Curve.BIMMeshProperties
|
||||
del bpy.types.Camera.BIMMeshProperties
|
||||
del bpy.types.PointLight.BIMMeshProperties
|
||||
bpy.types.SCENE_PT_unit.remove(ui.ifc_units)
|
||||
|
||||
for mod in reversed(list(modules.values())):
|
||||
mod.unregister()
|
||||
@@ -0,0 +1,24 @@
|
||||
<link href="jsgantt.css" rel="stylesheet" type="text/css"/>
|
||||
<script src="jsgantt.js" type="text/javascript"></script>
|
||||
<div style="position:relative" class="gantt" id="GanttChartDIV"></div>
|
||||
<script type="text/javascript">
|
||||
var g = new JSGantt.GanttChart(document.getElementById('GanttChartDIV'), 'day');
|
||||
g.setOptions({
|
||||
vCaptionType: 'Complete', // Set to Show Caption : None,Caption,Resource,Duration,Complete,
|
||||
vQuarterColWidth: 36,
|
||||
vDateTaskDisplayFormat: 'day dd month yyyy', // Shown in tool tip box
|
||||
vDayMajorDateDisplayFormat: 'mon yyyy - Week ww',// Set format to dates in the "Major" header of the "Day" view
|
||||
vWeekMinorDateDisplayFormat: 'dd mon', // Set format to display dates in the "Minor" header of the "Week" view
|
||||
vLang: 'en',
|
||||
vShowTaskInfoLink: 1, // Show link in tool tip (0/1)
|
||||
vShowEndWeekDate: 0, // Show/Hide the date for the last day of the week in header for daily
|
||||
vUseSingleCell: 10000, // Set the threshold cell per table row (Helps performance for large data.
|
||||
vFormatArr: ['Day', 'Week', 'Month', 'Quarter'], // Even with setUseSingleCell using Hour format on such a large chart can cause issues in some browsers,
|
||||
vTotalHeight: 1000,
|
||||
});
|
||||
var json_data = `
|
||||
{{{json_data}}}
|
||||
`;
|
||||
JSGantt.parseJSONString(json_data, g);
|
||||
g.Draw();
|
||||
</script>
|
||||
@@ -0,0 +1,12 @@
|
||||
ISO-10303-21;
|
||||
HEADER;
|
||||
FILE_DESCRIPTION((),'2;1');
|
||||
FILE_NAME('EPset_Parametric.ifc','2020-01-01T00:00:00',(),(),'EPset_Parametric','EPset_Parametric',$);
|
||||
FILE_SCHEMA(('IFC4'));
|
||||
ENDSEC;
|
||||
DATA;
|
||||
#1=IFCPROPERTYSETTEMPLATE('1Ja6GlovjFoeonRLXJwyyl',$,'EPset_Parametric','',.PSET_TYPEDRIVENOVERRIDE.,'IfcTypeObject',(#2,#3));
|
||||
#2=IFCSIMPLEPROPERTYTEMPLATE('2ZxSvp00j5hxrWv$Q8ajzx',$,'Engine','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#3=IFCSIMPLEPROPERTYTEMPLATE('2AN6WomqXCjRkP0g2iwEjp',$,'LayerSetDirection','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
ENDSEC;
|
||||
END-ISO-10303-21;
|
||||
@@ -0,0 +1,13 @@
|
||||
ISO-10303-21;
|
||||
HEADER;
|
||||
FILE_DESCRIPTION((),'2;1');
|
||||
FILE_NAME('EPset_Productivity.ifc','2020-01-01T00:00:00',(),(),'EPset_Productivity','EPset_Productivity',$);
|
||||
FILE_SCHEMA(('IFC4'));
|
||||
ENDSEC;
|
||||
DATA;
|
||||
#1=IFCPROPERTYSETTEMPLATE('24XxTA2ED4o83uiZBG59D_',$,'EPset_Productivity','',.PSET_TYPEDRIVENOVERRIDE.,'IfcConstructionEquipmentResource,IfcLaborResource',(#2,#3,#4));
|
||||
#2=IFCSIMPLEPROPERTYTEMPLATE('3mL27FQ4X4MQn5fiGqIt8x',$,'BaseQuantityConsumed','',.P_SINGLEVALUE.,'IfcDuration',$,$,$,$,$,.READWRITE.);
|
||||
#3=IFCSIMPLEPROPERTYTEMPLATE('1DdJt5_Ar2mR4UDpO$98Ws',$,'BaseQuantityProducedName','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#4=IFCSIMPLEPROPERTYTEMPLATE('2OZPZ$Onb2gOvW20q7gacH',$,'BaseQuantityProducedValue','',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
|
||||
ENDSEC;
|
||||
END-ISO-10303-21;
|
||||
@@ -0,0 +1,12 @@
|
||||
ISO-10303-21;
|
||||
HEADER;
|
||||
FILE_DESCRIPTION((),'2;1');
|
||||
FILE_NAME('Qto_TaskBaseQuantities.ifc','2020-01-01T00:00:00',(),(),'Qto_TaskBaseQuantities','Qto_TaskBaseQuantities',$);
|
||||
FILE_SCHEMA(('IFC4'));
|
||||
ENDSEC;
|
||||
DATA;
|
||||
#1=IFCPROPERTYSETTEMPLATE('3uZCoCxrr8MA2yVRLzH6P4',$,'Qto_TaskBaseQuantities','',.QTO_OCCURRENCEDRIVEN.,'IfcTask',(#2,#3));
|
||||
#2=IFCSIMPLEPROPERTYTEMPLATE('0q8nByVuP4cv46Pm4wfGpf',$,'StandardWork','',.Q_TIME.,$,$,$,$,$,$,.READWRITE.);
|
||||
#3=IFCSIMPLEPROPERTYTEMPLATE('2uf5oHjAz4pRmtn9ihJiAs',$,'OvertimeWork','',.Q_TIME.,$,$,$,$,$,$,.READWRITE.);
|
||||
ENDSEC;
|
||||
END-ISO-10303-21;
|
||||
@@ -1,6 +1,26 @@
|
||||
* { stroke-linecap: round; }
|
||||
.cut { fill: black; stroke: black; stroke-linecap: 'round'; stroke-width: 0.35; }
|
||||
.background { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; }
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
* { stroke-linecap: round; stroke-linejoin: round; }
|
||||
*[id] { fill: black; stroke: black; stroke-linecap: 'round'; stroke-width: 0.35; }
|
||||
.projection { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; }
|
||||
.annotation { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; }
|
||||
.hidden { stroke-dasharray: 3, 2; }
|
||||
.solid {}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
.cut { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.35; }
|
||||
.background { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; }
|
||||
.annotation { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; }
|
||||
.hidden { stroke-dasharray: 3, 2; }
|
||||
.solid {}
|
||||
.leader { marker-end: url(#leader-marker); }
|
||||
.stair { marker-start: url(#stair-marker-start); marker-end: url(#stair-marker-end); }
|
||||
.break { fill: white; }
|
||||
.breakline { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; marker-mid: url(#breakline-marker); }
|
||||
.IfcSpace { fill: none; stroke: none; }
|
||||
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 572 B After Width: | Height: | Size: 572 B |
@@ -25,7 +25,7 @@
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<desc
|
||||
id="desc89610">/home/dion/Projects/IfcOpenShell/src/ifcblenderexport/titleblock.dxf - scale = 1.000000, origin = (0.000000, 0.000000), method = manual</desc>
|
||||
id="desc89610">/home/dion/Projects/IfcOpenShell/src/blenderbim/titleblock.dxf - scale = 1.000000, origin = (0.000000, 0.000000), method = manual</desc>
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.07874;stroke-linecap:round;stroke-linejoin:round;stop-color:#000000"
|
||||
id="rect1036"
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -25,7 +25,7 @@
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<desc
|
||||
id="desc89610">/home/dion/Projects/IfcOpenShell/src/ifcblenderexport/titleblock.dxf - scale = 1.000000, origin = (0.000000, 0.000000), method = manual</desc>
|
||||
id="desc89610">/home/dion/Projects/IfcOpenShell/src/blenderbim/titleblock.dxf - scale = 1.000000, origin = (0.000000, 0.000000), method = manual</desc>
|
||||
<rect
|
||||
y="3.1753578e-05"
|
||||
x="-4.3300333e-05"
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -25,7 +25,7 @@
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<desc
|
||||
id="desc89610">/home/dion/Projects/IfcOpenShell/src/ifcblenderexport/titleblock.dxf - scale = 1.000000, origin = (0.000000, 0.000000), method = manual</desc>
|
||||
id="desc89610">/home/dion/Projects/IfcOpenShell/src/blenderbim/titleblock.dxf - scale = 1.000000, origin = (0.000000, 0.000000), method = manual</desc>
|
||||
<rect
|
||||
y="3.1753578e-05"
|
||||
x="-4.3300333e-05"
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,206 @@
|
||||
# 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 os
|
||||
import bpy
|
||||
import json
|
||||
import numpy as np
|
||||
import datetime
|
||||
import zipfile
|
||||
import tempfile
|
||||
import addon_utils
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.placement
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
class IfcExporter:
|
||||
def __init__(self, ifc_export_settings):
|
||||
self.ifc_export_settings = ifc_export_settings
|
||||
|
||||
def export(self):
|
||||
self.file = IfcStore.get_file()
|
||||
self.set_header()
|
||||
if bpy.context.scene.BIMProjectProperties.is_authoring:
|
||||
self.sync_object_placements_and_deletions()
|
||||
self.sync_edited_objects()
|
||||
extension = self.ifc_export_settings.output_file.split(".")[-1]
|
||||
if extension == "ifczip":
|
||||
with tempfile.TemporaryDirectory() as unzipped_path:
|
||||
filename, ext = os.path.splitext(os.path.basename(self.ifc_export_settings.output_file))
|
||||
tmp_name = "{}.ifc".format(filename)
|
||||
tmp_file = os.path.join(unzipped_path, tmp_name)
|
||||
self.file.write(tmp_file)
|
||||
with zipfile.ZipFile(
|
||||
self.ifc_export_settings.output_file, mode="w", compression=zipfile.ZIP_DEFLATED, compresslevel=9
|
||||
) as zf:
|
||||
zf.write(tmp_file)
|
||||
elif extension == "ifc":
|
||||
self.file.write(self.ifc_export_settings.output_file)
|
||||
elif extension == "ifcjson":
|
||||
import ifcjson
|
||||
|
||||
if self.ifc_export_settings.json_version == "4":
|
||||
jsonData = ifcjson.IFC2JSON4(self.file, self.ifc_export_settings.json_compact).spf2Json()
|
||||
with open(self.ifc_export_settings.output_file, "w") as outfile:
|
||||
json.dump(jsonData, outfile, indent=None if self.ifc_export_settings.json_compact else 4)
|
||||
elif self.ifc_export_settings.json_version == "5a":
|
||||
jsonData = ifcjson.IFC2JSON5a(self.file, self.ifc_export_settings.json_compact).spf2Json()
|
||||
with open(self.ifc_export_settings.output_file, "w") as outfile:
|
||||
json.dump(jsonData, outfile, indent=None if self.ifc_export_settings.json_compact else 4)
|
||||
|
||||
def set_header(self):
|
||||
self.file.wrapped_data.header.file_name.name = os.path.basename(self.ifc_export_settings.output_file)
|
||||
self.file.wrapped_data.header.file_name.time_stamp = (
|
||||
datetime.datetime.utcnow()
|
||||
.replace(tzinfo=datetime.timezone.utc)
|
||||
.astimezone()
|
||||
.replace(microsecond=0)
|
||||
.isoformat()
|
||||
)
|
||||
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()
|
||||
)
|
||||
|
||||
def sync_object_placements_and_deletions(self):
|
||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
to_delete = []
|
||||
|
||||
for ifc_definition_id, obj in IfcStore.id_map.items():
|
||||
try:
|
||||
if isinstance(obj, bpy.types.Material):
|
||||
continue
|
||||
self.sync_object_placement(obj)
|
||||
self.sync_object_container(ifc_definition_id, obj)
|
||||
except ReferenceError:
|
||||
pass # The object is likely deleted
|
||||
if self.should_delete(obj):
|
||||
to_delete.append(ifc_definition_id)
|
||||
|
||||
for ifc_definition_id in to_delete:
|
||||
product = self.file.by_id(ifc_definition_id)
|
||||
IfcStore.unlink_element(product)
|
||||
ifcopenshell.api.run("root.remove_product", self.file, **{"product": product})
|
||||
|
||||
def sync_edited_objects(self):
|
||||
for obj in IfcStore.edited_objs.copy():
|
||||
if not obj:
|
||||
continue
|
||||
try:
|
||||
if isinstance(obj, bpy.types.Material):
|
||||
bpy.ops.bim.update_style_colours(material=obj.name)
|
||||
else:
|
||||
bpy.ops.bim.update_representation(obj=obj.name)
|
||||
except ReferenceError:
|
||||
pass # The object is likely deleted
|
||||
IfcStore.edited_objs.clear()
|
||||
|
||||
def sync_object_placement(self, obj):
|
||||
blender_matrix = np.array(obj.matrix_world)
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
if not hasattr(element, "ObjectPlacement"):
|
||||
return
|
||||
ifc_matrix = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)
|
||||
ifc_matrix[0][3] *= self.unit_scale
|
||||
ifc_matrix[1][3] *= self.unit_scale
|
||||
ifc_matrix[2][3] *= self.unit_scale
|
||||
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
if props.has_blender_offset and obj.BIMObjectProperties.blender_offset_type == "OBJECT_PLACEMENT":
|
||||
ifc_matrix = ifcopenshell.util.geolocation.global2local(
|
||||
ifc_matrix,
|
||||
float(props.blender_eastings) * self.unit_scale,
|
||||
float(props.blender_northings) * self.unit_scale,
|
||||
float(props.blender_orthogonal_height) * self.unit_scale,
|
||||
float(props.blender_x_axis_abscissa),
|
||||
float(props.blender_x_axis_ordinate),
|
||||
)
|
||||
if not np.allclose(ifc_matrix, blender_matrix, atol=0.0001):
|
||||
bpy.ops.bim.edit_object_placement(obj=obj.name)
|
||||
|
||||
def sync_object_container(self, guid, obj):
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element_collection = bpy.data.collections.get(obj.name)
|
||||
|
||||
if self.file.schema == "IFC2X3":
|
||||
if element.is_a("IfcProject"):
|
||||
return
|
||||
elif element.is_a("IfcContext"):
|
||||
return
|
||||
|
||||
if (
|
||||
(element.is_a("IfcElement") and element_collection)
|
||||
or element.is_a("IfcSpatialStructureElement")
|
||||
or element.is_a("IfcGrid")
|
||||
):
|
||||
try:
|
||||
parent_collection = [c for c in bpy.data.collections if c.children.get(element_collection.name)][0]
|
||||
except:
|
||||
return # Out of the spatial tree
|
||||
else:
|
||||
parent_collection = obj.users_collection[0]
|
||||
|
||||
parent_obj = bpy.data.objects.get(parent_collection.name)
|
||||
if not parent_obj or not parent_obj.BIMObjectProperties.ifc_definition_id:
|
||||
return
|
||||
parent = self.file.by_id(parent_obj.BIMObjectProperties.ifc_definition_id)
|
||||
|
||||
if parent.is_a("IfcSpatialStructureElement") and not element.is_a("IfcSpatialStructureElement"):
|
||||
if parent != ifcopenshell.util.element.get_container(element):
|
||||
bpy.ops.bim.assign_container(relating_structure=parent.id(), related_element=obj.name)
|
||||
elif parent != ifcopenshell.util.element.get_aggregate(element):
|
||||
bpy.ops.bim.assign_object(relating_object=parent_obj.name, related_object=obj.name)
|
||||
|
||||
def should_delete(self, obj):
|
||||
try:
|
||||
# This will throw an exception if the Blender object no longer exists
|
||||
foo = obj.name
|
||||
foo
|
||||
return False
|
||||
except:
|
||||
return True
|
||||
|
||||
def get_application_name(self):
|
||||
return "BlenderBIM"
|
||||
|
||||
def get_application_version(self):
|
||||
return ".".join(
|
||||
[
|
||||
str(x)
|
||||
for x in [
|
||||
addon.bl_info.get("version", (-1, -1, -1))
|
||||
for addon in addon_utils.modules()
|
||||
if addon.bl_info["name"] == "BlenderBIM"
|
||||
][0]
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class IfcExportSettings:
|
||||
def __init__(self):
|
||||
self.logger = None
|
||||
self.output_file = None
|
||||
|
||||
@staticmethod
|
||||
def factory(context, output_file, logger):
|
||||
settings = IfcExportSettings()
|
||||
settings.output_file = output_file
|
||||
settings.logger = logger
|
||||
return settings
|
||||
@@ -0,0 +1,308 @@
|
||||
# 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 json
|
||||
import addon_utils
|
||||
import ifcopenshell.api.owner.settings
|
||||
from blenderbim.bim.module.drawing.prop import RasterStyleProperty
|
||||
from bpy.app.handlers import persistent
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.owner.prop import getPersons, getOrganisations
|
||||
from ifcopenshell.api.attribute.data import Data as AttributeData
|
||||
from ifcopenshell.api.material.data import Data as MaterialData
|
||||
from ifcopenshell.api.style.data import Data as StyleData
|
||||
from ifcopenshell.api.type.data import Data as TypeData
|
||||
|
||||
|
||||
global_subscription_owner = object()
|
||||
|
||||
|
||||
def mode_callback(obj, data):
|
||||
if not bpy.context.scene.BIMProjectProperties.is_authoring:
|
||||
return
|
||||
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:
|
||||
representation = IfcStore.get_file().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
|
||||
if representation.RepresentationType in ["Tessellation", "Brep", "Annotation2D"]:
|
||||
IfcStore.edited_objs.add(obj)
|
||||
elif IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id).is_a("IfcGridAxis"):
|
||||
IfcStore.edited_objs.add(obj)
|
||||
|
||||
|
||||
def name_callback(obj, data):
|
||||
# TODO Do we still need this, now that we are monitoring the undo redo objects?
|
||||
try:
|
||||
obj.name
|
||||
except:
|
||||
return # In case the object RNA is gone during an undo / redo operation
|
||||
# Blender names are up to 63 UTF-8 bytes
|
||||
if len(bytes(obj.name, "utf-8")) >= 63:
|
||||
return
|
||||
|
||||
if isinstance(obj, bpy.types.Material):
|
||||
if obj.BIMObjectProperties.ifc_definition_id:
|
||||
IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id).Name = obj.name
|
||||
AttributeData.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
||||
MaterialData.load_materials()
|
||||
if obj.BIMMaterialProperties.ifc_style_id:
|
||||
IfcStore.get_file().by_id(obj.BIMMaterialProperties.ifc_style_id).Name = obj.name
|
||||
StyleData.load(IfcStore.get_file(), obj.BIMMaterialProperties.ifc_style_id)
|
||||
return
|
||||
|
||||
if not obj.BIMObjectProperties.ifc_definition_id or "/" not in obj.name:
|
||||
return
|
||||
element = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
if not element.is_a("IfcRoot"):
|
||||
return
|
||||
if element.is_a("IfcSpatialStructureElement") or (hasattr(element, "IsDecomposedBy") and element.IsDecomposedBy):
|
||||
collection = obj.users_collection[0]
|
||||
collection.name = obj.name
|
||||
if element.is_a("IfcGrid"):
|
||||
axis_obj = IfcStore.get_element(element.UAxes[0].id())
|
||||
axis_collection = axis_obj.users_collection[0]
|
||||
grid_collection = None
|
||||
for collection in bpy.data.collections:
|
||||
if axis_collection.name in collection.children.keys():
|
||||
grid_collection = collection
|
||||
break
|
||||
if grid_collection:
|
||||
grid_collection.name = obj.name
|
||||
if element.is_a("IfcTypeProduct"):
|
||||
TypeData.purge()
|
||||
element.Name = "/".join(obj.name.split("/")[1:])
|
||||
AttributeData.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
||||
|
||||
|
||||
def color_callback(obj, data):
|
||||
if obj.BIMMaterialProperties.ifc_style_id:
|
||||
IfcStore.edited_objs.add(obj)
|
||||
|
||||
|
||||
def active_object_callback():
|
||||
obj = bpy.context.active_object
|
||||
for obj in bpy.context.selected_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
continue
|
||||
stored_obj = IfcStore.get_element(obj.BIMObjectProperties.ifc_definition_id)
|
||||
if stored_obj and stored_obj != obj:
|
||||
bpy.ops.bim.copy_class(obj=obj.name)
|
||||
|
||||
|
||||
def subscribe_to(object, data_path, callback):
|
||||
try:
|
||||
subscribe_to = object.path_resolve(data_path, False)
|
||||
except:
|
||||
return
|
||||
bpy.msgbus.subscribe_rna(
|
||||
key=subscribe_to,
|
||||
owner=object,
|
||||
args=(
|
||||
object,
|
||||
data_path,
|
||||
),
|
||||
notify=callback,
|
||||
options={
|
||||
"PERSISTENT",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def purge_module_data():
|
||||
from blenderbim.bim import modules
|
||||
|
||||
for name, value in modules.items():
|
||||
try:
|
||||
getattr(getattr(getattr(ifcopenshell.api, name), "data"), "Data").purge()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
getattr(value, "prop").purge()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
@persistent
|
||||
def loadIfcStore(scene):
|
||||
IfcStore.purge()
|
||||
purge_module_data()
|
||||
if not IfcStore.get_file():
|
||||
return
|
||||
IfcStore.get_schema()
|
||||
IfcStore.reload_linked_elements()
|
||||
|
||||
|
||||
@persistent
|
||||
def undo_pre(scene):
|
||||
IfcStore.update_undo_redo_stack_objects()
|
||||
|
||||
|
||||
@persistent
|
||||
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()
|
||||
purge_module_data()
|
||||
IfcStore.update_undo_redo_stack_objects()
|
||||
IfcStore.reload_linked_elements(objects=[bpy.data.objects.get(o) for o in IfcStore.undo_redo_stack_objects])
|
||||
|
||||
|
||||
@persistent
|
||||
def redo_pre(scene):
|
||||
IfcStore.update_undo_redo_stack_objects()
|
||||
|
||||
|
||||
@persistent
|
||||
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()
|
||||
purge_module_data()
|
||||
IfcStore.update_undo_redo_stack_objects()
|
||||
IfcStore.reload_linked_elements(objects=[bpy.data.objects.get(o) for o in IfcStore.undo_redo_stack_objects])
|
||||
|
||||
|
||||
@persistent
|
||||
def ensureIfcExported(scene):
|
||||
if IfcStore.get_file() and not bpy.context.scene.BIMProperties.ifc_file:
|
||||
bpy.ops.export_ifc.bim("INVOKE_DEFAULT")
|
||||
|
||||
|
||||
def get_application(ifc):
|
||||
version = get_application_version()
|
||||
for element in ifc.by_type("IfcApplication"):
|
||||
if element.ApplicationIdentifier == "BlenderBIM" and element.Version == version:
|
||||
return element
|
||||
return ifcopenshell.api.run(
|
||||
"owner.add_application",
|
||||
ifc,
|
||||
version=get_application_version(),
|
||||
application_full_name="BlenderBIM Add-on",
|
||||
application_identifier="BlenderBIM",
|
||||
)
|
||||
|
||||
|
||||
def get_application_version():
|
||||
return ".".join(
|
||||
[
|
||||
str(x)
|
||||
for x in [
|
||||
addon.bl_info.get("version", (-1, -1, -1))
|
||||
for addon in addon_utils.modules()
|
||||
if addon.bl_info["name"] == "BlenderBIM"
|
||||
][0]
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@persistent
|
||||
def setDefaultProperties(scene):
|
||||
global global_subscription_owner
|
||||
active_object_key = bpy.types.LayerObjects, "active"
|
||||
bpy.msgbus.subscribe_rna(
|
||||
key=active_object_key, owner=global_subscription_owner, args=(), notify=active_object_callback
|
||||
)
|
||||
ifcopenshell.api.owner.settings.get_person = (
|
||||
lambda ifc: ifc.by_id(int(bpy.context.scene.BIMOwnerProperties.user_person))
|
||||
if getPersons(None, None) and bpy.context.scene.BIMOwnerProperties.user_person
|
||||
else None
|
||||
)
|
||||
ifcopenshell.api.owner.settings.get_organisation = (
|
||||
lambda ifc: ifc.by_id(int(bpy.context.scene.BIMOwnerProperties.user_organisation))
|
||||
if getOrganisations(None, None) and bpy.context.scene.BIMOwnerProperties.user_organisation
|
||||
else None
|
||||
)
|
||||
ifcopenshell.api.owner.settings.get_application = get_application
|
||||
if len(bpy.context.scene.DocProperties.drawing_styles) == 0:
|
||||
drawing_style = bpy.context.scene.DocProperties.drawing_styles.add()
|
||||
drawing_style.name = "Technical"
|
||||
drawing_style.render_type = "VIEWPORT"
|
||||
drawing_style.raster_style = json.dumps(
|
||||
{
|
||||
RasterStyleProperty.WORLD_COLOR.value: (1, 1, 1),
|
||||
RasterStyleProperty.RENDER_ENGINE.value: "BLENDER_WORKBENCH",
|
||||
RasterStyleProperty.RENDER_TRANSPARENT.value: False,
|
||||
RasterStyleProperty.SHADING_SHOW_OBJECT_OUTLINE.value: True,
|
||||
RasterStyleProperty.SHADING_SHOW_CAVITY.value: False,
|
||||
RasterStyleProperty.SHADING_CAVITY_TYPE.value: "BOTH",
|
||||
RasterStyleProperty.SHADING_CURVATURE_RIDGE_FACTOR.value: 1,
|
||||
RasterStyleProperty.SHADING_CURVATURE_VALLEY_FACTOR.value: 1,
|
||||
RasterStyleProperty.VIEW_TRANSFORM.value: "Standard",
|
||||
RasterStyleProperty.SHADING_LIGHT.value: "FLAT",
|
||||
RasterStyleProperty.SHADING_COLOR_TYPE.value: "SINGLE",
|
||||
RasterStyleProperty.SHADING_SINGLE_COLOR.value: (1, 1, 1),
|
||||
RasterStyleProperty.SHADING_SHOW_SHADOWS.value: False,
|
||||
RasterStyleProperty.SHADING_SHADOW_INTENSITY.value: 0.5,
|
||||
RasterStyleProperty.DISPLAY_LIGHT_DIRECTION.value: (0.5, 0.5, 0.5),
|
||||
RasterStyleProperty.VIEW_USE_CURVE_MAPPING.value: False,
|
||||
RasterStyleProperty.OVERLAY_SHOW_WIREFRAMES.value: True,
|
||||
RasterStyleProperty.OVERLAY_WIREFRAME_THRESHOLD.value: 0,
|
||||
RasterStyleProperty.OVERLAY_SHOW_FLOOR.value: False,
|
||||
RasterStyleProperty.OVERLAY_SHOW_AXIS_X.value: False,
|
||||
RasterStyleProperty.OVERLAY_SHOW_AXIS_Y.value: False,
|
||||
RasterStyleProperty.OVERLAY_SHOW_AXIS_Z.value: False,
|
||||
RasterStyleProperty.OVERLAY_SHOW_OBJECT_ORIGINS.value: False,
|
||||
RasterStyleProperty.OVERLAY_SHOW_RELATIONSHIP_LINES.value: False,
|
||||
}
|
||||
)
|
||||
drawing_style = bpy.context.scene.DocProperties.drawing_styles.add()
|
||||
drawing_style.name = "Shaded"
|
||||
drawing_style.render_type = "VIEWPORT"
|
||||
drawing_style.raster_style = json.dumps(
|
||||
{
|
||||
RasterStyleProperty.WORLD_COLOR.value: (1, 1, 1),
|
||||
RasterStyleProperty.RENDER_ENGINE.value: "BLENDER_WORKBENCH",
|
||||
RasterStyleProperty.RENDER_TRANSPARENT.value: False,
|
||||
RasterStyleProperty.SHADING_SHOW_OBJECT_OUTLINE.value: True,
|
||||
RasterStyleProperty.SHADING_SHOW_CAVITY.value: True,
|
||||
RasterStyleProperty.SHADING_CAVITY_TYPE.value: "BOTH",
|
||||
RasterStyleProperty.SHADING_CURVATURE_RIDGE_FACTOR.value: 1,
|
||||
RasterStyleProperty.SHADING_CURVATURE_VALLEY_FACTOR.value: 1,
|
||||
RasterStyleProperty.VIEW_TRANSFORM.value: "Standard",
|
||||
RasterStyleProperty.SHADING_LIGHT.value: "STUDIO",
|
||||
RasterStyleProperty.SHADING_COLOR_TYPE.value: "MATERIAL",
|
||||
RasterStyleProperty.SHADING_SINGLE_COLOR.value: (1, 1, 1),
|
||||
RasterStyleProperty.SHADING_SHOW_SHADOWS.value: True,
|
||||
RasterStyleProperty.SHADING_SHADOW_INTENSITY.value: 0.5,
|
||||
RasterStyleProperty.DISPLAY_LIGHT_DIRECTION.value: (0.5, 0.5, 0.5),
|
||||
RasterStyleProperty.VIEW_USE_CURVE_MAPPING.value: False,
|
||||
RasterStyleProperty.OVERLAY_SHOW_WIREFRAMES.value: True,
|
||||
RasterStyleProperty.OVERLAY_WIREFRAME_THRESHOLD.value: 0,
|
||||
RasterStyleProperty.OVERLAY_SHOW_FLOOR.value: False,
|
||||
RasterStyleProperty.OVERLAY_SHOW_AXIS_X.value: False,
|
||||
RasterStyleProperty.OVERLAY_SHOW_AXIS_Y.value: False,
|
||||
RasterStyleProperty.OVERLAY_SHOW_AXIS_Z.value: False,
|
||||
RasterStyleProperty.OVERLAY_SHOW_OBJECT_ORIGINS.value: False,
|
||||
RasterStyleProperty.OVERLAY_SHOW_RELATIONSHIP_LINES.value: False,
|
||||
}
|
||||
)
|
||||
drawing_style = bpy.context.scene.DocProperties.drawing_styles.add()
|
||||
drawing_style.name = "Blender Default"
|
||||
drawing_style.render_type = "DEFAULT"
|
||||
bpy.ops.bim.save_drawing_style(index="2")
|
||||
@@ -0,0 +1,89 @@
|
||||
# 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 json
|
||||
import math
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.attribute
|
||||
from mathutils import geometry
|
||||
from mathutils import Vector
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
def draw_attributes(props, layout, copy_operator=None):
|
||||
for attribute in props:
|
||||
row = layout.row(align=True)
|
||||
draw_attribute(attribute, row, copy_operator)
|
||||
|
||||
|
||||
def draw_attribute(attribute, layout, copy_operator=None):
|
||||
value_name = attribute.get_value_name()
|
||||
if not value_name:
|
||||
layout.label(text=attribute.name)
|
||||
return
|
||||
layout.prop(
|
||||
attribute,
|
||||
value_name,
|
||||
text=attribute.name,
|
||||
)
|
||||
if attribute.is_optional:
|
||||
layout.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||
if copy_operator:
|
||||
op = layout.operator(f"{copy_operator}", text="", icon="COPYDOWN")
|
||||
op.data = json.dumps({"name": attribute.name, "value": attribute.get_value(), "is_null": attribute.is_null})
|
||||
|
||||
|
||||
def import_attributes(ifc_class, props, data, callback=None):
|
||||
for attribute in IfcStore.get_schema().declaration_by_name(ifc_class).all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if isinstance(data_type, tuple) or data_type == "entity":
|
||||
callback(attribute.name(), None, data) if callback else None
|
||||
continue
|
||||
new = props.add()
|
||||
new.name = attribute.name()
|
||||
new.is_null = data[attribute.name()] is None
|
||||
new.is_optional = attribute.optional()
|
||||
new.data_type = data_type if isinstance(data_type, str) else ""
|
||||
is_handled_by_callback = callback(attribute.name(), new, data) if callback else None
|
||||
if is_handled_by_callback:
|
||||
pass # Our job is done
|
||||
elif is_handled_by_callback is False:
|
||||
props.remove(len(props) - 1)
|
||||
elif data_type == "string":
|
||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
||||
elif data_type == "boolean":
|
||||
new.bool_value = False if new.is_null else data[attribute.name()]
|
||||
elif data_type == "integer":
|
||||
new.int_value = 0 if new.is_null else data[attribute.name()]
|
||||
elif data_type == "float":
|
||||
new.float_value = 0.0 if new.is_null else data[attribute.name()]
|
||||
elif data_type == "enum":
|
||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
||||
if data[attribute.name()]:
|
||||
new.enum_value = data[attribute.name()]
|
||||
|
||||
|
||||
def export_attributes(props, callback=None):
|
||||
attributes = {}
|
||||
for prop in props:
|
||||
is_handled_by_callback = callback(attributes, prop) if callback else False
|
||||
if is_handled_by_callback:
|
||||
continue # Our job is done
|
||||
attributes[prop.name] = prop.get_value()
|
||||
return attributes
|
||||
@@ -0,0 +1,288 @@
|
||||
# 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 uuid
|
||||
import zipfile
|
||||
import tempfile
|
||||
import ifcopenshell
|
||||
import blenderbim.bim.handler
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class IfcStore:
|
||||
path = ""
|
||||
file = None
|
||||
schema = None
|
||||
id_map = {}
|
||||
guid_map = {}
|
||||
edited_objs = set()
|
||||
pset_template_path = ""
|
||||
pset_template_file = None
|
||||
library_path = ""
|
||||
library_file = None
|
||||
element_listeners = set()
|
||||
undo_redo_stack_objects = set()
|
||||
current_transaction = ""
|
||||
last_transaction = ""
|
||||
history = []
|
||||
future = []
|
||||
|
||||
@staticmethod
|
||||
def purge():
|
||||
IfcStore.path = ""
|
||||
IfcStore.file = None
|
||||
IfcStore.schema = None
|
||||
IfcStore.id_map = {}
|
||||
IfcStore.guid_map = {}
|
||||
IfcStore.edited_objs = set()
|
||||
IfcStore.pset_template_path = ""
|
||||
IfcStore.pset_template_file = None
|
||||
IfcStore.library_path = ""
|
||||
IfcStore.library_file = None
|
||||
|
||||
@staticmethod
|
||||
def get_file():
|
||||
if IfcStore.file is None:
|
||||
IfcStore.path = bpy.context.scene.BIMProperties.ifc_file
|
||||
if IfcStore.path:
|
||||
try:
|
||||
IfcStore.load_file(IfcStore.path)
|
||||
except:
|
||||
pass
|
||||
return IfcStore.file
|
||||
|
||||
@staticmethod
|
||||
def load_file(path):
|
||||
extension = path.split(".")[-1]
|
||||
if extension.lower() == "ifczip":
|
||||
with tempfile.TemporaryDirectory() as unzipped_path:
|
||||
with zipfile.ZipFile(path, "r") as zip_ref:
|
||||
zip_ref.extractall(unzipped_path)
|
||||
for filename in Path(unzipped_path).glob("**/*.ifc"):
|
||||
IfcStore.file = ifcopenshell.open(filename)
|
||||
return
|
||||
elif extension.lower() == "ifcxml":
|
||||
IfcStore.file = ifcopenshell.file(ifcopenshell.ifcopenshell_wrapper.parse_ifcxml(path))
|
||||
elif extension.lower() == "ifc":
|
||||
IfcStore.file = ifcopenshell.open(path)
|
||||
|
||||
@staticmethod
|
||||
def get_schema():
|
||||
if IfcStore.file is None:
|
||||
return
|
||||
elif IfcStore.schema is None:
|
||||
IfcStore.schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(IfcStore.file.schema)
|
||||
return IfcStore.schema
|
||||
|
||||
@staticmethod
|
||||
def get_element(id_or_guid):
|
||||
if isinstance(id_or_guid, int):
|
||||
map_object = IfcStore.id_map
|
||||
else:
|
||||
map_object = IfcStore.guid_map
|
||||
try:
|
||||
obj = map_object[id_or_guid]
|
||||
obj.name # In case the object has been deleted, this triggers an exception
|
||||
except:
|
||||
return
|
||||
return obj
|
||||
|
||||
@staticmethod
|
||||
def add_element_listener(callback):
|
||||
IfcStore.element_listeners.add(callback)
|
||||
|
||||
@staticmethod
|
||||
def update_undo_redo_stack_objects():
|
||||
"""Keeps track of selected object names, typically during undo and redo
|
||||
|
||||
When any Blender object is stored outside a Blender PointerProperty, such as
|
||||
in a regular Python list, there is the likely probability that the object
|
||||
will be invalidated when undo or redo occurs. Object invalidation seems to
|
||||
only occur for selected objects either pre/post undo/redo event, including
|
||||
selected objects for consecutive undo/redos, and all children.
|
||||
|
||||
So if I first select o1, then o2, then o3, then press undo, o3 will be
|
||||
invalidated. If instead I press undo twice, o3 and o2 will be invalidated.
|
||||
"""
|
||||
if bpy.context.active_object:
|
||||
objects = set([o.name for o in bpy.context.selected_objects + [bpy.context.active_object]])
|
||||
objects.update([o.name for o in bpy.context.active_object.children])
|
||||
else:
|
||||
objects = set([o.name for o in bpy.context.selected_objects])
|
||||
for obj in bpy.context.selected_objects:
|
||||
objects.update([o.name for o in obj.children])
|
||||
IfcStore.undo_redo_stack_objects |= objects
|
||||
|
||||
@staticmethod
|
||||
def reload_linked_elements(objects=None):
|
||||
file = IfcStore.get_file()
|
||||
if not file:
|
||||
return
|
||||
if objects is None:
|
||||
objects = bpy.data.objects
|
||||
|
||||
for obj in objects:
|
||||
if not obj:
|
||||
continue
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
continue
|
||||
element = file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
data = {"id": element.id(), "obj": obj.name}
|
||||
if hasattr(element, "GlobalId"):
|
||||
data["guid"] = element.GlobalId
|
||||
IfcStore.commit_link_element(data)
|
||||
|
||||
@staticmethod
|
||||
def link_element(element, obj):
|
||||
IfcStore.id_map[element.id()] = obj
|
||||
if hasattr(element, "GlobalId"):
|
||||
IfcStore.guid_map[element.GlobalId] = obj
|
||||
|
||||
if element.is_a("IfcSurfaceStyle"):
|
||||
obj.BIMMaterialProperties.ifc_style_id = element.id()
|
||||
else:
|
||||
obj.BIMObjectProperties.ifc_definition_id = element.id()
|
||||
|
||||
blenderbim.bim.handler.subscribe_to(obj, "name", blenderbim.bim.handler.name_callback)
|
||||
|
||||
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)
|
||||
|
||||
for listener in IfcStore.element_listeners:
|
||||
listener(element, obj)
|
||||
|
||||
if IfcStore.history:
|
||||
data = {"id": element.id(), "guid": getattr(element, "GlobalId", None), "obj": obj.name}
|
||||
IfcStore.history[-1]["operations"].append(
|
||||
{"rollback": IfcStore.rollback_link_element, "commit": IfcStore.commit_link_element, "data": data}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def rollback_link_element(data):
|
||||
del IfcStore.id_map[data["id"]]
|
||||
if data["guid"]:
|
||||
del IfcStore.guid_map[data["guid"]]
|
||||
|
||||
@staticmethod
|
||||
def commit_link_element(data):
|
||||
obj = bpy.data.objects.get(data["obj"])
|
||||
IfcStore.id_map[data["id"]] = obj
|
||||
if "guid" in data:
|
||||
IfcStore.guid_map[data["guid"]] = obj
|
||||
blenderbim.bim.handler.subscribe_to(obj, "mode", blenderbim.bim.handler.mode_callback)
|
||||
blenderbim.bim.handler.subscribe_to(obj, "name", blenderbim.bim.handler.name_callback)
|
||||
if isinstance(obj, bpy.types.Material):
|
||||
blenderbim.bim.handler.subscribe_to(obj, "diffuse_color", blenderbim.bim.handler.color_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 unlink_element(element=None, obj=None):
|
||||
if element is None:
|
||||
try:
|
||||
element = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
if element:
|
||||
del IfcStore.id_map[element.id()]
|
||||
else:
|
||||
del IfcStore.id_map[obj.BIMObjectProperties.ifc_definition_id]
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
if element and hasattr(element, "GlobalId"):
|
||||
del IfcStore.guid_map[element.GlobalId]
|
||||
except:
|
||||
pass
|
||||
|
||||
if obj:
|
||||
obj.BIMObjectProperties.ifc_definition_id = 0
|
||||
|
||||
@staticmethod
|
||||
def execute_ifc_operator(operator, context):
|
||||
is_top_level_operator = not bool(IfcStore.current_transaction)
|
||||
|
||||
if is_top_level_operator:
|
||||
IfcStore.begin_transaction(operator)
|
||||
IfcStore.get_file().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)
|
||||
else:
|
||||
operator.transaction_key = IfcStore.current_transaction
|
||||
|
||||
result = getattr(operator, "_execute")(context)
|
||||
|
||||
if is_top_level_operator:
|
||||
IfcStore.get_file().end_transaction()
|
||||
IfcStore.add_transaction_operation(
|
||||
operator, rollback=lambda d: IfcStore.get_file().undo(), commit=lambda d: IfcStore.get_file().redo()
|
||||
)
|
||||
IfcStore.end_transaction(operator)
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def begin_transaction(operator):
|
||||
IfcStore.undo_redo_stack_objects = set()
|
||||
IfcStore.current_transaction = str(uuid.uuid4())
|
||||
operator.transaction_key = IfcStore.current_transaction
|
||||
|
||||
@staticmethod
|
||||
def end_transaction(operator):
|
||||
IfcStore.current_transaction = ""
|
||||
operator.transaction_key = ""
|
||||
|
||||
@staticmethod
|
||||
def add_transaction_operation(operator, rollback=None, commit=None):
|
||||
key = getattr(operator, "transaction_key", None)
|
||||
data = getattr(operator, "transaction_data", None)
|
||||
bpy.context.scene.BIMProperties.last_transaction = key
|
||||
IfcStore.last_transaction = key
|
||||
rollback = rollback or getattr(operator, "rollback", lambda data: True)
|
||||
commit = commit or getattr(operator, "commit", lambda data: True)
|
||||
if IfcStore.history and IfcStore.history[-1]["key"] == key:
|
||||
IfcStore.history[-1]["operations"].append({"rollback": rollback, "commit": commit, "data": data})
|
||||
else:
|
||||
IfcStore.history.append(
|
||||
{"key": key, "operations": [{"rollback": rollback, "commit": commit, "data": data}]}
|
||||
)
|
||||
IfcStore.future = []
|
||||
|
||||
@staticmethod
|
||||
def undo():
|
||||
if not IfcStore.history:
|
||||
return
|
||||
event = IfcStore.history.pop()
|
||||
for transaction in event["operations"][::-1]:
|
||||
transaction["rollback"](transaction["data"])
|
||||
IfcStore.future.append(event)
|
||||
|
||||
@staticmethod
|
||||
def redo():
|
||||
if not IfcStore.future:
|
||||
return
|
||||
event = IfcStore.future.pop()
|
||||
for transaction in event["operations"]:
|
||||
transaction["commit"](transaction["data"])
|
||||
IfcStore.history.append(event)
|
||||
@@ -0,0 +1,17 @@
|
||||
# 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/>.
|
||||
@@ -0,0 +1,36 @@
|
||||
# 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 ui, operator
|
||||
|
||||
classes = (
|
||||
operator.AssignObject,
|
||||
operator.EnableEditingAggregate,
|
||||
operator.DisableEditingAggregate,
|
||||
operator.AddAggregate,
|
||||
ui.BIM_PT_aggregate,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
pass
|
||||
|
||||
|
||||
def unregister():
|
||||
pass
|
||||
@@ -0,0 +1,122 @@
|
||||
# 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 ifcopenshell.api
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.aggregate.data import Data
|
||||
|
||||
|
||||
class AssignObject(bpy.types.Operator):
|
||||
bl_idname = "bim.assign_object"
|
||||
bl_label = "Assign Object"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
relating_object: bpy.props.StringProperty()
|
||||
related_object: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
related_objects = (
|
||||
[bpy.data.objects.get(self.related_object)] if self.related_object else context.selected_objects
|
||||
)
|
||||
relating_object = bpy.data.objects.get(self.relating_object)
|
||||
if not relating_object or not relating_object.BIMObjectProperties.ifc_definition_id:
|
||||
return {"FINISHED"}
|
||||
for related_object in related_objects:
|
||||
oprops = related_object.BIMObjectProperties
|
||||
product = self.file.by_id(oprops.ifc_definition_id)
|
||||
ifcopenshell.api.run(
|
||||
"aggregate.assign_object",
|
||||
self.file,
|
||||
**{
|
||||
"product": product,
|
||||
"relating_object": self.file.by_id(relating_object.BIMObjectProperties.ifc_definition_id),
|
||||
},
|
||||
)
|
||||
bpy.ops.bim.edit_object_placement(obj=related_object.name)
|
||||
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
|
||||
bpy.ops.bim.disable_editing_aggregate(obj=related_object.name)
|
||||
|
||||
spatial_collection = bpy.data.collections.get(related_object.name)
|
||||
relating_collection = bpy.data.collections.get(relating_object.name)
|
||||
if spatial_collection:
|
||||
self.remove_collection(context.scene.collection, spatial_collection)
|
||||
for collection in bpy.data.collections:
|
||||
if collection == relating_collection:
|
||||
if not collection.children.get(spatial_collection.name):
|
||||
collection.children.link(spatial_collection)
|
||||
continue
|
||||
self.remove_collection(collection, spatial_collection)
|
||||
else:
|
||||
for collection in related_object.users_collection:
|
||||
if collection.name.startswith("Ifc"):
|
||||
collection.objects.unlink(related_object)
|
||||
relating_collection.objects.link(related_object)
|
||||
return {"FINISHED"}
|
||||
|
||||
def remove_collection(self, parent, child):
|
||||
try:
|
||||
parent.children.unlink(child)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
class EnableEditingAggregate(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_aggregate"
|
||||
bl_label = "Enable Editing Aggregate"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
context.active_object.BIMObjectProperties.relating_object = None
|
||||
context.active_object.BIMObjectProperties.is_editing_aggregate = True
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableEditingAggregate(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_aggregate"
|
||||
bl_label = "Disable Editing Aggregate"
|
||||
obj: bpy.props.StringProperty()
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
||||
obj.BIMObjectProperties.is_editing_aggregate = False
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddAggregate(bpy.types.Operator):
|
||||
bl_idname = "bim.add_aggregate"
|
||||
bl_label = "Add Aggregate"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
||||
aggregate_collection = bpy.data.collections.new("IfcElementAssembly/Assembly")
|
||||
context.scene.collection.children.link(aggregate_collection)
|
||||
aggregate = bpy.data.objects.new("Assembly", None)
|
||||
aggregate_collection.objects.link(aggregate)
|
||||
bpy.ops.bim.assign_class(obj=aggregate.name, ifc_class="IfcElementAssembly")
|
||||
bpy.ops.bim.assign_object(related_object=obj.name, relating_object=aggregate.name)
|
||||
return {"FINISHED"}
|
||||
@@ -1,5 +1,23 @@
|
||||
# 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/>.
|
||||
|
||||
from bpy.types import Panel
|
||||
from blenderbim.bim.module.aggregate.data import Data
|
||||
from ifcopenshell.api.aggregate.data import Data
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
@@ -16,10 +34,12 @@ class BIM_PT_aggregate(Panel):
|
||||
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
|
||||
if props.ifc_definition_id not in Data.products:
|
||||
Data.load(props.ifc_definition_id)
|
||||
Data.load(IfcStore.get_file(), props.ifc_definition_id)
|
||||
if not Data.products[props.ifc_definition_id]:
|
||||
return False
|
||||
return True
|
||||
@@ -29,13 +49,16 @@ class BIM_PT_aggregate(Panel):
|
||||
if not props.ifc_definition_id:
|
||||
return
|
||||
if props.ifc_definition_id not in Data.products:
|
||||
Data.load(props.ifc_definition_id)
|
||||
Data.load(IfcStore.get_file(), props.ifc_definition_id)
|
||||
|
||||
if props.is_editing_aggregate:
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "relating_object", text="")
|
||||
row.operator("bim.assign_object", icon="CHECKMARK", text="")
|
||||
row.operator("bim.disable_editing_aggregate", icon="X", text="")
|
||||
if props.relating_object:
|
||||
row.operator(
|
||||
"bim.assign_object", icon="CHECKMARK", text=""
|
||||
).relating_object = props.relating_object.name
|
||||
row.operator("bim.disable_editing_aggregate", icon="CANCEL", text="")
|
||||
else:
|
||||
row = self.layout.row(align=True)
|
||||
name = "{}/{}".format(
|
||||
@@ -0,0 +1,40 @@
|
||||
# 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 ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.EnableEditingAttributes,
|
||||
operator.DisableEditingAttributes,
|
||||
operator.EditAttributes,
|
||||
operator.GenerateGlobalId,
|
||||
prop.BIMAttributeProperties,
|
||||
ui.BIM_PT_object_attributes,
|
||||
ui.BIM_PT_material_attributes,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Object.BIMAttributeProperties = bpy.props.PointerProperty(type=prop.BIMAttributeProperties)
|
||||
bpy.types.Material.BIMAttributeProperties = bpy.props.PointerProperty(type=prop.BIMAttributeProperties)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Object.BIMAttributeProperties
|
||||
del bpy.types.Material.BIMAttributeProperties
|
||||
@@ -1,14 +1,33 @@
|
||||
# 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 json
|
||||
import ifcopenshell
|
||||
import blenderbim.bim.module.attribute.edit_attributes as edit_attributes
|
||||
import ifcopenshell.api
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.attribute.data import Data
|
||||
from ifcopenshell.api.attribute.data import Data
|
||||
|
||||
|
||||
class EnableEditingAttributes(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_attributes"
|
||||
bl_label = "Enable Editing Attributes"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj: bpy.props.StringProperty()
|
||||
obj_type: bpy.props.StringProperty()
|
||||
|
||||
@@ -20,11 +39,10 @@ class EnableEditingAttributes(bpy.types.Operator):
|
||||
obj = bpy.data.materials.get(self.obj)
|
||||
oprops = obj.BIMObjectProperties
|
||||
props = obj.BIMAttributeProperties
|
||||
while len(props.attributes) > 0:
|
||||
props.attributes.remove(0)
|
||||
props.attributes.clear()
|
||||
for attribute in Data.products[oprops.ifc_definition_id]:
|
||||
new = props.attributes.add()
|
||||
if attribute["type"] == "entity":
|
||||
if attribute["type"] == "entity" or (attribute["type"] == "list" and attribute["list_type"] == "entity"):
|
||||
continue
|
||||
new.name = attribute["name"]
|
||||
new.is_null = attribute["is_null"]
|
||||
@@ -33,7 +51,7 @@ class EnableEditingAttributes(bpy.types.Operator):
|
||||
elif attribute["type"] == "integer":
|
||||
new.int_value = attribute["value"] or 0
|
||||
elif attribute["type"] == "float":
|
||||
new.float_value = attribute["value"] or 0.
|
||||
new.float_value = attribute["value"] or 0.0
|
||||
elif attribute["type"] == "enum":
|
||||
new.enum_items = json.dumps(attribute["enum_items"])
|
||||
if attribute["value"]:
|
||||
@@ -45,6 +63,7 @@ class EnableEditingAttributes(bpy.types.Operator):
|
||||
class DisableEditingAttributes(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_attributes"
|
||||
bl_label = "Disable Editing Attributes"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj: bpy.props.StringProperty()
|
||||
obj_type: bpy.props.StringProperty()
|
||||
|
||||
@@ -61,10 +80,14 @@ class DisableEditingAttributes(bpy.types.Operator):
|
||||
class EditAttributes(bpy.types.Operator):
|
||||
bl_idname = "bim.edit_attributes"
|
||||
bl_label = "Edit Attributes"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj: bpy.props.StringProperty()
|
||||
obj_type: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
if self.obj_type == "Object":
|
||||
obj = bpy.data.objects.get(self.obj)
|
||||
@@ -95,17 +118,8 @@ class EditAttributes(bpy.types.Operator):
|
||||
elif attribute["type"] == "enum":
|
||||
attributes[attribute["name"]] = blender_attribute.enum_value
|
||||
product = self.file.by_id(oprops.ifc_definition_id)
|
||||
edit_attributes.Usecase(self.file, {
|
||||
"product": product,
|
||||
"attributes": attributes
|
||||
}).execute()
|
||||
if "Name" in attributes:
|
||||
new_name = "{}/{}".format(product.is_a(), product.Name or "Unnamed")
|
||||
collection = bpy.data.collections.get(obj.name)
|
||||
if collection:
|
||||
collection.name = new_name
|
||||
obj.name = new_name
|
||||
Data.load(oprops.ifc_definition_id)
|
||||
ifcopenshell.api.run("attribute.edit_attributes", self.file, **{"product": product, "attributes": attributes})
|
||||
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
|
||||
bpy.ops.bim.disable_editing_attributes(obj=obj.name, obj_type=self.obj_type)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -113,13 +127,14 @@ class EditAttributes(bpy.types.Operator):
|
||||
class GenerateGlobalId(bpy.types.Operator):
|
||||
bl_idname = "bim.generate_global_id"
|
||||
bl_label = "Regenerate GlobalId"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
index = bpy.context.active_object.BIMAttributeProperties.attributes.find("GlobalId")
|
||||
index = context.active_object.BIMAttributeProperties.attributes.find("GlobalId")
|
||||
if index >= 0:
|
||||
global_id = bpy.context.active_object.BIMAttributeProperties.attributes[index]
|
||||
global_id = context.active_object.BIMAttributeProperties.attributes[index]
|
||||
else:
|
||||
global_id = bpy.context.active_object.BIMAttributeProperties.attributes.add()
|
||||
global_id = context.active_object.BIMAttributeProperties.attributes.add()
|
||||
global_id.name = "GlobalId"
|
||||
global_id.data_type = "string"
|
||||
global_id.string_value = ifcopenshell.guid.new()
|
||||
@@ -0,0 +1,37 @@
|
||||
# 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 blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
StringProperty,
|
||||
EnumProperty,
|
||||
BoolProperty,
|
||||
IntProperty,
|
||||
FloatProperty,
|
||||
FloatVectorProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
|
||||
|
||||
class BIMAttributeProperties(PropertyGroup):
|
||||
attributes: CollectionProperty(name="Attributes", type=Attribute)
|
||||
is_editing_attributes: BoolProperty(name="Is Editing Attributes")
|
||||
@@ -1,5 +1,24 @@
|
||||
# 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/>.
|
||||
|
||||
from bpy.types import Panel
|
||||
from blenderbim.bim.module.attribute.data import Data
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.attribute.data import Data
|
||||
|
||||
|
||||
def draw_ui(context, layout, obj_type):
|
||||
@@ -7,14 +26,14 @@ def draw_ui(context, layout, obj_type):
|
||||
oprops = obj.BIMObjectProperties
|
||||
props = obj.BIMAttributeProperties
|
||||
if oprops.ifc_definition_id not in Data.products:
|
||||
Data.load(oprops.ifc_definition_id)
|
||||
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
|
||||
|
||||
if props.is_editing_attributes:
|
||||
row = layout.row(align=True)
|
||||
op = row.operator("bim.edit_attributes", icon="CHECKMARK", text="Save Attributes")
|
||||
op.obj_type = obj_type
|
||||
op.obj = obj.name
|
||||
op = row.operator("bim.disable_editing_attributes", icon="X", text="")
|
||||
op = row.operator("bim.disable_editing_attributes", icon="CANCEL", text="")
|
||||
op.obj_type = obj_type
|
||||
op.obj = obj.name
|
||||
|
||||
@@ -41,15 +60,17 @@ def draw_ui(context, layout, obj_type):
|
||||
icon="RADIOBUT_OFF" if blender_attribute.is_null else "RADIOBUT_ON",
|
||||
text="",
|
||||
)
|
||||
# TODO: reimplement, see #1222
|
||||
# op = row.operator("bim.copy_attribute_to_selection", icon="COPYDOWN", text="")
|
||||
# op.attribute_name = attribute.name
|
||||
# op.attribute_value = attribute.string_value
|
||||
else:
|
||||
row = layout.row()
|
||||
op = row.operator("bim.enable_editing_attributes", icon="GREASEPENCIL", text="Edit")
|
||||
op.obj_type = obj_type
|
||||
op.obj = obj.name
|
||||
|
||||
if "GlobalId" not in [a["name"] for a in Data.products[oprops.ifc_definition_id]]:
|
||||
row = layout.row(align=True)
|
||||
row.label(text="STEP ID")
|
||||
row.label(text=str(oprops.ifc_definition_id))
|
||||
|
||||
for attribute in Data.products[oprops.ifc_definition_id]:
|
||||
if attribute["value"] is None or attribute["type"] == "entity":
|
||||
continue
|
||||
@@ -71,6 +92,8 @@ class BIM_PT_object_attributes(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not IfcStore.get_element(context.active_object.BIMObjectProperties.ifc_definition_id):
|
||||
return False
|
||||
return bool(context.active_object.BIMObjectProperties.ifc_definition_id)
|
||||
|
||||
def draw(self, context):
|
||||
@@ -78,7 +101,7 @@ class BIM_PT_object_attributes(Panel):
|
||||
|
||||
|
||||
class BIM_PT_material_attributes(Panel):
|
||||
bl_label = "IFC Attributes"
|
||||
bl_label = "IFC Material Attributes"
|
||||
bl_idname = "BIM_PT_material_attributes"
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
@@ -86,6 +109,8 @@ class BIM_PT_material_attributes(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not IfcStore.get_file():
|
||||
return False
|
||||
try:
|
||||
return bool(context.active_object.active_material.BIMObjectProperties.ifc_definition_id)
|
||||
except:
|
||||
@@ -0,0 +1,36 @@
|
||||
# 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 ui, prop, operator
|
||||
|
||||
classes = (
|
||||
prop.AuginProperties,
|
||||
ui.BIM_PT_augin,
|
||||
operator.AuginLogin,
|
||||
operator.AuginCreateNewModel,
|
||||
operator.AuginReset,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Scene.AuginProperties = bpy.props.PointerProperty(type=prop.AuginProperties)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.AuginProperties
|
||||
@@ -0,0 +1,154 @@
|
||||
# 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 os
|
||||
import bpy
|
||||
import json
|
||||
import string
|
||||
import random
|
||||
import shutil
|
||||
import requests
|
||||
import tempfile
|
||||
import datetime
|
||||
import addon_utils
|
||||
|
||||
|
||||
class AuginLogin(bpy.types.Operator):
|
||||
bl_idname = "bim.augin_login"
|
||||
bl_label = "Login to Augin"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.AuginProperties
|
||||
|
||||
url = "https://server.auge.pro.br/API/v3/augin_rest.php/user_login"
|
||||
payload = {"email": props.username, "password": props.password}
|
||||
response = requests.request("POST", url, data=payload)
|
||||
result = response.json()
|
||||
|
||||
if result["success_feedback"]["success"]:
|
||||
props.token = result["token"]
|
||||
else:
|
||||
self.report({"ERROR"}, "Login failed :(")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AuginReset(bpy.types.Operator):
|
||||
bl_idname = "bim.augin_reset"
|
||||
bl_label = "Upload Another Project"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.AuginProperties
|
||||
props.is_success = False
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AuginCreateNewModel(bpy.types.Operator):
|
||||
bl_idname = "bim.augin_create_new_model"
|
||||
bl_label = "Create New Augin Model"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
import boto3
|
||||
from botocore.config import Config
|
||||
|
||||
props = context.scene.AuginProperties
|
||||
|
||||
# Create project
|
||||
url = "https://server.auge.pro.br/API/v3/augin_rest.php/new_model"
|
||||
|
||||
chars = string.ascii_uppercase + string.ascii_lowercase + string.digits
|
||||
props.project_filename = "BBM{}{}".format(
|
||||
datetime.datetime.now().strftime("%Y%m%d%H%M%S"), "".join(random.choice(chars) for _ in range(6))
|
||||
)
|
||||
addon_version = ".".join(
|
||||
[
|
||||
str(x)
|
||||
for x in [
|
||||
addon.bl_info.get("version", (-1, -1, -1))
|
||||
for addon in addon_utils.modules()
|
||||
if addon.bl_info["name"] == "BlenderBIM"
|
||||
][0]
|
||||
]
|
||||
)
|
||||
|
||||
payload = {
|
||||
"user_token": props.token,
|
||||
"partner_token": "Mmf2zpxdgrkHaUNRm6Cv7GLJdBAeb7Rn",
|
||||
"project_name": props.project_name,
|
||||
"model_filename": props.project_filename + ".ifc",
|
||||
"thumb_filename": props.project_filename + ".png",
|
||||
"app_name": "BlenderBIM",
|
||||
"sw_version": bpy.app.version_string,
|
||||
"plugin_version": addon_version,
|
||||
}
|
||||
response = requests.request("POST", url, data=payload)
|
||||
result = response.json()
|
||||
|
||||
# Upload to S3
|
||||
my_config = Config(
|
||||
region_name=result["s3_region"],
|
||||
)
|
||||
|
||||
client = boto3.client(
|
||||
"s3",
|
||||
aws_access_key_id=result["s3_key"],
|
||||
aws_secret_access_key=result["s3_secret"],
|
||||
aws_session_token=result["s3_token"],
|
||||
config=my_config,
|
||||
)
|
||||
|
||||
# Generate thumb
|
||||
old_file_format = context.scene.render.image_settings.file_format
|
||||
old_filepath = context.scene.render.filepath
|
||||
|
||||
cam = bpy.data.cameras.new("Camera")
|
||||
cam_obj = bpy.data.objects.new("Camera", cam)
|
||||
context.scene.collection.objects.link(cam_obj)
|
||||
context.scene.camera = cam_obj
|
||||
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
thumb_path = os.path.join(tmpdir, "thumb.png")
|
||||
context.scene.render.image_settings.file_format = "PNG"
|
||||
context.scene.render.filepath = thumb_path
|
||||
bpy.ops.render.opengl(write_still=True)
|
||||
|
||||
context.scene.render.image_settings.file_format = old_file_format
|
||||
context.scene.render.filepath = old_filepath
|
||||
|
||||
client.upload_file(context.scene.BIMProperties.ifc_file, result["s3_bucket"], result["model_path"])
|
||||
client.upload_file(thumb_path, result["s3_bucket"], result["thumb_path"])
|
||||
|
||||
# Notify done
|
||||
url = "https://server.auge.pro.br/API/v3/augin_rest.php/files_uploaded"
|
||||
payload = {
|
||||
"user_token": props.token,
|
||||
"ifc_filesize": os.path.getsize(context.scene.BIMProperties.ifc_file),
|
||||
"model_filesize": os.path.getsize(context.scene.BIMProperties.ifc_file),
|
||||
"thumb_filesize": os.path.getsize(thumb_path),
|
||||
"model_upload_path": result["model_path"],
|
||||
"thumb_upload_path": result["thumb_path"],
|
||||
"model_id": result["model_id"],
|
||||
}
|
||||
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
shutil.rmtree(tmpdir)
|
||||
props.is_success = True
|
||||
return {"FINISHED"}
|
||||
@@ -0,0 +1,29 @@
|
||||
# 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.props
|
||||
import bpy.types
|
||||
|
||||
|
||||
class AuginProperties(bpy.types.PropertyGroup):
|
||||
username: bpy.props.StringProperty(name="Username")
|
||||
password: bpy.props.StringProperty(name="Password")
|
||||
token: bpy.props.StringProperty(name="Token")
|
||||
project_name: bpy.props.StringProperty(name="Project Name")
|
||||
project_filename: bpy.props.StringProperty(name="IFC Filename")
|
||||
is_success: bpy.props.BoolProperty(name="Is Successful Upload", default=False)
|
||||
@@ -0,0 +1,63 @@
|
||||
# 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.types
|
||||
|
||||
|
||||
class BIM_PT_augin(bpy.types.Panel):
|
||||
bl_label = "Augin"
|
||||
bl_idname = "BIM_PT_augin"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
scene = context.scene
|
||||
props = scene.AuginProperties
|
||||
|
||||
if not props.token:
|
||||
row = layout.row()
|
||||
row.prop(props, "username")
|
||||
row = layout.row()
|
||||
row.prop(props, "password")
|
||||
row = layout.row()
|
||||
row.operator("bim.augin_login")
|
||||
return
|
||||
|
||||
row = layout.row()
|
||||
row.label(text="Logged in as " + props.username)
|
||||
|
||||
if not context.scene.BIMProperties.ifc_file:
|
||||
row = layout.row()
|
||||
row.label(text="No IFC Found")
|
||||
return
|
||||
|
||||
if props.is_success:
|
||||
row = layout.row()
|
||||
row.label(text="Upload Successful")
|
||||
row = layout.row()
|
||||
row.operator("bim.augin_reset")
|
||||
else:
|
||||
row = layout.row()
|
||||
row.prop(props, "project_name")
|
||||
row = layout.row()
|
||||
row.operator("bim.augin_create_new_model")
|
||||
@@ -1,3 +1,21 @@
|
||||
# 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 ui, prop, operator
|
||||
|
||||
@@ -20,6 +38,7 @@ classes = (
|
||||
operator.AddBcfLabel,
|
||||
operator.AddBcfRelatedTopic,
|
||||
operator.ViewBcfTopic,
|
||||
operator.RemoveBcfTopic,
|
||||
operator.RemoveBcfComment,
|
||||
operator.RemoveBcfBimSnippet,
|
||||
operator.RemoveBcfReferenceLink,
|
||||
@@ -0,0 +1,30 @@
|
||||
# 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 bcf
|
||||
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
|
||||
@@ -1,3 +1,21 @@
|
||||
# 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 bcfstore
|
||||
from blenderbim.bim.prop import StrProperty
|
||||
@@ -17,50 +35,49 @@ from bpy.props import (
|
||||
bcfviewpoints_enum = None
|
||||
|
||||
|
||||
def purge():
|
||||
global bcfviewpoints_enum
|
||||
bcfviewpoints_enum = None
|
||||
|
||||
|
||||
def updateBcfReferenceLink(self, context):
|
||||
if bpy.context.scene.BCFProperties.is_loaded:
|
||||
if context.scene.BCFProperties.is_loaded:
|
||||
bpy.ops.bim.edit_bcf_reference_links()
|
||||
|
||||
|
||||
def updateBcfLabel(self, context):
|
||||
if bpy.context.scene.BCFProperties.is_loaded:
|
||||
if context.scene.BCFProperties.is_loaded:
|
||||
bpy.ops.bim.edit_bcf_labels()
|
||||
|
||||
|
||||
def updateBcfProjectName(self, context):
|
||||
if bpy.context.scene.BCFProperties.is_loaded:
|
||||
if self.is_loaded:
|
||||
bpy.ops.bim.edit_bcf_project_name()
|
||||
|
||||
|
||||
def updateBcfAuthor(self, context):
|
||||
if bpy.context.scene.BCFProperties.is_loaded:
|
||||
if self.is_loaded:
|
||||
bpy.ops.bim.edit_bcf_author()
|
||||
|
||||
|
||||
def updateBcfTopicName(self, context):
|
||||
if bpy.context.scene.BCFProperties.is_loaded:
|
||||
if context.scene.BCFProperties.is_loaded:
|
||||
bpy.ops.bim.edit_bcf_topic_name()
|
||||
|
||||
|
||||
def updateBcfTopicIsEditable(self, context):
|
||||
if bpy.context.scene.BCFProperties.is_loaded and not self.is_editable:
|
||||
if context.scene.BCFProperties.is_loaded and not self.is_editable:
|
||||
bpy.ops.bim.edit_bcf_topic()
|
||||
|
||||
|
||||
def updateBcfCommentIsEditable(self, context):
|
||||
if bpy.context.scene.BCFProperties.is_loaded and not self.is_editable:
|
||||
bpy.ops.bim.edit_bcf_comment(comment_guid = self.name)
|
||||
if context.scene.BCFProperties.is_loaded and not self.is_editable:
|
||||
bpy.ops.bim.edit_bcf_comment(comment_guid=self.name)
|
||||
|
||||
|
||||
def refreshBcfTopic(self, context):
|
||||
global bcfviewpoints_enum
|
||||
bcfviewpoints_enum = None
|
||||
|
||||
props = bpy.context.scene.BCFProperties
|
||||
bcfxml = bcfstore.BcfStore.get_bcfxml()
|
||||
topic = props.topics[props.active_topic_index]
|
||||
header = bcfxml.get_header(topic.name)
|
||||
getBcfViewpoints(self, context)
|
||||
self.clear_input_fields()
|
||||
getBcfViewpoints(None, context, force_update=True)
|
||||
|
||||
|
||||
class BcfReferenceLink(PropertyGroup):
|
||||
@@ -71,13 +88,13 @@ class BcfLabel(PropertyGroup):
|
||||
name: StringProperty(name="Name", update=updateBcfLabel)
|
||||
|
||||
|
||||
def getBcfViewpoints(self, context):
|
||||
def getBcfViewpoints(self, context, force_update=False):
|
||||
global bcfviewpoints_enum
|
||||
if bcfviewpoints_enum is None:
|
||||
if bcfviewpoints_enum is None or force_update: # Retrieving Viewpoints is slow. Make sure we only do when needed
|
||||
bcfviewpoints_enum = []
|
||||
props = bpy.context.scene.BCFProperties
|
||||
props = context.scene.BCFProperties
|
||||
bcfxml = bcfstore.BcfStore.get_bcfxml()
|
||||
topic = props.topics[props.active_topic_index]
|
||||
topic = props.active_topic
|
||||
viewpoints = bcfxml.get_viewpoints(topic.name)
|
||||
bcfviewpoints_enum.extend([(v, f"Viewpoint {i+1}", "") for i, v in enumerate(viewpoints.keys())])
|
||||
return bcfviewpoints_enum
|
||||
@@ -122,28 +139,15 @@ class BcfTopic(PropertyGroup):
|
||||
assigned_to: StringProperty(default="", name="Assigned To")
|
||||
due_date: StringProperty(default="", name="Due Date")
|
||||
description: StringProperty(default="", name="Description")
|
||||
viewpoints: EnumProperty(items=getBcfViewpoints, name="BCF Viewpoints")
|
||||
viewpoints: EnumProperty(items=lambda _, context: getBcfViewpoints(_, context), name="BCF Viewpoints")
|
||||
files: CollectionProperty(name="Files", type=StrProperty)
|
||||
file_reference: StringProperty(default="", name="Reference")
|
||||
file_ifc_project: StringProperty(default="", name="IFC Project")
|
||||
file_ifc_spatial_structure_element: StringProperty(default="", name="IFC Spatial Structure Element")
|
||||
reference_links: CollectionProperty(name="Reference Links", type=BcfReferenceLink)
|
||||
reference_link: StringProperty(default="", name="Reference Link")
|
||||
labels: CollectionProperty(name="Labels", type=BcfLabel)
|
||||
label: StringProperty(default="", name="Label")
|
||||
bim_snippet: PointerProperty(type=BcfBimSnippet)
|
||||
bim_snippet_type: StringProperty(default="", name="Type")
|
||||
bim_snippet_reference: StringProperty(default="", name="Reference")
|
||||
bim_snippet_schema: StringProperty(default="", name="Schema")
|
||||
document_references: CollectionProperty(name="Document References", type=BcfDocumentReference)
|
||||
document_reference: StringProperty(default="", name="Referenced Document")
|
||||
document_reference_description: StringProperty(default="", name="Description")
|
||||
related_topics: CollectionProperty(name="Related Topics", type=StrProperty)
|
||||
related_topic: StringProperty(default="", name="Related Topic")
|
||||
comments: CollectionProperty(name="Comments", type=BcfComment)
|
||||
is_editable: BoolProperty(name="Is Editable", default=False, update=updateBcfTopicIsEditable)
|
||||
comment: StringProperty(default="", name="Comment")
|
||||
has_related_viewpoint: BoolProperty(name="Has Related Viewpoint", default=False)
|
||||
|
||||
|
||||
class BCFProperties(PropertyGroup):
|
||||
@@ -153,3 +157,44 @@ class BCFProperties(PropertyGroup):
|
||||
author: StringProperty(default="john@doe.com", name="Author Email", update=updateBcfAuthor)
|
||||
topics: CollectionProperty(name="BCF Topics", type=BcfTopic)
|
||||
active_topic_index: IntProperty(name="Active BCF Topic Index", update=refreshBcfTopic)
|
||||
file_reference: StringProperty(default="", name="Reference")
|
||||
file_ifc_project: StringProperty(default="", name="IFC Project")
|
||||
file_ifc_spatial_structure_element: StringProperty(default="", name="IFC Spatial Structure Element")
|
||||
reference_link: StringProperty(default="", name="Reference Link")
|
||||
label: StringProperty(default="", name="Label")
|
||||
bim_snippet_reference: StringProperty(default="", name="Reference")
|
||||
bim_snippet_type: StringProperty(default="", name="Type")
|
||||
bim_snippet_schema: StringProperty(default="", name="Schema")
|
||||
document_reference: StringProperty(default="", name="Referenced Document")
|
||||
document_reference_description: StringProperty(default="", name="Description")
|
||||
related_topic: StringProperty(name="Related Topic")
|
||||
comment: StringProperty(default="", name="Comment")
|
||||
has_related_viewpoint: BoolProperty(name="Has Related Viewpoint", default=False)
|
||||
|
||||
def clear_input_fields(self):
|
||||
self.file_reference = ""
|
||||
self.file_ifc_project = ""
|
||||
self.file_ifc_spatial_structure_element = ""
|
||||
self.reference_link = ""
|
||||
self.label = ""
|
||||
self.bim_snippet_reference = ""
|
||||
self.bim_snippet_type = ""
|
||||
self.bim_snippet_schema = ""
|
||||
self.document_reference = ""
|
||||
self.document_reference_description = ""
|
||||
self.related_topic = ""
|
||||
self.comment = ""
|
||||
self.has_related_viewpoint = False
|
||||
|
||||
@property
|
||||
def active_topic(self):
|
||||
if len(self.topics) == 0:
|
||||
return None
|
||||
if self.active_topic_index < 0:
|
||||
self.active_topic_index = 0
|
||||
if self.active_topic_index >= len(self.topics):
|
||||
self.active_topic_index = len(self.topics) - 1
|
||||
return self.topics[self.active_topic_index]
|
||||
|
||||
def refresh_topic(self, context):
|
||||
refreshBcfTopic(self, context)
|
||||
@@ -1,8 +1,27 @@
|
||||
# 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 os
|
||||
import bpy
|
||||
from . import bcfstore
|
||||
from bpy.types import Panel
|
||||
|
||||
|
||||
class BIM_PT_bcf(Panel):
|
||||
bl_label = "BCF Project"
|
||||
bl_idname = "BIM_PT_bcf"
|
||||
@@ -17,7 +36,7 @@ class BIM_PT_bcf(Panel):
|
||||
layout.use_property_decorate = False
|
||||
|
||||
scene = context.scene
|
||||
props = bpy.context.scene.BCFProperties
|
||||
props = scene.BCFProperties
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.operator("bim.new_bcf_project", text="New Project")
|
||||
@@ -34,17 +53,18 @@ class BIM_PT_bcf(Panel):
|
||||
row = layout.row()
|
||||
row.prop(props, "author")
|
||||
|
||||
props = bpy.context.scene.BCFProperties
|
||||
props = context.scene.BCFProperties
|
||||
row = layout.row()
|
||||
row.template_list("BIM_UL_topics", "", props, "topics", props, "active_topic_index")
|
||||
col = row.column(align=True)
|
||||
col.operator("bim.add_bcf_topic", icon="ADD", text="")
|
||||
col.operator("bim.remove_bcf_topic", icon="REMOVE", text="")
|
||||
if props.active_topic_index < len(props.topics):
|
||||
topic = props.topics[props.active_topic_index]
|
||||
topic = props.active_topic
|
||||
col.prop(topic, "is_editable", icon="CHECKMARK" if topic.is_editable else "GREASEPENCIL", icon_only=True)
|
||||
|
||||
if props.active_topic_index < len(props.topics):
|
||||
topic = props.topics[props.active_topic_index]
|
||||
topic = props.active_topic
|
||||
row = layout.row()
|
||||
row.enabled = topic.is_editable
|
||||
row.prop(topic, "description", text="")
|
||||
@@ -93,13 +113,13 @@ class BIM_PT_bcf_metadata(Panel):
|
||||
layout.use_property_decorate = False
|
||||
|
||||
scene = context.scene
|
||||
props = bpy.context.scene.BCFProperties
|
||||
props = scene.BCFProperties
|
||||
|
||||
if props.active_topic_index >= len(props.topics):
|
||||
layout.label(text="No BCF project is loaded")
|
||||
return
|
||||
|
||||
topic = props.topics[props.active_topic_index]
|
||||
topic = props.active_topic
|
||||
bcfxml = bcfstore.BcfStore.get_bcfxml()
|
||||
bcf_topic = bcfxml.topics[topic.name]
|
||||
|
||||
@@ -132,12 +152,12 @@ class BIM_PT_bcf_metadata(Panel):
|
||||
row.label(text=f.ifc_spatial_structure_element)
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(topic, "file_reference")
|
||||
row.prop(props, "file_reference")
|
||||
row.operator("bim.select_bcf_header_file", icon="FILE_FOLDER", text="")
|
||||
row = layout.row()
|
||||
row.prop(topic, "file_ifc_project")
|
||||
row.prop(props, "file_ifc_project")
|
||||
row = layout.row()
|
||||
row.prop(topic, "file_ifc_spatial_structure_element")
|
||||
row.prop(props, "file_ifc_spatial_structure_element")
|
||||
|
||||
row = layout.row()
|
||||
row.operator("bim.add_bcf_header_file")
|
||||
@@ -149,7 +169,7 @@ class BIM_PT_bcf_metadata(Panel):
|
||||
row.operator("bim.open_uri", icon="URL", text="").uri = link.name
|
||||
row.operator("bim.remove_bcf_reference_link", icon="X", text="").index = index
|
||||
row = layout.row()
|
||||
row.prop(topic, "reference_link")
|
||||
row.prop(props, "reference_link")
|
||||
row = layout.row()
|
||||
row.operator("bim.add_bcf_reference_link")
|
||||
|
||||
@@ -159,7 +179,7 @@ class BIM_PT_bcf_metadata(Panel):
|
||||
row.prop(label, "name", text="")
|
||||
row.operator("bim.remove_bcf_label", icon="X", text="").index = index
|
||||
row = layout.row()
|
||||
row.prop(topic, "label")
|
||||
row.prop(props, "label")
|
||||
row = layout.row()
|
||||
row.operator("bim.add_bcf_label")
|
||||
|
||||
@@ -180,12 +200,12 @@ class BIM_PT_bcf_metadata(Panel):
|
||||
row.operator("bim.remove_bcf_bim_snippet", icon="X", text="")
|
||||
else:
|
||||
row = layout.row(align=True)
|
||||
row.prop(topic, "bim_snippet_reference")
|
||||
row.prop(props, "bim_snippet_reference")
|
||||
row.operator("bim.select_bcf_bim_snippet_reference", icon="FILE_FOLDER", text="")
|
||||
row = layout.row()
|
||||
row.prop(topic, "bim_snippet_type")
|
||||
row.prop(props, "bim_snippet_type")
|
||||
row = layout.row()
|
||||
row.prop(topic, "bim_snippet_schema")
|
||||
row.prop(props, "bim_snippet_schema")
|
||||
row = layout.row()
|
||||
row.operator("bim.add_bcf_bim_snippet")
|
||||
|
||||
@@ -203,20 +223,26 @@ class BIM_PT_bcf_metadata(Panel):
|
||||
row = box.row(align=True)
|
||||
row.prop(doc, "description")
|
||||
row = layout.row(align=True)
|
||||
row.prop(topic, "document_reference")
|
||||
row.prop(props, "document_reference")
|
||||
row.operator("bim.select_bcf_document_reference", icon="FILE_FOLDER", text="")
|
||||
row = layout.row()
|
||||
row.prop(topic, "document_reference_description")
|
||||
row.prop(props, "document_reference_description")
|
||||
row = layout.row()
|
||||
row.operator("bim.add_bcf_document_reference")
|
||||
|
||||
layout.label(text="Related Topics:")
|
||||
for index, related_topic in enumerate(topic.related_topics):
|
||||
row = layout.row(align=True)
|
||||
row.operator("bim.view_bcf_topic", text=bcfxml.topics[related_topic.name.lower()].title).topic_guid = related_topic.name
|
||||
row.operator("bim.remove_bcf_related_topic", icon="X", text="").index = index
|
||||
try:
|
||||
row = layout.row(align=True)
|
||||
op = row.operator(
|
||||
"bim.view_bcf_topic", text=f"Select {bcfxml.topics[related_topic.name.lower()].title}"
|
||||
)
|
||||
op.topic_guid = related_topic.name
|
||||
row.operator("bim.remove_bcf_related_topic", icon="X", text="").index = index
|
||||
except KeyError:
|
||||
pass
|
||||
row = layout.row()
|
||||
row.prop(topic, "related_topic")
|
||||
row.prop(props, "related_topic")
|
||||
row = layout.row()
|
||||
row.operator("bim.add_bcf_related_topic")
|
||||
|
||||
@@ -236,7 +262,7 @@ class BIM_PT_bcf_comments(Panel):
|
||||
layout.use_property_decorate = False
|
||||
|
||||
scene = context.scene
|
||||
props = bpy.context.scene.BCFProperties
|
||||
props = scene.BCFProperties
|
||||
|
||||
if props.active_topic_index >= len(props.topics):
|
||||
layout.label(text="No BCF project is loaded")
|
||||
@@ -245,7 +271,7 @@ class BIM_PT_bcf_comments(Panel):
|
||||
row = layout.row()
|
||||
row.prop(props, "comment_text_width")
|
||||
|
||||
topic = props.topics[props.active_topic_index]
|
||||
topic = props.active_topic
|
||||
for comment in topic.comments:
|
||||
box = self.layout.box()
|
||||
|
||||
@@ -276,8 +302,8 @@ class BIM_PT_bcf_comments(Panel):
|
||||
col.label(text=" ".join(line_words))
|
||||
|
||||
row = layout.row()
|
||||
row.prop(topic, "comment")
|
||||
row.prop(props, "comment")
|
||||
row = layout.row()
|
||||
row.prop(topic, "has_related_viewpoint")
|
||||
row.prop(props, "has_related_viewpoint")
|
||||
row = layout.row()
|
||||
row.operator("bim.add_bcf_comment")
|
||||
@@ -0,0 +1,42 @@
|
||||
# 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 ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.ExecuteBIMTester,
|
||||
operator.BIMTesterPurge,
|
||||
operator.SelectFeature,
|
||||
operator.SelectSteps,
|
||||
operator.SelectBIMTesterIfcFile,
|
||||
operator.RejectElement,
|
||||
operator.ApproveClass,
|
||||
operator.RejectClass,
|
||||
operator.SelectAudited,
|
||||
prop.BimTesterProperties,
|
||||
ui.BIM_PT_qa,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Scene.BimTesterProperties = bpy.props.PointerProperty(type=prop.BimTesterProperties)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.BimTesterProperties
|
||||
@@ -1,13 +1,34 @@
|
||||
# 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 os
|
||||
import bpy
|
||||
import tempfile
|
||||
import webbrowser
|
||||
import ifcopenshell
|
||||
import bimtester
|
||||
import bimtester.run
|
||||
import bimtester.reports
|
||||
|
||||
try:
|
||||
import bimtester
|
||||
import bimtester.run
|
||||
import bimtester.reports
|
||||
except:
|
||||
print("Failed to load BIMTester. Try disabling other add-ons, in particular Blender-OSM. See bug #1318.")
|
||||
|
||||
from pathlib import Path
|
||||
from itertools import cycle
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
@@ -15,6 +36,11 @@ class ExecuteBIMTester(bpy.types.Operator):
|
||||
bl_idname = "bim.execute_bim_tester"
|
||||
bl_label = "Execute BIMTester"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
props = context.scene.BimTesterProperties
|
||||
return (props.ifc_file or props.should_load_from_memory) and props.feature
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BimTesterProperties
|
||||
|
||||
@@ -31,7 +57,7 @@ class ExecuteBIMTester(bpy.types.Operator):
|
||||
"schema_file": "",
|
||||
"schema_name": "",
|
||||
"lang": "en",
|
||||
"steps": props.steps
|
||||
"steps": props.steps,
|
||||
}
|
||||
use_stored_ifc = props.should_load_from_memory and IfcStore.get_file()
|
||||
runner = bimtester.run.TestRunner(args["ifc"], ifc=IfcStore.get_file() if use_stored_ifc else None)
|
||||
@@ -46,12 +72,8 @@ class BIMTesterPurge(bpy.types.Operator):
|
||||
bl_label = "Purge Tests"
|
||||
|
||||
def execute(self, context):
|
||||
filename = os.path.join(
|
||||
bpy.context.scene.BimTesterProperties.features_dir,
|
||||
bpy.context.scene.BimTesterProperties.features_file + ".feature",
|
||||
)
|
||||
cwd = os.getcwd()
|
||||
os.chdir(bpy.context.scene.BimTesterProperties.features_dir)
|
||||
os.chdir(context.scene.BimTesterProperties.features_dir)
|
||||
bimtester.clean.TestPurger().purge()
|
||||
os.chdir(cwd)
|
||||
return {"FINISHED"}
|
||||
@@ -59,13 +81,14 @@ class BIMTesterPurge(bpy.types.Operator):
|
||||
|
||||
class SelectFeature(bpy.types.Operator):
|
||||
bl_idname = "bim.select_feature"
|
||||
bl_label = "Select Feature"
|
||||
bl_label = "Select Feature / IDS"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filename_ext = ".feature"
|
||||
filter_glob: bpy.props.StringProperty(default="*.feature", options={"HIDDEN"})
|
||||
filter_glob: bpy.props.StringProperty(default="*.feature;*.xml", options={"HIDDEN"})
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def execute(self, context):
|
||||
bpy.context.scene.BimTesterProperties.feature = self.filepath
|
||||
context.scene.BimTesterProperties.feature = self.filepath
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
@@ -76,12 +99,13 @@ class SelectFeature(bpy.types.Operator):
|
||||
class SelectSteps(bpy.types.Operator):
|
||||
bl_idname = "bim.select_steps"
|
||||
bl_label = "Select Steps"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filename_ext = ".py"
|
||||
filter_glob: bpy.props.StringProperty(default="*.py", options={"HIDDEN"})
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def execute(self, context):
|
||||
bpy.context.scene.BimTesterProperties.steps = self.filepath
|
||||
context.scene.BimTesterProperties.steps = self.filepath
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
@@ -92,6 +116,7 @@ class SelectSteps(bpy.types.Operator):
|
||||
class SelectBIMTesterIfcFile(bpy.types.Operator):
|
||||
bl_idname = "bim.select_bimtester_ifc_file"
|
||||
bl_label = "Select BIMTester IFC File"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filename_ext = ".ifc"
|
||||
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
@@ -112,14 +137,14 @@ class RejectElement(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
lines = []
|
||||
self.file = IfcStore.get_file()
|
||||
for obj in bpy.context.selected_objects:
|
||||
for obj in context.selected_objects:
|
||||
lines.append(
|
||||
" * The element {} should not exist because {}".format(
|
||||
self.file.by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId,
|
||||
bpy.context.scene.BimTesterProperties.qa_reject_element_reason,
|
||||
context.scene.BimTesterProperties.qa_reject_element_reason,
|
||||
)
|
||||
)
|
||||
QAHelper.append_to_scenario(lines)
|
||||
QAHelper.append_to_scenario(lines, context)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -130,12 +155,12 @@ class ApproveClass(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
lines = []
|
||||
self.file = IfcStore.get_file()
|
||||
for obj in bpy.context.selected_objects:
|
||||
for obj in context.selected_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
continue
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
lines.append(" * The element {} is an {}".format(element.GlobalId, element.is_a()))
|
||||
QAHelper.append_to_scenario(lines)
|
||||
QAHelper.append_to_scenario(lines, context)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -146,27 +171,28 @@ class RejectClass(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
lines = []
|
||||
self.file = IfcStore.get_file()
|
||||
for obj in bpy.context.selected_objects:
|
||||
for obj in context.selected_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
continue
|
||||
lines.append(
|
||||
" * The element {} is an {}".format(
|
||||
self.file.by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId,
|
||||
bpy.context.scene.BimTesterProperties.audit_ifc_class,
|
||||
context.scene.BimTesterProperties.audit_ifc_class,
|
||||
)
|
||||
)
|
||||
QAHelper.append_to_scenario(lines)
|
||||
QAHelper.append_to_scenario(lines, context)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SelectAudited(bpy.types.Operator):
|
||||
bl_idname = "bim.select_audited"
|
||||
bl_label = "Select Audited"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
audited_global_ids = []
|
||||
self.file = IfcStore.get_file()
|
||||
for filename in Path(bpy.context.scene.BimTesterProperties.features_dir).glob("*.feature"):
|
||||
for filename in Path(context.scene.BimTesterProperties.features_dir).glob("*.feature"):
|
||||
with open(filename, "r") as feature_file:
|
||||
lines = feature_file.readlines()
|
||||
for line in lines:
|
||||
@@ -174,7 +200,7 @@ class SelectAudited(bpy.types.Operator):
|
||||
for word in words:
|
||||
if self.is_a_global_id(word):
|
||||
audited_global_ids.append(word)
|
||||
for obj in bpy.context.visible_objects:
|
||||
for obj in context.visible_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
continue
|
||||
if self.file.by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId in audited_global_ids:
|
||||
@@ -187,10 +213,10 @@ class SelectAudited(bpy.types.Operator):
|
||||
|
||||
class QAHelper:
|
||||
@classmethod
|
||||
def append_to_scenario(cls, lines):
|
||||
def append_to_scenario(cls, lines, context):
|
||||
filename = os.path.join(
|
||||
bpy.context.scene.BimTesterProperties.features_dir,
|
||||
bpy.context.scene.BimTesterProperties.features_file + ".feature",
|
||||
context.scene.BimTesterProperties.features_dir,
|
||||
context.scene.BimTesterProperties.features_file + ".feature",
|
||||
)
|
||||
if os.path.exists(filename + "~"):
|
||||
os.remove(filename + "~")
|
||||
@@ -201,7 +227,7 @@ class QAHelper:
|
||||
for source_line in source:
|
||||
if (
|
||||
"Scenario: " in source_line
|
||||
and bpy.context.scene.BimTesterProperties.scenario == source_line.strip()[len("Scenario: ") :]
|
||||
and context.scene.BimTesterProperties.scenario == source_line.strip()[len("Scenario: ") :]
|
||||
):
|
||||
is_in_scenario = True
|
||||
elif is_in_scenario:
|
||||
@@ -210,19 +236,3 @@ class QAHelper:
|
||||
is_in_scenario = False
|
||||
destination.write(source_line)
|
||||
os.remove(filename + "~")
|
||||
|
||||
|
||||
colour_list = [
|
||||
(0.651, 0.81, 0.892, 1),
|
||||
(0.121, 0.471, 0.706, 1),
|
||||
(0.699, 0.876, 0.54, 1),
|
||||
(0.199, 0.629, 0.174, 1),
|
||||
(0.983, 0.605, 0.602, 1),
|
||||
(0.89, 0.101, 0.112, 1),
|
||||
(0.989, 0.751, 0.427, 1),
|
||||
(0.986, 0.497, 0.1, 1),
|
||||
(0.792, 0.699, 0.839, 1),
|
||||
(0.414, 0.239, 0.603, 1),
|
||||
(0.993, 0.999, 0.6, 1),
|
||||
(0.693, 0.349, 0.157, 1),
|
||||
]
|
||||